@@ -119,11 +119,28 @@ private static List<string> CompareObjects(object expected, object actual, Prope
119
119
continue ;
120
120
}
121
121
122
+ Type propType = property . PropertyType ;
123
+
124
+ // 🔥 Special case: if it's object or anonymous, compare via JSON string
125
+ if ( propType == typeof ( object ) || IsAnonymousType ( expectedValue . GetType ( ) ) || IsAnonymousType ( actualValue . GetType ( ) ) )
126
+ {
127
+ var expectedJson = JsonSerializer . Serialize ( expectedValue ) ;
128
+ var actualJson = JsonSerializer . Serialize ( actualValue ) ;
129
+
130
+ if ( expectedJson != actualJson )
131
+ {
132
+ differences . Add ( $ " - ❌ { path } .{ property . Name } : Expected JSON **[{ expectedJson } ]**, but got **[{ actualJson } ]**.") ;
133
+ }
134
+
135
+ continue ;
136
+ }
137
+
138
+ // 💡 Deep compare if complex
122
139
if ( ! expectedValue . Equals ( actualValue ) )
123
140
{
124
- if ( PropertyMappingCache . IsComplexType ( property . PropertyType ) )
141
+ if ( PropertyMappingCache . IsComplexType ( propType ) )
125
142
{
126
- var nestedProperties = property . PropertyType . GetProperties ( BindingFlags . Public | BindingFlags . Instance )
143
+ var nestedProperties = propType . GetProperties ( BindingFlags . Public | BindingFlags . Instance )
127
144
. Where ( prop => ! Attribute . IsDefined ( prop , typeof ( MagicNotMappedAttribute ) ) )
128
145
. ToArray ( ) ;
129
146
@@ -139,5 +156,13 @@ private static List<string> CompareObjects(object expected, object actual, Prope
139
156
140
157
return differences ;
141
158
}
159
+ private static bool IsAnonymousType ( Type type )
160
+ {
161
+ return Attribute . IsDefined ( type , typeof ( System . Runtime . CompilerServices . CompilerGeneratedAttribute ) )
162
+ && type . IsGenericType
163
+ && type . Name . Contains ( "AnonymousType" )
164
+ && ( type . Name . StartsWith ( "<>" ) || type . Name . StartsWith ( "VB$" ) )
165
+ && type . Namespace == null ;
166
+ }
142
167
}
143
168
}
0 commit comments