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:
- Public API (lines ~46-118): The main
Assert.That(Expression<Func<bool>>) method
- Expression Evaluation Core (lines ~126-200): Core expression evaluation logic with caching (
EvaluateExpression, RequiresSinglePassEvaluation, EvaluateAllSubExpressions)
- Short-Circuit and Coalesce Handling (lines ~448-543): Special evaluation for boolean operators and null coalescing (
TryEvaluateShortCircuitBinary, TryEvaluateCoalesce, TryEvaluateConditional)
- Expression Replacement Logic (lines ~546-641): Rebuilding expressions with constants (
ReplaceSubExpressionsWithConstants, ReplaceChildWithConstant)
- Diagnostic Extraction (lines ~643-949): Main diagnostic formatting (
ExtractDetails, ExtractVariablesFromExpression, HandleArrayIndexExpression, AddMemberExpressionToDetails, HandleMethodCallExpression)
- Expression Cleanup Utilities (lines ~1099-1697): Text cleaning and formatting (
CleanExpressionText, RemoveAnonymousTypeWrappers, CleanListInitializers, CleanParentheses, RemoveCompilerGeneratedWrappers, FormatValue, GetFriendlyTypeName)
- 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:
-
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
-
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
-
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
-
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
-
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
-
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
- Preserve Behavior: All existing functionality must work identically after the split
- Maintain Public API: The
Assert.That extension method signature and behavior must remain unchanged
- Use Partial Classes: Keep
AssertExtensions as a partial class; each new file declares public static partial class AssertExtensions
- Internal Visibility: All helper methods should remain
private static within the partial class
- Test After Each Split: Run the full test suite after each incremental change
- One Module at a Time: Extract one logical module per commit to make review easier
Suggested Split Order
- Start with Constants (if creating separate file): Extract all constants to
Assert.That.Constants.cs
- Extract Formatter: Move all text cleaning/formatting methods to
Assert.That.ExpressionFormatter.cs
- Extract Diagnostic Extractor: Move diagnostic extraction to
Assert.That.DiagnosticExtractor.cs
- Extract Expression Rewriter: Move rewriting logic to
Assert.That.ExpressionRewriter.cs
- Extract Expression Evaluator: Move evaluation core to
Assert.That.ExpressionEvaluator.cs
- Keep Main API:
Assert.That.cs retains only the public That method and extension class definition
Acceptance Criteria
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 · ◷
Overview
The file
src/TestFramework/TestFramework/Assertions/Assert.That.cshas 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
src/TestFramework/TestFramework/Assertions/Assert.That.csStructural Analysis
The file contains the
AssertExtensionspartial class with the following major concerns:Assert.That(Expression<Func<bool>>)methodEvaluateExpression,RequiresSinglePassEvaluation,EvaluateAllSubExpressions)TryEvaluateShortCircuitBinary,TryEvaluateCoalesce,TryEvaluateConditional)ReplaceSubExpressionsWithConstants,ReplaceChildWithConstant)ExtractDetails,ExtractVariablesFromExpression,HandleArrayIndexExpression,AddMemberExpressionToDetails,HandleMethodCallExpression)CleanExpressionText,RemoveAnonymousTypeWrappers,CleanListInitializers,CleanParentheses,RemoveCompilerGeneratedWrappers,FormatValue,GetFriendlyTypeName)Refactoring Strategy
Proposed File Splits
Split the file into the following focused modules following the Single Responsibility Principle:
Assert.That.cs(~150-200 lines)Thatmethod and extension class definitionAssert.That.ExpressionEvaluator.cs(~250-300 lines)EvaluateExpression,RequiresSinglePassEvaluation,EvaluateAllSubExpressions,TryEvaluateShortCircuitBinary,TryEvaluateCoalesce,TryEvaluateConditional,EvaluateAssignmentTargetSubChildren,CreateEvaluationCacheAssert.That.ExpressionRewriter.cs(~150-200 lines)ReplaceSubExpressionsWithConstants,ReplaceChildWithConstantAssert.That.DiagnosticExtractor.cs(~400-500 lines)ExtractDetails,ExtractVariablesFromExpression,HandleArrayIndexExpression,AddMemberExpressionToDetails,HandleMethodCallExpression,TryAddExpressionValue,IsArrayGetCall,GetMethodCallDisplayName,GetCleanMemberName,GetIndexArgumentDisplay,IsCapturedThisAssert.That.ExpressionFormatter.cs(~600-700 lines)CleanExpressionText,RemoveAnonymousTypeWrappers,CleanListInitializers,TryMatchListInitPattern,CleanTypeName,CleanParentheses,RemoveOuterParentheses,CleanExcessiveParentheses,RemoveCompilerGeneratedWrappers,TryRemoveWrapper,FormatValue,GetFriendlyTypeName, regex definitions and constantsAssert.That.Constants.cs(~50 lines) - OptionalNullDisplay,NullAngleBrackets,GetItemMethodName, etc.) andFailedToEvaluateSentinelImplementation Guidelines
Assert.Thatextension method signature and behavior must remain unchangedAssertExtensionsas a partial class; each new file declarespublic static partial class AssertExtensionsprivate staticwithin the partial classSuggested Split Order
Assert.That.Constants.csAssert.That.ExpressionFormatter.csAssert.That.DiagnosticExtractor.csAssert.That.ExpressionRewriter.csAssert.That.ExpressionEvaluator.csAssert.That.csretains only the publicThatmethod and extension class definitionAcceptance Criteria
private staticvisibilityPriority: 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