10
10
using System . Reflection ;
11
11
using System . Threading . Tasks ;
12
12
using FluentAssertions ;
13
+ using FluentAssertions . Execution ;
13
14
using Xunit ;
14
15
15
16
namespace System . CommandLine . Tests . Binding
@@ -251,6 +252,28 @@ public async Task When_argument_type_is_not_known_until_binding_then_int_paramet
251
252
received . Should ( ) . Be ( 123 ) ;
252
253
}
253
254
255
+ [ Fact ]
256
+ public void When_argument_type_is_more_specific_than_parameter_type_then_parameter_is_bound_correctly ( )
257
+ {
258
+ FileSystemInfo received = null ;
259
+
260
+ var root = new RootCommand
261
+ {
262
+ new Option < DirectoryInfo > ( "-f" )
263
+ } ;
264
+ root . Handler = CommandHandler . Create < FileSystemInfo > ( f => received = f ) ;
265
+ var path = $ "{ Directory . GetCurrentDirectory ( ) } { Path . DirectorySeparatorChar } ";
266
+
267
+ root . Invoke ( $ "-f { path } ") ;
268
+
269
+ received . Should ( )
270
+ . BeOfType < DirectoryInfo > ( )
271
+ . Which
272
+ . FullName
273
+ . Should ( )
274
+ . Be ( path ) ;
275
+ }
276
+
254
277
[ Theory ]
255
278
[ InlineData ( typeof ( ClassWithCtorParameter < int > ) , false ) ]
256
279
[ InlineData ( typeof ( ClassWithCtorParameter < int > ) , true ) ]
@@ -260,10 +283,23 @@ public async Task When_argument_type_is_not_known_until_binding_then_int_paramet
260
283
[ InlineData ( typeof ( ClassWithCtorParameter < string > ) , true ) ]
261
284
[ InlineData ( typeof ( ClassWithSetter < string > ) , false ) ]
262
285
[ InlineData ( typeof ( ClassWithSetter < string > ) , true ) ]
286
+
263
287
[ InlineData ( typeof ( FileInfo ) , false ) ]
264
288
[ InlineData ( typeof ( FileInfo ) , true ) ]
265
289
[ InlineData ( typeof ( FileInfo [ ] ) , false ) ]
266
290
[ InlineData ( typeof ( FileInfo [ ] ) , true ) ]
291
+
292
+ [ InlineData ( typeof ( DirectoryInfo ) , false ) ]
293
+ [ InlineData ( typeof ( DirectoryInfo ) , true ) ]
294
+ [ InlineData ( typeof ( DirectoryInfo [ ] ) , false ) ]
295
+ [ InlineData ( typeof ( DirectoryInfo [ ] ) , true ) ]
296
+
297
+ [ InlineData ( typeof ( FileSystemInfo ) , true , nameof ( ExistingFile ) ) ]
298
+ [ InlineData ( typeof ( FileSystemInfo ) , true , nameof ( ExistingDirectory ) ) ]
299
+ [ InlineData ( typeof ( FileSystemInfo ) , true , nameof ( NonexistentPathWithTrailingSlash ) ) ]
300
+ [ InlineData ( typeof ( FileSystemInfo ) , true , nameof ( NonexistentPathWithTrailingAltSlash ) ) ]
301
+ [ InlineData ( typeof ( FileSystemInfo ) , true , nameof ( NonexistentPathWithoutTrailingSlash ) ) ]
302
+
267
303
[ InlineData ( typeof ( string [ ] ) , false ) ]
268
304
[ InlineData ( typeof ( string [ ] ) , true ) ]
269
305
[ InlineData ( typeof ( List < string > ) , false ) ]
@@ -274,9 +310,10 @@ public async Task When_argument_type_is_not_known_until_binding_then_int_paramet
274
310
[ InlineData ( typeof ( List < int > ) , true ) ]
275
311
public async Task Handler_method_receives_option_arguments_bound_to_the_specified_type (
276
312
Type type ,
277
- bool useDelegate )
313
+ bool useDelegate ,
314
+ string variation = null )
278
315
{
279
- var testCase = _bindingCases [ type ] ;
316
+ var testCase = _bindingCases [ ( type , variation ) ] ;
280
317
281
318
ICommandHandler handler ;
282
319
if ( ! useDelegate )
@@ -318,7 +355,7 @@ public async Task Handler_method_receives_option_arguments_bound_to_the_specifie
318
355
319
356
var boundValue = ( ( BoundValueCapturer ) invocationContext . InvocationResult ) . BoundValue ;
320
357
321
- boundValue . Should ( ) . BeOfType ( testCase . ParameterType ) ;
358
+ boundValue . Should ( ) . BeAssignableTo ( testCase . ParameterType ) ;
322
359
323
360
testCase . AssertBoundValue ( boundValue ) ;
324
361
}
@@ -443,14 +480,93 @@ public void Apply(InvocationContext context)
443
480
o => o . Value . Should ( ) . Be ( "123" ) ) ,
444
481
445
482
BindingTestCase . Create < FileInfo > (
446
- Path . Combine ( Directory . GetCurrentDirectory ( ) , "file1.txt" ) ,
447
- o => o . FullName . Should ( ) . Be ( Path . Combine ( Directory . GetCurrentDirectory ( ) , "file1.txt" ) ) ) ,
483
+ Path . Combine ( ExistingDirectory ( ) , "file1.txt" ) ,
484
+ o => o . FullName
485
+ . Should ( )
486
+ . Be ( Path . Combine ( ExistingDirectory ( ) , "file1.txt" ) ) ) ,
448
487
449
488
BindingTestCase . Create < FileInfo [ ] > (
450
- $ "{ Path . Combine ( Directory . GetCurrentDirectory ( ) , "file1.txt" ) } { Path . Combine ( Directory . GetCurrentDirectory ( ) , "file2.txt" ) } ",
489
+ $ "{ Path . Combine ( ExistingDirectory ( ) , "file1.txt" ) } { Path . Combine ( ExistingDirectory ( ) , "file2.txt" ) } ",
451
490
o => o . Select ( f => f . FullName )
452
491
. Should ( )
453
- . BeEquivalentTo ( new [ ] { Path . Combine ( Directory . GetCurrentDirectory ( ) , "file1.txt" ) , Path . Combine ( Directory . GetCurrentDirectory ( ) , "file2.txt" ) } ) ) ,
492
+ . BeEquivalentTo ( new [ ]
493
+ {
494
+ Path . Combine ( ExistingDirectory ( ) , "file1.txt" ) ,
495
+ Path . Combine ( ExistingDirectory ( ) , "file2.txt" )
496
+ } ) ) ,
497
+
498
+ BindingTestCase . Create < DirectoryInfo > (
499
+ ExistingDirectory ( ) ,
500
+ fsi => fsi . Should ( )
501
+ . BeOfType < DirectoryInfo > ( )
502
+ . Which
503
+ . FullName
504
+ . Should ( )
505
+ . Be ( ExistingDirectory ( ) ) ) ,
506
+
507
+ BindingTestCase . Create < DirectoryInfo [ ] > (
508
+ $ "{ ExistingDirectory ( ) } { ExistingDirectory ( ) } ",
509
+ fsi => fsi . Should ( )
510
+ . BeAssignableTo < IEnumerable < DirectoryInfo > > ( )
511
+ . Which
512
+ . Select ( d => d . FullName )
513
+ . Should ( )
514
+ . BeEquivalentTo ( new [ ]
515
+ {
516
+ ExistingDirectory ( ) ,
517
+ ExistingDirectory ( )
518
+ } ) ) ,
519
+
520
+ BindingTestCase . Create < FileSystemInfo > (
521
+ ExistingFile ( ) ,
522
+ fsi => fsi . Should ( )
523
+ . BeOfType < FileInfo > ( )
524
+ . Which
525
+ . FullName
526
+ . Should ( )
527
+ . Be ( ExistingFile ( ) ) ,
528
+ variationName : nameof ( ExistingFile ) ) ,
529
+
530
+ BindingTestCase . Create < FileSystemInfo > (
531
+ ExistingDirectory ( ) ,
532
+ fsi => fsi . Should ( )
533
+ . BeOfType < DirectoryInfo > ( )
534
+ . Which
535
+ . FullName
536
+ . Should ( )
537
+ . Be ( ExistingDirectory ( ) ) ,
538
+ variationName : nameof ( ExistingDirectory ) ) ,
539
+
540
+ BindingTestCase . Create < FileSystemInfo > (
541
+ NonexistentPathWithTrailingSlash ( ) ,
542
+ fsi => fsi . Should ( )
543
+ . BeOfType < DirectoryInfo > ( )
544
+ . Which
545
+ . FullName
546
+ . Should ( )
547
+ . Be ( NonexistentPathWithTrailingSlash ( ) ) ,
548
+ variationName : nameof ( NonexistentPathWithTrailingSlash ) ) ,
549
+
550
+ BindingTestCase . Create < FileSystemInfo > (
551
+ NonexistentPathWithTrailingAltSlash ( ) ,
552
+ fsi => fsi . Should ( )
553
+ . BeOfType < DirectoryInfo > ( )
554
+ . Which
555
+ . FullName
556
+ . Should ( )
557
+ . Be ( NonexistentPathWithTrailingSlash ( ) ,
558
+ "DirectoryInfo replaces Path.AltDirectorySeparatorChar with Path.DirectorySeparatorChar on Windows" ) ,
559
+ variationName : nameof ( NonexistentPathWithTrailingAltSlash ) ) ,
560
+
561
+ BindingTestCase . Create < FileSystemInfo > (
562
+ NonexistentPathWithoutTrailingSlash ( ) ,
563
+ fsi => fsi . Should ( )
564
+ . BeOfType < FileInfo > ( )
565
+ . Which
566
+ . FullName
567
+ . Should ( )
568
+ . Be ( NonexistentPathWithoutTrailingSlash ( ) ) ,
569
+ variationName : nameof ( NonexistentPathWithoutTrailingSlash ) ) ,
454
570
455
571
BindingTestCase . Create < string [ ] > (
456
572
"one two" ,
@@ -468,5 +584,23 @@ public void Apply(InvocationContext context)
468
584
"1 2" ,
469
585
o => o . Should ( ) . BeEquivalentTo ( new List < int > { 1 , 2 } ) )
470
586
} ;
587
+
588
+ private static string NonexistentPathWithoutTrailingSlash ( )
589
+ {
590
+ return Path . Combine (
591
+ ExistingDirectory ( ) ,
592
+ "does-not-exist" ) ;
593
+ }
594
+
595
+ private static string NonexistentPathWithTrailingSlash ( ) =>
596
+ NonexistentPathWithoutTrailingSlash ( ) + Path . DirectorySeparatorChar ;
597
+ private static string NonexistentPathWithTrailingAltSlash ( ) =>
598
+ NonexistentPathWithoutTrailingSlash ( ) + Path . AltDirectorySeparatorChar ;
599
+
600
+ private static string ExistingFile ( ) =>
601
+ Directory . GetFiles ( ExistingDirectory ( ) ) . FirstOrDefault ( ) ??
602
+ throw new AssertionFailedException ( "No files found in current directory" ) ;
603
+
604
+ private static string ExistingDirectory ( ) => Directory . GetCurrentDirectory ( ) ;
471
605
}
472
606
}
0 commit comments