Skip to content

Commit

Permalink
Add FluentAssertions extension methods (#226)
Browse files Browse the repository at this point in the history
  • Loading branch information
MigMax authored Jan 11, 2025
1 parent e29689c commit c56f035
Show file tree
Hide file tree
Showing 17 changed files with 704 additions and 1 deletion.
14 changes: 14 additions & 0 deletions Ardalis.Result.sln
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
Directory.Packages.props = Directory.Packages.props
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ardalis.Result.FluentAssertions", "src\Ardalis.Result.FluentAssertions\Ardalis.Result.FluentAssertions.csproj", "{94145FF9-5A56-4479-87AF-3A99939B38F0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ardalis.Result.FluentAssertions.UnitTests", "tests\Ardalis.Result.FluentAssertions.UnitTests\Ardalis.Result.FluentAssertions.UnitTests.csproj", "{0800019A-0B40-4923-96E1-656A745E79C2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -95,6 +99,14 @@ Global
{C522FE42-BBEF-46A7-9E3E-44EA8339AF2E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C522FE42-BBEF-46A7-9E3E-44EA8339AF2E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C522FE42-BBEF-46A7-9E3E-44EA8339AF2E}.Release|Any CPU.Build.0 = Release|Any CPU
{94145FF9-5A56-4479-87AF-3A99939B38F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{94145FF9-5A56-4479-87AF-3A99939B38F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{94145FF9-5A56-4479-87AF-3A99939B38F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{94145FF9-5A56-4479-87AF-3A99939B38F0}.Release|Any CPU.Build.0 = Release|Any CPU
{0800019A-0B40-4923-96E1-656A745E79C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0800019A-0B40-4923-96E1-656A745E79C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0800019A-0B40-4923-96E1-656A745E79C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0800019A-0B40-4923-96E1-656A745E79C2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -111,6 +123,8 @@ Global
{60860685-37BB-47D9-B0DC-6FE7F0DB2AE5} = {FA061DC6-61B7-401F-87A4-D338B396CCD9}
{A9769533-C9B2-4AD4-8B24-70C474D8EBB0} = {FA061DC6-61B7-401F-87A4-D338B396CCD9}
{C522FE42-BBEF-46A7-9E3E-44EA8339AF2E} = {42693FB1-04E1-4635-B249-E1847609E801}
{94145FF9-5A56-4479-87AF-3A99939B38F0} = {865A74CD-F478-4AA5-AFA5-6C26FB38B849}
{0800019A-0B40-4923-96E1-656A745E79C2} = {42693FB1-04E1-4635-B249-E1847609E801}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7CD0ED8C-3B1C-4F16-8B8D-3D8F1A8F1A5A}
Expand Down
3 changes: 2 additions & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<ItemGroup>
<PackageVersion Include="Ardalis.ApiEndpoints" Version="4.1.0" />
<PackageVersion Include="coverlet.collector" Version="6.0.2" />
<PackageVersion Include="FluentAssertions" Version="6.10.0" />
<PackageVersion Include="FluentAssertions" Version="7.0.0" />
<PackageVersion Include="FluentValidation" Version="11.9.2" />
<PackageVersion Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="11.1.0" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
Expand All @@ -14,6 +14,7 @@
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageVersion Include="Microsoft.TestPlatform.ObjectModel" Version="17.5.0" />
<PackageVersion Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="7.0.4" />
<PackageVersion Include="Moq" Version="4.20.72" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageVersion Include="Swashbuckle.AspNetCore.Annotations" Version="6.5.0" />
<PackageVersion Include="System.ComponentModel.Annotations" Version="5.0.0" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<PackageId>Ardalis.Result.FluentAssertions</PackageId>
<Title>Ardalis.Result.FluentAssertions</Title>
<Description>A simple package to implement FluentAssertions with the Ardalis.Result package.</Description>
<Summary>A simple package to implement FluentAssertions with the Ardalis.Result package.</Summary>
<PackageTags>result;pattern;web;api;aspnetcore;mvc;FluentAssertions;Validation</PackageTags>
<PackageReleaseNotes>
</PackageReleaseNotes>
<AssemblyName>Ardalis.Result.FluentAssertions</AssemblyName>
<Version>1.0.0</Version>
</PropertyGroup>


<ItemGroup>
<None Include="icon.png" Pack="true" Visible="false" PackagePath="" />
</ItemGroup>


<ItemGroup>
<PackageReference Include="FluentAssertions" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Ardalis.Result\Ardalis.Result.csproj" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using FluentAssertions.Primitives;

namespace Ardalis.Result.FluentAssertions;

public static class FluentAssertionsResultExtensions
{
public static AndConstraint<ObjectAssertions> ShouldBeFailure(this Result result)
{
result.IsSuccess.Should().BeFalse();

return new AndConstraint<ObjectAssertions>(result.Should());
}

public static AndConstraint<ObjectAssertions> ShouldBeConflict(this Result result)
{
result.Status.Should().Be(ResultStatus.Conflict);

return new AndConstraint<ObjectAssertions>(result.Should());
}

public static AndConstraint<ObjectAssertions> ShouldBeConflict(this Result result, params string[] errorMessages)
{
return result.ShouldBeEquivalentTo(Result.Conflict(errorMessages));
}

public static AndConstraint<ObjectAssertions> ShouldBeCriticalError(this Result result)
{
result.Status.Should().Be(ResultStatus.CriticalError);

return new AndConstraint<ObjectAssertions>(result.Should());
}

public static AndConstraint<ObjectAssertions> ShouldBeCriticalError(this Result result, params string[] errorMessages)
{
return result.ShouldBeEquivalentTo(Result.CriticalError(errorMessages));
}

public static AndConstraint<ObjectAssertions> ShouldBeError(this Result result)
{
result.Status.Should().Be(ResultStatus.Error);

return new AndConstraint<ObjectAssertions>(result.Should());
}

public static AndConstraint<ObjectAssertions> ShouldBeError(this Result result, string errorMessage)
{
return result.ShouldBeEquivalentTo(Result.Error(errorMessage));
}

public static AndConstraint<ObjectAssertions> ShouldBeError(this Result result, ErrorList errorList)
{
return result.ShouldBeEquivalentTo(Result.Error(errorList));
}

public static AndConstraint<ObjectAssertions> ShouldBeError(this Result result, IEnumerable<string> errorMessages, string? correlationId)

Check warning on line 58 in src/Ardalis.Result.FluentAssertions/FluentAssertionsResultExtensions.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 58 in src/Ardalis.Result.FluentAssertions/FluentAssertionsResultExtensions.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 58 in src/Ardalis.Result.FluentAssertions/FluentAssertionsResultExtensions.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 58 in src/Ardalis.Result.FluentAssertions/FluentAssertionsResultExtensions.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 58 in src/Ardalis.Result.FluentAssertions/FluentAssertionsResultExtensions.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 58 in src/Ardalis.Result.FluentAssertions/FluentAssertionsResultExtensions.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 58 in src/Ardalis.Result.FluentAssertions/FluentAssertionsResultExtensions.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 58 in src/Ardalis.Result.FluentAssertions/FluentAssertionsResultExtensions.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 58 in src/Ardalis.Result.FluentAssertions/FluentAssertionsResultExtensions.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 58 in src/Ardalis.Result.FluentAssertions/FluentAssertionsResultExtensions.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
{
return result.ShouldBeEquivalentTo(Result.Error(new ErrorList(errorMessages, correlationId)));
}

public static AndConstraint<ObjectAssertions> ShouldBeForbidden(this Result result)
{
result.Status.Should().Be(ResultStatus.Forbidden);

return new AndConstraint<ObjectAssertions>(result.Should());
}

public static AndConstraint<ObjectAssertions> ShouldBeForbidden(this Result result, params string[] errorMessages)
{
return result.ShouldBeEquivalentTo(Result.Forbidden(errorMessages));
}

public static AndConstraint<ObjectAssertions> ShouldBeInvalid(this Result result)
{
result.Status.Should().Be(ResultStatus.Invalid);

return new AndConstraint<ObjectAssertions>(result.Should());
}

public static AndConstraint<ObjectAssertions> ShouldBeInvalid(this Result result, params ValidationError[] validationErrors)
{
return result.ShouldBeEquivalentTo(Result.Invalid(validationErrors));
}

public static AndConstraint<ObjectAssertions> ShouldBeNotFound(this Result result)
{
result.Status.Should().Be(ResultStatus.NotFound);

return new AndConstraint<ObjectAssertions>(result.Should());
}

public static AndConstraint<ObjectAssertions> ShouldBeNotFound(this Result result, params string[] errorMessages)
{
return result.ShouldBeEquivalentTo(Result.NotFound(errorMessages));
}

public static AndConstraint<ObjectAssertions> ShouldBeUnauthorized(this Result result)
{
result.Status.Should().Be(ResultStatus.Unauthorized);

return new AndConstraint<ObjectAssertions>(result.Should());
}

public static AndConstraint<ObjectAssertions> ShouldBeUnauthorized(this Result result, params string[] errorMessages)
{
return result.ShouldBeEquivalentTo(Result.Unauthorized(errorMessages));
}

public static AndConstraint<ObjectAssertions> ShouldBeUnavailable(this Result result)
{
result.Status.Should().Be(ResultStatus.Unavailable);

return new AndConstraint<ObjectAssertions>(result.Should());
}

public static AndConstraint<ObjectAssertions> ShouldBeUnavailable(this Result result, params string[] errorMessages)
{
return result.ShouldBeEquivalentTo(Result.Unavailable(errorMessages));
}

public static AndConstraint<ObjectAssertions> ShouldBeFailure(this Result result, params string[] errorMessages)
{
var andConstraint = result.ShouldBeFailure();

result.Errors.Should().BeEquivalentTo(errorMessages);

return andConstraint;
}

public static AndConstraint<ObjectAssertions> ShouldHaveValidationErrorWithCode(this Result result, string errorCode)
{
var andConstraint = result.ShouldBeInvalid();

result.ValidationErrors.Count().Should().BePositive();

result.ValidationErrors.Should().Satisfy(validationError => validationError.ErrorCode == errorCode);

return andConstraint;
}

public static AndConstraint<ObjectAssertions> ShouldHaveValidationErrorWithIdentifier(this Result result, string identifier)
{
var andConstraint = result.ShouldBeInvalid();

result.ValidationErrors.Count().Should().BePositive();

result.ValidationErrors.Should().Satisfy(validationError => validationError.Identifier == identifier);

return andConstraint;
}

public static AndConstraint<ObjectAssertions> ShouldHaveValidationErrorWithMessage(this Result result, string errorMessage)
{
var andConstraint = result.ShouldBeInvalid();

result.ValidationErrors.Count().Should().BePositive();

result.ValidationErrors.Should().Satisfy(validationError => validationError.ErrorMessage == errorMessage);

return andConstraint;
}

public static AndConstraint<ObjectAssertions> ShouldHaveValidationErrorWithSeverity(this Result result, ValidationSeverity severity)
{
var andConstraint = result.ShouldBeInvalid();

result.ValidationErrors.Count().Should().BePositive();

result.ValidationErrors.Should().Satisfy(validationError => validationError.Severity == severity);

return andConstraint;
}

public static AndConstraint<ObjectAssertions> ShouldBeSuccess<TResult>(this Result<TResult> result)
{
result.IsSuccess.Should().BeTrue();

return new AndConstraint<ObjectAssertions>(result.Should());
}

public static AndConstraint<ObjectAssertions> ShouldBeSuccess(this Result result)
{
result.IsSuccess.Should().BeTrue();

return new AndConstraint<ObjectAssertions>(result.Should());
}

public static AndConstraint<ObjectAssertions> ShouldBeCreatedWithLocation<TResult>(this Result<TResult> result, string location)
{
return result.Should().BeEquivalentTo(Result.Created(result.Value, location));
}

public static AndConstraint<ObjectAssertions> ShouldBeSuccessWithMessage(this Result result, string successMessage)
{
return result.ShouldBeEquivalentTo(Result.SuccessWithMessage(successMessage));
}

private static AndConstraint<ObjectAssertions> ShouldBeEquivalentTo(this Result result, Result assertingResult)
{
return result.Should().BeEquivalentTo(assertingResult);
}
}
Binary file added src/Ardalis.Result.FluentAssertions/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<PackageReference Include="FluentAssertions" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="Microsoft.TestPlatform.ObjectModel" />
<PackageReference Include="Moq" />
<PackageReference Include="xunit" />
<PackageReference Include="xunit.runner.visualstudio">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="coverlet.collector">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Ardalis.Result.FluentAssertions\Ardalis.Result.FluentAssertions.csproj" />
<ProjectReference Include="..\..\src\Ardalis.Result\Ardalis.Result.csproj" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using Xunit;
using static Ardalis.Result.Result;
using static Ardalis.Result.FluentAssertions.UnitTests.Utils.Constants;

namespace Ardalis.Result.FluentAssertions.UnitTests.FailureResults;

public class ConflictResult
{
[Fact]
public void ShouldBeFailure()
{
Conflict().ShouldBeFailure();
}

[Fact]
public void WithErrorMessages_ShouldBeFailureWithErrorMessages()
{
Conflict(ErrorMessage).ShouldBeFailure(ErrorMessage);
}

[Fact]
public void ShouldBeConflict()
{
Conflict().ShouldBeConflict();
}

[Fact]
public void WithErrorMessages_ShouldBeConflict()
{
Conflict(ErrorMessage).ShouldBeConflict();
}

[Fact]
public void WithErrorMessages_ShouldBeConflictWithErrorMessages()
{
Conflict(ErrorMessage).ShouldBeConflict(ErrorMessage);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using Xunit;
using static Ardalis.Result.Result;
using static Ardalis.Result.FluentAssertions.UnitTests.Utils.Constants;

namespace Ardalis.Result.FluentAssertions.UnitTests.FailureResults;

public class CriticalErrorResult
{
[Fact]
public void ShouldBeFailure()
{
CriticalError().ShouldBeFailure();
}

[Fact]
public void WithErrorMessages_ShouldBeFailureWithErrorMessages()
{
CriticalError(ErrorMessage).ShouldBeFailure(ErrorMessage);
}

[Fact]
public void ShouldBeCriticalError()
{
CriticalError().ShouldBeCriticalError();
}

[Fact]
public void WithErrorMessages_ShouldBeCriticalError()
{
CriticalError(ErrorMessage).ShouldBeCriticalError();
}

[Fact]
public void ShouldBeCriticalErrorWithErrorMessages()
{
CriticalError(ErrorMessage).ShouldBeCriticalError(ErrorMessage);
}
}
Loading

0 comments on commit c56f035

Please sign in to comment.