Render BCL values with full precision in assertion failure messages - #8964

Merged
Amaury Levé (Evangelink) merged 2 commits into
microsoft:mainfrom
Evangelink:dev/amauryleve/fix-8963-bcl-precision
Jun 10, 2026
Merged

Render BCL values with full precision in assertion failure messages#8964
Amaury Levé (Evangelink) merged 2 commits into
microsoft:mainfrom
Evangelink:dev/amauryleve/fix-8963-bcl-precision

Conversation

@Evangelink

Copy link
Copy Markdown
Member

Fixes#8963.

Problem

The structured assertion messages introduced by RFC-012 render values via AssertionValueRenderer.RenderValue, which previously fell back to value.ToString() for any type other than string/bool/char/IEnumerable. For many BCL types this collapses the precision the assertion was actually comparing, making failures hard to interpret. For example, when comparing two DateTime values that differ by a few ticks, both expected and actual were rendered as the same 2026-06-09T13:12:21 string.

Fix

Add type-specific, full-precision, culture-invariant arms to the central RenderValue switch:

TypeFormatNotes
DateTimeORound-trip, 7 fractional digits, preserves Kind
DateTimeOffsetORound-trip, preserves offset
TimeSpancConstant invariant format
DateOnly, TimeOnlyOGated #if NET6_0_OR_GREATER
float, doubleRRound-trip, distinguishes adjacent bit patterns
decimaldefaultAlready lossless; just forces InvariantCulture

All formatting uses CultureInfo.InvariantCulture so messages are reproducible regardless of the runner's locale (e.g. fr-FR no longer renders doubles with comma separators).

Because every public assertion API that surfaces values through structured messages funnels through this single renderer, the fix is centralized and covers AreEqual, AreNotEqual, AreEqual with delta, AreSequenceEqual, Contains, ContainsAll, DoesNotContain, IsInRange, IsGreaterThan, IsLessThan, AreEquivalent, etc.

Tests

  • Renderer-level (AssertionValueRendererTests): added ~20 tests covering all new branches — ticks-apart DateTime, UTC Kind, fractional-second TimeSpan, DateOnly/TimeOnly (NET6+), double NaN/Infinity/precision/invariant culture, float adjacent bit patterns, decimal invariant culture, and rendering inside collections. Float adjacent-bit construction uses BitConverter.GetBytes/ToUInt32/ToSingle so it works on net48.
  • End-to-end (AssertTests.RenderingPrecision.cs): a new AssertTests partial asserting failure-message contents for the impacted public APIs — Assert.AreEqual/AreNotEqual on DateTime/DateTimeOffset/double (incl. fr-FR)/float (adjacent-bit)/TimeSpan/decimal (fr-FR)/TimeOnly/DateOnly, AreEqual<double> with delta, IsInRange<DateTime>, IsGreaterThan<DateTime>, Contains<DateTime>, ContainsAll<DateTime>, AreSequenceEqual<DateTime>.

All 1,226 / 1,219 (net48) tests in TestFramework.UnitTests pass on net48, net8.0, and net9.0.

