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