Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions FirstClassErrors.RequestBinder.UnitTests/BindingContractTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ public void ConverterMayFailWithAPrimaryPortError() {
PropertySource<BookingRequest> body = bind.PropertiesOf(Request());

body.SimpleProperty(r => r.GuestEmail).AsRequired(_ => Outcome<EmailAddress>.Failure(
PrimaryPortError.Create(ErrorCode.Create("TEST_PORT_LEVEL_REJECTION"), Any.DiagnosticMessage(), Any.Transience())
.WithPublicMessage(Any.ShortMessage())));
PrimaryPortError.Create(ErrorCode.Create("TEST_PORT_LEVEL_REJECTION"), DiagnosticMessageFactory.Any(), TransienceFactory.Any())
.WithPublicMessage(ShortMessageFactory.Any())));

Outcome<string> outcome = bind.New(_ => "never");
Error invalid = outcome.Error!.InnerErrors.Single();
Expand All @@ -48,9 +48,9 @@ public void ConverterFailingWithAnotherFamilyIsABug() {
PropertySource<BookingRequest> body = bind.PropertiesOf(Request());

InfrastructureError foreignFamily =
InfrastructureError.Create(Any.ErrorCode(), Any.DiagnosticMessage(),
Any.InteractionDirection(), Transience.Unknown)
.WithPublicMessage(Any.ShortMessage());
InfrastructureError.Create(ErrorCodeFactory.Any(), DiagnosticMessageFactory.Any(),
InteractionDirectionFactory.Any(), Transience.Unknown)
.WithPublicMessage(ShortMessageFactory.Any());

InvalidOperationException exception = Assert.Throws<InvalidOperationException>(
() => { body.SimpleProperty(r => r.GuestEmail).AsRequired(_ => Outcome<EmailAddress>.Failure(foreignFamily)); });
Expand Down Expand Up @@ -93,9 +93,9 @@ public void BareNestedElementFailureIsWrapped() {
}

private static PrimaryPortError LeafPortError() {
return PrimaryPortError.Create(ErrorCode.Create("TEST_NESTED_PORT_LEAF"), Any.DiagnosticMessage(),
Any.Transience())
.WithPublicMessage(Any.ShortMessage());
return PrimaryPortError.Create(ErrorCode.Create("TEST_NESTED_PORT_LEAF"), DiagnosticMessageFactory.Any(),
TransienceFactory.Any())
.WithPublicMessage(ShortMessageFactory.Any());
}

[Fact(DisplayName = "A required nested binding that fails with a bare PrimaryPortError leaf (not its build-terminal envelope) is wrapped, so the path survives.")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
<ProjectReference Include="..\FirstClassErrors\FirstClassErrors.csproj" />
<ProjectReference Include="..\FirstClassErrors.RequestBinder\FirstClassErrors.RequestBinder.csproj" />
<ProjectReference Include="..\FirstClassErrors.Testing\FirstClassErrors.Testing.csproj" />
<!-- Direct reference: Testing references Dummies privately (PrivateAssets=all), so it does not flow
transitively; this project uses Dummies.Any.* directly for arbitrary primitives. -->
<ProjectReference Include="..\Dummies\Dummies.csproj" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ private static Outcome<Stay> BindStay(RequestBinder binder, StayDto dto) {
private static Outcome<Stay> AssembleStay(BookingDate checkIn, BookingDate checkOut) {
return checkOut.Value > checkIn.Value
? Outcome<Stay>.Success(new Stay(checkIn, checkOut))
: Outcome<Stay>.Failure(DomainError.Create(CheckOutNotAfterCheckIn, Any.DiagnosticMessage())
.WithPublicMessage(Any.ShortMessage()));
: Outcome<Stay>.Failure(DomainError.Create(CheckOutNotAfterCheckIn, DiagnosticMessageFactory.Any())
.WithPublicMessage(ShortMessageFactory.Any()));
}

[Fact(DisplayName = "New assembles the command exactly once when every property bound.")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

#endregion

namespace FirstClassErrors.UnitTests;
namespace FirstClassErrors.Testing.UnitTests;

[TestSubject(typeof(Clock))]
public sealed class ClockUseAnyTests {
Expand All @@ -31,15 +31,15 @@ public void UseAnyFreezesASingleInstant() {
}
}

[Fact(DisplayName = "Inside Any.Reproducibly, Clock.UseAny picks the same instant for a given seed.")]
[Fact(DisplayName = "Inside Dummies.Any.Reproducibly, Clock.UseAny picks the same instant for a given seed.")]
public void UseAnyIsReproducibleUnderAReproduciblyScope() {
DateTimeOffset first = default;
DateTimeOffset second = default;

Any.Reproducibly(42, () => {
Dummies.Any.Reproducibly(42, () => {
using (Clock.UseAny()) { first = AnError().OccurredAt; }
});
Any.Reproducibly(42, () => {
Dummies.Any.Reproducibly(42, () => {
using (Clock.UseAny()) { second = AnError().OccurredAt; }
});

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="coverlet.collector">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="JetBrains.Annotations" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="NFluent" />
<PackageReference Include="xunit.runner.visualstudio">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="xunit.v3" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\FirstClassErrors\FirstClassErrors.csproj" />
<ProjectReference Include="..\FirstClassErrors.Testing\FirstClassErrors.Testing.csproj" />
<ProjectReference Include="..\Dummies\Dummies.csproj" />
</ItemGroup>

<ItemGroup>
<Using Include="Xunit" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

#endregion

namespace FirstClassErrors.UnitTests;
namespace FirstClassErrors.Testing.UnitTests;

[TestSubject(typeof(InstanceIds))]
public sealed class InstanceIdsUseAnyTests {
Expand All @@ -31,20 +31,20 @@ public void UseAnyAssignsDistinctIds() {
}
}

[Fact(DisplayName = "Inside Any.Reproducibly, InstanceIds.UseAny reproduces the same id sequence for a given seed.")]
[Fact(DisplayName = "Inside Dummies.Any.Reproducibly, InstanceIds.UseAny reproduces the same id sequence for a given seed.")]
public void UseAnyIsReproducibleUnderAReproduciblyScope() {
Guid firstRunA = Guid.Empty;
Guid firstRunB = Guid.Empty;
Guid secondRunA = Guid.Empty;
Guid secondRunB = Guid.Empty;

Any.Reproducibly(7, () => {
Dummies.Any.Reproducibly(7, () => {
using (InstanceIds.UseAny()) {
firstRunA = AnError().InstanceId;
firstRunB = AnError().InstanceId;
}
});
Any.Reproducibly(7, () => {
Dummies.Any.Reproducibly(7, () => {
using (InstanceIds.UseAny()) {
secondRunA = AnError().InstanceId;
secondRunB = AnError().InstanceId;
Expand Down
31 changes: 31 additions & 0 deletions FirstClassErrors.Testing.UnitTests/MeaningfulEnumFactoryTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#region Usings declarations

using FirstClassErrors.Testing;

using NFluent;

#endregion

namespace FirstClassErrors.Testing.UnitTests;

/// <summary>
/// Contract tests for the meaningful-enum factories: they must never yield the <c>Unknown</c> sentinel, which is
/// the whole reason they exist next to a plain <c>Dummies.Any.Enum&lt;T&gt;()</c> draw.
/// </summary>
public sealed class MeaningfulEnumFactoryTests {

[Fact(DisplayName = "TransienceFactory.Any never returns the Unknown sentinel.")]
public void TransienceExcludesUnknown() {
for (int i = 0; i < 200; i++) {
Check.That(TransienceFactory.Any()).IsNotEqualTo(Transience.Unknown);
}
}

[Fact(DisplayName = "InteractionDirectionFactory.Any never returns the Unknown sentinel.")]
public void InteractionDirectionExcludesUnknown() {
for (int i = 0; i < 200; i++) {
Check.That(InteractionDirectionFactory.Any()).IsNotEqualTo(InteractionDirection.Unknown);
}
}

}
Loading