| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 |
- using Xunit;
- namespace Admin.NET.Plugin.AiDOP.Tests.S6.Manufacturing;
- /// <summary>S6 Phase 1C 录入/判定/完成 源码契约测试:快照唯一判定源、后端判定、幂等、事务、完成校验、tenant、入参不信任判定。</summary>
- public class S6ProcessInspectionEntryContractTests
- {
- private static string Svc() => File.ReadAllText(FindFile("server", "Plugins", "Admin.NET.Plugin.AiDOP", "Manufacturing", "S6ProcessInspectionService.cs"));
- private static string Dto() => File.ReadAllText(FindFile("server", "Plugins", "Admin.NET.Plugin.AiDOP", "Manufacturing", "Dto", "S6ProcessInspectionDto.cs"));
- private static string Judge() => File.ReadAllText(FindFile("server", "Plugins", "Admin.NET.Plugin.AiDOP", "Manufacturing", "S6ProcessInspectionJudge.cs"));
- [Fact]
- public void Save_BackendJudges_FromSnapshotConfig_NotLiveSpec()
- {
- var s = Svc();
- Assert.Contains("S6ProcessInspectionJudge.JudgeSample", s);
- Assert.Contains("LoadSnapshotConfigAsync", s);
- Assert.Contains("FROM ado_s6_process_inspection_snapshot_line", s);
- // 判定路径不回查 S0 检规
- Assert.DoesNotContain("FROM qms_gcjygfzb z\n WHERE z.tenant_id=@TenantId AND z.glid=@SpecId AND", s); // 仅生成时读,判定不读
- Assert.Contains("result_type AS ResultType, lower_limit AS LowerLimit, upper_limit AS UpperLimit, sample_count AS SampleCount", s);
- }
- [Fact]
- public void SaveInput_DoesNotAccept_JudgementOrTenantOrLimits()
- {
- var d = Dto();
- // 入参 DTO 只有 SnapshotLineId/SampleIndex/ActualValue/Remark
- Assert.Contains("public long SnapshotLineId", d);
- Assert.Contains("public string? ActualValue", d);
- Assert.DoesNotContain("public string? Judgement { get; set; }\n public long TenantId", d);
- // S6SaveResultSample 不含 Judgement / TenantId / LowerLimit / OverallResult
- var sampleClass = d.Substring(d.IndexOf("class S6SaveResultSample"));
- sampleClass = sampleClass.Substring(0, sampleClass.IndexOf("}") + 1);
- Assert.DoesNotContain("Judgement", sampleClass);
- Assert.DoesNotContain("TenantId", sampleClass);
- Assert.DoesNotContain("LowerLimit", sampleClass);
- }
- [Fact]
- public void Save_TenantScoped_AndTransactional()
- {
- var s = Svc();
- Assert.Contains("AidopTenantScope.ResolveOrThrow", s);
- Assert.Contains("BeginTran()", s);
- Assert.Contains("CommitTran()", s);
- Assert.Contains("RollbackTran()", s);
- Assert.DoesNotContain("tenant_id IS NULL", s);
- // 结果表读写均带 tenant
- Assert.Contains("WHERE tenant_id=@t AND bill_id=@bill", s);
- }
- [Fact]
- public void Save_IdempotentUpsert_ByBillLineSample()
- {
- var s = Svc();
- Assert.Contains("INSERT INTO ado_s6_process_inspection_result_item", s);
- Assert.Contains("ON DUPLICATE KEY UPDATE", s); // UK(bill,line,sample) 幂等
- }
- [Fact]
- public void Complete_EnforcesCompleteness()
- {
- var s = Svc();
- Assert.Contains("AllItemsCompleted", s);
- Assert.Contains("INSPECTION_INCOMPLETE", s);
- }
- [Fact]
- public void Header_CompletedAt_ConsistentWithStatus()
- {
- // completed_at 只在 COMPLETED 有值;回退时清空,避免 IN_PROGRESS 残留完成时间。
- var s = Svc();
- Assert.Contains("completed_at=CASE WHEN @status='COMPLETED' THEN @completedAt ELSE NULL END", s);
- }
- [Fact]
- public void Overall_And_Item_BackendComputed()
- {
- var s = Svc();
- Assert.Contains("AggregateItem", s);
- Assert.Contains("AggregateOverall", s);
- Assert.Contains("RecomputeAndPersistHeaderAsync", s);
- }
- [Fact]
- public void Judge_NonNumeric_AutoOkPassNgFail()
- {
- var j = Judge();
- Assert.Contains("\"OK\" => S6Judgement.Pass", j);
- Assert.Contains("\"NG\" => S6Judgement.Fail", j);
- // NUMERIC 无界限 → INVALID(不默认 PASS)
- Assert.Contains("if (lo == null && up == null) return S6Judgement.Invalid", j);
- Assert.Contains("if (actual == null) return S6Judgement.Invalid", j);
- }
- private static string FindFile(params string[] parts)
- {
- var dir = new DirectoryInfo(AppContext.BaseDirectory);
- while (dir != null)
- {
- var candidate = Path.Combine(new[] { dir.FullName }.Concat(parts).ToArray());
- if (File.Exists(candidate)) return candidate;
- dir = dir.Parent;
- }
- throw new FileNotFoundException(string.Join("/", parts));
- }
- }
|