Skip to content

Fix inverted colors in HTML report ring chart due to locale-dependent decimal formatting#5185

Merged
thomhurst merged 4 commits intomainfrom
copilot/fix-inverted-colors-html-report
Mar 18, 2026
Merged

Fix inverted colors in HTML report ring chart due to locale-dependent decimal formatting#5185
thomhurst merged 4 commits intomainfrom
copilot/fix-inverted-colors-html-report

Conversation

Copy link
Contributor

Copilot AI commented Mar 18, 2026

The SVG ring chart in the HTML test report renders pass/fail segment colors in the wrong positions on systems using a non-English locale (e.g. Italian, French, German) where the decimal separator is a comma instead of a period.

Root cause: ToString("F2") without CultureInfo.InvariantCulture produces comma-separated decimals on non-English locales (e.g. Italian: 254,47 instead of 254.47). SVG parsers interpret commas as value separators, so:

  • stroke-dasharray="254,47 84,82" → parsed as 4 values [254, 47, 84, 82] instead of 2
  • stroke-dashoffset="-254,47" → truncated to -254

This causes the ring segments to render with completely wrong sizes and positions.

Fix: Added CultureInfo.InvariantCulture to all numeric ToString calls that produce SVG/CSS attribute values, ensuring period decimal separators regardless of system locale. Also fixed the FormatDuration method for the same reason.

locale-fix-comparison
Left: Bug (comma decimals from Italian locale) — ring segments broken. Right: Fix (period decimals) — green correctly covers 75%, red covers 25%.

Original prompt

This section details on the original issue you should resolve

<issue_title>[Bug]: Inverted colors in html report</issue_title>
<issue_description>### Description

in the lasts version of tunit (in this case the 1.19.74) the colors for the percentage of passed tests seems inverted:

Image

the red color in the ring cover the 75% of it instead of the 25%.
On the other hand, when the tests are all successful, the colors are right

Image

Expected Behavior

the red color in the ring should cover the related percentage

Actual Behavior

the red color in the ring cover the success percentage

Steps to Reproduce

  1. run a suite with 4 or more tests
  2. make at least 1 of them fail
  3. inspect the report and check the ring of pass rate

TUnit Version

1.19.74

.NET Version

.NET10

Operating System

Windows

IDE / Test Runner

dotnet CLI (dotnet test / dotnet run)

Error Output / Stack Trace

Additional Context

No response

IDE-Specific Issue?

  • I've confirmed this issue occurs when running via dotnet test or dotnet run, not just in my IDE</issue_description>

Comments on the Issue (you are @copilot in this section)


💬 Send tasks to Copilot coding agent from Slack and Teams to turn conversations into code. Copilot posts an update in your thread when it's finished.

…e-dashoffset

Co-authored-by: thomhurst <30480171+thomhurst@users.noreply.github.com>
Copilot AI changed the title [WIP] [Bug] Fix inverted colors in HTML report Fix inverted colors in HTML report ring chart Mar 18, 2026
Copilot AI requested a review from thomhurst March 18, 2026 13:57
@thomhurst
Copy link
Owner

@copilot your image of the "fix" isn't right. The green would then account for an50% pass rate. And 25% is grey implying not run.

…erted colors

Co-authored-by: thomhurst <30480171+thomhurst@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Mar 18, 2026

@copilot your image of the "fix" isn't right. The green would then account for an50% pass rate. And 25% is grey implying not run.

You're right, the sign removal was wrong. The real root cause is locale-dependent decimal formatting — ToString("F2") without CultureInfo.InvariantCulture produces comma decimals on non-English locales (e.g. Italian: 254,47). SVG parsers interpret commas as value separators, so stroke-dasharray="254,47 84,82" becomes 4 values instead of 2, completely breaking the segment sizes.

Fixed in 007ad90 by adding CultureInfo.InvariantCulture to all numeric ToString calls in SVG output, and restored the original negative stroke-dashoffset sign which was mathematically correct.

locale-fix-comparison

