diff --git a/docs/mdsource/serializer-settings.source.md b/docs/mdsource/serializer-settings.source.md
index 59ad45a583..0dbea591c7 100644
--- a/docs/mdsource/serializer-settings.source.md
+++ b/docs/mdsource/serializer-settings.source.md
@@ -195,6 +195,21 @@ Result:
snippet: SerializationTests.IgnoreType.verified.txt
+## Scrub a type
+
+To scrub all members that match a certain type:
+
+snippet: AddScrubType
+
+Or globally:
+
+snippet: AddScrubTypeGlobal
+
+Result:
+
+snippet: SerializationTests.ScrubType.verified.txt
+
+
## Ignoring a instance
To ignore instances of a type based on delegate:
@@ -210,6 +225,21 @@ Result:
snippet: SerializationTests.AddIgnoreInstance.verified.txt
+## Scrub a instance
+
+To scrub instances of a type based on delegate:
+
+snippet: AddScrubInstance
+
+Or globally:
+
+snippet: AddScrubInstanceGlobal
+
+Result:
+
+snippet: SerializationTests.AddScrubInstance.verified.txt
+
+
## Obsolete members ignored
Members with an [ObsoleteAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.obsoleteattribute) are ignored:
@@ -251,6 +281,21 @@ Result:
snippet: SerializationTests.IgnoreMemberByExpression.verified.txt
+## Scrub member by expressions
+
+To scrub members of a certain type using an expression:
+
+snippet: ScrubMemberByExpression
+
+Or globally
+
+snippet: ScrubMemberByExpressionGlobal
+
+Result:
+
+snippet: SerializationTests.ScrubMemberByExpression.verified.txt
+
+
## Ignore member by name
To ignore members of a certain type using type and name:
@@ -266,6 +311,21 @@ Result:
snippet: SerializationTests.IgnoreMemberByName.verified.txt
+## Scrub member by name
+
+To scrub members of a certain type using type and name:
+
+snippet: ScrubMemberByName
+
+Or globally:
+
+snippet: ScrubMemberByNameGlobal
+
+Result:
+
+snippet: SerializationTests.ScrubMemberByName.verified.txt
+
+
## Members that throw
Members that throw exceptions can be excluded from serialization based on the exception type or properties.
diff --git a/docs/named-tuples.md b/docs/named-tuples.md
index 6c50bc719c..3e564d2321 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 42db666122..44702a0983 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 fd49c79d21..357228d23a 100644
--- a/docs/serializer-settings.md
+++ b/docs/serializer-settings.md
@@ -100,7 +100,7 @@ VerifierSettings
.AddExtraSettings(_ =>
_.TypeNameHandling = TypeNameHandling.All);
```
-snippet source | anchor
+snippet source | anchor
@@ -120,7 +120,7 @@ public Task AddExtraSettings()
return Verify("Value", settings);
}
```
-snippet source | anchor
+snippet source | anchor
@@ -136,7 +136,7 @@ public Task AddExtraSettingsFluent() =>
_ => _.Error += (sender, args)
=> Console.WriteLine(args.ErrorContext.Member));
```
-snippet source | anchor
+snippet source | anchor
@@ -156,7 +156,7 @@ To disable this behavior globally use:
```cs
VerifierSettings.DontIgnoreEmptyCollections();
```
-snippet source | anchor
+snippet source | anchor
@@ -178,7 +178,7 @@ var target = new GuidTarget
await Verify(target);
```
-snippet source | anchor
+snippet source | anchor
Results in the following:
@@ -203,7 +203,7 @@ Strings containing inline Guids can also be scrubbed. To enable this behavior, u
```cs
VerifierSettings.ScrubInlineGuids();
```
-snippet source | anchor
+snippet source | anchor
@@ -218,7 +218,7 @@ var settings = new VerifySettings();
settings.DontScrubGuids();
await Verify(target, settings);
```
-snippet source | anchor
+snippet source | anchor
Or with the fluent api:
@@ -229,7 +229,7 @@ Or with the fluent api:
await Verify(target)
.DontScrubGuids();
```
-snippet source | anchor
+snippet source | anchor
To disable this behavior globally use:
@@ -239,7 +239,7 @@ To disable this behavior globally use:
```cs
VerifierSettings.DontScrubGuids();
```
-snippet source | anchor
+snippet source | anchor
@@ -267,7 +267,7 @@ var target = new DateTimeTarget
await Verify(target);
```
-snippet source | anchor
+snippet source | anchor
Results in the following:
@@ -305,7 +305,7 @@ settings.DontScrubDateTimes();
return Verify(target, settings);
```
-snippet source | anchor
+snippet source | anchor
Or using the fluent api use:
@@ -321,7 +321,7 @@ var target = new
return Verify(target)
.DontScrubDateTimes();
```
-snippet source | anchor
+snippet source | anchor
Or globally use:
@@ -331,7 +331,7 @@ Or globally use:
```cs
VerifierSettings.DontScrubDateTimes();
```
-snippet source | anchor
+snippet source | anchor
@@ -474,7 +474,7 @@ public Task ScopedSerializerFluent()
.AddExtraSettings(_ => _.TypeNameHandling = TypeNameHandling.All);
}
```
-snippet source | anchor
+snippet source | anchor
Result:
@@ -602,7 +602,7 @@ public Task IgnoreTypeFluent()
.IgnoreMembersWithType();
}
```
-snippet source | anchor
+snippet source | anchor
Or globally:
@@ -612,7 +612,7 @@ Or globally:
```cs
VerifierSettings.IgnoreMembersWithType();
```
-snippet source | anchor
+snippet source | anchor
Result:
@@ -639,6 +639,161 @@ Result:
+## Scrub a type
+
+To scrub all members that match a certain type:
+
+
+
+```cs
+[Fact]
+public Task ScrubType()
+{
+ var target = new IgnoreTypeTarget
+ {
+ ToIgnore = new()
+ {
+ Property = "Value"
+ },
+ ToIgnoreNullable = new()
+ {
+ Property = "Value"
+ },
+ ToIgnoreByInterface = new()
+ {
+ Property = "Value"
+ },
+ ToIgnoreByBase = new()
+ {
+ Property = "Value"
+ },
+ ToIgnoreByBaseGeneric = new()
+ {
+ Property = "Value"
+ },
+ ToIgnoreByType = new()
+ {
+ Property = "Value"
+ },
+ ToInclude = new()
+ {
+ Property = "Value"
+ },
+ ToIncludeNullable = new()
+ {
+ Property = "Value"
+ },
+ ToIgnoreStruct = new("Value"),
+ ToIgnoreStructNullable = new("Value"),
+ ToIncludeStruct = new("Value"),
+ ToIncludeStructNullable = new("Value")
+ };
+ var settings = new VerifySettings();
+ settings.ScrubMembersWithType();
+ settings.ScrubMembersWithType();
+ settings.ScrubMembersWithType();
+ settings.ScrubMembersWithType();
+ settings.ScrubMembersWithType(typeof(BaseToIgnoreGeneric<>));
+ settings.ScrubMembersWithType();
+ return Verify(target, settings);
+}
+
+[Fact]
+public Task ScrubTypeFluent()
+{
+ var target = new IgnoreTypeTarget
+ {
+ ToIgnore = new()
+ {
+ Property = "Value"
+ },
+ ToIgnoreNullable = new()
+ {
+ Property = "Value"
+ },
+ ToIgnoreByInterface = new()
+ {
+ Property = "Value"
+ },
+ ToIgnoreByBase = new()
+ {
+ Property = "Value"
+ },
+ ToIgnoreByBaseGeneric = new()
+ {
+ Property = "Value"
+ },
+ ToIgnoreByType = new()
+ {
+ Property = "Value"
+ },
+ ToInclude = new()
+ {
+ Property = "Value"
+ },
+ ToIncludeNullable = new()
+ {
+ Property = "Value"
+ },
+ ToIgnoreStruct = new("Value"),
+ ToIgnoreStructNullable = new("Value"),
+ ToIncludeStruct = new("Value"),
+ ToIncludeStructNullable = new("Value")
+ };
+ return Verify(target)
+ .ScrubMembersWithType()
+ .ScrubMembersWithType()
+ .ScrubMembersWithType()
+ .ScrubMembersWithType()
+ .ScrubMembersWithType(typeof(BaseToIgnoreGeneric<>))
+ .ScrubMembersWithType();
+}
+```
+snippet source | anchor
+
+
+Or globally:
+
+
+
+```cs
+VerifierSettings.ScrubMembersWithType();
+```
+snippet source | anchor
+
+
+Result:
+
+
+
+```txt
+{
+ ToIgnore: {Scrubbed},
+ ToIgnoreByType: {Scrubbed},
+ ToIgnoreByInterface: {Scrubbed},
+ ToIgnoreByBase: {Scrubbed},
+ ToIgnoreByBaseGeneric: {Scrubbed},
+ ToIgnoreNullable: {Scrubbed},
+ ToIgnoreStruct: {Scrubbed},
+ ToIgnoreStructNullable: {Scrubbed},
+ ToInclude: {
+ Property: Value
+ },
+ ToIncludeNullable: {
+ Property: Value
+ },
+ ToIncludeStruct: {
+ Property: Value
+ },
+ ToIncludeStructNullable: {
+ Property: Value
+ }
+}
+```
+snippet source | anchor
+
+
+
## Ignoring a instance
To ignore instances of a type based on delegate:
@@ -683,7 +838,7 @@ public Task AddIgnoreInstanceFluent()
.IgnoreInstance(_ => _.Property == "Ignore");
}
```
-snippet source | anchor
+snippet source | anchor
Or globally:
@@ -693,7 +848,7 @@ Or globally:
```cs
VerifierSettings.IgnoreInstance(_ => _.Property == "Ignore");
```
-snippet source | anchor
+snippet source | anchor
Result:
@@ -711,6 +866,79 @@ Result:
+## Scrub a instance
+
+To scrub instances of a type based on delegate:
+
+
+
+```cs
+[Fact]
+public Task AddScrubInstance()
+{
+ var target = new IgnoreInstanceTarget
+ {
+ ToIgnore = new()
+ {
+ Property = "Ignore"
+ },
+ ToInclude = new()
+ {
+ Property = "Include"
+ }
+ };
+ var settings = new VerifySettings();
+ settings.ScrubInstance(_ => _.Property == "Ignore");
+ return Verify(target, settings);
+}
+
+[Fact]
+public Task AddScrubInstanceFluent()
+{
+ var target = new IgnoreInstanceTarget
+ {
+ ToIgnore = new()
+ {
+ Property = "Ignore"
+ },
+ ToInclude = new()
+ {
+ Property = "Include"
+ }
+ };
+ return Verify(target)
+ .ScrubInstance(_ => _.Property == "Ignore");
+}
+```
+snippet source | anchor
+
+
+Or globally:
+
+
+
+```cs
+VerifierSettings.ScrubInstance(_ => _.Property == "Ignore");
+```
+snippet source | anchor
+
+
+Result:
+
+
+
+```txt
+{
+ ToIgnore: {Scrubbed},
+ ToInclude: {
+ Property: Include
+ }
+}
+```
+snippet source | anchor
+
+
+
## Obsolete members ignored
Members with an [ObsoleteAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.obsoleteattribute) are ignored:
@@ -736,7 +964,7 @@ public Task WithObsoleteProp()
return Verify(target);
}
```
-snippet source | anchor
+snippet source | anchor
Result:
@@ -784,7 +1012,7 @@ public Task WithObsoletePropIncludedFluent()
.IncludeObsoletes();
}
```
-snippet source | anchor
+snippet source | anchor
Or globally:
@@ -794,7 +1022,7 @@ Or globally:
```cs
VerifierSettings.IncludeObsoletes();
```
-snippet source | anchor
+snippet source | anchor
Result:
@@ -855,7 +1083,7 @@ public Task IgnoreMemberByExpressionFluent()
_ => _.PropertyThatThrows);
}
```
-snippet source | anchor
+snippet source | anchor
Or globally
@@ -870,7 +1098,7 @@ VerifierSettings.IgnoreMembers(
_ => _.GetOnlyProperty,
_ => _.PropertyThatThrows);
```
-snippet source | anchor
+snippet source | anchor
Result:
@@ -886,6 +1114,86 @@ Result:
+## Scrub member by expressions
+
+To scrub members of a certain type using an expression:
+
+
+
+```cs
+[Fact]
+public Task ScrubMemberByExpression()
+{
+ var target = new IgnoreExplicitTarget
+ {
+ Include = "Value",
+ Field = "Value",
+ Property = "Value",
+ PropertyWithPropertyName = "Value"
+ };
+ var settings = new VerifySettings();
+ settings.ScrubMembers(
+ _ => _.Property,
+ _ => _.PropertyWithPropertyName,
+ _ => _.Field,
+ _ => _.GetOnlyProperty,
+ _ => _.PropertyThatThrows);
+ return Verify(target, settings);
+}
+
+[Fact]
+public Task ScrubMemberByExpressionFluent()
+{
+ var target = new IgnoreExplicitTarget
+ {
+ Include = "Value",
+ Field = "Value",
+ Property = "Value"
+ };
+ return Verify(target)
+ .ScrubMembers(
+ _ => _.Property,
+ _ => _.Field,
+ _ => _.GetOnlyProperty,
+ _ => _.PropertyThatThrows);
+}
+```
+snippet source | anchor
+
+
+Or globally
+
+
+
+```cs
+VerifierSettings.ScrubMembers(
+ _ => _.Property,
+ _ => _.PropertyWithPropertyName,
+ _ => _.Field,
+ _ => _.GetOnlyProperty,
+ _ => _.PropertyThatThrows);
+```
+snippet source | anchor
+
+
+Result:
+
+
+
+```txt
+{
+ Include: Value,
+ Field: {Scrubbed},
+ Property: {Scrubbed},
+ _Custom: {Scrubbed},
+ GetOnlyProperty: {Scrubbed},
+ PropertyThatThrows: {Scrubbed}
+}
+```
+snippet source | anchor
+
+
+
## Ignore member by name
To ignore members of a certain type using type and name:
@@ -944,7 +1252,7 @@ public Task IgnoreMemberByNameFluent()
.IgnoreMember(_ => _.PropertyThatThrows);
}
```
-snippet source | anchor
+snippet source | anchor
Or globally:
@@ -964,7 +1272,7 @@ VerifierSettings.IgnoreMember("Field");
// For a specific type with expression
VerifierSettings.IgnoreMember(_ => _.PropertyThatThrows);
```
-snippet source | anchor
+snippet source | anchor
Result:
@@ -981,6 +1289,104 @@ Result:
+## Scrub member by name
+
+To scrub members of a certain type using type and name:
+
+
+
+```cs
+[Fact]
+public Task ScrubMemberByName()
+{
+ var target = new IgnoreExplicitTarget
+ {
+ Include = "Value",
+ Field = "Value",
+ Property = "Value",
+ PropertyByName = "Value"
+ };
+ var settings = new VerifySettings();
+
+ // For all types
+ settings.ScrubMember("PropertyByName");
+
+ // For a specific type
+ settings.ScrubMember(typeof(IgnoreExplicitTarget), "Property");
+
+ // For a specific type generic
+ settings.ScrubMember("Field");
+
+ // For a specific type with expression
+ settings.ScrubMember(_ => _.PropertyThatThrows);
+
+ return Verify(target, settings);
+}
+
+[Fact]
+public Task ScrubMemberByNameFluent()
+{
+ var target = new IgnoreExplicitTarget
+ {
+ Include = "Value",
+ Field = "Value",
+ Property = "Value",
+ PropertyByName = "Value"
+ };
+ return Verify(target)
+ // For all types
+ .ScrubMember("PropertyByName")
+
+ // For a specific type
+ .ScrubMember(typeof(IgnoreExplicitTarget), "Property")
+
+ // For a specific type generic
+ .ScrubMember("Field")
+
+ // For a specific type with expression
+ .ScrubMember(_ => _.PropertyThatThrows);
+}
+```
+snippet source | anchor
+
+
+Or globally:
+
+
+
+```cs
+// For all types
+VerifierSettings.ScrubMember("PropertyByName");
+
+// For a specific type
+VerifierSettings.ScrubMember(typeof(IgnoreExplicitTarget), "Property");
+
+// For a specific type generic
+VerifierSettings.ScrubMember("Field");
+
+// For a specific type with expression
+VerifierSettings.ScrubMember(_ => _.PropertyThatThrows);
+```
+snippet source | anchor
+
+
+Result:
+
+
+
+```txt
+{
+ Include: Value,
+ Field: {Scrubbed},
+ Property: {Scrubbed},
+ GetOnlyProperty: asd,
+ PropertyThatThrows: {Scrubbed}
+}
+```
+snippet source | anchor
+
+
+
## Members that throw
Members that throw exceptions can be excluded from serialization based on the exception type or properties.
@@ -1011,7 +1417,7 @@ public Task CustomExceptionPropFluent()
.IgnoreMembersThatThrow();
}
```
-snippet source | anchor
+snippet source | anchor
Or globally:
@@ -1021,7 +1427,7 @@ Or globally:
```cs
VerifierSettings.IgnoreMembersThatThrow();
```
-snippet source | anchor
+snippet source | anchor
Result:
@@ -1058,7 +1464,7 @@ public Task ExceptionMessagePropFluent()
.IgnoreMembersThatThrow(_ => _.Message == "Ignore");
}
```
-snippet source | anchor
+snippet source | anchor
Or globally:
@@ -1068,7 +1474,7 @@ Or globally:
```cs
VerifierSettings.IgnoreMembersThatThrow(_ => _.Message == "Ignore");
```
-snippet source | anchor
+snippet source | anchor
Result:
@@ -1234,7 +1640,7 @@ public Task MemberConverterByExpression()
return Verify(input);
}
```
-snippet source | anchor
+snippet source | anchor
diff --git a/readme.md b/readme.md
index 5fc38e65fb..8e77d93916 100644
--- a/readme.md
+++ b/readme.md
@@ -355,7 +355,7 @@ public Task VerifyJsonJToken()
return VerifyJson(target);
}
```
-snippet source | anchor
+snippet source | anchor
Results in:
diff --git a/src/Verify.Tests/Serialization/SerializationTests.AddScrubInstance.verified.txt b/src/Verify.Tests/Serialization/SerializationTests.AddScrubInstance.verified.txt
new file mode 100644
index 0000000000..3ff5444e8e
--- /dev/null
+++ b/src/Verify.Tests/Serialization/SerializationTests.AddScrubInstance.verified.txt
@@ -0,0 +1,6 @@
+{
+ ToIgnore: {Scrubbed},
+ ToInclude: {
+ Property: Include
+ }
+}
\ No newline at end of file
diff --git a/src/Verify.Tests/Serialization/SerializationTests.AddScrubInstanceFluent.verified.txt b/src/Verify.Tests/Serialization/SerializationTests.AddScrubInstanceFluent.verified.txt
new file mode 100644
index 0000000000..3ff5444e8e
--- /dev/null
+++ b/src/Verify.Tests/Serialization/SerializationTests.AddScrubInstanceFluent.verified.txt
@@ -0,0 +1,6 @@
+{
+ ToIgnore: {Scrubbed},
+ ToInclude: {
+ Property: Include
+ }
+}
\ No newline at end of file
diff --git a/src/Verify.Tests/Serialization/SerializationTests.JTokenScrub.verified.txt b/src/Verify.Tests/Serialization/SerializationTests.JTokenScrub.verified.txt
new file mode 100644
index 0000000000..a0031ffc51
--- /dev/null
+++ b/src/Verify.Tests/Serialization/SerializationTests.JTokenScrub.verified.txt
@@ -0,0 +1,3 @@
+{
+ Include: 1
+}
\ No newline at end of file
diff --git a/src/Verify.Tests/Serialization/SerializationTests.ScrubDictionaryKeyByName.verified.txt b/src/Verify.Tests/Serialization/SerializationTests.ScrubDictionaryKeyByName.verified.txt
new file mode 100644
index 0000000000..9547bb8454
--- /dev/null
+++ b/src/Verify.Tests/Serialization/SerializationTests.ScrubDictionaryKeyByName.verified.txt
@@ -0,0 +1,6 @@
+{
+ Include: {
+ Key1: Value2
+ },
+ Key2: Value4
+}
\ No newline at end of file
diff --git a/src/Verify.Tests/Serialization/SerializationTests.ScrubJTokenByName.verified.txt b/src/Verify.Tests/Serialization/SerializationTests.ScrubJTokenByName.verified.txt
new file mode 100644
index 0000000000..11bd9fd4a0
--- /dev/null
+++ b/src/Verify.Tests/Serialization/SerializationTests.ScrubJTokenByName.verified.txt
@@ -0,0 +1,8 @@
+{
+ short: {
+ key: {
+ code: 0,
+ msg: No action taken
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Verify.Tests/Serialization/SerializationTests.ScrubMemberByExpression.verified.txt b/src/Verify.Tests/Serialization/SerializationTests.ScrubMemberByExpression.verified.txt
new file mode 100644
index 0000000000..0b85fd8e34
--- /dev/null
+++ b/src/Verify.Tests/Serialization/SerializationTests.ScrubMemberByExpression.verified.txt
@@ -0,0 +1,8 @@
+{
+ Include: Value,
+ Field: {Scrubbed},
+ Property: {Scrubbed},
+ _Custom: {Scrubbed},
+ GetOnlyProperty: {Scrubbed},
+ PropertyThatThrows: {Scrubbed}
+}
\ No newline at end of file
diff --git a/src/Verify.Tests/Serialization/SerializationTests.ScrubMemberByExpressionFluent.verified.txt b/src/Verify.Tests/Serialization/SerializationTests.ScrubMemberByExpressionFluent.verified.txt
new file mode 100644
index 0000000000..3940c6e307
--- /dev/null
+++ b/src/Verify.Tests/Serialization/SerializationTests.ScrubMemberByExpressionFluent.verified.txt
@@ -0,0 +1,7 @@
+{
+ Include: Value,
+ Field: {Scrubbed},
+ Property: {Scrubbed},
+ GetOnlyProperty: {Scrubbed},
+ PropertyThatThrows: {Scrubbed}
+}
\ No newline at end of file
diff --git a/src/Verify.Tests/Serialization/SerializationTests.ScrubMemberByName.verified.txt b/src/Verify.Tests/Serialization/SerializationTests.ScrubMemberByName.verified.txt
new file mode 100644
index 0000000000..a8e75c6d84
--- /dev/null
+++ b/src/Verify.Tests/Serialization/SerializationTests.ScrubMemberByName.verified.txt
@@ -0,0 +1,7 @@
+{
+ Include: Value,
+ Field: {Scrubbed},
+ Property: {Scrubbed},
+ GetOnlyProperty: asd,
+ PropertyThatThrows: {Scrubbed}
+}
\ No newline at end of file
diff --git a/src/Verify.Tests/Serialization/SerializationTests.ScrubMemberByNameFluent.verified.txt b/src/Verify.Tests/Serialization/SerializationTests.ScrubMemberByNameFluent.verified.txt
new file mode 100644
index 0000000000..a8e75c6d84
--- /dev/null
+++ b/src/Verify.Tests/Serialization/SerializationTests.ScrubMemberByNameFluent.verified.txt
@@ -0,0 +1,7 @@
+{
+ Include: Value,
+ Field: {Scrubbed},
+ Property: {Scrubbed},
+ GetOnlyProperty: asd,
+ PropertyThatThrows: {Scrubbed}
+}
\ No newline at end of file
diff --git a/src/Verify.Tests/Serialization/SerializationTests.ScrubMembersNullable.verified.txt b/src/Verify.Tests/Serialization/SerializationTests.ScrubMembersNullable.verified.txt
new file mode 100644
index 0000000000..25c4bec55f
--- /dev/null
+++ b/src/Verify.Tests/Serialization/SerializationTests.ScrubMembersNullable.verified.txt
@@ -0,0 +1,3 @@
+{
+ Property: {Scrubbed}
+}
\ No newline at end of file
diff --git a/src/Verify.Tests/Serialization/SerializationTests.ScrubMembersNullableNested.verified.txt b/src/Verify.Tests/Serialization/SerializationTests.ScrubMembersNullableNested.verified.txt
new file mode 100644
index 0000000000..26cde96b93
--- /dev/null
+++ b/src/Verify.Tests/Serialization/SerializationTests.ScrubMembersNullableNested.verified.txt
@@ -0,0 +1,3 @@
+{
+ ToIgnoreStruct: {Scrubbed}
+}
\ No newline at end of file
diff --git a/src/Verify.Tests/Serialization/SerializationTests.ScrubType.verified.txt b/src/Verify.Tests/Serialization/SerializationTests.ScrubType.verified.txt
new file mode 100644
index 0000000000..0d678d8899
--- /dev/null
+++ b/src/Verify.Tests/Serialization/SerializationTests.ScrubType.verified.txt
@@ -0,0 +1,22 @@
+{
+ ToIgnore: {Scrubbed},
+ ToIgnoreByType: {Scrubbed},
+ ToIgnoreByInterface: {Scrubbed},
+ ToIgnoreByBase: {Scrubbed},
+ ToIgnoreByBaseGeneric: {Scrubbed},
+ ToIgnoreNullable: {Scrubbed},
+ ToIgnoreStruct: {Scrubbed},
+ ToIgnoreStructNullable: {Scrubbed},
+ ToInclude: {
+ Property: Value
+ },
+ ToIncludeNullable: {
+ Property: Value
+ },
+ ToIncludeStruct: {
+ Property: Value
+ },
+ ToIncludeStructNullable: {
+ Property: Value
+ }
+}
\ No newline at end of file
diff --git a/src/Verify.Tests/Serialization/SerializationTests.ScrubTypeFluent.verified.txt b/src/Verify.Tests/Serialization/SerializationTests.ScrubTypeFluent.verified.txt
new file mode 100644
index 0000000000..0d678d8899
--- /dev/null
+++ b/src/Verify.Tests/Serialization/SerializationTests.ScrubTypeFluent.verified.txt
@@ -0,0 +1,22 @@
+{
+ ToIgnore: {Scrubbed},
+ ToIgnoreByType: {Scrubbed},
+ ToIgnoreByInterface: {Scrubbed},
+ ToIgnoreByBase: {Scrubbed},
+ ToIgnoreByBaseGeneric: {Scrubbed},
+ ToIgnoreNullable: {Scrubbed},
+ ToIgnoreStruct: {Scrubbed},
+ ToIgnoreStructNullable: {Scrubbed},
+ ToInclude: {
+ Property: Value
+ },
+ ToIncludeNullable: {
+ Property: Value
+ },
+ ToIncludeStruct: {
+ Property: Value
+ },
+ ToIncludeStructNullable: {
+ Property: Value
+ }
+}
\ No newline at end of file
diff --git a/src/Verify.Tests/Serialization/SerializationTests.cs b/src/Verify.Tests/Serialization/SerializationTests.cs
index 3b5631363c..c4a19bec34 100644
--- a/src/Verify.Tests/Serialization/SerializationTests.cs
+++ b/src/Verify.Tests/Serialization/SerializationTests.cs
@@ -148,6 +148,24 @@ public Task JTokenIgnore()
.IgnoreMembers("Ignore", "Memory Info");
}
+ [Fact]
+ public Task JTokenScrub()
+ {
+ var jToken = JToken.Parse(@"{
+ Include: 1,
+ Ignore: 2,
+ ""Memory Info"": {
+ fragmentedBytes: 208,
+ heapSizeBytes: 2479536,
+ highMemoryLoadThresholdBytes: 30821986713,
+ memoryLoadBytes: 14041127280,
+ totalAvailableMemoryBytes: 34246651904
+ }
+}");
+ return Verify(jToken)
+ .ScrubMembers("Ignore", "Memory Info");
+ }
+
[Fact]
public Task JObjectIgnore()
{
@@ -375,12 +393,14 @@ public void SettingsIsCloned()
Assert.True(clone.GetShouldIgnoreInstance(GetType(), out var shouldIgnores));
var shouldIgnore = shouldIgnores.Single();
- Assert.True(shouldIgnore(this));
- Assert.False(shouldIgnore("notIgnored"));
- Assert.True(clone.ShouldIgnoreForMemberOfType(GetType(), "ignored"));
- Assert.False(clone.ShouldIgnoreForMemberOfType(GetType(), "notIgnored"));
- Assert.True(clone.ShouldIgnoreByName("ignored"));
- Assert.False(clone.ShouldIgnoreByName("notIgnored"));
+ Assert.Equal(ScrubOrIgnore.Ignore, shouldIgnore(this));
+ Assert.Null(shouldIgnore("notIgnored"));
+ Assert.True(clone.TryGetScrubOrIgnoreByMemberOfType(GetType(), "ignored", out var scrubOrIgnore));
+ Assert.Equal(ScrubOrIgnore.Ignore, scrubOrIgnore);
+ Assert.False(clone.TryGetScrubOrIgnoreByMemberOfType(GetType(), "notIgnored", out scrubOrIgnore));
+ Assert.True(clone.TryGetScrubOrIgnoreByName("ignored", out scrubOrIgnore));
+ Assert.Equal(ScrubOrIgnore.Ignore, scrubOrIgnore);
+ Assert.False(clone.TryGetScrubOrIgnoreByName("notIgnored", out scrubOrIgnore));
}
[Fact]
@@ -1683,6 +1703,11 @@ void AddIgnoreInstanceGlobal()
VerifierSettings.IgnoreInstance(_ => _.Property == "Ignore");
+ #endregion
+ #region AddScrubInstanceGlobal
+
+ VerifierSettings.ScrubInstance(_ => _.Property == "Ignore");
+
#endregion
}
@@ -1727,6 +1752,47 @@ public Task AddIgnoreInstanceFluent()
#endregion
+ #region AddScrubInstance
+
+ [Fact]
+ public Task AddScrubInstance()
+ {
+ var target = new IgnoreInstanceTarget
+ {
+ ToIgnore = new()
+ {
+ Property = "Ignore"
+ },
+ ToInclude = new()
+ {
+ Property = "Include"
+ }
+ };
+ var settings = new VerifySettings();
+ settings.ScrubInstance(_ => _.Property == "Ignore");
+ return Verify(target, settings);
+ }
+
+ [Fact]
+ public Task AddScrubInstanceFluent()
+ {
+ var target = new IgnoreInstanceTarget
+ {
+ ToIgnore = new()
+ {
+ Property = "Ignore"
+ },
+ ToInclude = new()
+ {
+ Property = "Include"
+ }
+ };
+ return Verify(target)
+ .ScrubInstance(_ => _.Property == "Ignore");
+ }
+
+ #endregion
+
[Fact]
public Task AddIgnoreInstanceInList()
{
@@ -1762,6 +1828,11 @@ void AddIgnoreTypeGlobal()
VerifierSettings.IgnoreMembersWithType();
+ #endregion
+ #region AddScrubTypeGlobal
+
+ VerifierSettings.ScrubMembersWithType();
+
#endregion
}
@@ -1872,6 +1943,114 @@ public Task IgnoreTypeFluent()
#endregion
+
+ #region AddScrubType
+
+ [Fact]
+ public Task ScrubType()
+ {
+ var target = new IgnoreTypeTarget
+ {
+ ToIgnore = new()
+ {
+ Property = "Value"
+ },
+ ToIgnoreNullable = new()
+ {
+ Property = "Value"
+ },
+ ToIgnoreByInterface = new()
+ {
+ Property = "Value"
+ },
+ ToIgnoreByBase = new()
+ {
+ Property = "Value"
+ },
+ ToIgnoreByBaseGeneric = new()
+ {
+ Property = "Value"
+ },
+ ToIgnoreByType = new()
+ {
+ Property = "Value"
+ },
+ ToInclude = new()
+ {
+ Property = "Value"
+ },
+ ToIncludeNullable = new()
+ {
+ Property = "Value"
+ },
+ ToIgnoreStruct = new("Value"),
+ ToIgnoreStructNullable = new("Value"),
+ ToIncludeStruct = new("Value"),
+ ToIncludeStructNullable = new("Value")
+ };
+ var settings = new VerifySettings();
+ settings.ScrubMembersWithType();
+ settings.ScrubMembersWithType();
+ settings.ScrubMembersWithType();
+ settings.ScrubMembersWithType();
+ settings.ScrubMembersWithType(typeof(BaseToIgnoreGeneric<>));
+ settings.ScrubMembersWithType();
+ return Verify(target, settings);
+ }
+
+ [Fact]
+ public Task ScrubTypeFluent()
+ {
+ var target = new IgnoreTypeTarget
+ {
+ ToIgnore = new()
+ {
+ Property = "Value"
+ },
+ ToIgnoreNullable = new()
+ {
+ Property = "Value"
+ },
+ ToIgnoreByInterface = new()
+ {
+ Property = "Value"
+ },
+ ToIgnoreByBase = new()
+ {
+ Property = "Value"
+ },
+ ToIgnoreByBaseGeneric = new()
+ {
+ Property = "Value"
+ },
+ ToIgnoreByType = new()
+ {
+ Property = "Value"
+ },
+ ToInclude = new()
+ {
+ Property = "Value"
+ },
+ ToIncludeNullable = new()
+ {
+ Property = "Value"
+ },
+ ToIgnoreStruct = new("Value"),
+ ToIgnoreStructNullable = new("Value"),
+ ToIncludeStruct = new("Value"),
+ ToIncludeStructNullable = new("Value")
+ };
+ return Verify(target)
+ .ScrubMembersWithType()
+ .ScrubMembersWithType()
+ .ScrubMembersWithType()
+ .ScrubMembersWithType()
+ .ScrubMembersWithType(typeof(BaseToIgnoreGeneric<>))
+ .ScrubMembersWithType();
+ }
+
+ #endregion
+
[Fact]
public Task IgnoreMembersNullable()
{
@@ -1881,6 +2060,15 @@ public Task IgnoreMembersNullable()
.IgnoreMembers(_ => _.Property);
}
+ [Fact]
+ public Task ScrubMembersNullable()
+ {
+ ToIgnoreStruct? toIgnoreStruct = new ToIgnoreStruct("Value");
+
+ return Verify(toIgnoreStruct)
+ .ScrubMembers(_ => _.Property);
+ }
+
[Fact]
public Task IgnoreMembersNullableNested()
{
@@ -1893,6 +2081,18 @@ public Task IgnoreMembersNullableNested()
.IgnoreMembers(_ => _.ToIgnoreStruct);
}
+ [Fact]
+ public Task ScrubMembersNullableNested()
+ {
+ var target = new IgnoreMembersNullableNestedTarget
+ {
+ ToIgnoreStruct = new ToIgnoreStruct("Value")
+ };
+
+ return Verify(target)
+ .ScrubMembers(_ => _.ToIgnoreStruct);
+ }
+
class IgnoreMembersNullableNestedTarget
{
public ToIgnoreStruct? ToIgnoreStruct { get; set; }
@@ -2048,6 +2248,16 @@ void IgnoreMemberByExpressionGlobal()
_ => _.PropertyThatThrows);
#endregion
+ #region ScrubMemberByExpressionGlobal
+
+ VerifierSettings.ScrubMembers(
+ _ => _.Property,
+ _ => _.PropertyWithPropertyName,
+ _ => _.Field,
+ _ => _.GetOnlyProperty,
+ _ => _.PropertyThatThrows);
+
+ #endregion
}
#region IgnoreMemberByExpression
@@ -2091,6 +2301,47 @@ public Task IgnoreMemberByExpressionFluent()
#endregion
+ #region ScrubMemberByExpression
+
+ [Fact]
+ public Task ScrubMemberByExpression()
+ {
+ var target = new IgnoreExplicitTarget
+ {
+ Include = "Value",
+ Field = "Value",
+ Property = "Value",
+ PropertyWithPropertyName = "Value"
+ };
+ var settings = new VerifySettings();
+ settings.ScrubMembers(
+ _ => _.Property,
+ _ => _.PropertyWithPropertyName,
+ _ => _.Field,
+ _ => _.GetOnlyProperty,
+ _ => _.PropertyThatThrows);
+ return Verify(target, settings);
+ }
+
+ [Fact]
+ public Task ScrubMemberByExpressionFluent()
+ {
+ var target = new IgnoreExplicitTarget
+ {
+ Include = "Value",
+ Field = "Value",
+ Property = "Value"
+ };
+ return Verify(target)
+ .ScrubMembers(
+ _ => _.Property,
+ _ => _.Field,
+ _ => _.GetOnlyProperty,
+ _ => _.PropertyThatThrows);
+ }
+
+ #endregion
+
#region MemberConverter
[Fact]
@@ -2139,6 +2390,21 @@ void IgnoreMemberByNameGlobal()
// For a specific type with expression
VerifierSettings.IgnoreMember(_ => _.PropertyThatThrows);
+ #endregion
+ #region ScrubMemberByNameGlobal
+
+ // For all types
+ VerifierSettings.ScrubMember("PropertyByName");
+
+ // For a specific type
+ VerifierSettings.ScrubMember(typeof(IgnoreExplicitTarget), "Property");
+
+ // For a specific type generic
+ VerifierSettings.ScrubMember("Field");
+
+ // For a specific type with expression
+ VerifierSettings.ScrubMember(_ => _.PropertyThatThrows);
+
#endregion
}
@@ -2197,6 +2463,61 @@ public Task IgnoreMemberByNameFluent()
#endregion
+ #region ScrubMemberByName
+
+ [Fact]
+ public Task ScrubMemberByName()
+ {
+ var target = new IgnoreExplicitTarget
+ {
+ Include = "Value",
+ Field = "Value",
+ Property = "Value",
+ PropertyByName = "Value"
+ };
+ var settings = new VerifySettings();
+
+ // For all types
+ settings.ScrubMember("PropertyByName");
+
+ // For a specific type
+ settings.ScrubMember(typeof(IgnoreExplicitTarget), "Property");
+
+ // For a specific type generic
+ settings.ScrubMember("Field");
+
+ // For a specific type with expression
+ settings.ScrubMember(_ => _.PropertyThatThrows);
+
+ return Verify(target, settings);
+ }
+
+ [Fact]
+ public Task ScrubMemberByNameFluent()
+ {
+ var target = new IgnoreExplicitTarget
+ {
+ Include = "Value",
+ Field = "Value",
+ Property = "Value",
+ PropertyByName = "Value"
+ };
+ return Verify(target)
+ // For all types
+ .ScrubMember("PropertyByName")
+
+ // For a specific type
+ .ScrubMember(typeof(IgnoreExplicitTarget), "Property")
+
+ // For a specific type generic
+ .ScrubMember("Field")
+
+ // For a specific type with expression
+ .ScrubMember(_ => _.PropertyThatThrows);
+ }
+
+ #endregion
+
public class IgnoreTargetBase
{
public string Property { get; set; }
@@ -2230,6 +2551,24 @@ public Task IgnoreJTokenByName()
var target = JToken.Parse(json);
return Verify(target).IgnoreMember("Ignore1");
}
+ [Fact]
+ public Task ScrubJTokenByName()
+ {
+ var json = @"{
+ 'short': {
+ 'key': {
+ 'code': 0,
+ 'msg': 'No action taken'
+ },
+ 'Ignore1': {
+ 'code': 2,
+ 'msg': 'ignore this'
+ }
+ }
+}";
+ var target = JToken.Parse(json);
+ return Verify(target).ScrubMember("Ignore1");
+ }
[Fact]
public Task VerifyJsonGuid()
@@ -2324,6 +2663,25 @@ public Task IgnoreDictionaryKeyByName()
.IgnoreMember("Ignore");
}
+ [Fact]
+ public Task ScrubDictionaryKeyByName()
+ {
+ var target = new Dictionary
+ {
+ {
+ "Include", new Dictionary
+ {
+ {"Ignore", "Value1"},
+ {"Key1", "Value2"}
+ }
+ },
+ {"Ignore", "Value3"},
+ {"Key2", "Value4"}
+ };
+ return Verify(target)
+ .ScrubMember("Ignore");
+ }
+
class IgnoreExplicitTarget
{
public string Include;
@@ -2452,7 +2810,6 @@ class WithNotSupportedException
public Guid NotImplementedExceptionProperty => throw new NotSupportedException();
}
-
void WithObsoletePropIncludedGlobally()
{
#region WithObsoletePropIncludedGlobally
diff --git a/src/Verify/Extensions.cs b/src/Verify/Extensions.cs
index 6405947fc5..13d5c1a17b 100644
--- a/src/Verify/Extensions.cs
+++ b/src/Verify/Extensions.cs
@@ -5,6 +5,12 @@ static class Extensions
public static List Clone(this List original) =>
new(original);
+ public static Dictionary Clone(this Dictionary original)
+ where TValue : struct where TKey : notnull => new(original);
+
+ public static Dictionary Clone(this Dictionary original)
+ where TValue : struct where TKey : notnull => new(original);
+
public static string TrimEnd(this string input, string suffixToRemove, StringComparison comparisonType = StringComparison.CurrentCulture)
{
if (input.EndsWith(suffixToRemove, comparisonType))
diff --git a/src/Verify/Serialization/ArrayConverter.cs b/src/Verify/Serialization/ArrayConverter.cs
index 534ddf20e9..c40e1ce15d 100644
--- a/src/Verify/Serialization/ArrayConverter.cs
+++ b/src/Verify/Serialization/ArrayConverter.cs
@@ -5,9 +5,18 @@ public override bool CanConvert(Type objectType) =>
public override void Write(VerifyJsonWriter writer, object value)
{
- if (!writer.serialization.ShouldSerialize(value))
+ if (writer.serialization.TryGetScrubOrIgnoreByInstance(value, out var scrubOrIgnore))
{
- return;
+ if (scrubOrIgnore == ScrubOrIgnore.Ignore)
+ {
+ return;
+ }
+
+ if (scrubOrIgnore == ScrubOrIgnore.Scrub)
+ {
+ writer.WriteRaw("{Scrubbed}");
+ return;
+ }
}
Type? type = null;
diff --git a/src/Verify/Serialization/Converters/DictionaryConverter.cs b/src/Verify/Serialization/Converters/DictionaryConverter.cs
index 1db7db77c9..7e858dec65 100644
--- a/src/Verify/Serialization/Converters/DictionaryConverter.cs
+++ b/src/Verify/Serialization/Converters/DictionaryConverter.cs
@@ -32,7 +32,12 @@ public override void Write(VerifyJsonWriter writer, object value)
var valueType = genericArguments.Last();
var keyType = genericArguments.First();
var definition = type.GetGenericTypeDefinition();
- Func shouldIgnoreByName = _ => writer.serialization.ShouldIgnoreByName(_);
+ Func shouldIgnoreByName = _ =>
+ {
+ writer.serialization.TryGetScrubOrIgnoreByName(_, out var scrubOrIgnore);
+ return scrubOrIgnore;
+ };
+
if (definition == typeof(SortedDictionary<,>) ||
definition.Name == "ImmutableSortedDictionary`2")
{
diff --git a/src/Verify/Serialization/CustomContractResolver.cs b/src/Verify/Serialization/CustomContractResolver.cs
index 80e016f3b6..3652578561 100644
--- a/src/Verify/Serialization/CustomContractResolver.cs
+++ b/src/Verify/Serialization/CustomContractResolver.cs
@@ -103,6 +103,21 @@ protected override JsonProperty CreateProperty(MemberInfo member, MemberSerializ
return property;
}
+ if (settings.TryGetScrubOrIgnore(member, out var scrubOrIgnore))
+ {
+ if (scrubOrIgnore == ScrubOrIgnore.Ignore)
+ {
+ property.Ignored = true;
+ }
+ else
+ {
+ property.PropertyType = typeof(string);
+ property.ValueProvider = new ScrubbedProvider();
+ }
+
+ return property;
+ }
+
if (member.Name == "Message")
{
if (member.DeclaringType == typeof(ArgumentException))
@@ -121,21 +136,12 @@ protected override JsonProperty CreateProperty(MemberInfo member, MemberSerializ
property.DefaultValueHandling = DefaultValueHandling.Include;
}
- if (settings.ShouldIgnore(member))
- {
- property.Ignored = true;
- return property;
- }
-
property.ValueProvider = new CustomValueProvider(
valueProvider,
memberType,
exception => settings.ShouldIgnoreException(exception),
- VerifierSettings.GetMemberConverter(member));
- if (settings.TryGetShouldSerialize(memberType, property.ValueProvider.GetValue, out var shouldSerialize))
- {
- property.ShouldSerialize = shouldSerialize;
- }
+ VerifierSettings.GetMemberConverter(member),
+ settings);
return property;
}
diff --git a/src/Verify/Serialization/CustomValueProvider.cs b/src/Verify/Serialization/CustomValueProvider.cs
index 2209bb86ad..f0c77f3183 100644
--- a/src/Verify/Serialization/CustomValueProvider.cs
+++ b/src/Verify/Serialization/CustomValueProvider.cs
@@ -5,17 +5,19 @@
Type memberType;
Func shouldIgnoreException;
ConvertTargetMember? membersConverter;
+ SerializationSettings settings;
- public CustomValueProvider(
- IValueProvider inner,
+ public CustomValueProvider(IValueProvider inner,
Type memberType,
Func shouldIgnoreException,
- ConvertTargetMember? membersConverter)
+ ConvertTargetMember? membersConverter,
+ SerializationSettings settings)
{
this.inner = inner;
this.memberType = memberType;
this.shouldIgnoreException = shouldIgnoreException;
this.membersConverter = membersConverter;
+ this.settings = settings;
}
public void SetValue(object target, object? value) =>
@@ -31,7 +33,20 @@ public void SetValue(object target, object? value) =>
try
{
- return inner.GetValue(target);
+ var value = inner.GetValue(target);
+ if (value != null &&
+ settings.TryGetScrubOrIgnoreByInstance(value, out var scrubOrIgnore))
+ {
+ if (scrubOrIgnore == ScrubOrIgnore.Ignore)
+ {
+ return null;
+ }
+ if (scrubOrIgnore == ScrubOrIgnore.Scrub)
+ {
+ return "{Scrubbed}";
+ }
+ }
+ return value;
}
catch (Exception exception)
{
diff --git a/src/Verify/Serialization/ScrubOrIgnore.cs b/src/Verify/Serialization/ScrubOrIgnore.cs
new file mode 100644
index 0000000000..08bcc7fa6a
--- /dev/null
+++ b/src/Verify/Serialization/ScrubOrIgnore.cs
@@ -0,0 +1,5 @@
+enum ScrubOrIgnore
+{
+ Scrub,
+ Ignore
+}
\ No newline at end of file
diff --git a/src/Verify/Serialization/ScrubbedProvider.cs b/src/Verify/Serialization/ScrubbedProvider.cs
new file mode 100644
index 0000000000..08f4527593
--- /dev/null
+++ b/src/Verify/Serialization/ScrubbedProvider.cs
@@ -0,0 +1,8 @@
+class ScrubbedProvider : IValueProvider
+{
+ public void SetValue(object target, object? value) =>
+ throw new NotImplementedException();
+
+ public object GetValue(object target) =>
+ "{Scrubbed}";
+}
\ No newline at end of file
diff --git a/src/Verify/Serialization/Scrubbers/DictionaryWrappers/OrderedStringDictionaryWrapper.cs b/src/Verify/Serialization/Scrubbers/DictionaryWrappers/OrderedStringDictionaryWrapper.cs
index df88859da0..14dce5c490 100644
--- a/src/Verify/Serialization/Scrubbers/DictionaryWrappers/OrderedStringDictionaryWrapper.cs
+++ b/src/Verify/Serialization/Scrubbers/DictionaryWrappers/OrderedStringDictionaryWrapper.cs
@@ -1,13 +1,35 @@
class OrderedStringDictionaryWrapper :
- Dictionary,
+ Dictionary,
IDictionaryWrapper
where TInner : IDictionary
{
- public OrderedStringDictionaryWrapper(Func shouldIgnore, TInner inner) :
- base(inner
- .Where(_ => !shouldIgnore(_.Key))
- .OrderBy(_ => _.Key, StringComparer.OrdinalIgnoreCase)
- .ToDictionary(_ => _.Key, _ => _.Value))
+ public OrderedStringDictionaryWrapper(Func shouldIgnore, TInner inner) :
+ base(BuildInner(shouldIgnore, inner))
{
}
+
+ static Dictionary BuildInner(Func shouldIgnore, TInner inner)
+ {
+ var dictionary = new Dictionary();
+ foreach (var pair in inner
+ .OrderBy(_ => _.Key, StringComparer.OrdinalIgnoreCase))
+ {
+ var key = pair.Key;
+ var scrubOrIgnore = shouldIgnore(key);
+ if (scrubOrIgnore == ScrubOrIgnore.Ignore)
+ {
+ continue;
+ }
+
+ if (scrubOrIgnore == ScrubOrIgnore.Scrub)
+ {
+ dictionary.Add(key, "{Scrubbed}");
+ continue;
+ }
+
+ dictionary.Add(key, pair.Value);
+ }
+
+ return dictionary;
+ }
}
\ No newline at end of file
diff --git a/src/Verify/Serialization/Scrubbers/DictionaryWrappers/StringDictionaryWrapper.cs b/src/Verify/Serialization/Scrubbers/DictionaryWrappers/StringDictionaryWrapper.cs
index 5525ff6b3a..85b24443aa 100644
--- a/src/Verify/Serialization/Scrubbers/DictionaryWrappers/StringDictionaryWrapper.cs
+++ b/src/Verify/Serialization/Scrubbers/DictionaryWrappers/StringDictionaryWrapper.cs
@@ -1,12 +1,32 @@
class StringDictionaryWrapper :
- Dictionary,
+ Dictionary,
IDictionaryWrapper
where TInner : IDictionary
{
- public StringDictionaryWrapper(Func shouldIgnore, TInner inner) :
- base(inner
- .Where(_ => !shouldIgnore(_.Key))
+ public StringDictionaryWrapper(Func shouldIgnore, TInner inner) :
+ base(BuildInner(shouldIgnore, inner)
.ToDictionary(_ => _.Key, _ => _.Value))
{
}
+
+ static IEnumerable<(string Key, object? Value)> BuildInner(Func shouldIgnore, TInner inner)
+ {
+ foreach (var pair in inner)
+ {
+ var key = pair.Key;
+ var scrubOrIgnore = shouldIgnore(key);
+ if (scrubOrIgnore == ScrubOrIgnore.Ignore)
+ {
+ continue;
+ }
+
+ if (scrubOrIgnore == ScrubOrIgnore.Scrub)
+ {
+ yield return (key, "{Scrubbed}");
+ continue;
+ }
+
+ yield return (key, pair.Value);
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Verify/Serialization/SerializationSettings_IgnoreByName.cs b/src/Verify/Serialization/SerializationSettings_IgnoreByName.cs
index b1e9b7b9d6..5f94cd352b 100644
--- a/src/Verify/Serialization/SerializationSettings_IgnoreByName.cs
+++ b/src/Verify/Serialization/SerializationSettings_IgnoreByName.cs
@@ -2,7 +2,7 @@
partial class SerializationSettings
{
- List ignoredByNameMembers = new();
+ Dictionary ignoredByNameMembers = new();
public void IgnoreStackTrace() =>
IgnoreMember("StackTrace");
@@ -10,7 +10,12 @@ public void IgnoreStackTrace() =>
public void IgnoreMember(string name)
{
Guard.AgainstNullOrEmpty(name, nameof(name));
- ignoredByNameMembers.Add(name);
+ ignoredByNameMembers[name] = ScrubOrIgnore.Ignore;
+ }
+ public void ScrubMember(string name)
+ {
+ Guard.AgainstNullOrEmpty(name, nameof(name));
+ ignoredByNameMembers[name] = ScrubOrIgnore.Ignore;
}
public void IgnoreMembers(params string[] names)
@@ -22,6 +27,15 @@ public void IgnoreMembers(params string[] names)
}
}
- internal bool ShouldIgnoreByName(string name) =>
- ignoredByNameMembers.Contains(name);
+ public void ScrubMembers(params string[] names)
+ {
+ Guard.AgainstNullOrEmpty(names, nameof(names));
+ foreach (var name in names)
+ {
+ ScrubMember(name);
+ }
+ }
+
+ internal bool TryGetScrubOrIgnoreByName(string name, [NotNullWhen(true)] out ScrubOrIgnore? scrubOrIgnore) =>
+ ignoredByNameMembers.TryGetValue(name, out scrubOrIgnore);
}
\ No newline at end of file
diff --git a/src/Verify/Serialization/SerializationSettings_IgnoreForMemberOfType.cs b/src/Verify/Serialization/SerializationSettings_IgnoreForMemberOfType.cs
index c44d1c7e93..3cd6ffb1cb 100644
--- a/src/Verify/Serialization/SerializationSettings_IgnoreForMemberOfType.cs
+++ b/src/Verify/Serialization/SerializationSettings_IgnoreForMemberOfType.cs
@@ -2,7 +2,7 @@
partial class SerializationSettings
{
- Dictionary> ignoredMembers = new();
+ Dictionary> ignoredMembers = new();
public void IgnoreMembers(params Expression>[] expressions)
where T : notnull
@@ -13,7 +13,24 @@ public void IgnoreMembers(params Expression>[] expressions)
}
}
+ public void ScrubMembers(params Expression>[] expressions)
+ where T : notnull
+ {
+ foreach (var expression in expressions)
+ {
+ ScrubMember(expression);
+ }
+ }
+
public void IgnoreMember(Expression> expression)
+ where T : notnull =>
+ IgnoreMember(expression, ScrubOrIgnore.Ignore);
+
+ public void ScrubMember(Expression> expression)
+ where T : notnull =>
+ IgnoreMember(expression, ScrubOrIgnore.Scrub);
+
+ void IgnoreMember(Expression> expression, ScrubOrIgnore scrubOrIgnore)
where T : notnull
{
var member = expression.FindMember();
@@ -24,17 +41,25 @@ public void IgnoreMember(Expression> expression)
To ignore specific members for T, create a custom converter.");
}
- IgnoreMember(declaringType, member.Name);
+ IgnoreMember(declaringType, member.Name,scrubOrIgnore);
}
public void IgnoreMembers(params string[] names)
where T : notnull =>
IgnoreMembers(typeof(T), names);
+ public void ScrubMembers(params string[] names)
+ where T : notnull =>
+ ScrubMembers(typeof(T), names);
+
public void IgnoreMember(string name)
where T : notnull =>
IgnoreMember(typeof(T), name);
+ public void ScrubMember(string name)
+ where T : notnull =>
+ ScrubMember(typeof(T), name);
+
public void IgnoreMembers(Type declaringType, params string[] names)
{
Guard.AgainstNullOrEmpty(names, nameof(names));
@@ -44,7 +69,22 @@ public void IgnoreMembers(Type declaringType, params string[] names)
}
}
- public void IgnoreMember(Type declaringType, string name)
+ public void ScrubMembers(Type declaringType, params string[] names)
+ {
+ Guard.AgainstNullOrEmpty(names, nameof(names));
+ foreach (var name in names)
+ {
+ ScrubMember(declaringType, name);
+ }
+ }
+
+ public void IgnoreMember(Type declaringType, string name) =>
+ IgnoreMember(declaringType, name, ScrubOrIgnore.Ignore);
+
+ public void ScrubMember(Type declaringType, string name) =>
+ IgnoreMember(declaringType, name, ScrubOrIgnore.Scrub);
+
+ void IgnoreMember(Type declaringType, string name, ScrubOrIgnore scrubOrIgnore)
{
Guard.AgainstNullOrEmpty(name, nameof(name));
Guard.AgainstNullable(declaringType, nameof(name));
@@ -53,10 +93,24 @@ public void IgnoreMember(Type declaringType, string name)
ignoredMembers[declaringType] = list = new();
}
- list.Add(name);
+ list[name] = scrubOrIgnore;
}
- internal bool ShouldIgnoreForMemberOfType(Type declaringType, string name) =>
- ignoredMembers.Where(_ => _.Value.Contains(name))
- .Any(_ => _.Key.IsAssignableFrom(declaringType));
+ internal bool TryGetScrubOrIgnoreByMemberOfType(Type declaringType, string name, [NotNullWhen(true)] out ScrubOrIgnore? scrubOrIgnore)
+ {
+ foreach (var typeIgnores in ignoredMembers)
+ {
+ if (typeIgnores.Key.IsAssignableFrom(declaringType))
+ {
+ if (typeIgnores.Value.TryGetValue(name, out var innerScrubOrIgnore))
+ {
+ scrubOrIgnore = innerScrubOrIgnore;
+ return true;
+ }
+ }
+ }
+
+ scrubOrIgnore = null;
+ return false;
+ }
}
\ No newline at end of file
diff --git a/src/Verify/Serialization/SerializationSettings_IgnoreInstance.cs b/src/Verify/Serialization/SerializationSettings_IgnoreInstance.cs
index be6d0099b7..c022ad195e 100644
--- a/src/Verify/Serialization/SerializationSettings_IgnoreInstance.cs
+++ b/src/Verify/Serialization/SerializationSettings_IgnoreInstance.cs
@@ -1,6 +1,6 @@
partial class SerializationSettings
{
- Dictionary> ignoredInstances = new();
+ Dictionary>> ignoredInstances = new();
public void IgnoreInstance(Func shouldIgnore)
where T : notnull
@@ -22,9 +22,48 @@ public void IgnoreInstance(Type type, ShouldIgnore shouldIgnore)
ignoredInstances[type] = list = new();
}
- list.Add(shouldIgnore);
+ list.Add(_ =>
+ {
+ if (shouldIgnore(_))
+ {
+ return ScrubOrIgnore.Ignore;
+ }
+
+ return null;
+ });
+ }
+
+ public void ScrubInstance(Func shouldScrub)
+ where T : notnull
+ {
+ var type = typeof(T);
+ ScrubInstance(
+ type,
+ target =>
+ {
+ var arg = (T) target;
+ return shouldScrub(arg);
+ });
+ }
+
+ public void ScrubInstance(Type type, ShouldScrub shouldScrub)
+ {
+ if (!ignoredInstances.TryGetValue(type, out var list))
+ {
+ ignoredInstances[type] = list = new();
+ }
+
+ list.Add(_ =>
+ {
+ if (shouldScrub(_))
+ {
+ return ScrubOrIgnore.Scrub;
+ }
+
+ return null;
+ });
}
- internal bool GetShouldIgnoreInstance(Type memberType, [NotNullWhen(true)] out List? funcs) =>
+ internal bool GetShouldIgnoreInstance(Type memberType, [NotNullWhen(true)] out List>? funcs) =>
ignoredInstances.TryGetValue(memberType, out funcs);
}
\ No newline at end of file
diff --git a/src/Verify/Serialization/SerializationSettings_IgnoreType.cs b/src/Verify/Serialization/SerializationSettings_IgnoreType.cs
index c62f56e743..37be8dd09b 100644
--- a/src/Verify/Serialization/SerializationSettings_IgnoreType.cs
+++ b/src/Verify/Serialization/SerializationSettings_IgnoreType.cs
@@ -2,32 +2,43 @@
partial class SerializationSettings
{
- List ignoredTypes = new();
+ Dictionary ignoredTypes = new();
+
+ public void ScrubMembersWithType()
+ where T : notnull =>
+ ScrubMembersWithType(typeof(T));
+
+ public void ScrubMembersWithType(Type type) =>
+ ignoredTypes[type]= ScrubOrIgnore.Scrub;
public void IgnoreMembersWithType()
where T : notnull =>
IgnoreMembersWithType(typeof(T));
public void IgnoreMembersWithType(Type type) =>
- ignoredTypes.Add(type);
+ ignoredTypes[type]= ScrubOrIgnore.Ignore;
- bool ShouldIgnoreType(Type memberType)
+ bool TryGetScrubOrIgnoreByType(Type memberType, [NotNullWhen(true)]out ScrubOrIgnore? scrubOrIgnore)
{
- if (ignoredTypes.Any(memberType.InheritsFrom))
+ foreach (var member in ignoredTypes)
{
- return true;
+ if (memberType.InheritsFrom(member.Key))
+ {
+ scrubOrIgnore = member.Value;
+ return true;
+ }
}
-
var typeFromNullable = Nullable.GetUnderlyingType(memberType);
-
- if (typeFromNullable != null)
+ foreach (var member in ignoredTypes)
{
- if (ignoredTypes.Any(_ => _.IsAssignableFrom(typeFromNullable)))
+ if (member.Key.IsAssignableFrom(typeFromNullable))
{
+ scrubOrIgnore = member.Value;
return true;
}
}
+ scrubOrIgnore = null;
return false;
}
}
\ No newline at end of file
diff --git a/src/Verify/Serialization/SerializationSettings_ShouldIgnore.cs b/src/Verify/Serialization/SerializationSettings_ShouldIgnore.cs
index fa69621aab..c19037dd27 100644
--- a/src/Verify/Serialization/SerializationSettings_ShouldIgnore.cs
+++ b/src/Verify/Serialization/SerializationSettings_ShouldIgnore.cs
@@ -1,94 +1,52 @@
partial class SerializationSettings
{
- internal bool ShouldIgnore(MemberInfo member)
+ internal bool TryGetScrubOrIgnore(MemberInfo member, [NotNullWhen(true)] out ScrubOrIgnore? scrubOrIgnore)
{
if (ShouldIgnoreIfObsolete(member))
{
+ scrubOrIgnore = ScrubOrIgnore.Ignore;
return true;
}
- return ShouldIgnore(member.DeclaringType!, member.MemberType(), member.Name);
+ return TryGetScrubOrIgnore(member.DeclaringType!, member.MemberType(), member.Name, out scrubOrIgnore);
}
- internal bool ShouldIgnore(Type declaringType, Type memberType, string name)
- {
- if (ShouldIgnoreType(memberType))
- {
- return true;
- }
+ internal bool TryGetScrubOrIgnore(Type declaringType, Type memberType, string name, [NotNullWhen(true)] out ScrubOrIgnore? scrubOrIgnore) =>
+ TryGetScrubOrIgnoreByType(memberType, out scrubOrIgnore) ||
+ TryGetScrubOrIgnoreByName(name, out scrubOrIgnore) ||
+ TryGetScrubOrIgnoreByMemberOfType(declaringType, name, out scrubOrIgnore);
- if (ShouldIgnoreByName(name))
- {
- return true;
- }
-
- if (ShouldIgnoreForMemberOfType(declaringType, name))
- {
- return true;
- }
-
- return false;
- }
-
- internal bool ShouldSerialize(object value)
+ internal bool TryGetScrubOrIgnoreByInstance(object value, [NotNullWhen(true)] out ScrubOrIgnore? scrubOrIgnore)
{
var memberType = value.GetType();
if (GetShouldIgnoreInstance(memberType, out var funcs))
{
- return funcs.All(func => !func(value));
- }
-
- if (IsIgnoredCollection(memberType))
- {
- // since inside IsCollection, it is safe to use IEnumerable
- var collection = (IEnumerable) value;
-
- return collection.HasMembers();
- }
-
- return true;
- }
-
- internal bool TryGetShouldSerialize(Type memberType, Func