Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions bool.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ type boolFlag interface {
IsBoolFlag() bool
}

func isNoOptBoolValue(v Value) bool {
if bf, ok := v.(boolFlag); ok {
return bf.IsBoolFlag()
}
return false
}

// -- bool Value
type boolValue bool

Expand Down
28 changes: 28 additions & 0 deletions bool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,34 @@ func TestImplicitFalse(t *testing.T) {
}
}

func TestCustomIsBoolFlagGetsNoOptDefaultAutomatically(t *testing.T) {
var tristate triStateValue
f := NewFlagSet("test", ContinueOnError)
tristate = triStateFalse
f.VarPF(&tristate, "tristate", "t", "tristate value (true, maybe or false)")

if err := f.Parse([]string{"--tristate"}); err != nil {
t.Fatal("expected no error; got", err)
}
if tristate != triStateTrue {
t.Fatal("expected", triStateTrue, "(triStateTrue) but got", tristate, "instead")
}
}

func TestCustomIsBoolFlagShortFormGetsNoOptDefaultAutomatically(t *testing.T) {
var tristate triStateValue
f := NewFlagSet("test", ContinueOnError)
tristate = triStateFalse
f.VarPF(&tristate, "tristate", "t", "tristate value (true, maybe or false)")

if err := f.Parse([]string{"-t"}); err != nil {
t.Fatal("expected no error; got", err)
}
if tristate != triStateTrue {
t.Fatal("expected", triStateTrue, "(triStateTrue) but got", tristate, "instead")
}
}

func TestInvalidValue(t *testing.T) {
var tristate triStateValue
f := setUpFlagSet(&tristate)
Expand Down
13 changes: 10 additions & 3 deletions flag.go
Original file line number Diff line number Diff line change
Expand Up @@ -614,9 +614,10 @@ func (f *FlagSet) PrintDefaults() {
// 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:
if isNoOptBoolValue(f.Value) {
return f.DefValue == "false" || f.DefValue == ""
}
switch f.Value.(type) {
case *durationValue:
// Beginning in Go 1.7, duration zero values are "0s"
return f.DefValue == "0" || f.DefValue == "0s"
Expand Down Expand Up @@ -665,6 +666,9 @@ func UnquoteUsage(flag *Flag) (name string, usage string) {
}

name = flag.Value.Type()
if isNoOptBoolValue(flag.Value) {
name = ""
}
switch name {
case "bool", "boolfunc":
name = ""
Expand Down Expand Up @@ -779,7 +783,7 @@ func (f *FlagSet) FlagUsagesWrapped(cols int) string {
}

varname, usage := UnquoteUsage(flag)
if flag.Value.Type() == "bool" {
if isNoOptBoolValue(flag.Value) && flag.Value.Type() == "bool" {
line += "[=true|false]"
} else if varname != "" {
line += " " + varname
Expand Down Expand Up @@ -941,6 +945,9 @@ func (f *FlagSet) AddFlag(flag *Flag) {
}

flag.Name = string(normalizedFlagName)
if flag.NoOptDefVal == "" && isNoOptBoolValue(flag.Value) {
flag.NoOptDefVal = "true"
}
f.formal[normalizedFlagName] = flag
f.orderedFormal = append(f.orderedFormal, flag)

Expand Down
44 changes: 44 additions & 0 deletions flag_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1481,6 +1481,20 @@ func (cv *customValue) Set(s string) error {

func (cv *customValue) Type() string { return "custom" }

type customBoolFlagValue bool

func (cv *customBoolFlagValue) String() string { return strconv.FormatBool(bool(*cv)) }

func (cv *customBoolFlagValue) Set(s string) error {
v, err := strconv.ParseBool(s)
*cv = customBoolFlagValue(v)
return err
}

func (cv *customBoolFlagValue) Type() string { return "custom-bool" }

func (cv *customBoolFlagValue) IsBoolFlag() bool { return true }

func TestPrintDefaults(t *testing.T) {
fs := NewFlagSet("print defaults test", ContinueOnError)
var buf bytes.Buffer
Expand Down Expand Up @@ -1529,6 +1543,36 @@ func TestPrintDefaults(t *testing.T) {
}
}

func TestCustomIsBoolFlagDefaultIsZeroValue(t *testing.T) {
var v customBoolFlagValue
flag := &Flag{
Name: "custom-bool",
Usage: "custom bool",
Value: &v,
DefValue: "",
}

if !flag.defaultIsZeroValue() {
t.Fatal("expected empty default for custom IsBoolFlag value to be treated as zero value")
}
}

func TestPrintDefaultsCustomIsBoolFlagOmitsDefault(t *testing.T) {
fs := NewFlagSet("print defaults custom bool", ContinueOnError)
var buf bytes.Buffer
fs.SetOutput(&buf)

var v customBoolFlagValue
fs.Var(&v, "custom-bool", "custom bool value implementation")

fs.PrintDefaults()
got := buf.String()
want := " --custom-bool[=true] custom bool value implementation\n"
if got != want {
t.Errorf("\n--- Got:\n%s--- Wanted:\n%s\n", got, want)
}
}

func TestVisitAllFlagOrder(t *testing.T) {
fs := NewFlagSet("TestVisitAllFlagOrder", ContinueOnError)
fs.SortFlags = false
Expand Down
Loading