Compare commits

...

2 Commits

Author SHA1 Message Date
Tim Van Baak 512c91d2de Add unit test for testing the repl 2024-08-27 04:18:36 +00:00
Tim Van Baak 416f2aa919 Rename to OrderParser 2024-08-27 03:23:28 +00:00
7 changed files with 110 additions and 16 deletions

View File

@ -10,7 +10,7 @@ namespace MultiversalDiplomacy.Model;
/// and other script inputs. It also provides helper functions to extract the captured order elements as tuples, /// and other script inputs. It also provides helper functions to extract the captured order elements as tuples,
/// which function as the structured intermediate representation between raw user input and full Order objects. /// which function as the structured intermediate representation between raw user input and full Order objects.
/// </summary> /// </summary>
public class OrderRegex(World world) public class OrderParser(World world)
{ {
public const string Type = "(A|F|Army|Fleet)"; public const string Type = "(A|F|Army|Fleet)";
@ -34,6 +34,15 @@ public class OrderRegex(World world)
public const string ViaConvoy = "(convoy|via convoy|by convoy)"; public const string ViaConvoy = "(convoy|via convoy|by convoy)";
public Regex PowerCommand = new($"^{world.Map.PowerRegex}(?:[:])? (.*)$");
public static (
string power,
string command)
ParsePowerCommand(Match match) => (
match.Groups[1].Value,
match.Groups[2].Value);
public Regex Hold => new( public Regex Hold => new(
$"^{UnitSpec} {HoldVerb}$", $"^{UnitSpec} {HoldVerb}$",
RegexOptions.IgnoreCase); RegexOptions.IgnoreCase);
@ -197,7 +206,7 @@ public class OrderRegex(World world)
public static bool TryParseOrder(World world, string power, string command, [NotNullWhen(true)] out Order? order) { public static bool TryParseOrder(World world, string power, string command, [NotNullWhen(true)] out Order? order) {
order = null; order = null;
OrderRegex re = new(world); OrderParser re = new(world);
if (re.Hold.Match(command) is Match holdMatch && holdMatch.Success) { if (re.Hold.Match(command) is Match holdMatch && holdMatch.Success) {
return TryParseHoldOrder(world, power, holdMatch, out order); return TryParseHoldOrder(world, power, holdMatch, out order);

View File

@ -36,8 +36,7 @@ public class AdjudicationQueryScriptHandler(World world, bool strict = false) :
case "assert": case "assert":
string assertion = input["assert ".Length..]; string assertion = input["assert ".Length..];
OrderRegex re = new(World); Regex prov = new($"{World.Map.ProvinceRegex} (.*)");
Regex prov = new($"{re.Province} (.*)");
Match match = prov.Match(assertion); Match match = prov.Match(assertion);
if (!match.Success) { if (!match.Success) {
Console.WriteLine($"Could not parse province from \"{assertion}\""); Console.WriteLine($"Could not parse province from \"{assertion}\"");

View File

@ -69,7 +69,7 @@ public class GameScriptHandler(World world, bool strict = false) : IScriptHandle
orderText = match.Groups[2].Value; orderText = match.Groups[2].Value;
} }
if (OrderRegex.TryParseOrder(World, orderPower, orderText, out Order? order)) { if (OrderParser.TryParseOrder(World, orderPower, orderText, out Order? order)) {
Console.WriteLine($"Parsed {orderPower} order \"{orderText}\" but doing anything with it isn't implemented yet"); Console.WriteLine($"Parsed {orderPower} order \"{orderText}\" but doing anything with it isn't implemented yet");
return this; return this;
} }

View File

@ -74,7 +74,7 @@ public class SetupScriptHandler(World world, bool strict = false) : IScriptHandl
case "unit": case "unit":
string unitSpec = input["unit ".Length..]; string unitSpec = input["unit ".Length..];
if (OrderRegex.TryParseUnit(World, unitSpec, out Unit? newUnit)) { if (OrderParser.TryParseUnit(World, unitSpec, out Unit? newUnit)) {
World = World.Update(units: World.Units.Append(newUnit)); World = World.Update(units: World.Units.Append(newUnit));
Console.WriteLine($"Created {newUnit}"); Console.WriteLine($"Created {newUnit}");
return this; return this;

View File

@ -41,10 +41,10 @@ public class RegexTest
[TestCaseSource(nameof(HoldRegexMatchesTestCases))] [TestCaseSource(nameof(HoldRegexMatchesTestCases))]
public void HoldRegexMatches(string order, string[] expected) public void HoldRegexMatches(string order, string[] expected)
{ {
OrderRegex re = new(World.WithStandardMap()); OrderParser re = new(World.WithStandardMap());
var match = re.Hold.Match(order); var match = re.Hold.Match(order);
Assert.True(match.Success, "Match failed"); Assert.True(match.Success, "Match failed");
var (type, timeline, province, location, turn, holdVerb) = OrderRegex.ParseHold(match); var (type, timeline, province, location, turn, holdVerb) = OrderParser.ParseHold(match);
string[] actual = [type, timeline, province, location, turn, holdVerb]; string[] actual = [type, timeline, province, location, turn, holdVerb];
// Use EquivalentTo for more detailed error message // Use EquivalentTo for more detailed error message
Assert.That(actual, Is.EquivalentTo(expected), "Unexpected parse results"); Assert.That(actual, Is.EquivalentTo(expected), "Unexpected parse results");
@ -94,11 +94,11 @@ public class RegexTest
[TestCaseSource(nameof(MoveRegexMatchesTestCases))] [TestCaseSource(nameof(MoveRegexMatchesTestCases))]
public void MoveRegexMatches(string order, string[] expected) public void MoveRegexMatches(string order, string[] expected)
{ {
OrderRegex re = new(World.WithStandardMap()); OrderParser re = new(World.WithStandardMap());
var match = re.Move.Match(order); var match = re.Move.Match(order);
Assert.True(match.Success, "Match failed"); Assert.True(match.Success, "Match failed");
var (type, timeline, province, location, turn, moveVerb, var (type, timeline, province, location, turn, moveVerb,
destTimeline, destProvince, destLocation, destTurn, viaConvoy) = OrderRegex.ParseMove(match); destTimeline, destProvince, destLocation, destTurn, viaConvoy) = OrderParser.ParseMove(match);
string[] actual = [type, timeline, province, location, turn, moveVerb, string[] actual = [type, timeline, province, location, turn, moveVerb,
destTimeline, destProvince, destLocation, destTurn, viaConvoy]; destTimeline, destProvince, destLocation, destTurn, viaConvoy];
// Use EquivalentTo for more detailed error message // Use EquivalentTo for more detailed error message
@ -145,11 +145,11 @@ public class RegexTest
[TestCaseSource(nameof(SupportHoldRegexMatchesTestCases))] [TestCaseSource(nameof(SupportHoldRegexMatchesTestCases))]
public void SupportHoldRegexMatches(string order, string[] expected) public void SupportHoldRegexMatches(string order, string[] expected)
{ {
OrderRegex re = new(World.WithStandardMap()); OrderParser re = new(World.WithStandardMap());
var match = re.SupportHold.Match(order); var match = re.SupportHold.Match(order);
Assert.True(match.Success, "Match failed"); Assert.True(match.Success, "Match failed");
var (type, timeline, province, location, turn, supportVerb, var (type, timeline, province, location, turn, supportVerb,
targetType, targetTimeline, targetProvince, targetLocation, targetTurn) = OrderRegex.ParseSupportHold(match); targetType, targetTimeline, targetProvince, targetLocation, targetTurn) = OrderParser.ParseSupportHold(match);
string[] actual = [type, timeline, province, location, turn, supportVerb, string[] actual = [type, timeline, province, location, turn, supportVerb,
targetType, targetTimeline, targetProvince, targetLocation, targetTurn]; targetType, targetTimeline, targetProvince, targetLocation, targetTurn];
// Use EquivalentTo for more detailed error message // Use EquivalentTo for more detailed error message
@ -184,12 +184,12 @@ public class RegexTest
[TestCaseSource(nameof(SupportMoveRegexMatchesTestCases))] [TestCaseSource(nameof(SupportMoveRegexMatchesTestCases))]
public void SupportMoveRegexMatches(string order, string[] expected) public void SupportMoveRegexMatches(string order, string[] expected)
{ {
OrderRegex re = new(World.WithStandardMap()); OrderParser re = new(World.WithStandardMap());
var match = re.SupportMove.Match(order); var match = re.SupportMove.Match(order);
Assert.True(match.Success, "Match failed"); Assert.True(match.Success, "Match failed");
var (type, timeline, province, location, turn, supportVerb, var (type, timeline, province, location, turn, supportVerb,
targetType, targetTimeline, targetProvince, targetLocation, targetTurn, moveVerb, targetType, targetTimeline, targetProvince, targetLocation, targetTurn, moveVerb,
destTimeline, destProvince, destLocation, destTurn) = OrderRegex.ParseSupportMove(match); destTimeline, destProvince, destLocation, destTurn) = OrderParser.ParseSupportMove(match);
string[] actual = [type, timeline, province, location, turn, supportVerb, string[] actual = [type, timeline, province, location, turn, supportVerb,
targetType, targetTimeline, targetProvince, targetLocation, targetTurn, moveVerb, targetType, targetTimeline, targetProvince, targetLocation, targetTurn, moveVerb,
destTimeline, destProvince, destLocation, destTurn]; destTimeline, destProvince, destLocation, destTurn];
@ -202,10 +202,10 @@ public class RegexTest
public void OrderParsingTest() public void OrderParsingTest()
{ {
World world = World.WithStandardMap().AddUnits("Germany A Mun"); World world = World.WithStandardMap().AddUnits("Germany A Mun");
OrderRegex re = new(world); OrderParser re = new(world);
var match = re.Move.Match("A Mun - Tyr"); var match = re.Move.Match("A Mun - Tyr");
var success = OrderRegex.TryParseMoveOrder(world, "Germany", match, out Order? order); var success = OrderParser.TryParseMoveOrder(world, "Germany", match, out Order? order);
Assert.That(success, Is.True); Assert.That(success, Is.True);
Assert.That(order, Is.TypeOf<MoveOrder>()); Assert.That(order, Is.TypeOf<MoveOrder>());

View File

@ -0,0 +1,51 @@
using NUnit.Framework;
using MultiversalDiplomacy.Script;
namespace MultiversalDiplomacyTests;
public class ReplDriver(IScriptHandler initialHandler, bool echo = false)
{
public IScriptHandler? Handler { get; private set; } = initialHandler;
private string? LastInput { get; set; } = "";
/// <summary>
/// Whether to print the inputs as they are executed. This is primarily a debugging aid.
/// </summary>
bool Echo { get; } = echo;
/// <summary>
/// Input a multiline string into the repl. Call <see cref="Ready"/> or <see cref="Closed"/> at the end so the
/// statement is valid.
/// </summary>
public ReplDriver this[string input] => ExecuteAll(input);
public ReplDriver ExecuteAll(string multiline)
{
var lines = multiline.Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
return lines.Aggregate(this, (repl, line) => repl.Execute(line));
}
public ReplDriver Execute(string inputLine)
{
if (Handler is null) throw new AssertionException(
$"Cannot execute \"{inputLine}\", handler quit. Last input was \"{LastInput}\"");
if (Echo) Console.WriteLine($"{Handler.Prompt}{inputLine}");
Handler = Handler.HandleInput(inputLine);
LastInput = inputLine;
return this;
}
public void Ready()
{
Assert.That(Handler, Is.Not.Null, "Handler is closed");
}
public void Closed()
{
Assert.That(Handler, Is.Null, "Handler is not closed");
}
}

View File

@ -0,0 +1,35 @@
using NUnit.Framework;
using MultiversalDiplomacy.Model;
using MultiversalDiplomacy.Script;
namespace MultiversalDiplomacyTests;
public class ReplTest
{
[Test]
public void SetupHandler()
{
SetupScriptHandler setup = new(World.WithStandardMap(), strict: true);
ReplDriver repl = new(setup);
repl["""
unit Germany A Munich
unit Austria Army Tyrolia
unit England F London
"""].Ready();
Assert.That(repl.Handler, Is.TypeOf<SetupScriptHandler>());
SetupScriptHandler handler = (SetupScriptHandler)repl.Handler!;
Assert.That(handler.World.Units.Count, Is.EqualTo(3));
Assert.That(handler.World.GetUnitAt("Mun"), Is.Not.Null);
Assert.That(handler.World.GetUnitAt("Tyr"), Is.Not.Null);
Assert.That(handler.World.GetUnitAt("Lon"), Is.Not.Null);
repl["""
---
"""].Ready();
Assert.That(repl.Handler, Is.TypeOf<GameScriptHandler>());
}
}