1package cli
2
3import (
4	"bytes"
5	"flag"
6	"fmt"
7	"io"
8	"io/ioutil"
9	"runtime"
10	"strings"
11	"testing"
12)
13
14func Test_ShowAppHelp_NoAuthor(t *testing.T) {
15	output := new(bytes.Buffer)
16	app := &App{Writer: output}
17
18	c := NewContext(app, nil, nil)
19
20	_ = ShowAppHelp(c)
21
22	if bytes.Contains(output.Bytes(), []byte("AUTHOR(S):")) {
23		t.Errorf("expected\n%snot to include %s", output.String(), "AUTHOR(S):")
24	}
25}
26
27func Test_ShowAppHelp_NoVersion(t *testing.T) {
28	output := new(bytes.Buffer)
29	app := &App{Writer: output}
30
31	app.Version = ""
32
33	c := NewContext(app, nil, nil)
34
35	_ = ShowAppHelp(c)
36
37	if bytes.Contains(output.Bytes(), []byte("VERSION:")) {
38		t.Errorf("expected\n%snot to include %s", output.String(), "VERSION:")
39	}
40}
41
42func Test_ShowAppHelp_HideVersion(t *testing.T) {
43	output := new(bytes.Buffer)
44	app := &App{Writer: output}
45
46	app.HideVersion = true
47
48	c := NewContext(app, nil, nil)
49
50	_ = ShowAppHelp(c)
51
52	if bytes.Contains(output.Bytes(), []byte("VERSION:")) {
53		t.Errorf("expected\n%snot to include %s", output.String(), "VERSION:")
54	}
55}
56
57func Test_Help_Custom_Flags(t *testing.T) {
58	oldFlag := HelpFlag
59	defer func() {
60		HelpFlag = oldFlag
61	}()
62
63	HelpFlag = &BoolFlag{
64		Name:    "help",
65		Aliases: []string{"x"},
66		Usage:   "show help",
67	}
68
69	app := App{
70		Flags: []Flag{
71			&BoolFlag{Name: "foo", Aliases: []string{"h"}},
72		},
73		Action: func(ctx *Context) error {
74			if ctx.Bool("h") != true {
75				t.Errorf("custom help flag not set")
76			}
77			return nil
78		},
79	}
80	output := new(bytes.Buffer)
81	app.Writer = output
82	_ = app.Run([]string{"test", "-h"})
83	if output.Len() > 0 {
84		t.Errorf("unexpected output: %s", output.String())
85	}
86}
87
88func Test_Version_Custom_Flags(t *testing.T) {
89	oldFlag := VersionFlag
90	defer func() {
91		VersionFlag = oldFlag
92	}()
93
94	VersionFlag = &BoolFlag{
95		Name:    "version",
96		Aliases: []string{"V"},
97		Usage:   "show version",
98	}
99
100	app := App{
101		Flags: []Flag{
102			&BoolFlag{Name: "foo", Aliases: []string{"v"}},
103		},
104		Action: func(ctx *Context) error {
105			if ctx.Bool("v") != true {
106				t.Errorf("custom version flag not set")
107			}
108			return nil
109		},
110	}
111	output := new(bytes.Buffer)
112	app.Writer = output
113	_ = app.Run([]string{"test", "-v"})
114	if output.Len() > 0 {
115		t.Errorf("unexpected output: %s", output.String())
116	}
117}
118
119func Test_helpCommand_Action_ErrorIfNoTopic(t *testing.T) {
120	app := &App{}
121
122	set := flag.NewFlagSet("test", 0)
123	_ = set.Parse([]string{"foo"})
124
125	c := NewContext(app, set, nil)
126
127	err := helpCommand.Action(c)
128
129	if err == nil {
130		t.Fatalf("expected error from helpCommand.Action(), but got nil")
131	}
132
133	exitErr, ok := err.(*exitError)
134	if !ok {
135		t.Fatalf("expected *exitError from helpCommand.Action(), but instead got: %v", err.Error())
136	}
137
138	if !strings.HasPrefix(exitErr.Error(), "No help topic for") {
139		t.Fatalf("expected an unknown help topic error, but got: %v", exitErr.Error())
140	}
141
142	if exitErr.exitCode != 3 {
143		t.Fatalf("expected exit value = 3, got %d instead", exitErr.exitCode)
144	}
145}
146
147func Test_helpCommand_InHelpOutput(t *testing.T) {
148	app := &App{}
149	output := &bytes.Buffer{}
150	app.Writer = output
151	_ = app.Run([]string{"test", "--help"})
152
153	s := output.String()
154
155	if strings.Contains(s, "\nCOMMANDS:\nGLOBAL OPTIONS:\n") {
156		t.Fatalf("empty COMMANDS section detected: %q", s)
157	}
158
159	if !strings.Contains(s, "help, h") {
160		t.Fatalf("missing \"help, h\": %q", s)
161	}
162}
163
164func Test_helpSubcommand_Action_ErrorIfNoTopic(t *testing.T) {
165	app := &App{}
166
167	set := flag.NewFlagSet("test", 0)
168	_ = set.Parse([]string{"foo"})
169
170	c := NewContext(app, set, nil)
171
172	err := helpSubcommand.Action(c)
173
174	if err == nil {
175		t.Fatalf("expected error from helpCommand.Action(), but got nil")
176	}
177
178	exitErr, ok := err.(*exitError)
179	if !ok {
180		t.Fatalf("expected *exitError from helpCommand.Action(), but instead got: %v", err.Error())
181	}
182
183	if !strings.HasPrefix(exitErr.Error(), "No help topic for") {
184		t.Fatalf("expected an unknown help topic error, but got: %v", exitErr.Error())
185	}
186
187	if exitErr.exitCode != 3 {
188		t.Fatalf("expected exit value = 3, got %d instead", exitErr.exitCode)
189	}
190}
191
192func TestShowAppHelp_CommandAliases(t *testing.T) {
193	app := &App{
194		Commands: []*Command{
195			{
196				Name:    "frobbly",
197				Aliases: []string{"fr", "frob"},
198				Action: func(ctx *Context) error {
199					return nil
200				},
201			},
202		},
203	}
204
205	output := &bytes.Buffer{}
206	app.Writer = output
207	_ = app.Run([]string{"foo", "--help"})
208
209	if !strings.Contains(output.String(), "frobbly, fr, frob") {
210		t.Errorf("expected output to include all command aliases; got: %q", output.String())
211	}
212}
213
214func TestShowCommandHelp_HelpPrinter(t *testing.T) {
215	doublecho := func(text string) string {
216		return text + " " + text
217	}
218
219	tests := []struct {
220		name         string
221		template     string
222		printer      helpPrinter
223		command      string
224		wantTemplate string
225		wantOutput   string
226	}{
227		{
228			name:     "no-command",
229			template: "",
230			printer: func(w io.Writer, templ string, data interface{}) {
231				fmt.Fprint(w, "yo")
232			},
233			command:      "",
234			wantTemplate: SubcommandHelpTemplate,
235			wantOutput:   "yo",
236		},
237		{
238			name:     "standard-command",
239			template: "",
240			printer: func(w io.Writer, templ string, data interface{}) {
241				fmt.Fprint(w, "yo")
242			},
243			command:      "my-command",
244			wantTemplate: CommandHelpTemplate,
245			wantOutput:   "yo",
246		},
247		{
248			name:     "custom-template-command",
249			template: "{{doublecho .Name}}",
250			printer: func(w io.Writer, templ string, data interface{}) {
251				// Pass a custom function to ensure it gets used
252				fm := map[string]interface{}{"doublecho": doublecho}
253				HelpPrinterCustom(w, templ, data, fm)
254			},
255			command:      "my-command",
256			wantTemplate: "{{doublecho .Name}}",
257			wantOutput:   "my-command my-command",
258		},
259	}
260
261	for _, tt := range tests {
262		t.Run(tt.name, func(t *testing.T) {
263			defer func(old helpPrinter) {
264				HelpPrinter = old
265			}(HelpPrinter)
266			HelpPrinter = func(w io.Writer, templ string, data interface{}) {
267				if templ != tt.wantTemplate {
268					t.Errorf("want template:\n%s\ngot template:\n%s", tt.wantTemplate, templ)
269				}
270
271				tt.printer(w, templ, data)
272			}
273
274			var buf bytes.Buffer
275			app := &App{
276				Name:   "my-app",
277				Writer: &buf,
278				Commands: []*Command{
279					{
280						Name:               "my-command",
281						CustomHelpTemplate: tt.template,
282					},
283				},
284			}
285
286			err := app.Run([]string{"my-app", "help", tt.command})
287			if err != nil {
288				t.Fatal(err)
289			}
290
291			got := buf.String()
292			if got != tt.wantOutput {
293				t.Errorf("want output %q, got %q", tt.wantOutput, got)
294			}
295		})
296	}
297}
298
299func TestShowCommandHelp_HelpPrinterCustom(t *testing.T) {
300	doublecho := func(text string) string {
301		return text + " " + text
302	}
303
304	tests := []struct {
305		name         string
306		template     string
307		printer      helpPrinterCustom
308		command      string
309		wantTemplate string
310		wantOutput   string
311	}{
312		{
313			name:     "no-command",
314			template: "",
315			printer: func(w io.Writer, templ string, data interface{}, fm map[string]interface{}) {
316				fmt.Fprint(w, "yo")
317			},
318			command:      "",
319			wantTemplate: SubcommandHelpTemplate,
320			wantOutput:   "yo",
321		},
322		{
323			name:     "standard-command",
324			template: "",
325			printer: func(w io.Writer, templ string, data interface{}, fm map[string]interface{}) {
326				fmt.Fprint(w, "yo")
327			},
328			command:      "my-command",
329			wantTemplate: CommandHelpTemplate,
330			wantOutput:   "yo",
331		},
332		{
333			name:     "custom-template-command",
334			template: "{{doublecho .Name}}",
335			printer: func(w io.Writer, templ string, data interface{}, _ map[string]interface{}) {
336				// Pass a custom function to ensure it gets used
337				fm := map[string]interface{}{"doublecho": doublecho}
338				printHelpCustom(w, templ, data, fm)
339			},
340			command:      "my-command",
341			wantTemplate: "{{doublecho .Name}}",
342			wantOutput:   "my-command my-command",
343		},
344	}
345
346	for _, tt := range tests {
347		t.Run(tt.name, func(t *testing.T) {
348			defer func(old helpPrinterCustom) {
349				HelpPrinterCustom = old
350			}(HelpPrinterCustom)
351			HelpPrinterCustom = func(w io.Writer, templ string, data interface{}, fm map[string]interface{}) {
352				if fm != nil {
353					t.Error("unexpected function map passed")
354				}
355
356				if templ != tt.wantTemplate {
357					t.Errorf("want template:\n%s\ngot template:\n%s", tt.wantTemplate, templ)
358				}
359
360				tt.printer(w, templ, data, fm)
361			}
362
363			var buf bytes.Buffer
364			app := &App{
365				Name:   "my-app",
366				Writer: &buf,
367				Commands: []*Command{
368					{
369						Name:               "my-command",
370						CustomHelpTemplate: tt.template,
371					},
372				},
373			}
374
375			err := app.Run([]string{"my-app", "help", tt.command})
376			if err != nil {
377				t.Fatal(err)
378			}
379
380			got := buf.String()
381			if got != tt.wantOutput {
382				t.Errorf("want output %q, got %q", tt.wantOutput, got)
383			}
384		})
385	}
386}
387
388func TestShowCommandHelp_CommandAliases(t *testing.T) {
389	app := &App{
390		Commands: []*Command{
391			{
392				Name:    "frobbly",
393				Aliases: []string{"fr", "frob", "bork"},
394				Action: func(ctx *Context) error {
395					return nil
396				},
397			},
398		},
399	}
400
401	output := &bytes.Buffer{}
402	app.Writer = output
403	_ = app.Run([]string{"foo", "help", "fr"})
404
405	if !strings.Contains(output.String(), "frobbly") {
406		t.Errorf("expected output to include command name; got: %q", output.String())
407	}
408
409	if strings.Contains(output.String(), "bork") {
410		t.Errorf("expected output to exclude command aliases; got: %q", output.String())
411	}
412}
413
414func TestShowSubcommandHelp_CommandAliases(t *testing.T) {
415	app := &App{
416		Commands: []*Command{
417			{
418				Name:    "frobbly",
419				Aliases: []string{"fr", "frob", "bork"},
420				Action: func(ctx *Context) error {
421					return nil
422				},
423			},
424		},
425	}
426
427	output := &bytes.Buffer{}
428	app.Writer = output
429	_ = app.Run([]string{"foo", "help"})
430
431	if !strings.Contains(output.String(), "frobbly, fr, frob, bork") {
432		t.Errorf("expected output to include all command aliases; got: %q", output.String())
433	}
434}
435
436func TestShowCommandHelp_Customtemplate(t *testing.T) {
437	app := &App{
438		Commands: []*Command{
439			{
440				Name: "frobbly",
441				Action: func(ctx *Context) error {
442					return nil
443				},
444				HelpName: "foo frobbly",
445				CustomHelpTemplate: `NAME:
446   {{.HelpName}} - {{.Usage}}
447
448USAGE:
449   {{.HelpName}} [FLAGS] TARGET [TARGET ...]
450
451FLAGS:
452  {{range .VisibleFlags}}{{.}}
453  {{end}}
454EXAMPLES:
455   1. Frobbly runs with this param locally.
456      $ {{.HelpName}} wobbly
457`,
458			},
459		},
460	}
461	output := &bytes.Buffer{}
462	app.Writer = output
463	_ = app.Run([]string{"foo", "help", "frobbly"})
464
465	if strings.Contains(output.String(), "2. Frobbly runs without this param locally.") {
466		t.Errorf("expected output to exclude \"2. Frobbly runs without this param locally.\"; got: %q", output.String())
467	}
468
469	if !strings.Contains(output.String(), "1. Frobbly runs with this param locally.") {
470		t.Errorf("expected output to include \"1. Frobbly runs with this param locally.\"; got: %q", output.String())
471	}
472
473	if !strings.Contains(output.String(), "$ foo frobbly wobbly") {
474		t.Errorf("expected output to include \"$ foo frobbly wobbly\"; got: %q", output.String())
475	}
476}
477
478func TestShowSubcommandHelp_CommandUsageText(t *testing.T) {
479	app := &App{
480		Commands: []*Command{
481			{
482				Name:      "frobbly",
483				UsageText: "this is usage text",
484			},
485		},
486	}
487
488	output := &bytes.Buffer{}
489	app.Writer = output
490
491	_ = app.Run([]string{"foo", "frobbly", "--help"})
492
493	if !strings.Contains(output.String(), "this is usage text") {
494		t.Errorf("expected output to include usage text; got: %q", output.String())
495	}
496}
497
498func TestShowSubcommandHelp_SubcommandUsageText(t *testing.T) {
499	app := &App{
500		Commands: []*Command{
501			{
502				Name: "frobbly",
503				Subcommands: []*Command{
504					{
505						Name:      "bobbly",
506						UsageText: "this is usage text",
507					},
508				},
509			},
510		},
511	}
512
513	output := &bytes.Buffer{}
514	app.Writer = output
515	_ = app.Run([]string{"foo", "frobbly", "bobbly", "--help"})
516
517	if !strings.Contains(output.String(), "this is usage text") {
518		t.Errorf("expected output to include usage text; got: %q", output.String())
519	}
520}
521
522func TestShowAppHelp_HiddenCommand(t *testing.T) {
523	app := &App{
524		Commands: []*Command{
525			{
526				Name: "frobbly",
527				Action: func(ctx *Context) error {
528					return nil
529				},
530			},
531			{
532				Name:   "secretfrob",
533				Hidden: true,
534				Action: func(ctx *Context) error {
535					return nil
536				},
537			},
538		},
539	}
540
541	output := &bytes.Buffer{}
542	app.Writer = output
543	_ = app.Run([]string{"app", "--help"})
544
545	if strings.Contains(output.String(), "secretfrob") {
546		t.Errorf("expected output to exclude \"secretfrob\"; got: %q", output.String())
547	}
548
549	if !strings.Contains(output.String(), "frobbly") {
550		t.Errorf("expected output to include \"frobbly\"; got: %q", output.String())
551	}
552}
553
554func TestShowAppHelp_HelpPrinter(t *testing.T) {
555	doublecho := func(text string) string {
556		return text + " " + text
557	}
558
559	tests := []struct {
560		name         string
561		template     string
562		printer      helpPrinter
563		wantTemplate string
564		wantOutput   string
565	}{
566		{
567			name:     "standard-command",
568			template: "",
569			printer: func(w io.Writer, templ string, data interface{}) {
570				fmt.Fprint(w, "yo")
571			},
572			wantTemplate: AppHelpTemplate,
573			wantOutput:   "yo",
574		},
575		{
576			name:     "custom-template-command",
577			template: "{{doublecho .Name}}",
578			printer: func(w io.Writer, templ string, data interface{}) {
579				// Pass a custom function to ensure it gets used
580				fm := map[string]interface{}{"doublecho": doublecho}
581				printHelpCustom(w, templ, data, fm)
582			},
583			wantTemplate: "{{doublecho .Name}}",
584			wantOutput:   "my-app my-app",
585		},
586	}
587
588	for _, tt := range tests {
589		t.Run(tt.name, func(t *testing.T) {
590			defer func(old helpPrinter) {
591				HelpPrinter = old
592			}(HelpPrinter)
593			HelpPrinter = func(w io.Writer, templ string, data interface{}) {
594				if templ != tt.wantTemplate {
595					t.Errorf("want template:\n%s\ngot template:\n%s", tt.wantTemplate, templ)
596				}
597
598				tt.printer(w, templ, data)
599			}
600
601			var buf bytes.Buffer
602			app := &App{
603				Name:                  "my-app",
604				Writer:                &buf,
605				CustomAppHelpTemplate: tt.template,
606			}
607
608			err := app.Run([]string{"my-app", "help"})
609			if err != nil {
610				t.Fatal(err)
611			}
612
613			got := buf.String()
614			if got != tt.wantOutput {
615				t.Errorf("want output %q, got %q", tt.wantOutput, got)
616			}
617		})
618	}
619}
620
621func TestShowAppHelp_HelpPrinterCustom(t *testing.T) {
622	doublecho := func(text string) string {
623		return text + " " + text
624	}
625
626	tests := []struct {
627		name         string
628		template     string
629		printer      helpPrinterCustom
630		wantTemplate string
631		wantOutput   string
632	}{
633		{
634			name:     "standard-command",
635			template: "",
636			printer: func(w io.Writer, templ string, data interface{}, fm map[string]interface{}) {
637				fmt.Fprint(w, "yo")
638			},
639			wantTemplate: AppHelpTemplate,
640			wantOutput:   "yo",
641		},
642		{
643			name:     "custom-template-command",
644			template: "{{doublecho .Name}}",
645			printer: func(w io.Writer, templ string, data interface{}, _ map[string]interface{}) {
646				// Pass a custom function to ensure it gets used
647				fm := map[string]interface{}{"doublecho": doublecho}
648				printHelpCustom(w, templ, data, fm)
649			},
650			wantTemplate: "{{doublecho .Name}}",
651			wantOutput:   "my-app my-app",
652		},
653	}
654
655	for _, tt := range tests {
656		t.Run(tt.name, func(t *testing.T) {
657			defer func(old helpPrinterCustom) {
658				HelpPrinterCustom = old
659			}(HelpPrinterCustom)
660			HelpPrinterCustom = func(w io.Writer, templ string, data interface{}, fm map[string]interface{}) {
661				if fm != nil {
662					t.Error("unexpected function map passed")
663				}
664
665				if templ != tt.wantTemplate {
666					t.Errorf("want template:\n%s\ngot template:\n%s", tt.wantTemplate, templ)
667				}
668
669				tt.printer(w, templ, data, fm)
670			}
671
672			var buf bytes.Buffer
673			app := &App{
674				Name:                  "my-app",
675				Writer:                &buf,
676				CustomAppHelpTemplate: tt.template,
677			}
678
679			err := app.Run([]string{"my-app", "help"})
680			if err != nil {
681				t.Fatal(err)
682			}
683
684			got := buf.String()
685			if got != tt.wantOutput {
686				t.Errorf("want output %q, got %q", tt.wantOutput, got)
687			}
688		})
689	}
690}
691
692func TestShowAppHelp_CustomAppTemplate(t *testing.T) {
693	app := &App{
694		Commands: []*Command{
695			{
696				Name: "frobbly",
697				Action: func(ctx *Context) error {
698					return nil
699				},
700			},
701			{
702				Name:   "secretfrob",
703				Hidden: true,
704				Action: func(ctx *Context) error {
705					return nil
706				},
707			},
708		},
709		ExtraInfo: func() map[string]string {
710			platform := fmt.Sprintf("OS: %s | Arch: %s", runtime.GOOS, runtime.GOARCH)
711			goruntime := fmt.Sprintf("Version: %s | CPUs: %d", runtime.Version(), runtime.NumCPU())
712			return map[string]string{
713				"PLATFORM": platform,
714				"RUNTIME":  goruntime,
715			}
716		},
717		CustomAppHelpTemplate: `NAME:
718  {{.Name}} - {{.Usage}}
719
720USAGE:
721  {{.Name}} {{if .VisibleFlags}}[FLAGS] {{end}}COMMAND{{if .VisibleFlags}} [COMMAND FLAGS | -h]{{end}} [ARGUMENTS...]
722
723COMMANDS:
724  {{range .VisibleCommands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}}
725  {{end}}{{if .VisibleFlags}}
726GLOBAL FLAGS:
727  {{range .VisibleFlags}}{{.}}
728  {{end}}{{end}}
729VERSION:
730  2.0.0
731{{"\n"}}{{range $key, $value := ExtraInfo}}
732{{$key}}:
733  {{$value}}
734{{end}}`,
735	}
736
737	output := &bytes.Buffer{}
738	app.Writer = output
739	_ = app.Run([]string{"app", "--help"})
740
741	if strings.Contains(output.String(), "secretfrob") {
742		t.Errorf("expected output to exclude \"secretfrob\"; got: %q", output.String())
743	}
744
745	if !strings.Contains(output.String(), "frobbly") {
746		t.Errorf("expected output to include \"frobbly\"; got: %q", output.String())
747	}
748
749	if !strings.Contains(output.String(), "PLATFORM:") ||
750		!strings.Contains(output.String(), "OS:") ||
751		!strings.Contains(output.String(), "Arch:") {
752		t.Errorf("expected output to include \"PLATFORM:, OS: and Arch:\"; got: %q", output.String())
753	}
754
755	if !strings.Contains(output.String(), "RUNTIME:") ||
756		!strings.Contains(output.String(), "Version:") ||
757		!strings.Contains(output.String(), "CPUs:") {
758		t.Errorf("expected output to include \"RUNTIME:, Version: and CPUs:\"; got: %q", output.String())
759	}
760
761	if !strings.Contains(output.String(), "VERSION:") ||
762		!strings.Contains(output.String(), "2.0.0") {
763		t.Errorf("expected output to include \"VERSION:, 2.0.0\"; got: %q", output.String())
764	}
765}
766
767func TestHideHelpCommand(t *testing.T) {
768	app := &App{
769		HideHelpCommand: true,
770		Writer:          ioutil.Discard,
771	}
772
773	err := app.Run([]string{"foo", "help"})
774	if err == nil {
775		t.Fatalf("expected a non-nil error")
776	}
777	if !strings.Contains(err.Error(), "No help topic for 'help'") {
778		t.Errorf("Run returned unexpected error: %v", err)
779	}
780
781	err = app.Run([]string{"foo", "--help"})
782	if err != nil {
783		t.Errorf("Run returned unexpected error: %v", err)
784	}
785}
786
787func TestHideHelpCommand_False(t *testing.T) {
788	app := &App{
789		HideHelpCommand: false,
790		Writer:          ioutil.Discard,
791	}
792
793	err := app.Run([]string{"foo", "help"})
794	if err != nil {
795		t.Errorf("Run returned unexpected error: %v", err)
796	}
797
798	err = app.Run([]string{"foo", "--help"})
799	if err != nil {
800		t.Errorf("Run returned unexpected error: %v", err)
801	}
802}
803
804func TestHideHelpCommand_WithHideHelp(t *testing.T) {
805	app := &App{
806		HideHelp:        true, // effective (hides both command and flag)
807		HideHelpCommand: true, // ignored
808		Writer:          ioutil.Discard,
809	}
810
811	err := app.Run([]string{"foo", "help"})
812	if err == nil {
813		t.Fatalf("expected a non-nil error")
814	}
815	if !strings.Contains(err.Error(), "No help topic for 'help'") {
816		t.Errorf("Run returned unexpected error: %v", err)
817	}
818
819	err = app.Run([]string{"foo", "--help"})
820	if err == nil {
821		t.Fatalf("expected a non-nil error")
822	}
823	if !strings.Contains(err.Error(), "flag: help requested") {
824		t.Errorf("Run returned unexpected error: %v", err)
825	}
826}
827
828func newContextFromStringSlice(ss []string) *Context {
829	set := flag.NewFlagSet("", flag.ContinueOnError)
830	_ = set.Parse(ss)
831	return &Context{flagSet: set}
832}
833
834func TestHideHelpCommand_RunAsSubcommand(t *testing.T) {
835	app := &App{
836		HideHelpCommand: true,
837		Writer:          ioutil.Discard,
838		Commands: []*Command{
839			{
840				Name: "dummy",
841			},
842		},
843	}
844
845	err := app.RunAsSubcommand(newContextFromStringSlice([]string{"", "help"}))
846	if err == nil {
847		t.Fatalf("expected a non-nil error")
848	}
849	if !strings.Contains(err.Error(), "No help topic for 'help'") {
850		t.Errorf("Run returned unexpected error: %v", err)
851	}
852
853	err = app.RunAsSubcommand(newContextFromStringSlice([]string{"", "--help"}))
854	if err != nil {
855		t.Errorf("Run returned unexpected error: %v", err)
856	}
857}
858
859func TestHideHelpCommand_RunAsSubcommand_False(t *testing.T) {
860	app := &App{
861		HideHelpCommand: false,
862		Writer:          ioutil.Discard,
863		Commands: []*Command{
864			{
865				Name: "dummy",
866			},
867		},
868	}
869
870	err := app.RunAsSubcommand(newContextFromStringSlice([]string{"", "help"}))
871	if err != nil {
872		t.Errorf("Run returned unexpected error: %v", err)
873	}
874
875	err = app.RunAsSubcommand(newContextFromStringSlice([]string{"", "--help"}))
876	if err != nil {
877		t.Errorf("Run returned unexpected error: %v", err)
878	}
879}
880
881func TestHideHelpCommand_WithSubcommands(t *testing.T) {
882	app := &App{
883		Writer: ioutil.Discard,
884		Commands: []*Command{
885			{
886				Name: "dummy",
887				Subcommands: []*Command{
888					{
889						Name: "dummy2",
890					},
891				},
892				HideHelpCommand: true,
893			},
894		},
895	}
896
897	err := app.Run([]string{"foo", "dummy", "help"})
898	if err == nil {
899		t.Fatalf("expected a non-nil error")
900	}
901	if !strings.Contains(err.Error(), "No help topic for 'help'") {
902		t.Errorf("Run returned unexpected error: %v", err)
903	}
904
905	err = app.Run([]string{"foo", "dummy", "--help"})
906	if err != nil {
907		t.Errorf("Run returned unexpected error: %v", err)
908	}
909}
910