diff --git a/.github/workflows/xunit-tests.yml b/.github/workflows/xunit-tests.yml new file mode 100644 index 0000000..d96ed70 --- /dev/null +++ b/.github/workflows/xunit-tests.yml @@ -0,0 +1,32 @@ +# This workflow will build a .NET project +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net +name: xunit-tests +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] +jobs: + build: + + runs-on: ubuntu-latest + strategy: + matrix: + dotnet-version: [ '7.0.x' ] + permissions: + actions: read + contents: read + security-events: write + + steps: + - uses: actions/checkout@v3 + - name: Setup .NET Core SDK ${{ matrix.dotnet-version }} + uses: actions/setup-dotnet@v3 + with: + dotnet-version: ${{ matrix.dotnet-version }} + + - name: Install dependencies + run: dotnet restore + + - name: Test + run: dotnet test test/SampleDotnet.Result.Tests/SampleDotnet.Result.Tests.csproj --no-restore --verbosity normal diff --git a/src/SampleDotnet.Result/BadRequestResponse.cs b/src/SampleDotnet.Result/BadRequestResponse.cs index c7f1a62..9fb661c 100644 --- a/src/SampleDotnet.Result/BadRequestResponse.cs +++ b/src/SampleDotnet.Result/BadRequestResponse.cs @@ -1,6 +1,6 @@ namespace SampleDotnet.Result; -public sealed class BadRequestResponse +public class BadRequestResponse : BaseJsonResult { public BadRequestResponse() diff --git a/src/SampleDotnet.Result/InternalServerErrorResponse.cs b/src/SampleDotnet.Result/InternalServerErrorResponse.cs index 3b3cec6..e942343 100644 --- a/src/SampleDotnet.Result/InternalServerErrorResponse.cs +++ b/src/SampleDotnet.Result/InternalServerErrorResponse.cs @@ -1,6 +1,6 @@ namespace SampleDotnet.Result; -public sealed class InternalServerErrorResponse +public class InternalServerErrorResponse : BaseJsonResult { public InternalServerErrorResponse() diff --git a/src/SampleDotnet.Result/NotFoundResponse.cs b/src/SampleDotnet.Result/NotFoundResponse.cs index 5ec9433..ead53c2 100644 --- a/src/SampleDotnet.Result/NotFoundResponse.cs +++ b/src/SampleDotnet.Result/NotFoundResponse.cs @@ -1,6 +1,6 @@ namespace SampleDotnet.Result; -public sealed class NotFoundResponse +public class NotFoundResponse : BaseJsonResult { public NotFoundResponse() @@ -9,7 +9,7 @@ public NotFoundResponse() } public NotFoundResponse(string message) - : base(StatusCodes.Status400BadRequest, message) + : base(StatusCodes.Status404NotFound, message) { } } \ No newline at end of file diff --git a/src/SampleDotnet.Result/OkResponse.cs b/src/SampleDotnet.Result/OkResponse.cs index 4156c9f..70f06f1 100644 --- a/src/SampleDotnet.Result/OkResponse.cs +++ b/src/SampleDotnet.Result/OkResponse.cs @@ -1,6 +1,6 @@ namespace SampleDotnet.Result; -public sealed class OkResponse +public class OkResponse : BaseJsonResult { public OkResponse() diff --git a/src/SampleDotnet.Result/StatusCodeResponse.cs b/src/SampleDotnet.Result/StatusCodeResponse.cs new file mode 100644 index 0000000..a6f786e --- /dev/null +++ b/src/SampleDotnet.Result/StatusCodeResponse.cs @@ -0,0 +1,26 @@ +namespace SampleDotnet.Result +{ + public class StatusCodeResponse + : BaseJsonResult + { + public StatusCodeResponse(int statusCode) : base(statusCode) + { + } + + public StatusCodeResponse(int statusCode, IEnumerable errorMessages) : base(statusCode, errorMessages) + { + } + + public StatusCodeResponse(int statusCode, string errorMessages) : base(statusCode, errorMessages) + { + } + + public StatusCodeResponse(int statusCode, object body) : base(statusCode, body) + { + } + + public StatusCodeResponse(int statusCode, IEnumerable body) : base(statusCode, body) + { + } + } +} \ No newline at end of file diff --git a/src/SampleDotnet.Result/UnauthorizedResponse.cs b/src/SampleDotnet.Result/UnauthorizedResponse.cs index 49af1a1..85aca97 100644 --- a/src/SampleDotnet.Result/UnauthorizedResponse.cs +++ b/src/SampleDotnet.Result/UnauthorizedResponse.cs @@ -1,6 +1,6 @@ namespace SampleDotnet.Result; -public sealed class UnauthorizedResponse +public class UnauthorizedResponse : BaseJsonResult { public UnauthorizedResponse() diff --git a/test/SampleDotnet.Result.Tests/BadRequestResponseTests.cs b/test/SampleDotnet.Result.Tests/BadRequestResponseTests.cs new file mode 100644 index 0000000..b636590 --- /dev/null +++ b/test/SampleDotnet.Result.Tests/BadRequestResponseTests.cs @@ -0,0 +1,71 @@ +namespace SampleDotnet.Result.Tests; + +public class BadRequestResponseTests +{ + private const int statusCode_BADREQUEST = 400; + + [Fact] + public void BadRequestResponse_Default() + { + BadRequestResponse response = new BadRequestResponse(); + + response.Model.Errors.ShouldBeNull(); + response.ShouldBeDefaultResponseModel(new ResponseModel()); + } + + [Fact] + public void BadRequestResponse_Ctor1() + { + string responseObject = "error message1"; + BadRequestResponse response = new BadRequestResponse(responseObject); + + response.ShouldValidatetCommons(statusCode_BADREQUEST); + response.Model.ShouldNotBeNull(); + response.Model.GetType().ShouldBeEquivalentTo(typeof(ResponseModel)); + + ResponseModel responseModel = new ResponseModel(responseObject); + response.ShouldSerializeAndDeserialize(responseModel); + } + + [Fact] + public void BadRequestResponse_Ctor2() + { + IEnumerable responseObjects = new List { "error message1", "error message2" }; + BadRequestResponse response = new BadRequestResponse(responseObjects); + + response.ShouldValidatetCommons(statusCode_BADREQUEST); + response.Model.ShouldNotBeNull(); + response.Model.GetType().ShouldBeEquivalentTo(typeof(ResponseModel)); + + ResponseModel responseModel = new ResponseModel(responseObjects); + response.ShouldSerializeAndDeserialize(responseModel); + } + + [Fact] + public void StatusCodeResponse_Ctor1() + { + string responseObject = "error message1"; + StatusCodeResponse response = new StatusCodeResponse(statusCode_BADREQUEST, responseObject); + + response.ShouldValidatetCommons(statusCode_BADREQUEST); + response.Model.ShouldNotBeNull(); + response.Model.GetType().ShouldBeEquivalentTo(typeof(ResponseModel)); + + ResponseModel responseModel = new ResponseModel(responseObject); + response.ShouldSerializeAndDeserialize(responseModel); + } + + [Fact] + public void StatusCodeResponse_Ctor2() + { + IEnumerable responseObjects = new List { "error message1", "error message2" }; + StatusCodeResponse response = new StatusCodeResponse(statusCode_BADREQUEST, responseObjects); + + response.ShouldValidatetCommons(statusCode_BADREQUEST); + response.Model.ShouldNotBeNull(); + response.Model.GetType().ShouldBeEquivalentTo(typeof(ResponseModel)); + + ResponseModel responseModel = new ResponseModel(responseObjects); + response.ShouldSerializeAndDeserialize(responseModel); + } +} \ No newline at end of file diff --git a/test/SampleDotnet.Result.Tests/ExecuteTests.cs b/test/SampleDotnet.Result.Tests/ExecuteTests.cs new file mode 100644 index 0000000..1429fd8 --- /dev/null +++ b/test/SampleDotnet.Result.Tests/ExecuteTests.cs @@ -0,0 +1,10 @@ +namespace SampleDotnet.Result.Tests; + +public class ExecuteTests +{ + [Fact] + public void Execute_Stats1() + { + //TODO: initialize demo app with WebApplicationFactory then exetuce ActionContext + } +} \ No newline at end of file diff --git a/test/SampleDotnet.Result.Tests/InternalServerErrorResponseTests.cs b/test/SampleDotnet.Result.Tests/InternalServerErrorResponseTests.cs new file mode 100644 index 0000000..d303017 --- /dev/null +++ b/test/SampleDotnet.Result.Tests/InternalServerErrorResponseTests.cs @@ -0,0 +1,43 @@ +namespace SampleDotnet.Result.Tests; + +public class InternalServerErrorResponseTests +{ + private const int statusCode_INTERNALSERVERERROR = 500; + + [Fact] + public void InternalServerErrorResponse_Default() + { + InternalServerErrorResponse response = new InternalServerErrorResponse(); + + response.Model.Errors.ShouldBeNull(); + response.ShouldBeDefaultResponseModel(new ResponseModel()); + } + + [Fact] + public void InternalServerErrorResponse_Ctor1() + { + string responseObject = "User Friendly Message1"; + InternalServerErrorResponse response = new InternalServerErrorResponse(responseObject); + + response.ShouldValidatetCommons(statusCode_INTERNALSERVERERROR); + response.Model.ShouldNotBeNull(); + response.Model.GetType().ShouldBeEquivalentTo(typeof(ResponseModel)); + + ResponseModel responseModel = new ResponseModel(responseObject); + response.ShouldSerializeAndDeserialize(responseModel); + } + + [Fact] + public void InternalServerErrorResponse_Ctor2() + { + IEnumerable responseObjects = new List { "User Friendly Message1", "User Friendly Message2" }; + InternalServerErrorResponse response = new InternalServerErrorResponse(responseObjects); + + response.ShouldValidatetCommons(statusCode_INTERNALSERVERERROR); + response.Model.ShouldNotBeNull(); + response.Model.GetType().ShouldBeEquivalentTo(typeof(ResponseModel)); + + ResponseModel responseModel = new ResponseModel(responseObjects); + response.ShouldSerializeAndDeserialize(responseModel); + } +} \ No newline at end of file diff --git a/test/SampleDotnet.Result.Tests/NotFoundResponseTests.cs b/test/SampleDotnet.Result.Tests/NotFoundResponseTests.cs new file mode 100644 index 0000000..0e0b2ba --- /dev/null +++ b/test/SampleDotnet.Result.Tests/NotFoundResponseTests.cs @@ -0,0 +1,29 @@ +namespace SampleDotnet.Result.Tests; + +public class NotFoundResponseTests +{ + private const int statusCode_NOTFOUND = 404; + + [Fact] + public void NotFoundResponse_Default() + { + NotFoundResponse response = new NotFoundResponse(); + + response.Model.Errors.ShouldBeNull(); + response.ShouldBeDefaultResponseModel(new ResponseModel()); + } + + [Fact] + public void NotFoundResponse_Ctor1() + { + string responseObject = "NotFound error message1"; + NotFoundResponse response = new NotFoundResponse(responseObject); + + response.ShouldValidatetCommons(statusCode_NOTFOUND); + response.Model.ShouldNotBeNull(); + response.Model.GetType().ShouldBeEquivalentTo(typeof(ResponseModel)); + + ResponseModel responseModel = new ResponseModel(responseObject); + response.ShouldSerializeAndDeserialize(responseModel); + } +} \ No newline at end of file diff --git a/test/SampleDotnet.Result.Tests/OkResponseTests.cs b/test/SampleDotnet.Result.Tests/OkResponseTests.cs new file mode 100644 index 0000000..52ea5a3 --- /dev/null +++ b/test/SampleDotnet.Result.Tests/OkResponseTests.cs @@ -0,0 +1,78 @@ +namespace SampleDotnet.Result.Tests; + +public class OkResponseTests +{ + private const int statusCode_OK = 200; + + [Fact] + public void OkResponse_Default() + { + OkResponse response = new OkResponse(); + + response.Model.Errors.ShouldBeNull(); + response.ShouldValidatetCommons(statusCode_OK); + response.ShouldBeDefaultResponseModel(new ResponseModel()); + } + + [Fact] + public void OkResponse_Ctor1() + { + OkResponseTestData responseObject = new OkResponseTestData { strval1 = "valueOfName" }; + OkResponse response = new OkResponse(responseObject); + + response.ShouldValidatetCommons(statusCode_OK); + response.Model.Errors.ShouldBeNull(); + response.Model.GetType().ShouldBeEquivalentTo(typeof(ResponseModel)); + + ResponseModel responseModel = new ResponseModel(responseObject); + response.ShouldSerializeAndDeserialize(responseModel); + } + + [Fact] + public void OkResponse_Ctor2() + { + IEnumerable responseObjects = new List { new OkResponseTestData() { strval1 = "valueOfName1", intval1 = 1 }, new OkResponseTestData { strval1 = "valueOfName2", intval1 = 2 } }; + OkResponse response = new OkResponse(responseObjects); + + response.ShouldValidatetCommons(statusCode_OK); + response.Model.Errors.ShouldBeNull(); + response.Model.GetType().ShouldBeEquivalentTo(typeof(ResponseModel)); + + ResponseModel responseModel = new ResponseModel(responseObjects); + response.ShouldSerializeAndDeserialize(responseModel); + } + + [Fact] + public void StatusCodeResponse_Ctor1() + { + OkResponseTestData responseObject = new OkResponseTestData { strval1 = "valueOfName" }; + StatusCodeResponse response = new StatusCodeResponse(statusCode_OK, responseObject); + + response.ShouldValidatetCommons(statusCode_OK); + response.Model.Errors.ShouldBeNull(); + response.Model.GetType().ShouldBeEquivalentTo(typeof(ResponseModel)); + + ResponseModel responseModel = new ResponseModel(responseObject); + response.ShouldSerializeAndDeserialize(responseModel); + } + + [Fact] + public void StatusCodeResponse_Ctor2() + { + IEnumerable responseObjects = new List { new OkResponseTestData() { strval1 = "valueOfName1", intval1 = 1 }, new OkResponseTestData { strval1 = "valueOfName2", intval1 = 2 } }; + StatusCodeResponse response = new StatusCodeResponse(statusCode_OK, responseObjects); + + response.ShouldValidatetCommons(statusCode_OK); + response.Model.Errors.ShouldBeNull(); + response.Model.GetType().ShouldBeEquivalentTo(typeof(ResponseModel)); + + ResponseModel responseModel = new ResponseModel(responseObjects); + response.ShouldSerializeAndDeserialize(responseModel); + } +} + +internal class OkResponseTestData +{ + public int intval1 { get; set; } + public string strval1 { get; set; } +} \ No newline at end of file diff --git a/test/SampleDotnet.Result.Tests/SampleDotnet.Result.Tests.csproj b/test/SampleDotnet.Result.Tests/SampleDotnet.Result.Tests.csproj index c4f43a8..fbacdab 100644 --- a/test/SampleDotnet.Result.Tests/SampleDotnet.Result.Tests.csproj +++ b/test/SampleDotnet.Result.Tests/SampleDotnet.Result.Tests.csproj @@ -1,7 +1,7 @@ - + - net5.0 + net7.0 enable enable false @@ -15,6 +15,26 @@ + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + diff --git a/test/SampleDotnet.Result.Tests/UnauthorizedResponseTests.cs b/test/SampleDotnet.Result.Tests/UnauthorizedResponseTests.cs new file mode 100644 index 0000000..3230182 --- /dev/null +++ b/test/SampleDotnet.Result.Tests/UnauthorizedResponseTests.cs @@ -0,0 +1,43 @@ +namespace SampleDotnet.Result.Tests; + +public class UnauthorizedResponseTests +{ + private const int statusCode_UNAUTHORIZED = 401; + + [Fact] + public void UnauthorizedResponse_Ctor1() + { + string responseObject = "Unauthorized message1"; + UnauthorizedResponse response = new UnauthorizedResponse(responseObject); + + response.ShouldValidatetCommons(statusCode_UNAUTHORIZED); + response.Model.ShouldNotBeNull(); + response.Model.GetType().ShouldBeEquivalentTo(typeof(ResponseModel)); + + ResponseModel responseModel = new ResponseModel(responseObject); + response.ShouldSerializeAndDeserialize(responseModel); + } + + [Fact] + public void UnauthorizedResponse_Ctor2() + { + IEnumerable responseObjects = new List { "Unauthorized message1", "Unauthorized message2" }; + UnauthorizedResponse response = new UnauthorizedResponse(responseObjects); + + response.ShouldValidatetCommons(statusCode_UNAUTHORIZED); + response.Model.ShouldNotBeNull(); + response.Model.GetType().ShouldBeEquivalentTo(typeof(ResponseModel)); + + ResponseModel responseModel = new ResponseModel(responseObjects); + response.ShouldSerializeAndDeserialize(responseModel); + } + + [Fact] + public void UnauthorizedResponse_Default() + { + UnauthorizedResponse response = new UnauthorizedResponse(); + + response.Model.Errors.ShouldNotBeNull(); + response.ShouldBeDefaultResponseModel(new ResponseModel("Unauthorized")); + } +} \ No newline at end of file diff --git a/test/SampleDotnet.Result.Tests/_Constants.cs b/test/SampleDotnet.Result.Tests/_Constants.cs new file mode 100644 index 0000000..3240034 --- /dev/null +++ b/test/SampleDotnet.Result.Tests/_Constants.cs @@ -0,0 +1,7 @@ +namespace SampleDotnet.Result.Tests; + +internal class _Constants +{ + internal const string RequestStartTime = "_RequestStartTime"; + internal const string ContentType_ApplicationJson = "application/json"; +} \ No newline at end of file diff --git a/test/SampleDotnet.Result.Tests/_Extensions.cs b/test/SampleDotnet.Result.Tests/_Extensions.cs new file mode 100644 index 0000000..b66b898 --- /dev/null +++ b/test/SampleDotnet.Result.Tests/_Extensions.cs @@ -0,0 +1,57 @@ +namespace SampleDotnet.Result.Tests; + +public static class _Extensions +{ + public static JsonSerializerSettings GetDefaultJsonSerializerForTesting() + { + return JsonConvert.DefaultSettings?.Invoke() ?? new JsonSerializerSettings(); + } + + public static void ShouldBeDefaultResponseModel(this BaseJsonResult response, ResponseModel responseModel) + { + response.SerializerSettings.ShouldBeEquivalentTo(GetDefaultJsonSerializerForTesting()); + response.Model.GetType().ShouldBeEquivalentTo(typeof(ResponseModel), "must be same type"); + + response.ShouldSerializeAndDeserialize(responseModel); + } + + public static void ShouldSerializeAndDeserialize(this BaseJsonResult response, ResponseModel previousResponseModel) + where TTESTDATA : class + { + response.SerializerSettings.ShouldBeEquivalentTo(GetDefaultJsonSerializerForTesting()); + + var jsonModel = JsonConvert.SerializeObject(response.Value, (JsonSerializerSettings?)response.SerializerSettings); + jsonModel.ShouldNotBeNullOrWhiteSpace("must be has a value"); + + ResponseModel? objModel = JsonConvert.DeserializeObject>(jsonModel, (JsonSerializerSettings?)response.SerializerSettings); + objModel.ShouldNotBeNull("shouldn't be null"); + objModel.ShouldBeEquivalentTo(previousResponseModel, "must be equivalent to previous generated value"); + objModel.GetType().ShouldBeEquivalentTo(typeof(ResponseModel), "must be same type"); + } + + public static void ShouldSerializeAndDeserialize(this BaseJsonResult response, ResponseModel previousResponseModel) + { + response.SerializerSettings.ShouldBeEquivalentTo(GetDefaultJsonSerializerForTesting()); + + var jsonModel = JsonConvert.SerializeObject(response.Value, (JsonSerializerSettings?)response.SerializerSettings); + jsonModel.ShouldNotBeNullOrWhiteSpace("must be has a value"); + + ResponseModel? objModel = JsonConvert.DeserializeObject(jsonModel, (JsonSerializerSettings?)response.SerializerSettings); + objModel.ShouldNotBeNull("shouldn't be null"); + objModel.ShouldBeEquivalentTo(previousResponseModel, "must be equivalent to previous generated value"); + objModel.GetType().ShouldBeEquivalentTo(typeof(ResponseModel), "must be same type"); + } + + public static void ShouldValidatetCommons(this BaseJsonResult response, int statusCode) + { + typeof(BaseJsonResult).IsAssignableFrom(response.GetType()).ShouldBe(true, "invalid casting"); + + response.StatusCode.ShouldNotBeNull("StatusCode must be defined"); + response.StatusCode.ShouldBe(statusCode, $"StatusCode must be equals to {statusCode}"); + + response.ContentType.ShouldNotBeNullOrEmpty("ContentType must be defined"); + response.ContentType.ShouldBe(_Constants.ContentType_ApplicationJson, $"ContentType must be equals to {_Constants.ContentType_ApplicationJson}"); + + response.Value.ShouldNotBeNull("Value must be defined"); + } +} \ No newline at end of file diff --git a/test/SampleDotnet.Result.Tests/_GlobalUsings.cs b/test/SampleDotnet.Result.Tests/_GlobalUsings.cs new file mode 100644 index 0000000..86e67f0 --- /dev/null +++ b/test/SampleDotnet.Result.Tests/_GlobalUsings.cs @@ -0,0 +1,4 @@ +global using Newtonsoft.Json; +global using SampleDotnet.Result.Abstractions; +global using Shouldly; +global using Xunit; \ No newline at end of file