diff --git a/flag.go b/flag.go index 28538c07..8c842baf 100644 --- a/flag.go +++ b/flag.go @@ -138,6 +138,10 @@ type FlagSet struct { // help/usage messages. SortFlags bool + // ShowZeroValue is used to indicate, if user wants to show zero value in + // help/usage messages. + ShowZeroValue bool + name string parsed bool actual map[NormalizedName]*Flag @@ -693,7 +697,7 @@ func (f *FlagSet) FlagUsagesWrapped(cols int) string { } line += usage - if !flag.defaultIsZeroValue() { + if f.ShowZeroValue || !flag.defaultIsZeroValue() { if flag.Value.Type() == "string" { line += fmt.Sprintf(" (default %q)", flag.DefValue) } else { diff --git a/flag_test.go b/flag_test.go index d587752f..6e2a6da2 100644 --- a/flag_test.go +++ b/flag_test.go @@ -1117,6 +1117,72 @@ func TestPrintDefaults(t *testing.T) { } } +const defaultOutputWithZeroValue = ` --A for bootstrapping, allow 'any' type (default false) + --Alongflagname disable bounds checking (default false) + -C, --CCC a boolean defaulting to true (default true) + --D path set relative path for local imports (default "") + -E, --EEE num[=1234] a num with NoOptDefVal (default 4321) + --F number a non-zero number (default 2.7) + --G float a float that defaults to zero (default 0) + --IP ip IP address with no default (default ) + --IPMask ipMask Netmask address with no default (default ) + --IPNet ipNet IP network with no default (default ) + --Ints ints int slice with zero default (default []) + --N int a non-zero int (default 27) + --ND1 string[="bar"] a string with NoOptDefVal (default "foo") + --ND2 num[=4321] a num with NoOptDefVal (default 1234) + --StringArray stringArray string array with zero default (default []) + --StringSlice strings string slice with zero default (default []) + --Z int an int that defaults to zero (default 0) + --custom custom custom Value implementation (default 0) + --customP custom a VarP with default (default 10) + --maxT timeout set timeout for dial (default 0s) + -v, --verbose count verbosity (default 0) +` + +func TestPrintDefaultsWithZeroValue(t *testing.T) { + fs := NewFlagSet("print defaults test", ContinueOnError) + fs.ShowZeroValue = true + var buf bytes.Buffer + fs.SetOutput(&buf) + fs.Bool("A", false, "for bootstrapping, allow 'any' type") + fs.Bool("Alongflagname", false, "disable bounds checking") + fs.BoolP("CCC", "C", true, "a boolean defaulting to true") + fs.String("D", "", "set relative `path` for local imports") + fs.Float64("F", 2.7, "a non-zero `number`") + fs.Float64("G", 0, "a float that defaults to zero") + fs.Int("N", 27, "a non-zero int") + fs.IntSlice("Ints", []int{}, "int slice with zero default") + fs.IP("IP", nil, "IP address with no default") + fs.IPMask("IPMask", nil, "Netmask address with no default") + fs.IPNet("IPNet", net.IPNet{}, "IP network with no default") + fs.Int("Z", 0, "an int that defaults to zero") + fs.Duration("maxT", 0, "set `timeout` for dial") + fs.String("ND1", "foo", "a string with NoOptDefVal") + fs.Lookup("ND1").NoOptDefVal = "bar" + fs.Int("ND2", 1234, "a `num` with NoOptDefVal") + fs.Lookup("ND2").NoOptDefVal = "4321" + fs.IntP("EEE", "E", 4321, "a `num` with NoOptDefVal") + fs.ShorthandLookup("E").NoOptDefVal = "1234" + fs.StringSlice("StringSlice", []string{}, "string slice with zero default") + fs.StringArray("StringArray", []string{}, "string array with zero default") + fs.CountP("verbose", "v", "verbosity") + + var cv customValue + fs.Var(&cv, "custom", "custom Value implementation") + + cv2 := customValue(10) + fs.VarP(&cv2, "customP", "", "a VarP with default") + + fs.PrintDefaults() + got := buf.String() + if got != defaultOutputWithZeroValue { + fmt.Println("\n" + got) + fmt.Println("\n" + defaultOutputWithZeroValue) + t.Errorf("got %q want %q\n", got, defaultOutputWithZeroValue) + } +} + func TestVisitAllFlagOrder(t *testing.T) { fs := NewFlagSet("TestVisitAllFlagOrder", ContinueOnError) fs.SortFlags = false