Skip to content

Commit 0f47591

Browse files
mlienauMitch Lienau
andauthored
#12 - Adds ability to convert a generic result to a non-generic result (#14)
Fixes #12 --------- Co-authored-by: Mitch Lienau <mitch@feature23.com>
1 parent 240608e commit 0f47591

File tree

10 files changed

+112
-12
lines changed

10 files changed

+112
-12
lines changed

src/F23.Kernel.Tests/AspNetCore/MinimalApiResultExtensionsTests.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
using F23.Kernel.AspNetCore;
44
using F23.Kernel.Results;
55
using Microsoft.AspNetCore.Http.HttpResults;
6-
using Microsoft.AspNetCore.Mvc;
76
using Microsoft.AspNetCore.Mvc.ModelBinding;
87

98
namespace F23.Kernel.Tests.AspNetCore;
@@ -76,7 +75,7 @@ public void PreconditionFailedResult_ConcurrencyMismatch_Returns_StatusCodeResul
7675

7776
// Assert
7877
var statusCodeResult = Assert.IsType<StatusCodeHttpResult>(actionResult);
79-
Assert.Equal((int) HttpStatusCode.PreconditionFailed, statusCodeResult.StatusCode);
78+
Assert.Equal((int)HttpStatusCode.PreconditionFailed, statusCodeResult.StatusCode);
8079
}
8180

8281
[Fact]
@@ -179,7 +178,7 @@ public void PreconditionFailedResultT_ConcurrencyMismatch_Returns_StatusCodeResu
179178

180179
// Assert
181180
var statusCodeResult = Assert.IsType<StatusCodeHttpResult>(actionResult);
182-
Assert.Equal((int) HttpStatusCode.PreconditionFailed, statusCodeResult.StatusCode);
181+
Assert.Equal((int)HttpStatusCode.PreconditionFailed, statusCodeResult.StatusCode);
183182
}
184183

185184
[Fact]
@@ -423,6 +422,11 @@ private class TestUnhandledResult() : Result(true)
423422

424423
private class TestUnhandledResult<T>() : Result<T>(true)
425424
{
426-
public override string Message => "whoopsie";
425+
public override string Message => "whoopsie";
426+
427+
public override Result Map()
428+
{
429+
throw new NotImplementedException();
430+
}
427431
}
428432
}

src/F23.Kernel.Tests/AspNetCore/MvcResultExtensionsTests.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
using F23.Kernel.AspNetCore;
44
using F23.Kernel.Results;
55
using Microsoft.AspNetCore.Mvc;
6-
using Microsoft.AspNetCore.Mvc.ModelBinding;
76

87
namespace F23.Kernel.Tests.AspNetCore;
98

@@ -75,7 +74,7 @@ public void PreconditionFailedResult_ConcurrencyMismatch_Returns_StatusCodeResul
7574

7675
// Assert
7776
var statusCodeResult = Assert.IsType<StatusCodeResult>(actionResult);
78-
Assert.Equal((int) HttpStatusCode.PreconditionFailed, statusCodeResult.StatusCode);
77+
Assert.Equal((int)HttpStatusCode.PreconditionFailed, statusCodeResult.StatusCode);
7978
}
8079

8180
[Fact]
@@ -178,7 +177,7 @@ public void PreconditionFailedResultT_ConcurrencyMismatch_Returns_StatusCodeResu
178177

179178
// Assert
180179
var statusCodeResult = Assert.IsType<StatusCodeResult>(actionResult);
181-
Assert.Equal((int) HttpStatusCode.PreconditionFailed, statusCodeResult.StatusCode);
180+
Assert.Equal((int)HttpStatusCode.PreconditionFailed, statusCodeResult.StatusCode);
182181
}
183182

184183
[Fact]
@@ -460,6 +459,11 @@ private class TestUnhandledResult() : Result(true)
460459

461460
private class TestUnhandledResult<T>() : Result<T>(true)
462461
{
463-
public override string Message => "whoopsie";
462+
public override string Message => "whoopsie";
463+
464+
public override Result Map()
465+
{
466+
throw new NotImplementedException();
467+
}
464468
}
465469
}

src/F23.Kernel.Tests/Mocks/UnknownResult.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,10 @@ namespace F23.Kernel.Tests.Mocks;
22

33
public class UnknownResult() : Result<TestResultContent>(false)
44
{
5-
public override string Message => "Unknown result";
5+
public override string Message => "Unknown result";
6+
7+
public override Result Map()
8+
{
9+
throw new NotImplementedException();
10+
}
611
}

src/F23.Kernel.Tests/ResultMappingTests.cs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,5 +87,55 @@ public void MapFailure_UnknownType_Throws()
8787

