From 69314be70bd113e1ba213babc89bcbfd9a5453e1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 9 Nov 2025 22:53:22 +0000 Subject: [PATCH 1/5] Initial plan From 7a58d42440b0b932cce6d75f5a76e2ef8d11910e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 9 Nov 2025 22:59:15 +0000 Subject: [PATCH 2/5] Add PropertyNamingSource enum to support proto field names Co-authored-by: Havret <9103861+Havret@users.noreply.github.com> --- .../JsonProtobufSerializerOptions.cs | 13 ++++- .../PropertyNamingSource.cs | 25 +++++++++ .../ProtobufConverter.cs | 27 +++++---- .../JsonNamingPolicyTests.cs | 56 +++++++++++++++++++ 4 files changed, 109 insertions(+), 12 deletions(-) create mode 100644 src/Protobuf.System.Text.Json/PropertyNamingSource.cs diff --git a/src/Protobuf.System.Text.Json/JsonProtobufSerializerOptions.cs b/src/Protobuf.System.Text.Json/JsonProtobufSerializerOptions.cs index 46095e7..3157367 100644 --- a/src/Protobuf.System.Text.Json/JsonProtobufSerializerOptions.cs +++ b/src/Protobuf.System.Text.Json/JsonProtobufSerializerOptions.cs @@ -12,7 +12,18 @@ public class JsonProtobufSerializerOptions /// option in the .proto file. /// The default value is false. /// - public bool UseProtobufJsonNames { get; set; } + [Obsolete("Use PropertyNamingSource instead. This property will be removed in a future version.")] + public bool UseProtobufJsonNames + { + get => PropertyNamingSource == PropertyNamingSource.ProtobufJsonName; + set => PropertyNamingSource = value ? PropertyNamingSource.ProtobufJsonName : PropertyNamingSource.Default; + } + + /// + /// Specifies the source for property names in JSON serialization. + /// The default value is . + /// + public PropertyNamingSource PropertyNamingSource { get; set; } = PropertyNamingSource.Default; /// /// Controls how fields are handled. diff --git a/src/Protobuf.System.Text.Json/PropertyNamingSource.cs b/src/Protobuf.System.Text.Json/PropertyNamingSource.cs new file mode 100644 index 0000000..8b14e76 --- /dev/null +++ b/src/Protobuf.System.Text.Json/PropertyNamingSource.cs @@ -0,0 +1,25 @@ +namespace Protobuf.System.Text.Json; + +/// +/// Specifies the source for property names in JSON serialization. +/// +public enum PropertyNamingSource +{ + /// + /// Use the default PropertyNamingPolicy from JsonSerializerOptions. + /// + Default = 0, + + /// + /// Use the JsonName from the protobuf contract. + /// This is usually the lower-camel-cased form of the field name, + /// but can be overridden using the json_name option in the .proto file. + /// + ProtobufJsonName = 1, + + /// + /// Use the original field name as defined in the .proto file. + /// For example, "double_property" instead of "doubleProperty". + /// + ProtobufFieldName = 2 +} diff --git a/src/Protobuf.System.Text.Json/ProtobufConverter.cs b/src/Protobuf.System.Text.Json/ProtobufConverter.cs index 8e0986a..569a7ab 100644 --- a/src/Protobuf.System.Text.Json/ProtobufConverter.cs +++ b/src/Protobuf.System.Text.Json/ProtobufConverter.cs @@ -24,7 +24,7 @@ public ProtobufConverter(JsonSerializerOptions jsonSerializerOptions, JsonProtob var propertyInfo = type.GetProperty("Descriptor", BindingFlags.Public | BindingFlags.Static); var messageDescriptor = (MessageDescriptor) propertyInfo?.GetValue(null, null)!; - var convertNameFunc = GetConvertNameFunc(jsonSerializerOptions.PropertyNamingPolicy, jsonProtobufSerializerOptions.UseProtobufJsonNames); + var convertNameFunc = GetConvertNameFunc(jsonSerializerOptions.PropertyNamingPolicy, jsonProtobufSerializerOptions.PropertyNamingSource); _fields = messageDescriptor.Fields.InDeclarationOrder().Select(fieldDescriptor => { @@ -49,19 +49,24 @@ public ProtobufConverter(JsonSerializerOptions jsonSerializerOptions, JsonProtob _fieldsLookup = _fields.ToDictionary(x => x.JsonName, x => x, stringComparer); } - private static Func GetConvertNameFunc(JsonNamingPolicy? jsonNamingPolicy, bool useProtobufJsonNames) + private static Func GetConvertNameFunc(JsonNamingPolicy? jsonNamingPolicy, PropertyNamingSource propertyNamingSource) { - if (useProtobufJsonNames) + switch (propertyNamingSource) { - return descriptor => descriptor.JsonName; - } - - if (jsonNamingPolicy != null) - { - return descriptor => jsonNamingPolicy.ConvertName(descriptor.PropertyName); + case PropertyNamingSource.ProtobufJsonName: + return descriptor => descriptor.JsonName; + + case PropertyNamingSource.ProtobufFieldName: + return descriptor => descriptor.Name; + + case PropertyNamingSource.Default: + default: + if (jsonNamingPolicy != null) + { + return descriptor => jsonNamingPolicy.ConvertName(descriptor.PropertyName); + } + return descriptor => descriptor.PropertyName; } - - return descriptor => descriptor.PropertyName; } public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) diff --git a/test/Protobuf.System.Text.Json.Tests/JsonNamingPolicyTests.cs b/test/Protobuf.System.Text.Json.Tests/JsonNamingPolicyTests.cs index 0d01dcf..0ba16fc 100644 --- a/test/Protobuf.System.Text.Json.Tests/JsonNamingPolicyTests.cs +++ b/test/Protobuf.System.Text.Json.Tests/JsonNamingPolicyTests.cs @@ -37,7 +37,9 @@ public void Should_ignore_PropertyNamingPolicy_when_UseProtobufJsonNames_set_to_ }; var jsonSerializerOptions = new JsonSerializerOptions(); jsonSerializerOptions.PropertyNamingPolicy = new JsonLowerCaseNamingPolicy(); +#pragma warning disable CS0618 // Type or member is obsolete jsonSerializerOptions.AddProtobufSupport(options => options.UseProtobufJsonNames = true); +#pragma warning restore CS0618 // Type or member is obsolete // Act var serialized = JsonSerializer.Serialize(msg, jsonSerializerOptions); @@ -47,6 +49,60 @@ public void Should_ignore_PropertyNamingPolicy_when_UseProtobufJsonNames_set_to_ approver.VerifyJson(serialized); } + [Fact] + public void Should_use_protobuf_json_name_when_PropertyNamingSource_set_to_ProtobufJsonName() + { + // Arrange + var msg = new SimpleMessage + { + DoubleProperty = 2.5d + }; + var jsonSerializerOptions = new JsonSerializerOptions(); + jsonSerializerOptions.PropertyNamingPolicy = new JsonLowerCaseNamingPolicy(); + jsonSerializerOptions.AddProtobufSupport(options => options.PropertyNamingSource = PropertyNamingSource.ProtobufJsonName); + + // Act + var serialized = JsonSerializer.Serialize(msg, jsonSerializerOptions); + + // Assert + Assert.Contains("\"doubleProperty\"", serialized); + } + + [Fact] + public void Should_use_protobuf_field_name_when_PropertyNamingSource_set_to_ProtobufFieldName() + { + // Arrange + var msg = new SimpleMessage + { + DoubleProperty = 2.5d + }; + var jsonSerializerOptions = new JsonSerializerOptions(); + jsonSerializerOptions.PropertyNamingPolicy = new JsonLowerCaseNamingPolicy(); + jsonSerializerOptions.AddProtobufSupport(options => options.PropertyNamingSource = PropertyNamingSource.ProtobufFieldName); + + // Act + var serialized = JsonSerializer.Serialize(msg, jsonSerializerOptions); + + // Assert + Assert.Contains("\"double_property\"", serialized); + } + + [Fact] + public void Should_deserialize_using_protobuf_field_name_when_PropertyNamingSource_set_to_ProtobufFieldName() + { + // Arrange + var json = "{\"double_property\": 2.5}"; + var jsonSerializerOptions = new JsonSerializerOptions(); + jsonSerializerOptions.AddProtobufSupport(options => options.PropertyNamingSource = PropertyNamingSource.ProtobufFieldName); + + // Act + var deserialized = JsonSerializer.Deserialize(json, jsonSerializerOptions); + + // Assert + Assert.NotNull(deserialized); + Assert.Equal(2.5d, deserialized.DoubleProperty); + } + private class JsonLowerCaseNamingPolicy : JsonNamingPolicy { public override string ConvertName(string name) From 8614e6b7bbd6b934c1e5b7791f877a3f7e2e7db3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 9 Nov 2025 23:00:35 +0000 Subject: [PATCH 3/5] Add comprehensive tests for PropertyNamingSource with custom json_name Co-authored-by: Havret <9103861+Havret@users.noreply.github.com> --- .../PropertyNamingSourceTests.cs | 109 ++++++++++++++++++ .../message_with_custom_json_name.proto | 9 ++ 2 files changed, 118 insertions(+) create mode 100644 test/Protobuf.System.Text.Json.Tests/PropertyNamingSourceTests.cs create mode 100644 test/Protobuf.System.Text.Json.Tests/Protos/message_with_custom_json_name.proto diff --git a/test/Protobuf.System.Text.Json.Tests/PropertyNamingSourceTests.cs b/test/Protobuf.System.Text.Json.Tests/PropertyNamingSourceTests.cs new file mode 100644 index 0000000..969d80d --- /dev/null +++ b/test/Protobuf.System.Text.Json.Tests/PropertyNamingSourceTests.cs @@ -0,0 +1,109 @@ +using System.Text.Json; +using System.Text.Json.Protobuf.Tests; +using Xunit; + +namespace Protobuf.System.Text.Json.Tests; + +public class PropertyNamingSourceTests +{ + [Fact] + public void Should_use_custom_json_name_when_PropertyNamingSource_is_ProtobufJsonName() + { + // Arrange + var msg = new MessageWithCustomJsonName + { + DoubleProperty = 2.5d, + StringProperty = "test" + }; + var jsonSerializerOptions = new JsonSerializerOptions(); + jsonSerializerOptions.AddProtobufSupport(options => options.PropertyNamingSource = PropertyNamingSource.ProtobufJsonName); + + // Act + var serialized = JsonSerializer.Serialize(msg, jsonSerializerOptions); + + // Assert + // double_property has json_name = "customDoubleProperty" + Assert.Contains("\"customDoubleProperty\"", serialized); + // string_property doesn't have json_name, so it should be camelCased to "stringProperty" + Assert.Contains("\"stringProperty\"", serialized); + } + + [Fact] + public void Should_use_proto_field_name_when_PropertyNamingSource_is_ProtobufFieldName() + { + // Arrange + var msg = new MessageWithCustomJsonName + { + DoubleProperty = 2.5d, + StringProperty = "test" + }; + var jsonSerializerOptions = new JsonSerializerOptions(); + jsonSerializerOptions.AddProtobufSupport(options => options.PropertyNamingSource = PropertyNamingSource.ProtobufFieldName); + + // Act + var serialized = JsonSerializer.Serialize(msg, jsonSerializerOptions); + + // Assert + // Both fields should use their original proto field names + Assert.Contains("\"double_property\"", serialized); + Assert.Contains("\"string_property\"", serialized); + // Should NOT use the custom json_name + Assert.DoesNotContain("\"customDoubleProperty\"", serialized); + } + + [Fact] + public void Should_deserialize_using_custom_json_name_when_PropertyNamingSource_is_ProtobufJsonName() + { + // Arrange + var json = "{\"customDoubleProperty\": 2.5, \"stringProperty\": \"test\"}"; + var jsonSerializerOptions = new JsonSerializerOptions(); + jsonSerializerOptions.AddProtobufSupport(options => options.PropertyNamingSource = PropertyNamingSource.ProtobufJsonName); + + // Act + var deserialized = JsonSerializer.Deserialize(json, jsonSerializerOptions); + + // Assert + Assert.NotNull(deserialized); + Assert.Equal(2.5d, deserialized.DoubleProperty); + Assert.Equal("test", deserialized.StringProperty); + } + + [Fact] + public void Should_deserialize_using_proto_field_name_when_PropertyNamingSource_is_ProtobufFieldName() + { + // Arrange + var json = "{\"double_property\": 2.5, \"string_property\": \"test\"}"; + var jsonSerializerOptions = new JsonSerializerOptions(); + jsonSerializerOptions.AddProtobufSupport(options => options.PropertyNamingSource = PropertyNamingSource.ProtobufFieldName); + + // Act + var deserialized = JsonSerializer.Deserialize(json, jsonSerializerOptions); + + // Assert + Assert.NotNull(deserialized); + Assert.Equal(2.5d, deserialized.DoubleProperty); + Assert.Equal("test", deserialized.StringProperty); + } + + [Fact] + public void Should_round_trip_with_ProtobufFieldName() + { + // Arrange + var original = new MessageWithCustomJsonName + { + DoubleProperty = 2.5d, + StringProperty = "test" + }; + var jsonSerializerOptions = new JsonSerializerOptions(); + jsonSerializerOptions.AddProtobufSupport(options => options.PropertyNamingSource = PropertyNamingSource.ProtobufFieldName); + + // Act + var serialized = JsonSerializer.Serialize(original, jsonSerializerOptions); + var deserialized = JsonSerializer.Deserialize(serialized, jsonSerializerOptions); + + // Assert + Assert.NotNull(deserialized); + Assert.Equal(original.DoubleProperty, deserialized.DoubleProperty); + Assert.Equal(original.StringProperty, deserialized.StringProperty); + } +} diff --git a/test/Protobuf.System.Text.Json.Tests/Protos/message_with_custom_json_name.proto b/test/Protobuf.System.Text.Json.Tests/Protos/message_with_custom_json_name.proto new file mode 100644 index 0000000..eb57a38 --- /dev/null +++ b/test/Protobuf.System.Text.Json.Tests/Protos/message_with_custom_json_name.proto @@ -0,0 +1,9 @@ +syntax = "proto3"; + +option csharp_namespace = "System.Text.Json.Protobuf.Tests"; + +message MessageWithCustomJsonName { + double double_property = 1 [json_name = "customDoubleProperty"]; + + string string_property = 2; +} From b293a71061fb44208a3c675760f087d20e627b8e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 9 Nov 2025 23:01:05 +0000 Subject: [PATCH 4/5] Update README with PropertyNamingSource documentation Co-authored-by: Havret <9103861+Havret@users.noreply.github.com> --- README.md | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 380525a..d48c0f8 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,26 @@ var deserialized = JsonSerializer.Deserialize(payload, jsonSerial ## Configuration The library offers several configuration options to fine-tune protobuf serialization. You can modify the default settings using a delegate passed to the AddProtobufSupport method. The available options are described below: -### UseProtobufJsonNames +### PropertyNamingSource +This option specifies the source for property names in JSON serialization. The default value is `PropertyNamingSource.Default`. + +Available values: +- `PropertyNamingSource.Default`: Use the default `PropertyNamingPolicy` from `JsonSerializerOptions`. +- `PropertyNamingSource.ProtobufJsonName`: Use the JsonName from the protobuf contract. This is usually the lower-camel-cased form of the field name, but can be overridden using the `json_name` option in the .proto file. +- `PropertyNamingSource.ProtobufFieldName`: Use the original field name as defined in the .proto file (e.g., "double_property" instead of "doubleProperty"). + +Example: +```csharp +var jsonSerializerOptions = new JsonSerializerOptions(); +jsonSerializerOptions.AddProtobufSupport(options => +{ + options.PropertyNamingSource = PropertyNamingSource.ProtobufFieldName; +}); +``` + +### UseProtobufJsonNames (Obsolete) +**Note:** This property is obsolete and will be removed in a future version. Use `PropertyNamingSource` instead. + This option defines how property names should be resolved for protobuf contracts. When set to `true`, the `PropertyNamingPolicy` will be ignored, and property names will be derived from the protobuf contract. The default value is `false`. ### TreatDurationAsTimeSpan From 065b2e92d08fbeed3b6310f51a23094e7dab5041 Mon Sep 17 00:00:00 2001 From: Havret Date: Mon, 10 Nov 2025 00:10:32 +0100 Subject: [PATCH 5/5] Improve tests --- ...ource_set_to_ProtobufFieldName.approved.json | 17 +++++++++++++++++ ...Source_set_to_ProtobufJsonName.approved.json | 17 +++++++++++++++++ .../JsonNamingPolicyTests.cs | 6 ++++-- ...mingSource_is_ProtobufJsonName.approved.json | 4 ++++ ...ingSource_is_ProtobufFieldName.approved.json | 4 ++++ .../PropertyNamingSourceTests.cs | 14 +++++--------- 6 files changed, 51 insertions(+), 11 deletions(-) create mode 100644 test/Protobuf.System.Text.Json.Tests/JsonNamingPolicyTests.Should_use_protobuf_field_name_when_PropertyNamingSource_set_to_ProtobufFieldName.approved.json create mode 100644 test/Protobuf.System.Text.Json.Tests/JsonNamingPolicyTests.Should_use_protobuf_json_name_when_PropertyNamingSource_set_to_ProtobufJsonName.approved.json create mode 100644 test/Protobuf.System.Text.Json.Tests/PropertyNamingSourceTests.Should_use_custom_json_name_when_PropertyNamingSource_is_ProtobufJsonName.approved.json create mode 100644 test/Protobuf.System.Text.Json.Tests/PropertyNamingSourceTests.Should_use_proto_field_name_when_PropertyNamingSource_is_ProtobufFieldName.approved.json diff --git a/test/Protobuf.System.Text.Json.Tests/JsonNamingPolicyTests.Should_use_protobuf_field_name_when_PropertyNamingSource_set_to_ProtobufFieldName.approved.json b/test/Protobuf.System.Text.Json.Tests/JsonNamingPolicyTests.Should_use_protobuf_field_name_when_PropertyNamingSource_set_to_ProtobufFieldName.approved.json new file mode 100644 index 0000000..712f9d9 --- /dev/null +++ b/test/Protobuf.System.Text.Json.Tests/JsonNamingPolicyTests.Should_use_protobuf_field_name_when_PropertyNamingSource_set_to_ProtobufFieldName.approved.json @@ -0,0 +1,17 @@ +{ + "double_property": 2.5, + "float_property": 0, + "int_32_property": 0, + "int_64_property": 0, + "uint_32_property": 0, + "uint_64_property": 0, + "sint_32_property": 0, + "sint_64_property": 0, + "fixed_32_property": 0, + "fixed_64_property": 0, + "sfixed_32_property": 0, + "sfixed_64_property": 0, + "bool_property": false, + "string_property": "", + "bytes_property": "" +} \ No newline at end of file diff --git a/test/Protobuf.System.Text.Json.Tests/JsonNamingPolicyTests.Should_use_protobuf_json_name_when_PropertyNamingSource_set_to_ProtobufJsonName.approved.json b/test/Protobuf.System.Text.Json.Tests/JsonNamingPolicyTests.Should_use_protobuf_json_name_when_PropertyNamingSource_set_to_ProtobufJsonName.approved.json new file mode 100644 index 0000000..1283b7d --- /dev/null +++ b/test/Protobuf.System.Text.Json.Tests/JsonNamingPolicyTests.Should_use_protobuf_json_name_when_PropertyNamingSource_set_to_ProtobufJsonName.approved.json @@ -0,0 +1,17 @@ +{ + "doubleProperty": 2.5, + "floatProperty": 0, + "int32Property": 0, + "int64Property": 0, + "uint32Property": 0, + "uint64Property": 0, + "sint32Property": 0, + "sint64Property": 0, + "fixed32Property": 0, + "fixed64Property": 0, + "sfixed32Property": 0, + "sfixed64Property": 0, + "boolProperty": false, + "stringProperty": "", + "bytesProperty": "" +} \ No newline at end of file diff --git a/test/Protobuf.System.Text.Json.Tests/JsonNamingPolicyTests.cs b/test/Protobuf.System.Text.Json.Tests/JsonNamingPolicyTests.cs index 0ba16fc..a73aab9 100644 --- a/test/Protobuf.System.Text.Json.Tests/JsonNamingPolicyTests.cs +++ b/test/Protobuf.System.Text.Json.Tests/JsonNamingPolicyTests.cs @@ -65,7 +65,8 @@ public void Should_use_protobuf_json_name_when_PropertyNamingSource_set_to_Proto var serialized = JsonSerializer.Serialize(msg, jsonSerializerOptions); // Assert - Assert.Contains("\"doubleProperty\"", serialized); + var approver = new ExplicitApprover(); + approver.VerifyJson(serialized); } [Fact] @@ -84,7 +85,8 @@ public void Should_use_protobuf_field_name_when_PropertyNamingSource_set_to_Prot var serialized = JsonSerializer.Serialize(msg, jsonSerializerOptions); // Assert - Assert.Contains("\"double_property\"", serialized); + var approver = new ExplicitApprover(); + approver.VerifyJson(serialized); } [Fact] diff --git a/test/Protobuf.System.Text.Json.Tests/PropertyNamingSourceTests.Should_use_custom_json_name_when_PropertyNamingSource_is_ProtobufJsonName.approved.json b/test/Protobuf.System.Text.Json.Tests/PropertyNamingSourceTests.Should_use_custom_json_name_when_PropertyNamingSource_is_ProtobufJsonName.approved.json new file mode 100644 index 0000000..bfbb690 --- /dev/null +++ b/test/Protobuf.System.Text.Json.Tests/PropertyNamingSourceTests.Should_use_custom_json_name_when_PropertyNamingSource_is_ProtobufJsonName.approved.json @@ -0,0 +1,4 @@ +{ + "customDoubleProperty": 2.5, + "stringProperty": "test" +} \ No newline at end of file diff --git a/test/Protobuf.System.Text.Json.Tests/PropertyNamingSourceTests.Should_use_proto_field_name_when_PropertyNamingSource_is_ProtobufFieldName.approved.json b/test/Protobuf.System.Text.Json.Tests/PropertyNamingSourceTests.Should_use_proto_field_name_when_PropertyNamingSource_is_ProtobufFieldName.approved.json new file mode 100644 index 0000000..e0d28fc --- /dev/null +++ b/test/Protobuf.System.Text.Json.Tests/PropertyNamingSourceTests.Should_use_proto_field_name_when_PropertyNamingSource_is_ProtobufFieldName.approved.json @@ -0,0 +1,4 @@ +{ + "double_property": 2.5, + "string_property": "test" +} \ No newline at end of file diff --git a/test/Protobuf.System.Text.Json.Tests/PropertyNamingSourceTests.cs b/test/Protobuf.System.Text.Json.Tests/PropertyNamingSourceTests.cs index 969d80d..0db3dc9 100644 --- a/test/Protobuf.System.Text.Json.Tests/PropertyNamingSourceTests.cs +++ b/test/Protobuf.System.Text.Json.Tests/PropertyNamingSourceTests.cs @@ -1,5 +1,6 @@ using System.Text.Json; using System.Text.Json.Protobuf.Tests; +using SmartAnalyzers.ApprovalTestsExtensions; using Xunit; namespace Protobuf.System.Text.Json.Tests; @@ -22,10 +23,8 @@ public void Should_use_custom_json_name_when_PropertyNamingSource_is_ProtobufJso var serialized = JsonSerializer.Serialize(msg, jsonSerializerOptions); // Assert - // double_property has json_name = "customDoubleProperty" - Assert.Contains("\"customDoubleProperty\"", serialized); - // string_property doesn't have json_name, so it should be camelCased to "stringProperty" - Assert.Contains("\"stringProperty\"", serialized); + var approver = new ExplicitApprover(); + approver.VerifyJson(serialized); } [Fact] @@ -44,11 +43,8 @@ public void Should_use_proto_field_name_when_PropertyNamingSource_is_ProtobufFie var serialized = JsonSerializer.Serialize(msg, jsonSerializerOptions); // Assert - // Both fields should use their original proto field names - Assert.Contains("\"double_property\"", serialized); - Assert.Contains("\"string_property\"", serialized); - // Should NOT use the custom json_name - Assert.DoesNotContain("\"customDoubleProperty\"", serialized); + var approver = new ExplicitApprover(); + approver.VerifyJson(serialized); } [Fact]