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
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using F23.Kernel.AspNetCore;
using F23.Kernel.Results;
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;

namespace F23.Kernel.Tests.AspNetCore;
Expand Down Expand Up @@ -76,7 +75,7 @@ public void PreconditionFailedResult_ConcurrencyMismatch_Returns_StatusCodeResul

// Assert
var statusCodeResult = Assert.IsType<StatusCodeHttpResult>(actionResult);
Assert.Equal((int) HttpStatusCode.PreconditionFailed, statusCodeResult.StatusCode);
Assert.Equal((int)HttpStatusCode.PreconditionFailed, statusCodeResult.StatusCode);
}

[Fact]
Expand Down Expand Up @@ -179,7 +178,7 @@ public void PreconditionFailedResultT_ConcurrencyMismatch_Returns_StatusCodeResu

// Assert
var statusCodeResult = Assert.IsType<StatusCodeHttpResult>(actionResult);
Assert.Equal((int) HttpStatusCode.PreconditionFailed, statusCodeResult.StatusCode);
Assert.Equal((int)HttpStatusCode.PreconditionFailed, statusCodeResult.StatusCode);
}

[Fact]
Expand Down Expand Up @@ -423,6 +422,11 @@ private class TestUnhandledResult() : Result(true)

private class TestUnhandledResult<T>() : Result<T>(true)
{
public override string Message => "whoopsie";
public override string Message => "whoopsie";

public override Result Map()
{
throw new NotImplementedException();
}
}
}
12 changes: 8 additions & 4 deletions src/F23.Kernel.Tests/AspNetCore/MvcResultExtensionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using F23.Kernel.AspNetCore;
using F23.Kernel.Results;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;

namespace F23.Kernel.Tests.AspNetCore;

Expand Down Expand Up @@ -75,7 +74,7 @@ public void PreconditionFailedResult_ConcurrencyMismatch_Returns_StatusCodeResul

// Assert
var statusCodeResult = Assert.IsType<StatusCodeResult>(actionResult);
Assert.Equal((int) HttpStatusCode.PreconditionFailed, statusCodeResult.StatusCode);
Assert.Equal((int)HttpStatusCode.PreconditionFailed, statusCodeResult.StatusCode);
}

[Fact]
Expand Down Expand Up @@ -178,7 +177,7 @@ public void PreconditionFailedResultT_ConcurrencyMismatch_Returns_StatusCodeResu

// Assert
var statusCodeResult = Assert.IsType<StatusCodeResult>(actionResult);
Assert.Equal((int) HttpStatusCode.PreconditionFailed, statusCodeResult.StatusCode);
Assert.Equal((int)HttpStatusCode.PreconditionFailed, statusCodeResult.StatusCode);
}

[Fact]
Expand Down Expand Up @@ -460,6 +459,11 @@ private class TestUnhandledResult() : Result(true)

private class TestUnhandledResult<T>() : Result<T>(true)
{
public override string Message => "whoopsie";
public override string Message => "whoopsie";

public override Result Map()
{
throw new NotImplementedException();
}
}
}
7 changes: 6 additions & 1 deletion src/F23.Kernel.Tests/Mocks/UnknownResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,10 @@ namespace F23.Kernel.Tests.Mocks;

public class UnknownResult() : Result<TestResultContent>(false)
{
public override string Message => "Unknown result";
public override string Message => "Unknown result";

public override Result Map()
{
throw new NotImplementedException();
}
}
50 changes: 50 additions & 0 deletions src/F23.Kernel.Tests/ResultMappingTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,5 +87,55 @@ public void MapFailure_UnknownType_Throws()

// Assert
Assert.Throws<InvalidOperationException>(Act);
}

[Fact]
public void GenericSuccessResult_IsConvertedTo_NonGenericSuccessResult()
{
var genericResult = Result<int>.Success(42);

Assert.IsType<SuccessResult>(genericResult.Map());
}

[Fact]
public void GenericValidationFailedResult_IsConvertedTo_NonGenericValidationFailedResult()
{
var genericResult = Result<int>.ValidationFailed("key", "message");

var validationFailedResult = Assert.IsType<ValidationFailedResult>(genericResult.Map());

Assert.Single(validationFailedResult.Errors);
Assert.Equal("key", validationFailedResult.Errors.First().Key);
Assert.Equal("message", validationFailedResult.Errors.First().Message);
}

[Fact]
public void GenericValidationPassedResult_IsConvertedTo_NonGenericValidationPassedResult()
{
var genericResult = new ValidationPassedResult<int>();

var validationFailedResult = Assert.IsType<ValidationPassedResult>(genericResult.Map());

Assert.Equal("Validation passed", validationFailedResult.Message);
}

