<!-- GENERATED FILE - DO NOT EDIT This file was generated by [MarkdownSnippets](https://github.com/SimonCropp/MarkdownSnippets). Source File: /docs/mdsource/scrubbers.source.md To change this file edit the source file and then run MarkdownSnippets. --> # Scrubbers Scrubbers run on the final string before doing the verification action. Multiple scrubbers [can be defined at multiple levels](#Scrubber-levels). By default scrubber are executed in reverse order. So the most recent added method scrubber through to earliest added global scrubber. All scrubber APIs support a `ScrubberLocation location`. To execute a scrubber last use `ScrubberLocation.Last`. Scrubbers can be added multiple times to have them execute multiple times. This can be helpful when compounding multiple scrubbers together. ## Available Scrubbers Scrubbers can be added to an instance of `VerifySettings` or globally on `VerifierSettings`. ### Directory Scrubbers * The current solution directory will be replaced with `{SolutionDirectory}`. To disable use `VerifierSettings.DontScrubSolutionDirectory()` in a module initializer. * The current project directory will be replaced with `{ProjectDirectory}`. To disable use `VerifierSettings.DontScrubProjectDirectory()` in a module initializer. * On Windows, the current [user profile](https://learn.microsoft.com/en-us/dotnet/api/system.environment.specialfolder) will be replaced with `{UserProfile}`. To disable use `VerifierSettings.DontScrubUserProfile()` in a module initializer. * The `AppDomain.CurrentDomain.BaseDirectory` will be replaced with `{CurrentDirectory}`. * The `Assembly.CodeBase` will be replaced with `{CurrentDirectory}`. * The `Path.GetTempPath()` will be replaced with `{TempPath}`. #### Attribute data The solution and project directory replacement functionality is achieved by adding attributes to the target assembly at compile time. For any project that references Verify, the following attributes will be added: ``` [assembly: AssemblyMetadata("Verify.ProjectDirectory", "C:\Code\TheSolution\Project\")] [assembly: AssemblyMetadata("Verify.SolutionDirectory", "C:\Code\TheSolution\")] ``` This information can be useful to consumers when writing tests, so it is exposed via `AttributeReader`: * Project directory for an assembly: `AttributeReader.GetProjectDirectory(assembly)` * Project directory for the current executing assembly: `AttributeReader.GetProjectDirectory()` * Solution directory for an assembly: `AttributeReader.GetSolutionDirectory(assembly)` * Solution directory for the current executing assembly: `AttributeReader.GetSolutionDirectory()` ### ScrubLines Allows lines to be selectively removed using a `Func`. For example remove lines containing `text`: <!-- snippet: ScrubLines --> <a id='snippet-ScrubLines'></a> ```cs verifySettings.ScrubLines(line => line.Contains("text")); ``` <sup><a href='/src/Verify.Tests/Serialization/SerializationTests.cs#L1824-L1828' title='Snippet source file'>snippet source</a> | <a href='#snippet-ScrubLines' title='Start of snippet'>anchor</a></sup> <!-- endSnippet --> ### ScrubLinesContaining Remove all lines containing any of the defined strings. For example remove lines containing `text1` or `text2` <!-- snippet: ScrubLinesContaining --> <a id='snippet-ScrubLinesContaining'></a> ```cs verifySettings.ScrubLinesContaining("text1", "text2"); ``` <sup><a href='/src/Verify.Tests/Serialization/SerializationTests.cs#L1830-L1834' title='Snippet source file'>snippet source</a> | <a href='#snippet-ScrubLinesContaining' title='Start of snippet'>anchor</a></sup> <!-- endSnippet --> Case insensitive by default (StringComparison.OrdinalIgnoreCase). `StringComparison` can be overridden: <!-- snippet: ScrubLinesContainingOrdinal --> <a id='snippet-ScrubLinesContainingOrdinal'></a> ```cs verifySettings.ScrubLinesContaining(StringComparison.Ordinal, "text1", "text2"); ``` <sup><a href='/src/Verify.Tests/Serialization/SerializationTests.cs#L1836-L1840' title='Snippet source file'>snippet source</a> | <a href='#snippet-ScrubLinesContainingOrdinal' title='Start of snippet'>anchor</a></sup> <!-- endSnippet --> ### ScrubLinesWithReplace Allows lines to be selectively replaced using a `Func`. For example converts lines to upper case: <!-- snippet: ScrubLinesWithReplace --> <a id='snippet-ScrubLinesWithReplace'></a> ```cs verifySettings.ScrubLinesWithReplace(line => line.ToUpper()); ``` <sup><a href='/src/Verify.Tests/Serialization/SerializationTests.cs#L1842-L1846' title='Snippet source file'>snippet source</a> | <a href='#snippet-ScrubLinesWithReplace' title='Start of snippet'>anchor</a></sup> <!-- endSnippet --> ### ScrubMachineName Replaces `Environment.MachineName` with `TheMachineName`. <!-- snippet: ScrubMachineName --> <a id='snippet-ScrubMachineName'></a> ```cs verifySettings.ScrubMachineName(); ``` <sup><a href='/src/Verify.Tests/Serialization/SerializationTests.cs#L1848-L1852' title='Snippet source file'>snippet source</a> | <a href='#snippet-ScrubMachineName' title='Start of snippet'>anchor</a></sup> <!-- endSnippet --> ### ScrubUserName Replaces `Environment.UserName` with `TheUserName`. <!-- snippet: ScrubUserName --> <a id='snippet-ScrubUserName'></a> ```cs verifySettings.ScrubUserName(); ``` <sup><a href='/src/Verify.Tests/Serialization/SerializationTests.cs#L1854-L1858' title='Snippet source file'>snippet source</a> | <a href='#snippet-ScrubUserName' title='Start of snippet'>anchor</a></sup> <!-- endSnippet --> ### AddScrubber Adds a scrubber with full control over the text via a `Func` ## More complete example ### NUnit <!-- snippet: ScrubbersSampleNUnit --> <a id='snippet-ScrubbersSampleNUnit'></a> ```cs [TestFixture] public class ScrubbersSample { [Test] public Task Lines() { var settings = new VerifySettings(); settings.ScrubLinesWithReplace( replaceLine: _ => { if (_.Contains("LineE")) { return "NoMoreLineE"; } return _; }); settings.ScrubLines(removeLine: _ => _.Contains('J')); settings.ScrubLinesContaining("b", "D"); settings.ScrubLinesContaining(StringComparison.Ordinal, "H"); return Verify( settings: settings, target: """ LineA LineB LineC LineD LineE LineH LineI LineJ """); } [Test] public Task LinesFluent() => Verify(""" LineA LineB LineC LineD LineE LineH LineI LineJ """) .ScrubLinesWithReplace( replaceLine: _ => { if (_.Contains("LineE")) { return "NoMoreLineE"; } return _; }) .ScrubLines(removeLine: _ => _.Contains('J')) .ScrubLinesContaining("b", "D") .ScrubLinesContaining(StringComparison.Ordinal, "H"); [Test] public Task RemoveOrReplace() => Verify(""" LineA LineB LineC """) .ScrubLinesWithReplace( replaceLine: line => { if (line.Contains("LineB")) { return null; } return line.ToLower(); }); [Test] public Task EmptyLines() => Verify(""" LineA LineC """) .ScrubEmptyLines(); } ``` <sup><a href='/src/Verify.NUnit.Tests/Scrubbers/ScrubbersSample.cs#L1-L93' title='Snippet source file'>snippet source</a> | <a href='#snippet-ScrubbersSampleNUnit' title='Start of snippet'>anchor</a></sup> <!-- endSnippet --> ### xUnit <!-- snippet: ScrubbersSampleXunit --> <a id='snippet-ScrubbersSampleXunit'></a> ```cs public class ScrubbersSample { [Fact] public Task Lines() { var settings = new VerifySettings(); settings.ScrubLinesWithReplace( replaceLine: line => { if (line.Contains("LineE")) { return "NoMoreLineE"; } return line; }); settings.ScrubLines(removeLine: _ => _.Contains('J')); settings.ScrubLinesContaining("b", "D"); settings.ScrubLinesContaining(StringComparison.Ordinal, "H"); return Verify( settings: settings, target: """ LineA LineB LineC LineD LineE LineH LineI LineJ """); } [Fact] public Task EmptyLine() { var settings = new VerifySettings(); settings.ScrubLinesWithReplace( replaceLine: _ => ""); return Verify( settings: settings, target: ""); } [Fact] public Task LinesFluent() => Verify(""" LineA LineB LineC LineD LineE LineH LineI LineJ """) .ScrubLinesWithReplace( replaceLine: _ => { if (_.Contains("LineE")) { return "NoMoreLineE"; } return _; }) .ScrubLines(removeLine: _ => _.Contains('J')) .ScrubLinesContaining("b", "D") .ScrubLinesContaining(StringComparison.Ordinal, "H"); [Fact] public Task RemoveOrReplace() => Verify(""" LineA LineB LineC """) .ScrubLinesWithReplace( replaceLine: line => { if (line.Contains("LineB")) { return null; } return line.ToLower(); }); [Fact] public Task EmptyLines() => Verify(""" LineA LineC """) .ScrubEmptyLines(); } ``` <sup><a href='/src/Verify.XunitV3.Tests/Scrubbers/ScrubbersSample.cs#L1-L103' title='Snippet source file'>snippet source</a> | <a href='#snippet-ScrubbersSampleXunit' title='Start of snippet'>anchor</a></sup> <!-- endSnippet --> ### Fixie <!-- snippet: ScrubbersSampleFixie --> <a id='snippet-ScrubbersSampleFixie'></a> ```cs public class ScrubbersSample { public Task Lines() { var settings = new VerifySettings(); settings.ScrubLinesWithReplace( replaceLine: _ => { if (_.Contains("LineE")) { return "NoMoreLineE"; } return _; }); settings.ScrubLines(removeLine: _ => _.Contains('J')); settings.ScrubLinesContaining("b", "D"); settings.ScrubLinesContaining(StringComparison.Ordinal, "H"); return Verify( settings: settings, target: """ LineA LineB LineC LineD LineE LineH LineI LineJ """); } public Task LinesFluent() => Verify(""" LineA LineB LineC LineD LineE LineH LineI LineJ """) .ScrubLinesWithReplace( replaceLine: _ => { if (_.Contains("LineE")) { return "NoMoreLineE"; } return _; }) .ScrubLines(removeLine: _ => _.Contains('J')) .ScrubLinesContaining("b", "D") .ScrubLinesContaining(StringComparison.Ordinal, "H"); public Task RemoveOrReplace() => Verify(""" LineA LineB LineC """) .ScrubLinesWithReplace( replaceLine: line => { if (line.Contains("LineB")) { return null; } return line.ToLower(); }); public Task EmptyLines() => Verify(""" LineA LineC """) .ScrubEmptyLines(); } ``` <sup><a href='/src/Verify.Fixie.Tests/Scrubbers/ScrubbersSample.cs#L1-L88' title='Snippet source file'>snippet source</a> | <a href='#snippet-ScrubbersSampleFixie' title='Start of snippet'>anchor</a></sup> <!-- endSnippet --> ### MSTest <!-- snippet: ScrubbersSampleMSTest --> <a id='snippet-ScrubbersSampleMSTest'></a> ```cs [TestClass] public partial class ScrubbersSample { [TestMethod] public Task Lines() { var settings = new VerifySettings(); settings.ScrubLinesWithReplace( replaceLine: _ => { if (_.Contains("LineE")) { return "NoMoreLineE"; } return _; }); settings.ScrubLines(removeLine: _ => _.Contains('J')); settings.ScrubLinesContaining("b", "D"); settings.ScrubLinesContaining(StringComparison.Ordinal, "H"); return Verify( settings: settings, target: """ LineA LineB LineC LineD LineE LineH LineI LineJ """); } [TestMethod] public Task LinesFluent() => Verify(""" LineA LineB LineC LineD LineE LineH LineI LineJ """) .ScrubLinesWithReplace( replaceLine: _ => { if (_.Contains("LineE")) { return "NoMoreLineE"; } return _; }) .ScrubLines(removeLine: _ => _.Contains('J')) .ScrubLinesContaining("b", "D") .ScrubLinesContaining(StringComparison.Ordinal, "H"); [TestMethod] public Task RemoveOrReplace() => Verify(""" LineA LineB LineC """) .ScrubLinesWithReplace( replaceLine: line => { if (line.Contains("LineB")) { return null; } return line.ToLower(); }); [TestMethod] public Task EmptyLines() => Verify(""" LineA LineC """) .ScrubEmptyLines(); } ``` <sup><a href='/src/Verify.MSTest.Tests/Scrubbers/ScrubbersSample.cs#L1-L93' title='Snippet source file'>snippet source</a> | <a href='#snippet-ScrubbersSampleMSTest' title='Start of snippet'>anchor</a></sup> <!-- endSnippet --> ### TUnit <!-- snippet: ScrubbersSampleTUnit --> <a id='snippet-ScrubbersSampleTUnit'></a> ```cs public class ScrubbersSample { [Test] public Task Lines() { var settings = new VerifySettings(); settings.ScrubLinesWithReplace( replaceLine: _ => { if (_.Contains("LineE")) { return "NoMoreLineE"; } return _; }); settings.ScrubLines(removeLine: _ => _.Contains('J')); settings.ScrubLinesContaining("b", "D"); settings.ScrubLinesContaining(StringComparison.Ordinal, "H"); return Verify( settings: settings, target: """ LineA LineB LineC LineD LineE LineH LineI LineJ """); } [Test] public Task LinesFluent() => Verify(""" LineA LineB LineC LineD LineE LineH LineI LineJ """) .ScrubLinesWithReplace( replaceLine: _ => { if (_.Contains("LineE")) { return "NoMoreLineE"; } return _; }) .ScrubLines(removeLine: _ => _.Contains('J')) .ScrubLinesContaining("b", "D") .ScrubLinesContaining(StringComparison.Ordinal, "H"); [Test] public Task RemoveOrReplace() => Verify(""" LineA LineB LineC """) .ScrubLinesWithReplace( replaceLine: line => { if (line.Contains("LineB")) { return null; } return line.ToLower(); }); [Test] public Task EmptyLines() => Verify(""" LineA LineC """) .ScrubEmptyLines(); } ``` <sup><a href='/src/Verify.TUnit.Tests/Scrubbers/ScrubbersSample.cs#L1-L92' title='Snippet source file'>snippet source</a> | <a href='#snippet-ScrubbersSampleTUnit' title='Start of snippet'>anchor</a></sup> <!-- endSnippet --> ### Results <!-- snippet: Verify.Xunit.Tests/Scrubbers/ScrubbersSample.Lines.verified.txt --> <a id='snippet-Verify.Xunit.Tests/Scrubbers/ScrubbersSample.Lines.verified.txt'></a> ```txt LineA LineC NoMoreLineE LineI ``` <sup><a href='/src/Verify.Xunit.Tests/Scrubbers/ScrubbersSample.Lines.verified.txt#L1-L4' title='Snippet source file'>snippet source</a> | <a href='#snippet-Verify.Xunit.Tests/Scrubbers/ScrubbersSample.Lines.verified.txt' title='Start of snippet'>anchor</a></sup> <!-- endSnippet --> ## Scrubber levels Scrubbers can be defined at three levels: * Method: Will run the verification in the current test method. * Class: As a class level 'VerifySettings' field then re-used at the method level. * Global: Will run for test methods on all tests. ### NUnit <!-- snippet: ScrubberLevelsSampleNUnit --> <a id='snippet-ScrubberLevelsSampleNUnit'></a> ```cs [TestFixture] public class ScrubberLevelsSample { VerifySettings classLevelSettings; public ScrubberLevelsSample() { classLevelSettings = new(); classLevelSettings.AddScrubber(_ => _.Replace("Three", "C")); } [Test] public Task Simple() { var settings = new VerifySettings(classLevelSettings); settings.AddScrubber(_ => _.Replace("Two", "B")); return Verify("One Two Three", settings); } [Test] public Task SimpleFluent() => Verify("One Two Three", classLevelSettings) .AddScrubber(_ => _.Replace("Two", "B")); [ModuleInitializer] public static void Setup() => VerifierSettings.AddScrubber(_ => _.Replace("One", "A")); } ``` <sup><a href='/src/Verify.NUnit.Tests/Scrubbers/ScrubberLevelsSample.cs#L1-L32' title='Snippet source file'>snippet source</a> | <a href='#snippet-ScrubberLevelsSampleNUnit' title='Start of snippet'>anchor</a></sup> <!-- endSnippet --> ### xUnit <!-- snippet: ScrubberLevelsSampleXunit --> <a id='snippet-ScrubberLevelsSampleXunit'></a> ```cs public class ScrubberLevelsSample { VerifySettings classLevelSettings; public ScrubberLevelsSample() { classLevelSettings = new(); classLevelSettings.AddScrubber(_ => _.Replace("Three", "C")); } [Fact] public Task Usage() { var settings = new VerifySettings(classLevelSettings); settings.AddScrubber(_ => _.Replace("Two", "B")); return Verify("One Two Three", settings); } [Fact] public Task UsageFluent() => Verify("One Two Three", classLevelSettings) .AddScrubber(_ => _.Replace("Two", "B")); [ModuleInitializer] public static void Initialize() => VerifierSettings.AddScrubber(_ => _.Replace("One", "A")); } ``` <sup><a href='/src/Verify.XunitV3.Tests/Scrubbers/ScrubberLevelsSample.cs#L1-L31' title='Snippet source file'>snippet source</a> | <a href='#snippet-ScrubberLevelsSampleXunit' title='Start of snippet'>anchor</a></sup> <!-- endSnippet --> ### Fixie <!-- snippet: ScrubberLevelsSampleFixie --> <a id='snippet-ScrubberLevelsSampleFixie'></a> ```cs public class ScrubberLevelsSample { VerifySettings classLevelSettings; public ScrubberLevelsSample() { classLevelSettings = new(); classLevelSettings.AddScrubber(_ => _.Replace("Three", "C")); } public Task Simple() { var settings = new VerifySettings(classLevelSettings); settings.AddScrubber(_ => _.Replace("Two", "B")); return Verify("One Two Three", settings); } public Task SimpleFluent() => Verify("One Two Three", classLevelSettings) .AddScrubber(_ => _.Replace("Two", "B")); [ModuleInitializer] public static void Setup() => VerifierSettings.AddScrubber(_ => _.Replace("One", "A")); } ``` <sup><a href='/src/Verify.Fixie.Tests/Scrubbers/ScrubberLevelsSample.cs#L1-L29' title='Snippet source file'>snippet source</a> | <a href='#snippet-ScrubberLevelsSampleFixie' title='Start of snippet'>anchor</a></sup> <!-- endSnippet --> ### MSTest <!-- snippet: ScrubberLevelsSampleMSTest --> <a id='snippet-ScrubberLevelsSampleMSTest'></a> ```cs [TestClass] public partial class ScrubberLevelsSample { VerifySettings classLevelSettings; public ScrubberLevelsSample() { classLevelSettings = new(); classLevelSettings.AddScrubber(_ => _.Replace("Three", "C")); } [TestMethod] public Task Simple() { var settings = new VerifySettings(classLevelSettings); settings.AddScrubber(_ => _.Replace("Two", "B")); return Verify("One Two Three", settings); } [TestMethod] public Task SimpleFluent() => Verify("One Two Three", classLevelSettings) .AddScrubber(_ => _.Replace("Two", "B")); [AssemblyInitialize] public static void Setup(TestContext testContext) => VerifierSettings.AddScrubber(_ => _.Replace("One", "A")); } ``` <sup><a href='/src/Verify.MSTest.Tests/Scrubbers/ScrubberLevelsSample.cs#L1-L32' title='Snippet source file'>snippet source</a> | <a href='#snippet-ScrubberLevelsSampleMSTest' title='Start of snippet'>anchor</a></sup> <!-- endSnippet --> ### TUnit <!-- snippet: ScrubberLevelsSampleTUnit --> <a id='snippet-ScrubberLevelsSampleTUnit'></a> ```cs public class ScrubberLevelsSample { VerifySettings classLevelSettings; public ScrubberLevelsSample() { classLevelSettings = new(); classLevelSettings.AddScrubber(_ => _.Replace("Three", "C")); } [Test] public Task Simple() { var settings = new VerifySettings(classLevelSettings); settings.AddScrubber(_ => _.Replace("Two", "B")); return Verify("One Two Three", settings); } [Test] public Task SimpleFluent() => Verify("One Two Three", classLevelSettings) .AddScrubber(_ => _.Replace("Two", "B")); [ModuleInitializer] public static void Setup() => VerifierSettings.AddScrubber(_ => _.Replace("One", "A")); } ``` <sup><a href='/src/Verify.TUnit.Tests/Scrubbers/ScrubberLevelsSample.cs#L1-L31' title='Snippet source file'>snippet source</a> | <a href='#snippet-ScrubberLevelsSampleTUnit' title='Start of snippet'>anchor</a></sup> <!-- endSnippet --> ### Result <!-- snippet: Verify.Xunit.Tests/Scrubbers/ScrubberLevelsSample.Usage.verified.txt --> <a id='snippet-Verify.Xunit.Tests/Scrubbers/ScrubberLevelsSample.Usage.verified.txt'></a> ```txt A B C ``` <sup><a href='/src/Verify.Xunit.Tests/Scrubbers/ScrubberLevelsSample.Usage.verified.txt#L1-L1' title='Snippet source file'>snippet source</a> | <a href='#snippet-Verify.Xunit.Tests/Scrubbers/ScrubberLevelsSample.Usage.verified.txt' title='Start of snippet'>anchor</a></sup> <!-- endSnippet --> ## See also * [Guid behavior](guids.md) * [Date behavior](dates.md) * [Numeric Ids](numeric-ids.md)