6
6
using System . Globalization ;
7
7
using System . Linq . Expressions ;
8
8
using System . Reflection ;
9
+ using Microsoft . Extensions . Internal ;
9
10
10
11
namespace Microsoft . AspNetCore . Http . Extensions . Tests
11
12
{
@@ -274,6 +275,63 @@ public void FindBindAsyncMethod_FindsNonNullableReturningBindAsyncMethodGivenNul
274
275
Assert . True ( new ParameterBindingMethodCache ( ) . HasBindAsyncMethod ( parameterInfo ) ) ;
275
276
}
276
277
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
+
277
335
enum Choice
278
336
{
279
337
One ,
@@ -292,8 +350,6 @@ private static void NullableReturningBindAsyncStructMethod(NullableReturningBind
292
350
293
351
private static void BindAsyncSingleArgRecordMethod ( BindAsyncSingleArgRecord arg ) { }
294
352
private static void BindAsyncSingleArgStructMethod ( BindAsyncSingleArgStruct arg ) { }
295
- private static void BindAsyncNullableSingleArgStructMethod ( BindAsyncSingleArgStruct ? arg ) { }
296
- private static void NullableReturningBindAsyncSingleArgStructMethod ( NullableReturningBindAsyncSingleArgStruct arg ) { }
297
353
298
354
private static ParameterInfo GetFirstParameter < T > ( Expression < Action < T > > expr )
299
355
{
@@ -331,6 +387,157 @@ public static bool TryParse(string? value, IFormatProvider formatProvider, out T
331
387
}
332
388
}
333
389
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
+
334
541
private record BindAsyncRecord ( int Value )
335
542
{
336
543
public static ValueTask < BindAsyncRecord ? > BindAsync ( HttpContext context , ParameterInfo parameter )
@@ -395,9 +602,45 @@ public static ValueTask<BindAsyncSingleArgStruct> BindAsync(HttpContext context)
395
602
}
396
603
}
397
604
398
- private record struct NullableReturningBindAsyncSingleArgStruct ( int Value )
605
+ private record struct InvalidWrongReturnBindAsyncStruct ( int Value )
399
606
{
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 ) =>
401
644
throw new NotImplementedException ( ) ;
402
645
}
403
646
0 commit comments