godosa-engine

git clone https://git.godosa.eu/godosa-engine

master

raw ยท 3270 bytes

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()"));
}