Skip to content

Assert.That: restore friendly method-call display from #6691#8364

Merged
Evangelink merged 2 commits into
mainfrom
dev/amauryleve/assert-that-display-fixes
May 20, 2026
Merged

Assert.That: restore friendly method-call display from #6691#8364
Evangelink merged 2 commits into
mainfrom
dev/amauryleve/assert-that-display-fixes

Conversation

@Evangelink
Copy link
Copy Markdown
Member

Follow-up to #8306 / #8307 / #8352 restoring two friendly-display fixes from issue #6691 that PR #8307's architectural rewrite silently regressed.

Regressions repaired

1. obj.Get(...) was rendered as obj[...] for any receiver

HandleMethodCallExpression currently matches any instance method named Get and renders it as object[args]. So a user assertion Assert.That(() => box.Get(1) == 0) on a plain class produces box[1] = 101 in the failure details, which is misleading — looks like an indexer, isn't.

The original #6691 fix gated this on callExpr.Object.Type.IsArray (the multi-dim-array case is exactly why this special case exists — int[,] exposes a runtime-synthesized Get on the array type itself, not on System.Array). This PR re-introduces that gate as IsMultiDimensionalArrayGetCall.

2. this.Method(...) / Type.Method(...) rendering lost

Non-boolean method calls fall back to raw callExpr.ToString() cleanup, which renders:

Call site Current Expected
Static method, same type GetAnimal() AssertTests.GetAnimal()
Instance method on this value(AssertTests).GetAnimalInstance() / similar this.GetAnimalInstance()
Extension method on this display-class field or type name this.GetGreeting()

Re-introduces GetMethodCallDisplayName + IsCapturedThis from the original fix, with the no-closure ConstantExpression branch guarded by ce.Type == ce.Value.GetType() so a base-typed local isn't mislabeled as this (while inherited methods on this are still rendered correctly via IsAssignableFrom).

Tests

Four regression tests added in AssertTests.That.cs:

  • That_ArbitraryGetMethodOnNonArray_RendersAsMethodCall_NotIndexer
  • That_StaticMethodOnSameType_RendersWithTypeNamePrefix
  • That_InstanceMethodOnThis_RendersAsThisMethod
  • That_ExtensionMethodOnThis_RendersAsThisMethod

The tests assert on substrings rather than full-message matches so the exact parenthesization / argument rendering can still evolve.

Validation

  • dotnet build src/TestFramework/TestFramework/TestFramework.csproj -c Debug → 0 warnings, 0 errors across netstandard2.0, net462, net8.0, net9.0.
  • All 918 AssertTests pass on net9.0 (76 That_* tests, including the 4 new ones).

Notes

  • No new public API surface; all additions are private helpers in AssertExtensions.
  • The extension-method receiver path uses the first parameter's declared type with IsCapturedThis so Assert.That(() => this.SomeExtension() == x) renders as this.SomeExtension(...) rather than <>4__this.SomeExtension(...) or TypeName.SomeExtension(...).

PR #8307 re-architected `Assert.That` and silently regressed two display
fixes from the original #6691 work:

1. Any instance method named `Get(...)` was rendered as `obj[...]` in
   failure details, regardless of whether the receiver was an array. So
   `box.Get(1) == 0` produced `box[1] = 101` instead of
   `box.Get(1) = 101`. The original fix gated this on
   `callExpr.Object.Type.IsArray`.

2. Non-boolean method calls fell back to a raw `callExpr.ToString()`
   cleanup, losing the friendly `this.Method(...)` / `Type.Method(...)`
   / `receiver.Method(...)` rendering. Inherited methods on `this`,
   captured-this extension methods, and static methods on the same type
   all suffered.

Re-introduces:

* `IsMultiDimensionalArrayGetCall` — scopes the `Get -> obj[...]`
  special case to actual array receivers (matches multi-dim arrays like
  `int[,]` whose `Get` is runtime-synthesized on the array type
  itself, not on `System.Array`).
* `GetMethodCallDisplayName` — builds the friendly receiver string for
  non-boolean method calls.
* `IsCapturedThis` — recognizes the compiler-synthesized `<>4__this`
  field used in closures AND the no-closure `ConstantExpression` form,
  guarded by `ce.Type == ce.Value.GetType()` so a base-typed local
  isn't mislabeled as `this` (while inherited methods on `this` are
  still rendered correctly via `IsAssignableFrom`).

Four regression tests added in `AssertTests.That.cs`:

* `That_ArbitraryGetMethodOnNonArray_RendersAsMethodCall_NotIndexer`
* `That_StaticMethodOnSameType_RendersWithTypeNamePrefix`
* `That_InstanceMethodOnThis_RendersAsThisMethod`
* `That_ExtensionMethodOnThis_RendersAsThisMethod`

All 918 `AssertTests` pass on `net9.0`.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 19, 2026 17:53
Copy link
Copy Markdown
Contributor

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

Note

Copilot was unable to run its full agentic suite in this review.

Restores friendlier method-call rendering in Assert.That failure details (regressions from #6691) and adds regression tests to lock in the message formatting.

Changes:

  • Gate array.Get(...)array[...] rendering to true array receivers to avoid mis-rendering arbitrary Get(...) methods.
  • Add friendly receiver formatting for method calls (this.Method(...), Type.Method(...), and extension methods on this).
  • Add 4 regression tests covering the restored display behavior.
Show a summary per file
File Description
test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.That.cs Adds regression tests for friendly receiver/method-call rendering.
src/TestFramework/TestFramework/Assertions/Assert.That.cs Reintroduces friendly method-call display logic and corrects the Get-as-indexer special case.

Copilot's findings

  • Files reviewed: 2/2 changed files
  • Comments generated: 6

Comment thread test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.That.cs Outdated
Comment thread src/TestFramework/TestFramework/Assertions/Assert.That.cs
Copy link
Copy Markdown
Contributor

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.

Copilot's findings

  • Files reviewed: 2/2 changed files
  • Comments generated: 3

Comment thread test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.That.cs Outdated
Comment thread src/TestFramework/TestFramework/Assertions/Assert.That.cs Outdated
Comment thread src/TestFramework/TestFramework/Assertions/Assert.That.cs Outdated
- Resolve Assert.That.cs / AssertTests.That.cs merge conflicts (both sides additive).

- Rename IsMultiDimensionalArrayGetCall -> IsArrayGetCall to match the IsArray gate; update doc to explain that the call only fires for multidim arrays in practice.

- Static method-call rendering now uses a friendly type name (no namespace, '+' replaced with '.') so the displayed type matches the user-facing C# syntax described in the comment.

- Fix 'mis-leading' typo in regression-test header.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink Evangelink merged commit be1d378 into main May 20, 2026
149 of 154 checks passed
@Evangelink Evangelink deleted the dev/amauryleve/assert-that-display-fixes branch May 20, 2026 13:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants