From fb5b1ac074966e47591e75ec7af40ea197a12f90 Mon Sep 17 00:00:00 2001 From: "John R. Lenton" Date: Wed, 26 Sep 2018 15:44:00 +0100 Subject: [PATCH 1/3] Fix issue #275 This change restores the old behaviour of PassAfterNonOption working together with commands so that a command would (also) get everything after the first non-option, while also preserving the new behaviour of those non-options landing in the positional array if provided. The behaviour for when a command and a positional array are both present continues to be weird (but it's unclear whether there's a non-weird way out of that one other than failing with a "don't do that"). --- options_test.go | 35 +++++++++++++++++++++++++++++++++++ parser.go | 2 +- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/options_test.go b/options_test.go index 110fe2f..0b14205 100644 --- a/options_test.go +++ b/options_test.go @@ -45,6 +45,41 @@ func TestPassAfterNonOption(t *testing.T) { assertStringArray(t, ret, []string{"arg", "-v", "-g"}) } +type fooCmd struct { + Flag bool `short:"f"` + args []string +} + +func (foo *fooCmd) Execute(s []string) error { + foo.args = s + return nil +} + +func TestPassAfterNonOptionWithCommand(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + Foo fooCmd `command:"foo"` + }{} + p := NewParser(&opts, PassAfterNonOption) + ret, err := p.ParseArgs([]string{"-v", "foo", "-f", "bar", "-v", "-g"}) + + if err != nil { + t.Fatalf("Unexpected error: %v", err) + return + } + + if !opts.Value { + t.Errorf("Expected Value to be true") + } + + if !opts.Foo.Flag { + t.Errorf("Expected Foo.Flag to be true") + } + + assertStringArray(t, ret, []string{"bar", "-v", "-g"}) + assertStringArray(t, opts.Foo.args, []string{"bar", "-v", "-g"}) +} + func TestPassAfterNonOptionWithPositional(t *testing.T) { var opts = struct { Value bool `short:"v"` diff --git a/parser.go b/parser.go index d75a17c..54816a6 100644 --- a/parser.go +++ b/parser.go @@ -252,7 +252,7 @@ func (p *Parser) ParseArgs(args []string) ([]string, error) { } if !argumentIsOption(arg) { - if (p.Options & PassAfterNonOption) != None { + if (p.Options&PassAfterNonOption) != None && s.lookup.commands[arg] == nil { // If PassAfterNonOption is set then all remaining arguments // are considered positional if err = s.addArgs(s.arg); err != nil { From 9a38bfa8fedf0fdfa03666007497c987daba6330 Mon Sep 17 00:00:00 2001 From: "John R. Lenton" Date: Wed, 26 Sep 2018 15:52:32 +0100 Subject: [PATCH 2/3] added test to check for new command + positional behaviour --- options_test.go | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/options_test.go b/options_test.go index 0b14205..5b07099 100644 --- a/options_test.go +++ b/options_test.go @@ -80,6 +80,39 @@ func TestPassAfterNonOptionWithCommand(t *testing.T) { assertStringArray(t, opts.Foo.args, []string{"bar", "-v", "-g"}) } +type barCmd struct { + fooCmd + Positional struct { + Args []string + } `positional-args:"yes"` +} + +func TestPassAfterNonOptionWithCommandWithPositional(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + Bar barCmd `command:"bar"` + }{} + p := NewParser(&opts, PassAfterNonOption) + ret, err := p.ParseArgs([]string{"-v", "bar", "-f", "baz", "-v", "-g"}) + + if err != nil { + t.Fatalf("Unexpected error: %v", err) + return + } + + if !opts.Value { + t.Errorf("Expected Value to be true") + } + + if !opts.Bar.Flag { + t.Errorf("Expected Bar.Flag to be true") + } + + assertStringArray(t, ret, []string{}) + assertStringArray(t, opts.Bar.args, []string{}) + assertStringArray(t, opts.Bar.Positional.Args, []string{"baz", "-v", "-g"}) +} + func TestPassAfterNonOptionWithPositional(t *testing.T) { var opts = struct { Value bool `short:"v"` From e7ac6cd8efdaaad25ca45e5394ead835b6b1e19f Mon Sep 17 00:00:00 2001 From: "John R. Lenton" Date: Thu, 27 Sep 2018 09:01:41 +0100 Subject: [PATCH 3/3] move tests for PassAfterNonOption with commands to command_test --- command_test.go | 68 +++++++++++++++++++++++++++++++++++++++++++++++++ options_test.go | 68 ------------------------------------------------- 2 files changed, 68 insertions(+), 68 deletions(-) diff --git a/command_test.go b/command_test.go index dc04b66..80d56be 100644 --- a/command_test.go +++ b/command_test.go @@ -580,3 +580,71 @@ func TestSubCommandFindOptionByShortFlag(t *testing.T) { t.Errorf("Expected 'o', but got %v", opt.ShortName) } } + +type fooCmd struct { + Flag bool `short:"f"` + args []string +} + +func (foo *fooCmd) Execute(s []string) error { + foo.args = s + return nil +} + +func TestCommandPassAfterNonOption(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + Foo fooCmd `command:"foo"` + }{} + p := NewParser(&opts, PassAfterNonOption) + ret, err := p.ParseArgs([]string{"-v", "foo", "-f", "bar", "-v", "-g"}) + + if err != nil { + t.Fatalf("Unexpected error: %v", err) + return + } + + if !opts.Value { + t.Errorf("Expected Value to be true") + } + + if !opts.Foo.Flag { + t.Errorf("Expected Foo.Flag to be true") + } + + assertStringArray(t, ret, []string{"bar", "-v", "-g"}) + assertStringArray(t, opts.Foo.args, []string{"bar", "-v", "-g"}) +} + +type barCmd struct { + fooCmd + Positional struct { + Args []string + } `positional-args:"yes"` +} + +func TestCommandPassAfterNonOptionWithPositional(t *testing.T) { + var opts = struct { + Value bool `short:"v"` + Bar barCmd `command:"bar"` + }{} + p := NewParser(&opts, PassAfterNonOption) + ret, err := p.ParseArgs([]string{"-v", "bar", "-f", "baz", "-v", "-g"}) + + if err != nil { + t.Fatalf("Unexpected error: %v", err) + return + } + + if !opts.Value { + t.Errorf("Expected Value to be true") + } + + if !opts.Bar.Flag { + t.Errorf("Expected Bar.Flag to be true") + } + + assertStringArray(t, ret, []string{}) + assertStringArray(t, opts.Bar.args, []string{}) + assertStringArray(t, opts.Bar.Positional.Args, []string{"baz", "-v", "-g"}) +} diff --git a/options_test.go b/options_test.go index 5b07099..110fe2f 100644 --- a/options_test.go +++ b/options_test.go @@ -45,74 +45,6 @@ func TestPassAfterNonOption(t *testing.T) { assertStringArray(t, ret, []string{"arg", "-v", "-g"}) } -type fooCmd struct { - Flag bool `short:"f"` - args []string -} - -func (foo *fooCmd) Execute(s []string) error { - foo.args = s - return nil -} - -func TestPassAfterNonOptionWithCommand(t *testing.T) { - var opts = struct { - Value bool `short:"v"` - Foo fooCmd `command:"foo"` - }{} - p := NewParser(&opts, PassAfterNonOption) - ret, err := p.ParseArgs([]string{"-v", "foo", "-f", "bar", "-v", "-g"}) - - if err != nil { - t.Fatalf("Unexpected error: %v", err) - return - } - - if !opts.Value { - t.Errorf("Expected Value to be true") - } - - if !opts.Foo.Flag { - t.Errorf("Expected Foo.Flag to be true") - } - - assertStringArray(t, ret, []string{"bar", "-v", "-g"}) - assertStringArray(t, opts.Foo.args, []string{"bar", "-v", "-g"}) -} - -type barCmd struct { - fooCmd - Positional struct { - Args []string - } `positional-args:"yes"` -} - -func TestPassAfterNonOptionWithCommandWithPositional(t *testing.T) { - var opts = struct { - Value bool `short:"v"` - Bar barCmd `command:"bar"` - }{} - p := NewParser(&opts, PassAfterNonOption) - ret, err := p.ParseArgs([]string{"-v", "bar", "-f", "baz", "-v", "-g"}) - - if err != nil { - t.Fatalf("Unexpected error: %v", err) - return - } - - if !opts.Value { - t.Errorf("Expected Value to be true") - } - - if !opts.Bar.Flag { - t.Errorf("Expected Bar.Flag to be true") - } - - assertStringArray(t, ret, []string{}) - assertStringArray(t, opts.Bar.args, []string{}) - assertStringArray(t, opts.Bar.Positional.Args, []string{"baz", "-v", "-g"}) -} - func TestPassAfterNonOptionWithPositional(t *testing.T) { var opts = struct { Value bool `short:"v"`