From ff64b459caafc6dd5924acfd7c8415394788c574 Mon Sep 17 00:00:00 2001 From: Jaculabilis Date: Mon, 28 Mar 2022 15:05:04 -0700 Subject: [PATCH] Reduce verbosity of test case assertions --- .../Decision/BinaryAdjudicationDecision.cs | 5 ++ MultiversalDiplomacyTests/DATC_A.cs | 86 ++++++++++--------- MultiversalDiplomacyTests/Is.cs | 17 +++- MultiversalDiplomacyTests/NullOrder.cs | 9 -- .../OrderBinaryAdjudicationConstraint.cs | 32 +++++++ MultiversalDiplomacyTests/OrderReference.cs | 78 +++++++++++++++-- .../OrderValidationConstraint.cs | 13 ++- 7 files changed, 176 insertions(+), 64 deletions(-) delete mode 100644 MultiversalDiplomacyTests/NullOrder.cs create mode 100644 MultiversalDiplomacyTests/OrderBinaryAdjudicationConstraint.cs diff --git a/MultiversalDiplomacy/Adjudicate/Decision/BinaryAdjudicationDecision.cs b/MultiversalDiplomacy/Adjudicate/Decision/BinaryAdjudicationDecision.cs index 65e6084..476a04d 100644 --- a/MultiversalDiplomacy/Adjudicate/Decision/BinaryAdjudicationDecision.cs +++ b/MultiversalDiplomacy/Adjudicate/Decision/BinaryAdjudicationDecision.cs @@ -6,6 +6,11 @@ public abstract class BinaryAdjudicationDecision : AdjudicationDecision public override bool Resolved => this.Outcome != null; + public override string ToString() + { + return $"{this.GetType().Name}={this.Outcome}"; + } + public bool Update(bool outcome) { if (this.Outcome == null) diff --git a/MultiversalDiplomacyTests/DATC_A.cs b/MultiversalDiplomacyTests/DATC_A.cs index 60cb2bf..e296d12 100644 --- a/MultiversalDiplomacyTests/DATC_A.cs +++ b/MultiversalDiplomacyTests/DATC_A.cs @@ -1,6 +1,7 @@ using MultiversalDiplomacy.Adjudicate; using MultiversalDiplomacy.Adjudicate.Decision; using MultiversalDiplomacy.Model; +using MultiversalDiplomacy.Orders; using NUnit.Framework; @@ -17,9 +18,9 @@ public class DATC_A setup["England"] .Fleet("North Sea").MovesTo("Picardy").GetReference(out var order); + // Order should fail. setup.ValidateOrders(MovementPhaseAdjudicator.Instance); - - Assert.That(order.Validation, Is.Invalid(ValidationReason.UnreachableDestination)); + Assert.That(order, Is.Invalid(ValidationReason.UnreachableDestination)); } [Test] @@ -27,6 +28,7 @@ public class DATC_A { TestCaseBuilder setup = new TestCaseBuilder(StandardEmpty); + // Order should fail. Assert.That( () => { @@ -41,6 +43,7 @@ public class DATC_A { TestCaseBuilder setup = new TestCaseBuilder(StandardEmpty); + // Order should fail. Assert.That( () => { @@ -57,9 +60,9 @@ public class DATC_A setup["Germany"] .Fleet("Kiel").MovesTo("Kiel").GetReference(out var order); + // Program should not crash. setup.ValidateOrders(MovementPhaseAdjudicator.Instance); - - Assert.That(order.Validation, Is.Invalid(ValidationReason.DestinationMatchesOrigin)); + Assert.That(order, Is.Invalid(ValidationReason.DestinationMatchesOrigin)); } [Test] @@ -72,15 +75,20 @@ public class DATC_A .Army("Yorkshire").MovesTo("Yorkshire").GetReference(out var orderYor) .Army("Liverpool").Supports.Army("Yorkshire").MoveTo("Yorkshire") ["Germany"] - .Fleet("London").MovesTo("Yorkshire") + .Fleet("London").MovesTo("Yorkshire").GetReference(out var orderLon) .Army("Wales").Supports.Fleet("London").MoveTo("Yorkshire"); + // The move of the army in Yorkshire is illegal. This makes the support of Liverpool also illegal. setup.ValidateOrders(MovementPhaseAdjudicator.Instance); + Assert.That(orderLon, Is.Valid); + Assert.That(orderNth, Is.Invalid(ValidationReason.DestinationMatchesOrigin)); + Assert.That(orderYor, Is.Invalid(ValidationReason.DestinationMatchesOrigin)); + var orderYorRepl = orderYor.GetReplacementReference(); - Assert.That(orderNth.Validation, Is.Invalid(ValidationReason.DestinationMatchesOrigin)); - Assert.That(orderYor.Validation, Is.Invalid(ValidationReason.DestinationMatchesOrigin)); - - // TODO assert dislodge + // Without the support, the Germans have a stronger force. The army in London dislodges the army in Yorkshire. + setup.AdjudicateOrders(MovementPhaseAdjudicator.Instance); + Assert.That(orderLon, Is.Victorious); + Assert.That(orderYorRepl, Is.Dislodged); } [Test] @@ -91,9 +99,9 @@ public class DATC_A ["Germany"] .Fleet("London", powerName: "England").MovesTo("North Sea").GetReference(out var order); + // Order should fail. setup.ValidateOrders(MovementPhaseAdjudicator.Instance); - - Assert.That(order.Validation, Is.Invalid(ValidationReason.InvalidUnitForPower)); + Assert.That(order, Is.Invalid(ValidationReason.InvalidUnitForPower)); } [Test] @@ -105,9 +113,9 @@ public class DATC_A .Fleet("London").MovesTo("Belgium") .Fleet("North Sea").Convoys.Army("London").To("Belgium").GetReference(out var order); + // Move from London to Belgium should fail. setup.ValidateOrders(MovementPhaseAdjudicator.Instance); - - Assert.That(order.Validation, Is.Invalid(ValidationReason.InvalidOrderTypeForUnit)); + Assert.That(order, Is.Invalid(ValidationReason.InvalidOrderTypeForUnit)); } [Test] @@ -122,15 +130,12 @@ public class DATC_A .Fleet("Trieste").Supports.Fleet("Trieste").Hold().GetReference(out var orderTri); setup.ValidateOrders(MovementPhaseAdjudicator.Instance); - Assert.That(orderTri.Validation, Is.Invalid(ValidationReason.NoSelfSupport)); + Assert.That(orderTri, Is.Invalid(ValidationReason.NoSelfSupport)); + var orderTriRepl = orderTri.GetReplacementReference(); // The army in Trieste should be dislodged. - var adjudications = setup.AdjudicateOrders(MovementPhaseAdjudicator.Instance); - // The order reference captures the invalidated order, but the unit is the same. - var dislodgeTri = adjudications - .OfType() - .Single(adj => adj.Order.Unit == orderTri.Order.Unit); - Assert.That(dislodgeTri.Outcome, Is.True, "Expected F Tri to be dislodged"); + setup.AdjudicateOrders(MovementPhaseAdjudicator.Instance); + Assert.That(orderTriRepl, Is.Dislodged); } [Test] @@ -141,9 +146,9 @@ public class DATC_A ["Italy"] .Fleet("Rome").MovesTo("Venice").GetReference(out var order); + // Move fails. An army can go from Rome to Venice, but a fleet can not. setup.ValidateOrders(MovementPhaseAdjudicator.Instance); - - Assert.That(order.Validation, Is.Invalid(ValidationReason.UnreachableDestination)); + Assert.That(order, Is.Invalid(ValidationReason.UnreachableDestination)); } [Test] @@ -160,12 +165,11 @@ public class DATC_A setup.ValidateOrders(MovementPhaseAdjudicator.Instance); // The support of Rome is illegal, because Venice can not be reached from Rome by a fleet. - Assert.That(orderRom.Validation, Is.Invalid(ValidationReason.UnreachableSupport)); + Assert.That(orderRom, Is.Invalid(ValidationReason.UnreachableSupport)); // Venice is not dislodged. setup.AdjudicateOrders(MovementPhaseAdjudicator.Instance); - Assert.That(orderVen.Adjudications.OfType().Count(), Is.EqualTo(1)); - Assert.That(orderVen.Adjudications.OfType().First().Outcome, Is.False); + Assert.That(orderVen, Is.NotDislodged); } [Test] @@ -179,15 +183,15 @@ public class DATC_A .Army("Venice").MovesTo("Tyrolia").GetReference(out var orderVen); setup.ValidateOrders(MovementPhaseAdjudicator.Instance); - Assert.That(orderVie.Validation, Is.Valid); - Assert.That(orderVen.Validation, Is.Valid); + Assert.That(orderVie, Is.Valid); + Assert.That(orderVen, Is.Valid); - var adjudications = setup.AdjudicateOrders(MovementPhaseAdjudicator.Instance); // The two units bounce. - Assert.That(orderVie.Adjudications.OfType().Count(), Is.EqualTo(1)); - Assert.That(orderVie.Adjudications.OfType().First().Outcome, Is.False); - Assert.That(orderVen.Adjudications.OfType().Count(), Is.EqualTo(1)); - Assert.That(orderVen.Adjudications.OfType().First().Outcome, Is.False); + var adjudications = setup.AdjudicateOrders(MovementPhaseAdjudicator.Instance); + Assert.That(orderVie, Is.Repelled); + Assert.That(orderVie, Is.NotDislodged); + Assert.That(orderVen, Is.Repelled); + Assert.That(orderVen, Is.NotDislodged); } [Test] @@ -203,17 +207,17 @@ public class DATC_A .Army("Venice").MovesTo("Tyrolia").GetReference(out var orderVen); var validations = setup.ValidateOrders(MovementPhaseAdjudicator.Instance); - Assert.That(orderVie.Validation, Is.Valid); - Assert.That(orderMun.Validation, Is.Valid); - Assert.That(orderVen.Validation, Is.Valid); + Assert.That(orderVie, Is.Valid); + Assert.That(orderMun, Is.Valid); + Assert.That(orderVen, Is.Valid); var adjudications = setup.AdjudicateOrders(MovementPhaseAdjudicator.Instance); // The three units bounce. - Assert.That(orderVie.Adjudications.OfType().Count(), Is.EqualTo(1)); - Assert.That(orderVie.Adjudications.OfType().First().Outcome, Is.False); - Assert.That(orderMun.Adjudications.OfType().Count(), Is.EqualTo(1)); - Assert.That(orderMun.Adjudications.OfType().First().Outcome, Is.False); - Assert.That(orderVen.Adjudications.OfType().Count(), Is.EqualTo(1)); - Assert.That(orderVen.Adjudications.OfType().First().Outcome, Is.False); + Assert.That(orderVie, Is.Repelled); + Assert.That(orderVie, Is.NotDislodged); + Assert.That(orderMun, Is.Repelled); + Assert.That(orderMun, Is.NotDislodged); + Assert.That(orderVen, Is.Repelled); + Assert.That(orderVen, Is.NotDislodged); } } \ No newline at end of file diff --git a/MultiversalDiplomacyTests/Is.cs b/MultiversalDiplomacyTests/Is.cs index 5e36e88..12d772f 100644 --- a/MultiversalDiplomacyTests/Is.cs +++ b/MultiversalDiplomacyTests/Is.cs @@ -1,12 +1,25 @@ using MultiversalDiplomacy.Adjudicate; +using MultiversalDiplomacy.Adjudicate.Decision; namespace MultiversalDiplomacyTests; public class Is : NUnit.Framework.Is { public static OrderValidationConstraint Valid - => new OrderValidationConstraint(true, ValidationReason.Valid); + => new(true, ValidationReason.Valid); public static OrderValidationConstraint Invalid(ValidationReason expected) - => new OrderValidationConstraint(false, expected); + => new(false, expected); + + public static OrderBinaryAdjudicationConstraint Dislodged + => new(true); + + public static OrderBinaryAdjudicationConstraint NotDislodged + => new(false); + + public static OrderBinaryAdjudicationConstraint Victorious + => new(true); + + public static OrderBinaryAdjudicationConstraint Repelled + => new(false); } diff --git a/MultiversalDiplomacyTests/NullOrder.cs b/MultiversalDiplomacyTests/NullOrder.cs deleted file mode 100644 index cab6c7a..0000000 --- a/MultiversalDiplomacyTests/NullOrder.cs +++ /dev/null @@ -1,9 +0,0 @@ -using MultiversalDiplomacy.Model; -using MultiversalDiplomacy.Orders; - -namespace MultiversalDiplomacyTests; - -public class NullOrder : Order -{ - public NullOrder(Power power) : base(power) {} -} \ No newline at end of file diff --git a/MultiversalDiplomacyTests/OrderBinaryAdjudicationConstraint.cs b/MultiversalDiplomacyTests/OrderBinaryAdjudicationConstraint.cs new file mode 100644 index 0000000..b428653 --- /dev/null +++ b/MultiversalDiplomacyTests/OrderBinaryAdjudicationConstraint.cs @@ -0,0 +1,32 @@ +using MultiversalDiplomacy.Adjudicate; +using MultiversalDiplomacy.Adjudicate.Decision; + +using NUnit.Framework.Constraints; + +namespace MultiversalDiplomacyTests; + +public class OrderBinaryAdjudicationConstraint : Constraint + where DecisionType : BinaryAdjudicationDecision +{ + private bool expectedOutcome; + + public override string Description + { + get => $"{typeof(DecisionType).Name}={expectedOutcome}"; + } + + public OrderBinaryAdjudicationConstraint(bool outcome) + { + this.expectedOutcome = outcome; + } + + public override ConstraintResult ApplyTo(TActual actual) + { + if (actual is OrderReference orderRef) + { + DecisionType decision = orderRef.GetDecision(); + return new ConstraintResult(this, decision, decision.Outcome == this.expectedOutcome); + } + return new ConstraintResult(this, actual, false); + } +} diff --git a/MultiversalDiplomacyTests/OrderReference.cs b/MultiversalDiplomacyTests/OrderReference.cs index ddcd4c6..3bcca25 100644 --- a/MultiversalDiplomacyTests/OrderReference.cs +++ b/MultiversalDiplomacyTests/OrderReference.cs @@ -8,16 +8,21 @@ using NUnit.Framework; namespace MultiversalDiplomacyTests; /// -/// An object that provides a view into an order's fate during a test case. +/// An object that provides a view into an order's fate during a test case. This object is +/// stateless and provides data by encapsulating queries on the state of the origin test case +/// builder. /// -public class OrderReference where OrderType : Order +public abstract class OrderReference { - private TestCaseBuilder Builder { get; } + protected TestCaseBuilder Builder { get; } - /// - /// The order. - /// - public OrderType Order { get; } + protected Order Order { get; } + + public OrderReference(TestCaseBuilder builder, Order order) + { + this.Builder = builder; + this.Order = order; + } /// /// The validation result for the order. Throws if validation has not occurred. @@ -63,6 +68,28 @@ public class OrderReference where OrderType : Order } } + /// + /// Returns an for the order that replaced this order. + /// + public OrderReference GetReplacementReference() + where ReplacementOrderType : Order + { + if (this.Replacement == null) + { + throw new InvalidOperationException("This order was not replaced"); + } + Assert.That( + this.Replacement.Order, + Is.AssignableTo(typeof(ReplacementOrderType)), + "Unexpected replacement order type"); + ReplacementOrderType replacementOrder = (ReplacementOrderType)this.Replacement.Order; + return new(this.Builder, replacementOrder); + } + + /// + /// A list of all adjudication decisions related to this order. Throws if adjudication has not + /// occurred. + /// public List Adjudications { get @@ -76,15 +103,35 @@ public class OrderReference where OrderType : Order IsDislodged dislodged => dislodged.Order == this.Order, DoesMove moves => moves.Order == this.Order, GivesSupport supports => supports.Order == this.Order, + HasPath path => path.Order == this.Order, AttackStrength attack => attack.Order == this.Order, DefendStrength defend => defend.Order == this.Order, PreventStrength prevent => prevent.Order == this.Order, + HoldStrength hold => this.Order is UnitOrder unitOrder + ? hold.Province == unitOrder.Unit.Location.Province + : false, _ => false, }).ToList(); return adjudications; } } + /// + /// Returns an adjudication decision of a specified type for this order. Throws if adjudication + /// has not occurred. + /// + public DecisionType GetDecision() + where DecisionType : AdjudicationDecision + { + var typeAdjudications = this.Adjudications.OfType(); + Assert.That(typeAdjudications.Any(), Is.True, $"No {typeof(DecisionType)} decision found"); + return typeAdjudications.Single(); + } + + /// + /// If this order is a unit order and the unit was dislodged, the + /// representing the retreat. Throws if adjudication has not occurred. + /// public RetreatingUnit? Retreat { get @@ -105,10 +152,23 @@ public class OrderReference where OrderType : Order return null; } } +} + +/// +/// An object that provides a view into an order's fate during a test case. This object is +/// stateless and provides data by encapsulating queries on the state of the origin test case +/// builder. +/// +public class OrderReference : OrderReference where OrderType : Order +{ + /// + /// The order. + /// + new public OrderType Order { get; } public OrderReference(TestCaseBuilder builder, OrderType order) + : base(builder, order) { - this.Builder = builder; this.Order = order; } -} \ No newline at end of file +} diff --git a/MultiversalDiplomacyTests/OrderValidationConstraint.cs b/MultiversalDiplomacyTests/OrderValidationConstraint.cs index ece27bd..86a9e19 100644 --- a/MultiversalDiplomacyTests/OrderValidationConstraint.cs +++ b/MultiversalDiplomacyTests/OrderValidationConstraint.cs @@ -22,9 +22,16 @@ public class OrderValidationConstraint : Constraint public override ConstraintResult ApplyTo(TActual actual) { - bool success = actual is OrderValidation validation - && validation.Valid == this.valid - && validation.Reason == this.expectedReason; + bool success = actual switch + { + OrderReference reference + => reference.Validation.Valid == this.valid + && reference.Validation.Reason == this.expectedReason, + OrderValidation validation + => validation.Valid == this.valid + && validation.Reason == this.expectedReason, + _ => false, + }; return new ConstraintResult(this, actual, success); } }