Skip to content

Commit

Permalink
Merge branch 'main' into radekwojpl2/drop-dependencies-to-aspnetcore
Browse files Browse the repository at this point in the history
  • Loading branch information
ardalis authored Sep 12, 2023
2 parents 0564053 + 8e93188 commit 89cfb7b
Show file tree
Hide file tree
Showing 9 changed files with 111 additions and 7 deletions.
20 changes: 18 additions & 2 deletions src/Ardalis.Result.AspNetCore/ResultStatusMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ public ResultStatusMap AddDefaultMap()
.For(ResultStatus.NotFound, HttpStatusCode.NotFound, resultStatusOptions => resultStatusOptions
.With(NotFoundEntity))
.For(ResultStatus.Conflict, HttpStatusCode.Conflict, resultStatusOptions => resultStatusOptions
.With(ConflictEntity));
.With(ConflictEntity))
.For(ResultStatus.CriticalError, HttpStatusCode.InternalServerError, resultStatusOptions =>
resultStatusOptions
.With(CriticalEntity));
}

/// <summary>
Expand Down Expand Up @@ -139,6 +142,19 @@ private static ProblemDetails ConflictEntity(ControllerBase controller, IResult
Detail = result.Errors.Any() ? details.ToString() : null
};
}

private static ProblemDetails CriticalEntity(ControllerBase controller, IResult result)
{
var details = new StringBuilder("Next error(s) occured:");

foreach (var error in result.Errors) details.Append("* ").Append(error).AppendLine();

return new ProblemDetails
{
Title = "Something went wrong.",
Detail = result.Errors.Any() ? details.ToString() : null
};
}
}

public class ResultStatusOptions
Expand Down Expand Up @@ -217,4 +233,4 @@ public ResultStatusOptions With(Type responseType, Func<ControllerBase, IResult,
return this;
}
}
}
}
10 changes: 10 additions & 0 deletions src/Ardalis.Result/Result.Void.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,16 @@ public static Result ErrorWithCorrelationId(string correlationId, params string[
};
}

/// <summary>
/// Represents the validation error that prevents the underlying service from completing.
/// </summary>
/// <param name="validationError">The validation error encountered</param>
/// <returns>A Result</returns>
public new static Result Invalid(ValidationError validationError)
{
return new Result(ResultStatus.Invalid) { ValidationErrors = { validationError } };
}

/// <summary>
/// Represents validation errors that prevent the underlying service from completing.
/// </summary>
Expand Down
22 changes: 22 additions & 0 deletions src/Ardalis.Result/Result.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,16 @@ public static Result<T> Error(params string[] errorMessages)
return new Result<T>(ResultStatus.Error) { Errors = errorMessages };
}

/// <summary>
/// Represents a validation error that prevents the underlying service from completing.
/// </summary>
/// <param name="validationError">The validation error encountered</param>
/// <returns>A Result<typeparamref name="T"/></returns>
public static Result<T> Invalid(ValidationError validationError)
{
return new Result<T>(ResultStatus.Invalid) { ValidationErrors = { validationError } };
}

/// <summary>
/// Represents validation errors that prevent the underlying service from completing.
/// </summary>
Expand Down Expand Up @@ -184,5 +194,17 @@ public static Result<T> Conflict(params string[] errorMessages)
{
return new Result<T>(ResultStatus.Conflict) { Errors = errorMessages };
}

/// <summary>
/// Represents a critical error that occurred during the execution of the service.
/// Everything provided by the user was valid, but the service was unable to complete due to an exception.
/// See also HTTP 500 Internal Server Error: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#5xx_server_errors
/// </summary>
/// <param name="errorMessages">A list of string error messages.</param>
/// <returns>A Result<typeparamref name="T"/></returns>
public static Result<T> CriticalError(params string[] errorMessages)
{
return new Result<T>(ResultStatus.CriticalError) { Errors = errorMessages };
}
}
}
1 change: 1 addition & 0 deletions src/Ardalis.Result/ResultExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public static Result<TDestination> Map<TSource, TDestination>(this Result<TSourc
case ResultStatus.Conflict: return result.Errors.Any()
? Result<TDestination>.Conflict(result.Errors.ToArray())
: Result<TDestination>.Conflict();
case ResultStatus.CriticalError: return Result<TDestination>.CriticalError(result.Errors.ToArray());
default:
throw new NotSupportedException($"Result {result.Status} conversion is not supported.");
}
Expand Down
1 change: 1 addition & 0 deletions src/Ardalis.Result/ResultStatus.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ public enum ResultStatus
Invalid,
NotFound,
Conflict,
CriticalError
}
}
10 changes: 9 additions & 1 deletion tests/Ardalis.Result.UnitTests/ResultConstructor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -207,10 +207,18 @@ public void InitializedIsSuccessFalseForForbiddenFactoryCall()
Assert.False(result.IsSuccess);
}

