using System.Text.RegularExpressions; using Admin.NET.Plugin.AiDOP.SmartOps; using Xunit; namespace Admin.NET.Plugin.AiDOP.Tests.SmartOps; public class KpiResultStatusResolverTests { [Fact] public void SeedMetrics_AllHaveADependencyRow() { var root = RepoRoot(); var seed = File.ReadAllText(Path.Combine( root, "server", "Plugins", "Admin.NET.Plugin.AiDOP", "Infrastructure", "AidopKpiMasterSeed.cs")); var codes = Regex.Matches(seed, "\"(S[5679]_L\\d+_\\d+)\"") .Select(m => m.Groups[1].Value) .Distinct(StringComparer.Ordinal) .ToList(); var missing = codes.Where(c => !KpiSemanticDependency.Contains(c)).OrderBy(c => c).ToList(); Assert.True(missing.Count == 0, "附录 F 缺行: " + string.Join(", ", missing)); Assert.Contains("S5_L1_004", KpiSemanticDependency.Codes); } [Fact] public void UnsupportedSemantic_NullsTheValue() { var decision = KpiResultStatusResolver.Resolve( "S7_L2_013", 3m, new Dictionary { ["FG_RECEIPT_TIME"] = "源系统没有客户签收时间" }, new HashSet()); Assert.Equal("SOURCE_UNSUPPORTED", decision.Status); Assert.Null(decision.Value); Assert.Contains("客户签收", decision.Reason); } [Fact] public void MissingObject_IsFailed() { var decision = KpiResultStatusResolver.Resolve( "S7_L1_001", 1m, new Dictionary(), new HashSet()); Assert.Equal("FAILED", decision.Status); Assert.Null(decision.Value); } [Fact] public void StarredLocation_DoesNotFailReceiptEfficiency() { var decision = KpiResultStatusResolver.Resolve( "S5_L3_002", 2m, new Dictionary { ["INV_LOCATION"] = "无库位" }, new HashSet()); Assert.Equal("OK", decision.Status); Assert.Equal(2m, decision.Value); } [Fact] public void NullValue_IsNoData() { var decision = KpiResultStatusResolver.Resolve( "S5_L1_001", null, new Dictionary(), new HashSet()); Assert.Equal("NO_DATA", decision.Status); Assert.Null(decision.Value); } 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"); } }