S6ProcessSpecResolverTests.cs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. using Admin.NET.Plugin.AiDOP.Manufacturing;
  2. using Admin.NET.Plugin.AiDOP.Manufacturing.Dto;
  3. using Xunit;
  4. namespace Admin.NET.Plugin.AiDOP.Tests.S6.Manufacturing;
  5. /// <summary>
  6. /// S6 Phase 1B 过程检规解析器 裁决逻辑单测(纯函数 Decide,无 DB)。
  7. /// 覆盖 MATCHED / NO_MATCH / AMBIGUOUS / VERSION / INVALID_SPEC + 日期归一化 + tokenize。
  8. /// </summary>
  9. public class S6ProcessSpecResolverTests
  10. {
  11. private static S6SpecCandidate C(long id, string wjbh, int version, string sxrj, int detail) =>
  12. new() { Id = id, Wjbh = wjbh, Bb = "A." + version, Version = version, Sxrj = sxrj, DetailCount = detail };
  13. private static readonly DateTime Ref = new(2026, 9, 1);
  14. [Fact]
  15. public void Matched_SingleEffectiveWjbh()
  16. {
  17. var r = S6ProcessSpecResolver.Decide(new[] { C(101, "UATD-GC-001", 1, "2026-08-28", 2) }, Ref);
  18. Assert.Equal(S6SpecResolveStatus.Matched, r.Status);
  19. Assert.Equal(101, r.MatchedSpecId);
  20. Assert.Equal(1, r.CandidateCount);
  21. }
  22. [Fact]
  23. public void NoMatch_EmptyCandidates()
  24. {
  25. var r = S6ProcessSpecResolver.Decide(System.Array.Empty<S6SpecCandidate>(), Ref);
  26. Assert.Equal(S6SpecResolveStatus.NoMatch, r.Status);
  27. }
  28. [Fact]
  29. public void Ambiguous_TwoDistinctWjbhBothEffective()
  30. {
  31. var r = S6ProcessSpecResolver.Decide(new[]
  32. {
  33. C(201, "UATD-GC-002", 1, "2026-08-28", 2),
  34. C(202, "UATD-GC-006", 1, "2026-08-28", 2),
  35. }, Ref);
  36. Assert.Equal(S6SpecResolveStatus.Ambiguous, r.Status);
  37. Assert.Equal(2, r.CandidateCount);
  38. Assert.Null(r.MatchedSpecId);
  39. }
  40. [Fact]
  41. public void Version_SameWjbhPicksNewestEffective()
  42. {
  43. var r = S6ProcessSpecResolver.Decide(new[]
  44. {
  45. C(301, "UATD-GC-003", 1, "2026-08-28", 2),
  46. C(302, "UATD-GC-003", 2, "2026-08-29", 2),
  47. }, Ref);
  48. Assert.Equal(S6SpecResolveStatus.Matched, r.Status);
  49. Assert.Equal(302, r.MatchedSpecId); // 同 wjbh 取 sxrj 最新版本
  50. Assert.Equal(1, r.CandidateCount);
  51. }
  52. [Fact]
  53. public void InvalidSpec_MatchedButNoDetail()
  54. {
  55. var r = S6ProcessSpecResolver.Decide(new[] { C(401, "UATD-GC-009", 1, "2026-08-28", 0) }, Ref);
  56. Assert.Equal(S6SpecResolveStatus.InvalidSpec, r.Status);
  57. }
  58. [Fact]
  59. public void NoMatch_OnlyFutureEffective()
  60. {
  61. var r = S6ProcessSpecResolver.Decide(new[] { C(501, "UATD-GC-010", 1, "2027-01-01", 2) }, Ref);
  62. Assert.Equal(S6SpecResolveStatus.NoMatch, r.Status);
  63. }
  64. [Fact]
  65. public void NormalizeDate_HandlesFreeTextFormats()
  66. {
  67. Assert.NotNull(S6ProcessSpecResolver.NormalizeDate("2026-08-28"));
  68. Assert.NotNull(S6ProcessSpecResolver.NormalizeDate("2025.12.12"));
  69. Assert.NotNull(S6ProcessSpecResolver.NormalizeDate("2025-05-28 00:00:00"));
  70. Assert.Null(S6ProcessSpecResolver.NormalizeDate(""));
  71. Assert.Null(S6ProcessSpecResolver.NormalizeDate("包装(灭菌类)"));
  72. }
  73. [Fact]
  74. public void Tokenize_SplitsMixedDelimiters()
  75. {
  76. var t = S6ProcessSpecResolver.Tokenize("91HC1N7;91HC1N8,98BC19A、982C01911 91HC12N");
  77. Assert.Contains("91HC1N7", t);
  78. Assert.Contains("98BC19A", t);
  79. Assert.Contains("982C01911", t);
  80. Assert.Equal(5, t.Count);
  81. }
  82. }