From 33aecf876abb1ff3b191f721d8ff15f525174b30 Mon Sep 17 00:00:00 2001 From: Tim Van Baak Date: Mon, 26 Aug 2024 16:32:33 +0000 Subject: [PATCH] Add test cases for support-hold --- MultiversalDiplomacy/Model/Regex.cs | 40 ++++++++++++++++ MultiversalDiplomacyTests/RegexTest.cs | 65 +++++++++++++++++++++++++- 2 files changed, 103 insertions(+), 2 deletions(-) diff --git a/MultiversalDiplomacy/Model/Regex.cs b/MultiversalDiplomacy/Model/Regex.cs index e79bc09..d2eaae3 100644 --- a/MultiversalDiplomacy/Model/Regex.cs +++ b/MultiversalDiplomacy/Model/Regex.cs @@ -5,6 +5,11 @@ using MultiversalDiplomacy.Orders; namespace MultiversalDiplomacy.Model; +/// +/// This class defines the regular expressions that are used to build up larger expressions for matching orders +/// 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. +/// public class OrderRegex(World world) { public const string Type = "(A|F|Army|Fleet)"; @@ -25,6 +30,8 @@ public class OrderRegex(World world) public const string MoveVerb = "(-|(?:->)|(?:=>)|(?:attack(?:s)?)|(?:move(?:s)?(?: to)?))"; + public const string SupportVerb = "(s|support|supports)"; + public const string ViaConvoy = "(convoy|via convoy|by convoy)"; public Regex Hold => new( @@ -81,6 +88,39 @@ public class OrderRegex(World world) match.Groups[12].Value, match.Groups[13].Value); + public Regex SupportHold => new( + $"^{UnitSpec} {SupportVerb} {UnitSpec}$", + RegexOptions.IgnoreCase); + + public static ( + string type, + string timeline, + string province, + string location, + string turn, + string supportVerb, + string targetType, + string targetTimeline, + string targetProvince, + string targetLocation, + string targetTurn) + ParseSupportHold(Match match) => ( + match.Groups[1].Value, + match.Groups[2].Value, + match.Groups[3].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 > 0 + ? 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) { newUnit = null; diff --git a/MultiversalDiplomacyTests/RegexTest.cs b/MultiversalDiplomacyTests/RegexTest.cs index 5b10af7..1e07da2 100644 --- a/MultiversalDiplomacyTests/RegexTest.cs +++ b/MultiversalDiplomacyTests/RegexTest.cs @@ -70,10 +70,18 @@ public class RegexTest yield return Test( "A F-STP - MOS", "A", "F", "STP", "", "", "-", "", "MOS", "", "", ""); + // No confusion of timeline and hold verb + yield return Test( + "A Mun - h-Tyr", + "A", "", "Mun", "", "", "-", "h", "Tyr", "", "", ""); + // No confusion of timeline and support verb + yield return Test( + "A Mun - s-Tyr", + "A", "", "Mun", "", "", "-", "s", "Tyr", "", "", ""); // 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"); + "Western Mediterranean Sea moves to Gulf of Lyons via convoy", + "", "", "Western Mediterranean Sea", "", "", "moves to", "", "Gulf of Lyons", "", "", "via convoy"); // Parenthesis location yield return Test( "F Spain(nc) - Spain(sc)", @@ -98,4 +106,57 @@ public class RegexTest Assert.That(actual, Is.EquivalentTo(expected), "Unexpected parse results"); Assert.That(actual, Is.EqualTo(expected), "Unexpected parse results"); } + + static IEnumerable SupportHoldRegexMatchesTestCases() + { + 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 s A a-Tyrolia/l@0", + "Army", "a", "Munich", "l", "0", "s", "A", "a", "Tyrolia", "l", "0"); + // Case insensitivity + yield return Test( + "fleet B-lon/C@0 SUPPORTS B-enc/W@0", + "fleet", "B", "lon", "C", "0", "SUPPORTS", "", "B", "enc", "W", "0"); + // All optionals missing + yield return Test( + "ROM s VIE", + "", "", "ROM", "", "", "s", "", "", "VIE", "", ""); + // No confusion of unit type and timeline + yield return Test( + "A F-STP s MOS", + "A", "F", "STP", "", "", "s", "", "", "MOS", "", ""); + // No confusion of timeline and support verb + yield return Test( + "A Mun s Tyr", + "A", "", "Mun", "", "", "s", "", "", "Tyr", "", ""); + // Elements with spaces + yield return Test( + "Western Mediterranean Sea supports Gulf of Lyons", + "", "", "Western Mediterranean Sea", "", "", "supports", "", "", "Gulf of Lyons", "", ""); + // Parenthesis location + yield return Test( + "F Spain(nc) s Spain(sc)", + "F", "", "Spain", "nc", "", "s", "", "", "Spain", "sc", ""); + // Timeline designation spells out a province + yield return Test( + "A tyr-MUN(vie) s mun-TYR/vie", + "A", "tyr", "MUN", "vie", "", "s", "", "mun", "TYR", "vie", ""); + } + + [TestCaseSource(nameof(SupportHoldRegexMatchesTestCases))] + public void SupportHoldRegexMatches(string order, string[] expected) + { + OrderRegex re = new(World.WithStandardMap()); + var match = re.SupportHold.Match(order); + Assert.True(match.Success, "Match failed"); + var (type, timeline, province, location, turn, supportVerb, + targetType, targetTimeline, targetProvince, targetLocation, targetTurn) = OrderRegex.ParseSupportHold(match); + string[] actual = [type, timeline, province, location, turn, supportVerb, + targetType, targetTimeline, targetProvince, targetLocation, targetTurn]; + // 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"); + } }