From 4fa0f1cfdd2314606fa7e4f024f9191c5a9a6182 Mon Sep 17 00:00:00 2001 From: Gilles TOURREAU Date: Tue, 18 Jun 2024 11:58:54 +0200 Subject: [PATCH 1/5] Upgrade the NuGet packages for the unit tests to the last version. --- .../FluentAssertions.Json.Tests.csproj | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/FluentAssertions.Json.Tests/FluentAssertions.Json.Tests.csproj b/tests/FluentAssertions.Json.Tests/FluentAssertions.Json.Tests.csproj index 96ab1ea..b48b3c2 100644 --- a/tests/FluentAssertions.Json.Tests/FluentAssertions.Json.Tests.csproj +++ b/tests/FluentAssertions.Json.Tests/FluentAssertions.Json.Tests.csproj @@ -1,7 +1,7 @@  - net7.0 + net8.0 disable @@ -9,13 +9,13 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all From 1b0f5dde2361e4948e9d4d6ff3e0e62f4e8beaf3 Mon Sep 17 00:00:00 2001 From: Gilles TOURREAU Date: Tue, 18 Jun 2024 12:00:28 +0200 Subject: [PATCH 2/5] Remove the shortcut of .editorconfig in Directory.Build.props. --- Directory.Build.props | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index d39119a..796c9aa 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -31,10 +31,6 @@ stylecop.json - - - - From 167e385af084658a76c07e6f65ee63784c11254d Mon Sep 17 00:00:00 2001 From: Gilles TOURREAU Date: Tue, 18 Jun 2024 12:02:23 +0200 Subject: [PATCH 3/5] Migrates the Azure Pipelines to GitHub actions (#17). --- .github/workflows/github-actions-ci.yaml | 24 +++++++++ .github/workflows/github-actions-release.yml | 36 +++++++++++++ PosInformatique.FluentAssertions.Json.sln | 7 --- build/azure-pipelines-ci.yaml | 24 --------- build/azure-pipelines-release.yaml | 54 -------------------- 5 files changed, 60 insertions(+), 85 deletions(-) create mode 100644 .github/workflows/github-actions-ci.yaml create mode 100644 .github/workflows/github-actions-release.yml delete mode 100644 build/azure-pipelines-ci.yaml delete mode 100644 build/azure-pipelines-release.yaml diff --git a/.github/workflows/github-actions-ci.yaml b/.github/workflows/github-actions-ci.yaml new file mode 100644 index 0000000..dbb42e6 --- /dev/null +++ b/.github/workflows/github-actions-ci.yaml @@ -0,0 +1,24 @@ +name: Continuous Integration + +on: + pull_request: + branches: [ "main" ] + push: + branches: [ "releases/**" ] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Setup .NET 8.x + uses: actions/setup-dotnet@v3 + with: + dotnet-version: '8.x' + + - name: Build + run: dotnet build --property:Configuration=Debug "PosInformatique.FluentAssertions.Json.sln" + + - name: Test with the dotnet CLI + run: dotnet test --property:Configuration=Debug "PosInformatique.FluentAssertions.Json.sln" diff --git a/.github/workflows/github-actions-release.yml b/.github/workflows/github-actions-release.yml new file mode 100644 index 0000000..aaacc5d --- /dev/null +++ b/.github/workflows/github-actions-release.yml @@ -0,0 +1,36 @@ +name: Release + +on: + workflow_dispatch: + inputs: + VersionPrefix: + type: string + description: The version of the library + required: true + default: 1.3.0 + VersionSuffix: + type: string + description: The version suffix of the library (for example rc.1) + +run-name: ${{ inputs.VersionPrefix }}-${{ inputs.VersionSuffix }} + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Setup .NET 8.x + uses: actions/setup-dotnet@v3 + with: + dotnet-version: '8.x' + + - name: Build + run: dotnet pack + --property:Configuration=Release + --property:VersionPrefix=${{ github.event.inputs.VersionPrefix }} + --property:VersionSuffix=${{ github.event.inputs.VersionSuffix }} + "src/FluentAssertions.Json/FluentAssertions.Json.csproj" + + - name: Publish the package to nuget.org + run: dotnet nuget push "src/FluentAssertions.Json/bin/Release/*.nupkg" --api-key "${{ secrets.NUGET_APIKEY }}" --source https://api.nuget.org/v3/index.json diff --git a/PosInformatique.FluentAssertions.Json.sln b/PosInformatique.FluentAssertions.Json.sln index 106286f..6c91e91 100644 --- a/PosInformatique.FluentAssertions.Json.sln +++ b/PosInformatique.FluentAssertions.Json.sln @@ -22,12 +22,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{7928175B tests\.editorconfig = tests\.editorconfig EndProjectSection EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{E7CF7FC5-E257-4A28-8641-F41032340CA9}" - ProjectSection(SolutionItems) = preProject - build\azure-pipelines-ci.yaml = build\azure-pipelines-ci.yaml - build\azure-pipelines-release.yaml = build\azure-pipelines-release.yaml - EndProjectSection -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -48,7 +42,6 @@ Global EndGlobalSection GlobalSection(NestedProjects) = preSolution {7928175B-C3B3-4F81-B956-BF4E4F816436} = {882949E5-7DCE-4EB6-8E9A-CB88FD0ED1F9} - {E7CF7FC5-E257-4A28-8641-F41032340CA9} = {882949E5-7DCE-4EB6-8E9A-CB88FD0ED1F9} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {0582B8EB-4FA4-488E-9953-9B7CEEE4E94F} diff --git a/build/azure-pipelines-ci.yaml b/build/azure-pipelines-ci.yaml deleted file mode 100644 index fced5ca..0000000 --- a/build/azure-pipelines-ci.yaml +++ /dev/null @@ -1,24 +0,0 @@ -trigger: none - -pool: - vmImage: ubuntu-latest - -jobs: -- job: Build - displayName: Build the library - steps: - - task: DotNetCoreCLI@2 - name: BuildLibrary - displayName: Build the library - inputs: - command: 'build' - projects: 'PosInformatique.FluentAssertions.Json.sln' - arguments: '--property:Configuration=Debug' - - - task: DotNetCoreCLI@2 - name: ExecuteUnitTests - displayName: Execute the unit tests - inputs: - command: 'test' - projects: 'PosInformatique.FluentAssertions.Json.sln' - arguments: '--property:Configuration=Debug' \ No newline at end of file diff --git a/build/azure-pipelines-release.yaml b/build/azure-pipelines-release.yaml deleted file mode 100644 index 7ac4e4d..0000000 --- a/build/azure-pipelines-release.yaml +++ /dev/null @@ -1,54 +0,0 @@ -parameters: -- name: VersionPrefix - displayName: The version of the library - type: string - default: 1.2.0 -- name: VersionSuffix - displayName: The version suffix of the library (rc.1). Use a space ' ' if no suffix. - type: string - default: rc.1 - -trigger: none -pr: none - -pool: - vmImage: ubuntu-latest - -jobs: -- job: Build - displayName: Build the library - steps: - - task: PowerShell@2 - name: UpdateBuildNumber - displayName: Update build number - inputs: - targetType: 'inline' - script: ' - if ("${{parameters.VersionSuffix}}".Trim() -eq "") - { - Write-Host "##vso[build.updatebuildnumber]${{parameters.VersionPrefix}}" - } - else - { - Write-Host "##vso[build.updatebuildnumber]${{parameters.VersionPrefix}}-${{parameters.VersionSuffix}}" - }' - - - task: DotNetCoreCLI@2 - name: BuildLibrary - displayName: Build the library - inputs: - command: 'pack' - packagesToPack: 'src/FluentAssertions.Json/FluentAssertions.Json.csproj' - configuration: 'Release' - versioningScheme: 'off' - buildProperties: 'VersionPrefix=${{parameters.VersionPrefix}};VersionSuffix=${{parameters.VersionSuffix}}' - verbosityPack: 'Normal' - - - task: NuGetCommand@2 - name: PublishNuGetPackages - displayName: Publish to NuGet - inputs: - command: 'push' - packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg' - nuGetFeedType: 'external' - publishFeedCredentials: 'nuget.org' \ No newline at end of file From 389e434f9a2387c1dbc3c36acfc50232cb670689 Mon Sep 17 00:00:00 2001 From: Gilles TOURREAU Date: Tue, 18 Jun 2024 13:16:55 +0200 Subject: [PATCH 4/5] Add new overrides BeJsonDeserializableInto() to test the string collections, string and numeric values (#16). --- .../FluentAssertions.Json.csproj | 4 + .../JsonFluentAssertionsExtensions.cs | 98 ++++++++++++++++++- .../JsonFluentAssertionsExtensionsTest.cs | 97 ++++++++++++++++++ 3 files changed, 198 insertions(+), 1 deletion(-) diff --git a/src/FluentAssertions.Json/FluentAssertions.Json.csproj b/src/FluentAssertions.Json/FluentAssertions.Json.csproj index 015d71b..a3fd7d9 100644 --- a/src/FluentAssertions.Json/FluentAssertions.Json.csproj +++ b/src/FluentAssertions.Json/FluentAssertions.Json.csproj @@ -11,6 +11,10 @@ https://github.com/PosInformatique/PosInformatique.FluentAssertions.Json README.md + 1.3.0 + - Add new override BeJsonDeserializableInto() method to test the string collections. + - Add new override BeJsonDeserializableInto() method to test the string and numeric values. + 1.2.0 - Add new override BeJsonSerializableInto() method to test polymorphism serialization with discriminator JSON property. - Add the support to assert the deserialization of root JSON array. diff --git a/src/FluentAssertions.Json/JsonFluentAssertionsExtensions.cs b/src/FluentAssertions.Json/JsonFluentAssertionsExtensions.cs index cde0951..08a7b80 100644 --- a/src/FluentAssertions.Json/JsonFluentAssertionsExtensions.cs +++ b/src/FluentAssertions.Json/JsonFluentAssertionsExtensions.cs @@ -12,6 +12,7 @@ namespace FluentAssertions using FluentAssertions.Collections; using FluentAssertions.Common; using FluentAssertions.Equivalency; + using FluentAssertions.Numeric; using FluentAssertions.Primitives; using PosInformatique.FluentAssertions.Json; @@ -105,7 +106,7 @@ public static void BeJsonDeserializableInto(this ObjectAssertions assertions, /// /// Type of the element of the collection to check the JSON deserialization. /// Type of the object to deserialize from JSON. - /// which contains the JSON collection subject to deserialize. + /// which contains the JSON collection subject to deserialize. /// Expected collection deserialized expected. /// to use to assert the deserialization. If not specified /// the default of the @@ -115,6 +116,49 @@ public static void BeJsonDeserializableInto(this GenericCollectionA BeJsonDeserializableIntoCore(assertions.Subject, expectedObject, GetSerializerOptions(options)); } + /// + /// Check if the JSON subject string collection is deserializable into the specified argument. + /// + /// Type of the object to deserialize from JSON. + /// which contains the JSON string collection subject to deserialize. + /// Expected string collection deserialized expected. + /// to use to assert the deserialization. If not specified + /// the default of the + /// will be used. + public static void BeJsonDeserializableInto(this StringCollectionAssertions assertions, T expectedObject, JsonSerializerOptions? options = null) + { + BeJsonDeserializableIntoCore(assertions.Subject, expectedObject, GetSerializerOptions(options)); + } + + /// + /// Check if the JSON subject numeric is deserializable into the specified argument. + /// + /// Type of the object to deserialize from JSON. + /// which contains the JSON numeric subject to deserialize. + /// Expected numeric value deserialized expected. + /// to use to assert the deserialization. If not specified + /// the default of the + /// will be used. + public static void BeJsonDeserializableInto(this NumericAssertions assertions, T expectedObject, JsonSerializerOptions? options = null) + where T : struct, IComparable + { + BeJsonDeserializableIntoCore(assertions.Subject, expectedObject, GetSerializerOptions(options)); + } + + /// + /// Check if the JSON subject string is deserializable into the specified argument. + /// + /// Type of the object to deserialize from JSON. + /// which contains the JSON string subject to deserialize. + /// Expected string value deserialized expected. + /// to use to assert the deserialization. If not specified + /// the default of the + /// will be used. + public static void BeJsonDeserializableInto(this StringAssertions assertions, T expectedObject, JsonSerializerOptions? options = null) + { + BeJsonDeserializableIntoCore(assertions.Subject, expectedObject, GetSerializerOptions(options)); + } + /// /// Check if the JSON subject object is deserializable into the specified argument. /// @@ -150,6 +194,58 @@ public static void BeJsonDeserializableInto(this GenericCollectionA BeJsonDeserializableIntoCore(assertions.Subject, expectedObject, optionsCopy); } + /// + /// Check if the JSON subject string collection is deserializable into the specified argument. + /// + /// Type of the object to deserialize from JSON. + /// which contains the JSON string collection subject to deserialize. + /// Expected string collection deserialized expected. + /// Allows to change the default + /// of the used to assert the deserialization. + public static void BeJsonDeserializableInto(this StringCollectionAssertions assertions, T expectedObject, Action configureOptions) + { + var optionsCopy = new JsonSerializerOptions(FluentAssertionsJson.Configuration.JsonSerializerOptions); + + configureOptions(optionsCopy); + + BeJsonDeserializableIntoCore(assertions.Subject, expectedObject, optionsCopy); + } + + /// + /// Check if the JSON subject numeric is deserializable into the specified argument. + /// + /// Type of the numeric value to deserialize from JSON. + /// which contains the JSON numeric subject to deserialize. + /// Expected numeric value deserialized expected. + /// Allows to change the default + /// of the used to assert the deserialization. + public static void BeJsonDeserializableInto(this NumericAssertions assertions, T expectedObject, Action configureOptions) + where T : struct, IComparable + { + var optionsCopy = new JsonSerializerOptions(FluentAssertionsJson.Configuration.JsonSerializerOptions); + + configureOptions(optionsCopy); + + BeJsonDeserializableIntoCore(assertions.Subject, expectedObject, optionsCopy); + } + + /// + /// Check if the JSON subject string is deserializable into the specified argument. + /// + /// Type of the string value to deserialize from JSON. + /// which contains the JSON string subject to deserialize. + /// Expected string value deserialized expected. + /// Allows to change the default + /// of the used to assert the deserialization. + public static void BeJsonDeserializableInto(this StringAssertions assertions, T expectedObject, Action configureOptions) + { + var optionsCopy = new JsonSerializerOptions(FluentAssertionsJson.Configuration.JsonSerializerOptions); + + configureOptions(optionsCopy); + + BeJsonDeserializableIntoCore(assertions.Subject, expectedObject, optionsCopy); + } + private static void BeJsonSerializableIntoCore(ObjectAssertions assertions, object? expectedJson, JsonSerializerOptions options) { if (assertions.Subject is not null && assertions.Subject is not TBase) diff --git a/tests/FluentAssertions.Json.Tests/JsonFluentAssertionsExtensionsTest.cs b/tests/FluentAssertions.Json.Tests/JsonFluentAssertionsExtensionsTest.cs index 08c5870..b4258dd 100644 --- a/tests/FluentAssertions.Json.Tests/JsonFluentAssertionsExtensionsTest.cs +++ b/tests/FluentAssertions.Json.Tests/JsonFluentAssertionsExtensionsTest.cs @@ -1205,6 +1205,103 @@ public void BeJsonDeserializableInto_WithObjectProperty_String_WrongType() .WithMessage("$.inner.object_property: Expected property to be 'Number' type instead of 'String' type."); } + [Fact] + public void BeJsonDeserializableInto_WithArrayOfString() + { + var json = new[] { "A", "B", "C" }; + + json.Should().BeJsonDeserializableInto(new[] { "A", "B", "C" }); + } + + [Fact] + public void BeJsonDeserializableInto_WithArrayOfString_WithOptions() + { + var json = new[] { "A", "B", "C" }; + + json.Should().BeJsonDeserializableInto( + new[] { "A", "B", "C" }, + new JsonSerializerOptions() + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + }); + } + + [Fact] + public void BeJsonDeserializableInto_ArrayOfString_WithOptionsConfigure() + { + var json = new[] { "A", "B", "C" }; + + json.Should().BeJsonDeserializableInto( + new[] { "A", "B", "C" }, + opt => + { + opt.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; + }); + } + + [Fact] + public void BeJsonDeserializableInto_PrimitiveValues() + { + var json = "A"; + + json.Should().BeJsonDeserializableInto("A"); + + var json2 = 1234; + + json2.Should().BeJsonDeserializableInto(1234); + + var json3 = 12.34; + + json3.Should().BeJsonDeserializableInto(12.34); + } + + [Fact] + public void BeJsonDeserializableInto_PrimitiveValues_WithOptions() + { + var json = "A"; + + json.Should().BeJsonDeserializableInto("A", new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); + + var json2 = 1234; + + json2.Should().BeJsonDeserializableInto(1234, new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); + + var json3 = 12.34; + + json3.Should().BeJsonDeserializableInto(12.34, new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); + } + + [Fact] + public void BeJsonDeserializableInto_PrimitiveValues_WithOptionsConfigure() + { + var json = "A"; + + json.Should().BeJsonDeserializableInto( + "A", + opt => + { + opt.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; + }); + + var json2 = 1234; + + json2.Should().BeJsonDeserializableInto( + 1234, + opt => + { + opt.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; + }); + + var json3 = 12.34; + + json3.Should().BeJsonDeserializableInto( + 12.34, + opt => + { + opt.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; + }); + } + private class JsonSerializableClass { [JsonPropertyName("string_property")] From 2caa5b745d2e1755b54f789c0362eb86c8ee608c Mon Sep 17 00:00:00 2001 From: Gilles TOURREAU Date: Fri, 28 Jun 2024 06:00:49 +0200 Subject: [PATCH 5/5] Fix the release notes --- src/FluentAssertions.Json/FluentAssertions.Json.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/FluentAssertions.Json/FluentAssertions.Json.csproj b/src/FluentAssertions.Json/FluentAssertions.Json.csproj index a3fd7d9..bf34078 100644 --- a/src/FluentAssertions.Json/FluentAssertions.Json.csproj +++ b/src/FluentAssertions.Json/FluentAssertions.Json.csproj @@ -12,11 +12,11 @@ README.md 1.3.0 - - Add new override BeJsonDeserializableInto() method to test the string collections. - - Add new override BeJsonDeserializableInto() method to test the string and numeric values. + - Add new overload BeJsonDeserializableInto() method to test the string collections. + - Add new overload BeJsonDeserializableInto() method to test the string and numeric values. 1.2.0 - - Add new override BeJsonSerializableInto() method to test polymorphism serialization with discriminator JSON property. + - Add new overload BeJsonSerializableInto() method to test polymorphism serialization with discriminator JSON property. - Add the support to assert the deserialization of root JSON array. 1.1.0