From 2d741947d8931325576427b3699d1af20e7be7cf Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Sun, 18 Sep 2022 22:05:00 +1000 Subject: [PATCH] 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 --- src/flag/flag.go | 6 ++++-- src/flag/flag_test.go | 26 ++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) 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 -- 2.50.0