fix: only annotate Collection as incomplete when the formatter truncates#956
Conversation
…cates The `(… and maybe others)` annotation on the `Collection` section was attached whenever a collection constraint exited early on a cancelEarly source, regardless of whether the formatter actually had more items to show. For a small finite source that the formatter walks fully, this was misleading. Resolve the flag at constraint time by walking the materialized enumerable up to the formatter's display limit + 1. The walk is bounded and the cache is reused by the formatter later. The `Matching items` / `Not matching items` annotation continues to reflect constraint coverage (incomplete on early exit), since the constraint may not have categorized all source items.
There was a problem hiding this comment.
Pull request overview
Fixes the misleading (… and maybe others) annotation on the Collection context section, which was previously appended whenever a constraint exited early on a non-ICollection source, even when the formatter could display the entire collection. The fix introduces an ExceedsFormatterLimit helper that walks the materialized (cached) enumerable up to the formatter's display limit + 1 and uses the result to decide whether the "incomplete" marker should be appended.
Changes:
- Adds
ExceedsFormatterLimitextension methods (generic and non-generic) inCollectionHelpers.cs, bounded by the configured formatter limit. - Replaces the hardcoded
trueargument toAddCollectionContexton early-exit paths withmaterialized.ExceedsFormatterLimit()in theCollectionConstraintearly-exit branches ofThatEnumerable.csandThatEnumerable.Elements.ComplyWith.cs. - Updates expectation snapshots across many collection tests to drop the
(… and maybe others)line for cases where the formatter actually showed the whole collection.
Reviewed changes
Copilot reviewed 23 out of 23 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| Source/aweXpect/That/Collections/CollectionHelpers.cs | Adds bounded ExceedsFormatterLimit helpers for IEnumerable<T> and IEnumerable. |
| Source/aweXpect/That/Collections/ThatEnumerable.cs | Resolves the incomplete flag at constraint time on four early-exit branches. |
| Source/aweXpect/That/Collections/ThatEnumerable.Elements.ComplyWith.cs | Same fix applied to the four ComplyWith constraint variants. |
| Tests/aweXpect.Tests/Collections/ThatEnumerable.All.Are.Tests.cs | Snapshot updated to remove spurious (… and maybe others). |
| Tests/aweXpect.Tests/Collections/ThatEnumerable.All.Are.EnumerableTests.cs | Same snapshot update. |
| Tests/aweXpect.Tests/Collections/ThatEnumerable.All.AreExactly.Tests.cs | Same snapshot update. |
| Tests/aweXpect.Tests/Collections/ThatEnumerable.All.AreExactly.EnumerableTests.cs | Same snapshot update. |
| Tests/aweXpect.Tests/Collections/ThatEnumerable.All.ComplyWith.Tests.cs | Same snapshot update. |
| Tests/aweXpect.Tests/Collections/ThatEnumerable.All.ComplyWith.EnumerableTests.cs | Same snapshot update. |
| Tests/aweXpect.Tests/Collections/ThatEnumerable.AtMost.Tests.cs | Same snapshot update. |
| Tests/aweXpect.Tests/Collections/ThatEnumerable.AtMost.EnumerableTests.cs | Same snapshot update. |
| Tests/aweXpect.Tests/Collections/ThatEnumerable.Between.Tests.cs | Same snapshot update. |
| Tests/aweXpect.Tests/Collections/ThatEnumerable.Between.EnumerableTests.cs | Same snapshot update. |
| Tests/aweXpect.Tests/Collections/ThatEnumerable.Exactly.Tests.cs | Same snapshot update. |
| Tests/aweXpect.Tests/Collections/ThatEnumerable.Exactly.EnumerableTests.cs | Same snapshot update. |
| Tests/aweXpect.Tests/Collections/ThatEnumerable.LessThan.Tests.cs | Same snapshot update. |
| Tests/aweXpect.Tests/Collections/ThatEnumerable.LessThan.EnumerableTests.cs | Same snapshot update. |
| Tests/aweXpect.Tests/Collections/ThatEnumerable.None.AreEqualTo.Tests.cs | Same snapshot update. |
| Tests/aweXpect.Tests/Collections/ThatEnumerable.None.AreEqualTo.EnumerableTests.cs | Same snapshot update. |
| Tests/aweXpect.Tests/Collections/ThatEnumerable.None.Satisfy.Tests.cs | Same snapshot update. |
| Tests/aweXpect.Tests/Collections/ThatDictionary.ContainsKeys.Tests.cs | Same snapshot update for dictionary collection context. |
| Tests/aweXpect.Tests/Collections/ThatReadOnlyDictionary.ContainsKeys.Tests.cs | Same snapshot update for read-only dictionary collection context. |
| Tests/aweXpect.Tests/Delegates/ThatDelegate.ThrowsException.WithRecursiveInnerExceptionsTests.cs | Snapshot update reflecting the new behavior (note: Not matching items retains the marker, as documented). |
🚀 Benchmark ResultsDetails
|
👽 Mutation ResultsaweXpectDetails
The final mutation score is 84.62%Coverage Thresholds: high:80 low:60 break:0aweXpect.CoreDetails
The final mutation score is NaN%Coverage Thresholds: high:80 low:60 break:0 |
…traints The previous fix only narrowed `(… and maybe others)` for the predicate quantifier sites. Apply the same treatment to the other sync early-exit paths in `ThatEnumerable.cs`, `ThatEnumerable.StartsWith.cs`, and `ThatEnumerable.EndsWith.cs` so small finite sources no longer get the misleading flag from `IsEqualTo`, `HasCount`, `StartsWith`, or `EndsWith` failure messages either. Gate `ExceedsFormatterLimit` behind `Outcome == Outcome.Failure` for the variable-outcome sites so passing tests on the cancel-early path do not walk the source eagerly. Always-failure sites call it unguarded. Async paths are left as-is because their `LimitedCollection` bound (limit+1) guarantees the formatter is truncating. Short-circuit `ExceedsFormatterLimit` on `ICollection`/`ICountable` counts, and replace the counting `foreach` with `Skip(limit).Any()` to satisfy SonarS3267.
|
…mplete when the formatter truncates (#956) by Valentin Breuß
…mplete when the formatter truncates (#956) by Valentin Breuß
|
This is addressed in release v2.34.0. |



The
(… and maybe others)annotation on theCollectionsection was attached whenever a collection constraint exited early on a cancelEarly source, regardless of whether the formatter actually had more items to show. For a small finite source that the formatter walks fully, this was misleading.Resolve the flag at constraint time by walking the materialized enumerable up to the formatter's display limit + 1. The walk is bounded and the cache is reused by the formatter later.
The
Matching items/Not matching itemsannotation continues to reflect constraint coverage (incomplete on early exit), since the constraint may not have categorized all source items.