From 39066900773e7857faf2d02e7ed51b71d219d97d Mon Sep 17 00:00:00 2001 From: godosa Date: Tue, 6 Oct 2026 23:39:36 +0200 Subject: godosa-engine: initial public history --- src/Godosa.Core.Tests/Runs/RunsTests.cs | 149 ++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 src/Godosa.Core.Tests/Runs/RunsTests.cs (limited to 'src/Godosa.Core.Tests/Runs/RunsTests.cs') diff --git a/src/Godosa.Core.Tests/Runs/RunsTests.cs b/src/Godosa.Core.Tests/Runs/RunsTests.cs new file mode 100644 index 0000000..1b6d6d4 --- /dev/null +++ b/src/Godosa.Core.Tests/Runs/RunsTests.cs @@ -0,0 +1,149 @@ +using Godosa.Core.Runs; +using Xunit; + +namespace Godosa.Core.Tests.Runs; + +public class RunsTests +{ + private static RunFlags Parse(params string[] args) + { + var flags = new RunFlags(); + for (var i = 0; i < args.Length; i++) + Assert.True(RunFlags.TryTake(args, ref i, ref flags), args[i]); + return flags; + } + + [Fact] + public void Flags_DeterministicWithAndWithoutSeed() + { + Assert.Equal(new RunFlags(Deterministic: true, Seed: 7), Parse("--deterministic", "7")); + Assert.Equal(new RunFlags(Deterministic: true), Parse("--deterministic")); + Assert.Equal(1UL, Parse("--deterministic").SeedOr(1)); + Assert.Equal(7UL, Parse("--deterministic", "7").SeedOr(1)); + } + + [Fact] + public void Flags_SeedNotTakenWhenNextIsAnOption() + { + string[] args = ["--deterministic", "--mute"]; + var flags = new RunFlags(); + var i = 0; + Assert.True(RunFlags.TryTake(args, ref i, ref flags)); + Assert.Equal(0, i); + i = 1; + Assert.False(RunFlags.TryTake(args, ref i, ref flags)); + } + + [Fact] + public void Flags_DigestEveryAndHeadless() + { + Assert.Equal(new RunFlags(Digest: true), Parse("--digest")); + Assert.Equal(new RunFlags(Digest: true, DigestEvery: 60), Parse("--digest", "every=60")); + Assert.Equal(new RunFlags(Deterministic: true, Headless: true), Parse("--headless")); + Assert.Equal(new RunFlags(Deterministic: true, Seed: 3, Headless: true), Parse("--headless", "--deterministic", "3")); + } + + [Fact] + public void Flags_BadDigestEvery_Throws() => + Assert.Throws(() => Parse("--digest", "every=0")); + + [Fact] + public void Clock_DeterministicFixedStep() + { + var clock = new FrameClock(true); + Assert.Equal(1.0 / 60, clock.Next(0.5)); + Assert.Equal(1.0 / 60, clock.Next(0.001)); + Assert.Equal(2, clock.Frame); + Assert.Equal(2.0 / 60, clock.Seconds, 12); + } + + [Fact] + public void Clock_WallClamped() + { + var clock = new FrameClock(false); + Assert.Equal(0.1, clock.Next(0.5)); + Assert.Equal(0.02, clock.Next(0.02)); + Assert.Equal(0, clock.Next(-1)); + Assert.Equal(3, clock.Frame); + } + + [Fact] + public void Clock_Held_NoTimeNoFrame() + { + var clock = new FrameClock(true) { Held = true }; + Assert.Equal(0, clock.Next(1.0 / 60)); + Assert.Equal(0, clock.Frame); + Assert.Equal(0, clock.Seconds); + clock.Held = false; + clock.Next(0); + Assert.Equal(1, clock.Frame); + } + + // Published FNV-1a 64 vectors (isthe.com/chongo/tech/comp/fnv). + [Theory] + [InlineData("", 0xcbf29ce484222325UL)] + [InlineData("a", 0xaf63dc4c8601ec8cUL)] + [InlineData("foobar", 0x85944171f73967e8UL)] + public void Digest_FnvVectors(string text, ulong expected) + { + var d = new StateDigest(); + d.Add(text); + Assert.Equal(expected, d.Value); + Assert.Equal(expected, StateDigest.Of(System.Text.Encoding.UTF8.GetBytes(text))); + } + + // Hand-checked: FNV-1a 64 of the little-endian bytes 01 00 00 00 and of 1.5 as an IEEE double. + [Fact] + public void Digest_NumbersLittleEndian() + { + var u = new StateDigest(); + u.Add(1u); + Assert.Equal(0xad2aca7747985764UL, u.Value); + var d = new StateDigest(); + d.Add(1.5); + Assert.Equal(0xaa95e93229a27c80UL, d.Value); + Assert.Equal("aa95e93229a27c80", d.Hex); + } + + [Fact] + public void Line_Format() => + Assert.Equal("digest 120 3.5 000000000000beef", DigestLine.Format(120, 3.5, 0xbeef)); + + [Fact] + public void Line_FormatRoundsGameTime() => + Assert.Equal("digest 1 0.017 0000000000000001", DigestLine.Format(1, 1.0 / 60, 1)); + + [Fact] + public void Line_Due() + { + Assert.True(DigestLine.Due(60, 60)); + Assert.False(DigestLine.Due(59, 60)); + Assert.False(DigestLine.Due(0, 60)); + Assert.False(DigestLine.Due(60, 0)); + } + + // SplitMix64 seeded 0: outputs e220a8397b1dcdaf, 6e789e6aa1b965f4 (published reference sequence). + [Fact] + public void Seeds_SplitMixReference() + { + Assert.Equal(0xe220a8397b1dcdafUL, SeedStreams.Of(0, 0)); + Assert.Equal(0x6e789e6aa1b965f4UL, SeedStreams.Of(0, 1)); + Assert.Equal(0x63cbe1e459320dd7UL, SeedStreams.Of(7, 0)); + } + + [Fact] + public void Loop_StopsWhenFrameReturnsFalse() + { + var seen = new List(); + var (frames, capped) = HeadlessLoop.Run(n => { seen.Add(n); return n < 3; }, null); + Assert.Equal([1L, 2, 3], seen); + Assert.Equal(3, frames); + Assert.False(capped); + } + + [Fact] + public void Loop_FramesLimit() => Assert.Equal((5L, false), HeadlessLoop.Run(_ => true, 5)); + + [Fact] + public void Loop_Cap() => Assert.Equal((10L, true), HeadlessLoop.Run(_ => true, null, cap: 10)); +} -- cgit