diff --git a/docs/dates.md b/docs/dates.md index cf7cdb72b..adff2dbd6 100644 --- a/docs/dates.md +++ b/docs/dates.md @@ -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 diff --git a/docs/guids.md b/docs/guids.md index 2a3d9e87b..503f9cde1 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,13 +79,15 @@ await Verify(target) ```cs VerifierSettings.DontScrubGuids(); ``` -snippet source | anchor +snippet source | anchor ## Inline Guids -Strings containing inline Guids can also be scrubbed. To enable this behavior, use: +Strings containing inline Guids can also be scrubbed. Guids in the `D` format (`00000000-0000-0000-0000-000000000000`) and the `N` format (`00000000000000000000000000000000`) are matched when bounded by non-alphanumeric characters. `B` and `P` formatted Guids are covered by the `D` format matching between their delimiters. Note that any 32 character hex sequence is a valid `N` format Guid, so hex content of that exact length (an MD5 hash for example) will also be scrubbed. + +To enable this behavior, use: ### Instance @@ -103,7 +105,7 @@ public Task ScrubInlineGuidsInstance() settings); } ``` -snippet source | anchor +snippet source | anchor @@ -117,7 +119,7 @@ public Task ScrubInlineGuidsFluent() => Verify("content 651ad409-fc30-4b12-a47e-616d3f953e4c content") .ScrubInlineGuids(); ``` -snippet source | anchor +snippet source | anchor @@ -133,7 +135,7 @@ public static class ModuleInitializer VerifierSettings.ScrubInlineGuids(); } ``` -snippet source | anchor +snippet source | anchor @@ -161,7 +163,7 @@ public Task NamedGuidInstance() settings); } ``` -snippet source | anchor +snippet source | anchor @@ -182,7 +184,7 @@ public Task NamedGuidFluent() .AddNamedGuid(guid, "instanceNamed"); } ``` -snippet source | anchor +snippet source | anchor @@ -217,7 +219,7 @@ public Task InferredNamedGuidFluent() .AddNamedGuid(namedGuid); } ``` -snippet source | anchor +snippet source | anchor Result: diff --git a/docs/mdsource/guids.source.md b/docs/mdsource/guids.source.md index 6eb0f5e1a..a8d6127b4 100644 --- a/docs/mdsource/guids.source.md +++ b/docs/mdsource/guids.source.md @@ -31,7 +31,9 @@ snippet: DontScrubGuidsGlobal ## Inline Guids -Strings containing inline Guids can also be scrubbed. To enable this behavior, use: +Strings containing inline Guids can also be scrubbed. Guids in the `D` format (`00000000-0000-0000-0000-000000000000`) and the `N` format (`00000000000000000000000000000000`) are matched when bounded by non-alphanumeric characters. `B` and `P` formatted Guids are covered by the `D` format matching between their delimiters. Note that any 32 character hex sequence is a valid `N` format Guid, so hex content of that exact length (an MD5 hash for example) will also be scrubbed. + +To enable this behavior, use: ### Instance diff --git a/docs/members-throw.md b/docs/members-throw.md index fea107e64..7dbebe855 100644 --- a/docs/members-throw.md +++ b/docs/members-throw.md @@ -35,7 +35,7 @@ public Task CustomExceptionPropFluent() .IgnoreMembersThatThrow(); } ``` -snippet source | anchor +snippet source | anchor Or globally: @@ -45,7 +45,7 @@ Or globally: ```cs VerifierSettings.IgnoreMembersThatThrow(); ``` -snippet source | anchor +snippet source | anchor Result: @@ -82,7 +82,7 @@ public Task ExceptionMessagePropFluent() .IgnoreMembersThatThrow(_ => _.Message == "Ignore"); } ``` -snippet source | anchor +snippet source | anchor Or globally: @@ -92,7 +92,7 @@ Or globally: ```cs VerifierSettings.IgnoreMembersThatThrow(_ => _.Message == "Ignore"); ``` -snippet source | anchor +snippet source | anchor Result: diff --git a/docs/named-tuples.md b/docs/named-tuples.md index cbc2a40f2..221a4f5ad 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/obsolete-members.md b/docs/obsolete-members.md index 9a8412f1a..726f461d9 100644 --- a/docs/obsolete-members.md +++ b/docs/obsolete-members.md @@ -31,7 +31,7 @@ public Task WithObsoleteProp() return Verify(target); } ``` -snippet source | anchor +snippet source | anchor Result: @@ -79,7 +79,7 @@ public Task WithObsoletePropIncludedFluent() .IncludeObsoletes(); } ``` -snippet source | anchor +snippet source | anchor Or globally: @@ -89,7 +89,7 @@ Or globally: ```cs VerifierSettings.IncludeObsoletes(); ``` -snippet source | anchor +snippet source | anchor Result: diff --git a/docs/scrubbers.md b/docs/scrubbers.md index ccbd5d869..3a3473b56 100644 --- a/docs/scrubbers.md +++ b/docs/scrubbers.md @@ -44,7 +44,7 @@ verifySettings.ScrubWindow( return null; }); ``` -snippet source | anchor +snippet source | anchor `ScrubLines` and `ScrubLinesWithReplace` also accept span based delegates (`LineMatch` / `LineReplace`) that avoid allocating a string per line. Use an explicitly typed lambda parameter to select them, e.g. `ScrubLines((ReadOnlySpan line) => ...)`; untyped lambdas bind the string overloads. @@ -69,7 +69,7 @@ Instead of being executed by the engine, `AddScrubber(Action)` mu ```cs verifySettings.AddScrubber(_ => _.Remove(0, 100)); ``` -snippet source | anchor +snippet source | anchor Since these run after every engine scrubber, they can also modify text that the engine has already replaced. @@ -118,7 +118,7 @@ For example remove lines containing `text`: ```cs verifySettings.ScrubLines(line => line.Contains("text")); ``` -snippet source | anchor +snippet source | anchor @@ -133,7 +133,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`). @@ -145,7 +145,7 @@ Case insensitive by default (`StringComparison.OrdinalIgnoreCase`). ```cs verifySettings.ScrubLinesContaining(StringComparison.Ordinal, "text1", "text2"); ``` -snippet source | anchor +snippet source | anchor @@ -160,7 +160,7 @@ For example converts lines to upper case: ```cs verifySettings.ScrubLinesWithReplace(line => line.ToUpper()); ``` -snippet source | anchor +snippet source | anchor @@ -173,7 +173,7 @@ Replaces `Environment.MachineName` with `TheMachineName`. ```cs verifySettings.ScrubMachineName(); ``` -snippet source | anchor +snippet source | anchor @@ -186,7 +186,7 @@ Replaces `Environment.UserName` with `TheUserName`. ```cs verifySettings.ScrubUserName(); ``` -snippet source | anchor +snippet source | anchor @@ -788,7 +788,7 @@ Scrubbers can be scoped to verified files with a matching extension by passing t ```cs verifySettings.ScrubReplace("json", "abc", "xyz"); ``` -snippet source | anchor +snippet source | anchor A scrubber registered this way runs only for verified files with that extension, while a scrubber registered without an extension runs for all of them. Extension scoping is available at every [level](#Scrubber-levels), and for the legacy `AddScrubber(Action)` overloads. diff --git a/docs/serializer-settings.md b/docs/serializer-settings.md index f7cda568a..794480e4a 100644 --- a/docs/serializer-settings.md +++ b/docs/serializer-settings.md @@ -204,7 +204,7 @@ To disable this behavior globally use: ```cs VerifierSettings.DontIgnoreEmptyCollections(); ``` -snippet source | anchor +snippet source | anchor @@ -495,7 +495,7 @@ public Task ScopedSerializerFluent() .AddExtraSettings(_ => _.TypeNameHandling = TypeNameHandling.All); } ``` -snippet source | anchor +snippet source | anchor Result: @@ -623,7 +623,7 @@ public Task IgnoreTypeFluent() .IgnoreMembersWithType(); } ``` -snippet source | anchor +snippet source | anchor Or globally: @@ -633,7 +633,7 @@ Or globally: ```cs VerifierSettings.IgnoreMembersWithType(); ``` -snippet source | anchor +snippet source | anchor Result: @@ -770,7 +770,7 @@ public Task ScrubTypeFluent() .ScrubMembersWithType(); } ``` -snippet source | anchor +snippet source | anchor Or globally: @@ -780,7 +780,7 @@ Or globally: ```cs VerifierSettings.ScrubMembersWithType(); ``` -snippet source | anchor +snippet source | anchor Result: @@ -859,7 +859,7 @@ public Task AddIgnoreInstanceFluent() .IgnoreInstance(_ => _.Property == "Ignore"); } ``` -snippet source | anchor +snippet source | anchor Or globally: @@ -869,7 +869,7 @@ Or globally: ```cs VerifierSettings.IgnoreInstance(_ => _.Property == "Ignore"); ``` -snippet source | anchor +snippet source | anchor Result: @@ -931,7 +931,7 @@ public Task AddScrubInstanceFluent() .ScrubInstance(_ => _.Property == "Ignore"); } ``` -snippet source | anchor +snippet source | anchor Or globally: @@ -941,7 +941,7 @@ Or globally: ```cs VerifierSettings.ScrubInstance(_ => _.Property == "Ignore"); ``` -snippet source | anchor +snippet source | anchor Result: @@ -1004,7 +1004,7 @@ public Task IgnoreMemberByExpressionFluent() _ => _.PropertyThatThrows); } ``` -snippet source | anchor +snippet source | anchor Or globally @@ -1019,7 +1019,7 @@ VerifierSettings.IgnoreMembers( _ => _.GetOnlyProperty, _ => _.PropertyThatThrows); ``` -snippet source | anchor +snippet source | anchor Result: @@ -1079,7 +1079,7 @@ public Task ScrubMemberByExpressionFluent() _ => _.PropertyThatThrows); } ``` -snippet source | anchor +snippet source | anchor Or globally @@ -1094,7 +1094,7 @@ VerifierSettings.ScrubMembers( _ => _.GetOnlyProperty, _ => _.PropertyThatThrows); ``` -snippet source | anchor +snippet source | anchor Result: @@ -1173,7 +1173,7 @@ public Task IgnoreMemberByNameFluent() .IgnoreMember(_ => _.PropertyThatThrows); } ``` -snippet source | anchor +snippet source | anchor Or globally: @@ -1193,7 +1193,7 @@ VerifierSettings.IgnoreMember("Field"); // For a specific type with expression VerifierSettings.IgnoreMember(_ => _.PropertyThatThrows); ``` -snippet source | anchor +snippet source | anchor Result: @@ -1268,7 +1268,7 @@ public Task ScrubMemberByNameFluent() .ScrubMember(_ => _.PropertyThatThrows); } ``` -snippet source | anchor +snippet source | anchor Or globally: @@ -1288,7 +1288,7 @@ VerifierSettings.ScrubMember("Field"); // For a specific type with expression VerifierSettings.ScrubMember(_ => _.PropertyThatThrows); ``` -snippet source | anchor +snippet source | anchor Result: @@ -1381,7 +1381,7 @@ public Task IgnoreDictionaryByPredicate() return Verify(target, settings); } ``` -snippet source | anchor +snippet source | anchor Or globally: @@ -1393,7 +1393,7 @@ VerifierSettings.IgnoreMembers( _=>_.DeclaringType == typeof(TargetClass) && _.Name == "Proprty"); ``` -snippet source | anchor +snippet source | anchor Result: @@ -1482,7 +1482,7 @@ public Task ScrubDictionaryByPredicate() return Verify(target, settings); } ``` -snippet source | anchor +snippet source | anchor Or globally: @@ -1494,7 +1494,7 @@ VerifierSettings.ScrubMembers( _=>_.DeclaringType == typeof(TargetClass) && _.Name == "Proprty"); ``` -snippet source | anchor +snippet source | anchor Result: @@ -1548,7 +1548,7 @@ public Task MemberConverterByExpression() return Verify(input); } ``` -snippet source | anchor +snippet source | anchor diff --git a/src/StrictJsonTests/SerializationTests.ScrubInlineGuidsNFormatInString.verified.txt b/src/StrictJsonTests/SerializationTests.ScrubInlineGuidsNFormatInString.verified.txt new file mode 100644 index 000000000..92305f785 --- /dev/null +++ b/src/StrictJsonTests/SerializationTests.ScrubInlineGuidsNFormatInString.verified.txt @@ -0,0 +1 @@ +The string Guid_1 \ No newline at end of file diff --git a/src/Verify.Tests/GuidScrubberTests.InlineNamedGuidNFormat.verified.txt b/src/Verify.Tests/GuidScrubberTests.InlineNamedGuidNFormat.verified.txt new file mode 100644 index 000000000..20362a0e5 --- /dev/null +++ b/src/Verify.Tests/GuidScrubberTests.InlineNamedGuidNFormat.verified.txt @@ -0,0 +1 @@ +value: guidName \ No newline at end of file diff --git a/src/Verify.Tests/GuidScrubberTests.Run_n-d-same.verified.txt b/src/Verify.Tests/GuidScrubberTests.Run_n-d-same.verified.txt new file mode 100644 index 000000000..d629666f8 --- /dev/null +++ b/src/Verify.Tests/GuidScrubberTests.Run_n-d-same.verified.txt @@ -0,0 +1 @@ +Guid_1 Guid_1 \ No newline at end of file diff --git a/src/Verify.Tests/GuidScrubberTests.Run_n-dash.verified.txt b/src/Verify.Tests/GuidScrubberTests.Run_n-dash.verified.txt new file mode 100644 index 000000000..95d007458 --- /dev/null +++ b/src/Verify.Tests/GuidScrubberTests.Run_n-dash.verified.txt @@ -0,0 +1 @@ +-Guid_1- \ No newline at end of file diff --git a/src/Verify.Tests/GuidScrubberTests.Run_n-duplicate.verified.txt b/src/Verify.Tests/GuidScrubberTests.Run_n-duplicate.verified.txt new file mode 100644 index 000000000..d629666f8 --- /dev/null +++ b/src/Verify.Tests/GuidScrubberTests.Run_n-duplicate.verified.txt @@ -0,0 +1 @@ +Guid_1 Guid_1 \ No newline at end of file diff --git a/src/Verify.Tests/GuidScrubberTests.Run_n-end-letters.verified.txt b/src/Verify.Tests/GuidScrubberTests.Run_n-end-letters.verified.txt new file mode 100644 index 000000000..78fc3df3c --- /dev/null +++ b/src/Verify.Tests/GuidScrubberTests.Run_n-end-letters.verified.txt @@ -0,0 +1 @@ +173535ae995b4cc6a74e8cd4be57039ca \ No newline at end of file diff --git a/src/Verify.Tests/GuidScrubberTests.Run_n-letters.verified.txt b/src/Verify.Tests/GuidScrubberTests.Run_n-letters.verified.txt new file mode 100644 index 000000000..4335afcf6 --- /dev/null +++ b/src/Verify.Tests/GuidScrubberTests.Run_n-letters.verified.txt @@ -0,0 +1 @@ +a173535ae995b4cc6a74e8cd4be57039ca \ No newline at end of file diff --git a/src/Verify.Tests/GuidScrubberTests.Run_n-multiple.verified.txt b/src/Verify.Tests/GuidScrubberTests.Run_n-multiple.verified.txt new file mode 100644 index 000000000..1e289258d --- /dev/null +++ b/src/Verify.Tests/GuidScrubberTests.Run_n-multiple.verified.txt @@ -0,0 +1 @@ +Guid_1 Guid_2 \ No newline at end of file diff --git a/src/Verify.Tests/GuidScrubberTests.Run_n-sha1.verified.txt b/src/Verify.Tests/GuidScrubberTests.Run_n-sha1.verified.txt new file mode 100644 index 000000000..012818aef --- /dev/null +++ b/src/Verify.Tests/GuidScrubberTests.Run_n-sha1.verified.txt @@ -0,0 +1 @@ +da39a3ee5e6b4b0d3255bfef95601890afd80709 \ No newline at end of file diff --git a/src/Verify.Tests/GuidScrubberTests.Run_n-sha256.verified.txt b/src/Verify.Tests/GuidScrubberTests.Run_n-sha256.verified.txt new file mode 100644 index 000000000..0dec1a2bd --- /dev/null +++ b/src/Verify.Tests/GuidScrubberTests.Run_n-sha256.verified.txt @@ -0,0 +1 @@ +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 \ No newline at end of file diff --git a/src/Verify.Tests/GuidScrubberTests.Run_n-square.verified.txt b/src/Verify.Tests/GuidScrubberTests.Run_n-square.verified.txt new file mode 100644 index 000000000..0ec11b6d8 --- /dev/null +++ b/src/Verify.Tests/GuidScrubberTests.Run_n-square.verified.txt @@ -0,0 +1 @@ +[Guid_1] \ No newline at end of file diff --git a/src/Verify.Tests/GuidScrubberTests.Run_n-start-letters.verified.txt b/src/Verify.Tests/GuidScrubberTests.Run_n-start-letters.verified.txt new file mode 100644 index 000000000..0be9f08eb --- /dev/null +++ b/src/Verify.Tests/GuidScrubberTests.Run_n-start-letters.verified.txt @@ -0,0 +1 @@ +a173535ae995b4cc6a74e8cd4be57039c \ No newline at end of file diff --git a/src/Verify.Tests/GuidScrubberTests.Run_n-upper.verified.txt b/src/Verify.Tests/GuidScrubberTests.Run_n-upper.verified.txt new file mode 100644 index 000000000..bc34cb3ff --- /dev/null +++ b/src/Verify.Tests/GuidScrubberTests.Run_n-upper.verified.txt @@ -0,0 +1 @@ +Guid_1 \ No newline at end of file diff --git a/src/Verify.Tests/GuidScrubberTests.Run_n-zeros.verified.txt b/src/Verify.Tests/GuidScrubberTests.Run_n-zeros.verified.txt new file mode 100644 index 000000000..3ea1b9dc9 --- /dev/null +++ b/src/Verify.Tests/GuidScrubberTests.Run_n-zeros.verified.txt @@ -0,0 +1 @@ +Guid_Empty \ No newline at end of file diff --git a/src/Verify.Tests/GuidScrubberTests.Run_n.verified.txt b/src/Verify.Tests/GuidScrubberTests.Run_n.verified.txt new file mode 100644 index 000000000..bc34cb3ff --- /dev/null +++ b/src/Verify.Tests/GuidScrubberTests.Run_n.verified.txt @@ -0,0 +1 @@ +Guid_1 \ No newline at end of file diff --git a/src/Verify.Tests/GuidScrubberTests.cs b/src/Verify.Tests/GuidScrubberTests.cs index 3c179b8da..ac83d2b95 100644 --- a/src/Verify.Tests/GuidScrubberTests.cs +++ b/src/Verify.Tests/GuidScrubberTests.cs @@ -11,7 +11,7 @@ public class GuidScrubberTests static string ReplaceGuids(string value, Counter counter) { - var set = EngineScrubberSet.ForScrubbers([GuidMatcher.Instance]); + var set = EngineScrubberSet.ForScrubbers([GuidMatcher.Instance, GuidMatcher.NInstance]); return ScrubEngine.Run(value, set, counter, emptyContext, applyDirectoryReplacements: false); } @@ -48,6 +48,19 @@ static string ReplaceGuids(string value, Counter counter) [InlineData("1173535ae-995b-4cc6-a74e-8cd4be57039c1", "numbers")] [InlineData("1173535ae-995b-4cc6-a74e-8cd4be57039c", "start-numbers")] [InlineData("173535ae-995b-4cc6-a74e-8cd4be57039c1", "end-numbers")] + [InlineData("173535ae995b4cc6a74e8cd4be57039c", "n")] + [InlineData("173535ae995b4cc6a74e8cd4be57039c 173535ae995b4cc6a74e8cd4be57039d", "n-multiple")] + [InlineData("173535ae995b4cc6a74e8cd4be57039c 173535ae995b4cc6a74e8cd4be57039c", "n-duplicate")] + [InlineData("173535ae-995b-4cc6-a74e-8cd4be57039c 173535ae995b4cc6a74e8cd4be57039c", "n-d-same")] + [InlineData("173535AE995B4CC6A74E8CD4BE57039C", "n-upper")] + [InlineData("[173535ae995b4cc6a74e8cd4be57039c]", "n-square")] + [InlineData("-173535ae995b4cc6a74e8cd4be57039c-", "n-dash")] + [InlineData("a173535ae995b4cc6a74e8cd4be57039ca", "n-letters")] + [InlineData("a173535ae995b4cc6a74e8cd4be57039c", "n-start-letters")] + [InlineData("173535ae995b4cc6a74e8cd4be57039ca", "n-end-letters")] + [InlineData("00000000000000000000000000000000", "n-zeros")] + [InlineData("da39a3ee5e6b4b0d3255bfef95601890afd80709", "n-sha1")] + [InlineData("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "n-sha256")] public async Task Run(string guid, string name) { using var counter = Counter.Start(); @@ -105,6 +118,11 @@ public void Multiple() Assert.Equal("[Guid_1][Guid_2]", result); } + [Fact] + public Task InlineNamedGuidNFormat() => + Verify("value: c8eeaf99d5c4434185434597c3fd40c9") + .ScrubInlineGuids(); + #region NamedGuidFluent [Fact] diff --git a/src/Verify.Tests/NewLineTests.TrailingNewlinesRaw.verified.txt b/src/Verify.Tests/NewLineTests.TrailingNewlinesRaw.verified.txt new file mode 100644 index 000000000..7a2a9ee4f --- /dev/null +++ b/src/Verify.Tests/NewLineTests.TrailingNewlinesRaw.verified.txt @@ -0,0 +1 @@ +a diff --git a/src/Verify.Tests/Serialization/SerializationTests.ScrubInlineGuidsNFormatInString.verified.txt b/src/Verify.Tests/Serialization/SerializationTests.ScrubInlineGuidsNFormatInString.verified.txt new file mode 100644 index 000000000..92305f785 --- /dev/null +++ b/src/Verify.Tests/Serialization/SerializationTests.ScrubInlineGuidsNFormatInString.verified.txt @@ -0,0 +1 @@ +The string Guid_1 \ No newline at end of file diff --git a/src/Verify.Tests/Serialization/SerializationTests.cs b/src/Verify.Tests/Serialization/SerializationTests.cs index 8a624fd50..27cb3ac82 100644 --- a/src/Verify.Tests/Serialization/SerializationTests.cs +++ b/src/Verify.Tests/Serialization/SerializationTests.cs @@ -1498,6 +1498,14 @@ public Task ScrubInlineGuidsInString() .ScrubInlineGuids(); } + [Fact] + public Task ScrubInlineGuidsNFormatInString() + { + var id = Guid.NewGuid(); + return Verify($"The string {id:N} ") + .ScrubInlineGuids(); + } + [Fact] public Task WriteRawInConverterTest() { diff --git a/src/Verify/Serialization/Scrubbers/GuidMatcher.cs b/src/Verify/Serialization/Scrubbers/GuidMatcher.cs index a5f9b2c9a..68853261a 100644 --- a/src/Verify/Serialization/Scrubbers/GuidMatcher.cs +++ b/src/Verify/Serialization/Scrubbers/GuidMatcher.cs @@ -1,6 +1,9 @@ -// The inline guid scrubber: a fixed 36 char window over the canonical "D" format. -// The engine anchor jumps between '-' chars at offset 8 (the first dash of the "D" -// format), so no-match text is scanned vectorized instead of per position. +// The inline guid scrubbers: a fixed 36 char window over the canonical "D" format +// and a fixed 32 char window over the "N" format. +// The "D" engine anchor jumps between '-' chars at offset 8 (the first dash of the +// "D" format), so no-match text is scanned vectorized instead of per position. +// "B" and "P" occurrences are covered by the "D" window matching between their +// delimiters. "X" is not matched: its hex components are too short to reach a window. static class GuidMatcher { public static readonly Scrubber Instance = Scrubber.GatedWindow( @@ -13,6 +16,16 @@ static class GuidMatcher anchorChar: '-', anchorOffset: 8); + // No char appears at a fixed offset in the "N" format, so no anchor applies. + // Candidate positions are filtered by the engine's word boundary check, then by + // the first and last char prefilter, before the parse runs. + public static readonly Scrubber NInstance = Scrubber.GatedWindow( + 32, + 32, + MatchN, + static counter => counter.ScrubGuids, + requireWordBoundary: true); + static string? Match(CharSpan window, Counter counter, IReadOnlyDictionary context) { // Cheap prefilter: the "D" format has dashes at fixed offsets @@ -31,4 +44,26 @@ static class GuidMatcher return counter.Convert(guid); } + + static string? MatchN(CharSpan window, Counter counter, IReadOnlyDictionary context) + { + if (!IsHex(window[0]) || + !IsHex(window[31])) + { + return null; + } + + if (!Guid.TryParseExact(window, "N", out var guid)) + { + return null; + } + + return counter.Convert(guid); + } + + static bool IsHex(char value) => + value + is >= '0' and <= '9' + or >= 'a' and <= 'f' + or >= 'A' and <= 'F'; } diff --git a/src/Verify/Serialization/Scrubbers/VerifierSettings_ExtensionMappedGlobalScrubbers.cs b/src/Verify/Serialization/Scrubbers/VerifierSettings_ExtensionMappedGlobalScrubbers.cs index 60085999e..36edbd50b 100644 --- a/src/Verify/Serialization/Scrubbers/VerifierSettings_ExtensionMappedGlobalScrubbers.cs +++ b/src/Verify/Serialization/Scrubbers/VerifierSettings_ExtensionMappedGlobalScrubbers.cs @@ -90,8 +90,11 @@ public static void ScrubEmptyLines(string extension) => /// /// Replace inline s with a placeholder. /// - public static void ScrubInlineGuids(string extension) => + public static void ScrubInlineGuids(string extension) + { AddScrubber(extension, GuidMatcher.Instance); + AddScrubber(extension, GuidMatcher.NInstance); + } /// /// Scrub lines with an optional replace. diff --git a/src/Verify/Serialization/Scrubbers/VerifierSettings_GlobalScrubbers.cs b/src/Verify/Serialization/Scrubbers/VerifierSettings_GlobalScrubbers.cs index ea66c5860..c26a5339a 100644 --- a/src/Verify/Serialization/Scrubbers/VerifierSettings_GlobalScrubbers.cs +++ b/src/Verify/Serialization/Scrubbers/VerifierSettings_GlobalScrubbers.cs @@ -127,8 +127,11 @@ public static void ScrubInlineDates( /// /// Replace inline s with a placeholder. /// - public static void ScrubInlineGuids() => + public static void ScrubInlineGuids() + { AddScrubber(GuidMatcher.Instance); + AddScrubber(GuidMatcher.NInstance); + } /// /// Scrub lines with an optional replace. diff --git a/src/Verify/Serialization/Scrubbers/VerifySettings_ExtensionMappedInstanceScrubbers.cs b/src/Verify/Serialization/Scrubbers/VerifySettings_ExtensionMappedInstanceScrubbers.cs index 199a20841..d31d9cb3a 100644 --- a/src/Verify/Serialization/Scrubbers/VerifySettings_ExtensionMappedInstanceScrubbers.cs +++ b/src/Verify/Serialization/Scrubbers/VerifySettings_ExtensionMappedInstanceScrubbers.cs @@ -78,8 +78,11 @@ public void ScrubLinesContaining(string extension, StringComparison comparison, /// /// Replace inline s with a placeholder. /// - public void ScrubInlineGuids(string extension) => + public void ScrubInlineGuids(string extension) + { AddScrubber(extension, GuidMatcher.Instance); + AddScrubber(extension, GuidMatcher.NInstance); + } /// /// Remove any lines matching from the test results. diff --git a/src/Verify/Serialization/Scrubbers/VerifySettings_InstanceScrubbers.cs b/src/Verify/Serialization/Scrubbers/VerifySettings_InstanceScrubbers.cs index 281a099fa..04cebe482 100644 --- a/src/Verify/Serialization/Scrubbers/VerifySettings_InstanceScrubbers.cs +++ b/src/Verify/Serialization/Scrubbers/VerifySettings_InstanceScrubbers.cs @@ -93,6 +93,7 @@ public void ScrubInlineGuids() } AddScrubber(GuidMatcher.Instance); + AddScrubber(GuidMatcher.NInstance); } ///