Copilot AI changed the title Fix inverted colors in HTML report ring chart Fix inverted colors in HTML report ring chart due to locale-dependent decimal formatting Mar 18, 2026
@thomhurst thomhurst marked this pull request as ready for review March 18, 2026 15:27
@thomhurst thomhurst enabled auto-merge (squash) March 18, 2026 15:27
Copy link
Contributor

@claude claude bot left a comment

Choose a reason for hiding this comment

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

Review: Fix inverted colors in HTML report ring chart due to locale-dependent decimal formatting

This is a correct and targeted fix for a genuine locale-sensitivity bug. The root cause analysis is accurate: ToString("F2") without CultureInfo.InvariantCulture produces comma as the decimal separator on many locales (e.g., Italian, French, German), which breaks SVG stroke-dasharray and stroke-dashoffset attribute parsing since SVG uses commas as value separators.

Correctness

The fix is correct. All five numeric formatting call sites that produce SVG/CSS attribute values are addressed:

  • passRate.ToString("F0", CultureInfo.InvariantCulture) — ring center percentage label (line 224)
  • len.ToString("F2", CultureInfo.InvariantCulture) — stroke-dasharray segment length (line 256)
  • (circumference - len).ToString("F2", CultureInfo.InvariantCulture) — stroke-dasharray gap (line 258)
  • offset.ToString("F2", CultureInfo.InvariantCulture) — stroke-dashoffset (line 260)
  • FormatDuration returns via string.Create(CultureInfo.InvariantCulture, ...) for all three branches (lines 372, 377, 380)

Minor Observations (not blocking)

1. FormatDuration — inconsistent approach vs. AppendRingSegment

The AppendRingSegment method uses .ToString("F2", CultureInfo.InvariantCulture) directly on double, while FormatDuration uses string.Create(CultureInfo.InvariantCulture, $"..."). Both are correct, but mixing styles across the same file is slightly inconsistent. For what it's worth, string.Create with an interpolated string handler avoids a format string allocation and is the more modern idiom — so if anything, the FormatDuration style is the better pattern.

2. FormatDuration output is used as display text, not SVG attribute values

The duration string is rendered inside an HTML <span> (line 243: sb.Append(FormatDuration(totalDurationMs))), not as an SVG numeric attribute. This means locale-dependent decimals here would not break SVG parsing — but they would cause visual inconsistency in the HTML text (e.g., "1,50s" vs "1.50s"), so fixing it here is still the right call for a consistent user experience.

3. Integer ToString() calls (lines 232–236) are locale-safe

The summary.Total.ToString(), summary.Passed.ToString(), etc. are integer types — ToString() on integers never uses a decimal separator, so these are safe to leave as-is.

4. passRate.ToString("F0", ...) — "F0" rounds to integer

"F0" produces no decimal point regardless of locale (it rounds to the nearest whole number), so the original passRate.ToString("F0") was already locale-safe. Adding CultureInfo.InvariantCulture here is harmless and makes the intent explicit, which is fine.

Summary

The fix is correct, minimal in scope, and directly addresses the reported bug. No unrelated changes are included. The approach is idiomatic for .NET locale-safe number formatting. Ready to merge.

@thomhurst
Copy link
Owner

@copilot failing pr checks

…atDuration

Co-authored-by: thomhurst <30480171+thomhurst@users.noreply.github.com>
auto-merge was automatically disabled March 18, 2026 15:47

Head branch was pushed to by a user without write access

Copy link
Contributor Author

Copilot AI commented Mar 18, 2026

@copilot failing pr checks

The netstandard2.0 build was failing because string.Create(CultureInfo, ...) is a .NET 6+ API. Replaced with ToString(format, CultureInfo.InvariantCulture) + suffix which is compatible with all targets. Fixed in dc25963.

Copilot AI temporarily deployed to Pull Requests March 18, 2026 17:50 Inactive
Copilot AI temporarily deployed to Pull Requests March 18, 2026 17:50 Inactive
@thomhurst thomhurst enabled auto-merge (squash) March 18, 2026 17:50
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.

[Bug]: Inverted colors in html report

2 participants