@@ -138,16 +138,21 @@ private HttpMessageOptions GetExpectedOption(HttpMessageOptions option)
138138 throw new ArgumentNullException ( nameof ( option ) ) ;
139139 }
140140
141- return _lotsOfOptions . Values . SingleOrDefault ( x => ( x . RequestUri . Equals ( option . RequestUri , StringComparison . OrdinalIgnoreCase ) ||
142- x . RequestUri == HttpMessageOptions . NoValue ) &&
143- ( x . HttpMethod == option . HttpMethod ||
144- x . HttpMethod == null ) &&
145- ( x . HttpContent == option . HttpContent ||
146- x . HttpContent == null ) &&
147- ( x . Headers == null ||
148- x . Headers . Count == 0 ) ||
149- ( x . Headers != null &&
150- HeaderExists ( x . Headers , option . Headers ) ) ) ;
141+ // NOTE: We only compare the *setup* HttpMessageOptions properties if they were provided.
142+ // So if there was no HEADERS provided ... but the real 'option' has some, we still ignore
143+ // and don't compare.
144+ return _lotsOfOptions . Values . SingleOrDefault ( x => ( x . RequestUri == HttpMessageOptions . NoValue || // Don't care about the Request Uri.
145+ x . RequestUri . Equals ( option . RequestUri , StringComparison . OrdinalIgnoreCase ) ) &&
146+
147+ ( x . HttpMethod == null || // Don't care about the HttpMethod.
148+ x . HttpMethod == option . HttpMethod ) &&
149+
150+ ( x . HttpContent == null || // Don't care about the Content.
151+ ContentAreEqual ( x . HttpContent , option . HttpContent ) ) &&
152+
153+ ( x . Headers == null || // Don't care about the Header.
154+ x . Headers . Count == 0 || // No header's were supplied, so again don't care/
155+ HeadersAreEqual ( x . Headers , option . Headers ) ) ) ;
151156 }
152157
153158 private static void IncrementCalls ( HttpMessageOptions options )
@@ -168,17 +173,51 @@ private static void IncrementCalls(HttpMessageOptions options)
168173 propertyInfo . SetValue ( options , ++ existingValue ) ;
169174 }
170175
171- private static bool HeaderExists ( IDictionary < string , IEnumerable < string > > source ,
172- IDictionary < string , IEnumerable < string > > destination )
176+ private static bool ContentAreEqual ( HttpContent source , HttpContent destination )
177+ {
178+ if ( source == null &&
179+ destination == null )
180+ {
181+ // Both are null - so they match :P
182+ return true ;
183+ }
184+
185+ if ( source == null ||
186+ destination == null )
187+ {
188+ return false ;
189+ }
190+
191+ // Extract the content from both HttpContent's.
192+ var sourceContentTask = source . ReadAsStringAsync ( ) ;
193+ var destinationContentTask = destination . ReadAsStringAsync ( ) ;
194+ var tasks = new List < Task >
195+ {
196+ sourceContentTask ,
197+ destinationContentTask
198+ } ;
199+ Task . WaitAll ( tasks . ToArray ( ) ) ;
200+
201+ // Now compare both results.
202+ // NOTE: Case sensitive.
203+ return sourceContentTask . Result == destinationContentTask . Result ;
204+ }
205+
206+ private static bool HeadersAreEqual ( IDictionary < string , IEnumerable < string > > source ,
207+ IDictionary < string , IEnumerable < string > > destination )
173208 {
174- if ( source == null )
209+ if ( source == null &&
210+ destination == null )
175211 {
176- throw new ArgumentNullException ( nameof ( source ) ) ;
212+ // Nothing from both .. so that's ok!
213+ return true ;
177214 }
178215
179- if ( destination == null )
216+ if ( source == null ||
217+ destination == null )
180218 {
181- throw new ArgumentNullException ( nameof ( destination ) ) ;
219+ // At least one is different so don't bother checking.
220+ return false ;
182221 }
183222
184223 // Both sides are not the same size.
0 commit comments