Compare commits

..

No commits in common. "5e2d495fa50b42ecb721ed12258bfc306df85664" and "4096e4d517c772c0b04d148e9fa8fb66385a7169" have entirely different histories.

10 changed files with 33 additions and 111 deletions

View File

@ -58,14 +58,6 @@ public class AdjudicationQueryScriptHandler(
private ScriptResult EvaluateAssertion(string assertion) private ScriptResult EvaluateAssertion(string assertion)
{ {
var args = assertion.Split(' ', 2, StringSplitOptions.RemoveEmptyEntries); var args = assertion.Split(' ', 2, StringSplitOptions.RemoveEmptyEntries);
OrderParser re = new(World);
Regex prov = new($"^{re.FullLocation}$", RegexOptions.IgnoreCase);
Match match;
string timeline;
IEnumerable<Season> seasonsInTimeline;
int turn;
Season season;
Province province;
switch (args[0]) switch (args[0])
{ {
@ -75,56 +67,28 @@ public class AdjudicationQueryScriptHandler(
case "false": case "false":
return ScriptResult.Fail("assert false", this); return ScriptResult.Fail("assert false", this);
case "hold-order":
// The hold-order assertion primarily serves to verify that a unit's order was illegal in cases where
// a written non-hold order was rejected before order validation and replaced with a hold order.
match = prov.Match(args[1]);
timeline = match.Groups[1].Length > 0
? match.Groups[1].Value
: Season.First.Timeline;
seasonsInTimeline = World.Timelines.Seasons.Where(season => season.Timeline == timeline);
if (!seasonsInTimeline.Any()) return ScriptResult.Fail($"No seasons in timeline {timeline}", this);
turn = match.Groups[4].Length > 0
? int.Parse(match.Groups[4].Value)
// If turn is unspecified, use the second-latest turn in the timeline,
// since we want to assert against the subjects of the orders just adjudicated,
// and adjudication created a new set of seasons.
: seasonsInTimeline.Max(season => season.Turn) - 1;
season = new(timeline, turn);
province = World.Map.Provinces.Single(province => province.Is(match.Groups[2].Value));
var matchingHolds = Validations.Where(val
=> val.Valid
&& val.Order is HoldOrder hold
&& hold.Unit.Season == season
&& World.Map.GetLocation(hold.Unit.Location).ProvinceName == province.Name);
if (!matchingHolds.Any()) return ScriptResult.Fail("No matching holds");
return ScriptResult.Succeed(this);
case "order-valid": case "order-valid":
case "order-invalid": case "order-invalid":
match = prov.Match(args[1]); OrderParser re = new(World);
Regex prov = new($"^{re.FullLocation}$", RegexOptions.IgnoreCase);
Match match = prov.Match(args[1]);
if (!match.Success) return ScriptResult.Fail($"Could not parse province from \"{args[1]}\"", this); if (!match.Success) return ScriptResult.Fail($"Could not parse province from \"{args[1]}\"", this);
timeline = match.Groups[1].Length > 0 string timeline = match.Groups[1].Length > 0
? match.Groups[1].Value ? match.Groups[1].Value
: Season.First.Timeline; : Season.First.Timeline;
seasonsInTimeline = World.Timelines.Seasons.Where(season => season.Timeline == timeline); var seasonsInTimeline = World.Timelines.Seasons.Where(season => season.Timeline == timeline);
if (!seasonsInTimeline.Any()) return ScriptResult.Fail($"No seasons in timeline {timeline}", this); if (!seasonsInTimeline.Any()) return ScriptResult.Fail($"No seasons in timeline {timeline}", this);
turn = match.Groups[4].Length > 0 int turn = match.Groups[4].Length > 0
? int.Parse(match.Groups[4].Value) ? int.Parse(match.Groups[4].Value)
// If turn is unspecified, use the second-latest turn in the timeline, // If turn is unspecified, use the second-latest turn in the timeline,
// since we want to assert against the subjects of the orders just adjudicated, // since we want to assert against the subjects of the orders just adjudicated,
// and adjudication created a new set of seasons. // and adjudication created a new set of seasons.
: seasonsInTimeline.Max(season => season.Turn) - 1; : seasonsInTimeline.Max(season => season.Turn) - 1;
season = new(timeline, turn); Season season = new(timeline, turn);
province = World.Map.Provinces.Single(province => province.Is(match.Groups[2].Value)); Province province = World.Map.Provinces.Single(province => province.Is(match.Groups[2].Value));
var matching = Validations.Where(val var matching = Validations.Where(val
=> val.Order is UnitOrder order => val.Order is UnitOrder order
@ -142,20 +106,20 @@ public class AdjudicationQueryScriptHandler(
case "has-past": case "has-past":
Regex hasPast = new($"^([a-z]+[0-9]+)>([a-z]+[0-9]+)$"); Regex hasPast = new($"^([a-z]+[0-9]+)>([a-z]+[0-9]+)$");
match = hasPast.Match(args[1]); Match hpMatch = hasPast.Match(args[1]);
if (!match.Success) return ScriptResult.Fail("Expected format s1>s2", this); if (!hpMatch.Success) return ScriptResult.Fail("Expected format s1>s2", this);
Season future = new(match.Groups[1].Value); Season future = new(hpMatch.Groups[1].Value);
if (!World.Timelines.Pasts.TryGetValue(future.Key, out Season? actual)) { if (!World.Timelines.Pasts.TryGetValue(future.Key, out Season? actual)) {
return ScriptResult.Fail($"No such season \"{future}\""); return ScriptResult.Fail($"No such season \"{future}\"");
} }
Season expected = new(match.Groups[2].Value); Season expected = new(hpMatch.Groups[2].Value);
if (actual != expected) return ScriptResult.Fail( if (actual != expected) return ScriptResult.Fail(
$"Expected past of {future} to be {expected}, but it was {actual}"); $"Expected past of {future} to be {expected}, but it was {actual}");
return ScriptResult.Succeed(this); return ScriptResult.Succeed(this);
case "not-dislodged": case "holds":
case "dislodged": case "dislodged":
re = new(World); re = new(World);
prov = new($"^{re.FullLocation}$", RegexOptions.IgnoreCase); prov = new($"^{re.FullLocation}$", RegexOptions.IgnoreCase);
@ -185,7 +149,7 @@ public class AdjudicationQueryScriptHandler(
if (!matchingDislodges.Any()) return ScriptResult.Fail("No matching dislodge decisions"); if (!matchingDislodges.Any()) return ScriptResult.Fail("No matching dislodge decisions");
var isDislodged = matchingDislodges.Cast<IsDislodged>().First(); var isDislodged = matchingDislodges.Cast<IsDislodged>().First();
if (args[0] == "not-dislodged" && isDislodged.Outcome != false) { if (args[0] == "holds" && isDislodged.Outcome != false) {
return ScriptResult.Fail($"Adjudication {isDislodged} is true"); return ScriptResult.Fail($"Adjudication {isDislodged} is true");
} }
if (args[0] == "dislodged" && isDislodged.Outcome != true) { if (args[0] == "dislodged" && isDislodged.Outcome != true) {

View File

@ -133,24 +133,6 @@ public class ReplTest
repl.AssertFails("assert has-past a2>a1"); repl.AssertFails("assert has-past a2>a1");
} }
[Test]
public void AssertHoldOrder()
{
var repl = StandardRepl();
repl.ExecuteAll("""
unit Germany A Mun
---
""");
repl.AssertFails("Germany A Mun - The Sun");
repl.Execute("---");
// Order is invalid
repl.Execute("assert hold-order Mun");
// order-invalid requires the order be parsable, which this isn't
repl.AssertFails("assert order-invalid Mun");
}
[Test] [Test]
public void AssertMovement() public void AssertMovement()
{ {
@ -259,7 +241,7 @@ public class ReplTest
"""); """);
// Move repelled // Move repelled
repl.Execute("assert not-dislodged Tyr"); repl.Execute("assert holds Tyr");
repl.AssertFails("assert dislodged Tyr"); repl.AssertFails("assert dislodged Tyr");
repl.ExecuteAll(""" repl.ExecuteAll("""
@ -271,6 +253,6 @@ public class ReplTest
// Move succeeds // Move succeeds
repl.Execute("assert dislodged Tyr"); repl.Execute("assert dislodged Tyr");
repl.AssertFails("assert not-dislodged Tyr"); repl.AssertFails("assert holds Tyr");
} }
} }

View File

@ -19,37 +19,21 @@ public class ScriptTests
[TestCaseSource(nameof(DatcTestCases))] [TestCaseSource(nameof(DatcTestCases))]
public void Test_DATC(string testScriptPath) public void Test_DATC(string testScriptPath)
{ {
Assert.Ignore("Script tests postponed until parsing tests are done");
string filename = Path.GetFileName(testScriptPath); string filename = Path.GetFileName(testScriptPath);
int line = 0; int line = 0;
bool expectFailure = false;
IScriptHandler handler = new SetupScriptHandler( IScriptHandler handler = new SetupScriptHandler(
(msg) => {/* discard */}, (msg) => {/* discard */},
World.WithStandardMap(), World.WithStandardMap(),
Adjudicator.MovementPhase); Adjudicator.MovementPhase);
foreach (string input in File.ReadAllLines(testScriptPath)) { foreach (string input in File.ReadAllLines(testScriptPath)) {
line++; line++;
// Handle test directives
if (input == "#test:skip") {
Assert.Ignore($"Script {filename} skipped at line {line}");
}
if (input == "#test:fails") {
expectFailure = true;
continue;
}
var result = handler.HandleInput(input); var result = handler.HandleInput(input);
if (expectFailure && result.Success) throw new AssertionException( if (!result.Success) throw new AssertionException(
$"Script {filename} expected line {line} to fail, but it succeeded");
if (!expectFailure && !result.Success) throw new AssertionException(
$"Script {filename} error at line {line}: {result.Message}"); $"Script {filename} error at line {line}: {result.Message}");
if (result.NextHandler is null) throw new AssertionException( if (result.NextHandler is null) throw new AssertionException(
$"Script {filename} quit unexpectedly at line {line}: \"{input}\""); $"Script {filename} quit unexpectedly at line {line}: \"{input}\"");
handler = result.NextHandler; handler = result.NextHandler;
expectFailure = false;
} }
} }
} }

View File

@ -11,4 +11,4 @@ F North Sea - Picardy
--- ---
# Order should fail. # Order should fail.
assert hold-order North Sea assert North Sea holds

View File

@ -6,10 +6,9 @@ unit England A Liverpool
--- ---
England: England:
#test:fails
A Liverpool - Irish Sea A Liverpool - Irish Sea
--- ---
# Order should fail. # Order should fail.
assert hold-order Liverpool assert Liverpool holds

View File

@ -1,15 +1,14 @@
# 6.A.3. TEST CASE, MOVE FLEET TO LAND # 6.A.3. TEST CASE, MOVE FLEET TO LAND
# Check whether a fleet cannot move to land. # Check whether a fleet cannot move to land.
unit Germany F Kiel unit Germany Army Kiel
--- ---
Germany: Germany:
#test:fails
F Kiel - Munich F Kiel - Munich
--- ---
# Order should fail. # Order should fail.
assert hold-order Kiel assert Kiel holds

View File

@ -1,7 +1,7 @@
# 6.A.4. TEST CASE, MOVE TO OWN SECTOR # 6.A.4. TEST CASE, MOVE TO OWN SECTOR
# Moving to the same sector is an illegal move (2023 rulebook, page 7, "An Army can be ordered to move into an adjacent inland or coastal province."). # Moving to the same sector is an illegal move (2023 rulebook, page 7, "An Army can be ordered to move into an adjacent inland or coastal province.").
unit Germany F Kiel unit Germany Army Kiel
--- ---
@ -11,4 +11,4 @@ F Kiel - Kiel
--- ---
# Program should not crash. # Program should not crash.
assert hold-order Kiel assert Kiel holds

View File

@ -1,9 +1,6 @@
# 6.A.5. TEST CASE, MOVE TO OWN SECTOR WITH CONVOY # 6.A.5. TEST CASE, MOVE TO OWN SECTOR WITH CONVOY
# Moving to the same sector is still illegal with convoy (2023 rulebook, page 7, "Note: An Army can move across water provinces from one coastal province to another..."). # Moving to the same sector is still illegal with convoy (2023 rulebook, page 7, "Note: An Army can move across water provinces from one coastal province to another...").
# TODO convoy order parsing
#test:skip
unit England F North Sea unit England F North Sea
unit England A Yorkshire unit England A Yorkshire
unit England A Liverpool unit England A Liverpool
@ -24,11 +21,11 @@ A Wales Supports F London - Yorkshire
--- ---
# The move of the army in Yorkshire is illegal. # The move of the army in Yorkshire is illegal.
assert hold-order Yorkshire assert Yorkshire holds
# This makes the support of Liverpool also illegal and without the support, the Germans have a stronger force. # This makes the support of Liverpool also illegal and without the support, the Germans have a stronger force.
assert hold-order North Sea assert North Sea holds
assert hold-order Liverpool assert Liverpool holds
assert moves London assert London moves
# The army in London dislodges the army in Yorkshire. # The army in London dislodges the army in Yorkshire.
assert support-given Wales assert Wales supports
assert dislodged Yorkshire assert Yorkshire dislodged

View File

@ -13,4 +13,4 @@ F London - North Sea
--- ---
# Order should fail. # Order should fail.
assert hold-order London assert London holds

View File

@ -1,11 +1,8 @@
# 6.A.7. TEST CASE, ONLY ARMIES CAN BE CONVOYED # 6.A.7. TEST CASE, ONLY ARMIES CAN BE CONVOYED
# A fleet cannot be convoyed. # A fleet cannot be convoyed.
# TODO convoy order parsing
#test:skip
unit England F London unit England F London
unit England F North Sea unit England North Sea
--- ---
@ -16,4 +13,4 @@ F North Sea Convoys A London - Belgium
--- ---
# Move from London to Belgium should fail. # Move from London to Belgium should fail.
assert hold-order London assert London holds