NeutralLayerTokenGuardTests.cs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. using System.Text.RegularExpressions;
  2. using Xunit;
  3. namespace Admin.NET.Plugin.AiDOP.Tests.DataPlatform;
  4. /// <summary>
  5. /// 指标计算与诊断依据不得再出现 T8 列名或中文业务类型字面量。
  6. /// T8 适配器文件不在扫描范围内。
  7. /// </summary>
  8. public class NeutralLayerTokenGuardTests
  9. {
  10. private static readonly string[] Files =
  11. [
  12. Path.Combine("Supply", "S3MdpSyncTransformService.cs"),
  13. Path.Combine("MaterialWarehouse", "S5MdpSyncTransformService.cs"),
  14. Path.Combine("Manufacturing", "S6MdpSyncTransformService.cs"),
  15. Path.Combine("FinishedWarehouse", "S7MdpSyncTransformService.cs"),
  16. Path.Combine("SmartOps", "SmartDiagnosisEvidenceRegistry.cs"),
  17. Path.Combine("SmartOps", "SmartOpsKpiAtomicBuildService.cs"),
  18. Path.Combine("SmartOps", "S9CompositeKpiWriter.cs")
  19. ];
  20. private static readonly string[] Tokens =
  21. [
  22. "mdp_std_t8_", "ztid", "lbs", "hzyn", "zfyn", "shyn", "shtime",
  23. "noid", "rwnoid", "lynoid", "gdyn", "gdtime", "jhdate", "slzx", "zzzt",
  24. "采购入库", "生产领料", "生产任务", "生产入库", "销售订单", "销售出库", "销售退货"
  25. ];
  26. [Fact]
  27. public void KpiReaders_DoNotContainT8Tokens()
  28. {
  29. var hits = new List<string>();
  30. foreach (var relative in Files)
  31. {
  32. var text = ReadPluginFile(relative);
  33. foreach (var token in Tokens)
  34. {
  35. var pattern = token.Any(c => c > 127)
  36. ? Regex.Escape(token)
  37. : $@"\b{Regex.Escape(token)}\b";
  38. if (Regex.IsMatch(text, pattern))
  39. hits.Add($"{relative}: {token}");
  40. }
  41. }
  42. Assert.Empty(hits);
  43. }
  44. [Fact]
  45. public void InventoryAndEmployeeKpiSql_FilterBySource()
  46. {
  47. var files = new[]
  48. {
  49. Path.Combine("Supply", "S3MdpSyncTransformService.cs"),
  50. Path.Combine("MaterialWarehouse", "S5MdpSyncTransformService.cs"),
  51. Path.Combine("Manufacturing", "S6MdpSyncTransformService.cs"),
  52. Path.Combine("FinishedWarehouse", "S7MdpSyncTransformService.cs")
  53. };
  54. var hits = new List<string>();
  55. foreach (var relative in files)
  56. {
  57. var text = ReadPluginFile(relative);
  58. foreach (Match match in Regex.Matches(text, @"from\s+mdp_std_(inv_trans|employee)\b", RegexOptions.IgnoreCase))
  59. {
  60. var window = text.Substring(match.Index, Math.Min(1200, text.Length - match.Index));
  61. if (!window.Contains("source_system", StringComparison.OrdinalIgnoreCase))
  62. hits.Add($"{relative}@{match.Index}");
  63. }
  64. }
  65. Assert.Empty(hits);
  66. }
  67. [Fact]
  68. public void S5S6S7MetricSql_DoesNotNameT8()
  69. {
  70. var files = new[]
  71. {
  72. Path.Combine("MaterialWarehouse", "S5MdpSyncTransformService.cs"),
  73. Path.Combine("Manufacturing", "S6MdpSyncTransformService.cs"),
  74. Path.Combine("FinishedWarehouse", "S7MdpSyncTransformService.cs"),
  75. Path.Combine("Supply", "S3MdpSyncTransformService.cs")
  76. };
  77. var hits = new List<string>();
  78. foreach (var relative in files)
  79. {
  80. var text = ReadPluginFile(relative);
  81. foreach (Match match in Regex.Matches(text, "@\"(?:[^\"]|\"\")*\"|\"\"\"[\\s\\S]*?\"\"\""))
  82. {
  83. if (match.Value.Contains("T8", StringComparison.Ordinal))
  84. hits.Add($"{relative}:{match.Index}");
  85. }
  86. }
  87. Assert.Empty(hits);
  88. }
  89. [Fact]
  90. public void RefreshService_DoesNotHardcodePbxfxp()
  91. {
  92. var text = ReadPluginFile(Path.Combine("DataPlatform", "AidopT8KpiManualRefreshService.cs"));
  93. Assert.DoesNotContain("pbxfxp", text, StringComparison.OrdinalIgnoreCase);
  94. }
  95. private static string ReadPluginFile(string relative)
  96. {
  97. var dir = new DirectoryInfo(AppContext.BaseDirectory);
  98. while (dir != null)
  99. {
  100. var candidate = Path.Combine(dir.FullName, "server", "Plugins", "Admin.NET.Plugin.AiDOP", relative);
  101. if (File.Exists(candidate)) return File.ReadAllText(candidate);
  102. dir = dir.Parent;
  103. }
  104. throw new FileNotFoundException(relative);
  105. }
  106. }