…icrosoft#8963)
Centralizes type-specific, full-precision, culture-invariant formatting
in AssertionValueRenderer.RenderValue so RFC-012 structured assertion
messages no longer collapse precision when comparing BCL values such as
DateTime, DateTimeOffset, TimeSpan, DateOnly, TimeOnly, float, double,
and decimal.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR improves MSTest’s structured assertion failure messages by rendering common BCL value types with full precision and using InvariantCulture, ensuring expected/actual values don’t collapse to indistinguishable text (fixes #8963).

Changes:

  • Extend AssertionValueRenderer.RenderValue with type-specific, full-precision, culture-invariant formatting for DateTime, DateTimeOffset, TimeSpan, float, double, decimal (and DateOnly/TimeOnly on NET6+).
  • Add renderer-level unit tests covering the new formatting branches and culture invariance.
  • Add end-to-end assertion tests validating failure-message contents for multiple public Assert APIs.
Show a summary per file
FileDescription
src/TestFramework/TestFramework/Assertions/AssertionValueRenderer.csAdds invariant, full-precision formatting arms for key BCL types in the central renderer.
test/UnitTests/TestFramework.UnitTests/Assertions/AssertionValueRendererTests.csExpands unit coverage for new renderer behavior (precision, special floating values, invariant culture, NET6+ types, collections).
test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.RenderingPrecision.csAdds regression tests that validate failure messages across key assertion APIs now render BCL values with full precision.

Copilot's findings

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

Replace ex.Message.Should().Contain(...) substring checks with exact
full-message assertions via .WithMessage(raw-string) so we catch any
change in the structured message layout (summary, evidence block
padding, call-site expression) in addition to the rendered values
themselves.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for freeto 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.

Expected/actual values are not precise enough for BCL types

3 participants

@Evangelink@YuliiaKovalova
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Render BCL values with full precision in assertion failure messages - #8964

Merged
Amaury Levé (Evangelink) merged 2 commits into
microsoft:mainfrom
Evangelink:dev/amauryleve/fix-8963-bcl-precision
Jun 10, 2026
Merged

Render BCL values with full precision in assertion failure messages#8964
Amaury Levé (Evangelink) merged 2 commits into
microsoft:mainfrom
Evangelink:dev/amauryleve/fix-8963-bcl-precision

Conversation

@Evangelink

Copy link
Copy Markdown
Member

Fixes#8963.

Problem

The structured assertion messages introduced by RFC-012 render values via AssertionValueRenderer.RenderValue, which previously fell back to value.ToString() for any type other than string/bool/char/IEnumerable. For many BCL types this collapses the precision the assertion was actually comparing, making failures hard to interpret. For example, when comparing two DateTime values that differ by a few ticks, both expected and actual were rendered as the same 2026-06-09T13:12:21 string.

Fix

Add type-specific, full-precision, culture-invariant arms to the central RenderValue switch:

TypeFormatNotes
DateTimeORound-trip, 7 fractional digits, preserves Kind
DateTimeOffsetORound-trip, preserves offset
TimeSpancConstant invariant format
DateOnly, TimeOnlyOGated #if NET6_0_OR_GREATER
float, doubleRRound-trip, distinguishes adjacent bit patterns
decimaldefaultAlready lossless; just forces InvariantCulture

All formatting uses CultureInfo.InvariantCulture so messages are reproducible regardless of the runner's locale (e.g. fr-FR no longer renders doubles with comma separators).

Because every public assertion API that surfaces values through structured messages funnels through this single renderer, the fix is centralized and covers AreEqual, AreNotEqual, AreEqual with delta, AreSequenceEqual, Contains, ContainsAll, DoesNotContain, IsInRange, IsGreaterThan, IsLessThan, AreEquivalent, etc.

Tests

  • Renderer-level (AssertionValueRendererTests): added ~20 tests covering all new branches — ticks-apart DateTime, UTC Kind, fractional-second TimeSpan, DateOnly/TimeOnly (NET6+), double NaN/Infinity/precision/invariant culture, float adjacent bit patterns, decimal invariant culture, and rendering inside collections. Float adjacent-bit construction uses BitConverter.GetBytes/ToUInt32/ToSingle so it works on net48.
  • End-to-end (AssertTests.RenderingPrecision.cs): a new AssertTests partial asserting failure-message contents for the impacted public APIs — Assert.AreEqual/AreNotEqual on DateTime/DateTimeOffset/double (incl. fr-FR)/float (adjacent-bit)/TimeSpan/decimal (fr-FR)/TimeOnly/DateOnly, AreEqual<double> with delta, IsInRange<DateTime>, IsGreaterThan<DateTime>, Contains<DateTime>, ContainsAll<DateTime>, AreSequenceEqual<DateTime>.

All 1,226 / 1,219 (net48) tests in TestFramework.UnitTests pass on net48, net8.0, and net9.0.

…icrosoft#8963)
Centralizes type-specific, full-precision, culture-invariant formatting
in AssertionValueRenderer.RenderValue so RFC-012 structured assertion
messages no longer collapse precision when comparing BCL values such as
DateTime, DateTimeOffset, TimeSpan, DateOnly, TimeOnly, float, double,
and decimal.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR improves MSTest’s structured assertion failure messages by rendering common BCL value types with full precision and using InvariantCulture, ensuring expected/actual values don’t collapse to indistinguishable text (fixes #8963).

Changes:

  • Extend AssertionValueRenderer.RenderValue with type-specific, full-precision, culture-invariant formatting for DateTime, DateTimeOffset, TimeSpan, float, double, decimal (and DateOnly/TimeOnly on NET6+).
  • Add renderer-level unit tests covering the new formatting branches and culture invariance.
  • Add end-to-end assertion tests validating failure-message contents for multiple public Assert APIs.
Show a summary per file
FileDescription
src/TestFramework/TestFramework/Assertions/AssertionValueRenderer.csAdds invariant, full-precision formatting arms for key BCL types in the central renderer.
test/UnitTests/TestFramework.UnitTests/Assertions/AssertionValueRendererTests.csExpands unit coverage for new renderer behavior (precision, special floating values, invariant culture, NET6+ types, collections).
test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.RenderingPrecision.csAdds regression tests that validate failure messages across key assertion APIs now render BCL values with full precision.

Copilot's findings

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

Replace ex.Message.Should().Contain(...) substring checks with exact
full-message assertions via .WithMessage(raw-string) so we catch any
change in the structured message layout (summary, evidence block
padding, call-site expression) in addition to the rendered values
themselves.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for freeto 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.

Expected/actual values are not precise enough for BCL types

3 participants

@Evangelink@YuliiaKovalova
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Render BCL values with full precision in assertion failure messages - #8964

Merged
Amaury Levé (Evangelink) merged 2 commits into
microsoft:mainfrom
Evangelink:dev/amauryleve/fix-8963-bcl-precision
Jun 10, 2026
Merged

Render BCL values with full precision in assertion failure messages#8964
Amaury Levé (Evangelink) merged 2 commits into
microsoft:mainfrom
Evangelink:dev/amauryleve/fix-8963-bcl-precision

Conversation

@Evangelink

Copy link
Copy Markdown
Member

Fixes#8963.

Problem

The structured assertion messages introduced by RFC-012 render values via AssertionValueRenderer.RenderValue, which previously fell back to value.ToString() for any type other than string/bool/char/IEnumerable. For many BCL types this collapses the precision the assertion was actually comparing, making failures hard to interpret. For example, when comparing two DateTime values that differ by a few ticks, both expected and actual were rendered as the same 2026-06-09T13:12:21 string.

Fix

Add type-specific, full-precision, culture-invariant arms to the central RenderValue switch:

TypeFormatNotes
DateTimeORound-trip, 7 fractional digits, preserves Kind
DateTimeOffsetORound-trip, preserves offset
TimeSpancConstant invariant format
DateOnly, TimeOnlyOGated #if NET6_0_OR_GREATER
float, doubleRRound-trip, distinguishes adjacent bit patterns
decimaldefaultAlready lossless; just forces InvariantCulture

All formatting uses CultureInfo.InvariantCulture so messages are reproducible regardless of the runner's locale (e.g. fr-FR no longer renders doubles with comma separators).

Because every public assertion API that surfaces values through structured messages funnels through this single renderer, the fix is centralized and covers AreEqual, AreNotEqual, AreEqual with delta, AreSequenceEqual, Contains, ContainsAll, DoesNotContain, IsInRange, IsGreaterThan, IsLessThan, AreEquivalent, etc.

Tests

  • Renderer-level (AssertionValueRendererTests): added ~20 tests covering all new branches — ticks-apart DateTime, UTC Kind, fractional-second TimeSpan, DateOnly/TimeOnly (NET6+), double NaN/Infinity/precision/invariant culture, float adjacent bit patterns, decimal invariant culture, and rendering inside collections. Float adjacent-bit construction uses BitConverter.GetBytes/ToUInt32/ToSingle so it works on net48.
  • End-to-end (AssertTests.RenderingPrecision.cs): a new AssertTests partial asserting failure-message contents for the impacted public APIs — Assert.AreEqual/AreNotEqual on DateTime/DateTimeOffset/double (incl. fr-FR)/float (adjacent-bit)/TimeSpan/decimal (fr-FR)/TimeOnly/DateOnly, AreEqual<double> with delta, IsInRange<DateTime>, IsGreaterThan<DateTime>, Contains<DateTime>, ContainsAll<DateTime>, AreSequenceEqual<DateTime>.

All 1,226 / 1,219 (net48) tests in TestFramework.UnitTests pass on net48, net8.0, and net9.0.

…icrosoft#8963)
Centralizes type-specific, full-precision, culture-invariant formatting
in AssertionValueRenderer.RenderValue so RFC-012 structured assertion
messages no longer collapse precision when comparing BCL values such as
DateTime, DateTimeOffset, TimeSpan, DateOnly, TimeOnly, float, double,
and decimal.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR improves MSTest’s structured assertion failure messages by rendering common BCL value types with full precision and using InvariantCulture, ensuring expected/actual values don’t collapse to indistinguishable text (fixes #8963).

Changes:

  • Extend AssertionValueRenderer.RenderValue with type-specific, full-precision, culture-invariant formatting for DateTime, DateTimeOffset, TimeSpan, float, double, decimal (and DateOnly/TimeOnly on NET6+).
  • Add renderer-level unit tests covering the new formatting branches and culture invariance.
  • Add end-to-end assertion tests validating failure-message contents for multiple public Assert APIs.
Show a summary per file
FileDescription
src/TestFramework/TestFramework/Assertions/AssertionValueRenderer.csAdds invariant, full-precision formatting arms for key BCL types in the central renderer.
test/UnitTests/TestFramework.UnitTests/Assertions/AssertionValueRendererTests.csExpands unit coverage for new renderer behavior (precision, special floating values, invariant culture, NET6+ types, collections).
test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.RenderingPrecision.csAdds regression tests that validate failure messages across key assertion APIs now render BCL values with full precision.

Copilot's findings

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

Replace ex.Message.Should().Contain(...) substring checks with exact
full-message assertions via .WithMessage(raw-string) so we catch any
change in the structured message layout (summary, evidence block
padding, call-site expression) in addition to the rendered values
themselves.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for freeto 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.

Expected/actual values are not precise enough for BCL types

3 participants

@Evangelink@YuliiaKovalova
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Render BCL values with full precision in assertion failure messages - #8964

Merged
Amaury Levé (Evangelink) merged 2 commits into
microsoft:mainfrom
Evangelink:dev/amauryleve/fix-8963-bcl-precision
Jun 10, 2026
Merged

Render BCL values with full precision in assertion failure messages#8964
Amaury Levé (Evangelink) merged 2 commits into
microsoft:mainfrom
Evangelink:dev/amauryleve/fix-8963-bcl-precision

Conversation

@Evangelink

Copy link
Copy Markdown
Member

Fixes#8963.

Problem

The structured assertion messages introduced by RFC-012 render values via AssertionValueRenderer.RenderValue, which previously fell back to value.ToString() for any type other than string/bool/char/IEnumerable. For many BCL types this collapses the precision the assertion was actually comparing, making failures hard to interpret. For example, when comparing two DateTime values that differ by a few ticks, both expected and actual were rendered as the same 2026-06-09T13:12:21 string.

Fix

Add type-specific, full-precision, culture-invariant arms to the central RenderValue switch:

TypeFormatNotes
DateTimeORound-trip, 7 fractional digits, preserves Kind
DateTimeOffsetORound-trip, preserves offset
TimeSpancConstant invariant format
DateOnly, TimeOnlyOGated #if NET6_0_OR_GREATER
float, doubleRRound-trip, distinguishes adjacent bit patterns
decimaldefaultAlready lossless; just forces InvariantCulture

All formatting uses CultureInfo.InvariantCulture so messages are reproducible regardless of the runner's locale (e.g. fr-FR no longer renders doubles with comma separators).

Because every public assertion API that surfaces values through structured messages funnels through this single renderer, the fix is centralized and covers AreEqual, AreNotEqual, AreEqual with delta, AreSequenceEqual, Contains, ContainsAll, DoesNotContain, IsInRange, IsGreaterThan, IsLessThan, AreEquivalent, etc.

Tests

  • Renderer-level (AssertionValueRendererTests): added ~20 tests covering all new branches — ticks-apart DateTime, UTC Kind, fractional-second TimeSpan, DateOnly/TimeOnly (NET6+), double NaN/Infinity/precision/invariant culture, float adjacent bit patterns, decimal invariant culture, and rendering inside collections. Float adjacent-bit construction uses BitConverter.GetBytes/ToUInt32/ToSingle so it works on net48.
  • End-to-end (AssertTests.RenderingPrecision.cs): a new AssertTests partial asserting failure-message contents for the impacted public APIs — Assert.AreEqual/AreNotEqual on DateTime/DateTimeOffset/double (incl. fr-FR)/float (adjacent-bit)/TimeSpan/decimal (fr-FR)/TimeOnly/DateOnly, AreEqual<double> with delta, IsInRange<DateTime>, IsGreaterThan<DateTime>, Contains<DateTime>, ContainsAll<DateTime>, AreSequenceEqual<DateTime>.

All 1,226 / 1,219 (net48) tests in TestFramework.UnitTests pass on net48, net8.0, and net9.0.

…icrosoft#8963)
Centralizes type-specific, full-precision, culture-invariant formatting
in AssertionValueRenderer.RenderValue so RFC-012 structured assertion
messages no longer collapse precision when comparing BCL values such as
DateTime, DateTimeOffset, TimeSpan, DateOnly, TimeOnly, float, double,
and decimal.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR improves MSTest’s structured assertion failure messages by rendering common BCL value types with full precision and using InvariantCulture, ensuring expected/actual values don’t collapse to indistinguishable text (fixes #8963).

Changes:

  • Extend AssertionValueRenderer.RenderValue with type-specific, full-precision, culture-invariant formatting for DateTime, DateTimeOffset, TimeSpan, float, double, decimal (and DateOnly/TimeOnly on NET6+).
  • Add renderer-level unit tests covering the new formatting branches and culture invariance.
  • Add end-to-end assertion tests validating failure-message contents for multiple public Assert APIs.
Show a summary per file
FileDescription
src/TestFramework/TestFramework/Assertions/AssertionValueRenderer.csAdds invariant, full-precision formatting arms for key BCL types in the central renderer.
test/UnitTests/TestFramework.UnitTests/Assertions/AssertionValueRendererTests.csExpands unit coverage for new renderer behavior (precision, special floating values, invariant culture, NET6+ types, collections).
test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.RenderingPrecision.csAdds regression tests that validate failure messages across key assertion APIs now render BCL values with full precision.

Copilot's findings

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

Replace ex.Message.Should().Contain(...) substring checks with exact
full-message assertions via .WithMessage(raw-string) so we catch any
change in the structured message layout (summary, evidence block
padding, call-site expression) in addition to the rendered values
themselves.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for freeto 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.

Expected/actual values are not precise enough for BCL types

3 participants

@Evangelink@YuliiaKovalova
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Render BCL values with full precision in assertion failure messages - #8964

Merged
Amaury Levé (Evangelink) merged 2 commits into
microsoft:mainfrom
Evangelink:dev/amauryleve/fix-8963-bcl-precision
Jun 10, 2026
Merged

Render BCL values with full precision in assertion failure messages#8964
Amaury Levé (Evangelink) merged 2 commits into
microsoft:mainfrom
Evangelink:dev/amauryleve/fix-8963-bcl-precision

Conversation

@Evangelink

Copy link
Copy Markdown
Member

Fixes#8963.

Problem

The structured assertion messages introduced by RFC-012 render values via AssertionValueRenderer.RenderValue, which previously fell back to value.ToString() for any type other than string/bool/char/IEnumerable. For many BCL types this collapses the precision the assertion was actually comparing, making failures hard to interpret. For example, when comparing two DateTime values that differ by a few ticks, both expected and actual were rendered as the same 2026-06-09T13:12:21 string.

Fix

Add type-specific, full-precision, culture-invariant arms to the central RenderValue switch:

TypeFormatNotes
DateTimeORound-trip, 7 fractional digits, preserves Kind
DateTimeOffsetORound-trip, preserves offset
TimeSpancConstant invariant format
DateOnly, TimeOnlyOGated #if NET6_0_OR_GREATER
float, doubleRRound-trip, distinguishes adjacent bit patterns
decimaldefaultAlready lossless; just forces InvariantCulture

All formatting uses CultureInfo.InvariantCulture so messages are reproducible regardless of the runner's locale (e.g. fr-FR no longer renders doubles with comma separators).

Because every public assertion API that surfaces values through structured messages funnels through this single renderer, the fix is centralized and covers AreEqual, AreNotEqual, AreEqual with delta, AreSequenceEqual, Contains, ContainsAll, DoesNotContain, IsInRange, IsGreaterThan, IsLessThan, AreEquivalent, etc.

Tests

  • Renderer-level (AssertionValueRendererTests): added ~20 tests covering all new branches — ticks-apart DateTime, UTC Kind, fractional-second TimeSpan, DateOnly/TimeOnly (NET6+), double NaN/Infinity/precision/invariant culture, float adjacent bit patterns, decimal invariant culture, and rendering inside collections. Float adjacent-bit construction uses BitConverter.GetBytes/ToUInt32/ToSingle so it works on net48.
  • End-to-end (AssertTests.RenderingPrecision.cs): a new AssertTests partial asserting failure-message contents for the impacted public APIs — Assert.AreEqual/AreNotEqual on DateTime/DateTimeOffset/double (incl. fr-FR)/float (adjacent-bit)/TimeSpan/decimal (fr-FR)/TimeOnly/DateOnly, AreEqual<double> with delta, IsInRange<DateTime>, IsGreaterThan<DateTime>, Contains<DateTime>, ContainsAll<DateTime>, AreSequenceEqual<DateTime>.

All 1,226 / 1,219 (net48) tests in TestFramework.UnitTests pass on net48, net8.0, and net9.0.

…icrosoft#8963)
Centralizes type-specific, full-precision, culture-invariant formatting
in AssertionValueRenderer.RenderValue so RFC-012 structured assertion
messages no longer collapse precision when comparing BCL values such as
DateTime, DateTimeOffset, TimeSpan, DateOnly, TimeOnly, float, double,
and decimal.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR improves MSTest’s structured assertion failure messages by rendering common BCL value types with full precision and using InvariantCulture, ensuring expected/actual values don’t collapse to indistinguishable text (fixes #8963).

Changes:

  • Extend AssertionValueRenderer.RenderValue with type-specific, full-precision, culture-invariant formatting for DateTime, DateTimeOffset, TimeSpan, float, double, decimal (and DateOnly/TimeOnly on NET6+).
  • Add renderer-level unit tests covering the new formatting branches and culture invariance.
  • Add end-to-end assertion tests validating failure-message contents for multiple public Assert APIs.
Show a summary per file
FileDescription
src/TestFramework/TestFramework/Assertions/AssertionValueRenderer.csAdds invariant, full-precision formatting arms for key BCL types in the central renderer.
test/UnitTests/TestFramework.UnitTests/Assertions/AssertionValueRendererTests.csExpands unit coverage for new renderer behavior (precision, special floating values, invariant culture, NET6+ types, collections).
test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.RenderingPrecision.csAdds regression tests that validate failure messages across key assertion APIs now render BCL values with full precision.

Copilot's findings

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

Replace ex.Message.Should().Contain(...) substring checks with exact
full-message assertions via .WithMessage(raw-string) so we catch any
change in the structured message layout (summary, evidence block
padding, call-site expression) in addition to the rendered values
themselves.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for freeto 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.

Expected/actual values are not precise enough for BCL types

3 participants

@Evangelink@YuliiaKovalova
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Render BCL values with full precision in assertion failure messages - #8964

Merged
Amaury Levé (Evangelink) merged 2 commits into
microsoft:mainfrom
Evangelink:dev/amauryleve/fix-8963-bcl-precision
Jun 10, 2026
Merged

Render BCL values with full precision in assertion failure messages#8964
Amaury Levé (Evangelink) merged 2 commits into
microsoft:mainfrom
Evangelink:dev/amauryleve/fix-8963-bcl-precision

Conversation

@Evangelink

Copy link
Copy Markdown
Member

Fixes#8963.

Problem

The structured assertion messages introduced by RFC-012 render values via AssertionValueRenderer.RenderValue, which previously fell back to value.ToString() for any type other than string/bool/char/IEnumerable. For many BCL types this collapses the precision the assertion was actually comparing, making failures hard to interpret. For example, when comparing two DateTime values that differ by a few ticks, both expected and actual were rendered as the same 2026-06-09T13:12:21 string.

Fix

Add type-specific, full-precision, culture-invariant arms to the central RenderValue switch:

TypeFormatNotes
DateTimeORound-trip, 7 fractional digits, preserves Kind
DateTimeOffsetORound-trip, preserves offset
TimeSpancConstant invariant format
DateOnly, TimeOnlyOGated #if NET6_0_OR_GREATER
float, doubleRRound-trip, distinguishes adjacent bit patterns
decimaldefaultAlready lossless; just forces InvariantCulture

All formatting uses CultureInfo.InvariantCulture so messages are reproducible regardless of the runner's locale (e.g. fr-FR no longer renders doubles with comma separators).

Because every public assertion API that surfaces values through structured messages funnels through this single renderer, the fix is centralized and covers AreEqual, AreNotEqual, AreEqual with delta, AreSequenceEqual, Contains, ContainsAll, DoesNotContain, IsInRange, IsGreaterThan, IsLessThan, AreEquivalent, etc.

Tests

  • Renderer-level (AssertionValueRendererTests): added ~20 tests covering all new branches — ticks-apart DateTime, UTC Kind, fractional-second TimeSpan, DateOnly/TimeOnly (NET6+), double NaN/Infinity/precision/invariant culture, float adjacent bit patterns, decimal invariant culture, and rendering inside collections. Float adjacent-bit construction uses BitConverter.GetBytes/ToUInt32/ToSingle so it works on net48.
  • End-to-end (AssertTests.RenderingPrecision.cs): a new AssertTests partial asserting failure-message contents for the impacted public APIs — Assert.AreEqual/AreNotEqual on DateTime/DateTimeOffset/double (incl. fr-FR)/float (adjacent-bit)/TimeSpan/decimal (fr-FR)/TimeOnly/DateOnly, AreEqual<double> with delta, IsInRange<DateTime>, IsGreaterThan<DateTime>, Contains<DateTime>, ContainsAll<DateTime>, AreSequenceEqual<DateTime>.

All 1,226 / 1,219 (net48) tests in TestFramework.UnitTests pass on net48, net8.0, and net9.0.

…icrosoft#8963)
Centralizes type-specific, full-precision, culture-invariant formatting
in AssertionValueRenderer.RenderValue so RFC-012 structured assertion
messages no longer collapse precision when comparing BCL values such as
DateTime, DateTimeOffset, TimeSpan, DateOnly, TimeOnly, float, double,
and decimal.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR improves MSTest’s structured assertion failure messages by rendering common BCL value types with full precision and using InvariantCulture, ensuring expected/actual values don’t collapse to indistinguishable text (fixes #8963).

Changes:

  • Extend AssertionValueRenderer.RenderValue with type-specific, full-precision, culture-invariant formatting for DateTime, DateTimeOffset, TimeSpan, float, double, decimal (and DateOnly/TimeOnly on NET6+).
  • Add renderer-level unit tests covering the new formatting branches and culture invariance.
  • Add end-to-end assertion tests validating failure-message contents for multiple public Assert APIs.
Show a summary per file
FileDescription
src/TestFramework/TestFramework/Assertions/AssertionValueRenderer.csAdds invariant, full-precision formatting arms for key BCL types in the central renderer.
test/UnitTests/TestFramework.UnitTests/Assertions/AssertionValueRendererTests.csExpands unit coverage for new renderer behavior (precision, special floating values, invariant culture, NET6+ types, collections).
test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.RenderingPrecision.csAdds regression tests that validate failure messages across key assertion APIs now render BCL values with full precision.

Copilot's findings

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

Replace ex.Message.Should().Contain(...) substring checks with exact
full-message assertions via .WithMessage(raw-string) so we catch any
change in the structured message layout (summary, evidence block
padding, call-site expression) in addition to the rendered values
themselves.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for freeto 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.

Expected/actual values are not precise enough for BCL types

3 participants

@Evangelink@YuliiaKovalova
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Render BCL values with full precision in assertion failure messages - #8964

Merged
Amaury Levé (Evangelink) merged 2 commits into
microsoft:mainfrom
Evangelink:dev/amauryleve/fix-8963-bcl-precision
Jun 10, 2026
Merged

Render BCL values with full precision in assertion failure messages#8964
Amaury Levé (Evangelink) merged 2 commits into
microsoft:mainfrom
Evangelink:dev/amauryleve/fix-8963-bcl-precision

Conversation

@Evangelink

Copy link
Copy Markdown
Member

Fixes#8963.

Problem

The structured assertion messages introduced by RFC-012 render values via AssertionValueRenderer.RenderValue, which previously fell back to value.ToString() for any type other than string/bool/char/IEnumerable. For many BCL types this collapses the precision the assertion was actually comparing, making failures hard to interpret. For example, when comparing two DateTime values that differ by a few ticks, both expected and actual were rendered as the same 2026-06-09T13:12:21 string.

Fix

Add type-specific, full-precision, culture-invariant arms to the central RenderValue switch:

TypeFormatNotes
DateTimeORound-trip, 7 fractional digits, preserves Kind
DateTimeOffsetORound-trip, preserves offset
TimeSpancConstant invariant format
DateOnly, TimeOnlyOGated #if NET6_0_OR_GREATER
float, doubleRRound-trip, distinguishes adjacent bit patterns
decimaldefaultAlready lossless; just forces InvariantCulture

All formatting uses CultureInfo.InvariantCulture so messages are reproducible regardless of the runner's locale (e.g. fr-FR no longer renders doubles with comma separators).

Because every public assertion API that surfaces values through structured messages funnels through this single renderer, the fix is centralized and covers AreEqual, AreNotEqual, AreEqual with delta, AreSequenceEqual, Contains, ContainsAll, DoesNotContain, IsInRange, IsGreaterThan, IsLessThan, AreEquivalent, etc.

Tests

  • Renderer-level (AssertionValueRendererTests): added ~20 tests covering all new branches — ticks-apart DateTime, UTC Kind, fractional-second TimeSpan, DateOnly/TimeOnly (NET6+), double NaN/Infinity/precision/invariant culture, float adjacent bit patterns, decimal invariant culture, and rendering inside collections. Float adjacent-bit construction uses BitConverter.GetBytes/ToUInt32/ToSingle so it works on net48.
  • End-to-end (AssertTests.RenderingPrecision.cs): a new AssertTests partial asserting failure-message contents for the impacted public APIs — Assert.AreEqual/AreNotEqual on DateTime/DateTimeOffset/double (incl. fr-FR)/float (adjacent-bit)/TimeSpan/decimal (fr-FR)/TimeOnly/DateOnly, AreEqual<double> with delta, IsInRange<DateTime>, IsGreaterThan<DateTime>, Contains<DateTime>, ContainsAll<DateTime>, AreSequenceEqual<DateTime>.

All 1,226 / 1,219 (net48) tests in TestFramework.UnitTests pass on net48, net8.0, and net9.0.

…icrosoft#8963)
Centralizes type-specific, full-precision, culture-invariant formatting
in AssertionValueRenderer.RenderValue so RFC-012 structured assertion
messages no longer collapse precision when comparing BCL values such as
DateTime, DateTimeOffset, TimeSpan, DateOnly, TimeOnly, float, double,
and decimal.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR improves MSTest’s structured assertion failure messages by rendering common BCL value types with full precision and using InvariantCulture, ensuring expected/actual values don’t collapse to indistinguishable text (fixes #8963).

Changes:

  • Extend AssertionValueRenderer.RenderValue with type-specific, full-precision, culture-invariant formatting for DateTime, DateTimeOffset, TimeSpan, float, double, decimal (and DateOnly/TimeOnly on NET6+).
  • Add renderer-level unit tests covering the new formatting branches and culture invariance.
  • Add end-to-end assertion tests validating failure-message contents for multiple public Assert APIs.
Show a summary per file
FileDescription
src/TestFramework/TestFramework/Assertions/AssertionValueRenderer.csAdds invariant, full-precision formatting arms for key BCL types in the central renderer.
test/UnitTests/TestFramework.UnitTests/Assertions/AssertionValueRendererTests.csExpands unit coverage for new renderer behavior (precision, special floating values, invariant culture, NET6+ types, collections).
test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.RenderingPrecision.csAdds regression tests that validate failure messages across key assertion APIs now render BCL values with full precision.

Copilot's findings

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

Replace ex.Message.Should().Contain(...) substring checks with exact
full-message assertions via .WithMessage(raw-string) so we catch any
change in the structured message layout (summary, evidence block
padding, call-site expression) in addition to the rendered values
themselves.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for freeto 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.

Expected/actual values are not precise enough for BCL types

3 participants

@Evangelink@YuliiaKovalova
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Render BCL values with full precision in assertion failure messages - #8964

Merged
Amaury Levé (Evangelink) merged 2 commits into
microsoft:mainfrom
Evangelink:dev/amauryleve/fix-8963-bcl-precision
Jun 10, 2026
Merged

Render BCL values with full precision in assertion failure messages#8964
Amaury Levé (Evangelink) merged 2 commits into
microsoft:mainfrom
Evangelink:dev/amauryleve/fix-8963-bcl-precision

Conversation

@Evangelink

Copy link
Copy Markdown
Member

Fixes#8963.

Problem

The structured assertion messages introduced by RFC-012 render values via AssertionValueRenderer.RenderValue, which previously fell back to value.ToString() for any type other than string/bool/char/IEnumerable. For many BCL types this collapses the precision the assertion was actually comparing, making failures hard to interpret. For example, when comparing two DateTime values that differ by a few ticks, both expected and actual were rendered as the same 2026-06-09T13:12:21 string.

Fix

Add type-specific, full-precision, culture-invariant arms to the central RenderValue switch:

TypeFormatNotes
DateTimeORound-trip, 7 fractional digits, preserves Kind
DateTimeOffsetORound-trip, preserves offset
TimeSpancConstant invariant format
DateOnly, TimeOnlyOGated #if NET6_0_OR_GREATER
float, doubleRRound-trip, distinguishes adjacent bit patterns
decimaldefaultAlready lossless; just forces InvariantCulture

All formatting uses CultureInfo.InvariantCulture so messages are reproducible regardless of the runner's locale (e.g. fr-FR no longer renders doubles with comma separators).

Because every public assertion API that surfaces values through structured messages funnels through this single renderer, the fix is centralized and covers AreEqual, AreNotEqual, AreEqual with delta, AreSequenceEqual, Contains, ContainsAll, DoesNotContain, IsInRange, IsGreaterThan, IsLessThan, AreEquivalent, etc.

Tests

  • Renderer-level (AssertionValueRendererTests): added ~20 tests covering all new branches — ticks-apart DateTime, UTC Kind, fractional-second TimeSpan, DateOnly/TimeOnly (NET6+), double NaN/Infinity/precision/invariant culture, float adjacent bit patterns, decimal invariant culture, and rendering inside collections. Float adjacent-bit construction uses BitConverter.GetBytes/ToUInt32/ToSingle so it works on net48.
  • End-to-end (AssertTests.RenderingPrecision.cs): a new AssertTests partial asserting failure-message contents for the impacted public APIs — Assert.AreEqual/AreNotEqual on DateTime/DateTimeOffset/double (incl. fr-FR)/float (adjacent-bit)/TimeSpan/decimal (fr-FR)/TimeOnly/DateOnly, AreEqual<double> with delta, IsInRange<DateTime>, IsGreaterThan<DateTime>, Contains<DateTime>, ContainsAll<DateTime>, AreSequenceEqual<DateTime>.

All 1,226 / 1,219 (net48) tests in TestFramework.UnitTests pass on net48, net8.0, and net9.0.

…icrosoft#8963)
Centralizes type-specific, full-precision, culture-invariant formatting
in AssertionValueRenderer.RenderValue so RFC-012 structured assertion
messages no longer collapse precision when comparing BCL values such as
DateTime, DateTimeOffset, TimeSpan, DateOnly, TimeOnly, float, double,
and decimal.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR improves MSTest’s structured assertion failure messages by rendering common BCL value types with full precision and using InvariantCulture, ensuring expected/actual values don’t collapse to indistinguishable text (fixes #8963).

Changes:

  • Extend AssertionValueRenderer.RenderValue with type-specific, full-precision, culture-invariant formatting for DateTime, DateTimeOffset, TimeSpan, float, double, decimal (and DateOnly/TimeOnly on NET6+).
  • Add renderer-level unit tests covering the new formatting branches and culture invariance.
  • Add end-to-end assertion tests validating failure-message contents for multiple public Assert APIs.
Show a summary per file
FileDescription
src/TestFramework/TestFramework/Assertions/AssertionValueRenderer.csAdds invariant, full-precision formatting arms for key BCL types in the central renderer.
test/UnitTests/TestFramework.UnitTests/Assertions/AssertionValueRendererTests.csExpands unit coverage for new renderer behavior (precision, special floating values, invariant culture, NET6+ types, collections).
test/UnitTests/TestFramework.UnitTests/Assertions/AssertTests.RenderingPrecision.csAdds regression tests that validate failure messages across key assertion APIs now render BCL values with full precision.

Copilot's findings

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

Replace ex.Message.Should().Contain(...) substring checks with exact
full-message assertions via .WithMessage(raw-string) so we catch any
change in the structured message layout (summary, evidence block
padding, call-site expression) in addition to the rendered values
themselves.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for freeto 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.

Expected/actual values are not precise enough for BCL types

3 participants

@Evangelink@YuliiaKovalova