diff --git a/docs/dates.md b/docs/dates.md index 1e9d1a244..ecc3e834a 100644 --- a/docs/dates.md +++ b/docs/dates.md @@ -29,7 +29,7 @@ var target = new DateTimeTarget await Verify(target); ``` -snippet source | anchor +snippet source | anchor Results in the following: @@ -70,7 +70,7 @@ settings.DontScrubDateTimes(); return Verify(target, settings); ``` -snippet source | anchor +snippet source | anchor @@ -87,7 +87,7 @@ var target = new return Verify(target) .DontScrubDateTimes(); ``` -snippet source | anchor +snippet source | anchor @@ -100,7 +100,7 @@ return Verify(target) public static void ModuleInitializer() => VerifierSettings.DontScrubDateTimes(); ``` -snippet source | anchor +snippet source | anchor @@ -124,7 +124,7 @@ settings.DisableDateCounting(); return Verify(target, settings); ``` -snippet source | anchor +snippet source | anchor @@ -141,7 +141,7 @@ var target = new return Verify(target) .DisableDateCounting(); ``` -snippet source | anchor +snippet source | anchor @@ -154,7 +154,7 @@ return Verify(target) public static void ModuleInitializer() => VerifierSettings.DisableDateCounting(); ``` -snippet source | anchor +snippet source | anchor @@ -201,7 +201,7 @@ public Task ScrubInlineDateTimesInstance() settings); } ``` -snippet source | anchor +snippet source | anchor @@ -215,7 +215,7 @@ public Task ScrubInlineDateTimesFluent() => Verify("content 2020-10-20 content") .ScrubInlineDateTimes("yyyy-MM-dd"); ``` -snippet source | anchor +snippet source | anchor @@ -231,7 +231,7 @@ public static class ModuleInitializer VerifierSettings.ScrubInlineDateTimes("yyyy-MM-dd"); } ``` -snippet source | anchor +snippet source | anchor @@ -252,7 +252,7 @@ settings.AddNamedDateTime(new(2030, 1, 2), "instanceNamedDateTime"); settings.AddNamedDateTimeOffset(new DateTime(2030, 1, 2), "instanceNamedTimeOffset"); await Verify(target, settings); ``` -snippet source | anchor +snippet source | anchor @@ -267,7 +267,7 @@ await Verify(target) .AddNamedDateTime(new(2030, 1, 2), "instanceNamedDateTime") .AddNamedDateTimeOffset(new DateTime(2030, 1, 2), "instanceNamedTimeOffset"); ``` -snippet source | anchor +snippet source | anchor @@ -285,7 +285,7 @@ public static void NamedDatesAndTimesGlobal() VerifierSettings.AddNamedDateTimeOffset(new(new(2030, 1, 1)), "namedDateTimeOffset"); } ``` -snippet source | anchor +snippet source | anchor diff --git a/docs/guids.md b/docs/guids.md index 7d4f45e84..2ca00fa83 100644 --- a/docs/guids.md +++ b/docs/guids.md @@ -23,7 +23,7 @@ var target = new GuidTarget await Verify(target); ``` -snippet source | anchor +snippet source | anchor Results in the following: @@ -79,7 +79,7 @@ await Verify(target) ```cs VerifierSettings.DontScrubGuids(); ``` -snippet source | anchor +snippet source | anchor @@ -103,7 +103,7 @@ public Task ScrubInlineGuidsInstance() settings); } ``` -snippet source | anchor +snippet source | anchor @@ -117,7 +117,7 @@ public Task ScrubInlineGuidsFluent() => Verify("content 651ad409-fc30-4b12-a47e-616d3f953e4c content") .ScrubInlineGuids(); ``` -snippet source | anchor +snippet source | anchor @@ -133,7 +133,7 @@ public static class ModuleInitializer VerifierSettings.ScrubInlineGuids(); } ``` -snippet source | anchor +snippet source | anchor diff --git a/docs/named-tuples.md b/docs/named-tuples.md index 151cc9822..8f2da6526 100644 --- a/docs/named-tuples.md +++ b/docs/named-tuples.md @@ -19,7 +19,7 @@ Given a method that returns a named tuple: static (bool Member1, string Member2, string Member3) MethodWithNamedTuple() => (true, "A", "B"); ``` -snippet source | anchor +snippet source | anchor Can be verified: @@ -29,7 +29,7 @@ Can be verified: ```cs await VerifyTuple(() => MethodWithNamedTuple()); ``` -snippet source | anchor +snippet source | anchor Resulting in: diff --git a/docs/scrubbers.md b/docs/scrubbers.md index 6458f9e2f..790a9799f 100644 --- a/docs/scrubbers.md +++ b/docs/scrubbers.md @@ -59,7 +59,7 @@ For example remove lines containing `text`: ```cs verifySettings.ScrubLines(line => line.Contains("text")); ``` -snippet source | anchor +snippet source | anchor @@ -74,7 +74,7 @@ For example remove lines containing `text1` or `text2` ```cs verifySettings.ScrubLinesContaining("text1", "text2"); ``` -snippet source | anchor +snippet source | anchor Case insensitive by default (StringComparison.OrdinalIgnoreCase). @@ -86,7 +86,7 @@ Case insensitive by default (StringComparison.OrdinalIgnoreCase). ```cs verifySettings.ScrubLinesContaining(StringComparison.Ordinal, "text1", "text2"); ``` -snippet source | anchor +snippet source | anchor @@ -101,7 +101,7 @@ For example converts lines to upper case: ```cs verifySettings.ScrubLinesWithReplace(line => line.ToUpper()); ``` -snippet source | anchor +snippet source | anchor @@ -114,7 +114,7 @@ Replaces `Environment.MachineName` with `TheMachineName`. ```cs verifySettings.ScrubMachineName(); ``` -snippet source | anchor +snippet source | anchor @@ -127,7 +127,7 @@ Replaces `Environment.UserName` with `TheUserName`. ```cs verifySettings.ScrubUserName(); ``` -snippet source | anchor +snippet source | anchor diff --git a/docs/serializer-settings.md b/docs/serializer-settings.md index c8baaa757..df99f2775 100644 --- a/docs/serializer-settings.md +++ b/docs/serializer-settings.md @@ -246,7 +246,7 @@ To disable this behavior globally use: ```cs VerifierSettings.DontIgnoreEmptyCollections(); ``` -snippet source | anchor +snippet source | anchor @@ -347,7 +347,7 @@ public Task ScopedSerializerFluent() .AddExtraSettings(_ => _.TypeNameHandling = TypeNameHandling.All); } ``` -snippet source | anchor +snippet source | anchor Result: @@ -475,7 +475,7 @@ public Task IgnoreTypeFluent() .IgnoreMembersWithType(); } ``` -snippet source | anchor +snippet source | anchor Or globally: @@ -485,7 +485,7 @@ Or globally: ```cs VerifierSettings.IgnoreMembersWithType(); ``` -snippet source | anchor +snippet source | anchor Result: @@ -622,7 +622,7 @@ public Task ScrubTypeFluent() .ScrubMembersWithType(); } ``` -snippet source | anchor +snippet source | anchor Or globally: @@ -632,7 +632,7 @@ Or globally: ```cs VerifierSettings.ScrubMembersWithType(); ``` -snippet source | anchor +snippet source | anchor Result: @@ -711,7 +711,7 @@ public Task AddIgnoreInstanceFluent() .IgnoreInstance(_ => _.Property == "Ignore"); } ``` -snippet source | anchor +snippet source | anchor Or globally: @@ -721,7 +721,7 @@ Or globally: ```cs VerifierSettings.IgnoreInstance(_ => _.Property == "Ignore"); ``` -snippet source | anchor +snippet source | anchor Result: @@ -783,7 +783,7 @@ public Task AddScrubInstanceFluent() .ScrubInstance(_ => _.Property == "Ignore"); } ``` -snippet source | anchor +snippet source | anchor Or globally: @@ -793,7 +793,7 @@ Or globally: ```cs VerifierSettings.ScrubInstance(_ => _.Property == "Ignore"); ``` -snippet source | anchor +snippet source | anchor Result: @@ -838,7 +838,7 @@ public Task WithObsoleteProp() return Verify(target); } ``` -snippet source | anchor +snippet source | anchor Result: @@ -886,7 +886,7 @@ public Task WithObsoletePropIncludedFluent() .IncludeObsoletes(); } ``` -snippet source | anchor +snippet source | anchor Or globally: @@ -896,7 +896,7 @@ Or globally: ```cs VerifierSettings.IncludeObsoletes(); ``` -snippet source | anchor +snippet source | anchor Result: @@ -957,7 +957,7 @@ public Task IgnoreMemberByExpressionFluent() _ => _.PropertyThatThrows); } ``` -snippet source | anchor +snippet source | anchor Or globally @@ -972,7 +972,7 @@ VerifierSettings.IgnoreMembers( _ => _.GetOnlyProperty, _ => _.PropertyThatThrows); ``` -snippet source | anchor +snippet source | anchor Result: @@ -1032,7 +1032,7 @@ public Task ScrubMemberByExpressionFluent() _ => _.PropertyThatThrows); } ``` -snippet source | anchor +snippet source | anchor Or globally @@ -1047,7 +1047,7 @@ VerifierSettings.ScrubMembers( _ => _.GetOnlyProperty, _ => _.PropertyThatThrows); ``` -snippet source | anchor +snippet source | anchor Result: @@ -1126,7 +1126,7 @@ public Task IgnoreMemberByNameFluent() .IgnoreMember(_ => _.PropertyThatThrows); } ``` -snippet source | anchor +snippet source | anchor Or globally: @@ -1146,7 +1146,7 @@ VerifierSettings.IgnoreMember("Field"); // For a specific type with expression VerifierSettings.IgnoreMember(_ => _.PropertyThatThrows); ``` -snippet source | anchor +snippet source | anchor Result: @@ -1221,7 +1221,7 @@ public Task ScrubMemberByNameFluent() .ScrubMember(_ => _.PropertyThatThrows); } ``` -snippet source | anchor +snippet source | anchor Or globally: @@ -1241,7 +1241,7 @@ VerifierSettings.ScrubMember("Field"); // For a specific type with expression VerifierSettings.ScrubMember(_ => _.PropertyThatThrows); ``` -snippet source | anchor +snippet source | anchor Result: @@ -1292,7 +1292,7 @@ public Task CustomExceptionPropFluent() .IgnoreMembersThatThrow(); } ``` -snippet source | anchor +snippet source | anchor Or globally: @@ -1302,7 +1302,7 @@ Or globally: ```cs VerifierSettings.IgnoreMembersThatThrow(); ``` -snippet source | anchor +snippet source | anchor Result: @@ -1339,7 +1339,7 @@ public Task ExceptionMessagePropFluent() .IgnoreMembersThatThrow(_ => _.Message == "Ignore"); } ``` -snippet source | anchor +snippet source | anchor Or globally: @@ -1349,7 +1349,7 @@ Or globally: ```cs VerifierSettings.IgnoreMembersThatThrow(_ => _.Message == "Ignore"); ``` -snippet source | anchor +snippet source | anchor Result: @@ -1507,7 +1507,7 @@ public Task MemberConverterByExpression() return Verify(input); } ``` -snippet source | anchor +snippet source | anchor diff --git a/src/Directory.Build.props b/src/Directory.Build.props index c15b71cb9..fdda4e9df 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -2,7 +2,7 @@ CS1591;CS0649;xUnit1026;xUnit1013;CS1573;VerifyTestsProjectDir;VerifySetParameters;PolyFillTargetsForNuget - 28.2.0 + 28.2.1 enable preview 1.0.0 diff --git a/src/StrictJsonTests/SerializationTests.NullProperty.verified.json b/src/StrictJsonTests/SerializationTests.NullProperty.verified.json new file mode 100644 index 000000000..cca15c585 --- /dev/null +++ b/src/StrictJsonTests/SerializationTests.NullProperty.verified.json @@ -0,0 +1,3 @@ +{ + "property": "value1" +} \ No newline at end of file diff --git a/src/StrictJsonTests/SerializationTests.NullPropertyInclude.verified.json b/src/StrictJsonTests/SerializationTests.NullPropertyInclude.verified.json new file mode 100644 index 000000000..be84441d7 --- /dev/null +++ b/src/StrictJsonTests/SerializationTests.NullPropertyInclude.verified.json @@ -0,0 +1,3 @@ +{ + "nullProperty": null +} \ No newline at end of file diff --git a/src/StrictJsonTests/SerializationTests.WithWriteMemberNull.verified.json b/src/StrictJsonTests/SerializationTests.WithWriteMemberNull.verified.json new file mode 100644 index 000000000..22fdca1b2 --- /dev/null +++ b/src/StrictJsonTests/SerializationTests.WithWriteMemberNull.verified.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/src/StrictJsonTests/SerializationTests.WithWriteMemberNullIgnored.verified.json b/src/StrictJsonTests/SerializationTests.WithWriteMemberNullIgnored.verified.json new file mode 100644 index 000000000..22fdca1b2 --- /dev/null +++ b/src/StrictJsonTests/SerializationTests.WithWriteMemberNullIgnored.verified.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/src/StrictJsonTests/SerializationTests.WithWriteMemberNullIgnored_Include.verified.json b/src/StrictJsonTests/SerializationTests.WithWriteMemberNullIgnored_Include.verified.json new file mode 100644 index 000000000..22fdca1b2 --- /dev/null +++ b/src/StrictJsonTests/SerializationTests.WithWriteMemberNullIgnored_Include.verified.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/src/StrictJsonTests/SerializationTests.WithWriteMemberNullScrubbed.verified.json b/src/StrictJsonTests/SerializationTests.WithWriteMemberNullScrubbed.verified.json new file mode 100644 index 000000000..4f1ebe02f --- /dev/null +++ b/src/StrictJsonTests/SerializationTests.WithWriteMemberNullScrubbed.verified.json @@ -0,0 +1,3 @@ +{ + "Name": "Scrubbed" +} \ No newline at end of file diff --git a/src/StrictJsonTests/SerializationTests.WithWriteMemberNullScrubbed_Include.verified.json b/src/StrictJsonTests/SerializationTests.WithWriteMemberNullScrubbed_Include.verified.json new file mode 100644 index 000000000..4f1ebe02f --- /dev/null +++ b/src/StrictJsonTests/SerializationTests.WithWriteMemberNullScrubbed_Include.verified.json @@ -0,0 +1,3 @@ +{ + "Name": "Scrubbed" +} \ No newline at end of file diff --git a/src/StrictJsonTests/SerializationTests.WithWriteMemberNull_Include.verified.json b/src/StrictJsonTests/SerializationTests.WithWriteMemberNull_Include.verified.json new file mode 100644 index 000000000..6ae9aeee7 --- /dev/null +++ b/src/StrictJsonTests/SerializationTests.WithWriteMemberNull_Include.verified.json @@ -0,0 +1,3 @@ +{ + "Name": null +} \ No newline at end of file diff --git a/src/Verify.Tests/Serialization/SerializationTests.NullProperty.verified.txt b/src/Verify.Tests/Serialization/SerializationTests.NullProperty.verified.txt new file mode 100644 index 000000000..5e7849351 --- /dev/null +++ b/src/Verify.Tests/Serialization/SerializationTests.NullProperty.verified.txt @@ -0,0 +1,3 @@ +{ + property: value1 +} \ No newline at end of file diff --git a/src/Verify.Tests/Serialization/SerializationTests.NullPropertyInclude.verified.txt b/src/Verify.Tests/Serialization/SerializationTests.NullPropertyInclude.verified.txt new file mode 100644 index 000000000..7bafeb87a --- /dev/null +++ b/src/Verify.Tests/Serialization/SerializationTests.NullPropertyInclude.verified.txt @@ -0,0 +1,3 @@ +{ + nullProperty: null +} \ No newline at end of file diff --git a/src/Verify.Tests/Serialization/SerializationTests.WithWriteMemberNull.verified.txt b/src/Verify.Tests/Serialization/SerializationTests.WithWriteMemberNull.verified.txt new file mode 100644 index 000000000..22fdca1b2 --- /dev/null +++ b/src/Verify.Tests/Serialization/SerializationTests.WithWriteMemberNull.verified.txt @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/src/Verify.Tests/Serialization/SerializationTests.WithWriteMemberNullIgnored.verified.txt b/src/Verify.Tests/Serialization/SerializationTests.WithWriteMemberNullIgnored.verified.txt new file mode 100644 index 000000000..22fdca1b2 --- /dev/null +++ b/src/Verify.Tests/Serialization/SerializationTests.WithWriteMemberNullIgnored.verified.txt @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/src/Verify.Tests/Serialization/SerializationTests.WithWriteMemberNullIgnored_Include.verified.txt b/src/Verify.Tests/Serialization/SerializationTests.WithWriteMemberNullIgnored_Include.verified.txt new file mode 100644 index 000000000..22fdca1b2 --- /dev/null +++ b/src/Verify.Tests/Serialization/SerializationTests.WithWriteMemberNullIgnored_Include.verified.txt @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/src/Verify.Tests/Serialization/SerializationTests.WithWriteMemberNullScrubbed.verified.txt b/src/Verify.Tests/Serialization/SerializationTests.WithWriteMemberNullScrubbed.verified.txt new file mode 100644 index 000000000..536441ea1 --- /dev/null +++ b/src/Verify.Tests/Serialization/SerializationTests.WithWriteMemberNullScrubbed.verified.txt @@ -0,0 +1,3 @@ +{ + Name: Scrubbed +} \ No newline at end of file diff --git a/src/Verify.Tests/Serialization/SerializationTests.WithWriteMemberNullScrubbed_Include.verified.txt b/src/Verify.Tests/Serialization/SerializationTests.WithWriteMemberNullScrubbed_Include.verified.txt new file mode 100644 index 000000000..536441ea1 --- /dev/null +++ b/src/Verify.Tests/Serialization/SerializationTests.WithWriteMemberNullScrubbed_Include.verified.txt @@ -0,0 +1,3 @@ +{ + Name: Scrubbed +} \ No newline at end of file diff --git a/src/Verify.Tests/Serialization/SerializationTests.WithWriteMemberNull_Include.verified.txt b/src/Verify.Tests/Serialization/SerializationTests.WithWriteMemberNull_Include.verified.txt new file mode 100644 index 000000000..8975db01a --- /dev/null +++ b/src/Verify.Tests/Serialization/SerializationTests.WithWriteMemberNull_Include.verified.txt @@ -0,0 +1,3 @@ +{ + Name: null +} \ No newline at end of file diff --git a/src/Verify.Tests/Serialization/SerializationTests.cs b/src/Verify.Tests/Serialization/SerializationTests.cs index 3f36a5238..0ec53ed7e 100644 --- a/src/Verify.Tests/Serialization/SerializationTests.cs +++ b/src/Verify.Tests/Serialization/SerializationTests.cs @@ -921,6 +921,28 @@ public Task BoolDefault() return Verify(target); } + [Fact] + public Task NullProperty() => + Verify( + new + { + property ="value1", + nullProperty = (string?)null + }); + + [Fact] + public Task NullPropertyInclude() => + Verify( + new + { + nullProperty = (string?)null + }) + .AddExtraSettings(_=> + { + _.DefaultValueHandling = DefaultValueHandling.Include; + _.NullValueHandling = NullValueHandling.Include; + }); + [Fact] public Task BoolFalse() { @@ -3771,7 +3793,64 @@ public override void Write(VerifyJsonWriter writer, ConverterTarget target) } } - record ConverterTarget(string Name); + [Fact] + public Task WithWriteMemberNull() => + Verify(new ConverterTarget(null)) + .AddExtraSettings(_ => _.Converters.Add(new NullConverter())); + + [Fact] + public Task WithWriteMemberNull_Include() => + Verify(new ConverterTarget(null)) + .AddExtraSettings(_ => + { + _.Converters.Add(new NullConverter()); + _.NullValueHandling = NullValueHandling.Include; + }); + + [Fact] + public Task WithWriteMemberNullScrubbed() => + Verify(new ConverterTarget(null)) + .AddExtraSettings(_ => _.Converters.Add(new NullConverter())) + .ScrubMember("Name"); + + [Fact] + public Task WithWriteMemberNullScrubbed_Include() => + Verify(new ConverterTarget(null)) + .AddExtraSettings(_ => + { + _.Converters.Add(new NullConverter()); + _.NullValueHandling = NullValueHandling.Include; + }) + .ScrubMember("Name"); + + [Fact] + public Task WithWriteMemberNullIgnored() => + Verify(new ConverterTarget(null)) + .AddExtraSettings(_ => _.Converters.Add(new NullConverter())) + .IgnoreMember("Name"); + + [Fact] + public Task WithWriteMemberNullIgnored_Include() => + Verify(new ConverterTarget(null)) + .AddExtraSettings(_ => + { + _.Converters.Add(new NullConverter()); + _.NullValueHandling = NullValueHandling.Include; + }) + .IgnoreMember("Name"); + + class NullConverter : + WriteOnlyJsonConverter + { + public override void Write(VerifyJsonWriter writer, ConverterTarget target) + { + writer.WriteStartObject(); + writer.WriteMember(target, target.Name, "Name"); + writer.WriteEnd(); + } + } + + record ConverterTarget(string? Name); [Fact] public Task WithConverterIgnoreDefault() => diff --git a/src/Verify/Serialization/VerifyJsonWriter.cs b/src/Verify/Serialization/VerifyJsonWriter.cs index e03f0db18..5ba701abf 100644 --- a/src/Verify/Serialization/VerifyJsonWriter.cs +++ b/src/Verify/Serialization/VerifyJsonWriter.cs @@ -209,6 +209,26 @@ public void WriteMember(object target, object? value, string name) { if (value is null) { + if (serialization.TryGetScrubOrIgnoreByName(name, out var scrubOrIgnoreByName)) + { + if (scrubOrIgnoreByName == ScrubOrIgnore.Ignore) + { + return; + } + + WritePropertyName(name); + WriteRawValueIfNoStrict("Scrubbed"); + + return; + } + + if (serialization.Serializer.NullValueHandling.GetValueOrDefault(NullValueHandling.Ignore) == NullValueHandling.Ignore) + { + return; + } + + WritePropertyName(name); + WriteNull(); return; } diff --git a/src/global.json b/src/global.json index 745718c26..e69a6eefb 100644 --- a/src/global.json +++ b/src/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "9.0.100-rc.2.24474.11", + "version": "9.0.100", "allowPrerelease": true, "rollForward": "latestFeature" } diff --git a/usages/global.json b/usages/global.json index 745718c26..e69a6eefb 100644 --- a/usages/global.json +++ b/usages/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "9.0.100-rc.2.24474.11", + "version": "9.0.100", "allowPrerelease": true, "rollForward": "latestFeature" }