aboutsummaryrefslogtreecommitdiffziptar.gz
path: root/src/Godosa.Core.Tests/Runs/Scripts/ConditionTests.cs
blob: d14ea6acb53c4bd391594c30403354a20ef42715 (plain)
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
using Godosa.Core.Runs.Scripts;
using Xunit;

namespace Godosa.Core.Tests.Runs.Scripts;

public class ConditionTests
{
    private sealed class Ctx : IConditionContext
    {
        public Dictionary<string, RunValue> Values { get; } = new()
        {
            ["quest(1)"] = RunValue.Of(2), ["map"] = RunValue.Of("tarant"), ["dialog-open"] = RunValue.Of(true),
            ["global(gold)"] = RunValue.Of(500), ["alive"] = RunValue.Of(false),
        };

        public bool HasProbe(string name) => name is "quest" or "map" or "dialog-open" or "global" or "alive";

        public RunValue Probe(string name, IReadOnlyList<string> args) =>
            Values[args.Count == 0 ? name : $"{name}({string.Join(",", args)})"];

        public long? Constant(string name) => name switch { "accepted" => 2, "completed" => 4, _ => null };
    }

    private static bool Test(string text) => ConditionParser.Parse(text).Test(new Ctx());

    [Theory]
    [InlineData("quest(1) >= accepted", true)]
    [InlineData("quest(1) = completed", false)]
    [InlineData("map = \"tarant\"", true)]
    [InlineData("map != \"ashbury\"", true)]
    [InlineData("dialog-open", true)]
    [InlineData("alive", false)]
    [InlineData("not alive", true)]
    [InlineData("dialog-open and global(gold) > 499", true)]
    [InlineData("alive or global(gold) < 100", false)]
    [InlineData("not (alive or dialog-open)", false)]
    [InlineData("alive or dialog-open and quest(1) = 2", true)] // and binds tighter than or
    [InlineData("global(gold) <= 500", true)]
    public void Evaluates(string text, bool expected) => Assert.Equal(expected, Test(text));

    [Fact]
    public void MismatchedTypes_Fault() =>
        Assert.Equal("cannot compare tarant with 3", Assert.Throws<ScriptFault>(() => Test("map > 3")).Message);

    [Theory]
    [InlineData("quest(1) >=")]
    [InlineData("(alive")]
    [InlineData("alive alive")]
    [InlineData("\"open")]
    public void BadSyntax_Throws(string text) => Assert.Throws<FormatException>(() => ConditionParser.Parse(text));

    [Fact]
    public void ListsProbesAndBareNames()
    {
        var c = ConditionParser.Parse("quest(1) >= accepted and not dialog-open");
        Assert.Equal(["quest(1)", "accepted", "dialog-open"], c.Probes().Select(p => p.Args.Count == 0 ? p.Name : $"{p.Name}({string.Join(",", p.Args)})"));
        Assert.Equal(["accepted", "dialog-open"], c.Bare());
    }

    [Fact]
    public void Describe_ListsProbeValues() =>
        Assert.Equal("quest(1)=2 map=tarant", Cond.Describe(ConditionParser.Parse("quest(1) > 3 and map = \"x\""), new Ctx()));
}