diff --git a/Directory.Packages.props b/Directory.Packages.props index 4066a40..76dbaf9 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -4,14 +4,14 @@ - + - + - + diff --git a/samples/SimpleResults.Example.AspNetCore/GlobalUsings.cs b/samples/SimpleResults.Example.AspNetCore/GlobalUsings.cs index 858dd20..b73396e 100644 --- a/samples/SimpleResults.Example.AspNetCore/GlobalUsings.cs +++ b/samples/SimpleResults.Example.AspNetCore/GlobalUsings.cs @@ -1,4 +1,5 @@ global using System.Net.Mime; +global using System.Text.Json.Serialization; global using Bogus; global using Microsoft.AspNetCore.Mvc; global using Swashbuckle.AspNetCore.Annotations; diff --git a/samples/SimpleResults.Example.AspNetCore/Program.cs b/samples/SimpleResults.Example.AspNetCore/Program.cs index cf4d0cf..fa9d3d6 100644 --- a/samples/SimpleResults.Example.AspNetCore/Program.cs +++ b/samples/SimpleResults.Example.AspNetCore/Program.cs @@ -15,10 +15,15 @@ // Add filter for all controllers. options.Filters.Add(); }) +.AddJsonOptions(options => +{ + options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); +}) .ConfigureApiBehaviorOptions(options => { options.InvalidModelStateResponseFactory = (context) => context.ModelState.BadRequest(); }); + // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(options => diff --git a/samples/SimpleResults.Example.Web.Tests/Features/CreateOrderTests.cs b/samples/SimpleResults.Example.Web.Tests/Features/CreateOrderTests.cs index d08cdf6..8a173d7 100644 --- a/samples/SimpleResults.Example.Web.Tests/Features/CreateOrderTests.cs +++ b/samples/SimpleResults.Example.Web.Tests/Features/CreateOrderTests.cs @@ -38,6 +38,7 @@ public async Task Post_WhenOrderIsCreated_ShouldReturnsHttpStatusCodeCreated(str result.IsSuccess.Should().BeTrue(); result.Message.Should().NotBeNullOrEmpty(); result.Errors.Should().BeEmpty(); + result.Status.Should().Be(ResultStatus.Created); } [TestCase(Routes.Order.ManualValidation)] @@ -95,5 +96,6 @@ public async Task Post_WhenModelIsInvalid_ShouldReturnsHttpStatusCodeBadRequest( result.IsSuccess.Should().BeFalse(); result.Message.Should().NotBeNullOrEmpty(); result.Errors.Should().BeEquivalentTo(expectedErrors); + result.Status.Should().Be(ResultStatus.Invalid); } } diff --git a/samples/SimpleResults.Example.Web.Tests/Features/CreatePersonTests.cs b/samples/SimpleResults.Example.Web.Tests/Features/CreatePersonTests.cs index 492196d..5979d90 100644 --- a/samples/SimpleResults.Example.Web.Tests/Features/CreatePersonTests.cs +++ b/samples/SimpleResults.Example.Web.Tests/Features/CreatePersonTests.cs @@ -26,6 +26,7 @@ public async Task Post_WhenPersonIsCreated_ShouldReturnsHttpStatusCodeCreated(st result.IsSuccess.Should().BeTrue(); result.Message.Should().NotBeNullOrEmpty(); result.Errors.Should().BeEmpty(); + result.Status.Should().Be(ResultStatus.Created); } [TestCase(Routes.Person.WebApi)] @@ -52,5 +53,6 @@ public async Task Post_WhenPropertiesAreEmpty_ShouldReturnsHttpStatusCodeBadRequ result.IsSuccess.Should().BeFalse(); result.Message.Should().NotBeNullOrEmpty(); result.Errors.Should().NotBeNullOrEmpty(); + result.Status.Should().Be(ResultStatus.Invalid); } } diff --git a/samples/SimpleResults.Example.Web.Tests/Features/CreateUserTests.cs b/samples/SimpleResults.Example.Web.Tests/Features/CreateUserTests.cs index b1d7f77..0c044f8 100644 --- a/samples/SimpleResults.Example.Web.Tests/Features/CreateUserTests.cs +++ b/samples/SimpleResults.Example.Web.Tests/Features/CreateUserTests.cs @@ -23,6 +23,7 @@ public async Task Post_WhenUserIsCreated_ShouldReturnsHttpStatusCodeCreated(stri result.IsSuccess.Should().BeTrue(); result.Message.Should().NotBeNullOrEmpty(); result.Errors.Should().BeEmpty(); + result.Status.Should().Be(ResultStatus.Created); } [TestCase(Routes.User.WebApi)] @@ -46,5 +47,6 @@ public async Task Post_WhenNameIsEmpty_ShouldReturnsHttpStatusCodeBadRequest(str result.IsSuccess.Should().BeFalse(); result.Message.Should().NotBeNullOrEmpty(); result.Errors.Should().BeEmpty(); + result.Status.Should().Be(ResultStatus.Invalid); } } diff --git a/samples/SimpleResults.Example.Web.Tests/Features/DeleteUserTests.cs b/samples/SimpleResults.Example.Web.Tests/Features/DeleteUserTests.cs index 6a2c26e..d651bbe 100644 --- a/samples/SimpleResults.Example.Web.Tests/Features/DeleteUserTests.cs +++ b/samples/SimpleResults.Example.Web.Tests/Features/DeleteUserTests.cs @@ -23,6 +23,7 @@ public async Task Delete_WhenUserIsDeleted_ShouldReturnsHttpStatusCodeOk(string result.IsSuccess.Should().BeTrue(); result.Message.Should().NotBeNullOrEmpty(); result.Errors.Should().BeEmpty(); + result.Status.Should().Be(ResultStatus.Ok); } [TestCase(Routes.User.WebApi)] @@ -44,5 +45,6 @@ public async Task Delete_WhenUserIsNotFound_ShouldReturnsHttpStatusCodeNotFound( result.IsSuccess.Should().BeFalse(); result.Message.Should().NotBeNullOrEmpty(); result.Errors.Should().BeEmpty(); + result.Status.Should().Be(ResultStatus.NotFound); } } diff --git a/samples/SimpleResults.Example.Web.Tests/Features/GetFileResultTests.cs b/samples/SimpleResults.Example.Web.Tests/Features/GetFileResultTests.cs index d0722ad..0d71c5d 100644 --- a/samples/SimpleResults.Example.Web.Tests/Features/GetFileResultTests.cs +++ b/samples/SimpleResults.Example.Web.Tests/Features/GetFileResultTests.cs @@ -47,5 +47,6 @@ public async Task Get_WhenFileNameIsEmpty_ShouldReturnsHttpStatusCodeBadRequest( result.IsSuccess.Should().BeFalse(); result.Message.Should().NotBeNullOrEmpty(); result.Errors.Should().BeEmpty(); + result.Status.Should().Be(ResultStatus.Invalid); } } diff --git a/samples/SimpleResults.Example.Web.Tests/Features/GetMessageTests.cs b/samples/SimpleResults.Example.Web.Tests/Features/GetMessageTests.cs index fdd1a6c..dc550d1 100644 --- a/samples/SimpleResults.Example.Web.Tests/Features/GetMessageTests.cs +++ b/samples/SimpleResults.Example.Web.Tests/Features/GetMessageTests.cs @@ -21,6 +21,7 @@ public async Task Get_WhenMessageIsBan_ShouldReturnsHttpStatusCodeForbidden(stri result.IsSuccess.Should().BeFalse(); result.Message.Should().NotBeNullOrEmpty(); result.Errors.Should().BeEmpty(); + result.Status.Should().Be(ResultStatus.Forbidden); } [TestCase(Routes.Message.WebApi)] @@ -42,6 +43,7 @@ public async Task Get_WhenMessageIsError_ShouldReturnsHttpStatusCodeServerError( result.IsSuccess.Should().BeFalse(); result.Message.Should().NotBeNullOrEmpty(); result.Errors.Should().BeEmpty(); + result.Status.Should().Be(ResultStatus.CriticalError); } [TestCase(Routes.Message.WebApi)] @@ -63,5 +65,6 @@ public async Task Get_WhenMessageIsFalseIdentity_ShouldReturnsHttpStatusCodeUnau result.IsSuccess.Should().BeFalse(); result.Message.Should().NotBeNullOrEmpty(); result.Errors.Should().BeEmpty(); + result.Status.Should().Be(ResultStatus.Unauthorized); } } diff --git a/samples/SimpleResults.Example.Web.Tests/Features/GetPagedUsersTests.cs b/samples/SimpleResults.Example.Web.Tests/Features/GetPagedUsersTests.cs index 0b99a1f..aa37d03 100644 --- a/samples/SimpleResults.Example.Web.Tests/Features/GetPagedUsersTests.cs +++ b/samples/SimpleResults.Example.Web.Tests/Features/GetPagedUsersTests.cs @@ -24,6 +24,7 @@ public async Task Get_WhenPaginatedListIsObtained_ShouldReturnsHttpStatusCodeOk( result.IsSuccess.Should().BeTrue(); result.Message.Should().NotBeNullOrEmpty(); result.Errors.Should().BeEmpty(); + result.Status.Should().Be(ResultStatus.Ok); } [TestCase(Routes.User.WebApi)] @@ -48,6 +49,7 @@ public async Task Get_WhenNoResultsFound_ShouldReturnsHttpStatusCodeUnprocessabl result.IsSuccess.Should().BeFalse(); result.Message.Should().NotBeNullOrEmpty(); result.Errors.Should().BeEmpty(); + result.Status.Should().Be(ResultStatus.Failure); } [TestCase(Routes.User.WebApi)] @@ -72,5 +74,6 @@ public async Task Get_WhenPageNumberIsZero_ShouldReturnsHttpStatusCodeBadRequest result.IsSuccess.Should().BeFalse(); result.Message.Should().NotBeNullOrEmpty(); result.Errors.Should().BeEmpty(); + result.Status.Should().Be(ResultStatus.Invalid); } } diff --git a/samples/SimpleResults.Example.Web.Tests/Features/GetPersonsTests.cs b/samples/SimpleResults.Example.Web.Tests/Features/GetPersonsTests.cs index b7cb566..7fcb3e2 100644 --- a/samples/SimpleResults.Example.Web.Tests/Features/GetPersonsTests.cs +++ b/samples/SimpleResults.Example.Web.Tests/Features/GetPersonsTests.cs @@ -24,6 +24,7 @@ public async Task Get_WhenPersonsAreObtained_ShouldReturnsHttpStatusCodeOk(strin result.IsSuccess.Should().BeTrue(); result.Message.Should().NotBeNullOrEmpty(); result.Errors.Should().BeEmpty(); + result.Status.Should().Be(ResultStatus.Ok); } [TestCase(Routes.Person.WebApi)] @@ -48,5 +49,6 @@ public async Task Get_WhenThereAreNoPersons_ShouldReturnsHttpStatusCodeUnprocess result.IsSuccess.Should().BeFalse(); result.Message.Should().NotBeNullOrEmpty(); result.Errors.Should().BeEmpty(); + result.Status.Should().Be(ResultStatus.Failure); } } diff --git a/samples/SimpleResults.Example.Web.Tests/Features/GetUserByIdTests.cs b/samples/SimpleResults.Example.Web.Tests/Features/GetUserByIdTests.cs index b8711e9..03641b6 100644 --- a/samples/SimpleResults.Example.Web.Tests/Features/GetUserByIdTests.cs +++ b/samples/SimpleResults.Example.Web.Tests/Features/GetUserByIdTests.cs @@ -24,6 +24,7 @@ public async Task Get_WhenUserIsObtained_ShouldReturnsHttpStatusCodeOk(string re result.IsSuccess.Should().BeTrue(); result.Message.Should().NotBeNullOrEmpty(); result.Errors.Should().BeEmpty(); + result.Status.Should().Be(ResultStatus.Ok); } [TestCase(Routes.User.WebApi)] @@ -46,5 +47,6 @@ public async Task Get_WhenUserIsNotFound_ShouldReturnsHttpStatusCodeNotFound(str result.IsSuccess.Should().BeFalse(); result.Message.Should().NotBeNullOrEmpty(); result.Errors.Should().BeEmpty(); + result.Status.Should().Be(ResultStatus.NotFound); } } diff --git a/samples/SimpleResults.Example.Web.Tests/Features/GetUsersTests.cs b/samples/SimpleResults.Example.Web.Tests/Features/GetUsersTests.cs index 967f6ba..cee1361 100644 --- a/samples/SimpleResults.Example.Web.Tests/Features/GetUsersTests.cs +++ b/samples/SimpleResults.Example.Web.Tests/Features/GetUsersTests.cs @@ -22,6 +22,7 @@ public async Task Get_WhenUsersAreObtained_ShouldReturnsHttpStatusCodeOk(string result.IsSuccess.Should().BeTrue(); result.Message.Should().NotBeNullOrEmpty(); result.Errors.Should().BeEmpty(); + result.Status.Should().Be(ResultStatus.Ok); } [TestCase(Routes.User.WebApi)] @@ -46,5 +47,6 @@ public async Task Get_WhenThereAreNoUsers_ShouldReturnsHttpStatusCodeUnprocessab result.IsSuccess.Should().BeFalse(); result.Message.Should().NotBeNullOrEmpty(); result.Errors.Should().BeEmpty(); + result.Status.Should().Be(ResultStatus.Failure); } } diff --git a/samples/SimpleResults.Example.Web.Tests/Features/UpdateUserTests.cs b/samples/SimpleResults.Example.Web.Tests/Features/UpdateUserTests.cs index 9dd8a4f..9f2b07b 100644 --- a/samples/SimpleResults.Example.Web.Tests/Features/UpdateUserTests.cs +++ b/samples/SimpleResults.Example.Web.Tests/Features/UpdateUserTests.cs @@ -24,6 +24,7 @@ public async Task Put_WhenUserIsUpdated_ShouldReturnsHttpStatusCodeOk(string req result.IsSuccess.Should().BeTrue(); result.Message.Should().NotBeNullOrEmpty(); result.Errors.Should().BeEmpty(); + result.Status.Should().Be(ResultStatus.Ok); } [TestCase(Routes.User.WebApi)] @@ -46,6 +47,7 @@ public async Task Put_WhenUserIsNotFound_ShouldReturnsHttpStatusCodeNotFound(str result.IsSuccess.Should().BeFalse(); result.Message.Should().NotBeNullOrEmpty(); result.Errors.Should().BeEmpty(); + result.Status.Should().Be(ResultStatus.NotFound); } [TestCase(Routes.User.WebApi)] @@ -68,5 +70,6 @@ public async Task Put_WhenNameIsEmpty_ShouldReturnsHttpStatusCodeBadRequest(stri result.IsSuccess.Should().BeFalse(); result.Message.Should().NotBeNullOrEmpty(); result.Errors.Should().BeEmpty(); + result.Status.Should().Be(ResultStatus.Invalid); } } diff --git a/src/Core/ResultBase.cs b/src/Core/ResultBase.cs index b088131..fb82c8a 100644 --- a/src/Core/ResultBase.cs +++ b/src/Core/ResultBase.cs @@ -10,6 +10,16 @@ namespace SimpleResults; /// public abstract class ResultBase { + /// + /// Gets the current status of a result. + /// + /// + /// The current status of a result. + /// Its default value is a . + /// + [JsonConverter(typeof(JsonStringEnumConverter))] + public ResultStatus Status { get; init; } = ResultStatus.Failure; + /// /// A value indicating that the result was successful. /// @@ -39,14 +49,4 @@ public abstract class ResultBase /// Its default value is never a null value. /// public IEnumerable Errors { get; init; } = Enumerable.Empty(); - - /// - /// Gets the current status of a result. - /// - /// - /// The current status of a result. - /// Its default value is a . - /// - [JsonIgnore] - public ResultStatus Status { get; init; } = ResultStatus.Failure; } diff --git a/tests/Core/Json/SystemTextJson.ListedResultOfT.Tests.cs b/tests/Core/Json/SystemTextJson.ListedResultOfT.Tests.cs index 8347187..db0049b 100644 --- a/tests/Core/Json/SystemTextJson.ListedResultOfT.Tests.cs +++ b/tests/Core/Json/SystemTextJson.ListedResultOfT.Tests.cs @@ -16,6 +16,7 @@ public void ListedResultOfT_ShouldSerializeResultOfValueType() 1, 2 ], + "status": "Ok", "success": true, "message": "{{ResponseMessages.Success}}", "errors": [] @@ -51,6 +52,7 @@ public void ListedResultOfT_ShouldSerializeResultOfReferenceType() "name": "Alice" } ], + "status": "Ok", "success": true, "message": "{{ResponseMessages.Success}}", "errors": [] @@ -78,6 +80,7 @@ public void ListedResultOfT_ShouldDeserializeResultOfValueType() 1, 2 ], + "status": "Ok", "success": true, "message": "{{ResponseMessages.Success}}", "errors": [] @@ -88,9 +91,7 @@ public void ListedResultOfT_ShouldDeserializeResultOfValueType() var actual = JsonSerializer.Deserialize>(json, options); // Assert - actual - .Should() - .BeEquivalentTo(expectedResult, o => o.Excluding(r => r.Status)); + actual.Should().BeEquivalentTo(expectedResult); } [Test] @@ -115,6 +116,7 @@ public void ListedResultOfT_ShouldDeserializeResultOfReferenceType() "name": "Alice" } ], + "status": "Ok", "success": true, "message": "{{ResponseMessages.Success}}", "errors": [] @@ -125,8 +127,6 @@ public void ListedResultOfT_ShouldDeserializeResultOfReferenceType() var actual = JsonSerializer.Deserialize>(json, options); // Assert - actual - .Should() - .BeEquivalentTo(expectedResult, o => o.Excluding(r => r.Status)); + actual.Should().BeEquivalentTo(expectedResult); } } diff --git a/tests/Core/Json/SystemTextJson.PagedResultOfT.Tests.cs b/tests/Core/Json/SystemTextJson.PagedResultOfT.Tests.cs index 91ea19e..540560c 100644 --- a/tests/Core/Json/SystemTextJson.PagedResultOfT.Tests.cs +++ b/tests/Core/Json/SystemTextJson.PagedResultOfT.Tests.cs @@ -26,6 +26,7 @@ public void PagedResultOfT_ShouldSerializeResultOfValueType() "hasPrevious": false, "hasNext": true }, + "status": "Ok", "success": true, "message": "{{ResponseMessages.ObtainedResources}}", "errors": [] @@ -70,6 +71,7 @@ public void PagedResultOfT_ShouldSerializeResultOfReferenceType() "hasPrevious": false, "hasNext": true }, + "status": "Ok", "success": true, "message": "{{ResponseMessages.ObtainedResources}}", "errors": [] @@ -107,6 +109,7 @@ public void PagedResultOfT_ShouldDeserializeResultOfValueType() "hasPrevious": false, "hasNext": true }, + "status": "Ok", "success": true, "message": "{{ResponseMessages.ObtainedResources}}", "errors": [] @@ -117,9 +120,7 @@ public void PagedResultOfT_ShouldDeserializeResultOfValueType() var actual = JsonSerializer.Deserialize>(json, options); // Assert - actual - .Should() - .BeEquivalentTo(expectedResult, o => o.Excluding(r => r.Status)); + actual.Should().BeEquivalentTo(expectedResult); } [Test] @@ -153,6 +154,7 @@ public void PagedResultOfT_ShouldDeserializeResultOfReferenceType() "hasPrevious": false, "hasNext": true }, + "status": "Ok", "success": true, "message": "{{ResponseMessages.ObtainedResources}}", "errors": [] @@ -163,8 +165,6 @@ public void PagedResultOfT_ShouldDeserializeResultOfReferenceType() var actual = JsonSerializer.Deserialize>(json, options); // Assert - actual - .Should() - .BeEquivalentTo(expectedResult, o => o.Excluding(r => r.Status)); + actual.Should().BeEquivalentTo(expectedResult); } } diff --git a/tests/Core/Json/SystemTextJson.Result.Tests.cs b/tests/Core/Json/SystemTextJson.Result.Tests.cs index d28ce91..c554096 100644 --- a/tests/Core/Json/SystemTextJson.Result.Tests.cs +++ b/tests/Core/Json/SystemTextJson.Result.Tests.cs @@ -11,6 +11,7 @@ public void Result_ShouldSerializeResultWithoutData() var expectedJson = $$""" { + "status": "Ok", "success": true, "message": "{{ResponseMessages.Success}}", "errors": [] @@ -33,6 +34,7 @@ public void Result_ShouldDeserializeResultWithoutData() var json = $$""" { + "status": "Ok", "success": true, "message": "{{ResponseMessages.Success}}", "errors": [] @@ -43,8 +45,6 @@ public void Result_ShouldDeserializeResultWithoutData() var actual = JsonSerializer.Deserialize(json, options); // Assert - actual - .Should() - .BeEquivalentTo(expectedResult, o => o.Excluding(r => r.Status)); + actual.Should().BeEquivalentTo(expectedResult); } } diff --git a/tests/Core/Json/SystemTextJson.ResultOfT.Tests.cs b/tests/Core/Json/SystemTextJson.ResultOfT.Tests.cs index 9b2a89e..599ea17 100644 --- a/tests/Core/Json/SystemTextJson.ResultOfT.Tests.cs +++ b/tests/Core/Json/SystemTextJson.ResultOfT.Tests.cs @@ -12,6 +12,7 @@ public void ResultOfT_ShouldSerializeResultOfValueType() $$""" { "data": 1, + "status": "Ok", "success": true, "message": "{{ResponseMessages.Success}}", "errors": [] @@ -37,6 +38,7 @@ public void ResultOfT_ShouldSerializeResultOfReferenceType() "data": { "name": "Test" }, + "status": "Ok", "success": true, "message": "{{ResponseMessages.Success}}", "errors": [] @@ -60,6 +62,7 @@ public void ResultOfT_ShouldDeserializeResultOfValueType() $$""" { "data": 1, + "status": "Ok", "success": true, "message": "{{ResponseMessages.Success}}", "errors": [] @@ -70,9 +73,7 @@ public void ResultOfT_ShouldDeserializeResultOfValueType() var actual = JsonSerializer.Deserialize>(json, options); // Assert - actual - .Should() - .BeEquivalentTo(expectedResult, o => o.Excluding(r => r.Status)); + actual.Should().BeEquivalentTo(expectedResult); } [Test] @@ -87,6 +88,7 @@ public void ResultOfT_ShouldDeserializeResultOfCreatedIdType() "data": { "Id": 1 }, + "status": "Ok", "success": true, "message": "{{ResponseMessages.Success}}", "errors": [] @@ -97,9 +99,7 @@ public void ResultOfT_ShouldDeserializeResultOfCreatedIdType() var actual = JsonSerializer.Deserialize>(json, options); // Assert - actual - .Should() - .BeEquivalentTo(expectedResult, o => o.Excluding(r => r.Status)); + actual.Should().BeEquivalentTo(expectedResult); } [Test] @@ -115,6 +115,7 @@ public void ResultOfT_ShouldDeserializeResultOfCreatedGuidType() "data": { "Id": "{{guid}}" }, + "status": "Ok", "success": true, "message": "{{ResponseMessages.Success}}", "errors": [] @@ -125,8 +126,6 @@ public void ResultOfT_ShouldDeserializeResultOfCreatedGuidType() var actual = JsonSerializer.Deserialize>(json, options); // Assert - actual - .Should() - .BeEquivalentTo(expectedResult, o => o.Excluding(r => r.Status)); + actual.Should().BeEquivalentTo(expectedResult); } }