1+ // Copyright (c) .NET Foundation and contributors. All rights reserved.
2+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+ using System . CommandLine . Builder ;
5+ using System . CommandLine . Help ;
6+ using System . CommandLine . IO ;
7+ using System . CommandLine . Parsing ;
8+ using System . IO ;
9+ using FluentAssertions ;
10+ using Xunit ;
11+ using static System . Environment ;
12+
13+ namespace System . CommandLine . Tests . Help
14+ {
15+ public partial class HelpBuilderTests
16+ {
17+ public class Customization
18+ {
19+ private readonly HelpBuilder _helpBuilder ;
20+ private readonly StringWriter _console ;
21+ private readonly string _columnPadding ;
22+ private readonly string _indentation ;
23+
24+ public Customization ( )
25+ {
26+ _console = new ( ) ;
27+ _helpBuilder = GetHelpBuilder ( LargeMaxWidth ) ;
28+ _columnPadding = new string ( ' ' , ColumnGutterWidth ) ;
29+ _indentation = new string ( ' ' , IndentationWidth ) ;
30+ }
31+
32+ private HelpBuilder GetHelpBuilder ( int maxWidth ) =>
33+ new ( LocalizationResources . Instance ,
34+ maxWidth ) ;
35+
36+ [ Fact ]
37+ public void Option_can_customize_default_value ( )
38+ {
39+ var option = new Option < string > ( "--the-option" , getDefaultValue : ( ) => "not 42" ) ;
40+ var command = new Command ( "the-command" , "command help" )
41+ {
42+ option
43+ } ;
44+
45+ _helpBuilder . Customize ( option , defaultValue : "42" ) ;
46+
47+ _helpBuilder . Write ( command , _console ) ;
48+ var expected =
49+ $ "Options:{ NewLine } " +
50+ $ "{ _indentation } --the-option <the-option>{ _columnPadding } [default: 42]{ NewLine } { NewLine } ";
51+
52+ _console . ToString ( ) . Should ( ) . Contain ( expected ) ;
53+ }
54+
55+ [ Fact ]
56+ public void Option_can_customize_first_column_text ( )
57+ {
58+ var option = new Option < string > ( "--the-option" , "option description" ) ;
59+ var command = new Command ( "the-command" , "command help" )
60+ {
61+ option
62+ } ;
63+
64+ _helpBuilder . Customize ( option , firstColumnText : "other-name" ) ;
65+
66+ _helpBuilder . Write ( command , _console ) ;
67+ var expected =
68+ $ "Options:{ NewLine } " +
69+ $ "{ _indentation } other-name{ _columnPadding } option description{ NewLine } { NewLine } ";
70+
71+ _console . ToString ( ) . Should ( ) . Contain ( expected ) ;
72+ }
73+
74+ [ Fact ]
75+ public void Option_can_customize_left_column_text_based_on_parse_result ( )
76+ {
77+ var option = new Option < bool > ( "option" ) ;
78+ var commandA = new Command ( "a" , "a command help" )
79+ {
80+ option
81+ } ;
82+ var commandB = new Command ( "b" , "b command help" )
83+ {
84+ option
85+ } ;
86+ var command = new Command ( "root" , "root command help" )
87+ {
88+ commandA , commandB
89+ } ;
90+ var optionADescription = "option a help" ;
91+ var optionBDescription = "option b help" ;
92+
93+ var helpBuilder = new HelpBuilder ( LocalizationResources . Instance , LargeMaxWidth ) ;
94+ helpBuilder . Customize ( option , secondColumnText : parseResult =>
95+ parseResult . CommandResult . Command . Equals ( commandA )
96+ ? optionADescription
97+ : optionBDescription ) ;
98+
99+ var parser = new CommandLineBuilder ( command )
100+ . UseDefaults ( )
101+ . UseHelpBuilder ( _ => helpBuilder )
102+ . Build ( ) ;
103+
104+ var console = new TestConsole ( ) ;
105+ parser . Invoke ( "root a -h" , console ) ;
106+ console . Out . ToString ( ) . Should ( ) . Contain ( $ "option { optionADescription } ") ;
107+
108+ console = new TestConsole ( ) ;
109+ parser . Invoke ( "root b -h" , console ) ;
110+ console . Out . ToString ( ) . Should ( ) . Contain ( $ "option { optionBDescription } ") ;
111+ }
112+
113+ [ Fact ]
114+ public void Option_can_customize_first_column_text_based_on_parse_result ( )
115+ {
116+ var option = new Option < bool > ( "option" ) ;
117+ var commandA = new Command ( "a" , "a command help" )
118+ {
119+ option
120+ } ;
121+ var commandB = new Command ( "b" , "b command help" )
122+ {
123+ option
124+ } ;
125+ var command = new Command ( "root" , "root command help" )
126+ {
127+ commandA , commandB
128+ } ;
129+ var optionAFirstColumnText = "option a help" ;
130+ var optionBFirstColumnText = "option b help" ;
131+
132+ var helpBuilder = new HelpBuilder ( LocalizationResources . Instance , LargeMaxWidth ) ;
133+ helpBuilder . Customize ( option , firstColumnText : parseResult =>
134+ parseResult . CommandResult . Command . Equals ( commandA )
135+ ? optionAFirstColumnText
136+ : optionBFirstColumnText ) ;
137+ var parser = new CommandLineBuilder ( command )
138+ . UseDefaults ( )
139+ . UseHelpBuilder ( _ => helpBuilder )
140+ . Build ( ) ;
141+
142+ var console = new TestConsole ( ) ;
143+ parser . Invoke ( "root a -h" , console ) ;
144+ console . Out . ToString ( ) . Should ( ) . Contain ( optionAFirstColumnText ) ;
145+
146+ console = new TestConsole ( ) ;
147+ parser . Invoke ( "root b -h" , console ) ;
148+ console . Out . ToString ( ) . Should ( ) . Contain ( optionBFirstColumnText ) ;
149+ }
150+
151+ [ Fact ]
152+ public void Subcommand_can_customize_first_column_text ( )
153+ {
154+ var subcommand = new Command ( "subcommand" , "subcommand description" ) ;
155+ var command = new Command ( "the-command" , "command help" )
156+ {
157+ subcommand
158+ } ;
159+
160+ _helpBuilder . Customize ( subcommand , firstColumnText : "other-name" ) ;
161+
162+ _helpBuilder . Write ( command , _console ) ;
163+ var expected =
164+ $ "Commands:{ NewLine } " +
165+ $ "{ _indentation } other-name{ _columnPadding } subcommand description{ NewLine } { NewLine } ";
166+
167+ _console . ToString ( ) . Should ( ) . Contain ( expected ) ;
168+ }
169+
170+ [ Fact ]
171+ public void Command_arguments_can_customize_default_value ( )
172+ {
173+ var argument = new Argument < string > ( "some-arg" , getDefaultValue : ( ) => "not 42" ) ;
174+ var command = new Command ( "the-command" , "command help" )
175+ {
176+ argument
177+ } ;
178+
179+ _helpBuilder . Customize ( argument , defaultValue : "42" ) ;
180+
181+ _helpBuilder . Write ( command , _console ) ;
182+ var expected =
183+ $ "Arguments:{ NewLine } " +
184+ $ "{ _indentation } <some-arg>{ _columnPadding } [default: 42]{ NewLine } { NewLine } ";
185+
186+ _console . ToString ( ) . Should ( ) . Contain ( expected ) ;
187+ }
188+
189+ [ Fact ]
190+ public void Command_arguments_can_customize_second_column_text ( )
191+ {
192+ var argument = new Argument < string > ( "some-arg" , getDefaultValue : ( ) => "not 42" ) ;
193+ var command = new Command ( "the-command" , "command help" )
194+ {
195+ argument
196+ } ;
197+
198+ _helpBuilder . Customize ( argument , firstColumnText : "some-other-arg" ) ;
199+
200+ _helpBuilder . Write ( command , _console ) ;
201+ var expected =
202+ $ "Arguments:{ NewLine } " +
203+ $ "{ _indentation } some-other-arg{ _columnPadding } [default: not 42]{ NewLine } { NewLine } ";
204+
205+ _console . ToString ( ) . Should ( ) . Contain ( expected ) ;
206+ }
207+
208+ [ Fact ]
209+ public void Help_text_can_be_added_after_default_text_by_inheriting_HelpBuilder ( )
210+ {
211+ var parser = new CommandLineBuilder ( )
212+ . UseDefaults ( )
213+ . UseHelpBuilder ( context => new CustomHelpBuilderThatAddsTextAfterDefaultText ( "The text to add" ) )
214+ . Build ( ) ;
215+
216+ var console = new TestConsole ( ) ;
217+
218+ parser . Invoke ( "-h" , console ) ;
219+
220+ console . Out . ToString ( ) . Should ( ) . EndWith ( "The text to add" ) ;
221+ }
222+
223+ [ Fact ]
224+ public void Customize_throws_when_symbol_is_null ( )
225+ {
226+ Action action = ( ) => new HelpBuilder ( LocalizationResources . Instance ) . Customize ( null ! , "" ) ;
227+ action . Should ( ) . Throw < ArgumentNullException > ( ) ;
228+ }
229+ }
230+
231+ private class CustomHelpBuilderThatAddsTextAfterDefaultText : HelpBuilder
232+ {
233+ private readonly string _theTextToAdd ;
234+
235+ public CustomHelpBuilderThatAddsTextAfterDefaultText ( string theTextToAdd )
236+ : base ( LocalizationResources . Instance )
237+ {
238+ _theTextToAdd = theTextToAdd ;
239+ }
240+
241+ public override void Write ( ICommand command , TextWriter writer , ParseResult parseResult )
242+ {
243+ base . Write ( command , writer , parseResult ) ;
244+ writer . Write ( _theTextToAdd ) ;
245+ }
246+ }
247+
248+ private class CustomLocalizationResources : LocalizationResources
249+ {
250+ public string OverrideHelpDescriptionTitle { get ; set ; }
251+
252+ public override string HelpDescriptionTitle ( )
253+ {
254+ return OverrideHelpDescriptionTitle ?? base . HelpDescriptionTitle ( ) ;
255+ }
256+ }
257+ }
258+ }
0 commit comments