using Godosa.Core.Runs.Scripts;
using Xunit;
namespace Godosa.Core.Tests.Runs.Scripts;
public class ScriptValidatorTests
{
private static FakeGame Game()
{
var g = new FakeGame();
g.ProbeFns["quest"] = _ => RunValue.Of(0);
g.ProbeFns["dialog-open"] = _ => RunValue.Of(false);
g.ActionTable["talk"] = new FakeAction(VerbKind.Player, _ => new ActionStart(), min: 1, max: 1);
g.ActionTable["cheat"] = new FakeAction(VerbKind.Debug, _ => new ActionStart(Status: StepStatus.Done), min: 1, max: 20);
return g;
}
private static string Validate(string main, bool deterministic = true, FakeGame? game = null) =>
string.Join(" | ", ScriptValidator.Validate(
ScriptLoader.Load("main.steps", new MemoryScriptSource(new Dictionary<string, string> { ["main.steps"] = main }), new Dictionary<string, string>()),
game ?? Game(), deterministic).Select(e => e.ToString()));
[Fact]
public void ValidPlayerScript_NoErrors() =>
Assert.Equal("", Validate("format 1\nmode player\nsetup:\n cheat gold 5\ntalk @obj(Virgil)\nwait dialog-open 2s\nexpect quest(1) >= accepted\nclick 1,2\nkey R\nlog \"hi\""));
[Theory]
[InlineData("format 1\nmode player\ndance", "main.steps:3: unknown verb dance")]
[InlineData("format 1\nmode player\nwalk-to 3,4", "main.steps:3: verb walk-to not supported by game fake")]
[InlineData("format 1\nmode player\nclick", "main.steps:3: verb click takes 1..1 arguments, got 0")]
[InlineData("format 1\nmode player\ncheat gold 5", "main.steps:3: debug verb cheat outside setup in player mode")]
[InlineData("format 1\nmode player\nwait nope 10", "main.steps:3: unknown probe or constant nope")]
[InlineData("format 1\nmode player\nexpect quest(1) >=", "main.steps:3: condition ends early")]
[InlineData("format 1\nmode player\ntalk @npc(Virgil)", "main.steps:3: unknown locator @npc")]
[InlineData("format 1\nmode player\ntry:\n key R", "main.steps:3: try needs a non-deterministic run")]
[InlineData("format 1\nmode player\noutput loud", "main.steps:3: output level must be quiet|checkpoints|labels|steps|trace")]
public void Errors(string main, string error) => Assert.Contains(error, Validate(main));
[Fact]
public void DebugMode_DebugVerbAnywhere() => Assert.Equal("", Validate("format 1\nmode debug\ncheat gold 5\nkey R"));
[Fact]
public void Try_AllowedNonDeterministic() => Assert.Equal("", Validate("format 1\nmode player\ntry:\n key R", deterministic: false));
[Fact]
public void Rng_NeedsTheGameHook()
{
var g = Game();
g.RngImpl = null;
Assert.Contains("main.steps:3: verb rng not supported by game fake", Validate("format 1\nmode player\nrng seed 4", game: g));
}
[Fact]
public void GameVerb_ShadowingALibVerbWithAnotherKind_Rejected()
{
var g = Game();
g.ActionTable["click"] = new FakeAction(VerbKind.Debug, _ => new ActionStart());
Assert.Contains("game verb click shadows a lib verb", Validate("format 1\nmode debug\nkey R", game: g));
}
[Fact]
public void LoaderErrorsComeThrough() => Assert.Contains("main.steps:3: unknown def x", Validate("format 1\nmode debug\ncall x()"));
}