Summary
BannerMessageHelper.BuildBannerMessage (src/Adapter/Shared/BannerMessageHelper.cs) and OutputDeviceBannerHelper.BuildBannerText (src/Platform/Microsoft.Testing.Platform/OutputDevice/OutputDeviceBannerHelper.cs) implement structurally identical banner-building logic: both assemble a string via StringBuilder using the pattern [name] v[version] (UTC [date]) [[arch] - [framework]]. Any format change (e.g. date format, bracket style, separator) must be applied to both files independently.
Duplication Details
Pattern: Structural duplication — banner string construction
- Severity: Medium
- Occurrences: 2 instances of the same ~28-line structure
- Locations:
src/Adapter/Shared/BannerMessageHelper.cs (lines 14–41)
src/Platform/Microsoft.Testing.Platform/OutputDevice/OutputDeviceBannerHelper.cs (lines 17–43)
Side-by-side structure:
| Step |
BannerMessageHelper.BuildBannerMessage |
OutputDeviceBannerHelper.BuildBannerText |
| Name |
sb.Append(productName) |
sb.Append(platformInformation.Name) |
| Version |
sb.Append(" v"); sb.Append(version) |
sb.Append($" v{version}") |
| Commit hash |
(absent) |
Appends +<10-char hash> if present |
| Build date |
"(UTC " + date.ToShortDateString() + ')' |
$"(UTC {date:d})" |
| Dynamic-code guard |
#if NETCOREAPP RuntimeFeature.IsDynamicCodeCompiled |
runtimeFeature.IsDynamicCodeSupported |
| Arch |
RuntimeInformation.RuntimeIdentifier / ProcessArchitecture (direct) |
longArchitecture (injected) |
| Framework |
RuntimeInformation.FrameworkDescription (direct) |
runtimeFramework (injected) |
Callers:
BuildBannerMessage is called by MSTestBannerCapability.GetBannerMessageAsync() to provide an MSTest-branded override banner via IBannerMessageOwnerCapability
BuildBannerText is called by TerminalOutputDevice and SimplifiedConsoleOutputDeviceBase to render the MTP default banner when no framework capability overrides it
Impact Analysis
- Maintainability: If the banner format changes (e.g. switching from
(UTC ...) to a different date style, or modifying the [arch - framework] block), both files must be updated separately. The current mismatch between ToShortDateString() and {date:d} formatting is one example of existing drift.
- Bug Risk: The date formatting is already inconsistent (
ToShortDateString() is culture-sensitive; {date:d} with CultureInfo.InvariantCulture is not). A future bug fix in one method could silently leave the other method with the wrong behavior.
- Code Bloat: ~28 lines of parallel structure that could be extracted into a shared utility.
Refactoring Recommendations
-
Extract a shared banner-format core into OutputDeviceBannerHelper.BuildBannerText (or a new shared helper)
- Align the date format (prefer
CultureInfo.InvariantCulture with {date:d} for consistency)
- Accept
name, version, buildDate, and an optional [arch - framework] string as parameters
- Have
BannerMessageHelper.BuildBannerMessage pre-compute its arch/framework string (matching the existing TestApplication.cs / CommandLineHandler.cs pattern) and delegate to the shared core
-
Alternatively, have MSTestBannerCapability use OutputDeviceBannerHelper.BuildBannerText directly by passing productName, the version, and the pre-computed architecture strings — removing the need for a separate BannerMessageHelper entirely.
-
Estimated effort: Small (1–2 hours). The logic change is mechanical; the main work is choosing where the shared implementation lives given the layering constraints (Adapter cannot depend on Platform internals, so the shared helper must live in a mutually accessible location or the Platform must expose the helper as internal).
Implementation Checklist
Analysis Metadata
- Analyzed Files:
src/Adapter/Shared/, src/Platform/Microsoft.Testing.Platform/OutputDevice/
- Detection Method: Semantic code analysis + structural comparison
- Commit: d8c1e43
- Analysis Date: 2026-06-27
🤖 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. · 1.3K AIC · ⌖ 24.7 AIC · ⊞ 43.5K · [◷]( · ◷)
Add this agentic workflows to your repo
To install this agentic workflow, run
gh aw add githubnext/agentics/workflows/duplicate-code-detector.md@main
Summary
BannerMessageHelper.BuildBannerMessage(src/Adapter/Shared/BannerMessageHelper.cs) andOutputDeviceBannerHelper.BuildBannerText(src/Platform/Microsoft.Testing.Platform/OutputDevice/OutputDeviceBannerHelper.cs) implement structurally identical banner-building logic: both assemble a string viaStringBuilderusing the pattern[name] v[version] (UTC [date]) [[arch] - [framework]]. Any format change (e.g. date format, bracket style, separator) must be applied to both files independently.Duplication Details
Pattern: Structural duplication — banner string construction
src/Adapter/Shared/BannerMessageHelper.cs(lines 14–41)src/Platform/Microsoft.Testing.Platform/OutputDevice/OutputDeviceBannerHelper.cs(lines 17–43)Side-by-side structure:
BannerMessageHelper.BuildBannerMessageOutputDeviceBannerHelper.BuildBannerTextsb.Append(productName)sb.Append(platformInformation.Name)sb.Append(" v"); sb.Append(version)sb.Append($" v{version}")+<10-char hash>if present"(UTC " + date.ToShortDateString() + ')'$"(UTC {date:d})"#if NETCOREAPP RuntimeFeature.IsDynamicCodeCompiledruntimeFeature.IsDynamicCodeSupportedRuntimeInformation.RuntimeIdentifier/ProcessArchitecture(direct)longArchitecture(injected)RuntimeInformation.FrameworkDescription(direct)runtimeFramework(injected)Callers:
BuildBannerMessageis called byMSTestBannerCapability.GetBannerMessageAsync()to provide an MSTest-branded override banner viaIBannerMessageOwnerCapabilityBuildBannerTextis called byTerminalOutputDeviceandSimplifiedConsoleOutputDeviceBaseto render the MTP default banner when no framework capability overrides itImpact Analysis
(UTC ...)to a different date style, or modifying the[arch - framework]block), both files must be updated separately. The current mismatch betweenToShortDateString()and{date:d}formatting is one example of existing drift.ToShortDateString()is culture-sensitive;{date:d}withCultureInfo.InvariantCultureis not). A future bug fix in one method could silently leave the other method with the wrong behavior.Refactoring Recommendations
Extract a shared banner-format core into
OutputDeviceBannerHelper.BuildBannerText(or a new shared helper)CultureInfo.InvariantCulturewith{date:d}for consistency)name,version,buildDate, and an optional[arch - framework]string as parametersBannerMessageHelper.BuildBannerMessagepre-compute its arch/framework string (matching the existingTestApplication.cs/CommandLineHandler.cspattern) and delegate to the shared coreAlternatively, have
MSTestBannerCapabilityuseOutputDeviceBannerHelper.BuildBannerTextdirectly by passingproductName, the version, and the pre-computed architecture strings — removing the need for a separateBannerMessageHelperentirely.Estimated effort: Small (1–2 hours). The logic change is mechanical; the main work is choosing where the shared implementation lives given the layering constraints (Adapter cannot depend on Platform internals, so the shared helper must live in a mutually accessible location or the Platform must expose the helper as
internal).Implementation Checklist
ToShortDateString()vs{date:d}) and pick a consistent formatBannerMessageHelperand/orOutputDeviceBannerHelperto delegate to the shared logic--help/--infooutputAnalysis Metadata
src/Adapter/Shared/,src/Platform/Microsoft.Testing.Platform/OutputDevice/Add this agentic workflows to your repo
To install this agentic workflow, run