1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
using System.Text.Json;
using Godosa.Core.Runs;
using Godosa.Core.Runs.Scripts;
using Xunit;
namespace Godosa.Core.Tests.Runs.Scripts;
public sealed class RunReportTests : IDisposable
{
private readonly string _dir = Path.Combine(AppContext.BaseDirectory, "rs-tmp", Guid.NewGuid().ToString("N"));
public void Dispose()
{
if (Directory.Exists(_dir))
Directory.Delete(_dir, recursive: true);
}
private static (ScriptRunner Runner, RunResult Result, List<string> Output) Run(string main, FakeGame g, ScriptRunOptions o, Dictionary<string, string>? files = null)
{
var all = new Dictionary<string, string>(files ?? []) { ["main.steps"] = main };
var output = new List<string>();
var runner = new ScriptRunner(ScriptLoader.Load("main.steps", new MemoryScriptSource(all), new Dictionary<string, string>()), g, o, output.Add);
return (runner, runner.Run(10_000), output);
}
[Fact]
public void Failure_ReportHoldsChainStepReasonRecentDumpVars()
{
var g = new FakeGame { State = 7 };
g.ProbeFns["quest"] = _ => RunValue.Of(1);
var (runner, _, _) = Run("format 1\nmode player\nset who = Gilbert\nkey A\ninclude act2.steps", g, new ScriptRunOptions { ReportDir = _dir },
new() { ["act2.steps"] = "format 1\nstep talk-gilbert:\n key B\n expect quest(5) >= accepted" });
var f = runner.Report!.Failure!;
Assert.Equal("act2.steps:4", f.At);
Assert.Equal(["main.steps:5"], f.Chain);
Assert.Equal(("expect quest(5) >= accepted", "talk-gilbert"), (f.Step, f.Label));
Assert.Equal("expect failed: quest(5) >= accepted (quest(5)=1)", f.Reason);
Assert.Equal(["main.steps:4 key A f=2", "act2.steps:3 key B f=4"], f.Recent);
Assert.Equal("state=7 frame=4", f.Dump);
Assert.Equal("Gilbert", f.Vars["who"]);
Assert.True(File.Exists(Path.Combine(_dir, "report.txt")));
Assert.True(File.Exists(Path.Combine(_dir, "fail.snap")));
var json = JsonDocument.Parse(File.ReadAllText(Path.Combine(_dir, "report.json")));
Assert.Equal("Failed", json.RootElement.GetProperty("Outcome").GetString());
var text = File.ReadAllText(Path.Combine(_dir, "report.txt"));
Assert.Contains("main.steps:5 → act2.steps:4", text);
Assert.Contains("state=7 frame=4", text);
}
[Fact]
public void Recent_KeepsLast20()
{
var g = new FakeGame();
g.ProbeFns["no"] = _ => RunValue.Of(false);
var steps = string.Join("\n", Enumerable.Range(1, 25).Select(n => $"key K{n}"));
var (runner, _, _) = Run($"format 1\nmode player\n{steps}\nexpect no", g, new ScriptRunOptions());
var recent = runner.Report!.Failure!.Recent;
Assert.Equal(20, recent.Count);
Assert.StartsWith("main.steps:8 key K6", recent[0]);
}
[Fact]
public void Summary_StepsFramesCheckpointsDigests()
{
var g = new FakeGame { State = 3 };
var (runner, r, output) = Run("format 1\nmode player\nkey A\ncheckpoint one\nstep s:\n key B", g, new ScriptRunOptions { Seed = 9 });
var rep = runner.Report!;
Assert.Equal((RunOutcome.Passed, 4L, 2, 9UL), (rep.Outcome, rep.Frames, rep.Steps, rep.Seed));
// Digest = State * 1_000_003 + Frame (FakeGame), at frame 2: 3 * 1000003 + 2 = 3000011.
Assert.Equal([new CheckpointRecord("one", 2, 3000011UL.ToString("x16"), "replayed")], rep.Checkpoints);
Assert.Contains(DigestLine.Format(2, 2 / 60.0, 3000011UL), output);
Assert.Contains(DigestLine.Format(4, 4 / 60.0, 3000013UL), output); // after the labelled step
}
[Fact]
public void NonDeterministic_NoDigestLines_FlagInReport()
{
var (runner, _, output) = Run("format 1\nmode player\ncheckpoint one", new FakeGame(), new ScriptRunOptions { Deterministic = false });
Assert.DoesNotContain(output, l => l.StartsWith("digest "));
Assert.False(runner.Report!.Deterministic);
Assert.Contains("deterministic: no", ReportWriter.Text(runner.Report));
}
}
|