Skip to content

[file-diet] Refactor Assert.That.cs: Split 1,724-line file into focused modules #8477

@Evangelink

Description

@Evangelink

Overview

The file src/TestFramework/TestFramework/Assertions/Assert.That.cs has grown to 1,724 lines, making it harder to navigate and maintain. This task involves refactoring it into smaller, more focused files that each handle a specific aspect of the expression-based assertion functionality.

Current State

  • File: src/TestFramework/TestFramework/Assertions/Assert.That.cs
  • Size: 1,724 lines
  • Language: C#
Structural Analysis

The file contains the AssertExtensions partial class with the following major concerns:

  1. Public API (lines ~46-118): The main Assert.That(Expression<Func<bool>>) method
  2. Expression Evaluation Core (lines ~126-200): Core expression evaluation logic with caching (EvaluateExpression, RequiresSinglePassEvaluation, EvaluateAllSubExpressions)
  3. Short-Circuit and Coalesce Handling (lines ~448-543): Special evaluation for boolean operators and null coalescing (TryEvaluateShortCircuitBinary, TryEvaluateCoalesce, TryEvaluateConditional)
  4. Expression Replacement Logic (lines ~546-641): Rebuilding expressions with constants (ReplaceSubExpressionsWithConstants, ReplaceChildWithConstant)
  5. Diagnostic Extraction (lines ~643-949): Main diagnostic formatting (ExtractDetails, ExtractVariablesFromExpression, HandleArrayIndexExpression, AddMemberExpressionToDetails, HandleMethodCallExpression)
  6. Expression Cleanup Utilities (lines ~1099-1697): Text cleaning and formatting (CleanExpressionText, RemoveAnonymousTypeWrappers, CleanListInitializers, CleanParentheses, RemoveCompilerGeneratedWrappers, FormatValue, GetFriendlyTypeName)
  7. Regex Definitions (lines ~1698-1724): Compiled regex patterns for compiler-generated code detection

Refactoring Strategy

Proposed File Splits

Split the file into the following focused modules following the Single Responsibility Principle:

  1. Assert.That.cs (~150-200 lines)

    • Contents: The public That method and extension class definition
    • Responsibility: Public API surface for expression-based assertions
    • Orchestrates calls to the other modules below
  2. Assert.That.ExpressionEvaluator.cs (~250-300 lines)

    • Contents: EvaluateExpression, RequiresSinglePassEvaluation, EvaluateAllSubExpressions, TryEvaluateShortCircuitBinary, TryEvaluateCoalesce, TryEvaluateConditional, EvaluateAssignmentTargetSubChildren, CreateEvaluationCache
    • Responsibility: Expression tree evaluation with side-effect detection and caching
    • Pure expression evaluation logic
  3. Assert.That.ExpressionRewriter.cs (~150-200 lines)

    • Contents: ReplaceSubExpressionsWithConstants, ReplaceChildWithConstant
    • Responsibility: Expression tree rewriting for diagnostic purposes
    • Transforms expression trees by replacing subexpressions with their evaluated constants
  4. Assert.That.DiagnosticExtractor.cs (~400-500 lines)

    • Contents: ExtractDetails, ExtractVariablesFromExpression, HandleArrayIndexExpression, AddMemberExpressionToDetails, HandleMethodCallExpression, TryAddExpressionValue, IsArrayGetCall, GetMethodCallDisplayName, GetCleanMemberName, GetIndexArgumentDisplay, IsCapturedThis
    • Responsibility: Extract diagnostic information from expression trees for failure messages
    • Traverses expression trees and builds human-readable failure reports
  5. Assert.That.ExpressionFormatter.cs (~600-700 lines)

    • Contents: CleanExpressionText, RemoveAnonymousTypeWrappers, CleanListInitializers, TryMatchListInitPattern, CleanTypeName, CleanParentheses, RemoveOuterParentheses, CleanExcessiveParentheses, RemoveCompilerGeneratedWrappers, TryRemoveWrapper, FormatValue, GetFriendlyTypeName, regex definitions and constants
    • Responsibility: Format and clean expression text for display to users
    • String manipulation and cleanup of compiler-generated artifacts
  6. Assert.That.Constants.cs (~50 lines) - Optional

    • Contents: All private constants (NullDisplay, NullAngleBrackets, GetItemMethodName, etc.) and FailedToEvaluateSentinel
    • Responsibility: Shared constants used across assertion diagnostics
    • Centralizes magic strings and sentinel values

Implementation Guidelines

  1. Preserve Behavior: All existing functionality must work identically after the split
  2. Maintain Public API: The Assert.That extension method signature and behavior must remain unchanged
  3. Use Partial Classes: Keep AssertExtensions as a partial class; each new file declares public static partial class AssertExtensions
  4. Internal Visibility: All helper methods should remain private static within the partial class
  5. Test After Each Split: Run the full test suite after each incremental change
  6. One Module at a Time: Extract one logical module per commit to make review easier

Suggested Split Order

  1. Start with Constants (if creating separate file): Extract all constants to Assert.That.Constants.cs
  2. Extract Formatter: Move all text cleaning/formatting methods to Assert.That.ExpressionFormatter.cs
  3. Extract Diagnostic Extractor: Move diagnostic extraction to Assert.That.DiagnosticExtractor.cs
  4. Extract Expression Rewriter: Move rewriting logic to Assert.That.ExpressionRewriter.cs
  5. Extract Expression Evaluator: Move evaluation core to Assert.That.ExpressionEvaluator.cs
  6. Keep Main API: Assert.That.cs retains only the public That method and extension class definition

Acceptance Criteria

  • Original file is split into 5-6 focused partial class files
  • Each new file is under 700 lines (target: 200-400 lines each)
  • All tests pass after refactoring
  • No breaking changes to public API surface
  • All methods maintain their original private static visibility
  • File names clearly indicate their responsibility
  • Each partial class file contains logically cohesive functionality

Priority: Medium
Effort: Medium-Large (complex expression evaluation logic with many internal dependencies)
Expected Impact: Improved code navigability, easier to understand individual concerns, reduced cognitive load when working with assertion diagnostics

Generated by Daily File Diet · ● 1.9M ·

  • expires on May 23, 2026, 7:41 PM 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