using NUnit.Framework; using MultiversalDiplomacy.Model; using MultiversalDiplomacy.Orders; namespace MultiversalDiplomacyTests; public class RegexTest { 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); 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"); } static IEnumerable MoveRegexMatchesTestCases() { // 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", "", "", ""); // 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( "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)", "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", "", ""); } [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"); } static IEnumerable SupportHoldRegexMatchesTestCases() { // 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"); } static IEnumerable SupportMoveRegexMatchesTestCases() { // Full specification yield return Test( "Army a-Munich/l@0 s A a-Tyrolia/l@0 - a-Vienna/l@0", "Army", "a", "Munich", "l", "0", "s", "A", "a", "Tyrolia", "l", "0", "-", "a", "Vienna", "l", "0"); // Case insensitivity yield return Test( "fleet B-lon/C@0 SUPPORTS B-enc/W@0 MOVE TO B-nts/W@0", "fleet", "B", "lon", "C", "0", "SUPPORTS", "", "B", "enc", "W", "0", "MOVE TO", "B", "nts", "W", "0"); // All optionals missing yield return Test( "ROM s VIE - TYR", "", "", "ROM", "", "", "s", "", "", "VIE", "", "", "-", "", "TYR", "", ""); // No confusion of unit type and timeline yield return Test( "A F-STP S MOS - A-UKR", "A", "F", "STP", "", "", "S", "", "", "MOS", "", "", "-", "A", "UKR", "", ""); // Elements with spaces yield return Test( "Western Mediterranean Sea supports Gulf of Lyons move to North Sea", "", "", "Western Mediterranean Sea", "", "", "supports", "", "", "Gulf of Lyons", "", "", "move to", "", "North Sea", "", ""); } [TestCaseSource(nameof(SupportMoveRegexMatchesTestCases))] public void SupportMoveRegexMatches(string order, string[] expected) { OrderRegex re = new(World.WithStandardMap()); var match = re.SupportMove.Match(order); Assert.True(match.Success, "Match failed"); var (type, timeline, province, location, turn, supportVerb, targetType, targetTimeline, targetProvince, targetLocation, targetTurn, moveVerb, destTimeline, destProvince, destLocation, destTurn) = OrderRegex.ParseSupportMove(match); string[] actual = [type, timeline, province, location, turn, supportVerb, targetType, targetTimeline, targetProvince, targetLocation, targetTurn, moveVerb, destTimeline, destProvince, destLocation, destTurn]; // 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 OrderParsingTest() { World world = World.WithStandardMap().AddUnits("Germany A Mun"); OrderRegex re = new(world); var match = re.Move.Match("A Mun - Tyr"); var success = OrderRegex.TryParseMoveOrder(world, "Germany", match, out Order? order); Assert.That(success, Is.True); Assert.That(order, Is.TypeOf()); MoveOrder move = (MoveOrder)order!; Assert.That(move.Power, Is.EqualTo("Germany")); Assert.That(move.Unit.Key, Is.EqualTo("A a-Munich/l@0")); Assert.That(move.Location, Is.EqualTo("Tyrolia/l")); Assert.That(move.Season.Key, Is.EqualTo("a0")); } }