Skip to content

[duplicate-code] Duplicate Code: CTRF TestResultCapture duplicates constants and Truncate logic from TestResultCaptureHelper #9129

@Evangelink

Description

@Evangelink

🔍 Duplicate Code Detected: CTRF TestResultCapture diverges from TestResultCaptureHelper

Analysis of commit cf37d3b

Assignee: @copilot

Summary

src/Platform/Microsoft.Testing.Extensions.CtrfReport/TestResultCapture.cs contains hardcoded constants and a Truncate method that duplicate — and diverge fromSharedExtensionHelpers/TestResultCaptureHelper.cs. The JUnit and HTML report extensions already reference the shared helper; CTRF is the odd one out and has a subtly different (and potentially buggy) Truncate implementation that does not guard against splitting Unicode surrogate pairs.

Duplication Details

Pattern: Hardcoded size constants duplicated from TestResultCaptureHelper

  • Severity: Medium
  • Occurrences: 5 constants defined independently in CTRF, already centralised in shared helper
  • Locations:
    • src/Platform/Microsoft.Testing.Extensions.CtrfReport/TestResultCapture.cs (lines 16–20) — inline values
    • src/Platform/SharedExtensionHelpers/TestResultCaptureHelper.cs (lines 14–18) — canonical source
    • src/Platform/Microsoft.Testing.Extensions.JUnitReport/TestResultCapture.cs (lines 13–17) — already uses helper
    • src/Platform/Microsoft.Testing.Extensions.HtmlReport/TestResultCapture.cs (lines 13–17) — already uses helper

CTRF (duplicated inline values):

internal const int MaxStandardStreamLength = 32 * 1024;
internal const int MaxStackTraceLength     = 32 * 1024;
internal const int MaxMessageLength        = 16 * 1024;
internal const int MaxIdentityFieldLength  =  4 * 1024;
internal const int MaxTraitFieldLength     =       1024;

JUnit / HTML (correct — delegate to shared helper):

internal const int MaxStandardStreamLength = TestResultCaptureHelper.MaxStandardStreamLength;
internal const int MaxStackTraceLength     = TestResultCaptureHelper.MaxStackTraceLength;
// ...

Pattern: Truncate method implementation duplicated — and divergent

  • Severity: High (functional divergence — potential bug)
  • Occurrences: Local CTRF copy vs shared helper
  • Locations:
    • src/Platform/Microsoft.Testing.Extensions.CtrfReport/TestResultCapture.cs (lines 151–156) — own implementation
    • src/Platform/SharedExtensionHelpers/TestResultCaptureHelper.cs (lines 46–62) — canonical with surrogate-pair guard

CTRF Truncate (missing surrogate-pair guard):

internal static string? Truncate(string? value, int maxLength)
    => value is null || value.Length <= maxLength
        ? value
        : value.Substring(0, maxLength)
            + $"\n...[truncated, original length: {value.Length.ToString(CultureInfo.InvariantCulture)}]";

TestResultCaptureHelper.Truncate (correct — handles surrogate pairs):

int cut = maxLength;
if (cut > 0 && cut < value.Length && char.IsHighSurrogate(value[cut - 1]))
    cut--;   // drop the high surrogate to avoid an invalid UTF-16 string
return value.Substring(0, cut) + $"\n...[truncated, original length: ...]";

Impact Analysis

  • Maintainability: If the shared constants or Truncate logic in TestResultCaptureHelper are updated, the CTRF copy will silently drift further. The JUnit/HTML variants already delegate to the helper, making CTRF the outlier.
  • Bug Risk: Test-node display names or UIDs that end on a Unicode surrogate pair will produce an invalid string in the CTRF report (FormatException / JsonException when serialising) while working correctly in HTML and JUnit reports.
  • Code Bloat: ~12 lines of redundant code in a file that could be removed immediately.

Refactoring Recommendations

  1. Replace inline constants with TestResultCaptureHelper.* references

    • In src/Platform/Microsoft.Testing.Extensions.CtrfReport/TestResultCapture.cs, replace lines 16–20 with:
      internal const int MaxStandardStreamLength = TestResultCaptureHelper.MaxStandardStreamLength;
      internal const int MaxStackTraceLength     = TestResultCaptureHelper.MaxStackTraceLength;
      internal const int MaxMessageLength        = TestResultCaptureHelper.MaxMessageLength;
      internal const int MaxIdentityFieldLength  = TestResultCaptureHelper.MaxIdentityFieldLength;
      internal const int MaxTraitFieldLength     = TestResultCaptureHelper.MaxTraitFieldLength;
    • Estimated effort: < 15 minutes
    • Benefits: single source of truth; future constant changes propagate automatically
  2. Replace local Truncate with delegation to shared helper

    • Replace the CTRF Truncate implementation body with => TestResultCaptureHelper.Truncate(value, maxLength); — identical to the HTML pattern
    • Estimated effort: < 5 minutes
    • Benefits: fixes the surrogate-pair bug; keeps all reports consistent

Implementation Checklist

  • Review duplication findings
  • Replace the 5 inline constants in CTRF TestResultCapture with TestResultCaptureHelper.* references
  • Replace the CTRF Truncate body with delegation to TestResultCaptureHelper.Truncate
  • Remove the extra using directives in CtrfReport/TestResultCapture.cs that are no longer needed after delegation (e.g., Microsoft.Testing.Platform.Helpers, Microsoft.Testing.Platform)
  • Verify CTRF report unit tests still pass
  • Verify no functionality broken

Analysis Metadata

  • Analyzed Files: 4 (CtrfReport/TestResultCapture.cs, JUnitReport/TestResultCapture.cs, HtmlReport/TestResultCapture.cs, SharedExtensionHelpers/TestResultCaptureHelper.cs)
  • Detection Method: Semantic code analysis + diff between peer files
  • Commit: cf37d3b
  • Analysis Date: 2026-06-15

🤖 Automated content by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Duplicate Code Detector workflow. · 979.9 AIC · ⌖ 14.3 AIC · [◷]( · )

Add this agentic workflows to your repo

To install this agentic workflow, run

gh aw add githubnext/agentics/workflows/duplicate-code-detector.md@main
  • expires on Jun 17, 2026, 6:14 AM UTC

Metadata

Metadata

Labels

type/automationCreated or maintained by an agentic workflow.type/tech-debtCode health, refactoring, simplification.

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions