using System.Text.RegularExpressions; using Xunit; namespace Admin.NET.Plugin.AiDOP.Tests.DataPlatform; /// /// 指标计算与诊断依据不得再出现 T8 列名或中文业务类型字面量。 /// T8 适配器文件不在扫描范围内。 /// public class NeutralLayerTokenGuardTests { private static readonly string[] Files = [ Path.Combine("Supply", "S3MdpSyncTransformService.cs"), Path.Combine("MaterialWarehouse", "S5MdpSyncTransformService.cs"), Path.Combine("Manufacturing", "S6MdpSyncTransformService.cs"), Path.Combine("FinishedWarehouse", "S7MdpSyncTransformService.cs"), Path.Combine("SmartOps", "SmartDiagnosisEvidenceRegistry.cs"), Path.Combine("SmartOps", "SmartOpsKpiAtomicBuildService.cs"), Path.Combine("SmartOps", "S9CompositeKpiWriter.cs") ]; private static readonly string[] Tokens = [ "mdp_std_t8_", "ztid", "lbs", "hzyn", "zfyn", "shyn", "shtime", "noid", "rwnoid", "lynoid", "gdyn", "gdtime", "jhdate", "slzx", "zzzt", "采购入库", "生产领料", "生产任务", "生产入库", "销售订单", "销售出库", "销售退货" ]; [Fact] public void KpiReaders_DoNotContainT8Tokens() { var hits = new List(); foreach (var relative in Files) { var text = ReadPluginFile(relative); foreach (var token in Tokens) { var pattern = token.Any(c => c > 127) ? Regex.Escape(token) : $@"\b{Regex.Escape(token)}\b"; if (Regex.IsMatch(text, pattern)) hits.Add($"{relative}: {token}"); } } Assert.Empty(hits); } [Fact] public void InventoryAndEmployeeKpiSql_FilterBySource() { var files = new[] { Path.Combine("Supply", "S3MdpSyncTransformService.cs"), Path.Combine("MaterialWarehouse", "S5MdpSyncTransformService.cs"), Path.Combine("Manufacturing", "S6MdpSyncTransformService.cs"), Path.Combine("FinishedWarehouse", "S7MdpSyncTransformService.cs") }; var hits = new List(); foreach (var relative in files) { var text = ReadPluginFile(relative); foreach (Match match in Regex.Matches(text, @"from\s+mdp_std_(inv_trans|employee)\b", RegexOptions.IgnoreCase)) { var window = text.Substring(match.Index, Math.Min(1200, text.Length - match.Index)); if (!window.Contains("source_system", StringComparison.OrdinalIgnoreCase)) hits.Add($"{relative}@{match.Index}"); } } Assert.Empty(hits); } private static string ReadPluginFile(string relative) { var dir = new DirectoryInfo(AppContext.BaseDirectory); while (dir != null) { var candidate = Path.Combine(dir.FullName, "server", "Plugins", "Admin.NET.Plugin.AiDOP", relative); if (File.Exists(candidate)) return File.ReadAllText(candidate); dir = dir.Parent; } throw new FileNotFoundException(relative); } }