🔍 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 from — SharedExtensionHelpers/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
-
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
-
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
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
🔍 Duplicate Code Detected: CTRF
TestResultCapturediverges fromTestResultCaptureHelperAnalysis of commit cf37d3b
Assignee:
@copilotSummary
src/Platform/Microsoft.Testing.Extensions.CtrfReport/TestResultCapture.cscontains hardcoded constants and aTruncatemethod that duplicate — and diverge from —SharedExtensionHelpers/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)Truncateimplementation that does not guard against splitting Unicode surrogate pairs.Duplication Details
Pattern: Hardcoded size constants duplicated from
TestResultCaptureHelpersrc/Platform/Microsoft.Testing.Extensions.CtrfReport/TestResultCapture.cs(lines 16–20) — inline valuessrc/Platform/SharedExtensionHelpers/TestResultCaptureHelper.cs(lines 14–18) — canonical sourcesrc/Platform/Microsoft.Testing.Extensions.JUnitReport/TestResultCapture.cs(lines 13–17) — already uses helpersrc/Platform/Microsoft.Testing.Extensions.HtmlReport/TestResultCapture.cs(lines 13–17) — already uses helperCTRF (duplicated inline values):
JUnit / HTML (correct — delegate to shared helper):
Pattern:
Truncatemethod implementation duplicated — and divergentsrc/Platform/Microsoft.Testing.Extensions.CtrfReport/TestResultCapture.cs(lines 151–156) — own implementationsrc/Platform/SharedExtensionHelpers/TestResultCaptureHelper.cs(lines 46–62) — canonical with surrogate-pair guardCTRF
Truncate(missing surrogate-pair guard):TestResultCaptureHelper.Truncate(correct — handles surrogate pairs):Impact Analysis
Truncatelogic inTestResultCaptureHelperare updated, the CTRF copy will silently drift further. The JUnit/HTML variants already delegate to the helper, making CTRF the outlier.stringin the CTRF report (FormatException/JsonExceptionwhen serialising) while working correctly in HTML and JUnit reports.Refactoring Recommendations
Replace inline constants with
TestResultCaptureHelper.*referencessrc/Platform/Microsoft.Testing.Extensions.CtrfReport/TestResultCapture.cs, replace lines 16–20 with:Replace local
Truncatewith delegation to shared helperTruncateimplementation body with=> TestResultCaptureHelper.Truncate(value, maxLength);— identical to the HTML patternImplementation Checklist
TestResultCapturewithTestResultCaptureHelper.*referencesTruncatebody with delegation toTestResultCaptureHelper.Truncateusingdirectives inCtrfReport/TestResultCapture.csthat are no longer needed after delegation (e.g.,Microsoft.Testing.Platform.Helpers,Microsoft.Testing.Platform)Analysis Metadata
CtrfReport/TestResultCapture.cs,JUnitReport/TestResultCapture.cs,HtmlReport/TestResultCapture.cs,SharedExtensionHelpers/TestResultCaptureHelper.cs)diffbetween peer filesAdd this agentic workflows to your repo
To install this agentic workflow, run