Overview
The file src/TestFramework/TestFramework/Assertions/Assert.AreEquivalent.Comparer.cs has grown to 1248 lines, making it harder to navigate and maintain. This task involves refactoring it into smaller, more focused files.
Current State
- File:
src/TestFramework/TestFramework/Assertions/Assert.AreEquivalent.Comparer.cs
- Size: 1248 lines
- Language: C#
Structural Analysis
The file is a partial class Assert containing a large private EquivalenceComparer class and several supporting nested types. The key groups are:
EquivalenceComparer (lines ~13–853): The core comparison engine with methods for comparing primitives, enumerables, dictionaries, and object members via reflection. Also contains cycle-detection logic and IEquatable<T> invocation.
ReferenceObjectComparer (lines ~854–869): Tiny IEqualityComparer<object> used for reference-equality cycle tracking.
MemberLookup (lines ~871–888): Caches reflected properties/fields of a type.
DictionaryView / NonGenericDictionaryView / GenericDictionaryView / GenericDictionaryAccessors (lines ~890–1067): Abstraction layer that wraps both IDictionary and IDictionary<TKey,TValue> for uniform access.
MemberAccessor (lines ~1068–1098): Wraps a PropertyInfo or FieldInfo into a uniform getter delegate.
EquivalenceMismatch (lines ~1099–1248): Immutable result type describing a mismatch, including path, reason, and formatted expected/actual values.
Refactoring Strategy
Proposed File Splits
Based on the file's structure, split it into the following files (all nested inside the existing partial class Assert or extracted as file-scoped private types in a new partial file):
-
Assert.AreEquivalent.Mismatch.cs
- Contents:
EquivalenceMismatch sealed class
- Responsibility: Immutable result DTO — path, reason, expected/actual text, comparison-failure flag, and message formatting
-
Assert.AreEquivalent.DictionaryView.cs
- Contents:
DictionaryView (abstract), NonGenericDictionaryView, GenericDictionaryView, GenericDictionaryAccessors, DictionaryLookup
- Responsibility: Uniform read-only dictionary abstraction over both generic and non-generic
IDictionary types
-
Assert.AreEquivalent.MemberAccessor.cs
- Contents:
MemberAccessor, MemberLookup, ReferenceObjectComparer
- Responsibility: Reflection-based member discovery and cached accessor delegates
-
Assert.AreEquivalent.Comparer.cs (trimmed)
- Contents:
EquivalenceComparer — core comparison logic only, now that all helper types live in their own files
- Responsibility: Orchestrate deep-equality comparison using the types defined in the other files
Implementation Guidelines
- Preserve Behavior: All existing functionality must work identically after the split
- Maintain Public API: The public
AreEquivalent / AreNotEquivalent methods (defined elsewhere) must remain unchanged
- Use
file-scoped types or keep nesting: Since these types are private implementation details, they can remain as nested classes inside partial class Assert across multiple partial files — no visibility change required
- Test After Each Split: Run
dotnet test after each incremental file extraction
- One File at a Time: Extract one group of types at a time to make review easier
Acceptance Criteria
Priority: Medium
Effort: Small — all types are self-contained; no external callers need updating beyond within the same partial class
Expected Impact: Improved code navigability, easier testing of individual components, reduced merge conflicts on the Assert partial class files
Generated by Daily File Diet · ● 2M · ◷
Overview
The file
src/TestFramework/TestFramework/Assertions/Assert.AreEquivalent.Comparer.cshas grown to 1248 lines, making it harder to navigate and maintain. This task involves refactoring it into smaller, more focused files.Current State
src/TestFramework/TestFramework/Assertions/Assert.AreEquivalent.Comparer.csStructural Analysis
The file is a
partial class Assertcontaining a large privateEquivalenceComparerclass and several supporting nested types. The key groups are:EquivalenceComparer(lines ~13–853): The core comparison engine with methods for comparing primitives, enumerables, dictionaries, and object members via reflection. Also contains cycle-detection logic andIEquatable<T>invocation.ReferenceObjectComparer(lines ~854–869): TinyIEqualityComparer<object>used for reference-equality cycle tracking.MemberLookup(lines ~871–888): Caches reflected properties/fields of a type.DictionaryView/NonGenericDictionaryView/GenericDictionaryView/GenericDictionaryAccessors(lines ~890–1067): Abstraction layer that wraps bothIDictionaryandIDictionary<TKey,TValue>for uniform access.MemberAccessor(lines ~1068–1098): Wraps aPropertyInfoorFieldInfointo a uniform getter delegate.EquivalenceMismatch(lines ~1099–1248): Immutable result type describing a mismatch, including path, reason, and formatted expected/actual values.Refactoring Strategy
Proposed File Splits
Based on the file's structure, split it into the following files (all nested inside the existing
partial class Assertor extracted asfile-scoped private types in a newpartialfile):Assert.AreEquivalent.Mismatch.csEquivalenceMismatchsealed classAssert.AreEquivalent.DictionaryView.csDictionaryView(abstract),NonGenericDictionaryView,GenericDictionaryView,GenericDictionaryAccessors,DictionaryLookupIDictionarytypesAssert.AreEquivalent.MemberAccessor.csMemberAccessor,MemberLookup,ReferenceObjectComparerAssert.AreEquivalent.Comparer.cs(trimmed)EquivalenceComparer— core comparison logic only, now that all helper types live in their own filesImplementation Guidelines
AreEquivalent/AreNotEquivalentmethods (defined elsewhere) must remain unchangedfile-scoped types or keep nesting: Since these types are private implementation details, they can remain as nested classes insidepartial class Assertacross multiple partial files — no visibility change requireddotnet testafter each incremental file extractionAcceptance Criteria
Assert.AreEquivalent/Assert.AreNotEquivalentmethod signaturesPriority: Medium
Effort: Small — all types are self-contained; no external callers need updating beyond within the same
partial classExpected Impact: Improved code navigability, easier testing of individual components, reduced merge conflicts on the
Assertpartial class files