diff --git a/src/Verify.Tests/Converters/ExtensionConverterTests.NestedTarget#03.verified.txt b/src/Verify.Tests/Converters/ExtensionConverterTests.NestedTarget#03.verified.txt index 5f282702b..c1b8d743e 100644 --- a/src/Verify.Tests/Converters/ExtensionConverterTests.NestedTarget#03.verified.txt +++ b/src/Verify.Tests/Converters/ExtensionConverterTests.NestedTarget#03.verified.txt @@ -1 +1 @@ - \ No newline at end of file +emptyString \ No newline at end of file diff --git a/src/Verify.Tests/LinesScrubberTests.ScrubAllLinesToEmpty.verified.txt b/src/Verify.Tests/LinesScrubberTests.ScrubAllLinesToEmpty.verified.txt new file mode 100644 index 000000000..c1b8d743e --- /dev/null +++ b/src/Verify.Tests/LinesScrubberTests.ScrubAllLinesToEmpty.verified.txt @@ -0,0 +1 @@ +emptyString \ No newline at end of file diff --git a/src/Verify.Tests/LinesScrubberTests.cs b/src/Verify.Tests/LinesScrubberTests.cs index 8bf274259..994aea785 100644 --- a/src/Verify.Tests/LinesScrubberTests.cs +++ b/src/Verify.Tests/LinesScrubberTests.cs @@ -61,6 +61,23 @@ public Task FilterLines() """); } + [Fact] + public Task ScrubAllLinesToEmpty() + { + // Scrubbing away every line leaves empty content. It is normalized to the + // "emptyString" sentinel (the same one used for Verify(string.Empty)) so that + // empty content is never written as a snapshot nor passed to a string comparer. + var settings = new VerifySettings(); + settings.ScrubLines(removeLine: _ => true); + return Verify( + settings: settings, + target: """ + a + b + c + """); + } + [Fact] public Task ScrubLinesContaining_case_sensitive() { diff --git a/src/Verify/Verifier/InnerVerifier_Inner.cs b/src/Verify/Verifier/InnerVerifier_Inner.cs index b3ce46f7e..d7b5ae56b 100644 --- a/src/Verify/Verifier/InnerVerifier_Inner.cs +++ b/src/Verify/Verifier/InnerVerifier_Inner.cs @@ -136,6 +136,14 @@ void Scrub(in Target target) if (target.TryGetStringBuilder(out var builder)) { ApplyScrubbers.ApplyForExtension(target.Extension, builder, settings, counter); + // Content scrubbed away entirely is normalized to the same sentinel used for an + // empty root string (see TryGetRootTarget). This keeps empty out of the written + // snapshot and, more importantly, out of any registered string comparer, which may + // assume non-empty input. + if (builder.Length == 0) + { + builder.Append("emptyString"); + } } } @@ -170,9 +178,9 @@ bool TryGetRootTarget(object? root,bool ignoreNullRoot, [NotNullWhen(true)] out } else { - var builder = new StringBuilder(stringRoot); - ApplyScrubbers.ApplyForExtension("txt", builder, settings, counter); - target = new("txt", builder); + var textTarget = new Target("txt", new StringBuilder(stringRoot)); + Scrub(textTarget); + target = textTarget; } return true;