using Admin.NET.Plugin.AiDOP.DataPlatform; using SqlSugar; using Xunit; namespace Admin.NET.Plugin.AiDOP.Tests.DataPlatform; /// /// 九宫格取数与入站诊断日志的守卫。锚在实现正文,避免匹配到接口声明。 /// public class GridAndInboundGuardTests { private static string Read(string relative) { var path = Path.Combine(FindRepoRoot(), relative); return File.ReadAllText(path); } [Fact] public void Seed_Defines_S5_L1_004() { var source = Read(@"server\Plugins\Admin.NET.Plugin.AiDOP\Infrastructure\AidopKpiMasterSeed.cs"); Assert.Contains("\"S5_L1_004\"", source); Assert.Contains("品类物料库存周转", source); } [Fact] public void HomeGrid_ItemBizDate_DoesNotFallBackToModuleDate() { var source = Read(@"server\Plugins\Admin.NET.Plugin.AiDOP\Controllers\AidopKanbanController.Generic.cs"); Assert.Contains("biz_date AS BizDate", source); Assert.Contains("禁止拿未筛选的最后真实值补上", source); var items = source.IndexOf("items.Add(new", StringComparison.Ordinal); Assert.True(items > 0); var slice = source[items..source.IndexOf("return Ok", items, StringComparison.Ordinal)]; Assert.Contains("bizDate = card.BizDate", slice); Assert.DoesNotContain("bizDate = bizDate", slice); } [Fact] public void GateLog_SamplesBeforeConcat_AndDoesNotKillThePipeline() { var inventory = SliceMethod(Read(@"server\Plugins\Admin.NET.Plugin.AiDOP\MaterialWarehouse\InventoryMdpSyncService.cs"), "private async Task LogWorkOrderNotFoundAsync"); Assert.Contains("LIMIT 20", inventory); Assert.Contains("try", inventory); Assert.DoesNotContain("GROUP_CONCAT(DISTINCT t.work_ord)", inventory); Assert.Contains("LogWarning", inventory); var shipFile = Read(@"server\Plugins\Admin.NET.Plugin.AiDOP\DataPlatform\Wms\ShipTransNeutralProjection.cs"); var mark = shipFile.IndexOf("写失败不得中断发运投影", StringComparison.Ordinal); Assert.True(mark > 0); var around = shipFile.Substring(Math.Max(0, mark - 120), 500); Assert.Contains("try", around); Assert.Contains("LIMIT 12", shipFile); Assert.DoesNotContain("GROUP_CONCAT(DISTINCT CONCAT", shipFile); Assert.Contains("LogWarning", shipFile); } [Fact] public void ExtraParams_DropsConfigId_AndKeepsForeignKeys() { var dropped = new List(); var sqlServer = MdpSourceScopeFactory.SanitizeExtraParams( "ConfigId=t8_v5;TrustServerCertificate=true;Application Name=aidop", DbType.SqlServer, out dropped); Assert.Contains("ConfigId", dropped, StringComparer.OrdinalIgnoreCase); Assert.Contains("TrustServerCertificate", dropped, StringComparer.OrdinalIgnoreCase); Assert.DoesNotContain("ConfigId", sqlServer ?? "", StringComparison.OrdinalIgnoreCase); Assert.Contains("Application Name", sqlServer ?? "", StringComparison.OrdinalIgnoreCase); var mysql = MdpSourceScopeFactory.SanitizeExtraParams( "SslMode=Required;Connection Timeout=15", DbType.MySql, out dropped); Assert.Empty(dropped); Assert.Contains("SslMode", mysql ?? "", StringComparison.OrdinalIgnoreCase); var pg = MdpSourceScopeFactory.SanitizeExtraParams( "SslMode=Require;Timeout=15", DbType.PostgreSQL, out dropped); Assert.Empty(dropped); Assert.Contains("SslMode", pg ?? "", StringComparison.OrdinalIgnoreCase); } private static string SliceMethod(string source, string anchor) { var start = source.IndexOf(anchor, StringComparison.Ordinal); Assert.True(start >= 0, anchor); var end = source.IndexOf("\n private ", start + anchor.Length, StringComparison.Ordinal); if (end < 0) end = source.IndexOf("\n public ", start + anchor.Length, StringComparison.Ordinal); if (end < 0) end = source.Length; return source[start..end]; } private static string FindRepoRoot() { var dir = new DirectoryInfo(AppContext.BaseDirectory); while (dir != null) { if (File.Exists(Path.Combine(dir.FullName, "AGENTS.md"))) return dir.FullName; dir = dir.Parent; } throw new InvalidOperationException("找不到仓库根目录"); } }