From 72e54a1d0c9c11fe565479370ea705354d5d0727 Mon Sep 17 00:00:00 2001 From: Scott Wisniewski Date: Sat, 19 Mar 2022 13:31:36 -0700 Subject: [PATCH] One more round of PR Feedback. Make negatable bool * work. --- context.go | 21 ++++++++++++++++++++- kong_test.go | 29 ++++++++++++++++++++++++++++- tag.go | 4 +++- 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/context.go b/context.go index a97edb0..cefe728 100644 --- a/context.go +++ b/context.go @@ -663,6 +663,22 @@ func (c *Context) Apply() (string, error) { return strings.Join(path, " "), nil } +func flipBoolValue(value reflect.Value) error { + if value.Kind() == reflect.Bool { + value.SetBool(!value.Bool()) + return nil + } + + if value.Kind() == reflect.Ptr { + if !value.IsNil() { + return flipBoolValue(value.Elem()) + } + return nil + } + + return fmt.Errorf("cannot negate a value of %s", value.Type().String()) +} + func (c *Context) parseFlag(flags []*Flag, match string) (err error) { candidates := []string{} for _, flag := range flags { @@ -690,7 +706,10 @@ func (c *Context) parseFlag(flags []*Flag, match string) (err error) { } if flag.Negated { value := c.getValue(flag.Value) - value.SetBool(!value.Bool()) + err := flipBoolValue(value) + if err != nil { + return err + } flag.Value.Apply(value) } c.Path = append(c.Path, &Path{Flag: flag}) diff --git a/kong_test.go b/kong_test.go index 49ae4f5..1b2e1ea 100644 --- a/kong_test.go +++ b/kong_test.go @@ -1660,7 +1660,7 @@ func TestBoolPtr(t *testing.T) { require.Equal(t, true, *cli.X) } -func TestBoolPtrNegated(t *testing.T) { +func TestBoolPtrFalse(t *testing.T) { var cli struct { X *bool } @@ -1674,6 +1674,33 @@ func TestBoolPtrNegated(t *testing.T) { require.Equal(t, false, *cli.X) } +func TestBoolPtrNegated(t *testing.T) { + var cli struct { + X *bool `negatable:""` + } + k, err := kong.New(&cli) + require.NoError(t, err) + require.NotNil(t, k) + ctx, err := k.Parse([]string{"--no-x"}) + require.NoError(t, err) + require.NotNil(t, ctx) + require.NotNil(t, cli.X) + require.Equal(t, false, *cli.X) +} + +func TestNilNegatableBoolPtr(t *testing.T) { + var cli struct { + X *bool `negatable:""` + } + k, err := kong.New(&cli) + require.NoError(t, err) + require.NotNil(t, k) + ctx, err := k.Parse([]string{}) + require.NoError(t, err) + require.NotNil(t, ctx) + require.Nil(t, cli.X) +} + func TestBoolPtrNil(t *testing.T) { var cli struct { X *bool diff --git a/tag.go b/tag.go index 25cd242..b471613 100644 --- a/tag.go +++ b/tag.go @@ -169,9 +169,11 @@ func parseTag(parent reflect.Value, ft reflect.StructField) (*Tag, error) { func hydrateTag(t *Tag, typ reflect.Type) error { // nolint: gocyclo var typeName string var isBool bool + var isBoolPtr bool if typ != nil { typeName = typ.Name() isBool = typ.Kind() == reflect.Bool + isBoolPtr = typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Bool } var err error t.Cmd = t.Has("cmd") @@ -212,7 +214,7 @@ func hydrateTag(t *Tag, typ reflect.Type) error { // nolint: gocyclo t.EnvPrefix = t.Get("envprefix") t.Embed = t.Has("embed") negatable := t.Has("negatable") - if negatable && !isBool { + if negatable && !isBool && !isBoolPtr { return fmt.Errorf("negatable can only be set on booleans") } t.Negatable = negatable