1
1
// Copyright (c) .NET Foundation and contributors. All rights reserved.
2
2
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
3
4
+ using System . Collections . Generic ;
4
5
using System . CommandLine . Help ;
5
6
using System . IO ;
7
+ using System . Linq ;
6
8
using FluentAssertions ;
7
9
using Xunit ;
8
10
using static System . Environment ;
@@ -29,9 +31,9 @@ public Customization()
29
31
private HelpBuilder GetHelpBuilder ( int maxWidth ) => new ( maxWidth ) ;
30
32
31
33
[ Fact ]
32
- public void Option_can_customize_default_value ( )
34
+ public void Option_can_customize_displayed_default_value ( )
33
35
{
34
- var option = new Option < string > ( "--the-option" ) { DefaultValueFactory = ( _ ) => "not 42" } ;
36
+ var option = new Option < string > ( "--the-option" ) { DefaultValueFactory = _ => "not 42" } ;
35
37
var command = new Command ( "the-command" , "command help" )
36
38
{
37
39
option
@@ -136,9 +138,9 @@ public void Option_can_customize_second_column_text_based_on_parse_result()
136
138
ctx . Command . Equals ( commandA )
137
139
? optionADescription
138
140
: optionBDescription ) ;
139
- command . Options . Add ( new HelpOption ( )
141
+ command . Options . Add ( new HelpOption
140
142
{
141
- Action = new HelpAction ( )
143
+ Action = new HelpAction
142
144
{
143
145
Builder = helpBuilder
144
146
}
@@ -201,7 +203,7 @@ public void Command_arguments_can_customize_second_column_text()
201
203
var argument = new Argument < string > ( "some-arg" )
202
204
{
203
205
Description = "Default description" ,
204
- DefaultValueFactory = ( _ ) => "not 42"
206
+ DefaultValueFactory = _ => "not 42"
205
207
} ;
206
208
var command = new Command ( "the-command" , "command help" )
207
209
{
@@ -313,9 +315,9 @@ public void Argument_can_fallback_to_default_when_customizing(
313
315
314
316
CommandLineConfiguration config = new ( command ) ;
315
317
316
- command . Options . Add ( new HelpOption ( )
318
+ command . Options . Add ( new HelpOption
317
319
{
318
- Action = new HelpAction ( )
320
+ Action = new HelpAction
319
321
{
320
322
Builder = helpBuilder
321
323
}
@@ -325,6 +327,246 @@ public void Argument_can_fallback_to_default_when_customizing(
325
327
command . Parse ( "test -h" , config ) . Invoke ( ) ;
326
328
config . Output . ToString ( ) . Should ( ) . MatchRegex ( expected ) ;
327
329
}
330
+
331
+
332
+ [ Fact ]
333
+ public void Individual_symbols_can_be_customized ( )
334
+ {
335
+ var subcommand = new Command ( "subcommand" , "The default command description" ) ;
336
+ var option = new Option < int > ( "-x" ) { Description = "The default option description" } ;
337
+ var argument = new Argument < int > ( "int-value" ) { Description = "The default argument description" } ;
338
+
339
+ var rootCommand = new RootCommand
340
+ {
341
+ subcommand ,
342
+ option ,
343
+ argument ,
344
+ } ;
345
+
346
+ CommandLineConfiguration config = new ( rootCommand )
347
+ {
348
+ Output = new StringWriter ( )
349
+ } ;
350
+
351
+ ParseResult parseResult = rootCommand . Parse ( "-h" , config ) ;
352
+
353
+ if ( parseResult . Action is HelpAction helpAction )
354
+ {
355
+ helpAction . Builder . CustomizeSymbol ( subcommand , secondColumnText : "The custom command description" ) ;
356
+ helpAction . Builder . CustomizeSymbol ( option , secondColumnText : "The custom option description" ) ;
357
+ helpAction . Builder . CustomizeSymbol ( argument , secondColumnText : "The custom argument description" ) ;
358
+ }
359
+
360
+ parseResult . Invoke ( ) ;
361
+
362
+ config . Output
363
+ . ToString ( )
364
+ . Should ( )
365
+ . ContainAll ( "The custom command description" ,
366
+ "The custom option description" ,
367
+ "The custom argument description" ) ;
368
+ }
369
+
370
+ [ Fact ]
371
+ public void Help_sections_can_be_replaced ( )
372
+ {
373
+ CommandLineConfiguration config = new ( new RootCommand ( ) )
374
+ {
375
+ Output = new StringWriter ( )
376
+ } ;
377
+
378
+ ParseResult parseResult = config . Parse ( "-h" ) ;
379
+
380
+ if ( parseResult . Action is HelpAction helpAction )
381
+ {
382
+ helpAction . Builder . CustomizeLayout ( CustomLayout ) ;
383
+ }
384
+
385
+ parseResult . Invoke ( ) ;
386
+
387
+ config . Output . ToString ( ) . Should ( ) . Be ( $ "one{ NewLine } { NewLine } two{ NewLine } { NewLine } three{ NewLine } { NewLine } { NewLine } ") ;
388
+
389
+ IEnumerable < Action < HelpContext > > CustomLayout ( HelpContext _ )
390
+ {
391
+ yield return ctx => ctx . Output . WriteLine ( "one" ) ;
392
+ yield return ctx => ctx . Output . WriteLine ( "two" ) ;
393
+ yield return ctx => ctx . Output . WriteLine ( "three" ) ;
394
+ }
395
+ }
396
+
397
+ [ Fact ]
398
+ public void Help_sections_can_be_supplemented ( )
399
+ {
400
+ CommandLineConfiguration config = new ( new RootCommand ( "hello" ) )
401
+ {
402
+ Output = new StringWriter ( ) ,
403
+ } ;
404
+
405
+ ParseResult parseResult = config . Parse ( "-h" ) ;
406
+
407
+ if ( parseResult . Action is HelpAction helpAction )
408
+ {
409
+ helpAction . Builder . CustomizeLayout ( CustomLayout ) ;
410
+ }
411
+
412
+ parseResult . Invoke ( ) ;
413
+
414
+ var output = config . Output . ToString ( ) ;
415
+ var defaultHelp = GetDefaultHelp ( config . RootCommand ) ;
416
+
417
+ var expected = $ "first{ NewLine } { NewLine } { defaultHelp } last{ NewLine } { NewLine } ";
418
+
419
+ output . Should ( ) . Be ( expected ) ;
420
+
421
+ IEnumerable < Action < HelpContext > > CustomLayout ( HelpContext _ )
422
+ {
423
+ yield return ctx => ctx . Output . WriteLine ( "first" ) ;
424
+
425
+ foreach ( var section in HelpBuilder . Default . GetLayout ( ) )
426
+ {
427
+ yield return section ;
428
+ }
429
+
430
+ yield return ctx => ctx . Output . WriteLine ( "last" ) ;
431
+ }
432
+ }
433
+
434
+ [ Fact ]
435
+ public void Layout_can_be_composed_dynamically_based_on_context ( )
436
+ {
437
+ HelpBuilder helpBuilder = new ( ) ;
438
+ var commandWithTypicalHelp = new Command ( "typical" ) ;
439
+ var commandWithCustomHelp = new Command ( "custom" ) ;
440
+ var command = new RootCommand
441
+ {
442
+ commandWithTypicalHelp ,
443
+ commandWithCustomHelp
444
+ } ;
445
+
446
+ command . Options . OfType < HelpOption > ( ) . Single ( ) . Action = new HelpAction ( )
447
+ {
448
+ Builder = helpBuilder
449
+ } ;
450
+
451
+ var config = new CommandLineConfiguration ( command ) ;
452
+ helpBuilder . CustomizeLayout ( c =>
453
+ c . Command == commandWithTypicalHelp
454
+ ? HelpBuilder . Default . GetLayout ( )
455
+ : new Action < HelpContext > [ ]
456
+ {
457
+ c => c . Output . WriteLine ( "Custom layout!" )
458
+ }
459
+ . Concat ( HelpBuilder . Default . GetLayout ( ) ) ) ;
460
+
461
+ var typicalOutput = new StringWriter ( ) ;
462
+ config . Output = typicalOutput ;
463
+ command . Parse ( "typical -h" , config ) . Invoke ( ) ;
464
+
465
+ var customOutput = new StringWriter ( ) ;
466
+ config . Output = customOutput ;
467
+ command . Parse ( "custom -h" , config ) . Invoke ( ) ;
468
+
469
+ typicalOutput . ToString ( ) . Should ( ) . Be ( GetDefaultHelp ( commandWithTypicalHelp , false ) ) ;
470
+ customOutput . ToString ( ) . Should ( ) . Be ( $ "Custom layout!{ NewLine } { NewLine } { GetDefaultHelp ( commandWithCustomHelp , false ) } ") ;
471
+ }
472
+
473
+ [ Fact ]
474
+ public void Help_default_sections_can_be_wrapped ( )
475
+ {
476
+ Command command = new ( "test" )
477
+ {
478
+ new Option < string > ( "--option" )
479
+ {
480
+ Description = "option description" ,
481
+ HelpName = "option"
482
+ } ,
483
+ new HelpOption
484
+ {
485
+ Action = new HelpAction
486
+ {
487
+ Builder = new HelpBuilder ( 30 )
488
+ }
489
+ }
490
+ } ;
491
+
492
+ CommandLineConfiguration config = new ( command )
493
+ {
494
+ Output = new StringWriter ( )
495
+ } ;
496
+
497
+ config . Invoke ( "test -h" ) ;
498
+
499
+ string result = config . Output . ToString ( ) ;
500
+ result . Should ( ) . Be (
501
+ $ "Description:{ NewLine } { NewLine } " +
502
+ $ "Usage:{ NewLine } test [options]{ NewLine } { NewLine } " +
503
+ $ "Options:{ NewLine } " +
504
+ $ " --option option { NewLine } " +
505
+ $ " <option> description{ NewLine } " +
506
+ $ " -?, -h, Show help and { NewLine } " +
507
+ $ " --help usage { NewLine } " +
508
+ $ " information{ NewLine } { NewLine } { NewLine } ") ;
509
+ }
510
+
511
+ [ Fact ]
512
+ public void Help_customized_sections_can_be_wrapped ( )
513
+ {
514
+ CommandLineConfiguration config = new ( new RootCommand ( ) )
515
+ {
516
+ Output = new StringWriter ( )
517
+ } ;
518
+
519
+ ParseResult parseResult = config . Parse ( "-h" ) ;
520
+
521
+ if ( parseResult . Action is HelpAction helpAction )
522
+ {
523
+ helpAction . Builder = new HelpBuilder ( 10 ) ;
524
+ helpAction . Builder . CustomizeLayout ( CustomLayout ) ;
525
+ }
526
+
527
+ parseResult . Invoke ( ) ;
528
+
529
+ string result = config . Output . ToString ( ) ;
530
+ result . Should ( ) . Be ( $ " 123 123{ NewLine } 456 456{ NewLine } 78 789{ NewLine } 0{ NewLine } { NewLine } { NewLine } ") ;
531
+
532
+ IEnumerable < Action < HelpContext > > CustomLayout ( HelpContext _ )
533
+ {
534
+ yield return ctx => ctx . HelpBuilder . WriteColumns ( new [ ] { new TwoColumnHelpRow ( "12345678" , "1234567890" ) } , ctx ) ;
535
+ }
536
+ }
537
+
538
+ private string GetDefaultHelp ( Command command , bool trimOneNewline = true )
539
+ {
540
+ // The command might have already defined a HelpOption with custom settings,
541
+ // we need to overwrite it to get the actual defaults.
542
+ HelpOption defaultHelp = new ( ) ;
543
+ // HelpOption overrides Equals and treats every other instance of same type as equal
544
+ int index = command . Options . IndexOf ( defaultHelp ) ;
545
+ if ( index >= 0 )
546
+ {
547
+ command . Options [ index ] = defaultHelp ;
548
+ }
549
+ else
550
+ {
551
+ command . Options . Add ( defaultHelp ) ;
552
+ }
553
+
554
+ CommandLineConfiguration config = new ( command )
555
+ {
556
+ Output = new StringWriter ( )
557
+ } ;
558
+
559
+ config . Invoke ( "-h" ) ;
560
+
561
+ var output = config . Output . ToString ( ) ;
562
+
563
+ if ( trimOneNewline )
564
+ {
565
+ output = output . Substring ( 0 , output . Length - NewLine . Length ) ;
566
+ }
567
+
568
+ return output ;
569
+ }
328
570
}
329
571
}
330
572
}
0 commit comments