390 lines
18 KiB
C#
390 lines
18 KiB
C#
using NUnit.Framework;
|
|
|
|
using MultiversalDiplomacy.Model;
|
|
using MultiversalDiplomacy.Orders;
|
|
|
|
namespace MultiversalDiplomacyTests;
|
|
|
|
public class OrderParserTest
|
|
{
|
|
private static TestCaseData Test(string order, params string[] expected)
|
|
=> new TestCaseData(order, expected).SetName($"{{m}}(\"{order}\")");
|
|
|
|
static IEnumerable<TestCaseData> 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)
|
|
{
|
|
OrderParser re = new(World.WithStandardMap());
|
|
var match = re.Hold.Match(order);
|
|
Assert.True(match.Success, "Match failed");
|
|
var (type, timeline, province, location, turn, holdVerb) = OrderParser.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<TestCaseData> 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)
|
|
{
|
|
OrderParser 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) = OrderParser.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<TestCaseData> 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)
|
|
{
|
|
OrderParser 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) = OrderParser.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<TestCaseData> 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)
|
|
{
|
|
OrderParser 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) = OrderParser.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");
|
|
}
|
|
|
|
static IEnumerable<TestCaseData> ConvoyRegexMatchesTestCases()
|
|
{
|
|
// Full specification
|
|
yield return Test(
|
|
"Fleet a-Nth/w@0 c A a-London/l@0 - a-Belgium/l@0",
|
|
"Fleet", "a", "Nth", "w", "0", "c", "A", "a", "London", "l", "0", "-", "a", "Belgium", "l", "0");
|
|
// Case insensitivity
|
|
yield return Test(
|
|
"fleet B-nth/W@0 CONVOYS a B-lon/L@0 MOVE TO B-bel/L@0",
|
|
"fleet", "B", "nth", "W", "0", "CONVOYS", "a", "B", "lon", "L", "0", "MOVE TO", "B", "bel", "L", "0");
|
|
// All optionals missing
|
|
yield return Test(
|
|
"TYN c ROM - TUN",
|
|
"", "", "TYN", "", "", "c", "", "", "ROM", "", "", "-", "", "TUN", "", "");
|
|
// No confusion of unit type and timeline
|
|
yield return Test(
|
|
"F A-BOT C FIN - A-LVN",
|
|
"F", "A", "BOT", "", "", "C", "", "", "FIN", "", "", "-", "A", "LVN", "", "");
|
|
// Elements with spaces
|
|
yield return Test(
|
|
"Western Mediterranean Sea convoys Spain move to North Africa",
|
|
"", "", "Western Mediterranean Sea", "", "", "convoys", "", "", "Spain", "", "", "move to", "", "North Africa", "", "");
|
|
}
|
|
|
|
[TestCaseSource(nameof(ConvoyRegexMatchesTestCases))]
|
|
public void ConvoyRegexMatches(string order, string[] expected)
|
|
{
|
|
OrderParser re = new(World.WithStandardMap());
|
|
var match = re.Convoy.Match(order);
|
|
Assert.True(match.Success, "Match failed");
|
|
var (type, timeline, province, location, turn, convoyVerb,
|
|
targetType, targetTimeline, targetProvince, targetLocation, targetTurn, moveVerb,
|
|
destTimeline, destProvince, destLocation, destTurn) = OrderParser.ParseConvoy(match);
|
|
string[] actual = [type, timeline, province, location, turn, convoyVerb,
|
|
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");
|
|
OrderParser re = new(world);
|
|
|
|
var match = re.Move.Match("A Mun - Tyr");
|
|
var success = OrderParser.TryParseMoveOrder(world, "Germany", match, out Order? order);
|
|
|
|
Assert.That(success, Is.True);
|
|
Assert.That(order, Is.TypeOf<MoveOrder>());
|
|
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"));
|
|
}
|
|
|
|
[Test]
|
|
public void OrderDisambiguation()
|
|
{
|
|
World world = World.WithStandardMap().AddUnits("Germany A Mun");
|
|
OrderParser.TryParseOrder(world, "Germany", "Mun h", out Order? parsed);
|
|
Assert.That(parsed?.ToString(), Is.EqualTo("G A a-Munich/l@0 holds"));
|
|
}
|
|
|
|
[Test]
|
|
public void UnitTypeDisambiguatesCoastalLocation()
|
|
{
|
|
World world = World.WithStandardMap().AddUnits("England F Nth", "Germany A Ruhr");
|
|
|
|
Assert.That(
|
|
OrderParser.TryParseOrder(world, "England", "North Sea - Holland", out Order? fleetOrder),
|
|
"Failed to parse fleet order");
|
|
Assert.That(
|
|
OrderParser.TryParseOrder(world, "Germany", "Ruhr - Holland", out Order? armyOrder),
|
|
"Failed to parse army order");
|
|
|
|
Assert.That(fleetOrder, Is.TypeOf<MoveOrder>(), "Unexpected fleet order");
|
|
Assert.That(armyOrder, Is.TypeOf<MoveOrder>(), "Unexpected army order");
|
|
Location fleetDest = world.Map.GetLocation(((MoveOrder)fleetOrder!).Location);
|
|
Location armyDest = world.Map.GetLocation(((MoveOrder)armyOrder!).Location);
|
|
|
|
Assert.That(fleetDest.ProvinceName, Is.EqualTo(armyDest.ProvinceName));
|
|
Assert.That(fleetDest.Type, Is.EqualTo(LocationType.Water), "Unexpected fleet movement location");
|
|
Assert.That(armyDest.Type, Is.EqualTo(LocationType.Land), "Unexpected army movement location");
|
|
}
|
|
|
|
[Test]
|
|
public void UnitTypeOverrulesNonsenseLocation()
|
|
{
|
|
World world = World.WithStandardMap().AddUnits("England F Nth", "Germany A Ruhr");
|
|
|
|
Assert.That(
|
|
OrderParser.TryParseOrder(world, "England", "F North Sea - Holland/l", out Order? fleetOrder),
|
|
"Failed to parse fleet order");
|
|
Assert.That(
|
|
OrderParser.TryParseOrder(world, "Germany", "A Ruhr - Holland/w", out Order? armyOrder),
|
|
"Failed to parse army order");
|
|
|
|
Assert.That(fleetOrder, Is.TypeOf<MoveOrder>(), "Unexpected fleet order");
|
|
Assert.That(armyOrder, Is.TypeOf<MoveOrder>(), "Unexpected army order");
|
|
Location fleetDest = world.Map.GetLocation(((MoveOrder)fleetOrder!).Location);
|
|
Location armyDest = world.Map.GetLocation(((MoveOrder)armyOrder!).Location);
|
|
|
|
Assert.That(fleetDest.ProvinceName, Is.EqualTo(armyDest.ProvinceName));
|
|
Assert.That(fleetDest.Type, Is.EqualTo(LocationType.Water), "Unexpected fleet movement location");
|
|
Assert.That(armyDest.Type, Is.EqualTo(LocationType.Land), "Unexpected army movement location");
|
|
}
|
|
|
|
[Test]
|
|
public void DisambiguateSingleAccessibleCoast()
|
|
{
|
|
World world = World.WithStandardMap().AddUnits("France F Gascony", "France F Marseilles");
|
|
|
|
Assert.That(
|
|
OrderParser.TryParseOrder(world, "France", "Gascony - Spain", out Order? northOrder),
|
|
"Failed to parse north coast order");
|
|
Assert.That(
|
|
OrderParser.TryParseOrder(world, "France", "Marseilles - Spain", out Order? southOrder),
|
|
"Failed to parse south coast order");
|
|
|
|
Assert.That(northOrder, Is.TypeOf<MoveOrder>(), "Unexpected north coast order");
|
|
Assert.That(southOrder, Is.TypeOf<MoveOrder>(), "Unexpected south coast order");
|
|
Location north = world.Map.GetLocation(((MoveOrder)northOrder!).Location);
|
|
Location south = world.Map.GetLocation(((MoveOrder)southOrder!).Location);
|
|
|
|
Assert.That(north.Name, Is.EqualTo("north coast"), "Unexpected disambiguation");
|
|
Assert.That(south.Name, Is.EqualTo("south coast"), "Unexpected disambiguation");
|
|
}
|
|
|
|
[Test]
|
|
public void DisambiguateMultipleAccessibleCoasts()
|
|
{
|
|
World world = World.WithStandardMap().AddUnits("France F Portugal");
|
|
|
|
Assert.That(
|
|
OrderParser.TryParseOrder(world, "France", "Portugal - Spain", out Order? _),
|
|
Is.False,
|
|
"Should not parse ambiguous coastal move");
|
|
}
|
|
|
|
[Test]
|
|
public void DisambiguateSupportToSingleAccessibleCoast()
|
|
{
|
|
World world = World.WithStandardMap().AddUnits("France F Gascony", "France F Marseilles");
|
|
|
|
Assert.That(
|
|
OrderParser.TryParseOrder(world, "France", "Gascony S Marseilles - Spain", out Order? northOrder),
|
|
"Failed to parse north coast order");
|
|
Assert.That(
|
|
OrderParser.TryParseOrder(world, "France", "Marseilles S Gascony - Spain", out Order? southOrder),
|
|
"Failed to parse south coast order");
|
|
|
|
Assert.That(northOrder, Is.TypeOf<SupportMoveOrder>(), "Unexpected north coast order");
|
|
Assert.That(southOrder, Is.TypeOf<SupportMoveOrder>(), "Unexpected south coast order");
|
|
Location northTarget = ((SupportMoveOrder)northOrder!).Location;
|
|
Location southTarget = ((SupportMoveOrder)southOrder!).Location;
|
|
|
|
Assert.That(northTarget.Name, Is.EqualTo("south coast"), "Unexpected disambiguation");
|
|
Assert.That(southTarget.Name, Is.EqualTo("north coast"), "Unexpected disambiguation");
|
|
}
|
|
|
|
[Test]
|
|
public void DisambiguateSupportToMultipleAccessibleCoasts()
|
|
{
|
|
World world = World.WithStandardMap().AddUnits("France F Portugal", "France F Marseilles");
|
|
|
|
Assert.That(
|
|
OrderParser.TryParseOrder(world, "France", "Marseilles S Portugal - Spain", out Order? _),
|
|
Is.False,
|
|
"Should not parse ambiguous coastal support");
|
|
}
|
|
|
|
[Test]
|
|
public void DisambiguateConvoyDestination()
|
|
{
|
|
World world = World.WithStandardMap().AddUnits("France F MID", "France A Brest");
|
|
|
|
Assert.That(
|
|
OrderParser.TryParseOrder(world, "France", "MID C Brest - Spain", out Order? order),
|
|
"Failed to parse convoy order");
|
|
Assert.That(order, Is.TypeOf<ConvoyOrder>(), "Unexpected order type");
|
|
Location dest = ((ConvoyOrder)order!).Location;
|
|
Assert.That(dest.Name, Is.EqualTo("land"), "Unexpected destination location");
|
|
}
|
|
}
|