diff --git a/docs/named-tuples.md b/docs/named-tuples.md index 3baafada80..830c6a92c3 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 c796059ace..9f99ba2dec 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 fdeb6481de..0ddc67bf24 100644 --- a/docs/serializer-settings.md +++ b/docs/serializer-settings.md @@ -85,7 +85,7 @@ var settings = new JsonSerializerSettings DefaultValueHandling = DefaultValueHandling.Ignore, }; ``` -snippet source | anchor +snippet source | anchor @@ -157,7 +157,7 @@ To disable this behavior globally use: ```cs VerifierSettings.DontIgnoreEmptyCollections(); ``` -snippet source | anchor +snippet source | anchor @@ -179,7 +179,7 @@ var target = new GuidTarget await Verify(target); ``` -snippet source | anchor +snippet source | anchor Results in the following: @@ -204,7 +204,7 @@ Strings containing inline Guids can also be scrubbed. To enable this behavior, u ```cs VerifierSettings.ScrubInlineGuids(); ``` -snippet source | anchor +snippet source | anchor @@ -240,7 +240,7 @@ To disable this behavior globally use: ```cs VerifierSettings.DontScrubGuids(); ``` -snippet source | anchor +snippet source | anchor @@ -304,7 +304,7 @@ var target = new DateTimeTarget await Verify(target); ``` -snippet source | anchor +snippet source | anchor Results in the following: @@ -342,7 +342,7 @@ settings.DontScrubDateTimes(); return Verify(target, settings); ``` -snippet source | anchor +snippet source | anchor Or using the fluent api use: @@ -358,7 +358,7 @@ var target = new return Verify(target) .DontScrubDateTimes(); ``` -snippet source | anchor +snippet source | anchor Or globally use: @@ -368,7 +368,7 @@ Or globally use: ```cs VerifierSettings.DontScrubDateTimes(); ``` -snippet source | anchor +snippet source | anchor @@ -411,7 +411,7 @@ await Verify(target) .AddNamedDateTime(new(2030, 1, 2), "instanceNamedDateTime") .AddNamedDateTimeOffset(new DateTime(2030, 1, 2), "instanceNamedTimeOffset"); ``` -snippet source | anchor +snippet source | anchor @@ -429,7 +429,7 @@ public static void AddNamedDatesAndTimes() VerifierSettings.AddNamedDateTimeOffset(new(new(2030, 1, 1)), "namedDateTimeOffset"); } ``` -snippet source | anchor +snippet source | anchor @@ -563,7 +563,7 @@ public Task ScopedSerializerFluent() .AddExtraSettings(_ => _.TypeNameHandling = TypeNameHandling.All); } ``` -snippet source | anchor +snippet source | anchor Result: @@ -691,7 +691,7 @@ public Task IgnoreTypeFluent() .IgnoreMembersWithType(); } ``` -snippet source | anchor +snippet source | anchor Or globally: @@ -701,7 +701,7 @@ Or globally: ```cs VerifierSettings.IgnoreMembersWithType(); ``` -snippet source | anchor +snippet source | anchor Result: @@ -838,7 +838,7 @@ public Task ScrubTypeFluent() .ScrubMembersWithType(); } ``` -snippet source | anchor +snippet source | anchor Or globally: @@ -848,7 +848,7 @@ Or globally: ```cs VerifierSettings.ScrubMembersWithType(); ``` -snippet source | anchor +snippet source | anchor Result: @@ -927,7 +927,7 @@ public Task AddIgnoreInstanceFluent() .IgnoreInstance(_ => _.Property == "Ignore"); } ``` -snippet source | anchor +snippet source | anchor Or globally: @@ -937,7 +937,7 @@ Or globally: ```cs VerifierSettings.IgnoreInstance(_ => _.Property == "Ignore"); ``` -snippet source | anchor +snippet source | anchor Result: @@ -999,7 +999,7 @@ public Task AddScrubInstanceFluent() .ScrubInstance(_ => _.Property == "Ignore"); } ``` -snippet source | anchor +snippet source | anchor Or globally: @@ -1009,7 +1009,7 @@ Or globally: ```cs VerifierSettings.ScrubInstance(_ => _.Property == "Ignore"); ``` -snippet source | anchor +snippet source | anchor Result: @@ -1054,7 +1054,7 @@ public Task WithObsoleteProp() return Verify(target); } ``` -snippet source | anchor +snippet source | anchor Result: @@ -1102,7 +1102,7 @@ public Task WithObsoletePropIncludedFluent() .IncludeObsoletes(); } ``` -snippet source | anchor +snippet source | anchor Or globally: @@ -1112,7 +1112,7 @@ Or globally: ```cs VerifierSettings.IncludeObsoletes(); ``` -snippet source | anchor +snippet source | anchor Result: @@ -1173,7 +1173,7 @@ public Task IgnoreMemberByExpressionFluent() _ => _.PropertyThatThrows); } ``` -snippet source | anchor +snippet source | anchor Or globally @@ -1188,7 +1188,7 @@ VerifierSettings.IgnoreMembers( _ => _.GetOnlyProperty, _ => _.PropertyThatThrows); ``` -snippet source | anchor +snippet source | anchor Result: @@ -1248,7 +1248,7 @@ public Task ScrubMemberByExpressionFluent() _ => _.PropertyThatThrows); } ``` -snippet source | anchor +snippet source | anchor Or globally @@ -1263,7 +1263,7 @@ VerifierSettings.ScrubMembers( _ => _.GetOnlyProperty, _ => _.PropertyThatThrows); ``` -snippet source | anchor +snippet source | anchor Result: @@ -1342,7 +1342,7 @@ public Task IgnoreMemberByNameFluent() .IgnoreMember(_ => _.PropertyThatThrows); } ``` -snippet source | anchor +snippet source | anchor Or globally: @@ -1362,7 +1362,7 @@ VerifierSettings.IgnoreMember("Field"); // For a specific type with expression VerifierSettings.IgnoreMember(_ => _.PropertyThatThrows); ``` -snippet source | anchor +snippet source | anchor Result: @@ -1437,7 +1437,7 @@ public Task ScrubMemberByNameFluent() .ScrubMember(_ => _.PropertyThatThrows); } ``` -snippet source | anchor +snippet source | anchor Or globally: @@ -1457,7 +1457,7 @@ VerifierSettings.ScrubMember("Field"); // For a specific type with expression VerifierSettings.ScrubMember(_ => _.PropertyThatThrows); ``` -snippet source | anchor +snippet source | anchor Result: @@ -1508,7 +1508,7 @@ public Task CustomExceptionPropFluent() .IgnoreMembersThatThrow(); } ``` -snippet source | anchor +snippet source | anchor Or globally: @@ -1518,7 +1518,7 @@ Or globally: ```cs VerifierSettings.IgnoreMembersThatThrow(); ``` -snippet source | anchor +snippet source | anchor Result: @@ -1555,7 +1555,7 @@ public Task ExceptionMessagePropFluent() .IgnoreMembersThatThrow(_ => _.Message == "Ignore"); } ``` -snippet source | anchor +snippet source | anchor Or globally: @@ -1565,7 +1565,7 @@ Or globally: ```cs VerifierSettings.IgnoreMembersThatThrow(_ => _.Message == "Ignore"); ``` -snippet source | anchor +snippet source | anchor Result: @@ -1689,7 +1689,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 9ae84778c7..6288cf9ba6 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -2,7 +2,7 @@ CS1591;CS0649;xUnit1026;xUnit1013;msb3277;CS0436;CS1573 - 19.11.2 + 19.12.0 enable 11 true diff --git a/src/StrictJsonTests/SerializationTests.StringDictionary.verified.json b/src/StrictJsonTests/SerializationTests.StringDictionary.verified.json new file mode 100644 index 0000000000..ccddb17234 --- /dev/null +++ b/src/StrictJsonTests/SerializationTests.StringDictionary.verified.json @@ -0,0 +1,12 @@ +{ + "item2": { + "key": null + }, + "item4": { + "key": "value" + }, + "item8": { + "key1": "value1", + "key2": "value2" + } +} \ No newline at end of file diff --git a/src/Verify.Tests/Serialization/SerializationTests.StringDictionary.verified.txt b/src/Verify.Tests/Serialization/SerializationTests.StringDictionary.verified.txt new file mode 100644 index 0000000000..f9ee86ae50 --- /dev/null +++ b/src/Verify.Tests/Serialization/SerializationTests.StringDictionary.verified.txt @@ -0,0 +1,12 @@ +{ + item2: { + key: null + }, + item4: { + key: value + }, + item8: { + key1: value1, + key2: value2 + } +} \ No newline at end of file diff --git a/src/Verify.Tests/Serialization/SerializationTests.cs b/src/Verify.Tests/Serialization/SerializationTests.cs index 87b595da45..35ebf0ac38 100644 --- a/src/Verify.Tests/Serialization/SerializationTests.cs +++ b/src/Verify.Tests/Serialization/SerializationTests.cs @@ -679,6 +679,35 @@ public Task NameValueCollection() => } }); + + [Fact] + public Task StringDictionary() => + Verify( + new + { + item2 = new StringDictionary + { + { + "key", null + } + }, + item4 = new StringDictionary + { + { + "key", "value" + } + }, + item8 = new StringDictionary + { + { + "key1", "value1" + }, + { + "key2", "value2" + } + } + }); + [Fact] public Task Timespan() => Verify( diff --git a/src/Verify/Serialization/Converters/StringDictionaryConverter.cs b/src/Verify/Serialization/Converters/StringDictionaryConverter.cs new file mode 100644 index 0000000000..4b5409cda3 --- /dev/null +++ b/src/Verify/Serialization/Converters/StringDictionaryConverter.cs @@ -0,0 +1,16 @@ +class StringDictionaryConverter : + WriteOnlyJsonConverter +{ + public override void Write(VerifyJsonWriter writer, StringDictionary collection) + { + var dictionary = new Dictionary(collection.Count); + foreach (string? key in collection.Keys) + { + var notNullKey = key!; + var value = collection[notNullKey]; + dictionary[notNullKey] = value; + } + + writer.Serialize(dictionary); + } +} \ No newline at end of file diff --git a/src/Verify/Serialization/SerializationSettings.cs b/src/Verify/Serialization/SerializationSettings.cs index deeef7e0f6..8232241276 100644 --- a/src/Verify/Serialization/SerializationSettings.cs +++ b/src/Verify/Serialization/SerializationSettings.cs @@ -27,6 +27,7 @@ partial class SerializationSettings static ClaimsPrincipalConverter claimsPrincipalConverter = new(); static ClaimsIdentityConverter claimsIdentityConverter = new(); static NameValueCollectionConverter nameValueCollectionConverter = new(); + static StringDictionaryConverter stringDictionaryConverter = new(); static StringBuilderConverter stringBuilderConverter = new(); static TaskConverter taskConverter = new(); static ValueTaskConverter valueTaskConverter = new(); @@ -118,6 +119,7 @@ JsonSerializerSettings BuildSettings() converters.Add(jArrayConverter); converters.Add(jObjectConverter); converters.Add(nameValueCollectionConverter); + converters.Add(stringDictionaryConverter); converters.Add(keyValuePairConverter); foreach (var extraSetting in extraSettings) {