From 150b448d072487dea65e0e1c6cbcb226a18bccd3 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Sat, 9 Jul 2022 15:34:17 +0200 Subject: [PATCH] Added some more tests for JsonMatcher + refactored some code to use nullable (#770) --- .../Nullable/AllowNullAttribute.cs | 73 +++ .../Nullable/DisallowNullAttribute.cs | 73 +++ .../Nullable/DoesNotReturnAttribute.cs | 70 +++ .../Nullable/DoesNotReturnIfAttribute.cs | 88 +++ .../Nullable/MaybeNullAttribute.cs | 74 +++ .../Nullable/MaybeNullWhenAttribute.cs | 85 +++ .../Nullable/MemberNotNullAttribute.cs | 96 +++ .../Nullable/MemberNotNullWhenAttribute.cs | 114 ++++ .../Nullable/NotNullAttribute.cs | 74 +++ .../Nullable/NotNullIfNotNullAttribute.cs | 91 +++ .../Nullable/NotNullWhenAttribute.cs | 85 +++ ...WireMock.Net.Console.Net472.Classic.csproj | 68 ++- .../packages.config | 26 +- .../Admin/Mappings/WebhookRequestModel.cs | 8 +- .../Http/HttpResponseMessageHelper.cs | 94 +-- src/WireMock.Net/Matchers/JsonMatcher.cs | 4 +- .../Owin/Mappers/OwinRequestMapper.cs | 8 +- src/WireMock.Net/Util/BodyParser.cs | 274 +++++---- src/WireMock.Net/Util/BodyParserSettings.cs | 19 +- .../Matchers/JsonMatcherTests.cs | 559 ++++++++++-------- 20 files changed, 1497 insertions(+), 486 deletions(-) create mode 100644 examples/WireMock.Net.Console.Net472.Classic/Nullable/AllowNullAttribute.cs create mode 100644 examples/WireMock.Net.Console.Net472.Classic/Nullable/DisallowNullAttribute.cs create mode 100644 examples/WireMock.Net.Console.Net472.Classic/Nullable/DoesNotReturnAttribute.cs create mode 100644 examples/WireMock.Net.Console.Net472.Classic/Nullable/DoesNotReturnIfAttribute.cs create mode 100644 examples/WireMock.Net.Console.Net472.Classic/Nullable/MaybeNullAttribute.cs create mode 100644 examples/WireMock.Net.Console.Net472.Classic/Nullable/MaybeNullWhenAttribute.cs create mode 100644 examples/WireMock.Net.Console.Net472.Classic/Nullable/MemberNotNullAttribute.cs create mode 100644 examples/WireMock.Net.Console.Net472.Classic/Nullable/MemberNotNullWhenAttribute.cs create mode 100644 examples/WireMock.Net.Console.Net472.Classic/Nullable/NotNullAttribute.cs create mode 100644 examples/WireMock.Net.Console.Net472.Classic/Nullable/NotNullIfNotNullAttribute.cs create mode 100644 examples/WireMock.Net.Console.Net472.Classic/Nullable/NotNullWhenAttribute.cs diff --git a/examples/WireMock.Net.Console.Net472.Classic/Nullable/AllowNullAttribute.cs b/examples/WireMock.Net.Console.Net472.Classic/Nullable/AllowNullAttribute.cs new file mode 100644 index 00000000..8ce3e017 --- /dev/null +++ b/examples/WireMock.Net.Console.Net472.Classic/Nullable/AllowNullAttribute.cs @@ -0,0 +1,73 @@ +// +// This code file has automatically been added by the "Nullable" NuGet package (https://www.nuget.org/packages/Nullable). +// Please see https://github.com/manuelroemer/Nullable for more information. +// +// IMPORTANT: +// DO NOT DELETE THIS FILE if you are using a "packages.config" file to manage your NuGet references. +// Consider migrating to PackageReferences instead: +// https://docs.microsoft.com/en-us/nuget/consume-packages/migrate-packages-config-to-package-reference +// Migrating brings the following benefits: +// * The "Nullable" folder and the nullable "*Attribute.cs" files don't appear in your project. +// * The added files are immutable and can therefore not be modified by coincidence. +// * Updating/Uninstalling the package will work flawlessly. +// + +#region License +// MIT License +// +// Copyright (c) Manuel Römer +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +#endregion + +#if !NULLABLE_ATTRIBUTES_DISABLE +#nullable enable +#pragma warning disable + +namespace System.Diagnostics.CodeAnalysis +{ + using global::System; + +#if DEBUG + /// + /// Specifies that is allowed as an input even if the + /// corresponding type disallows it. + /// +#endif + [AttributeUsage( + AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, + Inherited = false + )] +#if !NULLABLE_ATTRIBUTES_INCLUDE_IN_CODE_COVERAGE + [DebuggerNonUserCode] +#endif + internal sealed class AllowNullAttribute : Attribute + { +#if DEBUG + /// + /// Initializes a new instance of the class. + /// +#endif + public AllowNullAttribute() { } + } +} + +#pragma warning restore +#nullable restore +#endif // NULLABLE_ATTRIBUTES_DISABLE diff --git a/examples/WireMock.Net.Console.Net472.Classic/Nullable/DisallowNullAttribute.cs b/examples/WireMock.Net.Console.Net472.Classic/Nullable/DisallowNullAttribute.cs new file mode 100644 index 00000000..dd2f7d6b --- /dev/null +++ b/examples/WireMock.Net.Console.Net472.Classic/Nullable/DisallowNullAttribute.cs @@ -0,0 +1,73 @@ +// +// This code file has automatically been added by the "Nullable" NuGet package (https://www.nuget.org/packages/Nullable). +// Please see https://github.com/manuelroemer/Nullable for more information. +// +// IMPORTANT: +// DO NOT DELETE THIS FILE if you are using a "packages.config" file to manage your NuGet references. +// Consider migrating to PackageReferences instead: +// https://docs.microsoft.com/en-us/nuget/consume-packages/migrate-packages-config-to-package-reference +// Migrating brings the following benefits: +// * The "Nullable" folder and the nullable "*Attribute.cs" files don't appear in your project. +// * The added files are immutable and can therefore not be modified by coincidence. +// * Updating/Uninstalling the package will work flawlessly. +// + +#region License +// MIT License +// +// Copyright (c) Manuel Römer +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +#endregion + +#if !NULLABLE_ATTRIBUTES_DISABLE +#nullable enable +#pragma warning disable + +namespace System.Diagnostics.CodeAnalysis +{ + using global::System; + +#if DEBUG + /// + /// Specifies that is disallowed as an input even if the + /// corresponding type allows it. + /// +#endif + [AttributeUsage( + AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, + Inherited = false + )] +#if !NULLABLE_ATTRIBUTES_INCLUDE_IN_CODE_COVERAGE + [DebuggerNonUserCode] +#endif + internal sealed class DisallowNullAttribute : Attribute + { +#if DEBUG + /// + /// Initializes a new instance of the class. + /// +#endif + public DisallowNullAttribute() { } + } +} + +#pragma warning restore +#nullable restore +#endif // NULLABLE_ATTRIBUTES_DISABLE diff --git a/examples/WireMock.Net.Console.Net472.Classic/Nullable/DoesNotReturnAttribute.cs b/examples/WireMock.Net.Console.Net472.Classic/Nullable/DoesNotReturnAttribute.cs new file mode 100644 index 00000000..71cce0d3 --- /dev/null +++ b/examples/WireMock.Net.Console.Net472.Classic/Nullable/DoesNotReturnAttribute.cs @@ -0,0 +1,70 @@ +// +// This code file has automatically been added by the "Nullable" NuGet package (https://www.nuget.org/packages/Nullable). +// Please see https://github.com/manuelroemer/Nullable for more information. +// +// IMPORTANT: +// DO NOT DELETE THIS FILE if you are using a "packages.config" file to manage your NuGet references. +// Consider migrating to PackageReferences instead: +// https://docs.microsoft.com/en-us/nuget/consume-packages/migrate-packages-config-to-package-reference +// Migrating brings the following benefits: +// * The "Nullable" folder and the nullable "*Attribute.cs" files don't appear in your project. +// * The added files are immutable and can therefore not be modified by coincidence. +// * Updating/Uninstalling the package will work flawlessly. +// + +#region License +// MIT License +// +// Copyright (c) Manuel Römer +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +#endregion + +#if !NULLABLE_ATTRIBUTES_DISABLE +#nullable enable +#pragma warning disable + +namespace System.Diagnostics.CodeAnalysis +{ + using global::System; + +#if DEBUG + /// + /// Specifies that a method that will never return under any circumstance. + /// +#endif + [AttributeUsage(AttributeTargets.Method, Inherited = false)] +#if !NULLABLE_ATTRIBUTES_INCLUDE_IN_CODE_COVERAGE + [DebuggerNonUserCode] +#endif + internal sealed class DoesNotReturnAttribute : Attribute + { +#if DEBUG + /// + /// Initializes a new instance of the class. + /// + /// +#endif + public DoesNotReturnAttribute() { } + } +} + +#pragma warning restore +#nullable restore +#endif // NULLABLE_ATTRIBUTES_DISABLE diff --git a/examples/WireMock.Net.Console.Net472.Classic/Nullable/DoesNotReturnIfAttribute.cs b/examples/WireMock.Net.Console.Net472.Classic/Nullable/DoesNotReturnIfAttribute.cs new file mode 100644 index 00000000..3c54fe96 --- /dev/null +++ b/examples/WireMock.Net.Console.Net472.Classic/Nullable/DoesNotReturnIfAttribute.cs @@ -0,0 +1,88 @@ +// +// This code file has automatically been added by the "Nullable" NuGet package (https://www.nuget.org/packages/Nullable). +// Please see https://github.com/manuelroemer/Nullable for more information. +// +// IMPORTANT: +// DO NOT DELETE THIS FILE if you are using a "packages.config" file to manage your NuGet references. +// Consider migrating to PackageReferences instead: +// https://docs.microsoft.com/en-us/nuget/consume-packages/migrate-packages-config-to-package-reference +// Migrating brings the following benefits: +// * The "Nullable" folder and the nullable "*Attribute.cs" files don't appear in your project. +// * The added files are immutable and can therefore not be modified by coincidence. +// * Updating/Uninstalling the package will work flawlessly. +// + +#region License +// MIT License +// +// Copyright (c) Manuel Römer +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +#endregion + +#if !NULLABLE_ATTRIBUTES_DISABLE +#nullable enable +#pragma warning disable + +namespace System.Diagnostics.CodeAnalysis +{ + using global::System; + +#if DEBUG + /// + /// Specifies that the method will not return if the associated + /// parameter is passed the specified value. + /// +#endif + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] +#if !NULLABLE_ATTRIBUTES_INCLUDE_IN_CODE_COVERAGE + [DebuggerNonUserCode] +#endif + internal sealed class DoesNotReturnIfAttribute : Attribute + { +#if DEBUG + /// + /// Gets the condition parameter value. + /// Code after the method is considered unreachable by diagnostics if the argument + /// to the associated parameter matches this value. + /// +#endif + public bool ParameterValue { get; } + +#if DEBUG + /// + /// Initializes a new instance of the + /// class with the specified parameter value. + /// + /// + /// The condition parameter value. + /// Code after the method is considered unreachable by diagnostics if the argument + /// to the associated parameter matches this value. + /// +#endif + public DoesNotReturnIfAttribute(bool parameterValue) + { + ParameterValue = parameterValue; + } + } +} + +#pragma warning restore +#nullable restore +#endif // NULLABLE_ATTRIBUTES_DISABLE diff --git a/examples/WireMock.Net.Console.Net472.Classic/Nullable/MaybeNullAttribute.cs b/examples/WireMock.Net.Console.Net472.Classic/Nullable/MaybeNullAttribute.cs new file mode 100644 index 00000000..dce8e389 --- /dev/null +++ b/examples/WireMock.Net.Console.Net472.Classic/Nullable/MaybeNullAttribute.cs @@ -0,0 +1,74 @@ +// +// This code file has automatically been added by the "Nullable" NuGet package (https://www.nuget.org/packages/Nullable). +// Please see https://github.com/manuelroemer/Nullable for more information. +// +// IMPORTANT: +// DO NOT DELETE THIS FILE if you are using a "packages.config" file to manage your NuGet references. +// Consider migrating to PackageReferences instead: +// https://docs.microsoft.com/en-us/nuget/consume-packages/migrate-packages-config-to-package-reference +// Migrating brings the following benefits: +// * The "Nullable" folder and the nullable "*Attribute.cs" files don't appear in your project. +// * The added files are immutable and can therefore not be modified by coincidence. +// * Updating/Uninstalling the package will work flawlessly. +// + +#region License +// MIT License +// +// Copyright (c) Manuel Römer +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +#endregion + +#if !NULLABLE_ATTRIBUTES_DISABLE +#nullable enable +#pragma warning disable + +namespace System.Diagnostics.CodeAnalysis +{ + using global::System; + +#if DEBUG + /// + /// Specifies that an output may be even if the + /// corresponding type disallows it. + /// +#endif + [AttributeUsage( + AttributeTargets.Field | AttributeTargets.Parameter | + AttributeTargets.Property | AttributeTargets.ReturnValue, + Inherited = false + )] +#if !NULLABLE_ATTRIBUTES_INCLUDE_IN_CODE_COVERAGE + [DebuggerNonUserCode] +#endif + internal sealed class MaybeNullAttribute : Attribute + { +#if DEBUG + /// + /// Initializes a new instance of the class. + /// +#endif + public MaybeNullAttribute() { } + } +} + +#pragma warning restore +#nullable restore +#endif // NULLABLE_ATTRIBUTES_DISABLE diff --git a/examples/WireMock.Net.Console.Net472.Classic/Nullable/MaybeNullWhenAttribute.cs b/examples/WireMock.Net.Console.Net472.Classic/Nullable/MaybeNullWhenAttribute.cs new file mode 100644 index 00000000..3f29fd65 --- /dev/null +++ b/examples/WireMock.Net.Console.Net472.Classic/Nullable/MaybeNullWhenAttribute.cs @@ -0,0 +1,85 @@ +// +// This code file has automatically been added by the "Nullable" NuGet package (https://www.nuget.org/packages/Nullable). +// Please see https://github.com/manuelroemer/Nullable for more information. +// +// IMPORTANT: +// DO NOT DELETE THIS FILE if you are using a "packages.config" file to manage your NuGet references. +// Consider migrating to PackageReferences instead: +// https://docs.microsoft.com/en-us/nuget/consume-packages/migrate-packages-config-to-package-reference +// Migrating brings the following benefits: +// * The "Nullable" folder and the nullable "*Attribute.cs" files don't appear in your project. +// * The added files are immutable and can therefore not be modified by coincidence. +// * Updating/Uninstalling the package will work flawlessly. +// + +#region License +// MIT License +// +// Copyright (c) Manuel Römer +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +#endregion + +#if !NULLABLE_ATTRIBUTES_DISABLE +#nullable enable +#pragma warning disable + +namespace System.Diagnostics.CodeAnalysis +{ + using global::System; + +#if DEBUG + /// + /// Specifies that when a method returns , + /// the parameter may be even if the corresponding type disallows it. + /// +#endif + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] +#if !NULLABLE_ATTRIBUTES_INCLUDE_IN_CODE_COVERAGE + [DebuggerNonUserCode] +#endif + internal sealed class MaybeNullWhenAttribute : Attribute + { +#if DEBUG + /// + /// Gets the return value condition. + /// If the method returns this value, the associated parameter may be . + /// +#endif + public bool ReturnValue { get; } + +#if DEBUG + /// + /// Initializes the attribute with the specified return value condition. + /// + /// + /// The return value condition. + /// If the method returns this value, the associated parameter may be . + /// +#endif + public MaybeNullWhenAttribute(bool returnValue) + { + ReturnValue = returnValue; + } + } +} + +#pragma warning restore +#nullable restore +#endif // NULLABLE_ATTRIBUTES_DISABLE diff --git a/examples/WireMock.Net.Console.Net472.Classic/Nullable/MemberNotNullAttribute.cs b/examples/WireMock.Net.Console.Net472.Classic/Nullable/MemberNotNullAttribute.cs new file mode 100644 index 00000000..d948d1b5 --- /dev/null +++ b/examples/WireMock.Net.Console.Net472.Classic/Nullable/MemberNotNullAttribute.cs @@ -0,0 +1,96 @@ +// +// This code file has automatically been added by the "Nullable" NuGet package (https://www.nuget.org/packages/Nullable). +// Please see https://github.com/manuelroemer/Nullable for more information. +// +// IMPORTANT: +// DO NOT DELETE THIS FILE if you are using a "packages.config" file to manage your NuGet references. +// Consider migrating to PackageReferences instead: +// https://docs.microsoft.com/en-us/nuget/consume-packages/migrate-packages-config-to-package-reference +// Migrating brings the following benefits: +// * The "Nullable" folder and the nullable "*Attribute.cs" files don't appear in your project. +// * The added files are immutable and can therefore not be modified by coincidence. +// * Updating/Uninstalling the package will work flawlessly. +// + +#region License +// MIT License +// +// Copyright (c) Manuel Römer +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +#endregion + +#if !NULLABLE_ATTRIBUTES_DISABLE +#nullable enable +#pragma warning disable + +namespace System.Diagnostics.CodeAnalysis +{ + using global::System; + +#if DEBUG + /// + /// Specifies that the method or property will ensure that the listed field and property members have + /// not- values. + /// +#endif + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] +#if !NULLABLE_ATTRIBUTES_INCLUDE_IN_CODE_COVERAGE + [DebuggerNonUserCode] +#endif + internal sealed class MemberNotNullAttribute : Attribute + { +#if DEBUG + /// + /// Gets field or property member names. + /// +#endif + public string[] Members { get; } + +#if DEBUG + /// + /// Initializes the attribute with a field or property member. + /// + /// + /// The field or property member that is promised to be not-null. + /// +#endif + public MemberNotNullAttribute(string member) + { + Members = new[] { member }; + } + +#if DEBUG + /// + /// Initializes the attribute with the list of field and property members. + /// + /// + /// The list of field and property members that are promised to be not-null. + /// +#endif + public MemberNotNullAttribute(params string[] members) + { + Members = members; + } + } +} + +#pragma warning restore +#nullable restore +#endif // NULLABLE_ATTRIBUTES_DISABLE diff --git a/examples/WireMock.Net.Console.Net472.Classic/Nullable/MemberNotNullWhenAttribute.cs b/examples/WireMock.Net.Console.Net472.Classic/Nullable/MemberNotNullWhenAttribute.cs new file mode 100644 index 00000000..8bbe44d8 --- /dev/null +++ b/examples/WireMock.Net.Console.Net472.Classic/Nullable/MemberNotNullWhenAttribute.cs @@ -0,0 +1,114 @@ +// +// This code file has automatically been added by the "Nullable" NuGet package (https://www.nuget.org/packages/Nullable). +// Please see https://github.com/manuelroemer/Nullable for more information. +// +// IMPORTANT: +// DO NOT DELETE THIS FILE if you are using a "packages.config" file to manage your NuGet references. +// Consider migrating to PackageReferences instead: +// https://docs.microsoft.com/en-us/nuget/consume-packages/migrate-packages-config-to-package-reference +// Migrating brings the following benefits: +// * The "Nullable" folder and the nullable "*Attribute.cs" files don't appear in your project. +// * The added files are immutable and can therefore not be modified by coincidence. +// * Updating/Uninstalling the package will work flawlessly. +// + +#region License +// MIT License +// +// Copyright (c) Manuel Römer +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +#endregion + +#if !NULLABLE_ATTRIBUTES_DISABLE +#nullable enable +#pragma warning disable + +namespace System.Diagnostics.CodeAnalysis +{ + using global::System; + +#if DEBUG + /// + /// Specifies that the method or property will ensure that the listed field and property members have + /// non- values when returning with the specified return value condition. + /// +#endif + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] +#if !NULLABLE_ATTRIBUTES_INCLUDE_IN_CODE_COVERAGE + [DebuggerNonUserCode] +#endif + internal sealed class MemberNotNullWhenAttribute : Attribute + { +#if DEBUG + /// + /// Gets the return value condition. + /// +#endif + public bool ReturnValue { get; } + +#if DEBUG + /// + /// Gets field or property member names. + /// +#endif + public string[] Members { get; } + +#if DEBUG + /// + /// Initializes the attribute with the specified return value condition and a field or property member. + /// + /// + /// The return value condition. If the method returns this value, + /// the associated parameter will not be . + /// + /// + /// The field or property member that is promised to be not-. + /// +#endif + public MemberNotNullWhenAttribute(bool returnValue, string member) + { + ReturnValue = returnValue; + Members = new[] { member }; + } + +#if DEBUG + /// + /// Initializes the attribute with the specified return value condition and list + /// of field and property members. + /// + /// + /// The return value condition. If the method returns this value, + /// the associated parameter will not be . + /// + /// + /// The list of field and property members that are promised to be not-null. + /// +#endif + public MemberNotNullWhenAttribute(bool returnValue, params string[] members) + { + ReturnValue = returnValue; + Members = members; + } + } +} + +#pragma warning restore +#nullable restore +#endif // NULLABLE_ATTRIBUTES_DISABLE diff --git a/examples/WireMock.Net.Console.Net472.Classic/Nullable/NotNullAttribute.cs b/examples/WireMock.Net.Console.Net472.Classic/Nullable/NotNullAttribute.cs new file mode 100644 index 00000000..ec3724ec --- /dev/null +++ b/examples/WireMock.Net.Console.Net472.Classic/Nullable/NotNullAttribute.cs @@ -0,0 +1,74 @@ +// +// This code file has automatically been added by the "Nullable" NuGet package (https://www.nuget.org/packages/Nullable). +// Please see https://github.com/manuelroemer/Nullable for more information. +// +// IMPORTANT: +// DO NOT DELETE THIS FILE if you are using a "packages.config" file to manage your NuGet references. +// Consider migrating to PackageReferences instead: +// https://docs.microsoft.com/en-us/nuget/consume-packages/migrate-packages-config-to-package-reference +// Migrating brings the following benefits: +// * The "Nullable" folder and the nullable "*Attribute.cs" files don't appear in your project. +// * The added files are immutable and can therefore not be modified by coincidence. +// * Updating/Uninstalling the package will work flawlessly. +// + +#region License +// MIT License +// +// Copyright (c) Manuel Römer +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +#endregion + +#if !NULLABLE_ATTRIBUTES_DISABLE +#nullable enable +#pragma warning disable + +namespace System.Diagnostics.CodeAnalysis +{ + using global::System; + +#if DEBUG + /// + /// Specifies that an output is not even if the + /// corresponding type allows it. + /// +#endif + [AttributeUsage( + AttributeTargets.Field | AttributeTargets.Parameter | + AttributeTargets.Property | AttributeTargets.ReturnValue, + Inherited = false + )] +#if !NULLABLE_ATTRIBUTES_INCLUDE_IN_CODE_COVERAGE + [DebuggerNonUserCode] +#endif + internal sealed class NotNullAttribute : Attribute + { +#if DEBUG + /// + /// Initializes a new instance of the class. + /// +#endif + public NotNullAttribute() { } + } +} + +#pragma warning restore +#nullable restore +#endif // NULLABLE_ATTRIBUTES_DISABLE diff --git a/examples/WireMock.Net.Console.Net472.Classic/Nullable/NotNullIfNotNullAttribute.cs b/examples/WireMock.Net.Console.Net472.Classic/Nullable/NotNullIfNotNullAttribute.cs new file mode 100644 index 00000000..72ee057b --- /dev/null +++ b/examples/WireMock.Net.Console.Net472.Classic/Nullable/NotNullIfNotNullAttribute.cs @@ -0,0 +1,91 @@ +// +// This code file has automatically been added by the "Nullable" NuGet package (https://www.nuget.org/packages/Nullable). +// Please see https://github.com/manuelroemer/Nullable for more information. +// +// IMPORTANT: +// DO NOT DELETE THIS FILE if you are using a "packages.config" file to manage your NuGet references. +// Consider migrating to PackageReferences instead: +// https://docs.microsoft.com/en-us/nuget/consume-packages/migrate-packages-config-to-package-reference +// Migrating brings the following benefits: +// * The "Nullable" folder and the nullable "*Attribute.cs" files don't appear in your project. +// * The added files are immutable and can therefore not be modified by coincidence. +// * Updating/Uninstalling the package will work flawlessly. +// + +#region License +// MIT License +// +// Copyright (c) Manuel Römer +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +#endregion + +#if !NULLABLE_ATTRIBUTES_DISABLE +#nullable enable +#pragma warning disable + +namespace System.Diagnostics.CodeAnalysis +{ + using global::System; + +#if DEBUG + /// + /// Specifies that the output will be non- if the + /// named parameter is non-. + /// +#endif + [AttributeUsage( + AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, + AllowMultiple = true, + Inherited = false + )] +#if !NULLABLE_ATTRIBUTES_INCLUDE_IN_CODE_COVERAGE + [DebuggerNonUserCode] +#endif + internal sealed class NotNullIfNotNullAttribute : Attribute + { +#if DEBUG + /// + /// Gets the associated parameter name. + /// The output will be non- if the argument to the + /// parameter specified is non-. + /// +#endif + public string ParameterName { get; } + +#if DEBUG + /// + /// Initializes the attribute with the associated parameter name. + /// + /// + /// The associated parameter name. + /// The output will be non- if the argument to the + /// parameter specified is non-. + /// +#endif + public NotNullIfNotNullAttribute(string parameterName) + { + ParameterName = parameterName; + } + } +} + +#pragma warning restore +#nullable restore +#endif // NULLABLE_ATTRIBUTES_DISABLE diff --git a/examples/WireMock.Net.Console.Net472.Classic/Nullable/NotNullWhenAttribute.cs b/examples/WireMock.Net.Console.Net472.Classic/Nullable/NotNullWhenAttribute.cs new file mode 100644 index 00000000..9887fabd --- /dev/null +++ b/examples/WireMock.Net.Console.Net472.Classic/Nullable/NotNullWhenAttribute.cs @@ -0,0 +1,85 @@ +// +// This code file has automatically been added by the "Nullable" NuGet package (https://www.nuget.org/packages/Nullable). +// Please see https://github.com/manuelroemer/Nullable for more information. +// +// IMPORTANT: +// DO NOT DELETE THIS FILE if you are using a "packages.config" file to manage your NuGet references. +// Consider migrating to PackageReferences instead: +// https://docs.microsoft.com/en-us/nuget/consume-packages/migrate-packages-config-to-package-reference +// Migrating brings the following benefits: +// * The "Nullable" folder and the nullable "*Attribute.cs" files don't appear in your project. +// * The added files are immutable and can therefore not be modified by coincidence. +// * Updating/Uninstalling the package will work flawlessly. +// + +#region License +// MIT License +// +// Copyright (c) Manuel Römer +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +#endregion + +#if !NULLABLE_ATTRIBUTES_DISABLE +#nullable enable +#pragma warning disable + +namespace System.Diagnostics.CodeAnalysis +{ + using global::System; + +#if DEBUG + /// + /// Specifies that when a method returns , + /// the parameter will not be even if the corresponding type allows it. + /// +#endif + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] +#if !NULLABLE_ATTRIBUTES_INCLUDE_IN_CODE_COVERAGE + [DebuggerNonUserCode] +#endif + internal sealed class NotNullWhenAttribute : Attribute + { +#if DEBUG + /// + /// Gets the return value condition. + /// If the method returns this value, the associated parameter will not be . + /// +#endif + public bool ReturnValue { get; } + +#if DEBUG + /// + /// Initializes the attribute with the specified return value condition. + /// + /// + /// The return value condition. + /// If the method returns this value, the associated parameter will not be . + /// +#endif + public NotNullWhenAttribute(bool returnValue) + { + ReturnValue = returnValue; + } + } +} + +#pragma warning restore +#nullable restore +#endif // NULLABLE_ATTRIBUTES_DISABLE diff --git a/examples/WireMock.Net.Console.Net472.Classic/WireMock.Net.Console.Net472.Classic.csproj b/examples/WireMock.Net.Console.Net472.Classic/WireMock.Net.Console.Net472.Classic.csproj index 09b01537..8591b27a 100644 --- a/examples/WireMock.Net.Console.Net472.Classic/WireMock.Net.Console.Net472.Classic.csproj +++ b/examples/WireMock.Net.Console.Net472.Classic/WireMock.Net.Console.Net472.Classic.csproj @@ -54,23 +54,23 @@ ..\..\packages\Handlebars.Net.Helpers.Core.2.3.5\lib\net452\HandlebarsDotNet.Helpers.Core.dll - - ..\..\packages\Handlebars.Net.Helpers.DynamicLinq.2.3.3\lib\net452\HandlebarsDotNet.Helpers.DynamicLinq.dll + + ..\..\packages\Handlebars.Net.Helpers.DynamicLinq.2.3.5\lib\net452\HandlebarsDotNet.Helpers.DynamicLinq.dll - - ..\..\packages\Handlebars.Net.Helpers.Humanizer.2.3.3\lib\net452\HandlebarsDotNet.Helpers.Humanizer.dll + + ..\..\packages\Handlebars.Net.Helpers.Humanizer.2.3.5\lib\net452\HandlebarsDotNet.Helpers.Humanizer.dll - - ..\..\packages\Handlebars.Net.Helpers.Json.2.3.3\lib\net452\HandlebarsDotNet.Helpers.Json.dll + + ..\..\packages\Handlebars.Net.Helpers.Json.2.3.5\lib\net452\HandlebarsDotNet.Helpers.Json.dll - - ..\..\packages\Handlebars.Net.Helpers.Random.2.3.3\lib\net452\HandlebarsDotNet.Helpers.Random.dll + + ..\..\packages\Handlebars.Net.Helpers.Random.2.3.5\lib\net452\HandlebarsDotNet.Helpers.Random.dll - - ..\..\packages\Handlebars.Net.Helpers.Xeger.2.3.3\lib\net452\HandlebarsDotNet.Helpers.Xeger.dll + + ..\..\packages\Handlebars.Net.Helpers.Xeger.2.3.5\lib\net452\HandlebarsDotNet.Helpers.Xeger.dll - - ..\..\packages\Handlebars.Net.Helpers.XPath.2.3.3\lib\net452\HandlebarsDotNet.Helpers.XPath.dll + + ..\..\packages\Handlebars.Net.Helpers.XPath.2.3.5\lib\net452\HandlebarsDotNet.Helpers.XPath.dll ..\..\packages\Humanizer.Core.2.14.1\lib\netstandard2.0\Humanizer.dll @@ -246,11 +246,23 @@ ..\..\packages\Microsoft.Net.Http.Headers.2.2.0\lib\netstandard2.0\Microsoft.Net.Http.Headers.dll + + ..\..\packages\Namotion.Reflection.2.0.10\lib\net45\Namotion.Reflection.dll + ..\..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll - - ..\..\packages\RandomDataGenerator.Net.1.0.14\lib\net45\RandomDataGenerator.dll + + ..\..\packages\NJsonSchema.10.6.10\lib\net45\NJsonSchema.dll + + + ..\..\packages\NJsonSchema.Extensions.0.1.0\lib\net45\NJsonSchema.Extensions.dll + + + ..\..\packages\NSwag.Core.13.15.10\lib\net45\NSwag.Core.dll + + + ..\..\packages\RandomDataGenerator.Net.1.0.15\lib\net45\RandomDataGenerator.dll ..\..\packages\Scriban.Signed.2.1.4\lib\net45\Scriban.Signed.dll @@ -289,6 +301,10 @@ ..\..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll + + + ..\..\packages\Microsoft.AspNet.WebApi.Client.5.2.8\lib\net45\System.Net.Http.Formatting.dll + @@ -300,6 +316,7 @@ ..\..\packages\System.Runtime.CompilerServices.Unsafe.5.0.0\lib\net45\System.Runtime.CompilerServices.Unsafe.dll + ..\..\packages\System.Security.Cryptography.Cng.4.5.0\lib\net47\System.Security.Cryptography.Cng.dll @@ -325,14 +342,14 @@ ..\..\packages\TinyMapper.3.0.3\lib\net40\TinyMapper.dll - - ..\..\packages\WireMock.Net.1.4.41\lib\net461\WireMock.Net.dll + + ..\..\packages\WireMock.Net.1.5.1\lib\net461\WireMock.Net.dll - - ..\..\packages\WireMock.Net.Abstractions.1.4.41\lib\net451\WireMock.Net.Abstractions.dll + + ..\..\packages\WireMock.Net.Abstractions.1.5.1\lib\net451\WireMock.Net.Abstractions.dll - - ..\..\packages\WireMock.Org.Abstractions.1.4.41\lib\net45\WireMock.Org.Abstractions.dll + + ..\..\packages\WireMock.Org.Abstractions.1.5.1\lib\net45\WireMock.Org.Abstractions.dll ..\..\packages\XPath2.1.1.3\lib\net452\XPath2.dll @@ -351,6 +368,17 @@ Program.cs + + + + + + + + + + + diff --git a/examples/WireMock.Net.Console.Net472.Classic/packages.config b/examples/WireMock.Net.Console.Net472.Classic/packages.config index 01a619d6..dbd11347 100644 --- a/examples/WireMock.Net.Console.Net472.Classic/packages.config +++ b/examples/WireMock.Net.Console.Net472.Classic/packages.config @@ -5,12 +5,12 @@ - - - - - - + + + + + + @@ -63,6 +63,7 @@ + @@ -119,8 +120,13 @@ + - + + + + + @@ -141,9 +147,9 @@ - - - + + + \ No newline at end of file diff --git a/src/WireMock.Net.Abstractions/Admin/Mappings/WebhookRequestModel.cs b/src/WireMock.Net.Abstractions/Admin/Mappings/WebhookRequestModel.cs index d74a1775..5dd749af 100644 --- a/src/WireMock.Net.Abstractions/Admin/Mappings/WebhookRequestModel.cs +++ b/src/WireMock.Net.Abstractions/Admin/Mappings/WebhookRequestModel.cs @@ -15,24 +15,24 @@ namespace WireMock.Admin.Mappings public string Url { get; set; } /// - /// The methods + /// The method /// public string Method { get; set; } /// /// Gets or sets the headers. /// - public IDictionary Headers { get; set; } + public IDictionary? Headers { get; set; } /// /// Gets or sets the body. /// - public string Body { get; set; } + public string? Body { get; set; } /// /// Gets or sets the body (as JSON object). /// - public object BodyAsJson { get; set; } + public object? BodyAsJson { get; set; } /// /// Use ResponseMessage Transformer. diff --git a/src/WireMock.Net/Http/HttpResponseMessageHelper.cs b/src/WireMock.Net/Http/HttpResponseMessageHelper.cs index a11517ba..54934c63 100644 --- a/src/WireMock.Net/Http/HttpResponseMessageHelper.cs +++ b/src/WireMock.Net/Http/HttpResponseMessageHelper.cs @@ -5,60 +5,64 @@ using System.Net.Http; using System.Threading.Tasks; using WireMock.Util; -namespace WireMock.Http +namespace WireMock.Http; + +internal static class HttpResponseMessageHelper { - internal static class HttpResponseMessageHelper + public static async Task CreateAsync( + HttpResponseMessage httpResponseMessage, + Uri requiredUri, + Uri originalUri, + bool deserializeJson, + bool decompressGzipAndDeflate) { - public static async Task CreateAsync(HttpResponseMessage httpResponseMessage, Uri requiredUri, Uri originalUri, bool deserializeJson, bool decompressGzipAndDeflate) + var responseMessage = new ResponseMessage { StatusCode = (int)httpResponseMessage.StatusCode }; + + // Set both content and response headers, replacing URLs in values + var headers = (httpResponseMessage.Content?.Headers.Union(httpResponseMessage.Headers) ?? Enumerable.Empty>>()).ToArray(); + if (httpResponseMessage.Content != null) { - var responseMessage = new ResponseMessage { StatusCode = (int)httpResponseMessage.StatusCode }; - - // Set both content and response headers, replacing URLs in values - var headers = (httpResponseMessage.Content?.Headers.Union(httpResponseMessage.Headers) ?? Enumerable.Empty>>()).ToArray(); - if (httpResponseMessage.Content != null) + var stream = await httpResponseMessage.Content.ReadAsStreamAsync().ConfigureAwait(false); + IEnumerable? contentTypeHeader = null; + if (headers.Any(header => string.Equals(header.Key, HttpKnownHeaderNames.ContentType, StringComparison.OrdinalIgnoreCase))) { - var stream = await httpResponseMessage.Content.ReadAsStreamAsync().ConfigureAwait(false); - IEnumerable contentTypeHeader = null; - if (headers.Any(header => string.Equals(header.Key, HttpKnownHeaderNames.ContentType, StringComparison.OrdinalIgnoreCase))) - { - contentTypeHeader = headers.First(header => string.Equals(header.Key, HttpKnownHeaderNames.ContentType, StringComparison.OrdinalIgnoreCase)).Value; - } - - IEnumerable contentEncodingHeader = null; - if (headers.Any(header => string.Equals(header.Key, HttpKnownHeaderNames.ContentEncoding, StringComparison.OrdinalIgnoreCase))) - { - contentEncodingHeader = headers.First(header => string.Equals(header.Key, HttpKnownHeaderNames.ContentEncoding, StringComparison.OrdinalIgnoreCase)).Value; - } - - var bodyParserSettings = new BodyParserSettings - { - Stream = stream, - ContentType = contentTypeHeader?.FirstOrDefault(), - DeserializeJson = deserializeJson, - ContentEncoding = contentEncodingHeader?.FirstOrDefault(), - DecompressGZipAndDeflate = decompressGzipAndDeflate - }; - responseMessage.BodyData = await BodyParser.ParseAsync(bodyParserSettings).ConfigureAwait(false); + contentTypeHeader = headers.First(header => string.Equals(header.Key, HttpKnownHeaderNames.ContentType, StringComparison.OrdinalIgnoreCase)).Value; } - foreach (var header in headers) + IEnumerable? contentEncodingHeader = null; + if (headers.Any(header => string.Equals(header.Key, HttpKnownHeaderNames.ContentEncoding, StringComparison.OrdinalIgnoreCase))) { - // If Location header contains absolute redirect URL, and base URL is one that we proxy to, - // we need to replace it to original one. - if (string.Equals(header.Key, HttpKnownHeaderNames.Location, StringComparison.OrdinalIgnoreCase) - && Uri.TryCreate(header.Value.First(), UriKind.Absolute, out Uri absoluteLocationUri) - && string.Equals(absoluteLocationUri.Host, requiredUri.Host, StringComparison.OrdinalIgnoreCase)) - { - var replacedLocationUri = new Uri(originalUri, absoluteLocationUri.PathAndQuery); - responseMessage.AddHeader(header.Key, replacedLocationUri.ToString()); - } - else - { - responseMessage.AddHeader(header.Key, header.Value.ToArray()); - } + contentEncodingHeader = headers.First(header => string.Equals(header.Key, HttpKnownHeaderNames.ContentEncoding, StringComparison.OrdinalIgnoreCase)).Value; } - return responseMessage; + var bodyParserSettings = new BodyParserSettings + { + Stream = stream, + ContentType = contentTypeHeader?.FirstOrDefault(), + DeserializeJson = deserializeJson, + ContentEncoding = contentEncodingHeader?.FirstOrDefault(), + DecompressGZipAndDeflate = decompressGzipAndDeflate + }; + responseMessage.BodyData = await BodyParser.ParseAsync(bodyParserSettings).ConfigureAwait(false); } + + foreach (var header in headers) + { + // If Location header contains absolute redirect URL, and base URL is one that we proxy to, + // we need to replace it to original one. + if (string.Equals(header.Key, HttpKnownHeaderNames.Location, StringComparison.OrdinalIgnoreCase) + && Uri.TryCreate(header.Value.First(), UriKind.Absolute, out Uri absoluteLocationUri) + && string.Equals(absoluteLocationUri.Host, requiredUri.Host, StringComparison.OrdinalIgnoreCase)) + { + var replacedLocationUri = new Uri(originalUri, absoluteLocationUri.PathAndQuery); + responseMessage.AddHeader(header.Key, replacedLocationUri.ToString()); + } + else + { + responseMessage.AddHeader(header.Key, header.Value.ToArray()); + } + } + + return responseMessage; } } \ No newline at end of file diff --git a/src/WireMock.Net/Matchers/JsonMatcher.cs b/src/WireMock.Net/Matchers/JsonMatcher.cs index 28810b2e..12d5d43c 100644 --- a/src/WireMock.Net/Matchers/JsonMatcher.cs +++ b/src/WireMock.Net/Matchers/JsonMatcher.cs @@ -68,9 +68,7 @@ public class JsonMatcher : IValueMatcher, IIgnoreCaseMatcher Value = value; _valueAsJToken = ConvertValueToJToken(value); - _jTokenConverter = ignoreCase - ? (Func)Rename - : jToken => jToken; + _jTokenConverter = ignoreCase ? Rename : jToken => jToken; } /// diff --git a/src/WireMock.Net/Owin/Mappers/OwinRequestMapper.cs b/src/WireMock.Net/Owin/Mappers/OwinRequestMapper.cs index 32c9a935..dbdcafde 100644 --- a/src/WireMock.Net/Owin/Mappers/OwinRequestMapper.cs +++ b/src/WireMock.Net/Owin/Mappers/OwinRequestMapper.cs @@ -27,8 +27,8 @@ namespace WireMock.Owin.Mappers string method = request.Method; - Dictionary headers = null; - IEnumerable contentEncodingHeader = null; + Dictionary? headers = null; + IEnumerable? contentEncodingHeader = null; if (request.Headers.Any()) { headers = new Dictionary(); @@ -43,7 +43,7 @@ namespace WireMock.Owin.Mappers } } - IDictionary cookies = null; + IDictionary? cookies = null; if (request.Cookies.Any()) { cookies = new Dictionary(); @@ -53,7 +53,7 @@ namespace WireMock.Owin.Mappers } } - IBodyData body = null; + IBodyData? body = null; if (request.Body != null && BodyParser.ShouldParseBody(method, options.AllowBodyForAllHttpMethods == true)) { var bodyParserSettings = new BodyParserSettings diff --git a/src/WireMock.Net/Util/BodyParser.cs b/src/WireMock.Net/Util/BodyParser.cs index 55b7c820..3ba04391 100644 --- a/src/WireMock.Net/Util/BodyParser.cs +++ b/src/WireMock.Net/Util/BodyParser.cs @@ -4,180 +4,176 @@ using System.Linq; using System.Net.Http.Headers; using System.Text; using System.Threading.Tasks; -using JetBrains.Annotations; +using Stef.Validation; using WireMock.Http; using WireMock.Matchers; using WireMock.Types; -using Stef.Validation; -namespace WireMock.Util +namespace WireMock.Util; + +internal static class BodyParser { - internal static class BodyParser + private static readonly Encoding DefaultEncoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true); + private static readonly Encoding[] SupportedBodyAsStringEncodingForMultipart = { DefaultEncoding, Encoding.ASCII }; + + /* + HEAD - No defined body semantics. + GET - No defined body semantics. + PUT - Body supported. + POST - Body supported. + DELETE - No defined body semantics. + TRACE - Body not supported. + OPTIONS - Body supported but no semantics on usage (maybe in the future). + CONNECT - No defined body semantics + PATCH - Body supported. + */ + private static readonly IDictionary BodyAllowedForMethods = new Dictionary { - private static readonly Encoding DefaultEncoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true); - private static readonly Encoding[] SupportedBodyAsStringEncodingForMultipart = { DefaultEncoding, Encoding.ASCII }; + { HttpRequestMethods.HEAD, false }, + { HttpRequestMethods.GET, false }, + { HttpRequestMethods.PUT, true }, + { HttpRequestMethods.POST, true }, + { HttpRequestMethods.DELETE, true }, + { HttpRequestMethods.TRACE, false }, + { HttpRequestMethods.OPTIONS, true }, + { HttpRequestMethods.CONNECT, false }, + { HttpRequestMethods.PATCH, true } + }; - /* - HEAD - No defined body semantics. - GET - No defined body semantics. - PUT - Body supported. - POST - Body supported. - DELETE - No defined body semantics. - TRACE - Body not supported. - OPTIONS - Body supported but no semantics on usage (maybe in the future). - CONNECT - No defined body semantics - PATCH - Body supported. - */ - private static readonly IDictionary BodyAllowedForMethods = new Dictionary + private static readonly IStringMatcher[] MultipartContentTypesMatchers = { + new WildcardMatcher("multipart/*", true) + }; + + private static readonly IStringMatcher[] JsonContentTypesMatchers = { + new WildcardMatcher("application/json", true), + new WildcardMatcher("application/vnd.*+json", true) + }; + + private static readonly IStringMatcher[] TextContentTypeMatchers = + { + new WildcardMatcher("text/*", true), + new RegexMatcher("^application\\/(java|type)script$", true), + new WildcardMatcher("application/*xml", true), + new WildcardMatcher("application/x-www-form-urlencoded", true) + }; + + public static bool ShouldParseBody(string? httpMethod, bool allowBodyForAllHttpMethods) + { + if (string.IsNullOrEmpty(httpMethod)) { - { HttpRequestMethods.HEAD, false }, - { HttpRequestMethods.GET, false }, - { HttpRequestMethods.PUT, true }, - { HttpRequestMethods.POST, true }, - { HttpRequestMethods.DELETE, true }, - { HttpRequestMethods.TRACE, false }, - { HttpRequestMethods.OPTIONS, true }, - { HttpRequestMethods.CONNECT, false }, - { HttpRequestMethods.PATCH, true } - }; + return false; + } - private static readonly IStringMatcher[] MultipartContentTypesMatchers = { - new WildcardMatcher("multipart/*", true) - }; - - private static readonly IStringMatcher[] JsonContentTypesMatchers = { - new WildcardMatcher("application/json", true), - new WildcardMatcher("application/vnd.*+json", true) - }; - - private static readonly IStringMatcher[] TextContentTypeMatchers = + if (allowBodyForAllHttpMethods) { - new WildcardMatcher("text/*", true), - new RegexMatcher("^application\\/(java|type)script$", true), - new WildcardMatcher("application/*xml", true), - new WildcardMatcher("application/x-www-form-urlencoded", true) - }; - - public static bool ShouldParseBody([CanBeNull] string httpMethod, bool allowBodyForAllHttpMethods) - { - if (string.IsNullOrEmpty(httpMethod)) - { - return false; - } - - if (allowBodyForAllHttpMethods) - { - return true; - } - - if (BodyAllowedForMethods.TryGetValue(httpMethod.ToUpper(), out bool allowed)) - { - return allowed; - } - - // If we don't have any knowledge of this method, we should assume that a body *may* - // be present, so we should parse it if it is. Therefore, if a new method is added to - // the HTTP Method Registry, we only really need to add it to BodyAllowedForMethods if - // we want to make it clear that a body is *not* allowed. return true; } - public static BodyType DetectBodyTypeFromContentType([CanBeNull] string contentTypeValue) + if (BodyAllowedForMethods.TryGetValue(httpMethod!.ToUpper(), out bool allowed)) { - if (string.IsNullOrEmpty(contentTypeValue) || !MediaTypeHeaderValue.TryParse(contentTypeValue, out MediaTypeHeaderValue contentType)) - { - return BodyType.Bytes; - } + return allowed; + } - if (TextContentTypeMatchers.Any(matcher => MatchScores.IsPerfect(matcher.IsMatch(contentType.MediaType)))) - { - return BodyType.String; - } - - if (JsonContentTypesMatchers.Any(matcher => MatchScores.IsPerfect(matcher.IsMatch(contentType.MediaType)))) - { - return BodyType.Json; - } - - if (MultipartContentTypesMatchers.Any(matcher => MatchScores.IsPerfect(matcher.IsMatch(contentType.MediaType)))) - { - return BodyType.MultiPart; - } + // If we don't have any knowledge of this method, we should assume that a body *may* + // be present, so we should parse it if it is. Therefore, if a new method is added to + // the HTTP Method Registry, we only really need to add it to BodyAllowedForMethods if + // we want to make it clear that a body is *not* allowed. + return true; + } + public static BodyType DetectBodyTypeFromContentType(string? contentTypeValue) + { + if (string.IsNullOrEmpty(contentTypeValue) || !MediaTypeHeaderValue.TryParse(contentTypeValue, out MediaTypeHeaderValue contentType)) + { return BodyType.Bytes; } - public static async Task ParseAsync([NotNull] BodyParserSettings settings) + if (TextContentTypeMatchers.Any(matcher => MatchScores.IsPerfect(matcher.IsMatch(contentType.MediaType)))) { - Guard.NotNull(settings, nameof(settings)); + return BodyType.String; + } - var bodyWithContentEncoding = await ReadBytesAsync(settings.Stream, settings.ContentEncoding, settings.DecompressGZipAndDeflate).ConfigureAwait(false); - var data = new BodyData - { - BodyAsBytes = bodyWithContentEncoding.Bytes, - DetectedCompression = bodyWithContentEncoding.ContentType, - DetectedBodyType = BodyType.Bytes, - DetectedBodyTypeFromContentType = DetectBodyTypeFromContentType(settings.ContentType) - }; + if (JsonContentTypesMatchers.Any(matcher => MatchScores.IsPerfect(matcher.IsMatch(contentType.MediaType)))) + { + return BodyType.Json; + } - // In case of MultiPart: check if the BodyAsBytes is a valid UTF8 or ASCII string, in that case read as String else keep as-is - if (data.DetectedBodyTypeFromContentType == BodyType.MultiPart) - { - if (BytesEncodingUtils.TryGetEncoding(data.BodyAsBytes, out Encoding encoding) && - SupportedBodyAsStringEncodingForMultipart.Select(x => x.Equals(encoding)).Any()) - { - data.BodyAsString = encoding.GetString(data.BodyAsBytes); - data.Encoding = encoding; - data.DetectedBodyType = BodyType.String; - } - - return data; - } + if (MultipartContentTypesMatchers.Any(matcher => MatchScores.IsPerfect(matcher.IsMatch(contentType.MediaType)))) + { + return BodyType.MultiPart; + } - // Try to get the body as String - try + return BodyType.Bytes; + } + + public static async Task ParseAsync(BodyParserSettings settings) + { + Guard.NotNull(settings); + + var bodyWithContentEncoding = await ReadBytesAsync(settings.Stream, settings.ContentEncoding, settings.DecompressGZipAndDeflate).ConfigureAwait(false); + var data = new BodyData + { + BodyAsBytes = bodyWithContentEncoding.Bytes, + DetectedCompression = bodyWithContentEncoding.ContentType, + DetectedBodyType = BodyType.Bytes, + DetectedBodyTypeFromContentType = DetectBodyTypeFromContentType(settings.ContentType) + }; + + // In case of MultiPart: check if the BodyAsBytes is a valid UTF8 or ASCII string, in that case read as String else keep as-is + if (data.DetectedBodyTypeFromContentType == BodyType.MultiPart) + { + if (BytesEncodingUtils.TryGetEncoding(data.BodyAsBytes, out Encoding encoding) && + SupportedBodyAsStringEncodingForMultipart.Select(x => x.Equals(encoding)).Any()) { - data.BodyAsString = DefaultEncoding.GetString(data.BodyAsBytes); - data.Encoding = DefaultEncoding; + data.BodyAsString = encoding.GetString(data.BodyAsBytes); + data.Encoding = encoding; data.DetectedBodyType = BodyType.String; - - // If string is not null or empty, try to deserialize the string to a JObject - if (settings.DeserializeJson && !string.IsNullOrEmpty(data.BodyAsString)) - { - try - { - data.BodyAsJson = JsonUtils.DeserializeObject(data.BodyAsString); - data.DetectedBodyType = BodyType.Json; - } - catch - { - // JsonConvert failed, just ignore. - } - } - } - catch - { - // Reading as string failed, just ignore } return data; } - private static async Task<(string ContentType, byte[] Bytes)> ReadBytesAsync(Stream stream, string contentEncoding = null, bool decompressGZipAndDeflate = true) + // Try to get the body as String or Json + try { - using (var memoryStream = new MemoryStream()) + data.BodyAsString = DefaultEncoding.GetString(data.BodyAsBytes); + data.Encoding = DefaultEncoding; + data.DetectedBodyType = BodyType.String; + + // If string is not null or empty, try to deserialize the string to a JObject + if (settings.DeserializeJson && !string.IsNullOrEmpty(data.BodyAsString)) { - await stream.CopyToAsync(memoryStream).ConfigureAwait(false); - byte[] data = memoryStream.ToArray(); - - string type = contentEncoding?.ToLowerInvariant(); - if (decompressGZipAndDeflate && (type == "gzip" || type == "deflate")) + try { - return (type, CompressionUtils.Decompress(type, data)); + data.BodyAsJson = JsonUtils.DeserializeObject(data.BodyAsString); + data.DetectedBodyType = BodyType.Json; + } + catch + { + // JsonConvert failed, just ignore. } - - return (null, data); } } + catch + { + // Reading as string failed, just ignore + } + + return data; + } + + private static async Task<(string? ContentType, byte[] Bytes)> ReadBytesAsync(Stream stream, string? contentEncoding = null, bool decompressGZipAndDeflate = true) + { + using var memoryStream = new MemoryStream(); + await stream.CopyToAsync(memoryStream).ConfigureAwait(false); + byte[] data = memoryStream.ToArray(); + + var type = contentEncoding?.ToLowerInvariant(); + if (decompressGZipAndDeflate && type is "gzip" or "deflate") + { + return (type, CompressionUtils.Decompress(type, data)); + } + + return (null, data); } } \ No newline at end of file diff --git a/src/WireMock.Net/Util/BodyParserSettings.cs b/src/WireMock.Net/Util/BodyParserSettings.cs index 3dfa820a..a6aec91a 100644 --- a/src/WireMock.Net/Util/BodyParserSettings.cs +++ b/src/WireMock.Net/Util/BodyParserSettings.cs @@ -1,17 +1,16 @@ -using System.IO; +using System.IO; -namespace WireMock.Util +namespace WireMock.Util; + +internal class BodyParserSettings { - internal class BodyParserSettings - { - public Stream Stream { get; set; } + public Stream Stream { get; set; } = null!; - public string ContentType { get; set; } + public string? ContentType { get; set; } - public string ContentEncoding { get; set; } + public string? ContentEncoding { get; set; } - public bool DecompressGZipAndDeflate { get; set; } = true; + public bool DecompressGZipAndDeflate { get; set; } = true; - public bool DeserializeJson { get; set; } = true; - } + public bool DeserializeJson { get; set; } = true; } \ No newline at end of file diff --git a/test/WireMock.Net.Tests/Matchers/JsonMatcherTests.cs b/test/WireMock.Net.Tests/Matchers/JsonMatcherTests.cs index 639994fa..8a0435eb 100644 --- a/test/WireMock.Net.Tests/Matchers/JsonMatcherTests.cs +++ b/test/WireMock.Net.Tests/Matchers/JsonMatcherTests.cs @@ -1,299 +1,356 @@ -using System; +using System; using System.IO; using FluentAssertions; using Newtonsoft.Json; +using Newtonsoft.Json.Converters; using Newtonsoft.Json.Linq; using NFluent; using WireMock.Matchers; using Xunit; -namespace WireMock.Net.Tests.Matchers +namespace WireMock.Net.Tests.Matchers; + +public class JsonMatcherTests { - public class JsonMatcherTests + [JsonConverter(typeof(StringEnumConverter))] + public enum EnumWithJsonConverter { - [Fact] - public void JsonMatcher_GetName() + Type1 + } + + public enum NormalEnum + { + Abc + } + + public class Test1 + { + public NormalEnum NormalEnum { get; set; } + } + + public class Test2 + { + public EnumWithJsonConverter EnumWithJsonConverter { get; set; } + } + + [Fact] + public void JsonMatcher_GetName() + { + // Assign + var matcher = new JsonMatcher("{}"); + + // Act + string name = matcher.Name; + + // Assert + Check.That(name).Equals("JsonMatcher"); + } + + [Fact] + public void JsonMatcher_GetValue() + { + // Assign + var matcher = new JsonMatcher("{}"); + + // Act + object value = matcher.Value; + + // Assert + Check.That(value).Equals("{}"); + } + + [Fact] + public void JsonMatcher_WithInvalidStringValue_Should_ThrowException() + { + // Act + // ReSharper disable once ObjectCreationAsStatement + Action action = () => new JsonMatcher(MatchBehaviour.AcceptOnMatch, "{ \"Id\""); + + // Assert + action.Should().Throw(); + } + + [Fact] + public void JsonMatcher_WithInvalidObjectValue_Should_ThrowException() + { + // Act + // ReSharper disable once ObjectCreationAsStatement + Action action = () => new JsonMatcher(MatchBehaviour.AcceptOnMatch, new MemoryStream()); + + // Assert + action.Should().Throw(); + } + + [Fact] + public void JsonMatcher_IsMatch_WithInvalidValue_And_ThrowExceptionIsFalse_Should_ReturnMismatch() + { + // Assign + var matcher = new JsonMatcher(""); + + // Act + double match = matcher.IsMatch(new MemoryStream()); + + // Assert + Check.That(match).IsEqualTo(0); + } + + [Fact] + public void JsonMatcher_IsMatch_WithInvalidValue_And_ThrowExceptionIsTrue_Should_ReturnMismatch() + { + // Assign + var matcher = new JsonMatcher("", false, true); + + // Act + Action action = () => matcher.IsMatch(new MemoryStream()); + + // Assert + action.Should().Throw(); + } + + [Fact] + public void JsonMatcher_IsMatch_ByteArray() + { + // Assign + var bytes = new byte[0]; + var matcher = new JsonMatcher(""); + + // Act + double match = matcher.IsMatch(bytes); + + // Assert + Check.That(match).IsEqualTo(0); + } + + [Fact] + public void JsonMatcher_IsMatch_NullString() + { + // Assign + string? s = null; + var matcher = new JsonMatcher(""); + + // Act + double match = matcher.IsMatch(s); + + // Assert + Check.That(match).IsEqualTo(0); + } + + [Fact] + public void JsonMatcher_IsMatch_NullObject() + { + // Assign + object? o = null; + var matcher = new JsonMatcher(""); + + // Act + double match = matcher.IsMatch(o); + + // Assert + Check.That(match).IsEqualTo(0); + } + + [Fact] + public void JsonMatcher_IsMatch_JArray() + { + // Assign + var matcher = new JsonMatcher(new[] { "x", "y" }); + + // Act + var jArray = new JArray { - // Assign - var matcher = new JsonMatcher("{}"); + "x", + "y" + }; + double match = matcher.IsMatch(jArray); - // Act - string name = matcher.Name; + // Assert + Assert.Equal(1.0, match); + } - // Assert - Check.That(name).Equals("JsonMatcher"); - } + [Fact] + public void JsonMatcher_IsMatch_JObject() + { + // Assign + var matcher = new JsonMatcher(new { Id = 1, Name = "Test" }); - [Fact] - public void JsonMatcher_GetValue() + // Act + var jObject = new JObject { - // Assign - var matcher = new JsonMatcher("{}"); + { "Id", new JValue(1) }, + { "Name", new JValue("Test") } + }; + double match = matcher.IsMatch(jObject); - // Act - object value = matcher.Value; + // Assert + Assert.Equal(1.0, match); + } - // Assert - Check.That(value).Equals("{}"); - } + [Fact] + public void JsonMatcher_IsMatch_WithIgnoreCaseTrue_JObject() + { + // Assign + var matcher = new JsonMatcher(new { id = 1, Name = "test" }, true); - [Fact] - public void JsonMatcher_WithInvalidStringValue_Should_ThrowException() + // Act + var jObject = new JObject { - // Act - Action action = () => new JsonMatcher(MatchBehaviour.AcceptOnMatch, "{ \"Id\""); + { "Id", new JValue(1) }, + { "NaMe", new JValue("Test") } + }; + double match = matcher.IsMatch(jObject); - // Assert - action.Should().Throw(); - } + // Assert + Assert.Equal(1.0, match); + } - [Fact] - public void JsonMatcher_WithInvalidObjectValue_Should_ThrowException() + [Fact] + public void JsonMatcher_IsMatch_JObjectParsed() + { + // Assign + var matcher = new JsonMatcher(new { Id = 1, Name = "Test" }); + + // Act + var jObject = JObject.Parse("{ \"Id\" : 1, \"Name\" : \"Test\" }"); + double match = matcher.IsMatch(jObject); + + // Assert + Assert.Equal(1.0, match); + } + + [Fact] + public void JsonMatcher_IsMatch_WithIgnoreCaseTrue_JObjectParsed() + { + // Assign + var matcher = new JsonMatcher(new { Id = 1, Name = "TESt" }, true); + + // Act + var jObject = JObject.Parse("{ \"Id\" : 1, \"Name\" : \"Test\" }"); + double match = matcher.IsMatch(jObject); + + // Assert + Assert.Equal(1.0, match); + } + + [Fact] + public void JsonMatcher_IsMatch_JArrayAsString() + { + // Assign + var matcher = new JsonMatcher("[ \"x\", \"y\" ]"); + + // Act + var jArray = new JArray { - // Act - Action action = () => new JsonMatcher(MatchBehaviour.AcceptOnMatch, new MemoryStream()); + "x", + "y" + }; + double match = matcher.IsMatch(jArray); - // Assert - action.Should().Throw(); - } + // Assert + Assert.Equal(1.0, match); + } - [Fact] - public void JsonMatcher_IsMatch_WithInvalidValue_And_ThrowExceptionIsFalse_Should_ReturnMismatch() + [Fact] + public void JsonMatcher_IsMatch_JObjectAsString() + { + // Assign + var matcher = new JsonMatcher("{ \"Id\" : 1, \"Name\" : \"Test\" }"); + + // Act + var jObject = new JObject { - // Assign - var matcher = new JsonMatcher(""); + { "Id", new JValue(1) }, + { "Name", new JValue("Test") } + }; + double match = matcher.IsMatch(jObject); - // Act - double match = matcher.IsMatch(new MemoryStream()); + // Assert + Assert.Equal(1.0, match); + } - // Assert - Check.That(match).IsEqualTo(0); - } + [Fact] + public void JsonMatcher_IsMatch_WithIgnoreCaseTrue_JObjectAsString() + { + // Assign + var matcher = new JsonMatcher("{ \"Id\" : 1, \"Name\" : \"test\" }", true); - [Fact] - public void JsonMatcher_IsMatch_WithInvalidValue_And_ThrowExceptionIsTrue_Should_ReturnMismatch() + // Act + var jObject = new JObject { - // Assign - var matcher = new JsonMatcher("", false, true); + { "Id", new JValue(1) }, + { "Name", new JValue("Test") } + }; + double match = matcher.IsMatch(jObject); - // Act - Action action = () => matcher.IsMatch(new MemoryStream()); + // Assert + Assert.Equal(1.0, match); + } - // Assert - action.Should().Throw(); - } + [Fact] + public void JsonMatcher_IsMatch_JObjectAsString_RejectOnMatch() + { + // Assign + var matcher = new JsonMatcher(MatchBehaviour.RejectOnMatch, "{ \"Id\" : 1, \"Name\" : \"Test\" }"); - [Fact] - public void JsonMatcher_IsMatch_ByteArray() + // Act + var jObject = new JObject { - // Assign - var bytes = new byte[0]; - var matcher = new JsonMatcher(""); + { "Id", new JValue(1) }, + { "Name", new JValue("Test") } + }; + double match = matcher.IsMatch(jObject); - // Act - double match = matcher.IsMatch(bytes); + // Assert + Assert.Equal(0.0, match); + } - // Assert - Check.That(match).IsEqualTo(0); - } + [Fact] + public void JsonMatcher_IsMatch_JObjectWithDateTimeOffsetAsString() + { + // Assign + var matcher = new JsonMatcher("{ \"preferredAt\" : \"2019-11-21T10:32:53.2210009+00:00\" }"); - [Fact] - public void JsonMatcher_IsMatch_NullString() + // Act + var jObject = new JObject { - // Assign - string s = null; - var matcher = new JsonMatcher(""); + { "preferredAt", new JValue("2019-11-21T10:32:53.2210009+00:00") } + }; + double match = matcher.IsMatch(jObject); - // Act - double match = matcher.IsMatch(s); + // Assert + Assert.Equal(1.0, match); + } - // Assert - Check.That(match).IsEqualTo(0); - } + [Fact] + public void JsonMatcher_IsMatch_NormalEnum() + { + // Assign + var matcher = new JsonMatcher(new Test1 { NormalEnum = NormalEnum.Abc}); - [Fact] - public void JsonMatcher_IsMatch_NullObject() + // Act + var jObject = new JObject { - // Assign - object o = null; - var matcher = new JsonMatcher(""); + { "NormalEnum", new JValue(0) } + }; + double match = matcher.IsMatch(jObject); - // Act - double match = matcher.IsMatch(o); + // Assert + match.Should().Be(1.0); + } - // Assert - Check.That(match).IsEqualTo(0); - } + [Fact] + public void JsonMatcher_IsMatch_EnumWithJsonConverter() + { + // Assign + var matcher = new JsonMatcher(new Test2 { EnumWithJsonConverter = EnumWithJsonConverter.Type1 }); - [Fact] - public void JsonMatcher_IsMatch_JArray() + // Act + var jObject = new JObject { - // Assign - var matcher = new JsonMatcher(new[] { "x", "y" }); + { "EnumWithJsonConverter", new JValue("Type1") } + }; + double match = matcher.IsMatch(jObject); - // Act - var jArray = new JArray - { - "x", - "y" - }; - double match = matcher.IsMatch(jArray); - - // Assert - Assert.Equal(1.0, match); - } - - [Fact] - public void JsonMatcher_IsMatch_JObject() - { - // Assign - var matcher = new JsonMatcher(new { Id = 1, Name = "Test" }); - - // Act - var jobject = new JObject - { - { "Id", new JValue(1) }, - { "Name", new JValue("Test") } - }; - double match = matcher.IsMatch(jobject); - - // Assert - Assert.Equal(1.0, match); - } - - [Fact] - public void JsonMatcher_IsMatch_WithIgnoreCaseTrue_JObject() - { - // Assign - var matcher = new JsonMatcher(new { id = 1, Name = "test" }, true); - - // Act - var jobject = new JObject - { - { "Id", new JValue(1) }, - { "NaMe", new JValue("Test") } - }; - double match = matcher.IsMatch(jobject); - - // Assert - Assert.Equal(1.0, match); - } - - [Fact] - public void JsonMatcher_IsMatch_JObjectParsed() - { - // Assign - var matcher = new JsonMatcher(new { Id = 1, Name = "Test" }); - - // Act - var jobject = JObject.Parse("{ \"Id\" : 1, \"Name\" : \"Test\" }"); - double match = matcher.IsMatch(jobject); - - // Assert - Assert.Equal(1.0, match); - } - - [Fact] - public void JsonMatcher_IsMatch_WithIgnoreCaseTrue_JObjectParsed() - { - // Assign - var matcher = new JsonMatcher(new { Id = 1, Name = "TESt" }, true); - - // Act - var jobject = JObject.Parse("{ \"Id\" : 1, \"Name\" : \"Test\" }"); - double match = matcher.IsMatch(jobject); - - // Assert - Assert.Equal(1.0, match); - } - - [Fact] - public void JsonMatcher_IsMatch_JArrayAsString() - { - // Assign - var matcher = new JsonMatcher("[ \"x\", \"y\" ]"); - - // Act - var jArray = new JArray - { - "x", - "y" - }; - double match = matcher.IsMatch(jArray); - - // Assert - Assert.Equal(1.0, match); - } - - [Fact] - public void JsonMatcher_IsMatch_JObjectAsString() - { - // Assign - var matcher = new JsonMatcher("{ \"Id\" : 1, \"Name\" : \"Test\" }"); - - // Act - var jobject = new JObject - { - { "Id", new JValue(1) }, - { "Name", new JValue("Test") } - }; - double match = matcher.IsMatch(jobject); - - // Assert - Assert.Equal(1.0, match); - } - - [Fact] - public void JsonMatcher_IsMatch_WithIgnoreCaseTrue_JObjectAsString() - { - // Assign - var matcher = new JsonMatcher("{ \"Id\" : 1, \"Name\" : \"test\" }", true); - - // Act - var jobject = new JObject - { - { "Id", new JValue(1) }, - { "Name", new JValue("Test") } - }; - double match = matcher.IsMatch(jobject); - - // Assert - Assert.Equal(1.0, match); - } - - [Fact] - public void JsonMatcher_IsMatch_JObjectAsString_RejectOnMatch() - { - // Assign - var matcher = new JsonMatcher(MatchBehaviour.RejectOnMatch, "{ \"Id\" : 1, \"Name\" : \"Test\" }"); - - // Act - var jobject = new JObject - { - { "Id", new JValue(1) }, - { "Name", new JValue("Test") } - }; - double match = matcher.IsMatch(jobject); - - // Assert - Assert.Equal(0.0, match); - } - - [Fact] - public void JsonMatcher_IsMatch_JObjectWithDateTimeOffsetAsString() - { - // Assign - var matcher = new JsonMatcher("{ \"preferredAt\" : \"2019-11-21T10:32:53.2210009+00:00\" }"); - - // Act - var jobject = new JObject - { - { "preferredAt", new JValue("2019-11-21T10:32:53.2210009+00:00") } - }; - double match = matcher.IsMatch(jobject); - - // Assert - Assert.Equal(1.0, match); - } + // Assert + match.Should().Be(1.0); } } \ No newline at end of file