Skip to content

[duplicate-code] Duplicate Code: Template-Resolve-and-Sanitize Pipeline in ArtifactNamingService vs ReportFileNameHelper #9841

Description

@github-actions

Summary

ArtifactNamingService.ResolveFileName (new, in Microsoft.Testing.Platform) and the ReportEngineBase method that delegates to ReportFileNameHelper.ResolveAndSanitize (in SharedExtensionHelpers) implement the same algorithm: resolve template placeholders via ArtifactNamingHelper, split the result into directory and leaf file name, sanitize the leaf, and reassemble the path.

Duplication Details

Pattern: Near-identical template-resolve-and-sanitize pipelines in two layers

  • Severity: Medium
  • Occurrences: 3 closely related code paths across 3 files
  • Locations:
    • src/Platform/Microsoft.Testing.Platform/Services/ArtifactNamingService.csResolveFileName (lines 21–38)
    • src/Platform/SharedExtensionHelpers/ReportFileNameHelper.csResolveAndSanitize (lines 28–38)
    • src/Platform/SharedExtensionHelpers/ReportEngineBase.cs — wrapper around ResolveAndSanitize (uses same processName/processId extraction pattern, lines ~60–72)

ArtifactNamingService.ResolveFileName:

string processName = Path.GetFileNameWithoutExtension(_testApplicationModuleInfo.GetCurrentTestApplicationFullPath());
string processId = _environment.ProcessId.ToString(CultureInfo.InvariantCulture);
Dictionary<string, string> replacements = ArtifactNamingHelper.GetStandardReplacements(processName, processId, _clock.UtcNow);
string resolved = ArtifactNamingHelper.ResolveTemplate(template, replacements);
string directoryPart = Path.GetDirectoryName(resolved) ?? string.Empty;
string leafName = Path.GetFileName(resolved);
string sanitized = ArtifactFileNameSanitizer.ReplaceInvalidFileNameChars(leafName);
return directoryPart.Length == 0 ? sanitized : Path.Combine(directoryPart, sanitized);

ReportFileNameHelper.ResolveAndSanitize:

Dictionary<string, string> replacements = ArtifactNamingHelper.GetStandardReplacements(processName, processId, now);
string resolved = ArtifactNamingHelper.ResolveTemplate(template, replacements);
string directoryPart = Path.GetDirectoryName(resolved) ?? string.Empty;
string sanitizedFileName = ReportFileNameSanitizer.ReplaceInvalidFileNameChars(Path.GetFileName(resolved));
return directoryPart.Length == 0 ? sanitizedFileName : Path.Combine(directoryPart, sanitizedFileName);

The only structural differences are:

  • The service receives processName/processId through DI (ITestApplicationModuleInfo, IEnvironment), while the helper receives them as parameters.
  • The service uses ArtifactFileNameSanitizer; the helper uses ReportFileNameSanitizer (themselves duplicates — see related issue).

Impact Analysis

  • Maintainability: Path-handling edge cases (e.g. invalid characters in directory portion, empty leaf name validation) must be kept in sync across two implementations. The ArtifactNamingService adds a non-empty leaf name guard that ReportFileNameHelper lacks.
  • Bug Risk: A change to template resolution or sanitization behavior needs to be reflected in both places.
  • Code Bloat: ~15 lines of near-identical logic in two files.

Refactoring Recommendations

  1. Delegate ReportFileNameHelper.ResolveAndSanitize to IArtifactNamingService

    • Inject IArtifactNamingService (already registered in the platform's DI container) into report engines that need template resolution, and remove ReportFileNameHelper.
    • Requires passing the service through ReportEngineContext or ReportEngineBase constructor, but the interface is already available in IServiceProvider.
    • Estimated effort: Low-medium.
  2. Extract a static ResolveAndSanitizeCore helper into ArtifactNamingHelper

    • Add a static overload that accepts processName/processId/timestamp and returns a sanitized resolved path.
    • Both ArtifactNamingService and ReportFileNameHelper delegate to it.
    • This is a smaller, less invasive change.

Implementation Checklist

  • Review duplication findings
  • Align sanitizer usage (consolidate ArtifactFileNameSanitizer / ReportFileNameSanitizer first or in parallel)
  • Unify the resolve-and-sanitize pipeline
  • Update tests
  • Verify no functionality broken

Analysis Metadata

  • Analyzed Files: 3
  • Detection Method: Semantic code analysis
  • Commit: c66515a
  • Analysis Date: 2026-07-11

🤖 Automated content by GitHub Copilot. Generated by the Duplicate Code Detector workflow. · 113.6 AIC · ⌖ 6.58 AIC · ⊞ 8K · [◷]( · )

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 Jul 13, 2026, 5:17 AM UTC

Metadata

Metadata

Assignees

No one assigned

    Labels

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

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions