urfave-cli/flag_test.go

3405 lines
101 KiB
Go

package cli
import (
"flag"
"fmt"
"io"
"io/ioutil"
"os"
"reflect"
"regexp"
"strings"
"testing"
"time"
)
var boolFlagTests = []struct {
name string
expected string
}{
{"help", "--help\t(default: false)"},
{"h", "-h\t(default: false)"},
}
func resetEnv(env []string) {
for _, e := range env {
fields := strings.SplitN(e, "=", 2)
os.Setenv(fields[0], fields[1])
}
}
func TestBoolFlagHelpOutput(t *testing.T) {
for _, test := range boolFlagTests {
fl := &BoolFlag{Name: test.name}
output := fl.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)
}
func TestBoolFlagValueFromContext(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Bool("trueflag", true, "doc")
set.Bool("falseflag", false, "doc")
ctx := NewContext(nil, set, nil)
tf := &BoolFlag{Name: "trueflag"}
ff := &BoolFlag{Name: "falseflag"}
expect(t, tf.Get(ctx), true)
expect(t, ff.Get(ctx), false)
}
func TestBoolFlagApply_SetsCount(t *testing.T) {
v := false
count := 0
fl := BoolFlag{Name: "wat", Aliases: []string{"W", "huh"}, Destination: &v, Count: &count}
set := flag.NewFlagSet("test", 0)
err := fl.Apply(set)
expect(t, err, nil)
err = set.Parse([]string{"--wat", "-W", "--huh"})
expect(t, err, nil)
expect(t, v, true)
expect(t, count, 3)
}
func TestBoolFlagCountFromContext(t *testing.T) {
boolCountTests := []struct {
input []string
expectedVal bool
expectedCount int
}{
{
input: []string{"-tf", "-w", "-huh"},
expectedVal: true,
expectedCount: 3,
},
{
input: []string{},
expectedVal: false,
expectedCount: 0,
},
}
for _, bct := range boolCountTests {
set := flag.NewFlagSet("test", 0)
ctx := NewContext(nil, set, nil)
tf := &BoolFlag{Name: "tf", Aliases: []string{"w", "huh"}}
err := tf.Apply(set)
expect(t, err, nil)
err = set.Parse(bct.input)
expect(t, err, nil)
expect(t, tf.Get(ctx), bct.expectedVal)
expect(t, ctx.Count("tf"), bct.expectedCount)
}
}
func TestFlagsFromEnv(t *testing.T) {
newSetFloat64Slice := func(defaults ...float64) Float64Slice {
s := NewFloat64Slice(defaults...)
s.hasBeenSet = false
return *s
}
newSetIntSlice := func(defaults ...int) IntSlice {
s := NewIntSlice(defaults...)
s.hasBeenSet = false
return *s
}
newSetUintSlice := func(defaults ...uint) UintSlice {
s := NewUintSlice(defaults...)
s.hasBeenSet = false
return *s
}
newSetInt64Slice := func(defaults ...int64) Int64Slice {
s := NewInt64Slice(defaults...)
s.hasBeenSet = false
return *s
}
newSetUint64Slice := func(defaults ...uint64) Uint64Slice {
s := NewUint64Slice(defaults...)
s.hasBeenSet = false
return *s
}
newSetStringSlice := func(defaults ...string) StringSlice {
s := NewStringSlice(defaults...)
s.hasBeenSet = false
return *s
}
var flagTests = []struct {
input string
output interface{}
flag Flag
errRegexp string
}{
{"", false, &BoolFlag{Name: "debug", EnvVars: []string{"DEBUG"}}, ""},
{"1", true, &BoolFlag{Name: "debug", EnvVars: []string{"DEBUG"}}, ""},
{"false", false, &BoolFlag{Name: "debug", EnvVars: []string{"DEBUG"}}, ""},
{"foobar", true, &BoolFlag{Name: "debug", EnvVars: []string{"DEBUG"}}, `could not parse "foobar" as bool value from environment variable "DEBUG" for flag debug: .*`},
{"1s", 1 * time.Second, &DurationFlag{Name: "time", EnvVars: []string{"TIME"}}, ""},
{"foobar", false, &DurationFlag{Name: "time", EnvVars: []string{"TIME"}}, `could not parse "foobar" as duration value from environment variable "TIME" for flag time: .*`},
{"1.2", 1.2, &Float64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}}, ""},
{"1", 1.0, &Float64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}}, ""},
{"foobar", 0, &Float64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}}, `could not parse "foobar" as float64 value from environment variable "SECONDS" for flag seconds: .*`},
{"1", int64(1), &Int64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}}, ""},
{"1.2", 0, &Int64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}}, `could not parse "1.2" as int value from environment variable "SECONDS" for flag seconds: .*`},
{"foobar", 0, &Int64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}}, `could not parse "foobar" as int value from environment variable "SECONDS" for flag seconds: .*`},
{"1", 1, &IntFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, ""},
{"08", 8, &IntFlag{Name: "seconds", EnvVars: []string{"SECONDS"}, Base: 10}, ""},
{"755", 493, &IntFlag{Name: "seconds", EnvVars: []string{"SECONDS"}, Base: 8}, ""},
{"deadBEEF", 3735928559, &IntFlag{Name: "seconds", EnvVars: []string{"SECONDS"}, Base: 16}, ""},
{"08", 0, &IntFlag{Name: "seconds", EnvVars: []string{"SECONDS"}, Base: 0}, `could not parse "08" as int value from environment variable "SECONDS" for flag seconds: .*`},
{"1.2", 0, &IntFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, `could not parse "1.2" as int value from environment variable "SECONDS" for flag seconds: .*`},
{"foobar", 0, &IntFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, `could not parse "foobar" as int value from environment variable "SECONDS" for flag seconds: .*`},
{"1.0,2", newSetFloat64Slice(1, 2), &Float64SliceFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, ""},
{"foobar", newSetFloat64Slice(), &Float64SliceFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, `could not parse "foobar" as float64 slice value from environment variable "SECONDS" for flag seconds: .*`},
{"1,2", newSetIntSlice(1, 2), &IntSliceFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, ""},
{"1.2,2", newSetIntSlice(), &IntSliceFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, `could not parse "1.2,2" as int slice value from environment variable "SECONDS" for flag seconds: .*`},
{"foobar", newSetIntSlice(), &IntSliceFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, `could not parse "foobar" as int slice value from environment variable "SECONDS" for flag seconds: .*`},
{"1,2", newSetUintSlice(1, 2), &UintSliceFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, ""},
{"1.2,2", newSetUintSlice(), &UintSliceFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, `could not parse "1.2,2" as uint slice value from environment variable "SECONDS" for flag seconds: .*`},
{"foobar", newSetUintSlice(), &UintSliceFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, `could not parse "foobar" as uint slice value from environment variable "SECONDS" for flag seconds: .*`},
{"1,2", newSetInt64Slice(1, 2), &Int64SliceFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, ""},
{"1.2,2", newSetInt64Slice(), &Int64SliceFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, `could not parse "1.2,2" as int64 slice value from environment variable "SECONDS" for flag seconds: .*`},
{"foobar", newSetInt64Slice(), &Int64SliceFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, `could not parse "foobar" as int64 slice value from environment variable "SECONDS" for flag seconds: .*`},
{"1,2", newSetUint64Slice(1, 2), &Uint64SliceFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, ""},
{"1.2,2", newSetUint64Slice(), &Uint64SliceFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, `could not parse "1.2,2" as uint64 slice value from environment variable "SECONDS" for flag seconds: .*`},
{"foobar", newSetUint64Slice(), &Uint64SliceFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, `could not parse "foobar" as uint64 slice value from environment variable "SECONDS" for flag seconds: .*`},
{"foo", "foo", &StringFlag{Name: "name", EnvVars: []string{"NAME"}}, ""},
{"path", "path", &PathFlag{Name: "path", EnvVars: []string{"PATH"}}, ""},
{"foo,bar", newSetStringSlice("foo", "bar"), &StringSliceFlag{Name: "names", EnvVars: []string{"NAMES"}}, ""},
{"1", uint(1), &UintFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, ""},
{"08", uint(8), &UintFlag{Name: "seconds", EnvVars: []string{"SECONDS"}, Base: 10}, ""},
{"755", uint(493), &UintFlag{Name: "seconds", EnvVars: []string{"SECONDS"}, Base: 8}, ""},
{"deadBEEF", uint(3735928559), &UintFlag{Name: "seconds", EnvVars: []string{"SECONDS"}, Base: 16}, ""},
{"08", 0, &UintFlag{Name: "seconds", EnvVars: []string{"SECONDS"}, Base: 0}, `could not parse "08" as uint value from environment variable "SECONDS" for flag seconds: .*`},
{"1.2", 0, &UintFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, `could not parse "1.2" as uint value from environment variable "SECONDS" for flag seconds: .*`},
{"foobar", 0, &UintFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, `could not parse "foobar" as uint value from environment variable "SECONDS" for flag seconds: .*`},
{"1", uint64(1), &Uint64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}}, ""},
{"08", uint64(8), &Uint64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}, Base: 10}, ""},
{"755", uint64(493), &Uint64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}, Base: 8}, ""},
{"deadBEEF", uint64(3735928559), &Uint64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}, Base: 16}, ""},
{"08", 0, &Uint64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}, Base: 0}, `could not parse "08" as uint64 value from environment variable "SECONDS" for flag seconds: .*`},
{"1.2", 0, &Uint64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}}, `could not parse "1.2" as uint64 value from environment variable "SECONDS" for flag seconds: .*`},
{"foobar", 0, &Uint64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}}, `could not parse "foobar" as uint64 value from environment variable "SECONDS" for flag seconds: .*`},
{"foo,bar", &Parser{"foo", "bar"}, &GenericFlag{Name: "names", Value: &Parser{}, EnvVars: []string{"NAMES"}}, ""},
}
for i, test := range flagTests {
defer resetEnv(os.Environ())
os.Clearenv()
f, ok := test.flag.(DocGenerationFlag)
if !ok {
t.Errorf("flag %[1]q (%[1]T) needs to implement DocGenerationFlag to retrieve env vars", test.flag)
}
envVarSlice := f.GetEnvVars()
_ = os.Setenv(envVarSlice[0], test.input)
a := App{
Flags: []Flag{test.flag},
Action: func(ctx *Context) error {
if !reflect.DeepEqual(ctx.Value(test.flag.Names()[0]), test.output) {
t.Errorf("ex:%01d expected %q to be parsed as %#v, instead was %#v", i, test.input, test.output, ctx.Value(test.flag.Names()[0]))
}
if !f.IsSet() {
t.Errorf("Flag %s not set", f.Names()[0])
}
// check that flag names are returned when set via env as well
if !reflect.DeepEqual(ctx.FlagNames(), test.flag.Names()) {
t.Errorf("Not enough flag names %+v", ctx.FlagNames())
}
return nil
},
}
err := a.Run([]string{"run"})
if test.errRegexp != "" {
if err == nil {
t.Errorf("expected error to match %q, got none", test.errRegexp)
} else {
if matched, _ := regexp.MatchString(test.errRegexp, err.Error()); !matched {
t.Errorf("expected error to match %q, got error %s", test.errRegexp, err)
}
}
} else {
if err != nil && test.errRegexp == "" {
t.Errorf("expected no error got %q", err)
}
}
}
}
type nodocFlag struct {
Flag
Name string
}
func TestFlagStringifying(t *testing.T) {
for _, tc := range []struct {
name string
fl Flag
expected string
}{
{
name: "bool-flag",
fl: &BoolFlag{Name: "vividly"},
expected: "--vividly\t(default: false)",
},
{
name: "bool-flag-with-default-text",
fl: &BoolFlag{Name: "wildly", DefaultText: "scrambled"},
expected: "--wildly\t(default: scrambled)",
},
{
name: "duration-flag",
fl: &DurationFlag{Name: "scream-for"},
expected: "--scream-for value\t(default: 0s)",
},
{
name: "duration-flag-with-default-text",
fl: &DurationFlag{Name: "feels-about", DefaultText: "whimsically"},
expected: "--feels-about value\t(default: whimsically)",
},
{
name: "float64-flag",
fl: &Float64Flag{Name: "arduous"},
expected: "--arduous value\t(default: 0)",
},
{
name: "float64-flag-with-default-text",
fl: &Float64Flag{Name: "filibuster", DefaultText: "42"},
expected: "--filibuster value\t(default: 42)",
},
{
name: "float64-slice-flag",
fl: &Float64SliceFlag{Name: "pizzas"},
expected: "--pizzas value [ --pizzas value ]\t",
},
{
name: "float64-slice-flag-with-default-text",
fl: &Float64SliceFlag{Name: "pepperonis", DefaultText: "shaved"},
expected: "--pepperonis value [ --pepperonis value ]\t(default: shaved)",
},
{
name: "generic-flag",
fl: &GenericFlag{Name: "yogurt"},
expected: "--yogurt value\t",
},
{
name: "generic-flag-with-default-text",
fl: &GenericFlag{Name: "ricotta", DefaultText: "plops"},
expected: "--ricotta value\t(default: plops)",
},
{
name: "int-flag",
fl: &IntFlag{Name: "grubs"},
expected: "--grubs value\t(default: 0)",
},
{
name: "int-flag-with-default-text",
fl: &IntFlag{Name: "poisons", DefaultText: "11ty"},
expected: "--poisons value\t(default: 11ty)",
},
{
name: "int-slice-flag",
fl: &IntSliceFlag{Name: "pencils"},
expected: "--pencils value [ --pencils value ]\t",
},
{
name: "int-slice-flag-with-default-text",
fl: &IntFlag{Name: "pens", DefaultText: "-19"},
expected: "--pens value\t(default: -19)",
},
{
name: "uint-slice-flag",
fl: &UintSliceFlag{Name: "pencils"},
expected: "--pencils value [ --pencils value ]\t",
},
{
name: "uint-slice-flag-with-default-text",
fl: &UintFlag{Name: "pens", DefaultText: "29"},
expected: "--pens value\t(default: 29)",
},
{
name: "int64-flag",
fl: &Int64Flag{Name: "flume"},
expected: "--flume value\t(default: 0)",
},
{
name: "int64-flag-with-default-text",
fl: &Int64Flag{Name: "shattering", DefaultText: "22"},
expected: "--shattering value\t(default: 22)",
},
{
name: "int64-slice-flag",
fl: &Int64SliceFlag{Name: "drawers"},
expected: "--drawers value [ --drawers value ]\t",
},
{
name: "int64-slice-flag-with-default-text",
fl: &Int64SliceFlag{Name: "handles", DefaultText: "-2"},
expected: "--handles value [ --handles value ]\t(default: -2)",
},
{
name: "uint64-slice-flag",
fl: &Uint64SliceFlag{Name: "drawers"},
expected: "--drawers value [ --drawers value ]\t",
},
{
name: "uint64-slice-flag-with-default-text",
fl: &Uint64SliceFlag{Name: "handles", DefaultText: "-2"},
expected: "--handles value [ --handles value ]\t(default: -2)",
},
{
name: "path-flag",
fl: &PathFlag{Name: "soup"},
expected: "--soup value\t",
},
{
name: "path-flag-with-default-text",
fl: &PathFlag{Name: "stew", DefaultText: "charred/beans"},
expected: "--stew value\t(default: charred/beans)",
},
{
name: "string-flag",
fl: &StringFlag{Name: "arf-sound"},
expected: "--arf-sound value\t",
},
{
name: "string-flag-with-default-text",
fl: &StringFlag{Name: "woof-sound", DefaultText: "urp"},
expected: "--woof-sound value\t(default: urp)",
},
{
name: "string-slice-flag",
fl: &StringSliceFlag{Name: "meow-sounds"},
expected: "--meow-sounds value [ --meow-sounds value ]\t",
},
{
name: "string-slice-flag-with-default-text",
fl: &StringSliceFlag{Name: "moo-sounds", DefaultText: "awoo"},
expected: "--moo-sounds value [ --moo-sounds value ]\t(default: awoo)",
},
{
name: "timestamp-flag",
fl: &TimestampFlag{Name: "eating"},
expected: "--eating value\t",
},
{
name: "timestamp-flag-with-default-text",
fl: &TimestampFlag{Name: "sleeping", DefaultText: "earlier"},
expected: "--sleeping value\t(default: earlier)",
},
{
name: "uint-flag",
fl: &UintFlag{Name: "jars"},
expected: "--jars value\t(default: 0)",
},
{
name: "uint-flag-with-default-text",
fl: &UintFlag{Name: "bottles", DefaultText: "99"},
expected: "--bottles value\t(default: 99)",
},
{
name: "uint64-flag",
fl: &Uint64Flag{Name: "cans"},
expected: "--cans value\t(default: 0)",
},
{
name: "uint64-flag-with-default-text",
fl: &UintFlag{Name: "tubes", DefaultText: "13"},
expected: "--tubes value\t(default: 13)",
},
{
name: "nodoc-flag",
fl: &nodocFlag{Name: "scarecrow"},
expected: "",
},
} {
t.Run(tc.name, func(ct *testing.T) {
s := stringifyFlag(tc.fl)
if s != tc.expected {
ct.Errorf("stringified flag %q does not match expected %q", s, tc.expected)
}
})
}
}
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 {
fl := &StringFlag{Name: test.name, Aliases: test.aliases, Usage: test.usage, Value: test.value}
// create a tmp flagset
tfs := flag.NewFlagSet("test", 0)
fl.Apply(tfs)
output := fl.String()
if output != test.expected {
t.Errorf("%q does not match %q", output, test.expected)
}
}
}
func TestStringFlagDefaultText(t *testing.T) {
fl := &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 := fl.String()
if output != expected {
t.Errorf("%q does not match %q", output, expected)
}
}
func TestStringFlagWithEnvVarHelpOutput(t *testing.T) {
defer resetEnv(os.Environ())
os.Clearenv()
_ = os.Setenv("APP_FOO", "derp")
for _, test := range stringFlagTests {
fl := &StringFlag{Name: test.name, Aliases: test.aliases, Value: test.value, EnvVars: []string{"APP_FOO"}}
output := fl.String()
expectedSuffix := withEnvHint([]string{"APP_FOO"}, "")
if !strings.HasSuffix(output, expectedSuffix) {
t.Errorf("%s does not end with"+expectedSuffix, output)
}
}
}
var _ = []struct {
name string
aliases []string
usage string
value string
prefixer FlagNamePrefixFunc
expected string
}{
{name: "foo", usage: "", value: "", prefixer: func(a []string, b string) string {
return fmt.Sprintf("name: %s, ph: %s", a, b)
}, expected: "name: foo, ph: value\t"},
{name: "f", usage: "", value: "", prefixer: func(a []string, b string) string {
return fmt.Sprintf("name: %s, ph: %s", a, b)
}, expected: "name: f, ph: value\t"},
{name: "f", usage: "The total `foo` desired", value: "all", prefixer: func(a []string, b string) string {
return fmt.Sprintf("name: %s, ph: %s", a, b)
}, expected: "name: f, ph: foo\tThe total foo desired (default: \"all\")"},
{name: "test", usage: "", value: "Something", prefixer: func(a []string, b string) string {
return fmt.Sprintf("name: %s, ph: %s", a, b)
}, expected: "name: test, ph: value\t(default: \"Something\")"},
{name: "config", aliases: []string{"c"}, usage: "Load configuration from `FILE`", value: "", prefixer: func(a []string, b string) string {
return fmt.Sprintf("name: %s, ph: %s", a, b)
}, expected: "name: config,c, ph: FILE\tLoad configuration from FILE"},
{name: "config", aliases: []string{"c"}, usage: "Load configuration from `CONFIG`", value: "config.json", prefixer: func(a []string, b string) string {
return fmt.Sprintf("name: %s, ph: %s", a, b)
}, expected: "name: config,c, ph: CONFIG\tLoad configuration from CONFIG (default: \"config.json\")"},
}
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")
}
func TestStringFlagValueFromContext(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.String("myflag", "foobar", "doc")
ctx := NewContext(nil, set, nil)
f := &StringFlag{Name: "myflag"}
expect(t, f.Get(ctx), "foobar")
}
var pathFlagTests = []struct {
name string
aliases []string
usage string
value string
expected string
}{
{"f", nil, "", "", "-f value\t"},
{"f", nil, "Path is the `path` of file", "/path/to/file", "-f path\tPath is the path of file (default: \"/path/to/file\")"},
}
func TestPathFlagHelpOutput(t *testing.T) {
for _, test := range pathFlagTests {
fl := &PathFlag{Name: test.name, Aliases: test.aliases, Usage: test.usage, Value: test.value}
// create a temporary flag set to apply
tfs := flag.NewFlagSet("test", 0)
fl.Apply(tfs)
output := fl.String()
if output != test.expected {
t.Errorf("%q does not match %q", output, test.expected)
}
}
}
func TestPathFlagWithEnvVarHelpOutput(t *testing.T) {
defer resetEnv(os.Environ())
os.Clearenv()
_ = os.Setenv("APP_PATH", "/path/to/file")
for _, test := range pathFlagTests {
fl := &PathFlag{Name: test.name, Aliases: test.aliases, Value: test.value, EnvVars: []string{"APP_PATH"}}
output := fl.String()
expectedSuffix := withEnvHint([]string{"APP_PATH"}, "")
if !strings.HasSuffix(output, expectedSuffix) {
t.Errorf("%s does not end with"+expectedSuffix, output)
}
}
}
func TestPathFlagApply_SetsAllNames(t *testing.T) {
v := "mmm"
fl := PathFlag{Name: "path", Aliases: []string{"p", "PATH"}, Destination: &v}
set := flag.NewFlagSet("test", 0)
_ = fl.Apply(set)
err := set.Parse([]string{"--path", "/path/to/file/path", "-p", "/path/to/file/p", "--PATH", "/path/to/file/PATH"})
expect(t, err, nil)
expect(t, v, "/path/to/file/PATH")
}
func TestPathFlagValueFromContext(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.String("myflag", "/my/path", "doc")
ctx := NewContext(nil, set, nil)
f := &PathFlag{Name: "myflag"}
expect(t, f.Get(ctx), "/my/path")
}
var _ = []struct {
name string
env string
hinter FlagEnvHintFunc
expected string
}{
{"foo", "", func(a []string, b string) string {
return fmt.Sprintf("env: %s, str: %s", a, b)
}, "env: , str: --foo value\t"},
{"f", "", func(a []string, b string) string {
return fmt.Sprintf("env: %s, str: %s", a, b)
}, "env: , str: -f value\t"},
{"foo", "ENV_VAR", func(a []string, b string) string {
return fmt.Sprintf("env: %s, str: %s", a, b)
}, "env: ENV_VAR, str: --foo value\t"},
{"f", "ENV_VAR", func(a []string, b string) string {
return fmt.Sprintf("env: %s, str: %s", a, b)
}, "env: ENV_VAR, str: -f value\t"},
}
//func TestFlagEnvHinter(t *testing.T) {
// defer func() {
// FlagEnvHinter = withEnvHint
// }()
//
// for _, test := range envHintFlagTests {
// FlagEnvHinter = test.hinter
// fl := StringFlag{Name: test.name, EnvVars: []string{test.env}}
// output := fl.String()
// if output != test.expected {
// t.Errorf("%q does not match %q", output, test.expected)
// }
// }
//}
var stringSliceFlagTests = []struct {
name string
aliases []string
value *StringSlice
expected string
}{
{"foo", nil, NewStringSlice(""), "--foo value [ --foo value ]\t"},
{"f", nil, NewStringSlice(""), "-f value [ -f value ]\t"},
{"f", nil, NewStringSlice("Lipstick"), "-f value [ -f value ]\t(default: \"Lipstick\")"},
{"test", nil, NewStringSlice("Something"), "--test value [ --test value ]\t(default: \"Something\")"},
{"dee", []string{"d"}, NewStringSlice("Inka", "Dinka", "dooo"), "--dee value, -d value [ --dee value, -d value ]\t(default: \"Inka\", \"Dinka\", \"dooo\")"},
}
func TestStringSliceFlagHelpOutput(t *testing.T) {
for _, test := range stringSliceFlagTests {
f := &StringSliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value}
output := f.String()
if output != test.expected {
t.Errorf("%q does not match %q", output, test.expected)
}
}
}
func TestStringSliceFlagWithEnvVarHelpOutput(t *testing.T) {
defer resetEnv(os.Environ())
os.Clearenv()
_ = os.Setenv("APP_QWWX", "11,4")
for _, test := range stringSliceFlagTests {
fl := &StringSliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value, EnvVars: []string{"APP_QWWX"}}
output := fl.String()
expectedSuffix := withEnvHint([]string{"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)
}
func TestStringSliceFlagApply_UsesEnvValues_noDefault(t *testing.T) {
defer resetEnv(os.Environ())
os.Clearenv()
_ = os.Setenv("MY_GOAT", "vincent van goat,scape goat")
var val StringSlice
fl := StringSliceFlag{Name: "goat", EnvVars: []string{"MY_GOAT"}, Value: &val}
set := flag.NewFlagSet("test", 0)
_ = fl.Apply(set)
err := set.Parse(nil)
expect(t, err, nil)
expect(t, val.Value(), []string(nil))
expect(t, set.Lookup("goat").Value.(*StringSlice).Value(), []string{"vincent van goat", "scape goat"})
}
func TestStringSliceFlagApply_UsesEnvValues_withDefault(t *testing.T) {
defer resetEnv(os.Environ())
os.Clearenv()
_ = os.Setenv("MY_GOAT", "vincent van goat,scape goat")
val := NewStringSlice(`some default`, `values here`)
fl := StringSliceFlag{Name: "goat", EnvVars: []string{"MY_GOAT"}, Value: val}
set := flag.NewFlagSet("test", 0)
_ = fl.Apply(set)
err := set.Parse(nil)
expect(t, err, nil)
expect(t, val.Value(), []string{`some default`, `values here`})
expect(t, set.Lookup("goat").Value.(*StringSlice).Value(), []string{"vincent van goat", "scape goat"})
}
func TestStringSliceFlagApply_DefaultValueWithDestination(t *testing.T) {
defValue := []string{"UA", "US"}
fl := StringSliceFlag{Name: "country", Value: NewStringSlice(defValue...), Destination: NewStringSlice("CA")}
set := flag.NewFlagSet("test", 0)
_ = fl.Apply(set)
err := set.Parse([]string{})
expect(t, err, nil)
expect(t, defValue, fl.Destination.Value())
}
func TestStringSliceFlagValueFromContext(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Var(NewStringSlice("a", "b", "c"), "myflag", "doc")
ctx := NewContext(nil, set, nil)
f := &StringSliceFlag{Name: "myflag"}
expect(t, f.Get(ctx), []string{"a", "b", "c"})
}
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 {
fl := &IntFlag{Name: test.name, Value: 9}
// create a temporary flag set to apply
tfs := flag.NewFlagSet("test", 0)
fl.Apply(tfs)
output := fl.String()
if output != test.expected {
t.Errorf("%s does not match %s", output, test.expected)
}
}
}
func TestIntFlagWithEnvVarHelpOutput(t *testing.T) {
defer resetEnv(os.Environ())
os.Clearenv()
_ = os.Setenv("APP_BAR", "2")
for _, test := range intFlagTests {
fl := &IntFlag{Name: test.name, EnvVars: []string{"APP_BAR"}}
output := fl.String()
expectedSuffix := withEnvHint([]string{"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)
}
func TestIntFlagValueFromContext(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Int("myflag", 42, "doc")
ctx := NewContext(nil, set, nil)
f := &IntFlag{Name: "myflag"}
expect(t, f.Get(ctx), 42)
}
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 {
fl := Int64Flag{Name: test.name, Value: 8589934592}
// create a temporary flag set to apply
tfs := flag.NewFlagSet("test", 0)
fl.Apply(tfs)
output := fl.String()
if output != test.expected {
t.Errorf("%s does not match %s", output, test.expected)
}
}
}
func TestInt64FlagWithEnvVarHelpOutput(t *testing.T) {
defer resetEnv(os.Environ())
os.Clearenv()
_ = os.Setenv("APP_BAR", "2")
for _, test := range int64FlagTests {
fl := IntFlag{Name: test.name, EnvVars: []string{"APP_BAR"}}
output := fl.String()
expectedSuffix := withEnvHint([]string{"APP_BAR"}, "")
if !strings.HasSuffix(output, expectedSuffix) {
t.Errorf("%s does not end with"+expectedSuffix, output)
}
}
}
func TestInt64FlagValueFromContext(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Int64("myflag", 42, "doc")
ctx := NewContext(nil, set, nil)
f := &Int64Flag{Name: "myflag"}
expect(t, f.Get(ctx), int64(42))
}
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 {
fl := UintFlag{Name: test.name, Value: 41}
// create a temporary flag set to apply
tfs := flag.NewFlagSet("test", 0)
fl.Apply(tfs)
output := fl.String()
if output != test.expected {
t.Errorf("%s does not match %s", output, test.expected)
}
}
}
func TestUintFlagWithEnvVarHelpOutput(t *testing.T) {
defer resetEnv(os.Environ())
os.Clearenv()
_ = os.Setenv("APP_BAR", "2")
for _, test := range uintFlagTests {
fl := UintFlag{Name: test.name, EnvVars: []string{"APP_BAR"}}
output := fl.String()
expectedSuffix := withEnvHint([]string{"APP_BAR"}, "")
if !strings.HasSuffix(output, expectedSuffix) {
t.Errorf("%s does not end with"+expectedSuffix, output)
}
}
}
func TestUintFlagValueFromContext(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Uint("myflag", 42, "doc")
ctx := NewContext(nil, set, nil)
f := &UintFlag{Name: "myflag"}
expect(t, f.Get(ctx), uint(42))
}
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 {
fl := Uint64Flag{Name: test.name, Value: 8589934582}
// create a temporary flag set to apply
tfs := flag.NewFlagSet("test", 0)
fl.Apply(tfs)
output := fl.String()
if output != test.expected {
t.Errorf("%s does not match %s", output, test.expected)
}
}
}
func TestUint64FlagWithEnvVarHelpOutput(t *testing.T) {
defer resetEnv(os.Environ())
os.Clearenv()
_ = os.Setenv("APP_BAR", "2")
for _, test := range uint64FlagTests {
fl := UintFlag{Name: test.name, EnvVars: []string{"APP_BAR"}}
output := fl.String()
expectedSuffix := withEnvHint([]string{"APP_BAR"}, "")
if !strings.HasSuffix(output, expectedSuffix) {
t.Errorf("%s does not end with"+expectedSuffix, output)
}
}
}
func TestUint64FlagValueFromContext(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Uint64("myflag", 42, "doc")
ctx := NewContext(nil, set, nil)
f := &Uint64Flag{Name: "myflag"}
expect(t, f.Get(ctx), uint64(42))
}
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 {
fl := &DurationFlag{Name: test.name, Value: 1 * time.Second}
// create a temporary flag set to apply
tfs := flag.NewFlagSet("test", 0)
fl.Apply(tfs)
output := fl.String()
if output != test.expected {
t.Errorf("%q does not match %q", output, test.expected)
}
}
}
func TestDurationFlagWithEnvVarHelpOutput(t *testing.T) {
defer resetEnv(os.Environ())
os.Clearenv()
_ = os.Setenv("APP_BAR", "2h3m6s")
for _, test := range durationFlagTests {
fl := &DurationFlag{Name: test.name, EnvVars: []string{"APP_BAR"}}
output := fl.String()
expectedSuffix := withEnvHint([]string{"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)
}
func TestDurationFlagValueFromContext(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Duration("myflag", 42*time.Second, "doc")
ctx := NewContext(nil, set, nil)
f := &DurationFlag{Name: "myflag"}
expect(t, f.Get(ctx), 42*time.Second)
}
var intSliceFlagTests = []struct {
name string
aliases []string
value *IntSlice
expected string
}{
{"heads", nil, NewIntSlice(), "--heads value [ --heads value ]\t"},
{"H", nil, NewIntSlice(), "-H value [ -H value ]\t"},
{"H", []string{"heads"}, NewIntSlice(9, 3), "-H value, --heads value [ -H value, --heads value ]\t(default: 9, 3)"},
}
func TestIntSliceFlagHelpOutput(t *testing.T) {
for _, test := range intSliceFlagTests {
fl := &IntSliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value}
output := fl.String()
if output != test.expected {
t.Errorf("%q does not match %q", output, test.expected)
}
}
}
func TestIntSliceFlagWithEnvVarHelpOutput(t *testing.T) {
defer resetEnv(os.Environ())
os.Clearenv()
_ = os.Setenv("APP_SMURF", "42,3")
for _, test := range intSliceFlagTests {
fl := &IntSliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value, EnvVars: []string{"APP_SMURF"}}
output := fl.String()
expectedSuffix := withEnvHint([]string{"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)
}
func TestIntSliceFlagApply_UsesEnvValues_noDefault(t *testing.T) {
defer resetEnv(os.Environ())
os.Clearenv()
_ = os.Setenv("MY_GOAT", "1 , 2")
var val IntSlice
fl := IntSliceFlag{Name: "goat", EnvVars: []string{"MY_GOAT"}, Value: &val}
set := flag.NewFlagSet("test", 0)
_ = fl.Apply(set)
err := set.Parse(nil)
expect(t, err, nil)
expect(t, val.Value(), []int(nil))
expect(t, set.Lookup("goat").Value.(*IntSlice).Value(), []int{1, 2})
}
func TestIntSliceFlagApply_UsesEnvValues_withDefault(t *testing.T) {
defer resetEnv(os.Environ())
os.Clearenv()
_ = os.Setenv("MY_GOAT", "1 , 2")
val := NewIntSlice(3, 4)
fl := IntSliceFlag{Name: "goat", EnvVars: []string{"MY_GOAT"}, Value: val}
set := flag.NewFlagSet("test", 0)
_ = fl.Apply(set)
err := set.Parse(nil)
expect(t, err, nil)
expect(t, val.Value(), []int{3, 4})
expect(t, set.Lookup("goat").Value.(*IntSlice).Value(), []int{1, 2})
}
func TestIntSliceFlagApply_DefaultValueWithDestination(t *testing.T) {
defValue := []int{1, 2}
fl := IntSliceFlag{Name: "country", Value: NewIntSlice(defValue...), Destination: NewIntSlice(3)}
set := flag.NewFlagSet("test", 0)
_ = fl.Apply(set)
err := set.Parse([]string{})
expect(t, err, nil)
expect(t, defValue, fl.Destination.Value())
}
func TestIntSliceFlagApply_ParentContext(t *testing.T) {
_ = (&App{
Flags: []Flag{
&IntSliceFlag{Name: "numbers", Aliases: []string{"n"}, Value: NewIntSlice(1, 2, 3)},
},
Commands: []*Command{
{
Name: "child",
Action: func(ctx *Context) error {
expected := []int{1, 2, 3}
if !reflect.DeepEqual(ctx.IntSlice("numbers"), expected) {
t.Errorf("child context unable to view parent flag: %v != %v", expected, ctx.IntSlice("numbers"))
}
if !reflect.DeepEqual(ctx.IntSlice("n"), expected) {
t.Errorf("child context unable to view parent flag: %v != %v", expected, ctx.IntSlice("n"))
}
return nil
},
},
},
}).Run([]string{"run", "child"})
}
func TestIntSliceFlag_SetFromParentContext(t *testing.T) {
fl := &IntSliceFlag{Name: "numbers", Aliases: []string{"n"}, Value: NewIntSlice(1, 2, 3, 4)}
set := flag.NewFlagSet("test", 0)
_ = fl.Apply(set)
ctx := &Context{
parentContext: &Context{
flagSet: set,
},
flagSet: flag.NewFlagSet("empty", 0),
}
expected := []int{1, 2, 3, 4}
if !reflect.DeepEqual(ctx.IntSlice("numbers"), expected) {
t.Errorf("child context unable to view parent flag: %v != %v", expected, ctx.IntSlice("numbers"))
}
}
func TestIntSliceFlagValueFromContext(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Var(NewIntSlice(1, 2, 3), "myflag", "doc")
ctx := NewContext(nil, set, nil)
f := &IntSliceFlag{Name: "myflag"}
expect(t, f.Get(ctx), []int{1, 2, 3})
}
var int64SliceFlagTests = []struct {
name string
aliases []string
value *Int64Slice
expected string
}{
{"heads", nil, NewInt64Slice(), "--heads value [ --heads value ]\t"},
{"H", nil, NewInt64Slice(), "-H value [ -H value ]\t"},
{"heads", []string{"H"}, NewInt64Slice(int64(2), int64(17179869184)),
"--heads value, -H value [ --heads value, -H value ]\t(default: 2, 17179869184)"},
}
func TestInt64SliceFlagHelpOutput(t *testing.T) {
for _, test := range int64SliceFlagTests {
fl := Int64SliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value}
output := fl.String()
if output != test.expected {
t.Errorf("%q does not match %q", output, test.expected)
}
}
}
func TestInt64SliceFlagWithEnvVarHelpOutput(t *testing.T) {
defer resetEnv(os.Environ())
os.Clearenv()
_ = os.Setenv("APP_SMURF", "42,17179869184")
for _, test := range int64SliceFlagTests {
fl := Int64SliceFlag{Name: test.name, Value: test.value, EnvVars: []string{"APP_SMURF"}}
output := fl.String()
expectedSuffix := withEnvHint([]string{"APP_SMURF"}, "")
if !strings.HasSuffix(output, expectedSuffix) {
t.Errorf("%q does not end with"+expectedSuffix, output)
}
}
}
func TestInt64SliceFlagApply_SetsAllNames(t *testing.T) {
fl := Int64SliceFlag{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)
}
func TestInt64SliceFlagApply_UsesEnvValues_noDefault(t *testing.T) {
defer resetEnv(os.Environ())
os.Clearenv()
_ = os.Setenv("MY_GOAT", "1 , 2")
var val Int64Slice
fl := Int64SliceFlag{Name: "goat", EnvVars: []string{"MY_GOAT"}, Value: &val}
set := flag.NewFlagSet("test", 0)
_ = fl.Apply(set)
err := set.Parse(nil)
expect(t, err, nil)
expect(t, val.Value(), []int64(nil))
expect(t, set.Lookup("goat").Value.(*Int64Slice).Value(), []int64{1, 2})
}
func TestInt64SliceFlagApply_UsesEnvValues_withDefault(t *testing.T) {
defer resetEnv(os.Environ())
os.Clearenv()
_ = os.Setenv("MY_GOAT", "1 , 2")
val := NewInt64Slice(3, 4)
fl := Int64SliceFlag{Name: "goat", EnvVars: []string{"MY_GOAT"}, Value: val}
set := flag.NewFlagSet("test", 0)
_ = fl.Apply(set)
err := set.Parse(nil)
expect(t, err, nil)
expect(t, val.Value(), []int64{3, 4})
expect(t, set.Lookup("goat").Value.(*Int64Slice).Value(), []int64{1, 2})
}
func TestInt64SliceFlagApply_DefaultValueWithDestination(t *testing.T) {
defValue := []int64{1, 2}
fl := Int64SliceFlag{Name: "country", Value: NewInt64Slice(defValue...), Destination: NewInt64Slice(3)}
set := flag.NewFlagSet("test", 0)
_ = fl.Apply(set)
err := set.Parse([]string{})
expect(t, err, nil)
expect(t, defValue, fl.Destination.Value())
}
func TestInt64SliceFlagApply_ParentContext(t *testing.T) {
_ = (&App{
Flags: []Flag{
&Int64SliceFlag{Name: "numbers", Aliases: []string{"n"}, Value: NewInt64Slice(1, 2, 3)},
},
Commands: []*Command{
{
Name: "child",
Action: func(ctx *Context) error {
expected := []int64{1, 2, 3}
if !reflect.DeepEqual(ctx.Int64Slice("numbers"), expected) {
t.Errorf("child context unable to view parent flag: %v != %v", expected, ctx.Int64Slice("numbers"))
}
if !reflect.DeepEqual(ctx.Int64Slice("n"), expected) {
t.Errorf("child context unable to view parent flag: %v != %v", expected, ctx.Int64Slice("n"))
}
return nil
},
},
},
}).Run([]string{"run", "child"})
}
func TestInt64SliceFlag_SetFromParentContext(t *testing.T) {
fl := &Int64SliceFlag{Name: "numbers", Aliases: []string{"n"}, Value: NewInt64Slice(1, 2, 3, 4)}
set := flag.NewFlagSet("test", 0)
_ = fl.Apply(set)
ctx := &Context{
parentContext: &Context{
flagSet: set,
},
flagSet: flag.NewFlagSet("empty", 0),
}
expected := []int64{1, 2, 3, 4}
if !reflect.DeepEqual(ctx.Int64Slice("numbers"), expected) {
t.Errorf("child context unable to view parent flag: %v != %v", expected, ctx.Int64Slice("numbers"))
}
}
func TestInt64SliceFlag_ReturnNil(t *testing.T) {
fl := &Int64SliceFlag{}
set := flag.NewFlagSet("test", 0)
_ = fl.Apply(set)
ctx := &Context{
parentContext: &Context{
flagSet: set,
},
flagSet: flag.NewFlagSet("empty", 0),
}
expected := []int64(nil)
if !reflect.DeepEqual(ctx.Int64Slice("numbers"), expected) {
t.Errorf("child context unable to view parent flag: %v != %v", expected, ctx.Int64Slice("numbers"))
}
}
func TestInt64SliceFlagValueFromContext(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Var(NewInt64Slice(1, 2, 3), "myflag", "doc")
ctx := NewContext(nil, set, nil)
f := &Int64SliceFlag{Name: "myflag"}
expect(t, f.Get(ctx), []int64{1, 2, 3})
}
var uintSliceFlagTests = []struct {
name string
aliases []string
value *UintSlice
expected string
}{
{"heads", nil, NewUintSlice(), "--heads value [ --heads value ]\t"},
{"H", nil, NewUintSlice(), "-H value [ -H value ]\t"},
{"heads", []string{"H"}, NewUintSlice(uint(2), uint(17179869184)),
"--heads value, -H value [ --heads value, -H value ]\t(default: 2, 17179869184)"},
}
func TestUintSliceFlagHelpOutput(t *testing.T) {
for _, test := range uintSliceFlagTests {
fl := UintSliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value}
output := fl.String()
if output != test.expected {
t.Errorf("%q does not match %q", output, test.expected)
}
}
}
func TestUintSliceFlagWithEnvVarHelpOutput(t *testing.T) {
defer resetEnv(os.Environ())
os.Clearenv()
_ = os.Setenv("APP_SMURF", "42,17179869184")
for _, test := range uintSliceFlagTests {
fl := UintSliceFlag{Name: test.name, Value: test.value, EnvVars: []string{"APP_SMURF"}}
output := fl.String()
expectedSuffix := withEnvHint([]string{"APP_SMURF"}, "")
if !strings.HasSuffix(output, expectedSuffix) {
t.Errorf("%q does not end with"+expectedSuffix, output)
}
}
}
func TestUintSliceFlagApply_SetsAllNames(t *testing.T) {
fl := UintSliceFlag{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)
}
func TestUintSliceFlagApply_UsesEnvValues_noDefault(t *testing.T) {
defer resetEnv(os.Environ())
os.Clearenv()
_ = os.Setenv("MY_GOAT", "1 , 2")
var val UintSlice
fl := UintSliceFlag{Name: "goat", EnvVars: []string{"MY_GOAT"}, Value: &val}
set := flag.NewFlagSet("test", 0)
_ = fl.Apply(set)
err := set.Parse(nil)
expect(t, err, nil)
expect(t, val.Value(), []uint(nil))
expect(t, set.Lookup("goat").Value.(*UintSlice).Value(), []uint{1, 2})
}
func TestUintSliceFlagApply_UsesEnvValues_withDefault(t *testing.T) {
defer resetEnv(os.Environ())
os.Clearenv()
_ = os.Setenv("MY_GOAT", "1 , 2")
val := NewUintSlice(3, 4)
fl := UintSliceFlag{Name: "goat", EnvVars: []string{"MY_GOAT"}, Value: val}
set := flag.NewFlagSet("test", 0)
_ = fl.Apply(set)
err := set.Parse(nil)
expect(t, err, nil)
expect(t, val.Value(), []uint{3, 4})
expect(t, set.Lookup("goat").Value.(*UintSlice).Value(), []uint{1, 2})
}
func TestUintSliceFlagApply_DefaultValueWithDestination(t *testing.T) {
defValue := []uint{1, 2}
fl := UintSliceFlag{Name: "country", Value: NewUintSlice(defValue...), Destination: NewUintSlice(3)}
set := flag.NewFlagSet("test", 0)
_ = fl.Apply(set)
err := set.Parse([]string{})
expect(t, err, nil)
expect(t, defValue, fl.Destination.Value())
}
func TestUintSliceFlagApply_ParentContext(t *testing.T) {
_ = (&App{
Flags: []Flag{
&UintSliceFlag{Name: "numbers", Aliases: []string{"n"}, Value: NewUintSlice(1, 2, 3)},
},
Commands: []*Command{
{
Name: "child",
Action: func(ctx *Context) error {
expected := []uint{1, 2, 3}
if !reflect.DeepEqual(ctx.UintSlice("numbers"), expected) {
t.Errorf("child context unable to view parent flag: %v != %v", expected, ctx.UintSlice("numbers"))
}
if !reflect.DeepEqual(ctx.UintSlice("n"), expected) {
t.Errorf("child context unable to view parent flag: %v != %v", expected, ctx.UintSlice("n"))
}
return nil
},
},
},
}).Run([]string{"run", "child"})
}
func TestUintSliceFlag_SetFromParentContext(t *testing.T) {
fl := &UintSliceFlag{Name: "numbers", Aliases: []string{"n"}, Value: NewUintSlice(1, 2, 3, 4)}
set := flag.NewFlagSet("test", 0)
_ = fl.Apply(set)
ctx := &Context{
parentContext: &Context{
flagSet: set,
},
flagSet: flag.NewFlagSet("empty", 0),
}
expected := []uint{1, 2, 3, 4}
if !reflect.DeepEqual(ctx.UintSlice("numbers"), expected) {
t.Errorf("child context unable to view parent flag: %v != %v", expected, ctx.UintSlice("numbers"))
}
}
func TestUintSliceFlag_ReturnNil(t *testing.T) {
fl := &UintSliceFlag{}
set := flag.NewFlagSet("test", 0)
_ = fl.Apply(set)
ctx := &Context{
parentContext: &Context{
flagSet: set,
},
flagSet: flag.NewFlagSet("empty", 0),
}
expected := []uint(nil)
if !reflect.DeepEqual(ctx.UintSlice("numbers"), expected) {
t.Errorf("child context unable to view parent flag: %v != %v", expected, ctx.UintSlice("numbers"))
}
}
var uint64SliceFlagTests = []struct {
name string
aliases []string
value *Uint64Slice
expected string
}{
{"heads", nil, NewUint64Slice(), "--heads value [ --heads value ]\t"},
{"H", nil, NewUint64Slice(), "-H value [ -H value ]\t"},
{"heads", []string{"H"}, NewUint64Slice(uint64(2), uint64(17179869184)),
"--heads value, -H value [ --heads value, -H value ]\t(default: 2, 17179869184)"},
}
func TestUint64SliceFlagHelpOutput(t *testing.T) {
for _, test := range uint64SliceFlagTests {
fl := Uint64SliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value}
output := fl.String()
if output != test.expected {
t.Errorf("%q does not match %q", output, test.expected)
}
}
}
func TestUint64SliceFlagWithEnvVarHelpOutput(t *testing.T) {
defer resetEnv(os.Environ())
os.Clearenv()
_ = os.Setenv("APP_SMURF", "42,17179869184")
for _, test := range uint64SliceFlagTests {
fl := Uint64SliceFlag{Name: test.name, Value: test.value, EnvVars: []string{"APP_SMURF"}}
output := fl.String()
expectedSuffix := withEnvHint([]string{"APP_SMURF"}, "")
if !strings.HasSuffix(output, expectedSuffix) {
t.Errorf("%q does not end with"+expectedSuffix, output)
}
}
}
func TestUint64SliceFlagApply_SetsAllNames(t *testing.T) {
fl := Uint64SliceFlag{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)
}
func TestUint64SliceFlagApply_UsesEnvValues_noDefault(t *testing.T) {
defer resetEnv(os.Environ())
os.Clearenv()
_ = os.Setenv("MY_GOAT", "1 , 2")
var val Uint64Slice
fl := Uint64SliceFlag{Name: "goat", EnvVars: []string{"MY_GOAT"}, Value: &val}
set := flag.NewFlagSet("test", 0)
_ = fl.Apply(set)
err := set.Parse(nil)
expect(t, err, nil)
expect(t, val.Value(), []uint64(nil))
expect(t, set.Lookup("goat").Value.(*Uint64Slice).Value(), []uint64{1, 2})
}
func TestUint64SliceFlagApply_UsesEnvValues_withDefault(t *testing.T) {
defer resetEnv(os.Environ())
os.Clearenv()
_ = os.Setenv("MY_GOAT", "1 , 2")
val := NewUint64Slice(3, 4)
fl := Uint64SliceFlag{Name: "goat", EnvVars: []string{"MY_GOAT"}, Value: val}
set := flag.NewFlagSet("test", 0)
_ = fl.Apply(set)
err := set.Parse(nil)
expect(t, err, nil)
expect(t, val.Value(), []uint64{3, 4})
expect(t, set.Lookup("goat").Value.(*Uint64Slice).Value(), []uint64{1, 2})
}
func TestUint64SliceFlagApply_DefaultValueWithDestination(t *testing.T) {
defValue := []uint64{1, 2}
fl := Uint64SliceFlag{Name: "country", Value: NewUint64Slice(defValue...), Destination: NewUint64Slice(3)}
set := flag.NewFlagSet("test", 0)
_ = fl.Apply(set)
err := set.Parse([]string{})
expect(t, err, nil)
expect(t, defValue, fl.Destination.Value())
}
func TestUint64SliceFlagApply_ParentContext(t *testing.T) {
_ = (&App{
Flags: []Flag{
&Uint64SliceFlag{Name: "numbers", Aliases: []string{"n"}, Value: NewUint64Slice(1, 2, 3)},
},
Commands: []*Command{
{
Name: "child",
Action: func(ctx *Context) error {
expected := []uint64{1, 2, 3}
if !reflect.DeepEqual(ctx.Uint64Slice("numbers"), expected) {
t.Errorf("child context unable to view parent flag: %v != %v", expected, ctx.Uint64Slice("numbers"))
}
if !reflect.DeepEqual(ctx.Uint64Slice("n"), expected) {
t.Errorf("child context unable to view parent flag: %v != %v", expected, ctx.Uint64Slice("n"))
}
return nil
},
},
},
}).Run([]string{"run", "child"})
}
func TestUint64SliceFlag_SetFromParentContext(t *testing.T) {
fl := &Uint64SliceFlag{Name: "numbers", Aliases: []string{"n"}, Value: NewUint64Slice(1, 2, 3, 4)}
set := flag.NewFlagSet("test", 0)
_ = fl.Apply(set)
ctx := &Context{
parentContext: &Context{
flagSet: set,
},
flagSet: flag.NewFlagSet("empty", 0),
}
expected := []uint64{1, 2, 3, 4}
if !reflect.DeepEqual(ctx.Uint64Slice("numbers"), expected) {
t.Errorf("child context unable to view parent flag: %v != %v", expected, ctx.Uint64Slice("numbers"))
}
}
func TestUint64SliceFlag_ReturnNil(t *testing.T) {
fl := &Uint64SliceFlag{}
set := flag.NewFlagSet("test", 0)
_ = fl.Apply(set)
ctx := &Context{
parentContext: &Context{
flagSet: set,
},
flagSet: flag.NewFlagSet("empty", 0),
}
expected := []uint64(nil)
if !reflect.DeepEqual(ctx.Uint64Slice("numbers"), expected) {
t.Errorf("child context unable to view parent flag: %v != %v", expected, ctx.Uint64Slice("numbers"))
}
}
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 {
f := &Float64Flag{Name: test.name, Value: 0.1}
output := f.String()
if output != test.expected {
t.Errorf("%q does not match %q", output, test.expected)
}
}
}
func TestFloat64FlagWithEnvVarHelpOutput(t *testing.T) {
defer resetEnv(os.Environ())
os.Clearenv()
_ = os.Setenv("APP_BAZ", "99.4")
for _, test := range float64FlagTests {
fl := &Float64Flag{Name: test.name, EnvVars: []string{"APP_BAZ"}}
output := fl.String()
expectedSuffix := withEnvHint([]string{"APP_BAZ"}, "")
if !strings.HasSuffix(output, expectedSuffix) {
t.Errorf("%s does not end with"+expectedSuffix, output)
}
}
}
func TestFloat64FlagApply_SetsAllNames(t *testing.T) {
v := 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))
}
func TestFloat64FlagValueFromContext(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Float64("myflag", 1.23, "doc")
ctx := NewContext(nil, set, nil)
f := &Float64Flag{Name: "myflag"}
expect(t, f.Get(ctx), 1.23)
}
var float64SliceFlagTests = []struct {
name string
aliases []string
value *Float64Slice
expected string
}{
{"heads", nil, NewFloat64Slice(), "--heads value [ --heads value ]\t"},
{"H", nil, NewFloat64Slice(), "-H value [ -H value ]\t"},
{"heads", []string{"H"}, NewFloat64Slice(0.1234, -10.5),
"--heads value, -H value [ --heads value, -H value ]\t(default: 0.1234, -10.5)"},
}
func TestFloat64SliceFlagHelpOutput(t *testing.T) {
for _, test := range float64SliceFlagTests {
fl := Float64SliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value}
output := fl.String()
if output != test.expected {
t.Errorf("%q does not match %q", output, test.expected)
}
}
}
func TestFloat64SliceFlagWithEnvVarHelpOutput(t *testing.T) {
defer resetEnv(os.Environ())
os.Clearenv()
_ = os.Setenv("APP_SMURF", "0.1234,-10.5")
for _, test := range float64SliceFlagTests {
fl := Float64SliceFlag{Name: test.name, Value: test.value, EnvVars: []string{"APP_SMURF"}}
output := fl.String()
expectedSuffix := withEnvHint([]string{"APP_SMURF"}, "")
if !strings.HasSuffix(output, expectedSuffix) {
t.Errorf("%q does not end with"+expectedSuffix, output)
}
}
}
func TestFloat64SliceFlagApply_SetsAllNames(t *testing.T) {
fl := Float64SliceFlag{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)
}
func TestFloat64SliceFlagApply_UsesEnvValues_noDefault(t *testing.T) {
defer resetEnv(os.Environ())
os.Clearenv()
_ = os.Setenv("MY_GOAT", "1.0 , 2.0")
var val Float64Slice
fl := Float64SliceFlag{Name: "goat", EnvVars: []string{"MY_GOAT"}, Value: &val}
set := flag.NewFlagSet("test", 0)
_ = fl.Apply(set)
err := set.Parse(nil)
expect(t, err, nil)
expect(t, val.Value(), []float64(nil))
expect(t, set.Lookup("goat").Value.(*Float64Slice).Value(), []float64{1, 2})
}
func TestFloat64SliceFlagApply_UsesEnvValues_withDefault(t *testing.T) {
defer resetEnv(os.Environ())
os.Clearenv()
_ = os.Setenv("MY_GOAT", "1.0 , 2.0")
val := NewFloat64Slice(3.0, 4.0)
fl := Float64SliceFlag{Name: "goat", EnvVars: []string{"MY_GOAT"}, Value: val}
set := flag.NewFlagSet("test", 0)
_ = fl.Apply(set)
err := set.Parse(nil)
expect(t, err, nil)
expect(t, val.Value(), []float64{3, 4})
expect(t, set.Lookup("goat").Value.(*Float64Slice).Value(), []float64{1, 2})
}
func TestFloat64SliceFlagApply_DefaultValueWithDestination(t *testing.T) {
defValue := []float64{1.0, 2.0}
fl := Float64SliceFlag{Name: "country", Value: NewFloat64Slice(defValue...), Destination: NewFloat64Slice(3)}
set := flag.NewFlagSet("test", 0)
_ = fl.Apply(set)
err := set.Parse([]string{})
expect(t, err, nil)
expect(t, defValue, fl.Destination.Value())
}
func TestFloat64SliceFlagValueFromContext(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Var(NewFloat64Slice(1.23, 4.56), "myflag", "doc")
ctx := NewContext(nil, set, nil)
f := &Float64SliceFlag{Name: "myflag"}
expect(t, f.Get(ctx), []float64{1.23, 4.56})
}
func TestFloat64SliceFlagApply_ParentContext(t *testing.T) {
_ = (&App{
Flags: []Flag{
&Float64SliceFlag{Name: "numbers", Aliases: []string{"n"}, Value: NewFloat64Slice(1.0, 2.0, 3.0)},
},
Commands: []*Command{
{
Name: "child",
Action: func(ctx *Context) error {
expected := []float64{1.0, 2.0, 3.0}
if !reflect.DeepEqual(ctx.Float64Slice("numbers"), expected) {
t.Errorf("child context unable to view parent flag: %v != %v", expected, ctx.Float64Slice("numbers"))
}
if !reflect.DeepEqual(ctx.Float64Slice("n"), expected) {
t.Errorf("child context unable to view parent flag: %v != %v", expected, ctx.Float64Slice("n"))
}
return nil
},
},
},
}).Run([]string{"run", "child"})
}
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 {
fl := &GenericFlag{Name: test.name, Value: test.value, Usage: "test flag"}
// create a temporary flag set to apply
tfs := flag.NewFlagSet("test", 0)
fl.Apply(tfs)
output := fl.String()
if output != test.expected {
t.Errorf("%q does not match %q", output, test.expected)
}
}
}
func TestGenericFlagWithEnvVarHelpOutput(t *testing.T) {
defer resetEnv(os.Environ())
os.Clearenv()
_ = os.Setenv("APP_ZAP", "3")
for _, test := range genericFlagTests {
fl := &GenericFlag{Name: test.name, EnvVars: []string{"APP_ZAP"}}
output := fl.String()
expectedSuffix := withEnvHint([]string{"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 TestGenericFlagValueFromContext(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Var(&Parser{"abc", "def"}, "myflag", "doc")
ctx := NewContext(nil, set, nil)
f := &GenericFlag{Name: "myflag"}
expect(t, f.Get(ctx), &Parser{"abc", "def"})
}
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
_ = (&App{
Flags: []Flag{
&StringFlag{
Name: "dest",
Destination: &dest,
},
},
Action: func(ctx *Context) error {
if dest != "10" {
t.Errorf("expected destination String 10")
}
return nil
},
}).Run([]string{"run", "--dest", "10"})
}
func TestParseMultiStringFromEnv(t *testing.T) {
defer resetEnv(os.Environ())
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) {
defer resetEnv(os.Environ())
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 TestParseMultiStringSliceWithDestination(t *testing.T) {
dest := &StringSlice{}
_ = (&App{
Flags: []Flag{
&StringSliceFlag{Name: "serve", Aliases: []string{"s"}, Destination: dest},
},
Action: func(ctx *Context) error {
expected := []string{"10", "20"}
if !reflect.DeepEqual(dest.slice, expected) {
t.Errorf("main name not set: %v != %v", expected, ctx.StringSlice("serve"))
}
if !reflect.DeepEqual(dest.slice, expected) {
t.Errorf("short name not set: %v != %v", expected, ctx.StringSlice("s"))
}
return nil
},
}).Run([]string{"run", "-s", "10", "-s", "20"})
}
func TestParseMultiStringSliceWithDestinationAndEnv(t *testing.T) {
defer resetEnv(os.Environ())
os.Clearenv()
_ = os.Setenv("APP_INTERVALS", "20,30,40")
dest := &StringSlice{}
_ = (&App{
Flags: []Flag{
&StringSliceFlag{Name: "serve", Aliases: []string{"s"}, Destination: dest, EnvVars: []string{"APP_INTERVALS"}},
},
Action: func(ctx *Context) error {
expected := []string{"10", "20"}
if !reflect.DeepEqual(dest.slice, expected) {
t.Errorf("main name not set: %v != %v", expected, ctx.StringSlice("serve"))
}
if !reflect.DeepEqual(dest.slice, expected) {
t.Errorf("short name not set: %v != %v", expected, ctx.StringSlice("s"))
}
return nil
},
}).Run([]string{"run", "-s", "10", "-s", "20"})
}
func TestParseMultiFloat64SliceWithDestinationAndEnv(t *testing.T) {
defer resetEnv(os.Environ())
os.Clearenv()
_ = os.Setenv("APP_INTERVALS", "20,30,40")
dest := &Float64Slice{}
_ = (&App{
Flags: []Flag{
&Float64SliceFlag{Name: "serve", Aliases: []string{"s"}, Destination: dest, EnvVars: []string{"APP_INTERVALS"}},
},
Action: func(ctx *Context) error {
expected := []float64{10, 20}
if !reflect.DeepEqual(dest.slice, expected) {
t.Errorf("main name not set: %v != %v", expected, ctx.StringSlice("serve"))
}
if !reflect.DeepEqual(dest.slice, expected) {
t.Errorf("short name not set: %v != %v", expected, ctx.StringSlice("s"))
}
return nil
},
}).Run([]string{"run", "-s", "10", "-s", "20"})
}
func TestParseMultiInt64SliceWithDestinationAndEnv(t *testing.T) {
defer resetEnv(os.Environ())
os.Clearenv()
_ = os.Setenv("APP_INTERVALS", "20,30,40")
dest := &Int64Slice{}
_ = (&App{
Flags: []Flag{
&Int64SliceFlag{Name: "serve", Aliases: []string{"s"}, Destination: dest, EnvVars: []string{"APP_INTERVALS"}},
},
Action: func(ctx *Context) error {
expected := []int64{10, 20}
if !reflect.DeepEqual(dest.slice, expected) {
t.Errorf("main name not set: %v != %v", expected, ctx.StringSlice("serve"))
}
if !reflect.DeepEqual(dest.slice, expected) {
t.Errorf("short name not set: %v != %v", expected, ctx.StringSlice("s"))
}
return nil
},
}).Run([]string{"run", "-s", "10", "-s", "20"})
}
func TestParseMultiIntSliceWithDestinationAndEnv(t *testing.T) {
defer resetEnv(os.Environ())
os.Clearenv()
_ = os.Setenv("APP_INTERVALS", "20,30,40")
dest := &IntSlice{}
_ = (&App{
Flags: []Flag{
&IntSliceFlag{Name: "serve", Aliases: []string{"s"}, Destination: dest, EnvVars: []string{"APP_INTERVALS"}},
},
Action: func(ctx *Context) error {
expected := []int{10, 20}
if !reflect.DeepEqual(dest.slice, expected) {
t.Errorf("main name not set: %v != %v", expected, ctx.StringSlice("serve"))
}
if !reflect.DeepEqual(dest.slice, 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) {
defer resetEnv(os.Environ())
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) {
defer resetEnv(os.Environ())
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) {
defer resetEnv(os.Environ())
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) {
defer resetEnv(os.Environ())
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 TestParseMultiStringSliceFromEnvWithDestination(t *testing.T) {
defer resetEnv(os.Environ())
os.Clearenv()
_ = os.Setenv("APP_INTERVALS", "20,30,40")
dest := &StringSlice{}
_ = (&App{
Flags: []Flag{
&StringSliceFlag{Name: "intervals", Aliases: []string{"i"}, Destination: dest, EnvVars: []string{"APP_INTERVALS"}},
},
Action: func(ctx *Context) error {
if !reflect.DeepEqual(dest.slice, []string{"20", "30", "40"}) {
t.Errorf("main name not set from env")
}
if !reflect.DeepEqual(dest.slice, []string{"20", "30", "40"}) {
t.Errorf("short name not set from env")
}
return nil
},
}).Run([]string{"run"})
}
func TestParseMultiInt(t *testing.T) {
_ = (&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
},
}).Run([]string{"run", "-s", "10"})
}
func TestParseDestinationInt(t *testing.T) {
var dest int
_ = (&App{
Flags: []Flag{
&IntFlag{
Name: "dest",
Destination: &dest,
},
},
Action: func(ctx *Context) error {
if dest != 10 {
t.Errorf("expected destination Int 10")
}
return nil
},
}).Run([]string{"run", "--dest", "10"})
}
func TestParseMultiIntFromEnv(t *testing.T) {
defer resetEnv(os.Environ())
os.Clearenv()
_ = os.Setenv("APP_TIMEOUT_SECONDS", "10")
_ = (&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
},
}).Run([]string{"run"})
}
func TestParseMultiIntFromEnvCascade(t *testing.T) {
defer resetEnv(os.Environ())
os.Clearenv()
_ = os.Setenv("APP_TIMEOUT_SECONDS", "10")
_ = (&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
},
}).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) {
defer resetEnv(os.Environ())
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) {
defer resetEnv(os.Environ())
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) {
defer resetEnv(os.Environ())
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")
<