66using System . Globalization ;
77using System . Linq . Expressions ;
88using System . Reflection ;
9+ using Microsoft . Extensions . Internal ;
910
1011namespace Microsoft . AspNetCore . Http . Extensions . Tests
1112{
@@ -274,6 +275,63 @@ public void FindBindAsyncMethod_FindsNonNullableReturningBindAsyncMethodGivenNul
274275 Assert . True ( new ParameterBindingMethodCache ( ) . HasBindAsyncMethod ( parameterInfo ) ) ;
275276 }
276277
278+ [ Theory ]
279+ [ InlineData ( typeof ( InvalidVoidReturnTryParseStruct ) ) ]
280+ [ InlineData ( typeof ( InvalidVoidReturnTryParseClass ) ) ]
281+ [ InlineData ( typeof ( InvalidWrongTypeTryParseStruct ) ) ]
282+ [ InlineData ( typeof ( InvalidWrongTypeTryParseClass ) ) ]
283+ [ InlineData ( typeof ( InvalidTryParseNullableStruct ) ) ]
284+ [ InlineData ( typeof ( InvalidTooFewArgsTryParseStruct ) ) ]
285+ [ InlineData ( typeof ( InvalidTooFewArgsTryParseClass ) ) ]
286+ [ InlineData ( typeof ( InvalidNonStaticTryParseStruct ) ) ]
287+ [ InlineData ( typeof ( InvalidNonStaticTryParseClass ) ) ]
288+ public void FindTryParseMethod_ThrowsIfInvalidTryParseOnType ( Type type )
289+ {
290+ var ex = Assert . Throws < InvalidOperationException > (
291+ ( ) => new ParameterBindingMethodCache ( ) . FindTryParseMethod ( type ) ) ;
292+ Assert . StartsWith ( $ "TryParse method found on { TypeNameHelper . GetTypeDisplayName ( type , fullName : false ) } with incorrect format. Must be a static method with format", ex . Message ) ;
293+ Assert . Contains ( $ "bool TryParse(string, IFormatProvider, out { TypeNameHelper . GetTypeDisplayName ( type , fullName : false ) } )", ex . Message ) ;
294+ Assert . Contains ( $ "bool TryParse(string, out { TypeNameHelper . GetTypeDisplayName ( type , fullName : false ) } )", ex . Message ) ;
295+ }
296+
297+ [ Theory ]
298+ [ InlineData ( typeof ( TryParseClassWithGoodAndBad ) ) ]
299+ [ InlineData ( typeof ( TryParseStructWithGoodAndBad ) ) ]
300+ public void FindTryParseMethod_IgnoresInvalidTryParseIfGoodOneFound ( Type type )
301+ {
302+ var method = new ParameterBindingMethodCache ( ) . FindTryParseMethod ( type ) ;
303+ Assert . NotNull ( method ) ;
304+ }
305+
306+ [ Theory ]
307+ [ InlineData ( typeof ( InvalidWrongReturnBindAsyncStruct ) ) ]
308+ [ InlineData ( typeof ( InvalidWrongReturnBindAsyncClass ) ) ]
309+ [ InlineData ( typeof ( InvalidWrongParamBindAsyncStruct ) ) ]
310+ [ InlineData ( typeof ( InvalidWrongParamBindAsyncClass ) ) ]
311+ public void FindBindAsyncMethod_ThrowsIfInvalidBindAsyncOnType ( Type type )
312+ {
313+ var cache = new ParameterBindingMethodCache ( ) ;
314+ var parameter = new MockParameterInfo ( type , "anything" ) ;
315+ var ex = Assert . Throws < InvalidOperationException > (
316+ ( ) => cache . FindBindAsyncMethod ( parameter ) ) ;
317+ Assert . StartsWith ( $ "BindAsync method found on { TypeNameHelper . GetTypeDisplayName ( type , fullName : false ) } with incorrect format. Must be a static method with format", ex . Message ) ;
318+ Assert . Contains ( $ "ValueTask<{ TypeNameHelper . GetTypeDisplayName ( type , fullName : false ) } > BindAsync(HttpContext context, ParameterInfo parameter)", ex . Message ) ;
319+ Assert . Contains ( $ "ValueTask<{ TypeNameHelper . GetTypeDisplayName ( type , fullName : false ) } > BindAsync(HttpContext context)", ex . Message ) ;
320+ Assert . Contains ( $ "ValueTask<{ TypeNameHelper . GetTypeDisplayName ( type , fullName : false ) } ?> BindAsync(HttpContext context, ParameterInfo parameter)", ex . Message ) ;
321+ Assert . Contains ( $ "ValueTask<{ TypeNameHelper . GetTypeDisplayName ( type , fullName : false ) } ?> BindAsync(HttpContext context)", ex . Message ) ;
322+ }
323+
324+ [ Theory ]
325+ [ InlineData ( typeof ( BindAsyncStructWithGoodAndBad ) ) ]
326+ [ InlineData ( typeof ( BindAsyncClassWithGoodAndBad ) ) ]
327+ public void FindBindAsyncMethod_IgnoresInvalidBindAsyncIfGoodOneFound ( Type type )
328+ {
329+ var cache = new ParameterBindingMethodCache ( ) ;
330+ var parameter = new MockParameterInfo ( type , "anything" ) ;
331+ var ( expression , _) = cache . FindBindAsyncMethod ( parameter ) ;
332+ Assert . NotNull ( expression ) ;
333+ }
334+
277335 enum Choice
278336 {
279337 One ,
@@ -292,8 +350,6 @@ private static void NullableReturningBindAsyncStructMethod(NullableReturningBind
292350
293351 private static void BindAsyncSingleArgRecordMethod ( BindAsyncSingleArgRecord arg ) { }
294352 private static void BindAsyncSingleArgStructMethod ( BindAsyncSingleArgStruct arg ) { }
295- private static void BindAsyncNullableSingleArgStructMethod ( BindAsyncSingleArgStruct ? arg ) { }
296- private static void NullableReturningBindAsyncSingleArgStructMethod ( NullableReturningBindAsyncSingleArgStruct arg ) { }
297353
298354 private static ParameterInfo GetFirstParameter < T > ( Expression < Action < T > > expr )
299355 {
@@ -331,6 +387,157 @@ public static bool TryParse(string? value, IFormatProvider formatProvider, out T
331387 }
332388 }
333389
390+ private record struct InvalidVoidReturnTryParseStruct ( int Value )
391+ {
392+ public static void TryParse ( string ? value , IFormatProvider formatProvider , out InvalidVoidReturnTryParseStruct result )
393+ {
394+ if ( ! int . TryParse ( value , NumberStyles . Integer , formatProvider , out var val ) )
395+ {
396+ result = default ;
397+ return ;
398+ }
399+
400+ result = new InvalidVoidReturnTryParseStruct ( val ) ;
401+ return ;
402+ }
403+ }
404+
405+ private record struct InvalidWrongTypeTryParseStruct ( int Value )
406+ {
407+ public static bool TryParse ( string ? value , IFormatProvider formatProvider , out InvalidVoidReturnTryParseStruct result )
408+ {
409+ if ( ! int . TryParse ( value , NumberStyles . Integer , formatProvider , out var val ) )
410+ {
411+ result = default ;
412+ return false ;
413+ }
414+
415+ result = new InvalidVoidReturnTryParseStruct ( val ) ;
416+ return true ;
417+ }
418+ }
419+
420+ private record struct InvalidTryParseNullableStruct ( int Value )
421+ {
422+ public static bool TryParse ( string ? value , IFormatProvider formatProvider , out InvalidTryParseNullableStruct ? result )
423+ {
424+ if ( ! int . TryParse ( value , NumberStyles . Integer , formatProvider , out var val ) )
425+ {
426+ result = default ;
427+ return false ;
428+ }
429+
430+ result = new InvalidTryParseNullableStruct ( val ) ;
431+ return true ;
432+ }
433+ }
434+
435+ private record struct InvalidTooFewArgsTryParseStruct ( int Value )
436+ {
437+ public static bool TryParse ( out InvalidTooFewArgsTryParseStruct result )
438+ {
439+ result = default ;
440+ return false ;
441+ }
442+ }
443+
444+ private struct TryParseStructWithGoodAndBad
445+ {
446+ public static bool TryParse ( string ? value , out TryParseStructWithGoodAndBad result )
447+ {
448+ result = new ( ) ;
449+ return false ;
450+ }
451+
452+ public static void TryParse ( out TryParseStructWithGoodAndBad result )
453+ {
454+ result = new ( ) ;
455+ }
456+ }
457+
458+ private record struct InvalidNonStaticTryParseStruct ( int Value )
459+ {
460+ public bool TryParse ( string ? value , IFormatProvider formatProvider , out InvalidVoidReturnTryParseStruct result )
461+ {
462+ if ( ! int . TryParse ( value , NumberStyles . Integer , formatProvider , out var val ) )
463+ {
464+ result = default ;
465+ return false ;
466+ }
467+
468+ result = new InvalidVoidReturnTryParseStruct ( val ) ;
469+ return true ;
470+ }
471+ }
472+
473+ private class InvalidVoidReturnTryParseClass
474+ {
475+ public static void TryParse ( string ? value , IFormatProvider formatProvider , out InvalidVoidReturnTryParseClass result )
476+ {
477+ if ( ! int . TryParse ( value , NumberStyles . Integer , formatProvider , out var val ) )
478+ {
479+ result = new ( ) ;
480+ return ;
481+ }
482+
483+ result = new ( ) ;
484+ }
485+ }
486+
487+ private class InvalidWrongTypeTryParseClass
488+ {
489+ public static bool TryParse ( string ? value , IFormatProvider formatProvider , out InvalidVoidReturnTryParseClass result )
490+ {
491+ if ( ! int . TryParse ( value , NumberStyles . Integer , formatProvider , out var val ) )
492+ {
493+ result = new ( ) ;
494+ return false ;
495+ }
496+
497+ result = new ( ) ;
498+ return true ;
499+ }
500+ }
501+
502+ private class InvalidTooFewArgsTryParseClass
503+ {
504+ public static bool TryParse ( out InvalidTooFewArgsTryParseClass result )
505+ {
506+ result = new ( ) ;
507+ return false ;
508+ }
509+ }
510+
511+ private class TryParseClassWithGoodAndBad
512+ {
513+ public static bool TryParse ( string ? value , out TryParseClassWithGoodAndBad result )
514+ {
515+ result = new ( ) ;
516+ return false ;
517+ }
518+
519+ public static bool TryParse ( out TryParseClassWithGoodAndBad result )
520+ {
521+ result = new ( ) ;
522+ return false ;
523+ }
524+ }
525+
526+ private class InvalidNonStaticTryParseClass
527+ {
528+ public bool TryParse ( string ? value , IFormatProvider formatProvider , out InvalidNonStaticTryParseClass result )
529+ {
530+ if ( ! int . TryParse ( value , NumberStyles . Integer , formatProvider , out var val ) )
531+ {
532+ result = new ( ) ;
533+ return false ;
534+ }
535+
536+ result = new ( ) ;
537+ return true ;
538+ }
539+ }
540+
334541 private record BindAsyncRecord ( int Value )
335542 {
336543 public static ValueTask < BindAsyncRecord ? > BindAsync ( HttpContext context , ParameterInfo parameter )
@@ -395,9 +602,45 @@ public static ValueTask<BindAsyncSingleArgStruct> BindAsync(HttpContext context)
395602 }
396603 }
397604
398- private record struct NullableReturningBindAsyncSingleArgStruct ( int Value )
605+ private record struct InvalidWrongReturnBindAsyncStruct ( int Value )
399606 {
400- public static ValueTask < NullableReturningBindAsyncStruct ? > BindAsync ( HttpContext context , ParameterInfo parameter ) =>
607+ public static Task < InvalidWrongReturnBindAsyncStruct > BindAsync ( HttpContext context , ParameterInfo parameter ) =>
608+ throw new NotImplementedException ( ) ;
609+ }
610+
611+ private class InvalidWrongReturnBindAsyncClass
612+ {
613+ public static Task < InvalidWrongReturnBindAsyncClass > BindAsync ( HttpContext context , ParameterInfo parameter ) =>
614+ throw new NotImplementedException ( ) ;
615+ }
616+
617+ private record struct InvalidWrongParamBindAsyncStruct ( int Value )
618+ {
619+ public static ValueTask < InvalidWrongParamBindAsyncStruct > BindAsync ( ParameterInfo parameter ) =>
620+ throw new NotImplementedException ( ) ;
621+ }
622+
623+ private class InvalidWrongParamBindAsyncClass
624+ {
625+ public static Task < InvalidWrongParamBindAsyncClass > BindAsync ( ParameterInfo parameter ) =>
626+ throw new NotImplementedException ( ) ;
627+ }
628+
629+ private record struct BindAsyncStructWithGoodAndBad ( int Value )
630+ {
631+ public static ValueTask < BindAsyncStructWithGoodAndBad > BindAsync ( HttpContext context , ParameterInfo parameter ) =>
632+ throw new NotImplementedException ( ) ;
633+
634+ public static ValueTask < BindAsyncStructWithGoodAndBad > BindAsync ( ParameterInfo parameter ) =>
635+ throw new NotImplementedException ( ) ;
636+ }
637+
638+ private class BindAsyncClassWithGoodAndBad
639+ {
640+ public static ValueTask < BindAsyncClassWithGoodAndBad > BindAsync ( HttpContext context , ParameterInfo parameter ) =>
641+ throw new NotImplementedException ( ) ;
642+
643+ public static ValueTask < BindAsyncClassWithGoodAndBad > BindAsync ( ParameterInfo parameter ) =>
401644 throw new NotImplementedException ( ) ;
402645 }
403646
0 commit comments