8888
// Assert
8989
Assert.Throws<InvalidOperationException>(Act);
90+
}
91+
92+
[Fact]
93+
public void GenericSuccessResult_IsConvertedTo_NonGenericSuccessResult()
94+
{
95+
var genericResult = Result<int>.Success(42);
96+
97+
Assert.IsType<SuccessResult>(genericResult.Map());
98+
}
99+
100+
[Fact]
101+
public void GenericValidationFailedResult_IsConvertedTo_NonGenericValidationFailedResult()
102+
{
103+
var genericResult = Result<int>.ValidationFailed("key", "message");
104+
105+
var validationFailedResult = Assert.IsType<ValidationFailedResult>(genericResult.Map());
106+
107+
Assert.Single(validationFailedResult.Errors);
108+
Assert.Equal("key", validationFailedResult.Errors.First().Key);
109+
Assert.Equal("message", validationFailedResult.Errors.First().Message);
110+
}
111+
112+
[Fact]
113+
public void GenericValidationPassedResult_IsConvertedTo_NonGenericValidationPassedResult()
114+
{
115+
var genericResult = new ValidationPassedResult<int>();
116+
117+
var validationFailedResult = Assert.IsType<ValidationPassedResult>(genericResult.Map());
118+
119+
Assert.Equal("Validation passed", validationFailedResult.Message);
120+
}
121+
122+
[Fact]
123+
public void GenericUnauthorizedResult_IsConvertedTo_NonGenericUnauthorizedResult()
124+
{
125+
var genericResult = Result<int>.Unauthorized("Something went wrong.");
126+
127+
var unauthorizedResult = Assert.IsType<UnauthorizedResult>(genericResult.Map());
128+
129+
Assert.Equal("Something went wrong.", unauthorizedResult.Message);
130+
}
131+
132+
[Fact]
133+
public void GenericPreconditionFailedResult_IsConvertedTo_NonGenericPreconditionFailedResult()
134+
{
135+
var genericResult = Result<int>.PreconditionFailed(PreconditionFailedReason.NotFound);
136+
137+
var preconditionFailedResult = Assert.IsType<PreconditionFailedResult>(genericResult.Map());
138+
139+
Assert.Equal(PreconditionFailedReason.NotFound, preconditionFailedResult.Reason);
90140
}
91141
}

src/F23.Kernel/Result.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,12 @@ public Result<TOther> MapFailure<TOther>() =>
155155
_ => throw new InvalidOperationException("Unknown result type")
156156
};
157157

158+
/// <summary>
159+
/// Maps the implementing generic Result to a non-generic <see cref="Result"/>.
160+
/// </summary>
161+
/// <returns>A new non-generic <see cref="Result"/>.</returns>
162+
public abstract Result Map();
163+
158164
/// <summary>
159165
/// Logs the failure result to the specified <see cref="ILogger"/>.
160166
/// </summary>
@@ -178,6 +184,7 @@ public void LogFailure(ILogger logger, LogLevel logLevel = LogLevel.Warning)
178184
break;
179185
default:
180186
throw new InvalidOperationException("Unknown result type");
181-
};
187+
}
188+
;
182189
}
183190
}

src/F23.Kernel/Results/PreconditionFailedResult.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,11 @@ public class PreconditionFailedResult<T>(PreconditionFailedReason reason, string
4646
/// Otherwise, it will return the default message associated with the
4747
/// <see cref="PreconditionFailedReason"/> value.
4848
/// </summary>
49-
public override string Message => message ?? Reason.ToMessage();
49+
public override string Message => message ?? Reason.ToMessage();
50+
51+
/// <summary>
52+
/// Maps this generic precondition failed result to a non-generic precondition failed result.
53+
/// </summary>
54+
/// <returns>A non-generic <see cref="PreconditionFailedResult"/>.</returns>
55+
public override Result Map() => new PreconditionFailedResult(Reason, Message);
5056
}

src/F23.Kernel/Results/SuccessResult.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,10 @@ public class SuccessResult<T>(T value) : Result<T>(true)
3030
/// This represents the successful outcome of the operation when the result is a <see cref="SuccessResult{T}"/>.
3131
/// </summary>
3232
public T Value => value;
33+
34+
/// <summary>
35+
/// Maps the current object to a successful result.
36+
/// </summary>
37+
/// <returns>A <see cref="Result"/> instance representing a successful operation.</returns>
38+
public override Result Map() => Success();
3339
}

src/F23.Kernel/Results/UnauthorizedResult.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,10 @@ public class UnauthorizedResult<T>(string message) : Result<T>(false)
2121
/// Gets a message describing the outcome of the operation.
2222
/// </summary>
2323
public override string Message => message;
24+
25+
/// <summary>
26+
/// Maps to a non-generic unauthorized result.
27+
/// </summary>
28+
/// <returns>A non-generic <see cref="UnauthorizedResult"/>.</returns>
29+
public override Result Map() => Result.Unauthorized(message);
2430
}

src/F23.Kernel/Results/ValidationFailedResult.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,11 @@ public class ValidationFailedResult<T>(IReadOnlyCollection<ValidationError> erro
3838
/// This property provides detailed information about the errors that occurred during validation,
3939
/// including the key associated with each error and its corresponding message.
4040
/// </remarks>
41-
public IReadOnlyCollection<ValidationError> Errors => errors;
41+
public IReadOnlyCollection<ValidationError> Errors => errors;
42+
43+
/// <summary>
44+
/// Maps the current validation errors to a <see cref="ValidationFailedResult"/>.
45+
/// </summary>
46+
/// <returns>A non-generic <see cref="ValidationFailedResult"/> containing the validation errors.</returns>
47+
public override Result Map() => new ValidationFailedResult(Errors);
4248
}

src/F23.Kernel/Results/ValidationPassedResult.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,10 @@ public class ValidationPassedResult<T>() : ValidationResult<T>(true)
2121
/// Gets a message describing the outcome of the operation.
2222
/// </summary>
2323
public override string Message => "Validation passed";
24+
25+
/// <summary>
26+
/// Maps to a non-generic <see cref="ValidationPassedResult"/> instance.
27+
/// </summary>
28+
/// <returns>A non-generic <see cref="ValidationPassedResult"/>.</returns>
29+
public override Result Map() => new ValidationPassedResult();
2430
}

0 commit comments

Comments
 (0)