From a1491038f8a8ae7615b4728f032aa00b2548d8c4 Mon Sep 17 00:00:00 2001 From: Naveen Gogineni Date: Sun, 4 Jun 2023 20:42:26 -0400 Subject: [PATCH 1/4] Fix:(issue_1668) Add test case for subcommand completion --- app_test.go | 40 ++++++++++++++++++++++++++++++++++++++++ help.go | 14 +++++++++++++- help_test.go | 8 +++----- 3 files changed, 56 insertions(+), 6 deletions(-) diff --git a/app_test.go b/app_test.go index 981d074697..a48ca81eeb 100644 --- a/app_test.go +++ b/app_test.go @@ -1391,6 +1391,46 @@ func TestApp_BeforeAfterFuncShellCompletion(t *testing.T) { } } +func TestApp_SubcommandShellCompletion(t *testing.T) { + + var w bytes.Buffer + + app := &App{ + Name: "command", + EnableBashCompletion: true, + Commands: []*Command{ + { + Name: "subcmd1", + Subcommands: []*Command{ + { + Name: "subcmd2", + Subcommands: []*Command{ + { + Name: "subcmd3", + }, + }, + }, + }, + }, + }, + Flags: []Flag{ + &StringFlag{Name: "opt"}, + }, + Writer: &w, + } + + // run with the Before() func succeeding + err := app.Run([]string{"command", "subcmd1", "subcmd2", "--generate-bash-completion"}) + + if err != nil { + t.Error(err) + } + + if !strings.Contains(w.String(), "subcmd3\n") { + t.Errorf("Expected subcmd3 got %s", w.String()) + } +} + func TestApp_AfterFunc(t *testing.T) { counts := &opCounts{} afterError := fmt.Errorf("fail") diff --git a/help.go b/help.go index a71fceb709..f58ce1a6da 100644 --- a/help.go +++ b/help.go @@ -209,9 +209,21 @@ func printFlagSuggestions(lastArg string, flags []Flag, writer io.Writer) { func DefaultCompleteWithFlags(cmd *Command) func(cCtx *Context) { return func(cCtx *Context) { + var lastArg string + if len(os.Args) > 2 { - lastArg := os.Args[len(os.Args)-2] + lastArg = os.Args[len(os.Args)-2] + } + + if cmd != nil { + if cCtx.NArg() > 1 { + lastArg = cCtx.Args().Get(cCtx.NArg() - 1) + } else { + lastArg = "" + } + } + if lastArg != "" { if strings.HasPrefix(lastArg, "-") { if cmd != nil { printFlagSuggestions(lastArg, cmd.Flags, cCtx.App.Writer) diff --git a/help_test.go b/help_test.go index fd9983bb64..975607fd73 100644 --- a/help_test.go +++ b/help_test.go @@ -1174,7 +1174,7 @@ func TestDefaultCompleteWithFlags(t *testing.T) { argv: []string{"prog", "cmd"}, expected: "", }, - { + /*{ name: "typical-flag-suggestion", c: &Context{App: &App{ Name: "cmd", @@ -1238,15 +1238,13 @@ func TestDefaultCompleteWithFlags(t *testing.T) { }, argv: []string{"cmd", "--url", "http://localhost:8000", "h", "--generate-bash-completion"}, expected: "help\n", - }, + },*/ } { t.Run(tc.name, func(ct *testing.T) { writer := &bytes.Buffer{} tc.c.App.Writer = writer - os.Args = tc.argv - f := DefaultCompleteWithFlags(tc.cmd) - f(tc.c) + tc.c.App.Run(tc.argv) written := writer.String() From b68cbf6488f3a5a4126c42270fe4d30909755c15 Mon Sep 17 00:00:00 2001 From: Naveen Gogineni Date: Sun, 4 Jun 2023 21:06:32 -0400 Subject: [PATCH 2/4] Add subcommand test case --- help_test.go | 96 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 60 insertions(+), 36 deletions(-) diff --git a/help_test.go b/help_test.go index 975607fd73..ae397b26b1 100644 --- a/help_test.go +++ b/help_test.go @@ -1162,21 +1162,19 @@ func TestDefaultCompleteWithFlags(t *testing.T) { for _, tc := range []struct { name string - c *Context - cmd *Command + a *App argv []string expected string }{ { name: "empty", - c: &Context{App: &App{}}, - cmd: &Command{}, + a: &App{}, argv: []string{"prog", "cmd"}, expected: "", }, - /*{ + { name: "typical-flag-suggestion", - c: &Context{App: &App{ + a: &App{ Name: "cmd", Flags: []Flag{ &BoolFlag{Name: "happiness"}, @@ -1185,66 +1183,92 @@ func TestDefaultCompleteWithFlags(t *testing.T) { Commands: []*Command{ {Name: "putz"}, }, - }}, - cmd: &Command{ - Flags: []Flag{ - &BoolFlag{Name: "excitement"}, - &StringFlag{Name: "hat-shape"}, - }, }, argv: []string{"cmd", "--e", "--generate-bash-completion"}, - expected: "--excitement\n", + expected: "--everybody-jump-on\n", }, { name: "typical-command-suggestion", - c: &Context{App: &App{ + a: &App{ Name: "cmd", Flags: []Flag{ &BoolFlag{Name: "happiness"}, &Int64Flag{Name: "everybody-jump-on"}, }, - }}, - cmd: &Command{ - Name: "putz", - Subcommands: []*Command{ - {Name: "futz"}, + Commands: []*Command{ + { + Name: "putz", + Subcommands: []*Command{ + {Name: "futz"}, + }, + Flags: []Flag{ + &BoolFlag{Name: "excitement"}, + &StringFlag{Name: "hat-shape"}, + }, + }, }, + }, + argv: []string{"cmd", "--generate-bash-completion"}, + expected: "putz\n", + }, + { + name: "typical-subcommand-suggestion", + a: &App{ + Name: "cmd", Flags: []Flag{ - &BoolFlag{Name: "excitement"}, - &StringFlag{Name: "hat-shape"}, + &BoolFlag{Name: "happiness"}, + &Int64Flag{Name: "everybody-jump-on"}, + }, + Commands: []*Command{ + { + Name: "putz", + HideHelp: true, + Subcommands: []*Command{ + {Name: "futz"}, + }, + Flags: []Flag{ + &BoolFlag{Name: "excitement"}, + &StringFlag{Name: "hat-shape"}, + }, + }, }, }, - argv: []string{"cmd", "--generate-bash-completion"}, + argv: []string{"cmd", "--happiness", "putz", "--generate-bash-completion"}, expected: "futz\n", }, { name: "autocomplete-with-spaces", - c: &Context{App: &App{ + a: &App{ Name: "cmd", Flags: []Flag{ &BoolFlag{Name: "happiness"}, &Int64Flag{Name: "everybody-jump-on"}, }, - }}, - cmd: &Command{ - Name: "putz", - Subcommands: []*Command{ - {Name: "help"}, - }, - Flags: []Flag{ - &BoolFlag{Name: "excitement"}, - &StringFlag{Name: "hat-shape"}, + Commands: []*Command{ + { + Name: "putz", + Subcommands: []*Command{ + {Name: "help"}, + }, + Flags: []Flag{ + &BoolFlag{Name: "excitement"}, + &StringFlag{Name: "hat-shape"}, + }, + }, }, }, - argv: []string{"cmd", "--url", "http://localhost:8000", "h", "--generate-bash-completion"}, + argv: []string{"cmd", "--happiness", "putz", "h", "--generate-bash-completion"}, expected: "help\n", - },*/ + }, } { t.Run(tc.name, func(ct *testing.T) { writer := &bytes.Buffer{} - tc.c.App.Writer = writer - tc.c.App.Run(tc.argv) + tc.a.EnableBashCompletion = true + tc.a.HideHelp = true + tc.a.Writer = writer + os.Args = tc.argv + tc.a.Run(tc.argv) written := writer.String() From 0b3304b0aa23cc5c34e3f0b97efb4ec326867105 Mon Sep 17 00:00:00 2001 From: Naveen Gogineni Date: Sun, 4 Jun 2023 21:21:56 -0400 Subject: [PATCH 3/4] Add subsub command test case --- app_test.go | 40 ---------------------------------------- help.go | 2 -- help_test.go | 31 ++++++++++++++++++++++++++++--- 3 files changed, 28 insertions(+), 45 deletions(-) diff --git a/app_test.go b/app_test.go index a48ca81eeb..981d074697 100644 --- a/app_test.go +++ b/app_test.go @@ -1391,46 +1391,6 @@ func TestApp_BeforeAfterFuncShellCompletion(t *testing.T) { } } -func TestApp_SubcommandShellCompletion(t *testing.T) { - - var w bytes.Buffer - - app := &App{ - Name: "command", - EnableBashCompletion: true, - Commands: []*Command{ - { - Name: "subcmd1", - Subcommands: []*Command{ - { - Name: "subcmd2", - Subcommands: []*Command{ - { - Name: "subcmd3", - }, - }, - }, - }, - }, - }, - Flags: []Flag{ - &StringFlag{Name: "opt"}, - }, - Writer: &w, - } - - // run with the Before() func succeeding - err := app.Run([]string{"command", "subcmd1", "subcmd2", "--generate-bash-completion"}) - - if err != nil { - t.Error(err) - } - - if !strings.Contains(w.String(), "subcmd3\n") { - t.Errorf("Expected subcmd3 got %s", w.String()) - } -} - func TestApp_AfterFunc(t *testing.T) { counts := &opCounts{} afterError := fmt.Errorf("fail") diff --git a/help.go b/help.go index f58ce1a6da..82d37fbb9f 100644 --- a/help.go +++ b/help.go @@ -218,8 +218,6 @@ func DefaultCompleteWithFlags(cmd *Command) func(cCtx *Context) { if cmd != nil { if cCtx.NArg() > 1 { lastArg = cCtx.Args().Get(cCtx.NArg() - 1) - } else { - lastArg = "" } } diff --git a/help_test.go b/help_test.go index ae397b26b1..736907a250 100644 --- a/help_test.go +++ b/help_test.go @@ -1221,8 +1221,7 @@ func TestDefaultCompleteWithFlags(t *testing.T) { }, Commands: []*Command{ { - Name: "putz", - HideHelp: true, + Name: "putz", Subcommands: []*Command{ {Name: "futz"}, }, @@ -1234,7 +1233,33 @@ func TestDefaultCompleteWithFlags(t *testing.T) { }, }, argv: []string{"cmd", "--happiness", "putz", "--generate-bash-completion"}, - expected: "futz\n", + expected: "futz\nhelp\nh\n", + }, + { + name: "typical-subcommand-subcommand-suggestion", + a: &App{ + Name: "cmd", + Flags: []Flag{ + &BoolFlag{Name: "happiness"}, + &Int64Flag{Name: "everybody-jump-on"}, + }, + Commands: []*Command{ + { + Name: "putz", + Subcommands: []*Command{ + { + Name: "futz", + Flags: []Flag{ + &BoolFlag{Name: "excitement"}, + &StringFlag{Name: "hat-shape"}, + }, + }, + }, + }, + }, + }, + argv: []string{"cmd", "--happiness", "putz", "futz", "-e", "--generate-bash-completion"}, + expected: "--excitement\n", }, { name: "autocomplete-with-spaces", From d93839a085ee1b0eab26dcdd590d7d3e61e5ec57 Mon Sep 17 00:00:00 2001 From: Naveen Gogineni Date: Mon, 5 Jun 2023 07:21:34 -0400 Subject: [PATCH 4/4] Remove redundant code --- help.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/help.go b/help.go index 82d37fbb9f..885d7843c4 100644 --- a/help.go +++ b/help.go @@ -211,16 +211,12 @@ func DefaultCompleteWithFlags(cmd *Command) func(cCtx *Context) { return func(cCtx *Context) { var lastArg string + // TODO: This shouldnt depend on os.Args rather it should + // depend on root arguments passed to App if len(os.Args) > 2 { lastArg = os.Args[len(os.Args)-2] } - if cmd != nil { - if cCtx.NArg() > 1 { - lastArg = cCtx.Args().Get(cCtx.NArg() - 1) - } - } - if lastArg != "" { if strings.HasPrefix(lastArg, "-") { if cmd != nil {