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