diff options
Diffstat (limited to 'src/LivingVillage.Desktop.Tests')
| -rw-r--r-- | src/LivingVillage.Desktop.Tests/LivingVillage.Desktop.Tests.fsproj | 1 | ||||
| -rw-r--r-- | src/LivingVillage.Desktop.Tests/M3BatchOutputTests.fs | 84 |
2 files changed, 85 insertions, 0 deletions
diff --git a/src/LivingVillage.Desktop.Tests/LivingVillage.Desktop.Tests.fsproj b/src/LivingVillage.Desktop.Tests/LivingVillage.Desktop.Tests.fsproj index b1b0ac2..a8aac24 100644 --- a/src/LivingVillage.Desktop.Tests/LivingVillage.Desktop.Tests.fsproj +++ b/src/LivingVillage.Desktop.Tests/LivingVillage.Desktop.Tests.fsproj @@ -10,6 +10,7 @@ <Compile Include="M6aTests.fs" /> <Compile Include="M6bTests.fs" /> <Compile Include="PrototypeTests.fs" /> + <Compile Include="M3BatchOutputTests.fs" /> <Compile Include="SampleTests.fs" /> </ItemGroup> diff --git a/src/LivingVillage.Desktop.Tests/M3BatchOutputTests.fs b/src/LivingVillage.Desktop.Tests/M3BatchOutputTests.fs new file mode 100644 index 0000000..e962e57 --- /dev/null +++ b/src/LivingVillage.Desktop.Tests/M3BatchOutputTests.fs @@ -0,0 +1,84 @@ +namespace LivingVillage.Desktop.Tests + +open System.Threading +open System.Threading.Tasks +open Microsoft.VisualStudio.TestTools.UnitTesting +open LivingVillage.Headless + +/// M3-1 可观测性回归:批次输出格式与逐世界流式驱动。 +[<TestClass>] +type M3BatchOutputTests () = + + let sampleBase = + "world=3 seed=45 chats_max=9 chats_avg=2.00 ratio=4.500 gini=0.100 relcnt_max=5 relcnt_min=1 relconn=6/6 nonfinite=0 check_a=PASS check_b=PASS check_c=PASS old_crit=PASS OK" + + [<TestMethod>] + member _.WorldLineKeepsPrefixAndAppendsElapsed () = + let line = BatchOutput.worldLine sampleBase 123.4 + Assert.IsTrue(line.StartsWith("world=3 seed=45 "), "world 行前缀必须保持不变") + Assert.IsTrue(line.StartsWith(sampleBase), "判据字段必须原样保留") + Assert.IsTrue(line.EndsWith("elapsed_s=123.4"), "耗时字段追加在行尾") + // 旧判据 token 仍在(监督器据此判定 OK)。 + Assert.AreEqual<string>(sampleBase + " elapsed_s=123.4", line) + + [<TestMethod>] + member _.DoneLineReportsProgressAndElapsed () = + Assert.AreEqual<string>("[done 2/4] elapsed=12.3s world=1", BatchOutput.doneLine 2 4 12.3 1) + Assert.AreEqual<string>("[done 4/4] elapsed=600.0s world=3", BatchOutput.doneLine 4 4 600.0 3) + + [<TestMethod>] + member _.SummaryLineKeepsOldFieldsAndAppendsWallClock () = + let line = BatchOutput.summaryLine 4 3 1 4 1.100 9.900 0.010 0.400 4 610.5 + // 监督器正则只读前三个字段,前缀必须逐字保持。 + Assert.IsTrue(line.StartsWith("batch_summary worlds=4 passed=3 failed=1 old_passed=4/4 "), line) + Assert.IsTrue(line.Contains("ratio_min=1.100 ratio_max=9.900 gini_min=0.010 gini_max=0.400"), line) + Assert.IsTrue(line.Contains("elapsed_s=610.5"), line) + Assert.IsTrue(line.EndsWith("workers=4 wall_s=610.5"), line) + + [<TestMethod>] + member _.CostLineDerivesThroughputFromMeasuredTicks () = + let line = BatchOutput.costLine 10L 51840000L 254.0 12345678L 3L 1L 0L + Assert.IsTrue(line.StartsWith("cost days=10 ticks=51840000 elapsed_s=254.000 "), line) + Assert.IsTrue(line.Contains("ticks_per_s=204094.5"), line) + Assert.IsTrue(line.EndsWith("allocated_bytes=12345678 gen0=3 gen1=1 gen2=0"), line) + + [<TestMethod>] + member _.DefaultCostLadderIsOneFiveTenTwentyFiftyHundred () = + CollectionAssert.AreEqual([| 1L; 5L; 10L; 20L; 50L; 100L |], List.toArray BatchOutput.defaultCostLadder) + + [<TestMethod>] + member _.RunStreamingEmitsEachWorldBeforeTheNextStarts () = + // workers=1:每次 work 后必须立刻 emit 该世界(证明不是收完再打印)。 + let events = ResizeArray<string> () + let results = + BatchOutput.runStreaming 3 1 + (fun k -> + lock events (fun () -> events.Add(sprintf "work%d" k)) + k * k) + (fun k _ _ -> + lock events (fun () -> events.Add(sprintf "emit%d" k))) + CollectionAssert.AreEqual([| 0; 1; 4 |], results) + CollectionAssert.AreEqual( + [| "work0"; "emit0"; "work1"; "emit1"; "work2"; "emit2" |], + events.ToArray()) + + [<TestMethod>] + member _.RunStreamingIsCompleteUnderParallelism () = + let total = 12 + let emitted = System.Collections.Concurrent.ConcurrentDictionary<int, int> () + let completions = ResizeArray<int> () + let results = + BatchOutput.runStreaming total 4 + (fun k -> k + 100) + (fun k result doneCount -> + Assert.AreEqual<int>(k + 100, result) + emitted.[k] <- doneCount + lock completions (fun () -> completions.Add doneCount)) + Assert.AreEqual<int>(total, results.Length) + Assert.AreEqual<int>(total, emitted.Count) + for k in 0 .. total - 1 do + Assert.IsTrue(emitted.ContainsKey k, sprintf "world=%d 未 emit" k) + // 完成计数恰为 1..total 的一个排列(并发下不重不漏)。 + CollectionAssert.AreEqual( + [| 1 .. total |], + completions |> Seq.sort |> Seq.toArray) |
