Skip to content

Apply structured assertion messages (RFC 012) to Assert.HasCount / IsEmpty / IsNotEmpty#8262

Open
Evangelink wants to merge 5 commits into
mainfrom
dev/amauryleve/assert-count-rfc012
Open

Apply structured assertion messages (RFC 012) to Assert.HasCount / IsEmpty / IsNotEmpty#8262
Evangelink wants to merge 5 commits into
mainfrom
dev/amauryleve/assert-count-rfc012

Conversation

@Evangelink
Copy link
Copy Markdown
Member

Continues the rollout of RFC 012 — Structured Assertion Messages by migrating Assert.HasCount / Assert.IsEmpty / Assert.IsNotEmpty (including their interpolated-string-handler overloads) to the structured-message format. Follows the patterns established by previously merged work (#8170, #8187, #8210, #8214) and the in-flight series (#8258, #8259, #8260).

Output format

Assert.HasCount(3, collection) (collection has 1 element):

Assertion failed. Expected collection to contain a specific number of elements.

expected count: 3
actual count:   1

Assert.HasCount(3, collection)

Assert.IsEmpty(collection) (collection has 1 element):

Assertion failed. Expected collection to be empty.

expected count: 0
actual count:   1

Assert.IsEmpty(collection)

Assert.IsNotEmpty(Array.Empty<int>()):

Assertion failed. Expected collection to not be empty.

actual count: 0

Assert.IsNotEmpty(Array.Empty<int>())

Notes

  • Adds HasCountFailedSummary / IsEmptyFailedSummary / IsNotEmptyFailedSummary resource entries (XLF files regenerated via UpdateXlf).
  • The interpolated-string-handler now passes the developer-built message directly to the structured report so the user-message line appears between the summary and the evidence block (consistent with the rest of RFC 012 migrations).
  • HasCount reconstructs the call-site as Assert.HasCount(<expected>, <collection>) so the literal expected count remains visible in the call-site line even though it is not captured by CallerArgumentExpression.
  • Updates the message-format tests in AssertTests.Items.cs to assert against the new layout.

Validation

  • dotnet build src/TestFramework/TestFramework/TestFramework.csproj -c Debug — clean.
  • dotnet test test/UnitTests/TestFramework.UnitTests/TestFramework.UnitTests.csproj -c Debug — 3535/3535 passed.

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

…Empty / IsNotEmpty

Migrates Assert.HasCount, Assert.IsEmpty, and Assert.IsNotEmpty (and their interpolated-string-handler overloads) to the structured assertion message format defined in RFC 012.

The HasCount/IsEmpty evidence block surfaces 'expected count:' and 'actual count:' so the size mismatch is visible at a glance; IsNotEmpty omits the expected line because the only actionable count is the actual zero.

The interpolated-string-handler now passes the user-built message directly to the structured report and lets FormatCallSiteExpression reconstruct the call-site (e.g. Assert.HasCount(1, Array.Empty<int>())) so the literal expected count remains visible even on the interpolated path.

Updates the affected message-format tests in AssertTests.Items.cs to assert against the new layout.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 15, 2026 14:07
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

Migrates Assert.HasCount / Assert.IsEmpty / Assert.IsNotEmpty (including interpolated-string-handler overloads) to the RFC 012 structured assertion message format, updating both resources and unit-test expectations accordingly.

Changes:

  • Updated Assert.Count failure paths to build StructuredAssertionMessage instances with evidence blocks and call-site expressions.
  • Added new localized summary resource entries (HasCountFailedSummary, IsEmptyFailedSummary, IsNotEmptyFailedSummary) and regenerated XLFs.
  • Updated AssertTests.Items expectations to validate the new structured multiline message layout (including interpolated handler scenarios).
Show a summary per file
File Description
test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.Items.cs Updates message assertions to the new structured multiline format for count/empty assertions.
src/TestFramework/TestFramework/Assertions/Assert.Count.cs Switches HasCount/IsEmpty/IsNotEmpty failure reporting to StructuredAssertionMessage with evidence + call-site.
src/TestFramework/TestFramework/Resources/FrameworkMessages.resx Adds new summary resource strings for the migrated assertions.
src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.cs.xlf Regenerated localization entries for new summary strings.
src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.de.xlf Regenerated localization entries for new summary strings.
src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.es.xlf Regenerated localization entries for new summary strings.
src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.fr.xlf Regenerated localization entries for new summary strings.
src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.it.xlf Regenerated localization entries for new summary strings.
src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ja.xlf Regenerated localization entries for new summary strings.
src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ko.xlf Regenerated localization entries for new summary strings.
src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pl.xlf Regenerated localization entries for new summary strings.
src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.pt-BR.xlf Regenerated localization entries for new summary strings.
src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.ru.xlf Regenerated localization entries for new summary strings.
src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.tr.xlf Regenerated localization entries for new summary strings.
src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hans.xlf Regenerated localization entries for new summary strings.
src/TestFramework/TestFramework/Resources/xlf/FrameworkMessages.zh-Hant.xlf Regenerated localization entries for new summary strings.

Copilot's findings

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

Comment thread src/TestFramework/TestFramework/Assertions/Assert.Count.cs Outdated
Comment thread src/TestFramework/TestFramework/Assertions/Assert.Count.cs Outdated
Copy link
Copy Markdown
Member Author

@Evangelink Evangelink left a comment

Choose a reason for hiding this comment

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

Review: RFC 012 migration for HasCount / IsEmpty / IsNotEmpty

The change is correct, well-structured, and consistent with the RFC 012 series. All 21 review dimensions were applied; most are clean. Two minor points are flagged inline:

Findings

Severity Area Summary
MODERATE Code structure ReportAssertCountFailed dispatches on assertionName == "IsEmpty" (magic string, twice). Consider splitting into two reporters or using an enum.
NIT Resources HasCountFailMsg / IsNotEmptyFailMsg are now dead strings; still present in .resx + all 14 .xlf files.

Everything else is clean

  • Correctness: ReportAssertIsNotEmptyFailed hardcoding "0" is correct (only called when the collection is empty).
  • HasCount call-site reconstruction: using expectedText (the captured integer value) as expression1 in FormatCallSiteExpression is intentional and correct — the literal expected count is always visible even without a CallerArgumentExpression for it.
  • XLF files: regenerated via UpdateXlf as stated; not hand-edited. Consistent with localization guidelines.
  • FrameworkMessages.Designer.cs duplicate hunk in the diff: the file is auto-generated and not tracked in git — the duplicate is a diff artifact, not an actual duplicate in the file.
  • Test quality: the HEAD of AssertTests.Items.cs uses "Assertion failed." prefix with raw string literals (platform-neutral). No \r\n or fragile assertions.
  • API surface: no new public API; BuildUserMessageForCollectionExpression cleanly removed. No PublicAPI.Unshipped.txt entry needed.
  • No threading, security, performance, cross-TFM, or flakiness concerns.

Generated by Expert Code Review (on open) for issue #8262 · ● 17.1M

Use invariant formatting for HasCount call-site arguments while keeping evidence culture-aware, and replace magic assertion-name strings with nameof usage. Add a regression test covering culture-specific negative-sign formatting for the displayed call site.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink
Copy link
Copy Markdown
Member Author

@copilot resolve the merge conflicts in this pull request

Co-authored-by: Evangelink <11340282+Evangelink@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 16, 2026 11:04
Copy link
Copy Markdown
Contributor

Copilot AI commented May 16, 2026

Review: RFC 012 migration for HasCount / IsEmpty / IsNotEmpty

The change is correct, well-structured, and consistent with the RFC 012 series. All 21 review dimensions were applied; most are ...

Addressed in 9ff9009: the dead HasCountFailMsg / IsNotEmptyFailMsg resource entries were removed from FrameworkMessages.resx, the XLFs were regenerated, and the now-unused helper methods in Assert.cs were dropped as part of the same cleanup.

@copilot resolve the merge conflicts in this pull request

Resolved in 9ff9009. I merged origin/main, fixed the conflicts in Assert.Count.cs and FrameworkMessages.resx, regenerated the XLFs, and finalized the merge commit.

@Evangelink Evangelink review requested due to automatic review settings May 16, 2026 11:04
Comment thread test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.Items.cs Outdated
Copilot AI review requested due to automatic review settings May 16, 2026 11:48
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: 17/17 changed files
  • Comments generated: 2

Comment on lines +385 to +386
EvidenceBlock evidence = EvidenceBlock.Create()
.AddLine("actual count:", "0");
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Done — the evidence value is now formatted via 0.ToString(CultureInfo.CurrentCulture) and reused for the new WithExpectedAndActual(...) call so the evidence respects non-Latin digit cultures, matching the other count-based assertions.


StructuredAssertionMessage structured = new(FrameworkMessages.IsNotEmptyFailedSummary);
structured.WithUserMessage(userMessage);
structured.WithEvidence(evidence);
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Done — added structured.WithExpectedAndActual("> 0", actualText) so ExpectedText/ActualText (and the assert.expected/assert.actual data entries) are populated for IsNotEmpty failures, matching the other count-based assertions.

…for IsNotEmpty

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.

4 participants