Skip to content

fix: only annotate Collection as incomplete when the formatter truncates#956

Merged
vbreuss merged 2 commits into
mainfrom
topic/improve-collection-element-error-message
May 17, 2026
Merged

fix: only annotate Collection as incomplete when the formatter truncates#956
vbreuss merged 2 commits into
mainfrom
topic/improve-collection-element-error-message

Conversation

@vbreuss
Copy link
Copy Markdown
Member

@vbreuss vbreuss commented May 17, 2026

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.

…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.
@vbreuss vbreuss self-assigned this May 17, 2026
Copilot AI review requested due to automatic review settings May 17, 2026 05:31
@vbreuss vbreuss added the bug Something isn't working label May 17, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 ExceedsFormatterLimit extension methods (generic and non-generic) in CollectionHelpers.cs, bounded by the configured formatter limit.
  • Replaces the hardcoded true argument to AddCollectionContext on early-exit paths with materialized.ExceedsFormatterLimit() in the CollectionConstraint early-exit branches of ThatEnumerable.cs and ThatEnumerable.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).

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 17, 2026

Test Results

     23 files   - 27       23 suites   - 27   7m 57s ⏱️ +53s
 19 817 tests  - 17   19 816 ✅  - 17  1 💤 ±0  0 ❌ ±0 
102 404 runs   - 81  102 403 ✅  - 81  1 💤 ±0  0 ❌ ±0 

Results for commit 3402212. ± Comparison against base commit 17f0b7e.

♻️ This comment has been updated with latest results.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 17, 2026

🚀 Benchmark Results

Details

BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
AMD EPYC 9V74 2.60GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.300
[Host] : .NET 8.0.27 (8.0.27, 8.0.2726.22922), X64 RyuJIT x86-64-v3

Job=InProcess Toolchain=InProcessEmitToolchain IterationCount=15
LaunchCount=1 WarmupCount=10

Method Mean Error StdDev Gen0 Gen1 Allocated
Bool_aweXpect 252.8 ns 2.28 ns 2.02 ns 0.0415 - 696 B
Bool_FluentAssertions 249.6 ns 1.71 ns 1.51 ns 0.0567 - 952 B
Equivalency_aweXpect 290,006.5 ns 3,240.30 ns 3,030.98 ns 20.0195 0.4883 335444 B
Equivalency_FluentAssertions 2,360,328.7 ns 50,071.86 ns 46,837.25 ns 285.1563 46.8750 4804906 B
Int_GreaterThan_aweXpect 261.3 ns 2.46 ns 2.18 ns 0.0515 - 864 B
Int_GreaterThan_FluentAssertions 250.5 ns 3.43 ns 3.21 ns 0.0730 - 1224 B
ItemsCount_AtLeast_aweXpect 473.8 ns 7.94 ns 7.04 ns 0.0811 - 1360 B
ItemsCount_AtLeast_FluentAssertions 485.9 ns 7.85 ns 7.35 ns 0.1192 - 2008 B
String_aweXpect 475.9 ns 3.92 ns 3.48 ns 0.0672 - 1128 B
String_FluentAssertions 1,193.0 ns 22.20 ns 19.68 ns 0.2346 - 3944 B
StringArray_aweXpect 1,908.6 ns 13.55 ns 12.68 ns 0.1564 - 2624 B
StringArray_FluentAssertions 1,354.8 ns 17.50 ns 16.37 ns 0.2480 - 4152 B
StringArrayInAnyOrder_aweXpect 2,531.8 ns 13.94 ns 13.04 ns 0.1678 - 2816 B
StringArrayInAnyOrder_FluentAssertions 64,090.2 ns 362.34 ns 302.57 ns 3.4180 - 57480 B

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 17, 2026

👽 Mutation Results

Mutation testing badge

aweXpect

Details
File Score Killed Survived Timeout No Coverage Ignored Compile Errors Total Detected Total Undetected Total Mutants
That/Collections/CollectionHelpers.cs 92.78% 89 5 1 2 29 40 90 7 166
That/Collections/ThatEnumerable.cs 82.46% 315 10 0 57 113 259 315 67 754
That/Collections/ThatEnumerable.Elements.ComplyWith.cs 67.23% 116 20 3 38 48 40 119 58 265
That/Collections/ThatEnumerable.EndsWith.cs 97.52% 118 3 0 0 24 46 118 3 191
That/Collections/ThatEnumerable.StartsWith.cs 99.07% 106 1 0 0 22 44 106 1 173

The final mutation score is 84.62%

Coverage Thresholds: high:80 low:60 break:0

aweXpect.Core

Details
File Score Killed Survived Timeout No Coverage Ignored Compile Errors Total Detected Total Undetected Total Mutants

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.
@vbreuss vbreuss enabled auto-merge (squash) May 17, 2026 06:18
@sonarqubecloud
Copy link
Copy Markdown

@vbreuss vbreuss merged commit 3b2559e into main May 17, 2026
13 checks passed
@vbreuss vbreuss deleted the topic/improve-collection-element-error-message branch May 17, 2026 06:24
github-actions Bot added a commit that referenced this pull request May 17, 2026
…mplete when the formatter truncates (#956) by Valentin Breuß
github-actions Bot added a commit that referenced this pull request May 17, 2026
…mplete when the formatter truncates (#956) by Valentin Breuß
@github-actions
Copy link
Copy Markdown
Contributor

This is addressed in release v2.34.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working state: released The issue is released

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants