From: Rob Pike Date: Sun, 18 Sep 2022 12:05:00 +0000 (+1000) Subject: flag: test IsBoolFlag when creating the usage message X-Git-Tag: go1.20rc1~985 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=2d741947d8931325576427b3699d1af20e7be7cf;p=gostls13.git flag: test IsBoolFlag when creating the usage message Although I can't think of any reason to do this, it is possible for a user-defined flag to implement IsBoolFlag but return "false". This is nuts because checking the interface is satisfied should obviously be sufficient, but the documentation kinda implies it's not. And if you try this, you'll discover that the usage message ignores the return value even though the rest of the package plays nice. Bother. So we fix it, as the fix is trivial: call the method when creating the usage message. Fixes #53473 Change-Id: I1ac80a876ad5626eebfc5ef6cb972cd3007afaad Reviewed-on: https://go-review.googlesource.com/c/go/+/431102 Reviewed-by: Cherry Mui Run-TryBot: Ian Lance Taylor TryBot-Result: Gopher Robot Reviewed-by: Ian Lance Taylor --- diff --git a/src/flag/flag.go b/src/flag/flag.go index 9abf8d769e..f6b38908f6 100644 --- a/src/flag/flag.go +++ b/src/flag/flag.go @@ -550,9 +550,11 @@ func UnquoteUsage(flag *Flag) (name string, usage string) { } // No explicit name, so use type if we can find one. name = "value" - switch flag.Value.(type) { + switch fv := flag.Value.(type) { case boolFlag: - name = "" + if fv.IsBoolFlag() { + name = "" + } case *durationValue: name = "duration" case *float64Value: diff --git a/src/flag/flag_test.go b/src/flag/flag_test.go index 791a8826be..1755168405 100644 --- a/src/flag/flag_test.go +++ b/src/flag/flag_test.go @@ -5,6 +5,7 @@ package flag_test import ( + "bytes" . "flag" "fmt" "internal/testenv" @@ -355,6 +356,31 @@ func TestUserDefinedBool(t *testing.T) { } } +func TestUserDefinedBoolUsage(t *testing.T) { + var flags FlagSet + flags.Init("test", ContinueOnError) + var buf bytes.Buffer + flags.SetOutput(&buf) + var b boolFlagVar + flags.Var(&b, "b", "X") + b.count = 0 + // b.IsBoolFlag() will return true and usage will look boolean. + flags.PrintDefaults() + got := buf.String() + want := " -b\tX\n" + if got != want { + t.Errorf("false: want %q; got %q", want, got) + } + b.count = 4 + // b.IsBoolFlag() will return false and usage will look non-boolean. + flags.PrintDefaults() + got = buf.String() + want = " -b\tX\n -b value\n \tX\n" + if got != want { + t.Errorf("false: want %q; got %q", want, got) + } +} + func TestSetOutput(t *testing.T) { var flags FlagSet var buf strings.Builder