Skip to content

[duplicate-code] Duplicate Code: Report Generator Infrastructure Triplicated Across Ctrf/Html/JUnit Extensions #9098

@Evangelink

Description

@Evangelink

Analysis of commit 916e3a0

Assignee: @copilot

Summary

CtrfReportGenerator, HtmlReportGenerator, and JUnitReportGenerator share nearly identical constructor signatures, field declarations, ConsumeAsync, OnTestSessionStartingAsync, and OnTestSessionFinishingAsync patterns — 180 duplicated lines across 10 clone pairs. A ReportEngineBase class already exists in src/Platform/SharedExtensionHelpers/ but the generators are not inheriting from it.

Duplication Details

Pattern: Triplicated Report Generator Infrastructure

  • Severity: High
  • Occurrences: 10 clone pairs, 180 duplicated lines (across 3 files of ~157–174 lines each)
  • Locations:
    • src/Platform/Microsoft.Testing.Extensions.CtrfReport/CtrfReportGenerator.cs (full file, 158 lines)
    • src/Platform/Microsoft.Testing.Extensions.HtmlReport/HtmlReportGenerator.cs (full file, 157 lines)
    • src/Platform/Microsoft.Testing.Extensions.JUnitReport/JUnitReportGenerator.cs (full file, 174 lines)

Duplicated blocks include:

  • Using directives (lines 4–18 in all three, 15 lines × 2 pairs)
  • Field declarations + constructor (lines 20–66 in Ctrf/Html, 17+14 lines × 2 pairs)
  • ConsumeAsync implementation (lines 91–112 / 91–111, 25 lines × 2 pairs)
  • OnTestSessionStartingAsync + OnTestSessionFinishingAsync lifecycle methods (lines 104–155+, 25+13 lines × 2 pairs)

Code Sample (identical constructor pattern across all three generators):

// Appears in CtrfReportGenerator.cs:26-66, HtmlReportGenerator.cs:26-66, JUnitReportGenerator.cs:26-72
private readonly IConfiguration _configuration;
private readonly ICommandLineOptions _commandLineOptions;
private readonly IFileSystem _fileSystem;
private readonly ITestApplicationModuleInfo _testApplicationModuleInfo;
private readonly IMessageBus _messageBus;
private readonly IClock _clock;
private readonly IEnvironment _environment;
private readonly IOutputDevice _outputDevice;
private readonly ITestFramework _testFramework;
private readonly ITestApplicationProcessExitCode _testApplicationProcessExitCode;
private readonly ILogger<TGenerator> _logger;
private readonly List<CapturedTestResult> _tests = [];
private readonly bool _isEnabled;
private DateTimeOffset? _testStartTime;

Impact Analysis

  • Maintainability: Adding a new constructor parameter (e.g. a new platform service) must be done in three places. The existing ReportEngineBase in SharedExtensionHelpers covers the engine layer but not the generator (data consumer) layer.
  • Bug Risk: Any behavioral change to ConsumeAsync or the session lifecycle hooks must be replicated across all three generators; divergence is possible and hard to detect.
  • Code Bloat: Approximately 50% of each generator file is boilerplate shared with the other two generators.

Refactoring Recommendations

  1. Introduce ReportGeneratorBase in SharedExtensionHelpers

    • Extract the shared field declarations, constructor, ConsumeAsync, OnTestSessionStartingAsync, and the common part of OnTestSessionFinishingAsync into an abstract base class alongside the existing ReportEngineBase
    • Path: src/Platform/SharedExtensionHelpers/ReportGeneratorBase.cs
    • Have CtrfReportGenerator, HtmlReportGenerator, and JUnitReportGenerator extend it
    • Estimated effort: 4–6 hours
    • Benefits: DRY constructor; future platform-service additions require a single-line change
  2. Template-method pattern for OnTestSessionFinishingAsync

    • The outer structure (cancellation check, _testStartTime guard, log message, engine instantiation, warning display, artifact publish) is identical; only the engine type, log message text, and resource strings differ
    • The base class can implement the outer flow and call an abstract CreateEngineAsync / GetArtifactDisplayName virtual pair

Implementation Checklist

  • Review ReportEngineBase to ensure it covers the needed field set
  • Create ReportGeneratorBase with common fields, constructor, and lifecycle methods
  • Migrate CtrfReportGenerator, HtmlReportGenerator, JUnitReportGenerator to extend ReportGeneratorBase
  • Verify all three generators still pass their acceptance tests after migration
  • Update tests if needed

Analysis Metadata

  • Analyzed Files: 1003 C# source files
  • Detection Method: jscpd semantic code analysis (threshold: minLines=6, minTokens=50)
  • Commit: 916e3a0
  • Analysis Date: 2026-06-13

🤖 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. · 734 AIC · ⌖ 14.1 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 15, 2026, 5:51 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