Skip to content

Commit 2fbb653

Browse files
authored
Keep empty collections ignored alongside instance predicates (#1860)
TryGetScrubOrIgnoreByInstance returned as soon as it found predicates registered for the value's type and none of them matched, skipping the empty collection check below it. So an empty List<string> started rendering as [] merely because some unrelated IgnoreInstance or ScrubInstance predicate had been registered for that type. No predicate matching is not a decision to keep the value, so the empty collection check now runs either way. The test lives in its own file rather than being appended to SerializationTests, so this does not collide with the other pending fixes that append there.
1 parent 175b49d commit 2fbb653

4 files changed

Lines changed: 25 additions & 4 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
NotEmpty: [
3+
TheValue
4+
]
5+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
public class IgnoreInstanceTests
2+
{
3+
[Fact]
4+
public Task NonMatchingPredicateKeepsEmptyCollectionsIgnored() =>
5+
Verify(
6+
new
7+
{
8+
Empty = new List<string>(),
9+
NotEmpty = new List<string>
10+
{
11+
"TheValue"
12+
}
13+
})
14+
// a predicate that never matches is not a decision to keep the value,
15+
// so Empty is still ignored as an empty collection
16+
.IgnoreInstance<List<string>>(_ => false);
17+
}

src/Verify/Serialization/SerializationSettings_ShouldIgnore.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ internal bool TryGetScrubOrIgnore(Type declaringType, Type memberType, string na
2323
internal bool TryGetScrubOrIgnoreByInstance(object value, [NotNullWhen(true)] out ScrubOrIgnore? scrubOrIgnore)
2424
{
2525
var memberType = value.GetType();
26+
// no predicate matching is not a decision to keep the value, so
27+
// the empty collection check still applies
2628
if (GetShouldIgnoreInstance(memberType, out var funcs))
2729
{
2830
foreach (var func in funcs)
@@ -34,9 +36,6 @@ internal bool TryGetScrubOrIgnoreByInstance(object value, [NotNullWhen(true)] ou
3436
return true;
3537
}
3638
}
37-
38-
scrubOrIgnore = null;
39-
return false;
4039
}
4140

4241
if (ignoreEmptyCollections &&

src/todo.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ All six resolved 2026-08-16 (five fixed here; the inline item resolved as by-des
4444
- [ ] **`MemberConverter` has no exact-type precedence.**
4545
`Verify/Serialization/VerifierSettings_MemberConverter.cs:13-25` — first registered entry with `IsAssignableFrom` wins, so a base-interface converter registered earlier permanently shadows a more specific one. Contrast `TryGetScrubOrIgnoreByMemberOfType`, which checks the exact declaring type first.
4646

47-
- [ ] **Registering an `IgnoreInstance` predicate disables empty-collection ignoring for that type.**
47+
- [x] **Registering an `IgnoreInstance` predicate disables empty-collection ignoring for that type.**
4848
`Verify/Serialization/SerializationSettings_ShouldIgnore.cs:26-40` — when predicates exist but none match, the early `return false` skips the `ignoreEmptyCollections` check at 42-47. An empty `List<string>` starts appearing as `[]` merely because an unrelated predicate was registered.
4949

5050
- [x] **Combinations name cache collapses distinct keys.**

0 commit comments

Comments
 (0)