You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
urfave-cli/flag_test.go

1445 lines
37 KiB

package cli
import (
"flag"
"fmt"
"os"
"reflect"
"runtime"
"strings"
"testing"
"time"
)
var boolFlagTests = []struct {
name string
expected string
}{
{"help", "--help\t(default: false)"},
{"h", "-h\t(default: false)"},
}
func TestBoolFlagHelpOutput(t *testing.T) {
for _, test := range boolFlagTests {
flag := &BoolFlag{Name: test.name}
output := flag.String()
if output != test.expected {
t.Errorf("%q does not match %q", output, test.expected)
}
}
}
func TestBoolFlagApply_SetsAllNames(t *testing.T) {
v := false
fl := BoolFlag{Name: "wat", Aliases: []string{"W", "huh"}, Destination: &v}
set := flag.NewFlagSet("test", 0)
fl.Apply(set)
err := set.Parse([]string{"--wat", "-W", "--huh"})
expect(t, err, nil)
expect(t, v, true)
}
var stringFlagTests = []struct {
name string
aliases []string
usage string
value string
expected string
}{
{"foo", nil, "", "", "--foo value\t"},
{"f", nil, "", "", "-f value\t"},
{"f", nil, "The total `foo` desired", "all", "-f foo\tThe total foo desired (default: \"all\")"},
{"test", nil, "", "Something", "--test value\t(default: \"Something\")"},
{"config", []string{"c"}, "Load configuration from `FILE`", "", "--config FILE, -c FILE\tLoad configuration from FILE"},
{"config", []string{"c"}, "Load configuration from `CONFIG`", "config.json", "--config CONFIG, -c CONFIG\tLoad configuration from CONFIG (default: \"config.json\")"},
}
func TestStringFlagHelpOutput(t *testing.T) {
for _, test := range stringFlagTests {
flag := &StringFlag{Name: test.name, Aliases: test.aliases, Usage: test.usage, Value: test.value}
output := flag.String()
if output != test.expected {
t.Errorf("%q does not match %q", output, test.expected)
}
}
}
func TestStringFlagDefaultText(t *testing.T) {
flag := &StringFlag{Name: "foo", Aliases: nil, Usage: "amount of `foo` requested", Value: "none", DefaultText: "all of it"}
expected := "--foo foo\tamount of foo requested (default: all of it)"
output := flag.String()
if output != expected {
t.Errorf("%q does not match %q", output, expected)
}
}
func TestStringFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_FOO", "derp")
for _, test := range stringFlagTests {
flag := &StringFlag{Name: test.name, Aliases: test.aliases, Value: test.value, EnvVars: []string{"APP_FOO"}}
output := flag.String()
expectedSuffix := " [$APP_FOO]"
if runtime.GOOS == "windows" {
expectedSuffix = " [%APP_FOO%]"
}
if !strings.HasSuffix(output, expectedSuffix) {
t.Errorf("%s does not end with"+expectedSuffix, output)
}
}
}
func TestStringFlagApply_SetsAllNames(t *testing.T) {
v := "mmm"
fl := StringFlag{Name: "hay", Aliases: []string{"H", "hayyy"}, Destination: &v}
set := flag.NewFlagSet("test", 0)
fl.Apply(set)
err := set.Parse([]string{"--hay", "u", "-H", "yuu", "--hayyy", "YUUUU"})
expect(t, err, nil)
expect(t, v, "YUUUU")
}
var stringSliceFlagTests = []struct {
name string
aliases []string
value *StringSlice
expected string
}{
{"foo", nil, NewStringSlice(""), "--foo value\t"},
{"f", nil, NewStringSlice(""), "-f value\t"},
{"f", nil, NewStringSlice("Lipstick"), "-f value\t(default: \"Lipstick\")"},
{"test", nil, NewStringSlice("Something"), "--test value\t(default: \"Something\")"},
{"dee", []string{"d"}, NewStringSlice("Inka", "Dinka", "dooo"), "--dee value, -d value\t(default: \"Inka\", \"Dinka\", \"dooo\")"},
}
func TestStringSliceFlagHelpOutput(t *testing.T) {
for _, test := range stringSliceFlagTests {
flag := &StringSliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value}
output := flag.String()
if output != test.expected {
t.Errorf("%q does not match %q", output, test.expected)
}
}
}
func TestStringSliceFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_QWWX", "11,4")
for _, test := range stringSliceFlagTests {
flag := &StringSliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value, EnvVars: []string{"APP_QWWX"}}
output := flag.String()
expectedSuffix := " [$APP_QWWX]"
if runtime.GOOS == "windows" {
expectedSuffix = " [%APP_QWWX%]"
}
if !strings.HasSuffix(output, expectedSuffix) {
t.Errorf("%q does not end with"+expectedSuffix, output)
}
}
}
func TestStringSliceFlagApply_SetsAllNames(t *testing.T) {
fl := StringSliceFlag{Name: "goat", Aliases: []string{"G", "gooots"}}
set := flag.NewFlagSet("test", 0)
fl.Apply(set)
err := set.Parse([]string{"--goat", "aaa", "-G", "bbb", "--gooots", "eeeee"})
expect(t, err, nil)
}
var intFlagTests = []struct {
name string
expected string
}{
{"hats", "--hats value\t(default: 9)"},
{"H", "-H value\t(default: 9)"},
}
func TestIntFlagHelpOutput(t *testing.T) {
for _, test := range intFlagTests {
flag := &IntFlag{Name: test.name, Value: 9}
output := flag.String()
if output != test.expected {
t.Errorf("%s does not match %s", output, test.expected)
}
}
}
func TestIntFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_BAR", "2")
for _, test := range intFlagTests {
flag := &IntFlag{Name: test.name, EnvVars: []string{"APP_BAR"}}
output := flag.String()
expectedSuffix := " [$APP_BAR]"
if runtime.GOOS == "windows" {
expectedSuffix = " [%APP_BAR%]"
}
if !strings.HasSuffix(output, expectedSuffix) {
t.Errorf("%s does not end with"+expectedSuffix, output)
}
}
}
func TestIntFlagApply_SetsAllNames(t *testing.T) {
v := 3
fl := IntFlag{Name: "banana", Aliases: []string{"B", "banannanana"}, Destination: &v}
set := flag.NewFlagSet("test", 0)
fl.Apply(set)
err := set.Parse([]string{"--banana", "1", "-B", "2", "--banannanana", "5"})
expect(t, err, nil)
expect(t, v, 5)
}
var int64FlagTests = []struct {
name string
expected string
}{
{"hats", "--hats value\t(default: 8589934592)"},
{"H", "-H value\t(default: 8589934592)"},
}
func TestInt64FlagHelpOutput(t *testing.T) {
for _, test := range int64FlagTests {
flag := Int64Flag{Name: test.name, Value: 8589934592}
output := flag.String()
if output != test.expected {
t.Errorf("%s does not match %s", output, test.expected)
}
}
}
func TestInt64FlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_BAR", "2")
for _, test := range int64FlagTests {
flag := IntFlag{Name: test.name, EnvVars: []string{"APP_BAR"}}
output := flag.String()
expectedSuffix := " [$APP_BAR]"
if runtime.GOOS == "windows" {
expectedSuffix = " [%APP_BAR%]"
}
if !strings.HasSuffix(output, expectedSuffix) {
t.Errorf("%s does not end with"+expectedSuffix, output)
}
}
}
var uintFlagTests = []struct {
name string
expected string
}{
{"nerfs", "--nerfs value\t(default: 41)"},
{"N", "-N value\t(default: 41)"},
}
func TestUintFlagHelpOutput(t *testing.T) {
for _, test := range uintFlagTests {
flag := UintFlag{Name: test.name, Value: 41}
output := flag.String()
if output != test.expected {
t.Errorf("%s does not match %s", output, test.expected)
}
}
}
func TestUintFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_BAR", "2")
for _, test := range uintFlagTests {
flag := UintFlag{Name: test.name, EnvVars: []string{"APP_BAR"}}
output := flag.String()
expectedSuffix := " [$APP_BAR]"
if runtime.GOOS == "windows" {
expectedSuffix = " [%APP_BAR%]"
}
if !strings.HasSuffix(output, expectedSuffix) {
t.Errorf("%s does not end with"+expectedSuffix, output)
}
}
}
var uint64FlagTests = []struct {
name string
expected string
}{
{"gerfs", "--gerfs value\t(default: 8589934582)"},
{"G", "-G value\t(default: 8589934582)"},
}
func TestUint64FlagHelpOutput(t *testing.T) {
for _, test := range uint64FlagTests {
flag := Uint64Flag{Name: test.name, Value: 8589934582}
output := flag.String()
if output != test.expected {
t.Errorf("%s does not match %s", output, test.expected)
}
}
}
func TestUint64FlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_BAR", "2")
for _, test := range uint64FlagTests {
flag := UintFlag{Name: test.name, EnvVars: []string{"APP_BAR"}}
output := flag.String()
expectedSuffix := " [$APP_BAR]"
if runtime.GOOS == "windows" {
expectedSuffix = " [%APP_BAR%]"
}
if !strings.HasSuffix(output, expectedSuffix) {
t.Errorf("%s does not end with"+expectedSuffix, output)
}
}
}
var durationFlagTests = []struct {
name string
expected string
}{
{"hooting", "--hooting value\t(default: 1s)"},
{"H", "-H value\t(default: 1s)"},
}
func TestDurationFlagHelpOutput(t *testing.T) {
for _, test := range durationFlagTests {
flag := &DurationFlag{Name: test.name, Value: 1 * time.Second}
output := flag.String()
if output != test.expected {
t.Errorf("%q does not match %q", output, test.expected)
}
}
}
func TestDurationFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_BAR", "2h3m6s")
for _, test := range durationFlagTests {
flag := &DurationFlag{Name: test.name, EnvVars: []string{"APP_BAR"}}
output := flag.String()
expectedSuffix := " [$APP_BAR]"
if runtime.GOOS == "windows" {
expectedSuffix = " [%APP_BAR%]"
}
if !strings.HasSuffix(output, expectedSuffix) {
t.Errorf("%s does not end with"+expectedSuffix, output)
}
}
}
func TestDurationFlagApply_SetsAllNames(t *testing.T) {
v := time.Second * 20
fl := DurationFlag{Name: "howmuch", Aliases: []string{"H", "whyyy"}, Destination: &v}
set := flag.NewFlagSet("test", 0)
fl.Apply(set)
err := set.Parse([]string{"--howmuch", "30s", "-H", "5m", "--whyyy", "30h"})
expect(t, err, nil)
expect(t, v, time.Hour*30)
}
var intSliceFlagTests = []struct {
name string
aliases []string
value *IntSlice
expected string
}{
{"heads", nil, NewIntSlice(), "--heads value\t"},
{"H", nil, NewIntSlice(), "-H value\t"},
{"H", []string{"heads"}, NewIntSlice(9, 3), "-H value, --heads value\t(default: 9, 3)"},
}
func TestIntSliceFlagHelpOutput(t *testing.T) {
for _, test := range intSliceFlagTests {
flag := &IntSliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value}
output := flag.String()
if output != test.expected {
t.Errorf("%q does not match %q", output, test.expected)
}
}
}
func TestIntSliceFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_SMURF", "42,3")
for _, test := range intSliceFlagTests {
flag := &IntSliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value, EnvVars: []string{"APP_SMURF"}}
output := flag.String()
expectedSuffix := " [$APP_SMURF]"
if runtime.GOOS == "windows" {
expectedSuffix = " [%APP_SMURF%]"
}
if !strings.HasSuffix(output, expectedSuffix) {
t.Errorf("%q does not end with"+expectedSuffix, output)
}
}
}
func TestIntSliceFlagApply_SetsAllNames(t *testing.T) {
fl := IntSliceFlag{Name: "bits", Aliases: []string{"B", "bips"}}
set := flag.NewFlagSet("test", 0)
fl.Apply(set)
err := set.Parse([]string{"--bits", "23", "-B", "3", "--bips", "99"})
expect(t, err, nil)
}
var int64SliceFlagTests = []struct {
name string
aliases []string
value *Int64Slice
expected string
}{
{"heads", nil, NewInt64Slice(), "--heads value\t"},
{"H", nil, NewInt64Slice(), "-H value\t"},
{"heads", []string{"H"}, NewInt64Slice(int64(2), int64(17179869184)),
"--heads value, -H value\t(default: 2, 17179869184)"},
}
func TestInt64SliceFlagHelpOutput(t *testing.T) {
for _, test := range int64SliceFlagTests {
flag := Int64SliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value}
output := flag.String()
if output != test.expected {
t.Errorf("%q does not match %q", output, test.expected)
}
}
}
func TestInt64SliceFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_SMURF", "42,17179869184")
for _, test := range int64SliceFlagTests {
flag := Int64SliceFlag{Name: test.name, Value: test.value, EnvVars: []string{"APP_SMURF"}}
output := flag.String()
expectedSuffix := " [$APP_SMURF]"
if runtime.GOOS == "windows" {
expectedSuffix = " [%APP_SMURF%]"
}
if !strings.HasSuffix(output, expectedSuffix) {
t.Errorf("%q does not end with"+expectedSuffix, output)
}
}
}
var float64FlagTests = []struct {
name string
expected string
}{
{"hooting", "--hooting value\t(default: 0.1)"},
{"H", "-H value\t(default: 0.1)"},
}
func TestFloat64FlagHelpOutput(t *testing.T) {
for _, test := range float64FlagTests {
flag := &Float64Flag{Name: test.name, Value: float64(0.1)}
output := flag.String()
if output != test.expected {
t.Errorf("%q does not match %q", output, test.expected)
}
}
}
func TestFloat64FlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_BAZ", "99.4")
for _, test := range float64FlagTests {
flag := &Float64Flag{Name: test.name, EnvVars: []string{"APP_BAZ"}}
output := flag.String()
expectedSuffix := " [$APP_BAZ]"
if runtime.GOOS == "windows" {
expectedSuffix = " [%APP_BAZ%]"
}
if !strings.HasSuffix(output, expectedSuffix) {
t.Errorf("%s does not end with"+expectedSuffix, output)
}
}
}
func TestFloat64FlagApply_SetsAllNames(t *testing.T) {
v := float64(99.1)
fl := Float64Flag{Name: "noodles", Aliases: []string{"N", "nurbles"}, Destination: &v}
set := flag.NewFlagSet("test", 0)
fl.Apply(set)
err := set.Parse([]string{"--noodles", "1.3", "-N", "11", "--nurbles", "43.33333"})
expect(t, err, nil)
expect(t, v, float64(43.33333))
}
var float64SliceFlagTests = []struct {
name string
aliases []string
value *Float64Slice
expected string
}{
{"heads", nil, NewFloat64Slice(), "--heads value\t"},
{"H", nil, NewFloat64Slice(), "-H value\t"},
{"heads", []string{"H"}, NewFloat64Slice(float64(0.1234), float64(-10.5)),
"--heads value, -H value\t(default: 0.1234, -10.5)"},
}
func TestFloat64SliceFlagHelpOutput(t *testing.T) {
for _, test := range float64SliceFlagTests {
flag := Float64SliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value}
output := flag.String()
if output != test.expected {
t.Errorf("%q does not match %q", output, test.expected)
}
}
}
func TestFloat64SliceFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_SMURF", "0.1234,-10.5")
for _, test := range float64SliceFlagTests {
flag := Float64SliceFlag{Name: test.name, Value: test.value, EnvVars: []string{"APP_SMURF"}}
output := flag.String()
expectedSuffix := " [$APP_SMURF]"
if runtime.GOOS == "windows" {
expectedSuffix = " [%APP_SMURF%]"
}
if !strings.HasSuffix(output, expectedSuffix) {
t.Errorf("%q does not end with"+expectedSuffix, output)
}
}
}
var genericFlagTests = []struct {
name string
value Generic
expected string
}{
{"toads", &Parser{"abc", "def"}, "--toads value\ttest flag (default: abc,def)"},
{"t", &Parser{"abc", "def"}, "-t value\ttest flag (default: abc,def)"},
}
func TestGenericFlagHelpOutput(t *testing.T) {
for _, test := range genericFlagTests {
flag := &GenericFlag{Name: test.name, Value: test.value, Usage: "test flag"}
output := flag.String()
if output != test.expected {
t.Errorf("%q does not match %q", output, test.expected)
}
}
}
func TestGenericFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_ZAP", "3")
for _, test := range genericFlagTests {
flag := &GenericFlag{Name: test.name, EnvVars: []string{"APP_ZAP"}}
output := flag.String()
expectedSuffix := " [$APP_ZAP]"
if runtime.GOOS == "windows" {
expectedSuffix = " [%APP_ZAP%]"
}
if !strings.HasSuffix(output, expectedSuffix) {
t.Errorf("%s does not end with"+expectedSuffix, output)
}
}
}
func TestGenericFlagApply_SetsAllNames(t *testing.T) {
fl := GenericFlag{Name: "orbs", Aliases: []string{"O", "obrs"}, Value: &Parser{}}
set := flag.NewFlagSet("test", 0)
fl.Apply(set)
err := set.Parse([]string{"--orbs", "eleventy,3", "-O", "4,bloop", "--obrs", "19,s"})
expect(t, err, nil)
}
func TestParseMultiString(t *testing.T) {
(&App{
Flags: []Flag{
&StringFlag{Name: "serve", Aliases: []string{"s"}},
},
Action: func(ctx *Context) error {
if ctx.String("serve") != "10" {
t.Errorf("main name not set")
}
if ctx.String("s") != "10" {
t.Errorf("short name not set")
}
return nil
},
}).Run([]string{"run", "-s", "10"})
}
func TestParseDestinationString(t *testing.T) {
var dest string
a := App{
Flags: []Flag{
&StringFlag{
Name: "dest",
Destination: &dest,
},
},
Action: func(ctx *Context) error {
if dest != "10" {
t.Errorf("expected destination String 10")
}
return nil
},
}
a.Run([]string{"run", "--dest", "10"})
}
func TestParseMultiStringFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_COUNT", "20")
(&App{
Flags: []Flag{
&StringFlag{Name: "count", Aliases: []string{"c"}, EnvVars: []string{"APP_COUNT"}},
},
Action: func(ctx *Context) error {
if ctx.String("count") != "20" {
t.Errorf("main name not set")
}
if ctx.String("c") != "20" {
t.Errorf("short name not set")
}
return nil
},
}).Run([]string{"run"})
}
func TestParseMultiStringFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_COUNT", "20")
(&App{
Flags: []Flag{
&StringFlag{Name: "count", Aliases: []string{"c"}, EnvVars: []string{"COMPAT_COUNT", "APP_COUNT"}},
},
Action: func(ctx *Context) error {
if ctx.String("count") != "20" {
t.Errorf("main name not set")
}
if ctx.String("c") != "20" {
t.Errorf("short name not set")
}
return nil
},
}).Run([]string{"run"})
}
func TestParseMultiStringSlice(t *testing.T) {
(&App{
Flags: []Flag{
&StringSliceFlag{Name: "serve", Aliases: []string{"s"}, Value: NewStringSlice()},
},
Action: func(ctx *Context) error {
expected := []string{"10", "20"}
if !reflect.DeepEqual(ctx.StringSlice("serve"), expected) {
t.Errorf("main name not set: %v != %v", expected, ctx.StringSlice("serve"))
}
if !reflect.DeepEqual(ctx.StringSlice("s"), expected) {
t.Errorf("short name not set: %v != %v", expected, ctx.StringSlice("s"))
}
return nil
},
}).Run([]string{"run", "-s", "10", "-s", "20"})
}
func TestParseMultiStringSliceWithDefaults(t *testing.T) {
(&App{
Flags: []Flag{
&StringSliceFlag{Name: "serve", Aliases: []string{"s"}, Value: NewStringSlice("9", "2")},
},
Action: func(ctx *Context) error {
expected := []string{"10", "20"}
if !reflect.DeepEqual(ctx.StringSlice("serve"), expected) {
t.Errorf("main name not set: %v != %v", expected, ctx.StringSlice("serve"))
}
if !reflect.DeepEqual(ctx.StringSlice("s"), expected) {
t.Errorf("short name not set: %v != %v", expected, ctx.StringSlice("s"))
}
return nil
},
}).Run([]string{"run", "-s", "10", "-s", "20"})
}
func TestParseMultiStringSliceWithDefaultsUnset(t *testing.T) {
(&App{
Flags: []Flag{
&StringSliceFlag{Name: "serve", Aliases: []string{"s"}, Value: NewStringSlice("9", "2")},
},
Action: func(ctx *Context) error {
if !reflect.DeepEqual(ctx.StringSlice("serve"), []string{"9", "2"}) {
t.Errorf("main name not set: %v", ctx.StringSlice("serve"))
}
if !reflect.DeepEqual(ctx.StringSlice("s"), []string{"9", "2"}) {
t.Errorf("short name not set: %v", ctx.StringSlice("s"))
}
return nil
},
}).Run([]string{"run"})
}
func TestParseMultiStringSliceFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_INTERVALS", "20,30,40")
(&App{
Flags: []Flag{
&StringSliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewStringSlice(), EnvVars: []string{"APP_INTERVALS"}},
},
Action: func(ctx *Context) error {
if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
t.Errorf("main name not set from env")
}
if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) {
t.Errorf("short name not set from env")
}
return nil
},
}).Run([]string{"run"})
}
func TestParseMultiStringSliceFromEnvWithDefaults(t *testing.T) {
os.Clearenv()
os.Setenv("APP_INTERVALS", "20,30,40")
(&App{
Flags: []Flag{
&StringSliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewStringSlice("1", "2", "5"), EnvVars: []string{"APP_INTERVALS"}},
},
Action: func(ctx *Context) error {
if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
t.Errorf("main name not set from env")
}
if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) {
t.Errorf("short name not set from env")
}
return nil
},
}).Run([]string{"run"})
}
func TestParseMultiStringSliceFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_INTERVALS", "20,30,40")
(&App{
Flags: []Flag{
&StringSliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewStringSlice(), EnvVars: []string{"COMPAT_INTERVALS", "APP_INTERVALS"}},
},
Action: func(ctx *Context) error {
if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
t.Errorf("main name not set from env")
}
if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) {
t.Errorf("short name not set from env")
}
return nil
},
}).Run([]string{"run"})
}
func TestParseMultiStringSliceFromEnvCascadeWithDefaults(t *testing.T) {
os.Clearenv()
os.Setenv("APP_INTERVALS", "20,30,40")
(&App{
Flags: []Flag{
&StringSliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewStringSlice("1", "2", "5"), EnvVars: []string{"COMPAT_INTERVALS", "APP_INTERVALS"}},
},
Action: func(ctx *Context) error {
if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
t.Errorf("main name not set from env")
}
if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) {
t.Errorf("short name not set from env")
}
return nil
},
}).Run([]string{"run"})
}
func TestParseMultiInt(t *testing.T) {
a := App{
Flags: []Flag{
&IntFlag{Name: "serve", Aliases: []string{"s"}},
},
Action: func(ctx *Context) error {
if ctx.Int("serve") != 10 {
t.Errorf("main name not set")
}
if ctx.Int("s") != 10 {
t.Errorf("short name not set")
}
return nil
},
}
a.Run([]string{"run", "-s", "10"})
}
func TestParseDestinationInt(t *testing.T) {
var dest int
a := App{
Flags: []Flag{
&IntFlag{
Name: "dest",
Destination: &dest,
},
},
Action: func(ctx *Context) error {
if dest != 10 {
t.Errorf("expected destination Int 10")
}
return nil
},
}
a.Run([]string{"run", "--dest", "10"})
}
func TestParseMultiIntFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_TIMEOUT_SECONDS", "10")
a := App{
Flags: []Flag{
&IntFlag{Name: "timeout", Aliases: []string{"t"}, EnvVars: []string{"APP_TIMEOUT_SECONDS"}},
},
Action: func(ctx *Context) error {
if ctx.Int("timeout") != 10 {
t.Errorf("main name not set")
}
if ctx.Int("t") != 10 {
t.Errorf("short name not set")
}
return nil
},
}
a.Run([]string{"run"})
}
func TestParseMultiIntFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_TIMEOUT_SECONDS", "10")
a := App{
Flags: []Flag{
&IntFlag{Name: "timeout", Aliases: []string{"t"}, EnvVars: []string{"COMPAT_TIMEOUT_SECONDS", "APP_TIMEOUT_SECONDS"}},
},
Action: func(ctx *Context) error {
if ctx.Int("timeout") != 10 {
t.Errorf("main name not set")
}
if ctx.Int("t") != 10 {
t.Errorf("short name not set")
}
return nil
},
}
a.Run([]string{"run"})
}
func TestParseMultiIntSlice(t *testing.T) {
(&App{
Flags: []Flag{
&IntSliceFlag{Name: "serve", Aliases: []string{"s"}, Value: NewIntSlice()},
},
Action: func(ctx *Context) error {
if !reflect.DeepEqual(ctx.IntSlice("serve"), []int{10, 20}) {
t.Errorf("main name not set")
}
if !reflect.DeepEqual(ctx.IntSlice("s"), []int{10, 20}) {
t.Errorf("short name not set")
}
return nil
},
}).Run([]string{"run", "-s", "10", "-s", "20"})
}
func TestParseMultiIntSliceWithDefaults(t *testing.T) {
(&App{
Flags: []Flag{
&IntSliceFlag{Name: "serve", Aliases: []string{"s"}, Value: NewIntSlice(9, 2)},
},
Action: func(ctx *Context) error {
if !reflect.DeepEqual(ctx.IntSlice("serve"), []int{10, 20}) {
t.Errorf("main name not set")
}
if !reflect.DeepEqual(ctx.IntSlice("s"), []int{10, 20}) {
t.Errorf("short name not set")
}
return nil
},
}).Run([]string{"run", "-s", "10", "-s", "20"})
}
func TestParseMultiIntSliceWithDefaultsUnset(t *testing.T) {
(&App{
Flags: []Flag{
&IntSliceFlag{Name: "serve", Aliases: []string{"s"}, Value: NewIntSlice(9, 2)},
},
Action: func(ctx *Context) error {
if !reflect.DeepEqual(ctx.IntSlice("serve"), []int{9, 2}) {
t.Errorf("main name not set")
}
if !reflect.DeepEqual(ctx.IntSlice("s"), []int{9, 2}) {
t.Errorf("short name not set")
}
return nil
},
}).Run([]string{"run"})
}
func TestParseMultiIntSliceFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_INTERVALS", "20,30,40")
(&App{
Flags: []Flag{
&IntSliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewIntSlice(), EnvVars: []string{"APP_INTERVALS"}},
},
Action: func(ctx *Context) error {
if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) {
t.Errorf("main name not set from env")
}
if !reflect.DeepEqual(ctx.IntSlice("i"), []int{20, 30, 40}) {
t.Errorf("short name not set from env")
}
return nil
},
}).Run([]string{"run"})
}
func TestParseMultiIntSliceFromEnvWithDefaults(t *testing.T) {
os.Clearenv()
os.Setenv("APP_INTERVALS", "20,30,40")
(&App{
Flags: []Flag{
&IntSliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewIntSlice(1, 2, 5), EnvVars: []string{"APP_INTERVALS"}},
},
Action: func(ctx *Context) error {
if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) {
t.Errorf("main name not set from env")
}
if !reflect.DeepEqual(ctx.IntSlice("i"), []int{20, 30, 40}) {
t.Errorf("short name not set from env")
}
return nil
},
}).Run([]string{"run"})
}
func TestParseMultiIntSliceFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_INTERVALS", "20,30,40")
(&App{
Flags: []Flag{
&IntSliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewIntSlice(), EnvVars: []string{"COMPAT_INTERVALS", "APP_INTERVALS"}},
},
Action: func(ctx *Context) error {
if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) {
t.Errorf("main name not set from env")
}
if !reflect.DeepEqual(ctx.IntSlice("i"), []int{20, 30, 40}) {
t.Errorf("short name not set from env")
}
return nil
},
}).Run([]string{"run"})
}
func TestParseMultiInt64Slice(t *testing.T) {
(&App{
Flags: []Flag{
&Int64SliceFlag{Name: "serve", Aliases: []string{"s"}, Value: NewInt64Slice()},
},
Action: func(ctx *Context) error {
if !reflect.DeepEqual(ctx.Int64Slice("serve"), []int64{10, 17179869184}) {
t.Errorf("main name not set")
}
if !reflect.DeepEqual(ctx.Int64Slice("s"), []int64{10, 17179869184}) {
t.Errorf("short name not set")
}
return nil
},
}).Run([]string{"run", "-s", "10", "-s", "17179869184"})
}
func TestParseMultiInt64SliceFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_INTERVALS", "20,30,17179869184")
(&App{
Flags: []Flag{
&Int64SliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewInt64Slice(), EnvVars: []string{"APP_INTERVALS"}},
},
Action: func(ctx *Context) error {
if !reflect.DeepEqual(ctx.Int64Slice("intervals"), []int64{20, 30, 17179869184}) {
t.Errorf("main name not set from env")
}
if !reflect.DeepEqual(ctx.Int64Slice("i"), []int64{20, 30, 17179869184}) {
t.Errorf("short name not set from env")
}
return nil
},
}).Run([]string{"run"})
}
func TestParseMultiInt64SliceFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_INTERVALS", "20,30,17179869184")
(&App{
Flags: []Flag{
&Int64SliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewInt64Slice(), EnvVars: []string{"COMPAT_INTERVALS", "APP_INTERVALS"}},
},
Action: func(ctx *Context) error {
if !reflect.DeepEqual(ctx.Int64Slice("intervals"), []int64{20, 30, 17179869184}) {
t.Errorf("main name not set from env")
}
if !reflect.DeepEqual(ctx.Int64Slice("i"), []int64{20, 30, 17179869184}) {
t.Errorf("short name not set from env")
}
return nil
},
}).Run([]string{"run"})
}
func TestParseMultiFloat64(t *testing.T) {
a := App{
Flags: []Flag{
&Float64Flag{Name: "serve", Aliases: []string{"s"}},
},
Action: func(ctx *Context) error {
if ctx.Float64("serve") != 10.2 {
t.Errorf("main name not set")
}
if ctx.Float64("s") != 10.2 {
t.Errorf("short name not set")
}
return nil
},
}
a.Run([]string{"run", "-s", "10.2"})
}
func TestParseDestinationFloat64(t *testing.T) {
var dest float64
a := App{
Flags: []Flag{
&Float64Flag{
Name: "dest",
Destination: &dest,
},
},
Action: func(ctx *Context) error {
if dest != 10.2 {
t.Errorf("expected destination Float64 10.2")
}
return nil
},
}
a.Run([]string{"run", "--dest", "10.2"})
}
func TestParseMultiFloat64FromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
a := App{
Flags: []Flag{
&Float64Flag{Name: "timeout", Aliases: []string{"t"}, EnvVars: []string{"APP_TIMEOUT_SECONDS"}},
},
Action: func(ctx *Context) error {
if ctx.Float64("timeout") != 15.5 {
t.Errorf("main name not set")
}
if ctx.Float64("t") != 15.5 {
t.Errorf("short name not set")
}
return nil
},
}
a.Run([]string{"run"})
}
func TestParseMultiFloat64FromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
a := App{
Flags: []Flag{
&Float64Flag{Name: "timeout", Aliases: []string{"t"}, EnvVars: []string{"COMPAT_TIMEOUT_SECONDS", "APP_TIMEOUT_SECONDS"}},
},
Action: func(ctx *Context) error {
if ctx.Float64("timeout") != 15.5 {
t.Errorf("main name not set")
}
if ctx.Float64("t") != 15.5 {
t.Errorf("short name not set")
}
return nil
},
}
a.Run([]string{"run"})
}
func TestParseMultiFloat64SliceFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_INTERVALS", "0.1,-10.5")
(&App{
Flags: []Flag{
&Float64SliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewFloat64Slice(), EnvVars: []string{"APP_INTERVALS"}},
},
Action: func(ctx *Context) error {
if !reflect.DeepEqual(ctx.Float64Slice("intervals"), []float64{0.1, -10.5}) {
t.Errorf("main name not set from env")
}
if !reflect.DeepEqual(ctx.Float64Slice("i"), []float64{0.1, -10.5}) {
t.Errorf("short name not set from env")
}
return nil
},
}).Run([]string{"run"})
}
func TestParseMultiFloat64SliceFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_INTERVALS", "0.1234,-10.5")
(&App{
Flags: []Flag{
&Float64SliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewFloat64Slice(), EnvVars: []string{"COMPAT_INTERVALS", "APP_INTERVALS"}},
},
Action: func(ctx *Context) error {
if !reflect.DeepEqual(ctx.Float64Slice("intervals"), []float64{0.1234, -10.5}) {
t.Errorf("main name not set from env")
}
if !reflect.DeepEqual(ctx.Float64Slice("i"), []float64{0.1234, -10.5}) {
t.Errorf("short name not set from env")
}
return nil
},
}).Run([]string{"run"})
}
func TestParseMultiBool(t *testing.T) {
a := App{
Flags: []Flag{
&BoolFlag{Name: "serve", Aliases: []string{"s"}},
},
Action: func(ctx *Context) error {
if ctx.Bool("serve") != true {
t.Errorf("main name not set")
}
if ctx.Bool("s") != true {
t.Errorf("short name not set")
}
return nil
},
}
a.Run([]string{"run", "--serve"})
}
func TestParseDestinationBool(t *testing.T) {
var dest bool
a := App{
Flags: []Flag{
&BoolFlag{
Name: "dest",
Destination: &dest,
},
},
Action: func(ctx *Context) error {
if dest != true {
t.Errorf("expected destination Bool true")
}
return nil
},
}
a.Run([]string{"run", "--dest"})
}
func TestParseMultiBoolFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_DEBUG", "1")
a := App{
Flags: []Flag{
&BoolFlag{Name: "debug", Aliases: []string{"d"}, EnvVars: []string{"APP_DEBUG"}},
},
Action: func(ctx *Context) error {
if ctx.Bool("debug") != true {
t.Errorf("main name not set from env")
}
if ctx.Bool("d") != true {
t.Errorf("short name not set from env")
}
return nil
},
}
a.Run([]string{"run"})
}
func TestParseMultiBoolFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_DEBUG", "1")
a := App{
Flags: []Flag{
&BoolFlag{Name: "debug", Aliases: []string{"d"}, EnvVars: []string{"COMPAT_DEBUG", "APP_DEBUG"}},
},
Action: func(ctx *Context) error {
if ctx.Bool("debug") != true {
t.Errorf("main name not set from env")
}
if ctx.Bool("d") != true {
t.Errorf("short name not set from env")
}
return nil
},
}
a.Run([]string{"run"})
}
func TestParseMultiBoolTrue(t *testing.T) {
a := App{
Flags: []Flag{
&BoolFlag{Name: "implode", Aliases: []string{"i"}, Value: true},
},
Action: func(ctx *Context) error {
if ctx.Bool("implode") {
t.Errorf("main name not set")
}
if ctx.Bool("i") {
t.Errorf("short name not set")
}
return nil
},
}
a.Run([]string{"run", "--implode=false"})
}
func TestParseDestinationBoolTrue(t *testing.T) {
dest := true
a := App{
Flags: []Flag{
&BoolFlag{
Name: "dest",
Value: true,
Destination: &dest,
},
},
Action: func(ctx *Context) error {
if dest {
t.Errorf("expected destination Bool false")
}
return nil
},
}
a.Run([]string{"run", "--dest=false"})
}
func TestParseMultiBoolTrueFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_DEBUG", "0")
a := App{
Flags: []Flag{
&BoolFlag{
Name: "debug",
Aliases: []string{"d"},
Value: true,
EnvVars: []string{"APP_DEBUG"},
},
},
Action: func(ctx *Context) error {
if ctx.Bool("debug") {
t.Errorf("main name not set from env")
}
if ctx.Bool("d") {
t.Errorf("short name not set from env")
}
return nil
},
}
a.Run([]string{"run"})
}
func TestParseMultiBoolTrueFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_DEBUG", "0")
a := App{
Flags: []Flag{
&BoolFlag{
Name: "debug",
Aliases: []string{"d"},
Value: true,
EnvVars: []string{"COMPAT_DEBUG", "APP_DEBUG"},
},
},
Action: func(ctx *Context) error {
if ctx.Bool("debug") {
t.Errorf("main name not set from env")
}
if ctx.Bool("d") {
t.Errorf("short name not set from env")
}
return nil
},
}
a.Run([]string{"run"})
}
type Parser [2]string
func (p *Parser) Set(value string) error {
parts := strings.Split(value, ",")
if len(parts) != 2 {
return fmt.Errorf("invalid format")
}
(*p)[0] = parts[0]
(*p)[1] = parts[1]
return nil
}
func (p *Parser) String() string {
return fmt.Sprintf("%s,%s", p[0], p[1])
}
func TestParseGeneric(t *testing.T) {
a := App{
Flags: []Flag{
&GenericFlag{Name: "serve", Aliases: []string{"s"}, Value: &Parser{}},
},
Action: func(ctx *Context) error {
if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"10", "20"}) {
t.Errorf("main name not set")
}
if !reflect.DeepEqual(ctx.Generic("s"), &Parser{"10", "20"}) {
t.Errorf("short name not set")
}
return nil
},
}
a.Run([]string{"run", "-s", "10,20"})
}
func TestParseGenericFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_SERVE", "20,30")
a := App{
Flags: []Flag{
&GenericFlag{
Name: "serve",
Aliases: []string{"s"},
Value: &Parser{},
EnvVars: []string{"APP_SERVE"},
},
},
Action: func(ctx *Context) error {
if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"20", "30"}) {
t.Errorf("main name not set from env")
}
if !reflect.DeepEqual(ctx.Generic("s"), &Parser{"20", "30"}) {
t.Errorf("short name not set from env")
}
return nil
},
}
a.Run([]string{"run"})
}
func TestParseGenericFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_FOO", "99,2000")
a := App{
Flags: []Flag{
&GenericFlag{
Name: "foos",
Value: &Parser{},
EnvVars: []string{"COMPAT_FOO", "APP_FOO"},
},
},
Action: func(ctx *Context) error {
if !reflect.DeepEqual(ctx.Generic("foos"), &Parser{"99", "2000"}) {
t.Errorf("value not set from env")
}
return nil
},
}
a.Run([]string{"run"})
}
func TestStringSlice_Serialized_Set(t *testing.T) {
sl0 := NewStringSlice("a", "b")
ser0 := sl0.Serialized()
if len(ser0) < len(slPfx) {
t.Fatalf("serialized shorter than expected: %q", ser0)
}
sl1 := NewStringSlice("c", "d")
sl1.Set(ser0)
if sl0.String() != sl1.String() {
t.Fatalf("pre and post serialization do not match: %v != %v", sl0, sl1)
}
}
func TestIntSlice_Serialized_Set(t *testing.T) {
sl0 := NewIntSlice(1, 2)
ser0 := sl0.Serialized()
if len(ser0) < len(slPfx) {
t.Fatalf("serialized shorter than expected: %q", ser0)
}
sl1 := NewIntSlice(3, 4)
sl1.Set(ser0)
if sl0.String() != sl1.String() {
t.Fatalf("pre and post serialization do not match: %v != %v", sl0, sl1)
}
}
func TestInt64Slice_Serialized_Set(t *testing.T) {
sl0 := NewInt64Slice(int64(1), int64(2))
ser0 := sl0.Serialized()
if len(ser0) < len(slPfx) {
t.Fatalf("serialized shorter than expected: %q", ser0)
}
sl1 := NewInt64Slice(int64(3), int64(4))
sl1.Set(ser0)
if sl0.String() != sl1.String() {
t.Fatalf("pre and post serialization do not match: %v != %v", sl0, sl1)
}
}