From b4f8f621ca4bb33df6aacaf9130a0ff280cc1fc8 Mon Sep 17 00:00:00 2001 From: Tim Van Baak Date: Mon, 26 Aug 2024 15:39:42 +0000 Subject: [PATCH] Add test cases for move order --- MultiversalDiplomacy/Model/Regex.cs | 28 +-- .../Script/GameScriptHandler.cs | 4 +- MultiversalDiplomacyTests/RegexTest.cs | 163 +++++++++--------- 3 files changed, 99 insertions(+), 96 deletions(-) diff --git a/MultiversalDiplomacy/Model/Regex.cs b/MultiversalDiplomacy/Model/Regex.cs index 28de6a7..e79bc09 100644 --- a/MultiversalDiplomacy/Model/Regex.cs +++ b/MultiversalDiplomacy/Model/Regex.cs @@ -27,7 +27,9 @@ public class OrderRegex(World world) public const string ViaConvoy = "(convoy|via convoy|by convoy)"; - public Regex Hold => new($"^{UnitSpec} {HoldVerb}$", RegexOptions.IgnoreCase); + public Regex Hold => new( + $"^{UnitSpec} {HoldVerb}$", + RegexOptions.IgnoreCase); public static ( string type, @@ -46,10 +48,11 @@ public class OrderRegex(World world) match.Groups[6].Value, match.Groups[7].Value); - public Regex Move => new($"^{UnitSpec} {MoveVerb} {FullLocation}(?: {ViaConvoy})?$"); + public Regex Move => new( + $"^{UnitSpec} {MoveVerb} {FullLocation}(?: {ViaConvoy})?$", + RegexOptions.IgnoreCase); public static ( - string power, string type, string timeline, string province, @@ -65,19 +68,18 @@ public class OrderRegex(World world) match.Groups[1].Value, match.Groups[2].Value, match.Groups[3].Value, - match.Groups[4].Value, - match.Groups[5].Length > 0 - ? match.Groups[5].Value - : match.Groups[6].Value, + match.Groups[4].Length > 0 + ? match.Groups[4].Value + : match.Groups[5].Value, + match.Groups[6].Value, match.Groups[7].Value, match.Groups[8].Value, match.Groups[9].Value, - match.Groups[10].Value, - match.Groups[11].Length > 1 - ? match.Groups[11].Value - : match.Groups[12].Value, - match.Groups[13].Value, - match.Groups[14].Value); + match.Groups[10].Length > 0 + ? match.Groups[10].Value + : match.Groups[11].Value, + match.Groups[12].Value, + match.Groups[13].Value); public static bool TryParseUnit(World world, string unitSpec, [NotNullWhen(true)] out Unit? newUnit) { diff --git a/MultiversalDiplomacy/Script/GameScriptHandler.cs b/MultiversalDiplomacy/Script/GameScriptHandler.cs index 21f1263..1fda3de 100644 --- a/MultiversalDiplomacy/Script/GameScriptHandler.cs +++ b/MultiversalDiplomacy/Script/GameScriptHandler.cs @@ -71,8 +71,8 @@ public class GameScriptHandler(World world, bool strict = false) : IScriptHandle if (OrderRegex.TryParseOrder(World, orderPower, orderText, out Order? order)) { Console.WriteLine($"Parsed {orderPower} order \"{orderText}\" but doing anything with it isn't implemented yet"); - return this; - } + return this; + } Console.WriteLine($"Failed to parse \"{orderText}\""); return Strict ? null : this; diff --git a/MultiversalDiplomacyTests/RegexTest.cs b/MultiversalDiplomacyTests/RegexTest.cs index da327f9..5b10af7 100644 --- a/MultiversalDiplomacyTests/RegexTest.cs +++ b/MultiversalDiplomacyTests/RegexTest.cs @@ -6,95 +6,96 @@ namespace MultiversalDiplomacyTests; public class RegexTest { - [TestCase( - "Army a-Munich/l@0 holds", - ExpectedResult = new string[] {"Army", "a", "Munich", "l", "0", "holds"}, - Description = "Full specification")] - [TestCase( - "fleet B-lon/C@0 H", - ExpectedResult = new string[] {"fleet", "B", "lon", "C", "0", "H"}, - Description = "Case insensitivity")] - [TestCase( - "ROM h", - ExpectedResult = new string[] {"", "", "ROM", "", "", "h"}, - Description = "All optionals missing")] - [TestCase( - "A F-STP hold", - ExpectedResult = new string[] {"A", "F", "STP", "", "", "hold"}, - Description = "No confusion of unit type and timeline")] - [TestCase( - "Fleet North Sea Hold", - ExpectedResult = new string[] {"Fleet", "", "North Sea", "", "", "Hold"}, - Description = "Province with space in name")] - [TestCase( - "F Spain(nc) holds", - ExpectedResult = new string[] {"F", "", "Spain", "nc", "", "holds"}, - Description = "Parenthesis location")] - public string[] HoldRegexMatches(string order) + private static TestCaseData Test(string order, params string[] expected) + => new TestCaseData(order, expected).SetName($"{{m}}(\"{order}\")"); + + static IEnumerable HoldRegexMatchesTestCases() + { + // Full specification + yield return Test( + "Army a-Munich/l@0 holds", + "Army", "a", "Munich", "l", "0", "holds"); + // Case insensitivity + yield return Test( + "fleet B-lon/C@0 H", + "fleet", "B", "lon", "C", "0", "H"); + // All optionals missing + yield return Test( + "ROM h", + "", "", "ROM", "", "", "h"); + // No confusion of unit type and timeline + yield return Test( + "A F-STP hold", + "A", "F", "STP", "", "", "hold"); + // Province with space in name + yield return Test( + "Fleet North Sea Hold", + "Fleet", "", "North Sea", "", "", "Hold"); + // Parenthesis location + yield return Test( + "F Spain(nc) holds", + "F", "", "Spain", "nc", "", "holds"); + } + + [TestCaseSource(nameof(HoldRegexMatchesTestCases))] + public void HoldRegexMatches(string order, string[] expected) { OrderRegex re = new(World.WithStandardMap()); var match = re.Hold.Match(order); Assert.True(match.Success, "Match failed"); var (type, timeline, province, location, turn, holdVerb) = OrderRegex.ParseHold(match); - return [type, timeline, province, location, turn, holdVerb]; + string[] actual = [type, timeline, province, location, turn, holdVerb]; + // Use EquivalentTo for more detailed error message + Assert.That(actual, Is.EquivalentTo(expected), "Unexpected parse results"); + Assert.That(actual, Is.EqualTo(expected), "Unexpected parse results"); } - [Test] - public void UnitTokenizer() + static IEnumerable MoveRegexMatchesTestCases() { - World world = World.WithStandardMap(); - OrderRegex re = new(world); + static TestCaseData Test(string order, params string[] expected) + => new TestCaseData(order, expected).SetName($"{{m}}(\"{order}\")"); + // Full specification + yield return Test( + "Army a-Munich/l@0 - a-Tyrolia/l@0", + "Army", "a", "Munich", "l", "0", "-", "a", "Tyrolia", "l", "0", ""); + // Case insensitivity + yield return Test( + "fleet B-lon/C@0 - B-enc/W@0", + "fleet", "B", "lon", "C", "0", "-", "B", "enc", "W", "0", ""); + // All optionals missing + yield return Test( + "ROM - VIE", + "", "", "ROM", "", "", "-", "", "VIE", "", "", ""); + // No confusion of unit type and timeline + yield return Test( + "A F-STP - MOS", + "A", "F", "STP", "", "", "-", "", "MOS", "", "", ""); + // Elements with spaces + yield return Test( + "Fleet Western Mediterranean Sea moves to Gulf of Lyons via convoy", + "Fleet", "", "Western Mediterranean Sea", "", "", "moves to", "", "Gulf of Lyons", "", "", "via convoy"); + // Parenthesis location + yield return Test( + "F Spain(nc) - Spain(sc)", + "F", "", "Spain", "nc", "", "-", "", "Spain", "sc", "", ""); + // Timeline designation spells out a province + yield return Test( + "A tyr-MUN(vie) - mun-TYR/vie", + "A", "tyr", "MUN", "vie", "", "-", "mun", "TYR", "vie", "", ""); + } - var match = re.Hold.Match("Germany Army a-Munich/l@0 holds"); - Assert.That(match.Success, Is.True); - var hold = OrderRegex.ParseHold(match); - // Assert.That(hold.power, Is.EqualTo("Germany")); - Assert.That(hold.type, Is.EqualTo("Army")); - Assert.That(hold.timeline, Is.EqualTo("a")); - Assert.That(hold.province, Is.EqualTo("Munich")); - Assert.That(hold.location, Is.EqualTo("l")); - Assert.That(hold.turn, Is.EqualTo("0")); - Assert.That(hold.holdVerb, Is.EqualTo("holds")); - - match = re.Hold.Match("F Venice hold"); - Assert.That(match.Success, Is.True); - hold = OrderRegex.ParseHold(match); - // Assert.That(hold.power, Is.Null); - Assert.That(hold.type, Is.EqualTo("F")); - Assert.That(hold.timeline, Is.Null); - Assert.That(hold.province, Is.EqualTo("Venice")); - Assert.That(hold.location, Is.Null); - Assert.That(hold.turn, Is.Null); - Assert.That(hold.holdVerb, Is.EqualTo("hold")); - - match = re.Move.Match("F Gascony - Spain(nc)"); - Assert.That(match.Success, Is.True); - var move = OrderRegex.ParseMove(match); - Assert.That(move.power, Is.Null); - Assert.That(move.type, Is.EqualTo("F")); - Assert.That(move.timeline, Is.Null); - Assert.That(move.province, Is.EqualTo("Gascony")); - Assert.That(move.location, Is.Null); - Assert.That(move.turn, Is.Null); - Assert.That(move.moveVerb, Is.EqualTo("-")); - Assert.That(move.destTimeline, Is.Null); - Assert.That(move.destProvince, Is.EqualTo("Spain")); - Assert.That(move.destLocation, Is.EqualTo("nc")); - Assert.That(move.destTurn, Is.Null); - - match = re.Move.Match("F North Sea - Picardy"); - Assert.That(match.Success, Is.True); - move = OrderRegex.ParseMove(match); - Assert.That(move.power, Is.Null); - Assert.That(move.type, Is.EqualTo("F")); - Assert.That(move.timeline, Is.Null); - Assert.That(move.province, Is.EqualTo("North Sea")); - Assert.That(move.location, Is.Null); - Assert.That(move.turn, Is.Null); - Assert.That(move.moveVerb, Is.EqualTo("-")); - Assert.That(move.destTimeline, Is.Null); - Assert.That(move.destProvince, Is.EqualTo("Picardy")); - Assert.That(move.destLocation, Is.Null); - Assert.That(move.destTurn, Is.Null); + [TestCaseSource(nameof(MoveRegexMatchesTestCases))] + public void MoveRegexMatches(string order, string[] expected) + { + OrderRegex re = new(World.WithStandardMap()); + var match = re.Move.Match(order); + Assert.True(match.Success, "Match failed"); + var (type, timeline, province, location, turn, moveVerb, + destTimeline, destProvince, destLocation, destTurn, viaConvoy) = OrderRegex.ParseMove(match); + string[] actual = [type, timeline, province, location, turn, moveVerb, + destTimeline, destProvince, destLocation, destTurn, viaConvoy]; + // Use EquivalentTo for more detailed error message + Assert.That(actual, Is.EquivalentTo(expected), "Unexpected parse results"); + Assert.That(actual, Is.EqualTo(expected), "Unexpected parse results"); } }