[Fact]
public void InitializedIsSuccessFalseForInvalidListFactoryCall()
{
var result = Result<object>.Invalid(new List<ValidationError>());

Assert.False(result.IsSuccess);
}

[Fact]
public void InitializedIsSuccessFalseForInvalidFactoryCall()
{
var result = Result<object>.Invalid(null);
var result = Result<object>.Invalid(new ValidationError());

Assert.False(result.IsSuccess);
}
Expand Down
20 changes: 18 additions & 2 deletions tests/Ardalis.Result.UnitTests/ResultVoidConstructor.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using FluentAssertions;
using System;
using System.Collections.Generic;
using System.Linq;
using Xunit;
Expand Down Expand Up @@ -73,7 +72,7 @@ public void InitializesErrorResultWithCorrelationIdWithFactoryMethod()
}

[Fact]
public void InitializesInvalidResultWithFactoryMethod()
public void InitializesInvalidResultWithMultipleValidationErrorsWithFactoryMethod()
{
var validationErrors = new List<ValidationError>
{
Expand All @@ -98,6 +97,23 @@ public void InitializesInvalidResultWithFactoryMethod()
result.ValidationErrors.Should().ContainEquivalentOf(new ValidationError { ErrorMessage = "PostalCode cannot exceed 10 characters", Identifier = "postalCode" });
}

[Fact]
public void InitializesInvalidResultWithSingleValidationErrorWithFactoryMethod()
{
var validationError = new ValidationError
{
Identifier = "name",
ErrorMessage = "Name is required"
};

var result = Result.Invalid(validationError);

Assert.Null(result.Value);
Assert.Equal(ResultStatus.Invalid, result.Status);

result.ValidationErrors.Should().ContainEquivalentOf(new ValidationError { ErrorMessage = "Name is required", Identifier = "name" });
}

[Fact]
public void InitializesNotFoundResultWithFactoryMethod()
{
Expand Down
14 changes: 13 additions & 1 deletion tests/Ardalis.Result.UnitTests/ResultVoidMap.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using FluentAssertions;
using System.Collections.Generic;
using Xunit;

namespace Ardalis.Result.UnitTests
Expand Down Expand Up @@ -48,10 +49,21 @@ public void ShouldProduceForbidden()
actual.Value.Should().BeNull();
}

[Fact]
public void ShouldProduceInvalidWithEmptyList()
{
var result = Result.Invalid(new List<ValidationError>());

var actual = result.Map(_ => "This should be ignored");

actual.Status.Should().Be(ResultStatus.Invalid);
actual.Value.Should().BeNull();
}

[Fact]
public void ShouldProduceInvalid()
{
var result = Result.Invalid(new());
var result = Result.Invalid(new ValidationError());

var actual = result.Map(_ => "This should be ignored");

Expand Down
20 changes: 19 additions & 1 deletion tests/Ardalis.Result.UnitTests/ResultVoidToResultOfT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public void ConvertFromErrorResultOfUnit(params string[] errors)
}

[Fact]
public void ConvertFromInvalidResultOfUnit()
public void ConvertFromInvalidResultOfUnitWithValidationErrorList()
{
var validationErrors = new List<ValidationError>
{
Expand All @@ -49,6 +49,24 @@ public void ConvertFromInvalidResultOfUnit()
result.ValidationErrors.Should().ContainEquivalentOf(new ValidationError { ErrorMessage = "PostalCode cannot exceed 10 characters", Identifier = "postalCode" });
}

[Fact]
public void ConvertFromInvalidResultOfUnitWithValidationError()
{
var validationError = new ValidationError
{
Identifier = "name",
ErrorMessage = "Name is required"
};

var result = DoBusinessOperationExample<object>(Result.Invalid(validationError));

Assert.Null(result.Value);
Assert.Equal(ResultStatus.Invalid, result.Status);

result.Status.Should().Be(ResultStatus.Invalid);
result.ValidationErrors.Should().ContainEquivalentOf(new ValidationError { ErrorMessage = "Name is required", Identifier = "name" });
}

[Fact]
public void ConvertFromNotFoundResultOfUnit()
{
Expand Down

0 comments on commit 89cfb7b

Please sign in to comment.