| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103 |
- using System.Text.RegularExpressions;
- using Admin.NET.Plugin.AiDOP.DataPlatform;
- using Xunit;
- namespace Admin.NET.Plugin.AiDOP.Tests.DataPlatform;
- /// <summary>
- /// 目录必须盖住代码里声明的中立表,以及当前库已有、但 DDL 不在 MdpSchemaDefinition 的表。
- /// 投影文件里的 INSERT INTO mdp_std_ 必须经过来源闸门。
- /// </summary>
- public class MdpStdObjectCatalogGuardTests
- {
- private static readonly string[] PhysicalTablesOutsideSchema =
- [
- "mdp_std_action_event",
- "mdp_std_delivery_exception",
- "mdp_std_delivery_result",
- "mdp_std_delivery_schedule",
- "mdp_std_employee",
- "mdp_std_inv_trans",
- "mdp_std_inventory",
- "mdp_std_inventory_balance_monthly",
- "mdp_std_iqc_inspection",
- "mdp_std_item",
- "mdp_std_material_readiness",
- "mdp_std_process_outsource_order",
- "mdp_std_purchase_order",
- "mdp_std_purchase_order_completion",
- "mdp_std_purchase_request",
- "mdp_std_ship_trans",
- "mdp_std_so",
- "mdp_std_supplier",
- "mdp_std_supplier_item",
- "mdp_std_supply_demand",
- "mdp_std_work_order_bom",
- "mdp_std_work_order_line",
- ];
- [Fact]
- public void Catalog_CoversEveryNeutralTable()
- {
- var schema = ReadRepoFile(Path.Combine(
- "server", "Plugins", "Admin.NET.Plugin.AiDOP", "DataPlatform", "Schema", "MdpSchemaDefinition.cs"));
- var names = Regex.Matches(schema, "\\[\"(mdp_std_[a-z0-9_]+)\"\\]")
- .Select(m => m.Groups[1].Value)
- .Concat(PhysicalTablesOutsideSchema)
- .Where(n => !n.StartsWith("mdp_std_t8_", StringComparison.OrdinalIgnoreCase)
- && !n.Contains("_unmapped", StringComparison.OrdinalIgnoreCase)
- && !n.Contains("_bak_", StringComparison.OrdinalIgnoreCase))
- .Distinct(StringComparer.OrdinalIgnoreCase)
- .ToList();
- var covered = MdpStdObjectCatalog.All.SelectMany(d => d.Tables).ToHashSet(StringComparer.OrdinalIgnoreCase);
- var missing = names.Where(n => !covered.Contains(n)).OrderBy(n => n).ToList();
- Assert.True(missing.Count == 0, "目录未覆盖: " + string.Join(", ", missing));
- }
- [Fact]
- public void NeutralInserts_CallSourceGate()
- {
- var root = RepoRoot();
- var plugin = Path.Combine(root, "server", "Plugins", "Admin.NET.Plugin.AiDOP");
- var hits = new List<string>();
- foreach (var file in Directory.EnumerateFiles(plugin, "*.cs", SearchOption.AllDirectories))
- {
- if (file.Contains($"{Path.DirectorySeparatorChar}Tests{Path.DirectorySeparatorChar}", StringComparison.OrdinalIgnoreCase))
- continue;
- var text = File.ReadAllText(file);
- var targets = Regex.Matches(text, @"INSERT\s+INTO\s+(mdp_std_[A-Za-z0-9_]+)", RegexOptions.IgnoreCase)
- .Select(m => m.Groups[1].Value)
- .Where(n => !n.Contains("unmapped", StringComparison.OrdinalIgnoreCase)
- && !n.Contains("_bak_", StringComparison.OrdinalIgnoreCase))
- .Distinct(StringComparer.OrdinalIgnoreCase)
- .ToList();
- if (targets.Count == 0)
- continue;
- if (!text.Contains("MdpNeutralSourceGate", StringComparison.Ordinal)
- && !text.Contains("MdpTenantStdSourceResolver", StringComparison.Ordinal))
- hits.Add(Path.GetRelativePath(plugin, file));
- }
- Assert.True(hits.Count == 0, "中立层写入未调用来源闸门: " + string.Join(", ", hits));
- }
- private static string ReadRepoFile(string relative)
- {
- var path = Path.Combine(RepoRoot(), relative);
- if (!File.Exists(path)) throw new FileNotFoundException(path);
- return File.ReadAllText(path);
- }
- private static string RepoRoot()
- {
- var dir = new DirectoryInfo(AppContext.BaseDirectory);
- while (dir != null)
- {
- if (Directory.Exists(Path.Combine(dir.FullName, "server", "Plugins", "Admin.NET.Plugin.AiDOP")))
- return dir.FullName;
- dir = dir.Parent;
- }
- throw new DirectoryNotFoundException("repo root");
- }
- }
|