From aa5da1eb235bfe6e80412ec8986e4eb5ca14bc84 Mon Sep 17 00:00:00 2001 From: Simon Cropp Date: Tue, 14 Jul 2026 07:02:12 +1000 Subject: [PATCH] Normalize scrubbed-to-empty text to emptyString MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Normalize scrubbed-to-empty text to emptyString The emptyString sentinel was only applied to the raw root string, so text that became empty during scrubbing (eg ScrubLines removing every line) or an empty converted stream bypassed it and reached the comparison layer empty — written as an empty snapshot or handed to a registered string comparer that assumes non-empty input (eg Verify.DiffPlex). Apply the sentinel after scrubbing in Scrub(), the single point all text targets pass through (root string, appenders, converted targets), and route the root string through Scrub() too. NestedTarget#03 updated: an empty converted stream now renders emptyString instead of an empty file. --- ...nConverterTests.NestedTarget#03.verified.txt | 2 +- ...ubberTests.ScrubAllLinesToEmpty.verified.txt | 1 + src/Verify.Tests/LinesScrubberTests.cs | 17 +++++++++++++++++ src/Verify/Verifier/InnerVerifier_Inner.cs | 14 +++++++++++--- 4 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 src/Verify.Tests/LinesScrubberTests.ScrubAllLinesToEmpty.verified.txt diff --git a/src/Verify.Tests/Converters/ExtensionConverterTests.NestedTarget#03.verified.txt b/src/Verify.Tests/Converters/ExtensionConverterTests.NestedTarget#03.verified.txt index 5f282702bb..c1b8d743e3 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 0000000000..c1b8d743e3 --- /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 8bf274259e..994aea7855 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 b3ce46f7e2..d7b5ae56bf 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;