Compare commits

...
4 Commits
Author SHA1 Message Date
mostalive 3b7e880717 add mise.toml for dotnet version 2026-09-03 14:16:02 +01:00
mostalive 4c0f1dd541 Let custom matcher provide clear failure messages 2026-09-03 14:06:24 +01:00
mostalive c6c5829748 pin .net version 2026-09-03 14:04:17 +01:00
mostalive 1736cd1abd add test and production code to solution
so that we can build it
2026-09-03 11:29:25 +01:00
7 changed files with 59 additions and 17 deletions
+1
View File
@@ -17,3 +17,4 @@ obj/
## NuGet local config (workaround for locked ~/.nuget) ## NuGet local config (workaround for locked ~/.nuget)
nuget.config nuget.config
*.log
@@ -14,4 +14,12 @@ Global
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{B2C3D4E5-F6A7-8901-BCDE-F12345678901}.Debug|Any CPU.ActiveCfg = Release|Any CPU
{B2C3D4E5-F6A7-8901-BCDE-F12345678901}.Debug|Any CPU.Build.0 = Release|Any CPU
{B2C3D4E5-F6A7-8901-BCDE-F12345678901}.Debug|Any CPU.Deploy.0 = Release|Any CPU
EndGlobalSection
EndGlobal EndGlobal
+6
View File
@@ -0,0 +1,6 @@
{
"sdk": {
"version": "10.0.400",
"rollForward": "latestFeature"
}
}
+2
View File
@@ -0,0 +1,2 @@
[tools]
dotnet = "10"
@@ -12,9 +12,7 @@ namespace OrderTests;
public static class Has public static class Has
{ {
public static IResolveConstraint OrderState(decimal expectedTotal, decimal[] expectedLineValues) public static IResolveConstraint OrderState(decimal expectedTotal, decimal[] expectedLineValues)
{ => new OrderStateConstraint(expectedTotal, expectedLineValues);
return new OrderStateConstraint(expectedTotal, expectedLineValues);
}
} }
public class OrderStateConstraint : Constraint public class OrderStateConstraint : Constraint
@@ -23,27 +21,54 @@ public class OrderStateConstraint : Constraint
private readonly decimal[] _expectedLineValues; private readonly decimal[] _expectedLineValues;
public OrderStateConstraint(decimal expectedTotal, decimal[] expectedLineValues) public OrderStateConstraint(decimal expectedTotal, decimal[] expectedLineValues)
: base($"order with total {expectedTotal} and line values [{string.Join(", ", expectedLineValues)}]")
{ {
_expectedTotal = expectedTotal; _expectedTotal = expectedTotal;
_expectedLineValues = expectedLineValues; _expectedLineValues = expectedLineValues;
} }
public override string Description =>
$"order with total {_expectedTotal} and line values [{string.Join(", ", _expectedLineValues)}]";
public override ConstraintResult ApplyTo<TActual>(TActual actual) public override ConstraintResult ApplyTo<TActual>(TActual actual)
{ {
var order = (Order)(object)actual!; var order = (Order)(object)actual!;
var actualTotal = order.Total; var actualTotal = order.Total;
var actualLineValues = order.Lines.Select(l => l.Value).ToArray(); var actualLineValues = order.Lines.Select(l => l.Value).ToArray();
var totalMatch = actualTotal == _expectedTotal; var details = new List<string>();
var linesMatch = actualLineValues.SequenceEqual(_expectedLineValues); if (actualTotal != _expectedTotal)
details.Add($"Total: expected {_expectedTotal}, but was {actualTotal}");
if (!actualLineValues.SequenceEqual(_expectedLineValues))
details.Add(
$"Line values: expected [{string.Join(", ", _expectedLineValues)}], " +
$"but was [{string.Join(", ", actualLineValues)}]");
var messages = new List<string>(); return new OrderStateResult(this, actual!, details.Count == 0, details);
if (!totalMatch) }
messages.Add($"Total: expected {_expectedTotal}, got {actualTotal}");
if (!linesMatch)
messages.Add($"Line values: expected [{string.Join(", ", _expectedLineValues)}], got [{string.Join(", ", actualLineValues)}]");
return new ConstraintResult(this, actual, totalMatch && linesMatch); /// <summary>
/// A ConstraintResult that carries the per-field mismatch details and
/// writes them as additional lines in the failure message, e.g.
///
/// Expected: order with total 210 and line values [160, 50]
/// But was: &lt;Order&gt;
/// Total: expected 210, but was 250
/// Line values: expected [160, 50], but was [200, 50]
/// </summary>
private sealed class OrderStateResult : ConstraintResult
{
private readonly IReadOnlyList<string> _details;
public OrderStateResult(Constraint constraint, object? actual, bool isSuccess, IReadOnlyList<string> details)
: base(constraint, actual, isSuccess)
{
_details = details;
}
public override void WriteAdditionalLinesTo(MessageWriter writer)
{
foreach (var detail in _details)
writer.WriteMessageLine(detail);
}
} }
} }
@@ -7,8 +7,8 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="NUnit" Version="3.13.3" /> <PackageReference Include="NUnit" Version="4.6.1" />
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0" /> <PackageReference Include="NUnit3TestAdapter" Version="6.3.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\OrderDomain\OrderDomain.csproj" /> <ProjectReference Include="..\..\src\OrderDomain\OrderDomain.csproj" />
@@ -18,7 +18,7 @@ public class OrderTotalTests
Assert.That(order, Has.OrderState( Assert.That(order, Has.OrderState(
expectedTotal: 210m, expectedTotal: 210m,
expectedLineValues: new[] { 160m, 50m })); expectedLineValues: [160m, 50m]));
} }
[Test] [Test]