diff --git a/src/F23.Kernel.Tests/AspNetCore/MinimalApiResultExtensionsTests.cs b/src/F23.Kernel.Tests/AspNetCore/MinimalApiResultExtensionsTests.cs index add8d58..fbd4c1f 100644 --- a/src/F23.Kernel.Tests/AspNetCore/MinimalApiResultExtensionsTests.cs +++ b/src/F23.Kernel.Tests/AspNetCore/MinimalApiResultExtensionsTests.cs @@ -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; @@ -76,7 +75,7 @@ public void PreconditionFailedResult_ConcurrencyMismatch_Returns_StatusCodeResul // Assert var statusCodeResult = Assert.IsType(actionResult); - Assert.Equal((int) HttpStatusCode.PreconditionFailed, statusCodeResult.StatusCode); + Assert.Equal((int)HttpStatusCode.PreconditionFailed, statusCodeResult.StatusCode); } [Fact] @@ -179,7 +178,7 @@ public void PreconditionFailedResultT_ConcurrencyMismatch_Returns_StatusCodeResu // Assert var statusCodeResult = Assert.IsType(actionResult); - Assert.Equal((int) HttpStatusCode.PreconditionFailed, statusCodeResult.StatusCode); + Assert.Equal((int)HttpStatusCode.PreconditionFailed, statusCodeResult.StatusCode); } [Fact] @@ -423,6 +422,11 @@ private class TestUnhandledResult() : Result(true) private class TestUnhandledResult() : Result(true) { - public override string Message => "whoopsie"; + public override string Message => "whoopsie"; + + public override Result Map() + { + throw new NotImplementedException(); + } } } diff --git a/src/F23.Kernel.Tests/AspNetCore/MvcResultExtensionsTests.cs b/src/F23.Kernel.Tests/AspNetCore/MvcResultExtensionsTests.cs index 24100c3..47b819e 100644 --- a/src/F23.Kernel.Tests/AspNetCore/MvcResultExtensionsTests.cs +++ b/src/F23.Kernel.Tests/AspNetCore/MvcResultExtensionsTests.cs @@ -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; @@ -75,7 +74,7 @@ public void PreconditionFailedResult_ConcurrencyMismatch_Returns_StatusCodeResul // Assert var statusCodeResult = Assert.IsType(actionResult); - Assert.Equal((int) HttpStatusCode.PreconditionFailed, statusCodeResult.StatusCode); + Assert.Equal((int)HttpStatusCode.PreconditionFailed, statusCodeResult.StatusCode); } [Fact] @@ -178,7 +177,7 @@ public void PreconditionFailedResultT_ConcurrencyMismatch_Returns_StatusCodeResu // Assert var statusCodeResult = Assert.IsType(actionResult); - Assert.Equal((int) HttpStatusCode.PreconditionFailed, statusCodeResult.StatusCode); + Assert.Equal((int)HttpStatusCode.PreconditionFailed, statusCodeResult.StatusCode); } [Fact] @@ -460,6 +459,11 @@ private class TestUnhandledResult() : Result(true) private class TestUnhandledResult() : Result(true) { - public override string Message => "whoopsie"; + public override string Message => "whoopsie"; + + public override Result Map() + { + throw new NotImplementedException(); + } } } diff --git a/src/F23.Kernel.Tests/Mocks/UnknownResult.cs b/src/F23.Kernel.Tests/Mocks/UnknownResult.cs index 0b0b2c3..f266396 100644 --- a/src/F23.Kernel.Tests/Mocks/UnknownResult.cs +++ b/src/F23.Kernel.Tests/Mocks/UnknownResult.cs @@ -2,5 +2,10 @@ namespace F23.Kernel.Tests.Mocks; public class UnknownResult() : Result(false) { - public override string Message => "Unknown result"; + public override string Message => "Unknown result"; + + public override Result Map() + { + throw new NotImplementedException(); + } } diff --git a/src/F23.Kernel.Tests/ResultMappingTests.cs b/src/F23.Kernel.Tests/ResultMappingTests.cs index 9973569..be0aba7 100644 --- a/src/F23.Kernel.Tests/ResultMappingTests.cs +++ b/src/F23.Kernel.Tests/ResultMappingTests.cs @@ -87,5 +87,55 @@ public void MapFailure_UnknownType_Throws() // Assert Assert.Throws(Act); + } + + [Fact] + public void GenericSuccessResult_IsConvertedTo_NonGenericSuccessResult() + { + var genericResult = Result.Success(42); + + Assert.IsType(genericResult.Map()); + } + + [Fact] + public void GenericValidationFailedResult_IsConvertedTo_NonGenericValidationFailedResult() + { + var genericResult = Result.ValidationFailed("key", "message"); + + var validationFailedResult = Assert.IsType(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(); + + var validationFailedResult = Assert.IsType(genericResult.Map()); + + Assert.Equal("Validation passed", validationFailedResult.Message); + } + + [Fact] + public void GenericUnauthorizedResult_IsConvertedTo_NonGenericUnauthorizedResult() + { + var genericResult = Result.Unauthorized("Something went wrong."); + + var unauthorizedResult = Assert.IsType(genericResult.Map()); + + Assert.Equal("Something went wrong.", unauthorizedResult.Message); + } + + [Fact] + public void GenericPreconditionFailedResult_IsConvertedTo_NonGenericPreconditionFailedResult() + { + var genericResult = Result.PreconditionFailed(PreconditionFailedReason.NotFound); + + var preconditionFailedResult = Assert.IsType(genericResult.Map()); + + Assert.Equal(PreconditionFailedReason.NotFound, preconditionFailedResult.Reason); } } diff --git a/src/F23.Kernel/Result.cs b/src/F23.Kernel/Result.cs index 6fb0dc4..dbddb18 100644 --- a/src/F23.Kernel/Result.cs +++ b/src/F23.Kernel/Result.cs @@ -155,6 +155,12 @@ public Result MapFailure() => _ => throw new InvalidOperationException("Unknown result type") }; + /// + /// Maps the implementing generic Result to a non-generic . + /// + /// A new non-generic . + public abstract Result Map(); + /// /// Logs the failure result to the specified . /// @@ -178,6 +184,7 @@ public void LogFailure(ILogger logger, LogLevel logLevel = LogLevel.Warning) break; default: throw new InvalidOperationException("Unknown result type"); - }; + } + ; } } diff --git a/src/F23.Kernel/Results/PreconditionFailedResult.cs b/src/F23.Kernel/Results/PreconditionFailedResult.cs index 791b443..d949f14 100644 --- a/src/F23.Kernel/Results/PreconditionFailedResult.cs +++ b/src/F23.Kernel/Results/PreconditionFailedResult.cs @@ -46,5 +46,11 @@ public class PreconditionFailedResult(PreconditionFailedReason reason, string /// Otherwise, it will return the default message associated with the /// value. /// - public override string Message => message ?? Reason.ToMessage(); + public override string Message => message ?? Reason.ToMessage(); + + /// + /// Maps this generic precondition failed result to a non-generic precondition failed result. + /// + /// A non-generic . + public override Result Map() => new PreconditionFailedResult(Reason, Message); } diff --git a/src/F23.Kernel/Results/SuccessResult.cs b/src/F23.Kernel/Results/SuccessResult.cs index dcfb779..68b988e 100644 --- a/src/F23.Kernel/Results/SuccessResult.cs +++ b/src/F23.Kernel/Results/SuccessResult.cs @@ -30,4 +30,10 @@ public class SuccessResult(T value) : Result(true) /// This represents the successful outcome of the operation when the result is a . /// public T Value => value; + + /// + /// Maps the current object to a successful result. + /// + /// A instance representing a successful operation. + public override Result Map() => Success(); } diff --git a/src/F23.Kernel/Results/UnauthorizedResult.cs b/src/F23.Kernel/Results/UnauthorizedResult.cs index 0540c1b..1c3f0ca 100644 --- a/src/F23.Kernel/Results/UnauthorizedResult.cs +++ b/src/F23.Kernel/Results/UnauthorizedResult.cs @@ -21,4 +21,10 @@ public class UnauthorizedResult(string message) : Result(false) /// Gets a message describing the outcome of the operation. /// public override string Message => message; + + /// + /// Maps to a non-generic unauthorized result. + /// + /// A non-generic . + public override Result Map() => Result.Unauthorized(message); } diff --git a/src/F23.Kernel/Results/ValidationFailedResult.cs b/src/F23.Kernel/Results/ValidationFailedResult.cs index 31f67de..a0c61b7 100644 --- a/src/F23.Kernel/Results/ValidationFailedResult.cs +++ b/src/F23.Kernel/Results/ValidationFailedResult.cs @@ -38,5 +38,11 @@ public class ValidationFailedResult(IReadOnlyCollection erro /// This property provides detailed information about the errors that occurred during validation, /// including the key associated with each error and its corresponding message. /// - public IReadOnlyCollection Errors => errors; + public IReadOnlyCollection Errors => errors; + + /// + /// Maps the current validation errors to a . + /// + /// A non-generic containing the validation errors. + public override Result Map() => new ValidationFailedResult(Errors); } diff --git a/src/F23.Kernel/Results/ValidationPassedResult.cs b/src/F23.Kernel/Results/ValidationPassedResult.cs index ef7b9f4..f2b2443 100644 --- a/src/F23.Kernel/Results/ValidationPassedResult.cs +++ b/src/F23.Kernel/Results/ValidationPassedResult.cs @@ -21,4 +21,10 @@ public class ValidationPassedResult() : ValidationResult(true) /// Gets a message describing the outcome of the operation. /// public override string Message => "Validation passed"; + + /// + /// Maps to a non-generic instance. + /// + /// A non-generic . + public override Result Map() => new ValidationPassedResult(); }