diff options
| -rw-r--r-- | flag.go | 32 | ||||
| -rw-r--r-- | flag_test.go | 51 |
2 files changed, 59 insertions, 24 deletions
@@ -419,20 +419,26 @@ func (f *FlagSet) PrintDefaults() { fmt.Fprintf(f.out(), "%s", usages) } -// isZeroValue guesses whether the string represents the zero -// value for a flag. It is not accurate but in practice works OK. -func isZeroValue(value string) bool { - switch value { - case "false": - return true - case "<nil>": - return true - case "": - return true - case "0": +// defaultIsZeroValue returns true if the default value for this flag represents +// a zero value. +func (f *Flag) defaultIsZeroValue() bool { + switch f.Value.(type) { + case boolFlag: + return f.DefValue == "false" + case *durationValue: + // Beginning in Go 1.7, duration zero values are "0s" + return f.DefValue == "0" || f.DefValue == "0s" + case *intValue, *int8Value, *int32Value, *int64Value, *uintValue, *uint8Value, *uint16Value, *uint32Value, *uint64Value, *countValue, *float32Value, *float64Value: + return f.DefValue == "0" + case *stringValue: + return f.DefValue == "" + case *ipValue, *ipMaskValue, *ipNetValue: + return f.DefValue == "<nil>" + case *intSliceValue, *stringSliceValue: + return f.DefValue == "[]" + default: return true } - return false } // UnquoteUsage extracts a back-quoted name from the usage @@ -516,7 +522,7 @@ func (f *FlagSet) FlagUsages() string { } line += usage - if !isZeroValue(flag.DefValue) { + if !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 0ae2e4f..86b37e5 100644 --- a/flag_test.go +++ b/flag_test.go @@ -13,6 +13,7 @@ import ( "os" "reflect" "sort" + "strconv" "strings" "testing" "time" @@ -873,19 +874,38 @@ func TestHiddenFlagUsage(t *testing.T) { } } -const defaultOutput = ` --A for bootstrapping, allow 'any' type - --Alongflagname disable bounds checking - -C, --CCC a boolean defaulting to true (default true) - --D path set relative path for local imports - --F number a non-zero number (default 2.7) - --G float a float that defaults to zero - --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) - --Z int an int that defaults to zero - --maxT timeout set timeout for dial +const defaultOutput = ` --A for bootstrapping, allow 'any' type + --Alongflagname disable bounds checking + -C, --CCC a boolean defaulting to true (default true) + --D path set relative path for local imports + --F number a non-zero number (default 2.7) + --G float a float that defaults to zero + --IP ip IP address with no default + --IPMask ipMask Netmask address with no default + --IPNet ipNet IP network with no default + --Ints intSlice int slice with zero 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) + --Strings stringSlice string slice with zero default + --Z int an int that defaults to zero + --custom custom custom Value implementation + --maxT timeout set timeout for dial ` +// Custom value that satisfies the Value interface. +type customValue int + +func (cv *customValue) String() string { return fmt.Sprintf("%v", *cv) } + +func (cv *customValue) Set(s string) error { + v, err := strconv.ParseInt(s, 0, 64) + *cv = customValue(v) + return err +} + +func (cv *customValue) Type() string { return "custom" } + func TestPrintDefaults(t *testing.T) { fs := NewFlagSet("print defaults test", ContinueOnError) var buf bytes.Buffer @@ -897,12 +917,21 @@ func TestPrintDefaults(t *testing.T) { 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.StringSlice("Strings", []string{}, "string slice with zero default") + + var cv customValue + fs.Var(&cv, "custom", "custom Value implementation") + fs.PrintDefaults() got := buf.String() if got != defaultOutput { |