[Fact]
public void GenericUnauthorizedResult_IsConvertedTo_NonGenericUnauthorizedResult()
{
var genericResult = Result<int>.Unauthorized("Something went wrong.");

var unauthorizedResult = Assert.IsType<UnauthorizedResult>(genericResult.Map());

Assert.Equal("Something went wrong.", unauthorizedResult.Message);
}

[Fact]
public void GenericPreconditionFailedResult_IsConvertedTo_NonGenericPreconditionFailedResult()
{
var genericResult = Result<int>.PreconditionFailed(PreconditionFailedReason.NotFound);

var preconditionFailedResult = Assert.IsType<PreconditionFailedResult>(genericResult.Map());

Assert.Equal(PreconditionFailedReason.NotFound, preconditionFailedResult.Reason);
}
}
9 changes: 8 additions & 1 deletion src/F23.Kernel/Result.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,12 @@ public Result<TOther> MapFailure<TOther>() =>
_ => throw new InvalidOperationException("Unknown result type")
};

/// <summary>
/// Maps the implementing generic Result to a non-generic <see cref="Result"/>.
/// </summary>
/// <returns>A new non-generic <see cref="Result"/>.</returns>
public abstract Result Map();

/// <summary>
/// Logs the failure result to the specified <see cref="ILogger"/>.
/// </summary>
Expand All @@ -178,6 +184,7 @@ public void LogFailure(ILogger logger, LogLevel logLevel = LogLevel.Warning)
break;
default:
throw new InvalidOperationException("Unknown result type");
};
}
;
}
}
8 changes: 7 additions & 1 deletion src/F23.Kernel/Results/PreconditionFailedResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,11 @@ public class PreconditionFailedResult<T>(PreconditionFailedReason reason, string
/// Otherwise, it will return the default message associated with the
/// <see cref="PreconditionFailedReason"/> value.
/// </summary>
public override string Message => message ?? Reason.ToMessage();
public override string Message => message ?? Reason.ToMessage();

/// <summary>
/// Maps this generic precondition failed result to a non-generic precondition failed result.
/// </summary>
/// <returns>A non-generic <see cref="PreconditionFailedResult"/>.</returns>
public override Result Map() => new PreconditionFailedResult(Reason, Message);
}
6 changes: 6 additions & 0 deletions src/F23.Kernel/Results/SuccessResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,10 @@ public class SuccessResult<T>(T value) : Result<T>(true)
/// This represents the successful outcome of the operation when the result is a <see cref="SuccessResult{T}"/>.
/// </summary>
public T Value => value;

/// <summary>
/// Maps the current object to a successful result.
/// </summary>
/// <returns>A <see cref="Result"/> instance representing a successful operation.</returns>
public override Result Map() => Success();
}
6 changes: 6 additions & 0 deletions src/F23.Kernel/Results/UnauthorizedResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,10 @@ public class UnauthorizedResult<T>(string message) : Result<T>(false)
/// Gets a message describing the outcome of the operation.
/// </summary>
public override string Message => message;

/// <summary>
/// Maps to a non-generic unauthorized result.
/// </summary>
/// <returns>A non-generic <see cref="UnauthorizedResult"/>.</returns>
public override Result Map() => Result.Unauthorized(message);
}
8 changes: 7 additions & 1 deletion src/F23.Kernel/Results/ValidationFailedResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,11 @@ public class ValidationFailedResult<T>(IReadOnlyCollection<ValidationError> erro
/// This property provides detailed information about the errors that occurred during validation,
/// including the key associated with each error and its corresponding message.
/// </remarks>
public IReadOnlyCollection<ValidationError> Errors => errors;
public IReadOnlyCollection<ValidationError> Errors => errors;

/// <summary>
/// Maps the current validation errors to a <see cref="ValidationFailedResult"/>.
/// </summary>
/// <returns>A non-generic <see cref="ValidationFailedResult"/> containing the validation errors.</returns>
public override Result Map() => new ValidationFailedResult(Errors);
}
6 changes: 6 additions & 0 deletions src/F23.Kernel/Results/ValidationPassedResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,10 @@ public class ValidationPassedResult<T>() : ValidationResult<T>(true)
/// Gets a message describing the outcome of the operation.
/// </summary>
public override string Message => "Validation passed";

/// <summary>
/// Maps to a non-generic <see cref="ValidationPassedResult"/> instance.
/// </summary>
/// <returns>A non-generic <see cref="ValidationPassedResult"/>.</returns>
public override Result Map() => new ValidationPassedResult();
}