...

Source file src/github.com/urfave/cli/v2/flag_test.go

Documentation: github.com/urfave/cli/v2

     1  package cli
     2  
     3  import (
     4  	"flag"
     5  	"fmt"
     6  	"io"
     7  	"os"
     8  	"reflect"
     9  	"regexp"
    10  	"strings"
    11  	"testing"
    12  	"time"
    13  )
    14  
    15  var boolFlagTests = []struct {
    16  	name     string
    17  	expected string
    18  }{
    19  	{"help", "--help\t(default: false)"},
    20  	{"h", "-h\t(default: false)"},
    21  }
    22  
    23  func resetEnv(env []string) {
    24  	for _, e := range env {
    25  		fields := strings.SplitN(e, "=", 2)
    26  		os.Setenv(fields[0], fields[1])
    27  	}
    28  }
    29  
    30  func TestBoolFlagHelpOutput(t *testing.T) {
    31  	for _, test := range boolFlagTests {
    32  		fl := &BoolFlag{Name: test.name}
    33  		output := fl.String()
    34  
    35  		if output != test.expected {
    36  			t.Errorf("%q does not match %q", output, test.expected)
    37  		}
    38  	}
    39  }
    40  
    41  func TestBoolFlagApply_SetsAllNames(t *testing.T) {
    42  	v := false
    43  	fl := BoolFlag{Name: "wat", Aliases: []string{"W", "huh"}, Destination: &v}
    44  	set := flag.NewFlagSet("test", 0)
    45  	if err := fl.Apply(set); err != nil {
    46  		t.Error(err)
    47  	}
    48  
    49  	err := set.Parse([]string{"--wat", "-W", "--huh"})
    50  	expect(t, err, nil)
    51  	expect(t, v, true)
    52  }
    53  
    54  func TestBoolFlagValueFromContext(t *testing.T) {
    55  	set := flag.NewFlagSet("test", 0)
    56  	set.Bool("trueflag", true, "doc")
    57  	set.Bool("falseflag", false, "doc")
    58  	ctx := NewContext(nil, set, nil)
    59  	tf := &BoolFlag{Name: "trueflag"}
    60  	ff := &BoolFlag{Name: "falseflag"}
    61  	expect(t, tf.Get(ctx), true)
    62  	expect(t, ff.Get(ctx), false)
    63  }
    64  
    65  func TestBoolFlagApply_SetsCount(t *testing.T) {
    66  	v := false
    67  	count := 0
    68  	app := &App{
    69  		Name: "foo",
    70  		Flags: []Flag{
    71  			&BoolFlag{Name: "wat", Aliases: []string{"W", "huh"}, Destination: &v, Count: &count},
    72  		},
    73  	}
    74  
    75  	err := app.Run([]string{"foo", "--wat", "-W", "--huh"})
    76  	if err == nil {
    77  		t.Error("Expected error")
    78  	} else if es := err.Error(); !strings.Contains(es, "Cannot use two forms of the same flag") {
    79  		t.Errorf("Unexpected error %s", es)
    80  	}
    81  
    82  	v = false
    83  	count = 0
    84  
    85  	err = app.Run([]string{"foo", "--wat", "--wat", "--wat"})
    86  	expect(t, err, nil)
    87  	expect(t, v, true)
    88  	expect(t, count, 3)
    89  }
    90  
    91  func TestBoolFlagCountFromContext(t *testing.T) {
    92  
    93  	boolCountTests := []struct {
    94  		input         []string
    95  		expectedVal   bool
    96  		expectedCount int
    97  	}{
    98  		{
    99  			input:         []string{"foo", "-tf"},
   100  			expectedVal:   true,
   101  			expectedCount: 1,
   102  		},
   103  		{
   104  			input:         []string{"foo", "-tf", "-tf", "-tf"},
   105  			expectedVal:   true,
   106  			expectedCount: 3,
   107  		},
   108  		{
   109  			input:         []string{},
   110  			expectedVal:   false,
   111  			expectedCount: 0,
   112  		},
   113  	}
   114  
   115  	for _, bct := range boolCountTests {
   116  		tf := &BoolFlag{Name: "tf", Aliases: []string{"w", "huh"}}
   117  		app := &App{
   118  			Name:  "foo",
   119  			Flags: []Flag{tf},
   120  			Action: func(ctx *Context) error {
   121  				expect(t, tf.Get(ctx), bct.expectedVal)
   122  				expect(t, ctx.Count("tf"), bct.expectedCount)
   123  				expect(t, ctx.Count("w"), bct.expectedCount)
   124  				expect(t, ctx.Count("huh"), bct.expectedCount)
   125  				return nil
   126  			},
   127  		}
   128  
   129  		err := app.Run(bct.input)
   130  		expect(t, err, nil)
   131  
   132  	}
   133  }
   134  
   135  func TestFlagsFromEnv(t *testing.T) {
   136  	newSetFloat64Slice := func(defaults ...float64) Float64Slice {
   137  		s := NewFloat64Slice(defaults...)
   138  		s.hasBeenSet = false
   139  		return *s
   140  	}
   141  
   142  	newSetIntSlice := func(defaults ...int) IntSlice {
   143  		s := NewIntSlice(defaults...)
   144  		s.hasBeenSet = false
   145  		return *s
   146  	}
   147  
   148  	newSetUintSlice := func(defaults ...uint) UintSlice {
   149  		s := NewUintSlice(defaults...)
   150  		s.hasBeenSet = false
   151  		return *s
   152  	}
   153  
   154  	newSetInt64Slice := func(defaults ...int64) Int64Slice {
   155  		s := NewInt64Slice(defaults...)
   156  		s.hasBeenSet = false
   157  		return *s
   158  	}
   159  
   160  	newSetUint64Slice := func(defaults ...uint64) Uint64Slice {
   161  		s := NewUint64Slice(defaults...)
   162  		s.hasBeenSet = false
   163  		return *s
   164  	}
   165  
   166  	newSetStringSlice := func(defaults ...string) StringSlice {
   167  		s := NewStringSlice(defaults...)
   168  		s.hasBeenSet = false
   169  		return *s
   170  	}
   171  	newSetStringSliceKeepSpace := func(defaults ...string) StringSlice {
   172  		s := newSetStringSlice(defaults...)
   173  		s.keepSpace = true
   174  		return s
   175  	}
   176  
   177  	var flagTests = []struct {
   178  		input     string
   179  		output    interface{}
   180  		flag      Flag
   181  		errRegexp string
   182  	}{
   183  		{"", false, &BoolFlag{Name: "debug", EnvVars: []string{"DEBUG"}}, ""},
   184  		{"1", true, &BoolFlag{Name: "debug", EnvVars: []string{"DEBUG"}}, ""},
   185  		{"false", false, &BoolFlag{Name: "debug", EnvVars: []string{"DEBUG"}}, ""},
   186  		{"foobar", true, &BoolFlag{Name: "debug", EnvVars: []string{"DEBUG"}}, `could not parse "foobar" as bool value from environment variable "DEBUG" for flag debug: .*`},
   187  
   188  		{"1s", 1 * time.Second, &DurationFlag{Name: "time", EnvVars: []string{"TIME"}}, ""},
   189  		{"foobar", false, &DurationFlag{Name: "time", EnvVars: []string{"TIME"}}, `could not parse "foobar" as duration value from environment variable "TIME" for flag time: .*`},
   190  
   191  		{"1.2", 1.2, &Float64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}}, ""},
   192  		{"1", 1.0, &Float64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}}, ""},
   193  		{"foobar", 0, &Float64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}}, `could not parse "foobar" as float64 value from environment variable "SECONDS" for flag seconds: .*`},
   194  
   195  		{"1", int64(1), &Int64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}}, ""},
   196  		{"1.2", 0, &Int64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}}, `could not parse "1.2" as int value from environment variable "SECONDS" for flag seconds: .*`},
   197  		{"foobar", 0, &Int64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}}, `could not parse "foobar" as int value from environment variable "SECONDS" for flag seconds: .*`},
   198  
   199  		{"1", 1, &IntFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, ""},
   200  		{"08", 8, &IntFlag{Name: "seconds", EnvVars: []string{"SECONDS"}, Base: 10}, ""},
   201  		{"755", 493, &IntFlag{Name: "seconds", EnvVars: []string{"SECONDS"}, Base: 8}, ""},
   202  		{"deadBEEF", 3735928559, &IntFlag{Name: "seconds", EnvVars: []string{"SECONDS"}, Base: 16}, ""},
   203  		{"08", 0, &IntFlag{Name: "seconds", EnvVars: []string{"SECONDS"}, Base: 0}, `could not parse "08" as int value from environment variable "SECONDS" for flag seconds: .*`},
   204  		{"1.2", 0, &IntFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, `could not parse "1.2" as int value from environment variable "SECONDS" for flag seconds: .*`},
   205  		{"foobar", 0, &IntFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, `could not parse "foobar" as int value from environment variable "SECONDS" for flag seconds: .*`},
   206  
   207  		{"1.0,2", newSetFloat64Slice(1, 2), &Float64SliceFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, ""},
   208  		{"foobar", newSetFloat64Slice(), &Float64SliceFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, `could not parse "foobar" as float64 slice value from environment variable "SECONDS" for flag seconds: .*`},
   209  
   210  		{"1,2", newSetIntSlice(1, 2), &IntSliceFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, ""},
   211  		{"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: .*`},
   212  		{"foobar", newSetIntSlice(), &IntSliceFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, `could not parse "foobar" as int slice value from environment variable "SECONDS" for flag seconds: .*`},
   213  
   214  		{"1,2", newSetUintSlice(1, 2), &UintSliceFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, ""},
   215  		{"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: .*`},
   216  		{"foobar", newSetUintSlice(), &UintSliceFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, `could not parse "foobar" as uint slice value from environment variable "SECONDS" for flag seconds: .*`},
   217  
   218  		{"1,2", newSetInt64Slice(1, 2), &Int64SliceFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, ""},
   219  		{"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: .*`},
   220  		{"foobar", newSetInt64Slice(), &Int64SliceFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, `could not parse "foobar" as int64 slice value from environment variable "SECONDS" for flag seconds: .*`},
   221  
   222  		{"1,2", newSetUint64Slice(1, 2), &Uint64SliceFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, ""},
   223  		{"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: .*`},
   224  		{"foobar", newSetUint64Slice(), &Uint64SliceFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, `could not parse "foobar" as uint64 slice value from environment variable "SECONDS" for flag seconds: .*`},
   225  
   226  		{"foo", "foo", &StringFlag{Name: "name", EnvVars: []string{"NAME"}}, ""},
   227  		{"path", "path", &PathFlag{Name: "path", EnvVars: []string{"PATH"}}, ""},
   228  
   229  		{"foo,bar", newSetStringSlice("foo", "bar"), &StringSliceFlag{Name: "names", EnvVars: []string{"NAMES"}}, ""},
   230  		{" space ", newSetStringSliceKeepSpace(" space "), &StringSliceFlag{Name: "names", KeepSpace: true, EnvVars: []string{"NAMES"}}, ""},
   231  		{" no space ", newSetStringSlice("no space"), &StringSliceFlag{Name: "names", EnvVars: []string{"NAMES"}}, ""},
   232  
   233  		{"1", uint(1), &UintFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, ""},
   234  		{"08", uint(8), &UintFlag{Name: "seconds", EnvVars: []string{"SECONDS"}, Base: 10}, ""},
   235  		{"755", uint(493), &UintFlag{Name: "seconds", EnvVars: []string{"SECONDS"}, Base: 8}, ""},
   236  		{"deadBEEF", uint(3735928559), &UintFlag{Name: "seconds", EnvVars: []string{"SECONDS"}, Base: 16}, ""},
   237  		{"08", 0, &UintFlag{Name: "seconds", EnvVars: []string{"SECONDS"}, Base: 0}, `could not parse "08" as uint value from environment variable "SECONDS" for flag seconds: .*`},
   238  		{"1.2", 0, &UintFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, `could not parse "1.2" as uint value from environment variable "SECONDS" for flag seconds: .*`},
   239  		{"foobar", 0, &UintFlag{Name: "seconds", EnvVars: []string{"SECONDS"}}, `could not parse "foobar" as uint value from environment variable "SECONDS" for flag seconds: .*`},
   240  
   241  		{"1", uint64(1), &Uint64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}}, ""},
   242  		{"08", uint64(8), &Uint64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}, Base: 10}, ""},
   243  		{"755", uint64(493), &Uint64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}, Base: 8}, ""},
   244  		{"deadBEEF", uint64(3735928559), &Uint64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}, Base: 16}, ""},
   245  		{"08", 0, &Uint64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}, Base: 0}, `could not parse "08" as uint64 value from environment variable "SECONDS" for flag seconds: .*`},
   246  		{"1.2", 0, &Uint64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}}, `could not parse "1.2" as uint64 value from environment variable "SECONDS" for flag seconds: .*`},
   247  		{"foobar", 0, &Uint64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}}, `could not parse "foobar" as uint64 value from environment variable "SECONDS" for flag seconds: .*`},
   248  
   249  		{"foo,bar", &Parser{"foo", "bar"}, &GenericFlag{Name: "names", Value: &Parser{}, EnvVars: []string{"NAMES"}}, ""},
   250  	}
   251  
   252  	for i, test := range flagTests {
   253  		defer resetEnv(os.Environ())
   254  		os.Clearenv()
   255  
   256  		f, ok := test.flag.(DocGenerationFlag)
   257  		if !ok {
   258  			t.Errorf("flag %v needs to implement DocGenerationFlag to retrieve env vars", test.flag)
   259  		}
   260  		envVarSlice := f.GetEnvVars()
   261  		_ = os.Setenv(envVarSlice[0], test.input)
   262  
   263  		a := App{
   264  			Flags: []Flag{test.flag},
   265  			Action: func(ctx *Context) error {
   266  				if !reflect.DeepEqual(ctx.Value(test.flag.Names()[0]), test.output) {
   267  					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]))
   268  				}
   269  				if !f.IsSet() {
   270  					t.Errorf("Flag %s not set", f.Names()[0])
   271  				}
   272  
   273  				// check that flag names are returned when set via env as well
   274  				if !reflect.DeepEqual(ctx.FlagNames(), test.flag.Names()) {
   275  					t.Errorf("Not enough flag names %+v", ctx.FlagNames())
   276  				}
   277  				return nil
   278  			},
   279  		}
   280  
   281  		err := a.Run([]string{"run"})
   282  
   283  		if test.errRegexp != "" {
   284  			if err == nil {
   285  				t.Errorf("expected error to match %q, got none", test.errRegexp)
   286  			} else {
   287  				if matched, _ := regexp.MatchString(test.errRegexp, err.Error()); !matched {
   288  					t.Errorf("expected error to match %q, got error %s", test.errRegexp, err)
   289  				}
   290  			}
   291  		} else {
   292  			if err != nil && test.errRegexp == "" {
   293  				t.Errorf("expected no error got %q", err)
   294  			}
   295  		}
   296  	}
   297  }
   298  
   299  type nodocFlag struct {
   300  	Flag
   301  
   302  	Name string
   303  }
   304  
   305  func TestFlagStringifying(t *testing.T) {
   306  	for _, tc := range []struct {
   307  		name     string
   308  		fl       Flag
   309  		expected string
   310  	}{
   311  		{
   312  			name:     "bool-flag",
   313  			fl:       &BoolFlag{Name: "vividly"},
   314  			expected: "--vividly\t(default: false)",
   315  		},
   316  		{
   317  			name:     "bool-flag-with-default-text",
   318  			fl:       &BoolFlag{Name: "wildly", DefaultText: "scrambled"},
   319  			expected: "--wildly\t(default: scrambled)",
   320  		},
   321  		{
   322  			name:     "duration-flag",
   323  			fl:       &DurationFlag{Name: "scream-for"},
   324  			expected: "--scream-for value\t(default: 0s)",
   325  		},
   326  		{
   327  			name:     "duration-flag-with-default-text",
   328  			fl:       &DurationFlag{Name: "feels-about", DefaultText: "whimsically"},
   329  			expected: "--feels-about value\t(default: whimsically)",
   330  		},
   331  		{
   332  			name:     "float64-flag",
   333  			fl:       &Float64Flag{Name: "arduous"},
   334  			expected: "--arduous value\t(default: 0)",
   335  		},
   336  		{
   337  			name:     "float64-flag-with-default-text",
   338  			fl:       &Float64Flag{Name: "filibuster", DefaultText: "42"},
   339  			expected: "--filibuster value\t(default: 42)",
   340  		},
   341  		{
   342  			name:     "float64-slice-flag",
   343  			fl:       &Float64SliceFlag{Name: "pizzas"},
   344  			expected: "--pizzas value [ --pizzas value ]\t",
   345  		},
   346  		{
   347  			name:     "float64-slice-flag-with-default-text",
   348  			fl:       &Float64SliceFlag{Name: "pepperonis", DefaultText: "shaved"},
   349  			expected: "--pepperonis value [ --pepperonis value ]\t(default: shaved)",
   350  		},
   351  		{
   352  			name:     "generic-flag",
   353  			fl:       &GenericFlag{Name: "yogurt"},
   354  			expected: "--yogurt value\t",
   355  		},
   356  		{
   357  			name:     "generic-flag-with-default-text",
   358  			fl:       &GenericFlag{Name: "ricotta", DefaultText: "plops"},
   359  			expected: "--ricotta value\t(default: plops)",
   360  		},
   361  		{
   362  			name:     "int-flag",
   363  			fl:       &IntFlag{Name: "grubs"},
   364  			expected: "--grubs value\t(default: 0)",
   365  		},
   366  		{
   367  			name:     "int-flag-with-default-text",
   368  			fl:       &IntFlag{Name: "poisons", DefaultText: "11ty"},
   369  			expected: "--poisons value\t(default: 11ty)",
   370  		},
   371  		{
   372  			name:     "int-slice-flag",
   373  			fl:       &IntSliceFlag{Name: "pencils"},
   374  			expected: "--pencils value [ --pencils value ]\t",
   375  		},
   376  		{
   377  			name:     "int-slice-flag-with-default-text",
   378  			fl:       &IntFlag{Name: "pens", DefaultText: "-19"},
   379  			expected: "--pens value\t(default: -19)",
   380  		},
   381  		{
   382  			name:     "uint-slice-flag",
   383  			fl:       &UintSliceFlag{Name: "pencils"},
   384  			expected: "--pencils value [ --pencils value ]\t",
   385  		},
   386  		{
   387  			name:     "uint-slice-flag-with-default-text",
   388  			fl:       &UintFlag{Name: "pens", DefaultText: "29"},
   389  			expected: "--pens value\t(default: 29)",
   390  		},
   391  		{
   392  			name:     "int64-flag",
   393  			fl:       &Int64Flag{Name: "flume"},
   394  			expected: "--flume value\t(default: 0)",
   395  		},
   396  		{
   397  			name:     "int64-flag-with-default-text",
   398  			fl:       &Int64Flag{Name: "shattering", DefaultText: "22"},
   399  			expected: "--shattering value\t(default: 22)",
   400  		},
   401  		{
   402  			name:     "int64-slice-flag",
   403  			fl:       &Int64SliceFlag{Name: "drawers"},
   404  			expected: "--drawers value [ --drawers value ]\t",
   405  		},
   406  		{
   407  			name:     "int64-slice-flag-with-default-text",
   408  			fl:       &Int64SliceFlag{Name: "handles", DefaultText: "-2"},
   409  			expected: "--handles value [ --handles value ]\t(default: -2)",
   410  		},
   411  		{
   412  			name:     "uint64-slice-flag",
   413  			fl:       &Uint64SliceFlag{Name: "drawers"},
   414  			expected: "--drawers value [ --drawers value ]\t",
   415  		},
   416  		{
   417  			name:     "uint64-slice-flag-with-default-text",
   418  			fl:       &Uint64SliceFlag{Name: "handles", DefaultText: "-2"},
   419  			expected: "--handles value [ --handles value ]\t(default: -2)",
   420  		},
   421  		{
   422  			name:     "path-flag",
   423  			fl:       &PathFlag{Name: "soup"},
   424  			expected: "--soup value\t",
   425  		},
   426  		{
   427  			name:     "path-flag-with-default-text",
   428  			fl:       &PathFlag{Name: "stew", DefaultText: "charred/beans"},
   429  			expected: "--stew value\t(default: charred/beans)",
   430  		},
   431  		{
   432  			name:     "string-flag",
   433  			fl:       &StringFlag{Name: "arf-sound"},
   434  			expected: "--arf-sound value\t",
   435  		},
   436  		{
   437  			name:     "string-flag-with-default-text",
   438  			fl:       &StringFlag{Name: "woof-sound", DefaultText: "urp"},
   439  			expected: "--woof-sound value\t(default: urp)",
   440  		},
   441  		{
   442  			name:     "string-slice-flag",
   443  			fl:       &StringSliceFlag{Name: "meow-sounds"},
   444  			expected: "--meow-sounds value [ --meow-sounds value ]\t",
   445  		},
   446  		{
   447  			name:     "string-slice-flag-with-default-text",
   448  			fl:       &StringSliceFlag{Name: "moo-sounds", DefaultText: "awoo"},
   449  			expected: "--moo-sounds value [ --moo-sounds value ]\t(default: awoo)",
   450  		},
   451  		{
   452  			name:     "timestamp-flag",
   453  			fl:       &TimestampFlag{Name: "eating"},
   454  			expected: "--eating value\t",
   455  		},
   456  		{
   457  			name:     "timestamp-flag-with-default-text",
   458  			fl:       &TimestampFlag{Name: "sleeping", DefaultText: "earlier"},
   459  			expected: "--sleeping value\t(default: earlier)",
   460  		},
   461  		{
   462  			name:     "uint-flag",
   463  			fl:       &UintFlag{Name: "jars"},
   464  			expected: "--jars value\t(default: 0)",
   465  		},
   466  		{
   467  			name:     "uint-flag-with-default-text",
   468  			fl:       &UintFlag{Name: "bottles", DefaultText: "99"},
   469  			expected: "--bottles value\t(default: 99)",
   470  		},
   471  		{
   472  			name:     "uint64-flag",
   473  			fl:       &Uint64Flag{Name: "cans"},
   474  			expected: "--cans value\t(default: 0)",
   475  		},
   476  		{
   477  			name:     "uint64-flag-with-default-text",
   478  			fl:       &UintFlag{Name: "tubes", DefaultText: "13"},
   479  			expected: "--tubes value\t(default: 13)",
   480  		},
   481  		{
   482  			name:     "nodoc-flag",
   483  			fl:       &nodocFlag{Name: "scarecrow"},
   484  			expected: "",
   485  		},
   486  	} {
   487  		t.Run(tc.name, func(ct *testing.T) {
   488  			s := stringifyFlag(tc.fl)
   489  			if s != tc.expected {
   490  				ct.Errorf("stringified flag %q does not match expected %q", s, tc.expected)
   491  			}
   492  		})
   493  	}
   494  }
   495  
   496  var stringFlagTests = []struct {
   497  	name     string
   498  	aliases  []string
   499  	usage    string
   500  	value    string
   501  	expected string
   502  }{
   503  	{"foo", nil, "", "", "--foo value\t"},
   504  	{"f", nil, "", "", "-f value\t"},
   505  	{"f", nil, "The total `foo` desired", "all", "-f foo\tThe total foo desired (default: \"all\")"},
   506  	{"test", nil, "", "Something", "--test value\t(default: \"Something\")"},
   507  	{"config", []string{"c"}, "Load configuration from `FILE`", "", "--config FILE, -c FILE\tLoad configuration from FILE"},
   508  	{"config", []string{"c"}, "Load configuration from `CONFIG`", "config.json", "--config CONFIG, -c CONFIG\tLoad configuration from CONFIG (default: \"config.json\")"},
   509  }
   510  
   511  func TestStringFlagHelpOutput(t *testing.T) {
   512  	for _, test := range stringFlagTests {
   513  		fl := &StringFlag{Name: test.name, Aliases: test.aliases, Usage: test.usage, Value: test.value}
   514  		// create a tmp flagset
   515  		tfs := flag.NewFlagSet("test", 0)
   516  		if err := fl.Apply(tfs); err != nil {
   517  			t.Error(err)
   518  		}
   519  		output := fl.String()
   520  
   521  		if output != test.expected {
   522  			t.Errorf("%q does not match %q", output, test.expected)
   523  		}
   524  	}
   525  }
   526  
   527  func TestStringFlagDefaultText(t *testing.T) {
   528  	fl := &StringFlag{Name: "foo", Aliases: nil, Usage: "amount of `foo` requested", Value: "none", DefaultText: "all of it"}
   529  	expected := "--foo foo\tamount of foo requested (default: all of it)"
   530  	output := fl.String()
   531  
   532  	if output != expected {
   533  		t.Errorf("%q does not match %q", output, expected)
   534  	}
   535  }
   536  
   537  func TestStringFlagWithEnvVarHelpOutput(t *testing.T) {
   538  	defer resetEnv(os.Environ())
   539  	os.Clearenv()
   540  	_ = os.Setenv("APP_FOO", "derp")
   541  
   542  	for _, test := range stringFlagTests {
   543  		fl := &StringFlag{Name: test.name, Aliases: test.aliases, Value: test.value, EnvVars: []string{"APP_FOO"}}
   544  		output := fl.String()
   545  
   546  		expectedSuffix := withEnvHint([]string{"APP_FOO"}, "")
   547  		if !strings.HasSuffix(output, expectedSuffix) {
   548  			t.Errorf("%s does not end with"+expectedSuffix, output)
   549  		}
   550  	}
   551  }
   552  
   553  var _ = []struct {
   554  	name     string
   555  	aliases  []string
   556  	usage    string
   557  	value    string
   558  	prefixer FlagNamePrefixFunc
   559  	expected string
   560  }{
   561  	{name: "foo", usage: "", value: "", prefixer: func(a []string, b string) string {
   562  		return fmt.Sprintf("name: %s, ph: %s", a, b)
   563  	}, expected: "name: foo, ph: value\t"},
   564  	{name: "f", usage: "", value: "", prefixer: func(a []string, b string) string {
   565  		return fmt.Sprintf("name: %s, ph: %s", a, b)
   566  	}, expected: "name: f, ph: value\t"},
   567  	{name: "f", usage: "The total `foo` desired", value: "all", prefixer: func(a []string, b string) string {
   568  		return fmt.Sprintf("name: %s, ph: %s", a, b)
   569  	}, expected: "name: f, ph: foo\tThe total foo desired (default: \"all\")"},
   570  	{name: "test", usage: "", value: "Something", prefixer: func(a []string, b string) string {
   571  		return fmt.Sprintf("name: %s, ph: %s", a, b)
   572  	}, expected: "name: test, ph: value\t(default: \"Something\")"},
   573  	{name: "config", aliases: []string{"c"}, usage: "Load configuration from `FILE`", value: "", prefixer: func(a []string, b string) string {
   574  		return fmt.Sprintf("name: %s, ph: %s", a, b)
   575  	}, expected: "name: config,c, ph: FILE\tLoad configuration from FILE"},
   576  	{name: "config", aliases: []string{"c"}, usage: "Load configuration from `CONFIG`", value: "config.json", prefixer: func(a []string, b string) string {
   577  		return fmt.Sprintf("name: %s, ph: %s", a, b)
   578  	}, expected: "name: config,c, ph: CONFIG\tLoad configuration from CONFIG (default: \"config.json\")"},
   579  }
   580  
   581  func TestStringFlagApply_SetsAllNames(t *testing.T) {
   582  	v := "mmm"
   583  	fl := StringFlag{Name: "hay", Aliases: []string{"H", "hayyy"}, Destination: &v}
   584  	set := flag.NewFlagSet("test", 0)
   585  	if err := fl.Apply(set); err != nil {
   586  		t.Error(err)
   587  	}
   588  
   589  	err := set.Parse([]string{"--hay", "u", "-H", "yuu", "--hayyy", "YUUUU"})
   590  	expect(t, err, nil)
   591  	expect(t, v, "YUUUU")
   592  }
   593  
   594  func TestStringFlagValueFromContext(t *testing.T) {
   595  	set := flag.NewFlagSet("test", 0)
   596  	set.String("myflag", "foobar", "doc")
   597  	ctx := NewContext(nil, set, nil)
   598  	f := &StringFlag{Name: "myflag"}
   599  	expect(t, f.Get(ctx), "foobar")
   600  }
   601  
   602  var pathFlagTests = []struct {
   603  	name     string
   604  	aliases  []string
   605  	usage    string
   606  	value    string
   607  	expected string
   608  }{
   609  	{"f", nil, "", "", "-f value\t"},
   610  	{"f", nil, "Path is the `path` of file", "/path/to/file", "-f path\tPath is the path of file (default: \"/path/to/file\")"},
   611  }
   612  
   613  func TestPathFlagHelpOutput(t *testing.T) {
   614  	for _, test := range pathFlagTests {
   615  		fl := &PathFlag{Name: test.name, Aliases: test.aliases, Usage: test.usage, Value: test.value}
   616  
   617  		// create a temporary flag set to apply
   618  		tfs := flag.NewFlagSet("test", 0)
   619  		if err := fl.Apply(tfs); err != nil {
   620  			t.Error(err)
   621  			return
   622  		}
   623  
   624  		output := fl.String()
   625  
   626  		if output != test.expected {
   627  			t.Errorf("%q does not match %q", output, test.expected)
   628  		}
   629  	}
   630  }
   631  
   632  func TestPathFlagWithEnvVarHelpOutput(t *testing.T) {
   633  	defer resetEnv(os.Environ())
   634  	os.Clearenv()
   635  	_ = os.Setenv("APP_PATH", "/path/to/file")
   636  	for _, test := range pathFlagTests {
   637  		fl := &PathFlag{Name: test.name, Aliases: test.aliases, Value: test.value, EnvVars: []string{"APP_PATH"}}
   638  		output := fl.String()
   639  
   640  		expectedSuffix := withEnvHint([]string{"APP_PATH"}, "")
   641  		if !strings.HasSuffix(output, expectedSuffix) {
   642  			t.Errorf("%s does not end with"+expectedSuffix, output)
   643  		}
   644  	}
   645  }
   646  
   647  func TestPathFlagApply_SetsAllNames(t *testing.T) {
   648  	v := "mmm"
   649  	fl := PathFlag{Name: "path", Aliases: []string{"p", "PATH"}, Destination: &v}
   650  	set := flag.NewFlagSet("test", 0)
   651  	if err := fl.Apply(set); err != nil {
   652  		t.Error(err)
   653  		return
   654  	}
   655  
   656  	err := set.Parse([]string{"--path", "/path/to/file/path", "-p", "/path/to/file/p", "--PATH", "/path/to/file/PATH"})
   657  	expect(t, err, nil)
   658  	expect(t, v, "/path/to/file/PATH")
   659  }
   660  
   661  func TestPathFlagValueFromContext(t *testing.T) {
   662  	set := flag.NewFlagSet("test", 0)
   663  	set.String("myflag", "/my/path", "doc")
   664  	ctx := NewContext(nil, set, nil)
   665  	f := &PathFlag{Name: "myflag"}
   666  	expect(t, f.Get(ctx), "/my/path")
   667  }
   668  
   669  var _ = []struct {
   670  	name     string
   671  	env      string
   672  	hinter   FlagEnvHintFunc
   673  	expected string
   674  }{
   675  	{"foo", "", func(a []string, b string) string {
   676  		return fmt.Sprintf("env: %s, str: %s", a, b)
   677  	}, "env: , str: --foo value\t"},
   678  	{"f", "", func(a []string, b string) string {
   679  		return fmt.Sprintf("env: %s, str: %s", a, b)
   680  	}, "env: , str: -f value\t"},
   681  	{"foo", "ENV_VAR", func(a []string, b string) string {
   682  		return fmt.Sprintf("env: %s, str: %s", a, b)
   683  	}, "env: ENV_VAR, str: --foo value\t"},
   684  	{"f", "ENV_VAR", func(a []string, b string) string {
   685  		return fmt.Sprintf("env: %s, str: %s", a, b)
   686  	}, "env: ENV_VAR, str: -f value\t"},
   687  }
   688  
   689  //func TestFlagEnvHinter(t *testing.T) {
   690  //	defer func() {
   691  //		FlagEnvHinter = withEnvHint
   692  //	}()
   693  //
   694  //	for _, test := range envHintFlagTests {
   695  //		FlagEnvHinter = test.hinter
   696  //		fl := StringFlag{Name: test.name, EnvVars: []string{test.env}}
   697  //		output := fl.String()
   698  //		if output != test.expected {
   699  //			t.Errorf("%q does not match %q", output, test.expected)
   700  //		}
   701  //	}
   702  //}
   703  
   704  var stringSliceFlagTests = []struct {
   705  	name     string
   706  	aliases  []string
   707  	value    *StringSlice
   708  	expected string
   709  }{
   710  	{"foo", nil, NewStringSlice(""), "--foo value [ --foo value ]\t"},
   711  	{"f", nil, NewStringSlice(""), "-f value [ -f value ]\t"},
   712  	{"f", nil, NewStringSlice("Lipstick"), "-f value [ -f value ]\t(default: \"Lipstick\")"},
   713  	{"test", nil, NewStringSlice("Something"), "--test value [ --test value ]\t(default: \"Something\")"},
   714  	{"dee", []string{"d"}, NewStringSlice("Inka", "Dinka", "dooo"), "--dee value, -d value [ --dee value, -d value ]\t(default: \"Inka\", \"Dinka\", \"dooo\")"},
   715  }
   716  
   717  func TestStringSliceFlagHelpOutput(t *testing.T) {
   718  	for _, test := range stringSliceFlagTests {
   719  		f := &StringSliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value}
   720  		output := f.String()
   721  
   722  		if output != test.expected {
   723  			t.Errorf("%q does not match %q", output, test.expected)
   724  		}
   725  	}
   726  }
   727  
   728  func TestStringSliceFlagWithEnvVarHelpOutput(t *testing.T) {
   729  	defer resetEnv(os.Environ())
   730  	os.Clearenv()
   731  	_ = os.Setenv("APP_QWWX", "11,4")
   732  
   733  	for _, test := range stringSliceFlagTests {
   734  		fl := &StringSliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value, EnvVars: []string{"APP_QWWX"}}
   735  		output := fl.String()
   736  
   737  		expectedSuffix := withEnvHint([]string{"APP_QWWX"}, "")
   738  		if !strings.HasSuffix(output, expectedSuffix) {
   739  			t.Errorf("%q does not end with"+expectedSuffix, output)
   740  		}
   741  	}
   742  }
   743  
   744  func TestStringSliceFlagApply_SetsAllNames(t *testing.T) {
   745  	fl := StringSliceFlag{Name: "goat", Aliases: []string{"G", "gooots"}}
   746  	set := flag.NewFlagSet("test", 0)
   747  	if err := fl.Apply(set); err != nil {
   748  		t.Error(err)
   749  	}
   750  
   751  	err := set.Parse([]string{"--goat", "aaa", "-G", "bbb", "--gooots", "eeeee"})
   752  	expect(t, err, nil)
   753  }
   754  
   755  func TestStringSliceFlagApply_UsesEnvValues_noDefault(t *testing.T) {
   756  	defer resetEnv(os.Environ())
   757  	os.Clearenv()
   758  	_ = os.Setenv("MY_GOAT", "vincent van goat,scape goat")
   759  	var val StringSlice
   760  	fl := StringSliceFlag{Name: "goat", EnvVars: []string{"MY_GOAT"}, Value: &val}
   761  	set := flag.NewFlagSet("test", 0)
   762  	if err := fl.Apply(set); err != nil {
   763  		t.Error(err)
   764  	}
   765  
   766  	err := set.Parse(nil)
   767  	expect(t, err, nil)
   768  	expect(t, val.Value(), []string(nil))
   769  	expect(t, set.Lookup("goat").Value.(*StringSlice).Value(), []string{"vincent van goat", "scape goat"})
   770  }
   771  
   772  func TestStringSliceFlagApply_UsesEnvValues_withDefault(t *testing.T) {
   773  	defer resetEnv(os.Environ())
   774  	os.Clearenv()
   775  	_ = os.Setenv("MY_GOAT", "vincent van goat,scape goat")
   776  	val := NewStringSlice(`some default`, `values here`)
   777  	fl := StringSliceFlag{Name: "goat", EnvVars: []string{"MY_GOAT"}, Value: val}
   778  	set := flag.NewFlagSet("test", 0)
   779  	if err := fl.Apply(set); err != nil {
   780  		t.Error(err)
   781  	}
   782  	err := set.Parse(nil)
   783  	expect(t, err, nil)
   784  	expect(t, val.Value(), []string{`some default`, `values here`})
   785  	expect(t, set.Lookup("goat").Value.(*StringSlice).Value(), []string{"vincent van goat", "scape goat"})
   786  }
   787  
   788  func TestStringSliceFlagApply_DefaultValueWithDestination(t *testing.T) {
   789  	defValue := []string{"UA", "US"}
   790  
   791  	fl := StringSliceFlag{Name: "country", Value: NewStringSlice(defValue...), Destination: NewStringSlice("CA")}
   792  	set := flag.NewFlagSet("test", 0)
   793  	if err := fl.Apply(set); err != nil {
   794  		t.Error(err)
   795  	}
   796  
   797  	err := set.Parse([]string{})
   798  	expect(t, err, nil)
   799  	expect(t, defValue, fl.Destination.Value())
   800  }
   801  
   802  func TestStringSliceFlagValueFromContext(t *testing.T) {
   803  	set := flag.NewFlagSet("test", 0)
   804  	set.Var(NewStringSlice("a", "b", "c"), "myflag", "doc")
   805  	ctx := NewContext(nil, set, nil)
   806  	f := &StringSliceFlag{Name: "myflag"}
   807  	expect(t, f.Get(ctx), []string{"a", "b", "c"})
   808  }
   809  
   810  func TestStringSliceFlag_MatchStringFlagBehavior(t *testing.T) {
   811  	t.Parallel()
   812  
   813  	values := []string{
   814  		"asd",
   815  		"123",
   816  		" asd ", // leading and tailing space
   817  	}
   818  	for testNum, value := range values {
   819  		value := value
   820  		t.Run(fmt.Sprintf("%d", testNum), func(t *testing.T) {
   821  			t.Parallel()
   822  
   823  			app := App{
   824  				Flags: []Flag{
   825  					&StringFlag{Name: "string"},
   826  					&StringSliceFlag{Name: "slice", KeepSpace: true},
   827  				},
   828  				Action: func(ctx *Context) error {
   829  					f1, f2 := ctx.String("string"), ctx.StringSlice("slice")
   830  					if l := len(f2); l != 1 {
   831  						t.Fatalf("StringSliceFlag should result in exactly one value, got %d", l)
   832  					}
   833  
   834  					v1, v2 := f1, f2[0]
   835  					if v1 != v2 {
   836  						t.Errorf("Expected StringSliceFlag to parse the same value as StringFlag (%q), got %q", v1, v2)
   837  					}
   838  					return nil
   839  				},
   840  			}
   841  
   842  			if err := app.Run([]string{"", "--string", value, "--slice", value}); err != nil {
   843  				t.Errorf("app run error: %s", err)
   844  			}
   845  		})
   846  	}
   847  }
   848  
   849  func TestStringSliceFlag_TrimSpace(t *testing.T) {
   850  	t.Parallel()
   851  
   852  	tests := []struct {
   853  		in, out string
   854  	}{
   855  		{" asd", "asd"},
   856  		{"123 ", "123"},
   857  		{" asd ", "asd"},
   858  	}
   859  	for testNum, tt := range tests {
   860  		tt := tt
   861  		t.Run(fmt.Sprintf("%d", testNum), func(t *testing.T) {
   862  			t.Parallel()
   863  
   864  			app := App{
   865  				Flags: []Flag{
   866  					&StringSliceFlag{Name: "trim"},
   867  					&StringSliceFlag{Name: "no-trim", KeepSpace: true},
   868  				},
   869  				Action: func(ctx *Context) error {
   870  					flagTrim, flagNoTrim := ctx.StringSlice("trim"), ctx.StringSlice("no-trim")
   871  					if l := len(flagTrim); l != 1 {
   872  						t.Fatalf("slice flag 'trim' should result in exactly one value, got %d", l)
   873  					}
   874  					if l := len(flagNoTrim); l != 1 {
   875  						t.Fatalf("slice flag 'no-trim' should result in exactly one value, got %d", l)
   876  					}
   877  
   878  					if v := flagTrim[0]; v != tt.out {
   879  						t.Errorf("Expected trimmed value %q, got %q", tt.out, v)
   880  					}
   881  					if v := flagNoTrim[0]; v != tt.in {
   882  						t.Errorf("Expected no trimmed value%q, got %q", tt.out, v)
   883  					}
   884  					return nil
   885  				},
   886  			}
   887  
   888  			if err := app.Run([]string{"", "--trim", tt.in, "--no-trim", tt.in}); err != nil {
   889  				t.Errorf("app run error: %s", err)
   890  			}
   891  		})
   892  	}
   893  }
   894  
   895  var intFlagTests = []struct {
   896  	name     string
   897  	expected string
   898  }{
   899  	{"hats", "--hats value\t(default: 9)"},
   900  	{"H", "-H value\t(default: 9)"},
   901  }
   902  
   903  func TestIntFlagHelpOutput(t *testing.T) {
   904  	for _, test := range intFlagTests {
   905  		fl := &IntFlag{Name: test.name, Value: 9}
   906  
   907  		// create a temporary flag set to apply
   908  		tfs := flag.NewFlagSet("test", 0)
   909  		if err := fl.Apply(tfs); err != nil {
   910  			t.Error(err)
   911  			return
   912  		}
   913  
   914  		output := fl.String()
   915  
   916  		if output != test.expected {
   917  			t.Errorf("%s does not match %s", output, test.expected)
   918  		}
   919  	}
   920  }
   921  
   922  func TestIntFlagWithEnvVarHelpOutput(t *testing.T) {
   923  	defer resetEnv(os.Environ())
   924  	os.Clearenv()
   925  	_ = os.Setenv("APP_BAR", "2")
   926  
   927  	for _, test := range intFlagTests {
   928  		fl := &IntFlag{Name: test.name, EnvVars: []string{"APP_BAR"}}
   929  		output := fl.String()
   930  
   931  		expectedSuffix := withEnvHint([]string{"APP_BAR"}, "")
   932  		if !strings.HasSuffix(output, expectedSuffix) {
   933  			t.Errorf("%s does not end with"+expectedSuffix, output)
   934  		}
   935  	}
   936  }
   937  
   938  func TestIntFlagApply_SetsAllNames(t *testing.T) {
   939  	v := 3
   940  	fl := IntFlag{Name: "banana", Aliases: []string{"B", "banannanana"}, Destination: &v}
   941  	set := flag.NewFlagSet("test", 0)
   942  	if err := fl.Apply(set); err != nil {
   943  		t.Error(err)
   944  	}
   945  
   946  	err := set.Parse([]string{"--banana", "1", "-B", "2", "--banannanana", "5"})
   947  	expect(t, err, nil)
   948  	expect(t, v, 5)
   949  }
   950  
   951  func TestIntFlagValueFromContext(t *testing.T) {
   952  	set := flag.NewFlagSet("test", 0)
   953  	set.Int("myflag", 42, "doc")
   954  	ctx := NewContext(nil, set, nil)
   955  	f := &IntFlag{Name: "myflag"}
   956  	expect(t, f.Get(ctx), 42)
   957  }
   958  
   959  var int64FlagTests = []struct {
   960  	name     string
   961  	expected string
   962  }{
   963  	{"hats", "--hats value\t(default: 8589934592)"},
   964  	{"H", "-H value\t(default: 8589934592)"},
   965  }
   966  
   967  func TestInt64FlagHelpOutput(t *testing.T) {
   968  	for _, test := range int64FlagTests {
   969  		fl := Int64Flag{Name: test.name, Value: 8589934592}
   970  
   971  		// create a temporary flag set to apply
   972  		tfs := flag.NewFlagSet("test", 0)
   973  		if err := fl.Apply(tfs); err != nil {
   974  			t.Error(err)
   975  			return
   976  		}
   977  
   978  		output := fl.String()
   979  
   980  		if output != test.expected {
   981  			t.Errorf("%s does not match %s", output, test.expected)
   982  		}
   983  	}
   984  }
   985  
   986  func TestInt64FlagWithEnvVarHelpOutput(t *testing.T) {
   987  	defer resetEnv(os.Environ())
   988  	os.Clearenv()
   989  	_ = os.Setenv("APP_BAR", "2")
   990  
   991  	for _, test := range int64FlagTests {
   992  		fl := IntFlag{Name: test.name, EnvVars: []string{"APP_BAR"}}
   993  		output := fl.String()
   994  
   995  		expectedSuffix := withEnvHint([]string{"APP_BAR"}, "")
   996  		if !strings.HasSuffix(output, expectedSuffix) {
   997  			t.Errorf("%s does not end with"+expectedSuffix, output)
   998  		}
   999  	}
  1000  }
  1001  
  1002  func TestInt64FlagValueFromContext(t *testing.T) {
  1003  	set := flag.NewFlagSet("test", 0)
  1004  	set.Int64("myflag", 42, "doc")
  1005  	ctx := NewContext(nil, set, nil)
  1006  	f := &Int64Flag{Name: "myflag"}
  1007  	expect(t, f.Get(ctx), int64(42))
  1008  }
  1009  
  1010  var uintFlagTests = []struct {
  1011  	name     string
  1012  	expected string
  1013  }{
  1014  	{"nerfs", "--nerfs value\t(default: 41)"},
  1015  	{"N", "-N value\t(default: 41)"},
  1016  }
  1017  
  1018  func TestUintFlagHelpOutput(t *testing.T) {
  1019  	for _, test := range uintFlagTests {
  1020  		fl := UintFlag{Name: test.name, Value: 41}
  1021  
  1022  		// create a temporary flag set to apply
  1023  		tfs := flag.NewFlagSet("test", 0)
  1024  		if err := fl.Apply(tfs); err != nil {
  1025  			t.Error(err)
  1026  			return
  1027  		}
  1028  
  1029  		output := fl.String()
  1030  
  1031  		if output != test.expected {
  1032  			t.Errorf("%s does not match %s", output, test.expected)
  1033  		}
  1034  	}
  1035  }
  1036  
  1037  func TestUintFlagWithEnvVarHelpOutput(t *testing.T) {
  1038  	defer resetEnv(os.Environ())
  1039  	os.Clearenv()
  1040  	_ = os.Setenv("APP_BAR", "2")
  1041  
  1042  	for _, test := range uintFlagTests {
  1043  		fl := UintFlag{Name: test.name, EnvVars: []string{"APP_BAR"}}
  1044  		output := fl.String()
  1045  
  1046  		expectedSuffix := withEnvHint([]string{"APP_BAR"}, "")
  1047  		if !strings.HasSuffix(output, expectedSuffix) {
  1048  			t.Errorf("%s does not end with"+expectedSuffix, output)
  1049  		}
  1050  	}
  1051  }
  1052  
  1053  func TestUintFlagValueFromContext(t *testing.T) {
  1054  	set := flag.NewFlagSet("test", 0)
  1055  	set.Uint("myflag", 42, "doc")
  1056  	ctx := NewContext(nil, set, nil)
  1057  	f := &UintFlag{Name: "myflag"}
  1058  	expect(t, f.Get(ctx), uint(42))
  1059  }
  1060  
  1061  var uint64FlagTests = []struct {
  1062  	name     string
  1063  	expected string
  1064  }{
  1065  	{"gerfs", "--gerfs value\t(default: 8589934582)"},
  1066  	{"G", "-G value\t(default: 8589934582)"},
  1067  }
  1068  
  1069  func TestUint64FlagHelpOutput(t *testing.T) {
  1070  	for _, test := range uint64FlagTests {
  1071  		fl := Uint64Flag{Name: test.name, Value: 8589934582}
  1072  
  1073  		// create a temporary flag set to apply
  1074  		tfs := flag.NewFlagSet("test", 0)
  1075  		if err := fl.Apply(tfs); err != nil {
  1076  			t.Error(err)
  1077  			return
  1078  		}
  1079  
  1080  		output := fl.String()
  1081  
  1082  		if output != test.expected {
  1083  			t.Errorf("%s does not match %s", output, test.expected)
  1084  		}
  1085  	}
  1086  }
  1087  
  1088  func TestUint64FlagWithEnvVarHelpOutput(t *testing.T) {
  1089  	defer resetEnv(os.Environ())
  1090  	os.Clearenv()
  1091  	_ = os.Setenv("APP_BAR", "2")
  1092  
  1093  	for _, test := range uint64FlagTests {
  1094  		fl := UintFlag{Name: test.name, EnvVars: []string{"APP_BAR"}}
  1095  		output := fl.String()
  1096  
  1097  		expectedSuffix := withEnvHint([]string{"APP_BAR"}, "")
  1098  		if !strings.HasSuffix(output, expectedSuffix) {
  1099  			t.Errorf("%s does not end with"+expectedSuffix, output)
  1100  		}
  1101  	}
  1102  }
  1103  
  1104  func TestUint64FlagValueFromContext(t *testing.T) {
  1105  	set := flag.NewFlagSet("test", 0)
  1106  	set.Uint64("myflag", 42, "doc")
  1107  	ctx := NewContext(nil, set, nil)
  1108  	f := &Uint64Flag{Name: "myflag"}
  1109  	expect(t, f.Get(ctx), uint64(42))
  1110  }
  1111  
  1112  var durationFlagTests = []struct {
  1113  	name     string
  1114  	expected string
  1115  }{
  1116  	{"hooting", "--hooting value\t(default: 1s)"},
  1117  	{"H", "-H value\t(default: 1s)"},
  1118  }
  1119  
  1120  func TestDurationFlagHelpOutput(t *testing.T) {
  1121  	for _, test := range durationFlagTests {
  1122  		fl := &DurationFlag{Name: test.name, Value: 1 * time.Second}
  1123  
  1124  		// create a temporary flag set to apply
  1125  		tfs := flag.NewFlagSet("test", 0)
  1126  		if err := fl.Apply(tfs); err != nil {
  1127  			t.Error(err)
  1128  			return
  1129  		}
  1130  
  1131  		output := fl.String()
  1132  
  1133  		if output != test.expected {
  1134  			t.Errorf("%q does not match %q", output, test.expected)
  1135  		}
  1136  	}
  1137  }
  1138  
  1139  func TestDurationFlagWithEnvVarHelpOutput(t *testing.T) {
  1140  	defer resetEnv(os.Environ())
  1141  	os.Clearenv()
  1142  	_ = os.Setenv("APP_BAR", "2h3m6s")
  1143  
  1144  	for _, test := range durationFlagTests {
  1145  		fl := &DurationFlag{Name: test.name, EnvVars: []string{"APP_BAR"}}
  1146  		output := fl.String()
  1147  
  1148  		expectedSuffix := withEnvHint([]string{"APP_BAR"}, "")
  1149  		if !strings.HasSuffix(output, expectedSuffix) {
  1150  			t.Errorf("%s does not end with"+expectedSuffix, output)
  1151  		}
  1152  	}
  1153  }
  1154  
  1155  func TestDurationFlagApply_SetsAllNames(t *testing.T) {
  1156  	v := time.Second * 20
  1157  	fl := DurationFlag{Name: "howmuch", Aliases: []string{"H", "whyyy"}, Destination: &v}
  1158  	set := flag.NewFlagSet("test", 0)
  1159  	if err := fl.Apply(set); err != nil {
  1160  		t.Error(err)
  1161  	}
  1162  
  1163  	err := set.Parse([]string{"--howmuch", "30s", "-H", "5m", "--whyyy", "30h"})
  1164  	expect(t, err, nil)
  1165  	expect(t, v, time.Hour*30)
  1166  }
  1167  
  1168  func TestDurationFlagValueFromContext(t *testing.T) {
  1169  	set := flag.NewFlagSet("test", 0)
  1170  	set.Duration("myflag", 42*time.Second, "doc")
  1171  	ctx := NewContext(nil, set, nil)
  1172  	f := &DurationFlag{Name: "myflag"}
  1173  	expect(t, f.Get(ctx), 42*time.Second)
  1174  }
  1175  
  1176  var intSliceFlagTests = []struct {
  1177  	name     string
  1178  	aliases  []string
  1179  	value    *IntSlice
  1180  	expected string
  1181  }{
  1182  	{"heads", nil, NewIntSlice(), "--heads value [ --heads value ]\t"},
  1183  	{"H", nil, NewIntSlice(), "-H value [ -H value ]\t"},
  1184  	{"H", []string{"heads"}, NewIntSlice(9, 3), "-H value, --heads value [ -H value, --heads value ]\t(default: 9, 3)"},
  1185  }
  1186  
  1187  func TestIntSliceFlagHelpOutput(t *testing.T) {
  1188  	for _, test := range intSliceFlagTests {
  1189  		fl := &IntSliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value}
  1190  		output := fl.String()
  1191  
  1192  		if output != test.expected {
  1193  			t.Errorf("%q does not match %q", output, test.expected)
  1194  		}
  1195  	}
  1196  }
  1197  
  1198  func TestIntSliceFlagWithEnvVarHelpOutput(t *testing.T) {
  1199  	defer resetEnv(os.Environ())
  1200  	os.Clearenv()
  1201  	_ = os.Setenv("APP_SMURF", "42,3")
  1202  
  1203  	for _, test := range intSliceFlagTests {
  1204  		fl := &IntSliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value, EnvVars: []string{"APP_SMURF"}}
  1205  		output := fl.String()
  1206  
  1207  		expectedSuffix := withEnvHint([]string{"APP_SMURF"}, "")
  1208  		if !strings.HasSuffix(output, expectedSuffix) {
  1209  			t.Errorf("%q does not end with"+expectedSuffix, output)
  1210  		}
  1211  	}
  1212  }
  1213  
  1214  func TestIntSliceFlagApply_SetsAllNames(t *testing.T) {
  1215  	fl := IntSliceFlag{Name: "bits", Aliases: []string{"B", "bips"}}
  1216  	set := flag.NewFlagSet("test", 0)
  1217  	if err := fl.Apply(set); err != nil {
  1218  		t.Error(err)
  1219  	}
  1220  
  1221  	err := set.Parse([]string{"--bits", "23", "-B", "3", "--bips", "99"})
  1222  	expect(t, err, nil)
  1223  }
  1224  
  1225  func TestIntSliceFlagApply_UsesEnvValues_noDefault(t *testing.T) {
  1226  	defer resetEnv(os.Environ())
  1227  	os.Clearenv()
  1228  	_ = os.Setenv("MY_GOAT", "1 , 2")
  1229  	var val IntSlice
  1230  	fl := IntSliceFlag{Name: "goat", EnvVars: []string{"MY_GOAT"}, Value: &val}
  1231  	set := flag.NewFlagSet("test", 0)
  1232  	if err := fl.Apply(set); err != nil {
  1233  		t.Error(err)
  1234  	}
  1235  
  1236  	err := set.Parse(nil)
  1237  	expect(t, err, nil)
  1238  	expect(t, val.Value(), []int(nil))
  1239  	expect(t, set.Lookup("goat").Value.(*IntSlice).Value(), []int{1, 2})
  1240  }
  1241  
  1242  func TestIntSliceFlagApply_UsesEnvValues_withDefault(t *testing.T) {
  1243  	defer resetEnv(os.Environ())
  1244  	os.Clearenv()
  1245  	_ = os.Setenv("MY_GOAT", "1 , 2")
  1246  	val := NewIntSlice(3, 4)
  1247  	fl := IntSliceFlag{Name: "goat", EnvVars: []string{"MY_GOAT"}, Value: val}
  1248  	set := flag.NewFlagSet("test", 0)
  1249  	if err := fl.Apply(set); err != nil {
  1250  		t.Error(err)
  1251  	}
  1252  	err := set.Parse(nil)
  1253  	expect(t, err, nil)
  1254  	expect(t, val.Value(), []int{3, 4})
  1255  	expect(t, set.Lookup("goat").Value.(*IntSlice).Value(), []int{1, 2})
  1256  }
  1257  
  1258  func TestIntSliceFlagApply_DefaultValueWithDestination(t *testing.T) {
  1259  	defValue := []int{1, 2}
  1260  
  1261  	fl := IntSliceFlag{Name: "country", Value: NewIntSlice(defValue...), Destination: NewIntSlice(3)}
  1262  	set := flag.NewFlagSet("test", 0)
  1263  	if err := fl.Apply(set); err != nil {
  1264  		t.Error(err)
  1265  	}
  1266  
  1267  	err := set.Parse([]string{})
  1268  	expect(t, err, nil)
  1269  	expect(t, defValue, fl.Destination.Value())
  1270  }
  1271  
  1272  func TestIntSliceFlagApply_ParentContext(t *testing.T) {
  1273  	_ = (&App{
  1274  		Flags: []Flag{
  1275  			&IntSliceFlag{Name: "numbers", Aliases: []string{"n"}, Value: NewIntSlice(1, 2, 3)},
  1276  		},
  1277  		Commands: []*Command{
  1278  			{
  1279  				Name: "child",
  1280  				Action: func(ctx *Context) error {
  1281  					expected := []int{1, 2, 3}
  1282  					if !reflect.DeepEqual(ctx.IntSlice("numbers"), expected) {
  1283  						t.Errorf("child context unable to view parent flag: %v != %v", expected, ctx.IntSlice("numbers"))
  1284  					}
  1285  					if !reflect.DeepEqual(ctx.IntSlice("n"), expected) {
  1286  						t.Errorf("child context unable to view parent flag: %v != %v", expected, ctx.IntSlice("n"))
  1287  					}
  1288  					return nil
  1289  				},
  1290  			},
  1291  		},
  1292  	}).Run([]string{"run", "child"})
  1293  }
  1294  
  1295  func TestIntSliceFlag_SetFromParentContext(t *testing.T) {
  1296  	fl := &IntSliceFlag{Name: "numbers", Aliases: []string{"n"}, Value: NewIntSlice(1, 2, 3, 4)}
  1297  	set := flag.NewFlagSet("test", 0)
  1298  	if err := fl.Apply(set); err != nil {
  1299  		t.Error(err)
  1300  	}
  1301  	ctx := &Context{
  1302  		parentContext: &Context{
  1303  			flagSet: set,
  1304  		},
  1305  		flagSet: flag.NewFlagSet("empty", 0),
  1306  	}
  1307  	expected := []int{1, 2, 3, 4}
  1308  	if !reflect.DeepEqual(ctx.IntSlice("numbers"), expected) {
  1309  		t.Errorf("child context unable to view parent flag: %v != %v", expected, ctx.IntSlice("numbers"))
  1310  	}
  1311  }
  1312  
  1313  func TestIntSliceFlagValueFromContext(t *testing.T) {
  1314  	set := flag.NewFlagSet("test", 0)
  1315  	set.Var(NewIntSlice(1, 2, 3), "myflag", "doc")
  1316  	ctx := NewContext(nil, set, nil)
  1317  	f := &IntSliceFlag{Name: "myflag"}
  1318  	expect(t, f.Get(ctx), []int{1, 2, 3})
  1319  }
  1320  
  1321  var int64SliceFlagTests = []struct {
  1322  	name     string
  1323  	aliases  []string
  1324  	value    *Int64Slice
  1325  	expected string
  1326  }{
  1327  	{"heads", nil, NewInt64Slice(), "--heads value [ --heads value ]\t"},
  1328  	{"H", nil, NewInt64Slice(), "-H value [ -H value ]\t"},
  1329  	{"heads", []string{"H"}, NewInt64Slice(int64(2), int64(17179869184)),
  1330  		"--heads value, -H value [ --heads value, -H value ]\t(default: 2, 17179869184)"},
  1331  }
  1332  
  1333  func TestInt64SliceFlagHelpOutput(t *testing.T) {
  1334  	for _, test := range int64SliceFlagTests {
  1335  		fl := Int64SliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value}
  1336  		output := fl.String()
  1337  
  1338  		if output != test.expected {
  1339  			t.Errorf("%q does not match %q", output, test.expected)
  1340  		}
  1341  	}
  1342  }
  1343  
  1344  func TestInt64SliceFlagWithEnvVarHelpOutput(t *testing.T) {
  1345  	defer resetEnv(os.Environ())
  1346  	os.Clearenv()
  1347  	_ = os.Setenv("APP_SMURF", "42,17179869184")
  1348  
  1349  	for _, test := range int64SliceFlagTests {
  1350  		fl := Int64SliceFlag{Name: test.name, Value: test.value, EnvVars: []string{"APP_SMURF"}}
  1351  		output := fl.String()
  1352  
  1353  		expectedSuffix := withEnvHint([]string{"APP_SMURF"}, "")
  1354  		if !strings.HasSuffix(output, expectedSuffix) {
  1355  			t.Errorf("%q does not end with"+expectedSuffix, output)
  1356  		}
  1357  	}
  1358  }
  1359  
  1360  func TestInt64SliceFlagApply_SetsAllNames(t *testing.T) {
  1361  	fl := Int64SliceFlag{Name: "bits", Aliases: []string{"B", "bips"}}
  1362  	set := flag.NewFlagSet("test", 0)
  1363  	if err := fl.Apply(set); err != nil {
  1364  		t.Error(err)
  1365  	}
  1366  
  1367  	err := set.Parse([]string{"--bits", "23", "-B", "3", "--bips", "99"})
  1368  	expect(t, err, nil)
  1369  }
  1370  
  1371  func TestInt64SliceFlagApply_UsesEnvValues_noDefault(t *testing.T) {
  1372  	defer resetEnv(os.Environ())
  1373  	os.Clearenv()
  1374  	_ = os.Setenv("MY_GOAT", "1 , 2")
  1375  	var val Int64Slice
  1376  	fl := Int64SliceFlag{Name: "goat", EnvVars: []string{"MY_GOAT"}, Value: &val}
  1377  	set := flag.NewFlagSet("test", 0)
  1378  	if err := fl.Apply(set); err != nil {
  1379  		t.Error(err)
  1380  	}
  1381  
  1382  	err := set.Parse(nil)
  1383  	expect(t, err, nil)
  1384  	expect(t, val.Value(), []int64(nil))
  1385  	expect(t, set.Lookup("goat").Value.(*Int64Slice).Value(), []int64{1, 2})
  1386  }
  1387  
  1388  func TestInt64SliceFlagApply_UsesEnvValues_withDefault(t *testing.T) {
  1389  	defer resetEnv(os.Environ())
  1390  	os.Clearenv()
  1391  	_ = os.Setenv("MY_GOAT", "1 , 2")
  1392  	val := NewInt64Slice(3, 4)
  1393  	fl := Int64SliceFlag{Name: "goat", EnvVars: []string{"MY_GOAT"}, Value: val}
  1394  	set := flag.NewFlagSet("test", 0)
  1395  	if err := fl.Apply(set); err != nil {
  1396  		t.Error(err)
  1397  	}
  1398  	err := set.Parse(nil)
  1399  	expect(t, err, nil)
  1400  	expect(t, val.Value(), []int64{3, 4})
  1401  	expect(t, set.Lookup("goat").Value.(*Int64Slice).Value(), []int64{1, 2})
  1402  }
  1403  
  1404  func TestInt64SliceFlagApply_DefaultValueWithDestination(t *testing.T) {
  1405  	defValue := []int64{1, 2}
  1406  
  1407  	fl := Int64SliceFlag{Name: "country", Value: NewInt64Slice(defValue...), Destination: NewInt64Slice(3)}
  1408  	set := flag.NewFlagSet("test", 0)
  1409  	if err := fl.Apply(set); err != nil {
  1410  		t.Error(err)
  1411  	}
  1412  
  1413  	err := set.Parse([]string{})
  1414  	expect(t, err, nil)
  1415  	expect(t, defValue, fl.Destination.Value())
  1416  }
  1417  
  1418  func TestInt64SliceFlagApply_ParentContext(t *testing.T) {
  1419  	_ = (&App{
  1420  		Flags: []Flag{
  1421  			&Int64SliceFlag{Name: "numbers", Aliases: []string{"n"}, Value: NewInt64Slice(1, 2, 3)},
  1422  		},
  1423  		Commands: []*Command{
  1424  			{
  1425  				Name: "child",
  1426  				Action: func(ctx *Context) error {
  1427  					expected := []int64{1, 2, 3}
  1428  					if !reflect.DeepEqual(ctx.Int64Slice("numbers"), expected) {
  1429  						t.Errorf("child context unable to view parent flag: %v != %v", expected, ctx.Int64Slice("numbers"))
  1430  					}
  1431  					if !reflect.DeepEqual(ctx.Int64Slice("n"), expected) {
  1432  						t.Errorf("child context unable to view parent flag: %v != %v", expected, ctx.Int64Slice("n"))
  1433  					}
  1434  					return nil
  1435  				},
  1436  			},
  1437  		},
  1438  	}).Run([]string{"run", "child"})
  1439  }
  1440  
  1441  func TestInt64SliceFlag_SetFromParentContext(t *testing.T) {
  1442  	fl := &Int64SliceFlag{Name: "numbers", Aliases: []string{"n"}, Value: NewInt64Slice(1, 2, 3, 4)}
  1443  	set := flag.NewFlagSet("test", 0)
  1444  	if err := fl.Apply(set); err != nil {
  1445  		t.Error(err)
  1446  	}
  1447  	ctx := &Context{
  1448  		parentContext: &Context{
  1449  			flagSet: set,
  1450  		},
  1451  		flagSet: flag.NewFlagSet("empty", 0),
  1452  	}
  1453  	expected := []int64{1, 2, 3, 4}
  1454  	if !reflect.DeepEqual(ctx.Int64Slice("numbers"), expected) {
  1455  		t.Errorf("child context unable to view parent flag: %v != %v", expected, ctx.Int64Slice("numbers"))
  1456  	}
  1457  }
  1458  func TestInt64SliceFlag_ReturnNil(t *testing.T) {
  1459  	fl := &Int64SliceFlag{}
  1460  	set := flag.NewFlagSet("test", 0)
  1461  	if err := fl.Apply(set); err != nil {
  1462  		t.Error(err)
  1463  	}
  1464  	ctx := &Context{
  1465  		parentContext: &Context{
  1466  			flagSet: set,
  1467  		},
  1468  		flagSet: flag.NewFlagSet("empty", 0),
  1469  	}
  1470  	expected := []int64(nil)
  1471  	if !reflect.DeepEqual(ctx.Int64Slice("numbers"), expected) {
  1472  		t.Errorf("child context unable to view parent flag: %v != %v", expected, ctx.Int64Slice("numbers"))
  1473  	}
  1474  }
  1475  
  1476  func TestInt64SliceFlagValueFromContext(t *testing.T) {
  1477  	set := flag.NewFlagSet("test", 0)
  1478  	set.Var(NewInt64Slice(1, 2, 3), "myflag", "doc")
  1479  	ctx := NewContext(nil, set, nil)
  1480  	f := &Int64SliceFlag{Name: "myflag"}
  1481  	expect(t, f.Get(ctx), []int64{1, 2, 3})
  1482  }
  1483  
  1484  var uintSliceFlagTests = []struct {
  1485  	name     string
  1486  	aliases  []string
  1487  	value    *UintSlice
  1488  	expected string
  1489  }{
  1490  	{"heads", nil, NewUintSlice(), "--heads value [ --heads value ]\t"},
  1491  	{"H", nil, NewUintSlice(), "-H value [ -H value ]\t"},
  1492  	{"heads", []string{"H"}, NewUintSlice(uint(2), uint(17179869184)),
  1493  		"--heads value, -H value [ --heads value, -H value ]\t(default: 2, 17179869184)"},
  1494  }
  1495  
  1496  func TestUintSliceFlagHelpOutput(t *testing.T) {
  1497  	for _, test := range uintSliceFlagTests {
  1498  		fl := UintSliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value}
  1499  		output := fl.String()
  1500  
  1501  		if output != test.expected {
  1502  			t.Errorf("%q does not match %q", output, test.expected)
  1503  		}
  1504  	}
  1505  }
  1506  
  1507  func TestUintSliceFlagWithEnvVarHelpOutput(t *testing.T) {
  1508  	defer resetEnv(os.Environ())
  1509  	os.Clearenv()
  1510  	_ = os.Setenv("APP_SMURF", "42,17179869184")
  1511  
  1512  	for _, test := range uintSliceFlagTests {
  1513  		fl := UintSliceFlag{Name: test.name, Value: test.value, EnvVars: []string{"APP_SMURF"}}
  1514  		output := fl.String()
  1515  
  1516  		expectedSuffix := withEnvHint([]string{"APP_SMURF"}, "")
  1517  		if !strings.HasSuffix(output, expectedSuffix) {
  1518  			t.Errorf("%q does not end with"+expectedSuffix, output)
  1519  		}
  1520  	}
  1521  }
  1522  
  1523  func TestUintSliceFlagApply_SetsAllNames(t *testing.T) {
  1524  	fl := UintSliceFlag{Name: "bits", Aliases: []string{"B", "bips"}}
  1525  	set := flag.NewFlagSet("test", 0)
  1526  	if err := fl.Apply(set); err != nil {
  1527  		t.Error(err)
  1528  	}
  1529  
  1530  	err := set.Parse([]string{"--bits", "23", "-B", "3", "--bips", "99"})
  1531  	expect(t, err, nil)
  1532  }
  1533  
  1534  func TestUintSliceFlagApply_UsesEnvValues_noDefault(t *testing.T) {
  1535  	defer resetEnv(os.Environ())
  1536  	os.Clearenv()
  1537  	_ = os.Setenv("MY_GOAT", "1 , 2")
  1538  	var val UintSlice
  1539  	fl := UintSliceFlag{Name: "goat", EnvVars: []string{"MY_GOAT"}, Value: &val}
  1540  	set := flag.NewFlagSet("test", 0)
  1541  	if err := fl.Apply(set); err != nil {
  1542  		t.Error(err)
  1543  	}
  1544  
  1545  	err := set.Parse(nil)
  1546  	expect(t, err, nil)
  1547  	expect(t, val.Value(), []uint(nil))
  1548  	expect(t, set.Lookup("goat").Value.(*UintSlice).Value(), []uint{1, 2})
  1549  }
  1550  
  1551  func TestUintSliceFlagApply_UsesEnvValues_withDefault(t *testing.T) {
  1552  	defer resetEnv(os.Environ())
  1553  	os.Clearenv()
  1554  	_ = os.Setenv("MY_GOAT", "1 , 2")
  1555  	val := NewUintSlice(3, 4)
  1556  	fl := UintSliceFlag{Name: "goat", EnvVars: []string{"MY_GOAT"}, Value: val}
  1557  	set := flag.NewFlagSet("test", 0)
  1558  	if err := fl.Apply(set); err != nil {
  1559  		t.Error(err)
  1560  	}
  1561  	err := set.Parse(nil)
  1562  	expect(t, err, nil)
  1563  	expect(t, val.Value(), []uint{3, 4})
  1564  	expect(t, set.Lookup("goat").Value.(*UintSlice).Value(), []uint{1, 2})
  1565  }
  1566  
  1567  func TestUintSliceFlagApply_DefaultValueWithDestination(t *testing.T) {
  1568  	defValue := []uint{1, 2}
  1569  
  1570  	fl := UintSliceFlag{Name: "country", Value: NewUintSlice(defValue...), Destination: NewUintSlice(3)}
  1571  	set := flag.NewFlagSet("test", 0)
  1572  	if err := fl.Apply(set); err != nil {
  1573  		t.Error(err)
  1574  	}
  1575  
  1576  	err := set.Parse([]string{})
  1577  	expect(t, err, nil)
  1578  	expect(t, defValue, fl.Destination.Value())
  1579  }
  1580  
  1581  func TestUintSliceFlagApply_ParentContext(t *testing.T) {
  1582  	_ = (&App{
  1583  		Flags: []Flag{
  1584  			&UintSliceFlag{Name: "numbers", Aliases: []string{"n"}, Value: NewUintSlice(1, 2, 3)},
  1585  		},
  1586  		Commands: []*Command{
  1587  			{
  1588  				Name: "child",
  1589  				Action: func(ctx *Context) error {
  1590  					expected := []uint{1, 2, 3}
  1591  					if !reflect.DeepEqual(ctx.UintSlice("numbers"), expected) {
  1592  						t.Errorf("child context unable to view parent flag: %v != %v", expected, ctx.UintSlice("numbers"))
  1593  					}
  1594  					if !reflect.DeepEqual(ctx.UintSlice("n"), expected) {
  1595  						t.Errorf("child context unable to view parent flag: %v != %v", expected, ctx.UintSlice("n"))
  1596  					}
  1597  					return nil
  1598  				},
  1599  			},
  1600  		},
  1601  	}).Run([]string{"run", "child"})
  1602  }
  1603  
  1604  func TestUintSliceFlag_SetFromParentContext(t *testing.T) {
  1605  	fl := &UintSliceFlag{Name: "numbers", Aliases: []string{"n"}, Value: NewUintSlice(1, 2, 3, 4)}
  1606  	set := flag.NewFlagSet("test", 0)
  1607  	if err := fl.Apply(set); err != nil {
  1608  		t.Error(err)
  1609  	}
  1610  	ctx := &Context{
  1611  		parentContext: &Context{
  1612  			flagSet: set,
  1613  		},
  1614  		flagSet: flag.NewFlagSet("empty", 0),
  1615  	}
  1616  	expected := []uint{1, 2, 3, 4}
  1617  	if !reflect.DeepEqual(ctx.UintSlice("numbers"), expected) {
  1618  		t.Errorf("child context unable to view parent flag: %v != %v", expected, ctx.UintSlice("numbers"))
  1619  	}
  1620  }
  1621  func TestUintSliceFlag_ReturnNil(t *testing.T) {
  1622  	fl := &UintSliceFlag{}
  1623  	set := flag.NewFlagSet("test", 0)
  1624  	if err := fl.Apply(set); err != nil {
  1625  		t.Error(err)
  1626  	}
  1627  	ctx := &Context{
  1628  		parentContext: &Context{
  1629  			flagSet: set,
  1630  		},
  1631  		flagSet: flag.NewFlagSet("empty", 0),
  1632  	}
  1633  	expected := []uint(nil)
  1634  	if !reflect.DeepEqual(ctx.UintSlice("numbers"), expected) {
  1635  		t.Errorf("child context unable to view parent flag: %v != %v", expected, ctx.UintSlice("numbers"))
  1636  	}
  1637  }
  1638  
  1639  var uint64SliceFlagTests = []struct {
  1640  	name     string
  1641  	aliases  []string
  1642  	value    *Uint64Slice
  1643  	expected string
  1644  }{
  1645  	{"heads", nil, NewUint64Slice(), "--heads value [ --heads value ]\t"},
  1646  	{"H", nil, NewUint64Slice(), "-H value [ -H value ]\t"},
  1647  	{"heads", []string{"H"}, NewUint64Slice(uint64(2), uint64(17179869184)),
  1648  		"--heads value, -H value [ --heads value, -H value ]\t(default: 2, 17179869184)"},
  1649  }
  1650  
  1651  func TestUint64SliceFlagHelpOutput(t *testing.T) {
  1652  	for _, test := range uint64SliceFlagTests {
  1653  		fl := Uint64SliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value}
  1654  		output := fl.String()
  1655  
  1656  		if output != test.expected {
  1657  			t.Errorf("%q does not match %q", output, test.expected)
  1658  		}
  1659  	}
  1660  }
  1661  
  1662  func TestUint64SliceFlagWithEnvVarHelpOutput(t *testing.T) {
  1663  	defer resetEnv(os.Environ())
  1664  	os.Clearenv()
  1665  	_ = os.Setenv("APP_SMURF", "42,17179869184")
  1666  
  1667  	for _, test := range uint64SliceFlagTests {
  1668  		fl := Uint64SliceFlag{Name: test.name, Value: test.value, EnvVars: []string{"APP_SMURF"}}
  1669  		output := fl.String()
  1670  
  1671  		expectedSuffix := withEnvHint([]string{"APP_SMURF"}, "")
  1672  		if !strings.HasSuffix(output, expectedSuffix) {
  1673  			t.Errorf("%q does not end with"+expectedSuffix, output)
  1674  		}
  1675  	}
  1676  }
  1677  
  1678  func TestUint64SliceFlagApply_SetsAllNames(t *testing.T) {
  1679  	fl := Uint64SliceFlag{Name: "bits", Aliases: []string{"B", "bips"}}
  1680  	set := flag.NewFlagSet("test", 0)
  1681  	if err := fl.Apply(set); err != nil {
  1682  		t.Error(err)
  1683  	}
  1684  
  1685  	err := set.Parse([]string{"--bits", "23", "-B", "3", "--bips", "99"})
  1686  	expect(t, err, nil)
  1687  }
  1688  
  1689  func TestUint64SliceFlagApply_UsesEnvValues_noDefault(t *testing.T) {
  1690  	defer resetEnv(os.Environ())
  1691  	os.Clearenv()
  1692  	_ = os.Setenv("MY_GOAT", "1 , 2")
  1693  	var val Uint64Slice
  1694  	fl := Uint64SliceFlag{Name: "goat", EnvVars: []string{"MY_GOAT"}, Value: &val}
  1695  	set := flag.NewFlagSet("test", 0)
  1696  	if err := fl.Apply(set); err != nil {
  1697  		t.Error(err)
  1698  	}
  1699  
  1700  	err := set.Parse(nil)
  1701  	expect(t, err, nil)
  1702  	expect(t, val.Value(), []uint64(nil))
  1703  	expect(t, set.Lookup("goat").Value.(*Uint64Slice).Value(), []uint64{1, 2})
  1704  }
  1705  
  1706  func TestUint64SliceFlagApply_UsesEnvValues_withDefault(t *testing.T) {
  1707  	defer resetEnv(os.Environ())
  1708  	os.Clearenv()
  1709  	_ = os.Setenv("MY_GOAT", "1 , 2")
  1710  	val := NewUint64Slice(3, 4)
  1711  	fl := Uint64SliceFlag{Name: "goat", EnvVars: []string{"MY_GOAT"}, Value: val}
  1712  	set := flag.NewFlagSet("test", 0)
  1713  	if err := fl.Apply(set); err != nil {
  1714  		t.Error(err)
  1715  	}
  1716  	err := set.Parse(nil)
  1717  	expect(t, err, nil)
  1718  	expect(t, val.Value(), []uint64{3, 4})
  1719  	expect(t, set.Lookup("goat").Value.(*Uint64Slice).Value(), []uint64{1, 2})
  1720  }
  1721  
  1722  func TestUint64SliceFlagApply_DefaultValueWithDestination(t *testing.T) {
  1723  	defValue := []uint64{1, 2}
  1724  
  1725  	fl := Uint64SliceFlag{Name: "country", Value: NewUint64Slice(defValue...), Destination: NewUint64Slice(3)}
  1726  	set := flag.NewFlagSet("test", 0)
  1727  	if err := fl.Apply(set); err != nil {
  1728  		t.Error(err)
  1729  	}
  1730  
  1731  	err := set.Parse([]string{})
  1732  	expect(t, err, nil)
  1733  	expect(t, defValue, fl.Destination.Value())
  1734  }
  1735  
  1736  func TestUint64SliceFlagApply_ParentContext(t *testing.T) {
  1737  	_ = (&App{
  1738  		Flags: []Flag{
  1739  			&Uint64SliceFlag{Name: "numbers", Aliases: []string{"n"}, Value: NewUint64Slice(1, 2, 3)},
  1740  		},
  1741  		Commands: []*Command{
  1742  			{
  1743  				Name: "child",
  1744  				Action: func(ctx *Context) error {
  1745  					expected := []uint64{1, 2, 3}
  1746  					if !reflect.DeepEqual(ctx.Uint64Slice("numbers"), expected) {
  1747  						t.Errorf("child context unable to view parent flag: %v != %v", expected, ctx.Uint64Slice("numbers"))
  1748  					}
  1749  					if !reflect.DeepEqual(ctx.Uint64Slice("n"), expected) {
  1750  						t.Errorf("child context unable to view parent flag: %v != %v", expected, ctx.Uint64Slice("n"))
  1751  					}
  1752  					return nil
  1753  				},
  1754  			},
  1755  		},
  1756  	}).Run([]string{"run", "child"})
  1757  }
  1758  
  1759  func TestUint64SliceFlag_SetFromParentContext(t *testing.T) {
  1760  	fl := &Uint64SliceFlag{Name: "numbers", Aliases: []string{"n"}, Value: NewUint64Slice(1, 2, 3, 4)}
  1761  	set := flag.NewFlagSet("test", 0)
  1762  	if err := fl.Apply(set); err != nil {
  1763  		t.Error(err)
  1764  	}
  1765  	ctx := &Context{
  1766  		parentContext: &Context{
  1767  			flagSet: set,
  1768  		},
  1769  		flagSet: flag.NewFlagSet("empty", 0),
  1770  	}
  1771  	expected := []uint64{1, 2, 3, 4}
  1772  	if !reflect.DeepEqual(ctx.Uint64Slice("numbers"), expected) {
  1773  		t.Errorf("child context unable to view parent flag: %v != %v", expected, ctx.Uint64Slice("numbers"))
  1774  	}
  1775  }
  1776  func TestUint64SliceFlag_ReturnNil(t *testing.T) {
  1777  	fl := &Uint64SliceFlag{}
  1778  	set := flag.NewFlagSet("test", 0)
  1779  	if err := fl.Apply(set); err != nil {
  1780  		t.Error(err)
  1781  	}
  1782  	ctx := &Context{
  1783  		parentContext: &Context{
  1784  			flagSet: set,
  1785  		},
  1786  		flagSet: flag.NewFlagSet("empty", 0),
  1787  	}
  1788  	expected := []uint64(nil)
  1789  	if !reflect.DeepEqual(ctx.Uint64Slice("numbers"), expected) {
  1790  		t.Errorf("child context unable to view parent flag: %v != %v", expected, ctx.Uint64Slice("numbers"))
  1791  	}
  1792  }
  1793  
  1794  var float64FlagTests = []struct {
  1795  	name     string
  1796  	expected string
  1797  }{
  1798  	{"hooting", "--hooting value\t(default: 0.1)"},
  1799  	{"H", "-H value\t(default: 0.1)"},
  1800  }
  1801  
  1802  func TestFloat64FlagHelpOutput(t *testing.T) {
  1803  	for _, test := range float64FlagTests {
  1804  		f := &Float64Flag{Name: test.name, Value: 0.1}
  1805  		output := f.String()
  1806  
  1807  		if output != test.expected {
  1808  			t.Errorf("%q does not match %q", output, test.expected)
  1809  		}
  1810  	}
  1811  }
  1812  
  1813  func TestFloat64FlagWithEnvVarHelpOutput(t *testing.T) {
  1814  	defer resetEnv(os.Environ())
  1815  	os.Clearenv()
  1816  	_ = os.Setenv("APP_BAZ", "99.4")
  1817  
  1818  	for _, test := range float64FlagTests {
  1819  		fl := &Float64Flag{Name: test.name, EnvVars: []string{"APP_BAZ"}}
  1820  		output := fl.String()
  1821  
  1822  		expectedSuffix := withEnvHint([]string{"APP_BAZ"}, "")
  1823  		if !strings.HasSuffix(output, expectedSuffix) {
  1824  			t.Errorf("%s does not end with"+expectedSuffix, output)
  1825  		}
  1826  	}
  1827  }
  1828  
  1829  func TestFloat64FlagApply_SetsAllNames(t *testing.T) {
  1830  	v := 99.1
  1831  	fl := Float64Flag{Name: "noodles", Aliases: []string{"N", "nurbles"}, Destination: &v}
  1832  	set := flag.NewFlagSet("test", 0)
  1833  	if err := fl.Apply(set); err != nil {
  1834  		t.Error(err)
  1835  	}
  1836  
  1837  	err := set.Parse([]string{"--noodles", "1.3", "-N", "11", "--nurbles", "43.33333"})
  1838  	expect(t, err, nil)
  1839  	expect(t, v, float64(43.33333))
  1840  }
  1841  
  1842  func TestFloat64FlagValueFromContext(t *testing.T) {
  1843  	set := flag.NewFlagSet("test", 0)
  1844  	set.Float64("myflag", 1.23, "doc")
  1845  	ctx := NewContext(nil, set, nil)
  1846  	f := &Float64Flag{Name: "myflag"}
  1847  	expect(t, f.Get(ctx), 1.23)
  1848  }
  1849  
  1850  var float64SliceFlagTests = []struct {
  1851  	name     string
  1852  	aliases  []string
  1853  	value    *Float64Slice
  1854  	expected string
  1855  }{
  1856  	{"heads", nil, NewFloat64Slice(), "--heads value [ --heads value ]\t"},
  1857  	{"H", nil, NewFloat64Slice(), "-H value [ -H value ]\t"},
  1858  	{"heads", []string{"H"}, NewFloat64Slice(0.1234, -10.5),
  1859  		"--heads value, -H value [ --heads value, -H value ]\t(default: 0.1234, -10.5)"},
  1860  }
  1861  
  1862  func TestFloat64SliceFlagHelpOutput(t *testing.T) {
  1863  	for _, test := range float64SliceFlagTests {
  1864  		fl := Float64SliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value}
  1865  		output := fl.String()
  1866  
  1867  		if output != test.expected {
  1868  			t.Errorf("%q does not match %q", output, test.expected)
  1869  		}
  1870  	}
  1871  }
  1872  
  1873  func TestFloat64SliceFlagWithEnvVarHelpOutput(t *testing.T) {
  1874  	defer resetEnv(os.Environ())
  1875  	os.Clearenv()
  1876  	_ = os.Setenv("APP_SMURF", "0.1234,-10.5")
  1877  	for _, test := range float64SliceFlagTests {
  1878  		fl := Float64SliceFlag{Name: test.name, Value: test.value, EnvVars: []string{"APP_SMURF"}}
  1879  		output := fl.String()
  1880  
  1881  		expectedSuffix := withEnvHint([]string{"APP_SMURF"}, "")
  1882  		if !strings.HasSuffix(output, expectedSuffix) {
  1883  			t.Errorf("%q does not end with"+expectedSuffix, output)
  1884  		}
  1885  	}
  1886  }
  1887  
  1888  func TestFloat64SliceFlagApply_SetsAllNames(t *testing.T) {
  1889  	fl := Float64SliceFlag{Name: "bits", Aliases: []string{"B", "bips"}}
  1890  	set := flag.NewFlagSet("test", 0)
  1891  	if err := fl.Apply(set); err != nil {
  1892  		t.Error(err)
  1893  	}
  1894  
  1895  	err := set.Parse([]string{"--bits", "23", "-B", "3", "--bips", "99"})
  1896  	expect(t, err, nil)
  1897  }
  1898  
  1899  func TestFloat64SliceFlagApply_UsesEnvValues_noDefault(t *testing.T) {
  1900  	defer resetEnv(os.Environ())
  1901  	os.Clearenv()
  1902  	_ = os.Setenv("MY_GOAT", "1.0 , 2.0")
  1903  	var val Float64Slice
  1904  	fl := Float64SliceFlag{Name: "goat", EnvVars: []string{"MY_GOAT"}, Value: &val}
  1905  	set := flag.NewFlagSet("test", 0)
  1906  	if err := fl.Apply(set); err != nil {
  1907  		t.Error(err)
  1908  	}
  1909  
  1910  	err := set.Parse(nil)
  1911  	expect(t, err, nil)
  1912  	expect(t, val.Value(), []float64(nil))
  1913  	expect(t, set.Lookup("goat").Value.(*Float64Slice).Value(), []float64{1, 2})
  1914  }
  1915  
  1916  func TestFloat64SliceFlagApply_UsesEnvValues_withDefault(t *testing.T) {
  1917  	defer resetEnv(os.Environ())
  1918  	os.Clearenv()
  1919  	_ = os.Setenv("MY_GOAT", "1.0 , 2.0")
  1920  	val := NewFloat64Slice(3.0, 4.0)
  1921  	fl := Float64SliceFlag{Name: "goat", EnvVars: []string{"MY_GOAT"}, Value: val}
  1922  	set := flag.NewFlagSet("test", 0)
  1923  	if err := fl.Apply(set); err != nil {
  1924  		t.Error(err)
  1925  	}
  1926  	err := set.Parse(nil)
  1927  	expect(t, err, nil)
  1928  	expect(t, val.Value(), []float64{3, 4})
  1929  	expect(t, set.Lookup("goat").Value.(*Float64Slice).Value(), []float64{1, 2})
  1930  }
  1931  
  1932  func TestFloat64SliceFlagApply_DefaultValueWithDestination(t *testing.T) {
  1933  	defValue := []float64{1.0, 2.0}
  1934  
  1935  	fl := Float64SliceFlag{Name: "country", Value: NewFloat64Slice(defValue...), Destination: NewFloat64Slice(3)}
  1936  	set := flag.NewFlagSet("test", 0)
  1937  	if err := fl.Apply(set); err != nil {
  1938  		t.Error(err)
  1939  	}
  1940  
  1941  	err := set.Parse([]string{})
  1942  	expect(t, err, nil)
  1943  	expect(t, defValue, fl.Destination.Value())
  1944  }
  1945  
  1946  func TestFloat64SliceFlagValueFromContext(t *testing.T) {
  1947  	set := flag.NewFlagSet("test", 0)
  1948  	set.Var(NewFloat64Slice(1.23, 4.56), "myflag", "doc")
  1949  	ctx := NewContext(nil, set, nil)
  1950  	f := &Float64SliceFlag{Name: "myflag"}
  1951  	expect(t, f.Get(ctx), []float64{1.23, 4.56})
  1952  }
  1953  
  1954  func TestFloat64SliceFlagApply_ParentContext(t *testing.T) {
  1955  	_ = (&App{
  1956  		Flags: []Flag{
  1957  			&Float64SliceFlag{Name: "numbers", Aliases: []string{"n"}, Value: NewFloat64Slice(1.0, 2.0, 3.0)},
  1958  		},
  1959  		Commands: []*Command{
  1960  			{
  1961  				Name: "child",
  1962  				Action: func(ctx *Context) error {
  1963  					expected := []float64{1.0, 2.0, 3.0}
  1964  					if !reflect.DeepEqual(ctx.Float64Slice("numbers"), expected) {
  1965  						t.Errorf("child context unable to view parent flag: %v != %v", expected, ctx.Float64Slice("numbers"))
  1966  					}
  1967  					if !reflect.DeepEqual(ctx.Float64Slice("n"), expected) {
  1968  						t.Errorf("child context unable to view parent flag: %v != %v", expected, ctx.Float64Slice("n"))
  1969  					}
  1970  					return nil
  1971  				},
  1972  			},
  1973  		},
  1974  	}).Run([]string{"run", "child"})
  1975  }
  1976  
  1977  var genericFlagTests = []struct {
  1978  	name     string
  1979  	value    Generic
  1980  	expected string
  1981  }{
  1982  	{"toads", &Parser{"abc", "def"}, "--toads value\ttest flag (default: abc,def)"},
  1983  	{"t", &Parser{"abc", "def"}, "-t value\ttest flag (default: abc,def)"},
  1984  }
  1985  
  1986  func TestGenericFlagHelpOutput(t *testing.T) {
  1987  	for _, test := range genericFlagTests {
  1988  		fl := &GenericFlag{Name: test.name, Value: test.value, Usage: "test flag"}
  1989  		// create a temporary flag set to apply
  1990  		tfs := flag.NewFlagSet("test", 0)
  1991  		if err := fl.Apply(tfs); err != nil {
  1992  			t.Error(err)
  1993  			return
  1994  		}
  1995  		output := fl.String()
  1996  
  1997  		if output != test.expected {
  1998  			t.Errorf("%q does not match %q", output, test.expected)
  1999  		}
  2000  	}
  2001  }
  2002  
  2003  func TestGenericFlagWithEnvVarHelpOutput(t *testing.T) {
  2004  	defer resetEnv(os.Environ())
  2005  	os.Clearenv()
  2006  	_ = os.Setenv("APP_ZAP", "3")
  2007  
  2008  	for _, test := range genericFlagTests {
  2009  		fl := &GenericFlag{Name: test.name, EnvVars: []string{"APP_ZAP"}}
  2010  		output := fl.String()
  2011  
  2012  		expectedSuffix := withEnvHint([]string{"APP_ZAP"}, "")
  2013  		if !strings.HasSuffix(output, expectedSuffix) {
  2014  			t.Errorf("%s does not end with"+expectedSuffix, output)
  2015  		}
  2016  	}
  2017  }
  2018  
  2019  func TestGenericFlagApply_SetsAllNames(t *testing.T) {
  2020  	fl := GenericFlag{Name: "orbs", Aliases: []string{"O", "obrs"}, Value: &Parser{}}
  2021  	set := flag.NewFlagSet("test", 0)
  2022  	if err := fl.Apply(set); err != nil {
  2023  		t.Error(err)
  2024  	}
  2025  
  2026  	err := set.Parse([]string{"--orbs", "eleventy,3", "-O", "4,bloop", "--obrs", "19,s"})
  2027  	expect(t, err, nil)
  2028  }
  2029  
  2030  func TestGenericFlagValueFromContext(t *testing.T) {
  2031  	set := flag.NewFlagSet("test", 0)
  2032  	set.Var(&Parser{"abc", "def"}, "myflag", "doc")
  2033  	ctx := NewContext(nil, set, nil)
  2034  	f := &GenericFlag{Name: "myflag"}
  2035  	expect(t, f.Get(ctx), &Parser{"abc", "def"})
  2036  }
  2037  
  2038  func TestParseMultiString(t *testing.T) {
  2039  	_ = (&App{
  2040  		Flags: []Flag{
  2041  			&StringFlag{Name: "serve", Aliases: []string{"s"}},
  2042  		},
  2043  		Action: func(ctx *Context) error {
  2044  			if ctx.String("serve") != "10" {
  2045  				t.Errorf("main name not set")
  2046  			}
  2047  			if ctx.String("s") != "10" {
  2048  				t.Errorf("short name not set")
  2049  			}
  2050  			return nil
  2051  		},
  2052  	}).Run([]string{"run", "-s", "10"})
  2053  }
  2054  
  2055  func TestParseDestinationString(t *testing.T) {
  2056  	var dest string
  2057  	_ = (&App{
  2058  		Flags: []Flag{
  2059  			&StringFlag{
  2060  				Name:        "dest",
  2061  				Destination: &dest,
  2062  			},
  2063  		},
  2064  		Action: func(ctx *Context) error {
  2065  			if dest != "10" {
  2066  				t.Errorf("expected destination String 10")
  2067  			}
  2068  			return nil
  2069  		},
  2070  	}).Run([]string{"run", "--dest", "10"})
  2071  }
  2072  
  2073  func TestParseMultiStringFromEnv(t *testing.T) {
  2074  	defer resetEnv(os.Environ())
  2075  	os.Clearenv()
  2076  	_ = os.Setenv("APP_COUNT", "20")
  2077  	_ = (&App{
  2078  		Flags: []Flag{
  2079  			&StringFlag{Name: "count", Aliases: []string{"c"}, EnvVars: []string{"APP_COUNT"}},
  2080  		},
  2081  		Action: func(ctx *Context) error {
  2082  			if ctx.String("count") != "20" {
  2083  				t.Errorf("main name not set")
  2084  			}
  2085  			if ctx.String("c") != "20" {
  2086  				t.Errorf("short name not set")
  2087  			}
  2088  			return nil
  2089  		},
  2090  	}).Run([]string{"run"})
  2091  }
  2092  
  2093  func TestParseMultiStringFromEnvCascade(t *testing.T) {
  2094  	defer resetEnv(os.Environ())
  2095  	os.Clearenv()
  2096  	_ = os.Setenv("APP_COUNT", "20")
  2097  	_ = (&App{
  2098  		Flags: []Flag{
  2099  			&StringFlag{Name: "count", Aliases: []string{"c"}, EnvVars: []string{"COMPAT_COUNT", "APP_COUNT"}},
  2100  		},
  2101  		Action: func(ctx *Context) error {
  2102  			if ctx.String("count") != "20" {
  2103  				t.Errorf("main name not set")
  2104  			}
  2105  			if ctx.String("c") != "20" {
  2106  				t.Errorf("short name not set")
  2107  			}
  2108  			return nil
  2109  		},
  2110  	}).Run([]string{"run"})
  2111  }
  2112  
  2113  func TestParseMultiStringSlice(t *testing.T) {
  2114  	_ = (&App{
  2115  		Flags: []Flag{
  2116  			&StringSliceFlag{Name: "serve", Aliases: []string{"s"}, Value: NewStringSlice()},
  2117  		},
  2118  		Action: func(ctx *Context) error {
  2119  			expected := []string{"10", "20"}
  2120  			if !reflect.DeepEqual(ctx.StringSlice("serve"), expected) {
  2121  				t.Errorf("main name not set: %v != %v", expected, ctx.StringSlice("serve"))
  2122  			}
  2123  			if !reflect.DeepEqual(ctx.StringSlice("s"), expected) {
  2124  				t.Errorf("short name not set: %v != %v", expected, ctx.StringSlice("s"))
  2125  			}
  2126  			return nil
  2127  		},
  2128  	}).Run([]string{"run", "-s", "10", "-s", "20"})
  2129  }
  2130  
  2131  func TestParseMultiStringSliceWithDefaults(t *testing.T) {
  2132  	_ = (&App{
  2133  		Flags: []Flag{
  2134  			&StringSliceFlag{Name: "serve", Aliases: []string{"s"}, Value: NewStringSlice("9", "2")},
  2135  		},
  2136  		Action: func(ctx *Context) error {
  2137  			expected := []string{"10", "20"}
  2138  			if !reflect.DeepEqual(ctx.StringSlice("serve"), expected) {
  2139  				t.Errorf("main name not set: %v != %v", expected, ctx.StringSlice("serve"))
  2140  			}
  2141  			if !reflect.DeepEqual(ctx.StringSlice("s"), expected) {
  2142  				t.Errorf("short name not set: %v != %v", expected, ctx.StringSlice("s"))
  2143  			}
  2144  			return nil
  2145  		},
  2146  	}).Run([]string{"run", "-s", "10", "-s", "20"})
  2147  }
  2148  
  2149  func TestParseMultiStringSliceWithDestination(t *testing.T) {
  2150  	dest := &StringSlice{}
  2151  	_ = (&App{
  2152  		Flags: []Flag{
  2153  			&StringSliceFlag{Name: "serve", Aliases: []string{"s"}, Destination: dest},
  2154  		},
  2155  		Action: func(ctx *Context) error {
  2156  			expected := []string{"10", "20"}
  2157  			if !reflect.DeepEqual(dest.slice, expected) {
  2158  				t.Errorf("main name not set: %v != %v", expected, ctx.StringSlice("serve"))
  2159  			}
  2160  			if !reflect.DeepEqual(dest.slice, expected) {
  2161  				t.Errorf("short name not set: %v != %v", expected, ctx.StringSlice("s"))
  2162  			}
  2163  			return nil
  2164  		},
  2165  	}).Run([]string{"run", "-s", "10", "-s", "20"})
  2166  }
  2167  
  2168  func TestParseMultiStringSliceWithDestinationAndEnv(t *testing.T) {
  2169  	defer resetEnv(os.Environ())
  2170  	os.Clearenv()
  2171  	_ = os.Setenv("APP_INTERVALS", "20,30,40")
  2172  
  2173  	dest := &StringSlice{}
  2174  	_ = (&App{
  2175  		Flags: []Flag{
  2176  			&StringSliceFlag{Name: "serve", Aliases: []string{"s"}, Destination: dest, EnvVars: []string{"APP_INTERVALS"}},
  2177  		},
  2178  		Action: func(ctx *Context) error {
  2179  			expected := []string{"10", "20"}
  2180  			if !reflect.DeepEqual(dest.slice, expected) {
  2181  				t.Errorf("main name not set: %v != %v", expected, ctx.StringSlice("serve"))
  2182  			}
  2183  			if !reflect.DeepEqual(dest.slice, expected) {
  2184  				t.Errorf("short name not set: %v != %v", expected, ctx.StringSlice("s"))
  2185  			}
  2186  			return nil
  2187  		},
  2188  	}).Run([]string{"run", "-s", "10", "-s", "20"})
  2189  }
  2190  
  2191  func TestParseMultiFloat64SliceWithDestinationAndEnv(t *testing.T) {
  2192  	defer resetEnv(os.Environ())
  2193  	os.Clearenv()
  2194  	_ = os.Setenv("APP_INTERVALS", "20,30,40")
  2195  
  2196  	dest := &Float64Slice{}
  2197  	_ = (&App{
  2198  		Flags: []Flag{
  2199  			&Float64SliceFlag{Name: "serve", Aliases: []string{"s"}, Destination: dest, EnvVars: []string{"APP_INTERVALS"}},
  2200  		},
  2201  		Action: func(ctx *Context) error {
  2202  			expected := []float64{10, 20}
  2203  			if !reflect.DeepEqual(dest.slice, expected) {
  2204  				t.Errorf("main name not set: %v != %v", expected, ctx.StringSlice("serve"))
  2205  			}
  2206  			if !reflect.DeepEqual(dest.slice, expected) {
  2207  				t.Errorf("short name not set: %v != %v", expected, ctx.StringSlice("s"))
  2208  			}
  2209  			return nil
  2210  		},
  2211  	}).Run([]string{"run", "-s", "10", "-s", "20"})
  2212  }
  2213  
  2214  func TestParseMultiInt64SliceWithDestinationAndEnv(t *testing.T) {
  2215  	defer resetEnv(os.Environ())
  2216  	os.Clearenv()
  2217  	_ = os.Setenv("APP_INTERVALS", "20,30,40")
  2218  
  2219  	dest := &Int64Slice{}
  2220  	_ = (&App{
  2221  		Flags: []Flag{
  2222  			&Int64SliceFlag{Name: "serve", Aliases: []string{"s"}, Destination: dest, EnvVars: []string{"APP_INTERVALS"}},
  2223  		},
  2224  		Action: func(ctx *Context) error {
  2225  			expected := []int64{10, 20}
  2226  			if !reflect.DeepEqual(dest.slice, expected) {
  2227  				t.Errorf("main name not set: %v != %v", expected, ctx.StringSlice("serve"))
  2228  			}
  2229  			if !reflect.DeepEqual(dest.slice, expected) {
  2230  				t.Errorf("short name not set: %v != %v", expected, ctx.StringSlice("s"))
  2231  			}
  2232  			return nil
  2233  		},
  2234  	}).Run([]string{"run", "-s", "10", "-s", "20"})
  2235  }
  2236  
  2237  func TestParseMultiIntSliceWithDestinationAndEnv(t *testing.T) {
  2238  	defer resetEnv(os.Environ())
  2239  	os.Clearenv()
  2240  	_ = os.Setenv("APP_INTERVALS", "20,30,40")
  2241  
  2242  	dest := &IntSlice{}
  2243  	_ = (&App{
  2244  		Flags: []Flag{
  2245  			&IntSliceFlag{Name: "serve", Aliases: []string{"s"}, Destination: dest, EnvVars: []string{"APP_INTERVALS"}},
  2246  		},
  2247  		Action: func(ctx *Context) error {
  2248  			expected := []int{10, 20}
  2249  			if !reflect.DeepEqual(dest.slice, expected) {
  2250  				t.Errorf("main name not set: %v != %v", expected, ctx.StringSlice("serve"))
  2251  			}
  2252  			if !reflect.DeepEqual(dest.slice, expected) {
  2253  				t.Errorf("short name not set: %v != %v", expected, ctx.StringSlice("s"))
  2254  			}
  2255  			return nil
  2256  		},
  2257  	}).Run([]string{"run", "-s", "10", "-s", "20"})
  2258  }
  2259  
  2260  func TestParseMultiStringSliceWithDefaultsUnset(t *testing.T) {
  2261  	_ = (&App{
  2262  		Flags: []Flag{
  2263  			&StringSliceFlag{Name: "serve", Aliases: []string{"s"}, Value: NewStringSlice("9", "2")},
  2264  		},
  2265  		Action: func(ctx *Context) error {
  2266  			if !reflect.DeepEqual(ctx.StringSlice("serve"), []string{"9", "2"}) {
  2267  				t.Errorf("main name not set: %v", ctx.StringSlice("serve"))
  2268  			}
  2269  			if !reflect.DeepEqual(ctx.StringSlice("s"), []string{"9", "2"}) {
  2270  				t.Errorf("short name not set: %v", ctx.StringSlice("s"))
  2271  			}
  2272  			return nil
  2273  		},
  2274  	}).Run([]string{"run"})
  2275  }
  2276  
  2277  func TestParseMultiStringSliceFromEnv(t *testing.T) {
  2278  	defer resetEnv(os.Environ())
  2279  	os.Clearenv()
  2280  	_ = os.Setenv("APP_INTERVALS", "20,30,40")
  2281  
  2282  	_ = (&App{
  2283  		Flags: []Flag{
  2284  			&StringSliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewStringSlice(), EnvVars: []string{"APP_INTERVALS"}},
  2285  		},
  2286  		Action: func(ctx *Context) error {
  2287  			if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
  2288  				t.Errorf("main name not set from env")
  2289  			}
  2290  			if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) {
  2291  				t.Errorf("short name not set from env")
  2292  			}
  2293  			return nil
  2294  		},
  2295  	}).Run([]string{"run"})
  2296  }
  2297  
  2298  func TestParseMultiStringSliceFromEnvWithDefaults(t *testing.T) {
  2299  	defer resetEnv(os.Environ())
  2300  	os.Clearenv()
  2301  	_ = os.Setenv("APP_INTERVALS", "20,30,40")
  2302  
  2303  	_ = (&App{
  2304  		Flags: []Flag{
  2305  			&StringSliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewStringSlice("1", "2", "5"), EnvVars: []string{"APP_INTERVALS"}},
  2306  		},
  2307  		Action: func(ctx *Context) error {
  2308  			if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
  2309  				t.Errorf("main name not set from env")
  2310  			}
  2311  			if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) {
  2312  				t.Errorf("short name not set from env")
  2313  			}
  2314  			return nil
  2315  		},
  2316  	}).Run([]string{"run"})
  2317  }
  2318  
  2319  func TestParseMultiStringSliceFromEnvCascade(t *testing.T) {
  2320  	defer resetEnv(os.Environ())
  2321  	os.Clearenv()
  2322  	_ = os.Setenv("APP_INTERVALS", "20,30,40")
  2323  
  2324  	_ = (&App{
  2325  		Flags: []Flag{
  2326  			&StringSliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewStringSlice(), EnvVars: []string{"COMPAT_INTERVALS", "APP_INTERVALS"}},
  2327  		},
  2328  		Action: func(ctx *Context) error {
  2329  			if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
  2330  				t.Errorf("main name not set from env")
  2331  			}
  2332  			if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) {
  2333  				t.Errorf("short name not set from env")
  2334  			}
  2335  			return nil
  2336  		},
  2337  	}).Run([]string{"run"})
  2338  }
  2339  
  2340  func TestParseMultiStringSliceFromEnvCascadeWithDefaults(t *testing.T) {
  2341  	defer resetEnv(os.Environ())
  2342  	os.Clearenv()
  2343  	_ = os.Setenv("APP_INTERVALS", "20,30,40")
  2344  
  2345  	_ = (&App{
  2346  		Flags: []Flag{
  2347  			&StringSliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewStringSlice("1", "2", "5"), EnvVars: []string{"COMPAT_INTERVALS", "APP_INTERVALS"}},
  2348  		},
  2349  		Action: func(ctx *Context) error {
  2350  			if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
  2351  				t.Errorf("main name not set from env")
  2352  			}
  2353  			if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) {
  2354  				t.Errorf("short name not set from env")
  2355  			}
  2356  			return nil
  2357  		},
  2358  	}).Run([]string{"run"})
  2359  }
  2360  
  2361  func TestParseMultiStringSliceFromEnvWithDestination(t *testing.T) {
  2362  	defer resetEnv(os.Environ())
  2363  	os.Clearenv()
  2364  	_ = os.Setenv("APP_INTERVALS", "20,30,40")
  2365  
  2366  	dest := &StringSlice{}
  2367  	_ = (&App{
  2368  		Flags: []Flag{
  2369  			&StringSliceFlag{Name: "intervals", Aliases: []string{"i"}, Destination: dest, EnvVars: []string{"APP_INTERVALS"}},
  2370  		},
  2371  		Action: func(ctx *Context) error {
  2372  			if !reflect.DeepEqual(dest.slice, []string{"20", "30", "40"}) {
  2373  				t.Errorf("main name not set from env")
  2374  			}
  2375  			if !reflect.DeepEqual(dest.slice, []string{"20", "30", "40"}) {
  2376  				t.Errorf("short name not set from env")
  2377  			}
  2378  			return nil
  2379  		},
  2380  	}).Run([]string{"run"})
  2381  }
  2382  
  2383  func TestParseMultiInt(t *testing.T) {
  2384  	_ = (&App{
  2385  		Flags: []Flag{
  2386  			&IntFlag{Name: "serve", Aliases: []string{"s"}},
  2387  		},
  2388  		Action: func(ctx *Context) error {
  2389  			if ctx.Int("serve") != 10 {
  2390  				t.Errorf("main name not set")
  2391  			}
  2392  			if ctx.Int("s") != 10 {
  2393  				t.Errorf("short name not set")
  2394  			}
  2395  			return nil
  2396  		},
  2397  	}).Run([]string{"run", "-s", "10"})
  2398  }
  2399  
  2400  func TestParseDestinationInt(t *testing.T) {
  2401  	var dest int
  2402  	_ = (&App{
  2403  		Flags: []Flag{
  2404  			&IntFlag{
  2405  				Name:        "dest",
  2406  				Destination: &dest,
  2407  			},
  2408  		},
  2409  		Action: func(ctx *Context) error {
  2410  			if dest != 10 {
  2411  				t.Errorf("expected destination Int 10")
  2412  			}
  2413  			return nil
  2414  		},
  2415  	}).Run([]string{"run", "--dest", "10"})
  2416  }
  2417  
  2418  func TestParseMultiIntFromEnv(t *testing.T) {
  2419  	defer resetEnv(os.Environ())
  2420  	os.Clearenv()
  2421  	_ = os.Setenv("APP_TIMEOUT_SECONDS", "10")
  2422  	_ = (&App{
  2423  		Flags: []Flag{
  2424  			&IntFlag{Name: "timeout", Aliases: []string{"t"}, EnvVars: []string{"APP_TIMEOUT_SECONDS"}},
  2425  		},
  2426  		Action: func(ctx *Context) error {
  2427  			if ctx.Int("timeout") != 10 {
  2428  				t.Errorf("main name not set")
  2429  			}
  2430  			if ctx.Int("t") != 10 {
  2431  				t.Errorf("short name not set")
  2432  			}
  2433  			return nil
  2434  		},
  2435  	}).Run([]string{"run"})
  2436  }
  2437  
  2438  func TestParseMultiIntFromEnvCascade(t *testing.T) {
  2439  	defer resetEnv(os.Environ())
  2440  	os.Clearenv()
  2441  	_ = os.Setenv("APP_TIMEOUT_SECONDS", "10")
  2442  	_ = (&App{
  2443  		Flags: []Flag{
  2444  			&IntFlag{Name: "timeout", Aliases: []string{"t"}, EnvVars: []string{"COMPAT_TIMEOUT_SECONDS", "APP_TIMEOUT_SECONDS"}},
  2445  		},
  2446  		Action: func(ctx *Context) error {
  2447  			if ctx.Int("timeout") != 10 {
  2448  				t.Errorf("main name not set")
  2449  			}
  2450  			if ctx.Int("t") != 10 {
  2451  				t.Errorf("short name not set")
  2452  			}
  2453  			return nil
  2454  		},
  2455  	}).Run([]string{"run"})
  2456  }
  2457  
  2458  func TestParseMultiIntSlice(t *testing.T) {
  2459  	_ = (&App{
  2460  		Flags: []Flag{
  2461  			&IntSliceFlag{Name: "serve", Aliases: []string{"s"}, Value: NewIntSlice()},
  2462  		},
  2463  		Action: func(ctx *Context) error {
  2464  			if !reflect.DeepEqual(ctx.IntSlice("serve"), []int{10, 20}) {
  2465  				t.Errorf("main name not set")
  2466  			}
  2467  			if !reflect.DeepEqual(ctx.IntSlice("s"), []int{10, 20}) {
  2468  				t.Errorf("short name not set")
  2469  			}
  2470  			return nil
  2471  		},
  2472  	}).Run([]string{"run", "-s", "10", "-s", "20"})
  2473  }
  2474  
  2475  func TestParseMultiIntSliceWithDefaults(t *testing.T) {
  2476  	_ = (&App{
  2477  		Flags: []Flag{
  2478  			&IntSliceFlag{Name: "serve", Aliases: []string{"s"}, Value: NewIntSlice(9, 2)},
  2479  		},
  2480  		Action: func(ctx *Context) error {
  2481  			if !reflect.DeepEqual(ctx.IntSlice("serve"), []int{10, 20}) {
  2482  				t.Errorf("main name not set")
  2483  			}
  2484  			if !reflect.DeepEqual(ctx.IntSlice("s"), []int{10, 20}) {
  2485  				t.Errorf("short name not set")
  2486  			}
  2487  			return nil
  2488  		},
  2489  	}).Run([]string{"run", "-s", "10", "-s", "20"})
  2490  }
  2491  
  2492  func TestParseMultiIntSliceWithDefaultsUnset(t *testing.T) {
  2493  	_ = (&App{
  2494  		Flags: []Flag{
  2495  			&IntSliceFlag{Name: "serve", Aliases: []string{"s"}, Value: NewIntSlice(9, 2)},
  2496  		},
  2497  		Action: func(ctx *Context) error {
  2498  			if !reflect.DeepEqual(ctx.IntSlice("serve"), []int{9, 2}) {
  2499  				t.Errorf("main name not set")
  2500  			}
  2501  			if !reflect.DeepEqual(ctx.IntSlice("s"), []int{9, 2}) {
  2502  				t.Errorf("short name not set")
  2503  			}
  2504  			return nil
  2505  		},
  2506  	}).Run([]string{"run"})
  2507  }
  2508  
  2509  func TestParseMultiIntSliceFromEnv(t *testing.T) {
  2510  	defer resetEnv(os.Environ())
  2511  	os.Clearenv()
  2512  	_ = os.Setenv("APP_INTERVALS", "20,30,40")
  2513  
  2514  	_ = (&App{
  2515  		Flags: []Flag{
  2516  			&IntSliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewIntSlice(), EnvVars: []string{"APP_INTERVALS"}},
  2517  		},
  2518  		Action: func(ctx *Context) error {
  2519  			if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) {
  2520  				t.Errorf("main name not set from env")
  2521  			}
  2522  			if !reflect.DeepEqual(ctx.IntSlice("i"), []int{20, 30, 40}) {
  2523  				t.Errorf("short name not set from env")
  2524  			}
  2525  			return nil
  2526  		},
  2527  	}).Run([]string{"run"})
  2528  }
  2529  
  2530  func TestParseMultiIntSliceFromEnvWithDefaults(t *testing.T) {
  2531  	defer resetEnv(os.Environ())
  2532  	os.Clearenv()
  2533  	_ = os.Setenv("APP_INTERVALS", "20,30,40")
  2534  
  2535  	_ = (&App{
  2536  		Flags: []Flag{
  2537  			&IntSliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewIntSlice(1, 2, 5), EnvVars: []string{"APP_INTERVALS"}},
  2538  		},
  2539  		Action: func(ctx *Context) error {
  2540  			if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) {
  2541  				t.Errorf("main name not set from env")
  2542  			}
  2543  			if !reflect.DeepEqual(ctx.IntSlice("i"), []int{20, 30, 40}) {
  2544  				t.Errorf("short name not set from env")
  2545  			}
  2546  			return nil
  2547  		},
  2548  	}).Run([]string{"run"})
  2549  }
  2550  
  2551  func TestParseMultiIntSliceFromEnvCascade(t *testing.T) {
  2552  	defer resetEnv(os.Environ())
  2553  	os.Clearenv()
  2554  	_ = os.Setenv("APP_INTERVALS", "20,30,40")
  2555  
  2556  	_ = (&App{
  2557  		Flags: []Flag{
  2558  			&IntSliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewIntSlice(), EnvVars: []string{"COMPAT_INTERVALS", "APP_INTERVALS"}},
  2559  		},
  2560  		Action: func(ctx *Context) error {
  2561  			if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) {
  2562  				t.Errorf("main name not set from env")
  2563  			}
  2564  			if !reflect.DeepEqual(ctx.IntSlice("i"), []int{20, 30, 40}) {
  2565  				t.Errorf("short name not set from env")
  2566  			}
  2567  			return nil
  2568  		},
  2569  	}).Run([]string{"run"})
  2570  }
  2571  
  2572  func TestParseMultiInt64Slice(t *testing.T) {
  2573  	_ = (&App{
  2574  		Flags: []Flag{
  2575  			&Int64SliceFlag{Name: "serve", Aliases: []string{"s"}, Value: NewInt64Slice()},
  2576  		},
  2577  		Action: func(ctx *Context) error {
  2578  			if !reflect.DeepEqual(ctx.Int64Slice("serve"), []int64{10, 17179869184}) {
  2579  				t.Errorf("main name not set")
  2580  			}
  2581  			if !reflect.DeepEqual(ctx.Int64Slice("s"), []int64{10, 17179869184}) {
  2582  				t.Errorf("short name not set")
  2583  			}
  2584  			return nil
  2585  		},
  2586  	}).Run([]string{"run", "-s", "10", "-s", "17179869184"})
  2587  }
  2588  
  2589  func TestParseMultiInt64SliceFromEnv(t *testing.T) {
  2590  	defer resetEnv(os.Environ())
  2591  	os.Clearenv()
  2592  	_ = os.Setenv("APP_INTERVALS", "20,30,17179869184")
  2593  
  2594  	_ = (&App{
  2595  		Flags: []Flag{
  2596  			&Int64SliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewInt64Slice(), EnvVars: []string{"APP_INTERVALS"}},
  2597  		},
  2598  		Action: func(ctx *Context) error {
  2599  			if !reflect.DeepEqual(ctx.Int64Slice("intervals"), []int64{20, 30, 17179869184}) {
  2600  				t.Errorf("main name not set from env")
  2601  			}
  2602  			if !reflect.DeepEqual(ctx.Int64Slice("i"), []int64{20, 30, 17179869184}) {
  2603  				t.Errorf("short name not set from env")
  2604  			}
  2605  			return nil
  2606  		},
  2607  	}).Run([]string{"run"})
  2608  }
  2609  
  2610  func TestParseMultiInt64SliceFromEnvCascade(t *testing.T) {
  2611  	defer resetEnv(os.Environ())
  2612  	os.Clearenv()
  2613  	_ = os.Setenv("APP_INTERVALS", "20,30,17179869184")
  2614  
  2615  	_ = (&App{
  2616  		Flags: []Flag{
  2617  			&Int64SliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewInt64Slice(), EnvVars: []string{"COMPAT_INTERVALS", "APP_INTERVALS"}},
  2618  		},
  2619  		Action: func(ctx *Context) error {
  2620  			if !reflect.DeepEqual(ctx.Int64Slice("intervals"), []int64{20, 30, 17179869184}) {
  2621  				t.Errorf("main name not set from env")
  2622  			}
  2623  			if !reflect.DeepEqual(ctx.Int64Slice("i"), []int64{20, 30, 17179869184}) {
  2624  				t.Errorf("short name not set from env")
  2625  			}
  2626  			return nil
  2627  		},
  2628  	}).Run([]string{"run"})
  2629  }
  2630  
  2631  func TestParseMultiFloat64(t *testing.T) {
  2632  	_ = (&App{
  2633  		Flags: []Flag{
  2634  			&Float64Flag{Name: "serve", Aliases: []string{"s"}},
  2635  		},
  2636  		Action: func(ctx *Context) error {
  2637  			if ctx.Float64("serve") != 10.2 {
  2638  				t.Errorf("main name not set")
  2639  			}
  2640  			if ctx.Float64("s") != 10.2 {
  2641  				t.Errorf("short name not set")
  2642  			}
  2643  			return nil
  2644  		},
  2645  	}).Run([]string{"run", "-s", "10.2"})
  2646  }
  2647  
  2648  func TestParseDestinationFloat64(t *testing.T) {
  2649  	var dest float64
  2650  	_ = (&App{
  2651  		Flags: []Flag{
  2652  			&Float64Flag{
  2653  				Name:        "dest",
  2654  				Destination: &dest,
  2655  			},
  2656  		},
  2657  		Action: func(ctx *Context) error {
  2658  			if dest != 10.2 {
  2659  				t.Errorf("expected destination Float64 10.2")
  2660  			}
  2661  			return nil
  2662  		},
  2663  	}).Run([]string{"run", "--dest", "10.2"})
  2664  }
  2665  
  2666  func TestParseMultiFloat64FromEnv(t *testing.T) {
  2667  	defer resetEnv(os.Environ())
  2668  	os.Clearenv()
  2669  	_ = os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
  2670  	_ = (&App{
  2671  		Flags: []Flag{
  2672  			&Float64Flag{Name: "timeout", Aliases: []string{"t"}, EnvVars: []string{"APP_TIMEOUT_SECONDS"}},
  2673  		},
  2674  		Action: func(ctx *Context) error {
  2675  			if ctx.Float64("timeout") != 15.5 {
  2676  				t.Errorf("main name not set")
  2677  			}
  2678  			if ctx.Float64("t") != 15.5 {
  2679  				t.Errorf("short name not set")
  2680  			}
  2681  			return nil
  2682  		},
  2683  	}).Run([]string{"run"})
  2684  }
  2685  
  2686  func TestParseMultiFloat64FromEnvCascade(t *testing.T) {
  2687  	defer resetEnv(os.Environ())
  2688  	os.Clearenv()
  2689  	_ = os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
  2690  	_ = (&App{
  2691  		Flags: []Flag{
  2692  			&Float64Flag{Name: "timeout", Aliases: []string{"t"}, EnvVars: []string{"COMPAT_TIMEOUT_SECONDS", "APP_TIMEOUT_SECONDS"}},
  2693  		},
  2694  		Action: func(ctx *Context) error {
  2695  			if ctx.Float64("timeout") != 15.5 {
  2696  				t.Errorf("main name not set")
  2697  			}
  2698  			if ctx.Float64("t") != 15.5 {
  2699  				t.Errorf("short name not set")
  2700  			}
  2701  			return nil
  2702  		},
  2703  	}).Run([]string{"run"})
  2704  }
  2705  
  2706  func TestParseMultiFloat64SliceFromEnv(t *testing.T) {
  2707  	defer resetEnv(os.Environ())
  2708  	os.Clearenv()
  2709  	_ = os.Setenv("APP_INTERVALS", "0.1,-10.5")
  2710  
  2711  	_ = (&App{
  2712  		Flags: []Flag{
  2713  			&Float64SliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewFloat64Slice(), EnvVars: []string{"APP_INTERVALS"}},
  2714  		},
  2715  		Action: func(ctx *Context) error {
  2716  			if !reflect.DeepEqual(ctx.Float64Slice("intervals"), []float64{0.1, -10.5}) {
  2717  				t.Errorf("main name not set from env")
  2718  			}
  2719  			if !reflect.DeepEqual(ctx.Float64Slice("i"), []float64{0.1, -10.5}) {
  2720  				t.Errorf("short name not set from env")
  2721  			}
  2722  			return nil
  2723  		},
  2724  	}).Run([]string{"run"})
  2725  }
  2726  
  2727  func TestParseMultiFloat64SliceFromEnvCascade(t *testing.T) {
  2728  	defer resetEnv(os.Environ())
  2729  	os.Clearenv()
  2730  	_ = os.Setenv("APP_INTERVALS", "0.1234,-10.5")
  2731  
  2732  	_ = (&App{
  2733  		Flags: []Flag{
  2734  			&Float64SliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewFloat64Slice(), EnvVars: []string{"COMPAT_INTERVALS", "APP_INTERVALS"}},
  2735  		},
  2736  		Action: func(ctx *Context) error {
  2737  			if !reflect.DeepEqual(ctx.Float64Slice("intervals"), []float64{0.1234, -10.5}) {
  2738  				t.Errorf("main name not set from env")
  2739  			}
  2740  			if !reflect.DeepEqual(ctx.Float64Slice("i"), []float64{0.1234, -10.5}) {
  2741  				t.Errorf("short name not set from env")
  2742  			}
  2743  			return nil
  2744  		},
  2745  	}).Run([]string{"run"})
  2746  }
  2747  
  2748  func TestParseMultiBool(t *testing.T) {
  2749  	_ = (&App{
  2750  		Flags: []Flag{
  2751  			&BoolFlag{Name: "serve", Aliases: []string{"s"}},
  2752  		},
  2753  		Action: func(ctx *Context) error {
  2754  			if ctx.Bool("serve") != true {
  2755  				t.Errorf("main name not set")
  2756  			}
  2757  			if ctx.Bool("s") != true {
  2758  				t.Errorf("short name not set")
  2759  			}
  2760  			return nil
  2761  		},
  2762  	}).Run([]string{"run", "--serve"})
  2763  }
  2764  
  2765  func TestParseBoolShortOptionHandle(t *testing.T) {
  2766  	_ = (&App{
  2767  		Commands: []*Command{
  2768  			{
  2769  				Name:                   "foobar",
  2770  				UseShortOptionHandling: true,
  2771  				Action: func(ctx *Context) error {
  2772  					if ctx.Bool("serve") != true {
  2773  						t.Errorf("main name not set")
  2774  					}
  2775  					if ctx.Bool("option") != true {
  2776  						t.Errorf("short name not set")
  2777  					}
  2778  					return nil
  2779  				},
  2780  				Flags: []Flag{
  2781  					&BoolFlag{Name: "serve", Aliases: []string{"s"}},
  2782  					&BoolFlag{Name: "option", Aliases: []string{"o"}},
  2783  				},
  2784  			},
  2785  		},
  2786  	}).Run([]string{"run", "foobar", "-so"})
  2787  }
  2788  
  2789  func TestParseDestinationBool(t *testing.T) {
  2790  	var dest bool
  2791  	_ = (&App{
  2792  		Flags: []Flag{
  2793  			&BoolFlag{
  2794  				Name:        "dest",
  2795  				Destination: &dest,
  2796  			},
  2797  		},
  2798  		Action: func(ctx *Context) error {
  2799  			if dest != true {
  2800  				t.Errorf("expected destination Bool true")
  2801  			}
  2802  			return nil
  2803  		},
  2804  	}).Run([]string{"run", "--dest"})
  2805  }
  2806  
  2807  func TestParseMultiBoolFromEnv(t *testing.T) {
  2808  	defer resetEnv(os.Environ())
  2809  	os.Clearenv()
  2810  	_ = os.Setenv("APP_DEBUG", "1")
  2811  	_ = (&App{
  2812  		Flags: []Flag{
  2813  			&BoolFlag{Name: "debug", Aliases: []string{"d"}, EnvVars: []string{"APP_DEBUG"}},
  2814  		},
  2815  		Action: func(ctx *Context) error {
  2816  			if ctx.Bool("debug") != true {
  2817  				t.Errorf("main name not set from env")
  2818  			}
  2819  			if ctx.Bool("d") != true {
  2820  				t.Errorf("short name not set from env")
  2821  			}
  2822  			return nil
  2823  		},
  2824  	}).Run([]string{"run"})
  2825  }
  2826  
  2827  func TestParseMultiBoolFromEnvCascade(t *testing.T) {
  2828  	defer resetEnv(os.Environ())
  2829  	os.Clearenv()
  2830  	_ = os.Setenv("APP_DEBUG", "1")
  2831  	_ = (&App{
  2832  		Flags: []Flag{
  2833  			&BoolFlag{Name: "debug", Aliases: []string{"d"}, EnvVars: []string{"COMPAT_DEBUG", "APP_DEBUG"}},
  2834  		},
  2835  		Action: func(ctx *Context) error {
  2836  			if ctx.Bool("debug") != true {
  2837  				t.Errorf("main name not set from env")
  2838  			}
  2839  			if ctx.Bool("d") != true {
  2840  				t.Errorf("short name not set from env")
  2841  			}
  2842  			return nil
  2843  		},
  2844  	}).Run([]string{"run"})
  2845  }
  2846  
  2847  func TestParseBoolFromEnv(t *testing.T) {
  2848  	var boolFlagTests = []struct {
  2849  		input  string
  2850  		output bool
  2851  	}{
  2852  		{"", false},
  2853  		{"1", true},
  2854  		{"false", false},
  2855  		{"true", true},
  2856  	}
  2857  
  2858  	for _, test := range boolFlagTests {
  2859  		defer resetEnv(os.Environ())
  2860  		os.Clearenv()
  2861  		_ = os.Setenv("DEBUG", test.input)
  2862  		_ = (&App{
  2863  			Flags: []Flag{
  2864  				&BoolFlag{Name: "debug", Aliases: []string{"d"}, EnvVars: []string{"DEBUG"}},
  2865  			},
  2866  			Action: func(ctx *Context) error {
  2867  				if ctx.Bool("debug") != test.output {
  2868  					t.Errorf("expected %+v to be parsed as %+v, instead was %+v", test.input, test.output, ctx.Bool("debug"))
  2869  				}
  2870  				if ctx.Bool("d") != test.output {
  2871  					t.Errorf("expected %+v to be parsed as %+v, instead was %+v", test.input, test.output, ctx.Bool("d"))
  2872  				}
  2873  				return nil
  2874  			},
  2875  		}).Run([]string{"run"})
  2876  	}
  2877  }
  2878  
  2879  func TestParseMultiBoolT(t *testing.T) {
  2880  	_ = (&App{
  2881  		Flags: []Flag{
  2882  			&BoolFlag{Name: "implode", Aliases: []string{"i"}, Value: true},
  2883  		},
  2884  		Action: func(ctx *Context) error {
  2885  			if ctx.Bool("implode") {
  2886  				t.Errorf("main name not set")
  2887  			}
  2888  			if ctx.Bool("i") {
  2889  				t.Errorf("short name not set")
  2890  			}
  2891  			return nil
  2892  		},
  2893  	}).Run([]string{"run", "--implode=false"})
  2894  }
  2895  
  2896  type Parser [2]string
  2897  
  2898  func (p *Parser) Set(value string) error {
  2899  	parts := strings.Split(value, ",")
  2900  	if len(parts) != 2 {
  2901  		return fmt.Errorf("invalid format")
  2902  	}
  2903  
  2904  	(*p)[0] = parts[0]
  2905  	(*p)[1] = parts[1]
  2906  
  2907  	return nil
  2908  }
  2909  
  2910  func (p *Parser) String() string {
  2911  	return fmt.Sprintf("%s,%s", p[0], p[1])
  2912  }
  2913  
  2914  func (p *Parser) Get() interface{} {
  2915  	return p
  2916  }
  2917  
  2918  func TestParseGeneric(t *testing.T) {
  2919  	_ = (&App{
  2920  		Flags: []Flag{
  2921  			&GenericFlag{Name: "serve", Aliases: []string{"s"}, Value: &Parser{}},
  2922  		},
  2923  		Action: func(ctx *Context) error {
  2924  			if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"10", "20"}) {
  2925  				t.Errorf("main name not set")
  2926  			}
  2927  			if !reflect.DeepEqual(ctx.Generic("s"), &Parser{"10", "20"}) {
  2928  				t.Errorf("short name not set")
  2929  			}
  2930  			return nil
  2931  		},
  2932  	}).Run([]string{"run", "-s", "10,20"})
  2933  }
  2934  
  2935  type genericType struct {
  2936  	s []string
  2937  }
  2938  
  2939  func (g *genericType) Set(value string) error {
  2940  	g.s = strings.Split(value, "-")
  2941  	return nil
  2942  }
  2943  
  2944  func (g *genericType) String() string {
  2945  	return strings.Join(g.s, "-")
  2946  }
  2947  
  2948  func TestParseDestinationGeneric(t *testing.T) {
  2949  	expectedString := "abc1-123d"
  2950  	expectedGeneric := &genericType{[]string{"abc1", "123d"}}
  2951  	dest := &genericType{}
  2952  
  2953  	_ = (&App{
  2954  		Flags: []Flag{
  2955  			&GenericFlag{
  2956  				Name:        "dest",
  2957  				Destination: dest,
  2958  			},
  2959  		},
  2960  		Action: func(ctx *Context) error {
  2961  
  2962  			if !reflect.DeepEqual(dest, expectedGeneric) {
  2963  				t.Errorf(
  2964  					"expected destination generic: %+v, actual: %+v",
  2965  					expectedGeneric,
  2966  					dest,
  2967  				)
  2968  			}
  2969  
  2970  			if dest.String() != expectedString {
  2971  				t.Errorf(
  2972  					"expected destination string: %s, actual: %s",
  2973  					expectedString,
  2974  					dest.String(),
  2975  				)
  2976  			}
  2977  			return nil
  2978  		},
  2979  	}).Run([]string{"run", "--dest", expectedString})
  2980  }
  2981  
  2982  func TestParseGenericFromEnv(t *testing.T) {
  2983  	defer resetEnv(os.Environ())
  2984  	os.Clearenv()
  2985  	_ = os.Setenv("APP_SERVE", "20,30")
  2986  	_ = (&App{
  2987  		Flags: []Flag{
  2988  			&GenericFlag{
  2989  				Name:    "serve",
  2990  				Aliases: []string{"s"},
  2991  				Value:   &Parser{},
  2992  				EnvVars: []string{"APP_SERVE"},
  2993  			},
  2994  		},
  2995  		Action: func(ctx *Context) error {
  2996  			if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"20", "30"}) {
  2997  				t.Errorf("main name not set from env")
  2998  			}
  2999  			if !reflect.DeepEqual(ctx.Generic("s"), &Parser{"20", "30"}) {
  3000  				t.Errorf("short name not set from env")
  3001  			}
  3002  			return nil
  3003  		},
  3004  	}).Run([]string{"run"})
  3005  }
  3006  
  3007  func TestParseGenericFromEnvCascade(t *testing.T) {
  3008  	defer resetEnv(os.Environ())
  3009  	os.Clearenv()
  3010  	_ = os.Setenv("APP_FOO", "99,2000")
  3011  	_ = (&App{
  3012  		Flags: []Flag{
  3013  			&GenericFlag{
  3014  				Name:    "foos",
  3015  				Value:   &Parser{},
  3016  				EnvVars: []string{"COMPAT_FOO", "APP_FOO"},
  3017  			},
  3018  		},
  3019  		Action: func(ctx *Context) error {
  3020  			if !reflect.DeepEqual(ctx.Generic("foos"), &Parser{"99", "2000"}) {
  3021  				t.Errorf("value not set from env")
  3022  			}
  3023  			return nil
  3024  		},
  3025  	}).Run([]string{"run"})
  3026  }
  3027  
  3028  func TestFlagFromFile(t *testing.T) {
  3029  	temp, err := os.CreateTemp("", "urfave_cli_test")
  3030  	if err != nil {
  3031  		t.Error(err)
  3032  		return
  3033  	}
  3034  
  3035  	defer resetEnv(os.Environ())
  3036  	os.Clearenv()
  3037  	os.Setenv("APP_FOO", "123")
  3038  
  3039  	_, _ = io.WriteString(temp, "abc")
  3040  	_ = temp.Close()
  3041  	defer func() {
  3042  		_ = os.Remove(temp.Name())
  3043  	}()
  3044  
  3045  	var filePathTests = []struct {
  3046  		path     string
  3047  		name     []string
  3048  		expected string
  3049  	}{
  3050  		{"file-does-not-exist", []string{"APP_BAR"}, ""},
  3051  		{"file-does-not-exist", []string{"APP_FOO"}, "123"},
  3052  		{"file-does-not-exist", []string{"APP_FOO", "APP_BAR"}, "123"},
  3053  		{temp.Name(), []string{"APP_FOO"}, "123"},
  3054  		{temp.Name(), []string{"APP_BAR"}, "abc"},
  3055  	}
  3056  
  3057  	for _, filePathTest := range filePathTests {
  3058  		got, _, _ := flagFromEnvOrFile(filePathTest.name, filePathTest.path)
  3059  		if want := filePathTest.expected; got != want {
  3060  			t.Errorf("Did not expect %v - Want %v", got, want)
  3061  		}
  3062  	}
  3063  }
  3064  
  3065  func TestStringSlice_Serialized_Set(t *testing.T) {
  3066  	sl0 := NewStringSlice("a", "b")
  3067  	ser0 := sl0.Serialize()
  3068  
  3069  	if len(ser0) < len(slPfx) {
  3070  		t.Fatalf("serialized shorter than expected: %q", ser0)
  3071  	}
  3072  
  3073  	sl1 := NewStringSlice("c", "d")
  3074  	_ = sl1.Set(ser0)
  3075  
  3076  	if sl0.String() != sl1.String() {
  3077  		t.Fatalf("pre and post serialization do not match: %v != %v", sl0, sl1)
  3078  	}
  3079  }
  3080  
  3081  func TestIntSlice_Serialized_Set(t *testing.T) {
  3082  	sl0 := NewIntSlice(1, 2)
  3083  	ser0 := sl0.Serialize()
  3084  
  3085  	if len(ser0) < len(slPfx) {
  3086  		t.Fatalf("serialized shorter than expected: %q", ser0)
  3087  	}
  3088  
  3089  	sl1 := NewIntSlice(3, 4)
  3090  	_ = sl1.Set(ser0)
  3091  
  3092  	if sl0.String() != sl1.String() {
  3093  		t.Fatalf("pre and post serialization do not match: %v != %v", sl0, sl1)
  3094  	}
  3095  }
  3096  
  3097  func TestInt64Slice_Serialized_Set(t *testing.T) {
  3098  	sl0 := NewInt64Slice(int64(1), int64(2))
  3099  	ser0 := sl0.Serialize()
  3100  
  3101  	if len(ser0) < len(slPfx) {
  3102  		t.Fatalf("serialized shorter than expected: %q", ser0)
  3103  	}
  3104  
  3105  	sl1 := NewInt64Slice(int64(3), int64(4))
  3106  	_ = sl1.Set(ser0)
  3107  
  3108  	if sl0.String() != sl1.String() {
  3109  		t.Fatalf("pre and post serialization do not match: %v != %v", sl0, sl1)
  3110  	}
  3111  }
  3112  
  3113  func TestUintSlice_Serialized_Set(t *testing.T) {
  3114  	sl0 := NewUintSlice(1, 2)
  3115  	ser0 := sl0.Serialize()
  3116  
  3117  	if len(ser0) < len(slPfx) {
  3118  		t.Fatalf("serialized shorter than expected: %q", ser0)
  3119  	}
  3120  
  3121  	sl1 := NewUintSlice(3, 4)
  3122  	_ = sl1.Set(ser0)
  3123  
  3124  	if sl0.String() != sl1.String() {
  3125  		t.Fatalf("pre and post serialization do not match: %v != %v", sl0, sl1)
  3126  	}
  3127  }
  3128  
  3129  func TestUint64Slice_Serialized_Set(t *testing.T) {
  3130  	sl0 := NewUint64Slice(1, 2)
  3131  	ser0 := sl0.Serialize()
  3132  
  3133  	if len(ser0) < len(slPfx) {
  3134  		t.Fatalf("serialized shorter than expected: %q", ser0)
  3135  	}
  3136  
  3137  	sl1 := NewUint64Slice(3, 4)
  3138  	_ = sl1.Set(ser0)
  3139  
  3140  	if sl0.String() != sl1.String() {
  3141  		t.Fatalf("pre and post serialization do not match: %v != %v", sl0, sl1)
  3142  	}
  3143  }
  3144  
  3145  func TestTimestamp_set(t *testing.T) {
  3146  	ts := Timestamp{
  3147  		timestamp:  nil,
  3148  		hasBeenSet: false,
  3149  		layout:     "Jan 2, 2006 at 3:04pm (MST)",
  3150  	}
  3151  
  3152  	time1 := "Feb 3, 2013 at 7:54pm (PST)"
  3153  	if err := ts.Set(time1); err != nil {
  3154  		t.Fatalf("Failed to parse time %s with layout %s", time1, ts.layout)
  3155  	}
  3156  	if ts.hasBeenSet == false {
  3157  		t.Fatalf("hasBeenSet is not true after setting a time")
  3158  	}
  3159  
  3160  	ts.hasBeenSet = false
  3161  	ts.SetLayout(time.RFC3339)
  3162  	time2 := "2006-01-02T15:04:05Z"
  3163  	if err := ts.Set(time2); err != nil {
  3164  		t.Fatalf("Failed to parse time %s with layout %s", time2, ts.layout)
  3165  	}
  3166  	if ts.hasBeenSet == false {
  3167  		t.Fatalf("hasBeenSet is not true after setting a time")
  3168  	}
  3169  }
  3170  
  3171  func TestTimestampFlagApply(t *testing.T) {
  3172  	expectedResult, _ := time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
  3173  	fl := TimestampFlag{Name: "time", Aliases: []string{"t"}, Layout: time.RFC3339}
  3174  	set := flag.NewFlagSet("test", 0)
  3175  	if err := fl.Apply(set); err != nil {
  3176  		t.Error(err)
  3177  	}
  3178  
  3179  	err := set.Parse([]string{"--time", "2006-01-02T15:04:05Z"})
  3180  	expect(t, err, nil)
  3181  	expect(t, *fl.Value.timestamp, expectedResult)
  3182  }
  3183  
  3184  func TestTimestampFlagApplyValue(t *testing.T) {
  3185  	expectedResult, _ := time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
  3186  	fl := TimestampFlag{Name: "time", Aliases: []string{"t"}, Layout: time.RFC3339, Value: NewTimestamp(expectedResult)}
  3187  	set := flag.NewFlagSet("test", 0)
  3188  	if err := fl.Apply(set); err != nil {
  3189  		t.Error(err)
  3190  	}
  3191  
  3192  	err := set.Parse([]string{""})
  3193  	expect(t, err, nil)
  3194  	expect(t, *fl.Value.timestamp, expectedResult)
  3195  }
  3196  
  3197  func TestTimestampFlagApply_Fail_Parse_Wrong_Layout(t *testing.T) {
  3198  	fl := TimestampFlag{Name: "time", Aliases: []string{"t"}, Layout: "randomlayout"}
  3199  	set := flag.NewFlagSet("test", 0)
  3200  	set.SetOutput(io.Discard)
  3201  	if err := fl.Apply(set); err != nil {
  3202  		t.Error(err)
  3203  	}
  3204  
  3205  	err := set.Parse([]string{"--time", "2006-01-02T15:04:05Z"})
  3206  	expect(t, err, fmt.Errorf("invalid value \"2006-01-02T15:04:05Z\" for flag -time: parsing time \"2006-01-02T15:04:05Z\" as \"randomlayout\": cannot parse \"2006-01-02T15:04:05Z\" as \"randomlayout\""))
  3207  }
  3208  
  3209  func TestTimestampFlagApply_Fail_Parse_Wrong_Time(t *testing.T) {
  3210  	fl := TimestampFlag{Name: "time", Aliases: []string{"t"}, Layout: "Jan 2, 2006 at 3:04pm (MST)"}
  3211  	set := flag.NewFlagSet("test", 0)
  3212  	set.SetOutput(io.Discard)
  3213  	if err := fl.Apply(set); err != nil {
  3214  		t.Error(err)
  3215  	}
  3216  
  3217  	err := set.Parse([]string{"--time", "2006-01-02T15:04:05Z"})
  3218  	expect(t, err, fmt.Errorf("invalid value \"2006-01-02T15:04:05Z\" for flag -time: parsing time \"2006-01-02T15:04:05Z\" as \"Jan 2, 2006 at 3:04pm (MST)\": cannot parse \"2006-01-02T15:04:05Z\" as \"Jan\""))
  3219  }
  3220  
  3221  func TestTimestampFlagApply_Timezoned(t *testing.T) {
  3222  	pdt := time.FixedZone("PDT", -7*60*60)
  3223  	expectedResult, _ := time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
  3224  	fl := TimestampFlag{Name: "time", Aliases: []string{"t"}, Layout: time.ANSIC, Timezone: pdt}
  3225  	set := flag.NewFlagSet("test", 0)
  3226  	if err := fl.Apply(set); err != nil {
  3227  		t.Error(err)
  3228  	}
  3229  
  3230  	err := set.Parse([]string{"--time", "Mon Jan 2 08:04:05 2006"})
  3231  	expect(t, err, nil)
  3232  	expect(t, *fl.Value.timestamp, expectedResult.In(pdt))
  3233  }
  3234  
  3235  func TestTimestampFlagValueFromContext(t *testing.T) {
  3236  	set := flag.NewFlagSet("test", 0)
  3237  	now := time.Now()
  3238  	set.Var(NewTimestamp(now), "myflag", "doc")
  3239  	ctx := NewContext(nil, set, nil)
  3240  	f := &TimestampFlag{Name: "myflag"}
  3241  	expect(t, f.Get(ctx), &now)
  3242  }
  3243  
  3244  type flagDefaultTestCase struct {
  3245  	name    string
  3246  	flag    Flag
  3247  	toParse []string
  3248  	expect  string
  3249  }
  3250  
  3251  func TestFlagDefaultValue(t *testing.T) {
  3252  	cases := []*flagDefaultTestCase{
  3253  		{
  3254  			name:    "stringSlice",
  3255  			flag:    &StringSliceFlag{Name: "flag", Value: NewStringSlice("default1", "default2")},
  3256  			toParse: []string{"--flag", "parsed"},
  3257  			expect:  `--flag value [ --flag value ]	(default: "default1", "default2")`,
  3258  		},
  3259  		{
  3260  			name:    "float64Slice",
  3261  			flag:    &Float64SliceFlag{Name: "flag", Value: NewFloat64Slice(1.1, 2.2)},
  3262  			toParse: []string{"--flag", "13.3"},
  3263  			expect:  `--flag value [ --flag value ]	(default: 1.1, 2.2)`,
  3264  		},
  3265  		{
  3266  			name:    "int64Slice",
  3267  			flag:    &Int64SliceFlag{Name: "flag", Value: NewInt64Slice(1, 2)},
  3268  			toParse: []string{"--flag", "13"},
  3269  			expect:  `--flag value [ --flag value ]	(default: 1, 2)`,
  3270  		},
  3271  		{
  3272  			name:    "intSlice",
  3273  			flag:    &IntSliceFlag{Name: "flag", Value: NewIntSlice(1, 2)},
  3274  			toParse: []string{"--flag", "13"},
  3275  			expect:  `--flag value [ --flag value ]	(default: 1, 2)`,
  3276  		},
  3277  		{
  3278  			name:    "uint64Slice",
  3279  			flag:    &Uint64SliceFlag{Name: "flag", Value: NewUint64Slice(1, 2)},
  3280  			toParse: []string{"--flag", "13"},
  3281  			expect:  `--flag value [ --flag value ]	(default: 1, 2)`,
  3282  		},
  3283  		{
  3284  			name:    "uintSlice",
  3285  			flag:    &UintSliceFlag{Name: "flag", Value: NewUintSlice(1, 2)},
  3286  			toParse: []string{"--flag", "13"},
  3287  			expect:  `--flag value [ --flag value ]	(default: 1, 2)`,
  3288  		},
  3289  		{
  3290  			name:    "string",
  3291  			flag:    &StringFlag{Name: "flag", Value: "default"},
  3292  			toParse: []string{"--flag", "parsed"},
  3293  			expect:  `--flag value	(default: "default")`,
  3294  		},
  3295  		{
  3296  			name:    "bool",
  3297  			flag:    &BoolFlag{Name: "flag", Value: true},
  3298  			toParse: []string{"--flag", "false"},
  3299  			expect:  `--flag	(default: true)`,
  3300  		},
  3301  		{
  3302  			name:    "uint64",
  3303  			flag:    &Uint64Flag{Name: "flag", Value: 1},
  3304  			toParse: []string{"--flag", "13"},
  3305  			expect:  `--flag value	(default: 1)`,
  3306  		},
  3307  	}
  3308  	for i, v := range cases {
  3309  		set := flag.NewFlagSet("test", 0)
  3310  		set.SetOutput(io.Discard)
  3311  		_ = v.flag.Apply(set)
  3312  		if err := set.Parse(v.toParse); err != nil {
  3313  			t.Error(err)
  3314  		}
  3315  		if got := v.flag.String(); got != v.expect {
  3316  			t.Errorf("TestFlagDefaultValue %d %s\nexpect:%s\ngot:%s", i, v.name, v.expect, got)
  3317  		}
  3318  	}
  3319  }
  3320  
  3321  type flagDefaultTestCaseWithEnv struct {
  3322  	name    string
  3323  	flag    Flag
  3324  	toParse []string
  3325  	expect  string
  3326  	environ map[string]string
  3327  }
  3328  
  3329  func TestFlagDefaultValueWithEnv(t *testing.T) {
  3330  	defer resetEnv(os.Environ())
  3331  	os.Clearenv()
  3332  
  3333  	ts, err := time.Parse(time.RFC3339, "2005-01-02T15:04:05Z")
  3334  	if err != nil {
  3335  		t.Fatal(err)
  3336  	}
  3337  	cases := []*flagDefaultTestCaseWithEnv{
  3338  		{
  3339  			name:    "stringSlice",
  3340  			flag:    &StringSliceFlag{Name: "flag", Value: NewStringSlice("default1", "default2"), EnvVars: []string{"ssflag"}},
  3341  			toParse: []string{"--flag", "parsed"},
  3342  			expect:  `--flag value [ --flag value ]	(default: "default1", "default2")` + withEnvHint([]string{"ssflag"}, ""),
  3343  			environ: map[string]string{
  3344  				"ssflag": "some-other-env_value",
  3345  			},
  3346  		},
  3347  		{
  3348  			name:    "float64Slice",
  3349  			flag:    &Float64SliceFlag{Name: "flag", Value: NewFloat64Slice(1.1, 2.2), EnvVars: []string{"fsflag"}},
  3350  			toParse: []string{"--flag", "13.3"},
  3351  			expect:  `--flag value [ --flag value ]	(default: 1.1, 2.2)` + withEnvHint([]string{"fsflag"}, ""),
  3352  			environ: map[string]string{
  3353  				"fsflag": "20304.222",
  3354  			},
  3355  		},
  3356  		{
  3357  			name:    "int64Slice",
  3358  			flag:    &Int64SliceFlag{Name: "flag", Value: NewInt64Slice(1, 2), EnvVars: []string{"isflag"}},
  3359  			toParse: []string{"--flag", "13"},
  3360  			expect:  `--flag value [ --flag value ]	(default: 1, 2)` + withEnvHint([]string{"isflag"}, ""),
  3361  			environ: map[string]string{
  3362  				"isflag": "101",
  3363  			},
  3364  		},
  3365  		{
  3366  			name:    "intSlice",
  3367  			flag:    &IntSliceFlag{Name: "flag", Value: NewIntSlice(1, 2), EnvVars: []string{"isflag"}},
  3368  			toParse: []string{"--flag", "13"},
  3369  			expect:  `--flag value [ --flag value ]	(default: 1, 2)` + withEnvHint([]string{"isflag"}, ""),
  3370  			environ: map[string]string{
  3371  				"isflag": "101",
  3372  			},
  3373  		},
  3374  		{
  3375  			name:    "uint64Slice",
  3376  			flag:    &Uint64SliceFlag{Name: "flag", Value: NewUint64Slice(1, 2), EnvVars: []string{"uisflag"}},
  3377  			toParse: []string{"--flag", "13"},
  3378  			expect:  `--flag value [ --flag value ]	(default: 1, 2)` + withEnvHint([]string{"uisflag"}, ""),
  3379  			environ: map[string]string{
  3380  				"uisflag": "3",
  3381  			},
  3382  		},
  3383  		{
  3384  			name:    "uintSlice",
  3385  			flag:    &UintSliceFlag{Name: "flag", Value: NewUintSlice(1, 2), EnvVars: []string{"uisflag"}},
  3386  			toParse: []string{"--flag", "13"},
  3387  			expect:  `--flag value [ --flag value ]	(default: 1, 2)` + withEnvHint([]string{"uisflag"}, ""),
  3388  			environ: map[string]string{
  3389  				"uisflag": "3",
  3390  			},
  3391  		},
  3392  		{
  3393  			name:    "string",
  3394  			flag:    &StringFlag{Name: "flag", Value: "default", EnvVars: []string{"uflag"}},
  3395  			toParse: []string{"--flag", "parsed"},
  3396  			expect:  `--flag value	(default: "default")` + withEnvHint([]string{"uflag"}, ""),
  3397  			environ: map[string]string{
  3398  				"uflag": "some-other-string",
  3399  			},
  3400  		},
  3401  		{
  3402  			name:    "bool",
  3403  			flag:    &BoolFlag{Name: "flag", Value: true, EnvVars: []string{"uflag"}},
  3404  			toParse: []string{"--flag", "false"},
  3405  			expect:  `--flag	(default: true)` + withEnvHint([]string{"uflag"}, ""),
  3406  			environ: map[string]string{
  3407  				"uflag": "false",
  3408  			},
  3409  		},
  3410  		{
  3411  			name:    "uint64",
  3412  			flag:    &Uint64Flag{Name: "flag", Value: 1, EnvVars: []string{"uflag"}},
  3413  			toParse: []string{"--flag", "13"},
  3414  			expect:  `--flag value	(default: 1)` + withEnvHint([]string{"uflag"}, ""),
  3415  			environ: map[string]string{
  3416  				"uflag": "10",
  3417  			},
  3418  		},
  3419  		{
  3420  			name:    "uint",
  3421  			flag:    &UintFlag{Name: "flag", Value: 1, EnvVars: []string{"uflag"}},
  3422  			toParse: []string{"--flag", "13"},
  3423  			expect:  `--flag value	(default: 1)` + withEnvHint([]string{"uflag"}, ""),
  3424  			environ: map[string]string{
  3425  				"uflag": "10",
  3426  			},
  3427  		},
  3428  		{
  3429  			name:    "int64",
  3430  			flag:    &Int64Flag{Name: "flag", Value: 1, EnvVars: []string{"uflag"}},
  3431  			toParse: []string{"--flag", "13"},
  3432  			expect:  `--flag value	(default: 1)` + withEnvHint([]string{"uflag"}, ""),
  3433  			environ: map[string]string{
  3434  				"uflag": "10",
  3435  			},
  3436  		},
  3437  		{
  3438  			name:    "int",
  3439  			flag:    &IntFlag{Name: "flag", Value: 1, EnvVars: []string{"uflag"}},
  3440  			toParse: []string{"--flag", "13"},
  3441  			expect:  `--flag value	(default: 1)` + withEnvHint([]string{"uflag"}, ""),
  3442  			environ: map[string]string{
  3443  				"uflag": "10",
  3444  			},
  3445  		},
  3446  		{
  3447  			name:    "duration",
  3448  			flag:    &DurationFlag{Name: "flag", Value: time.Second, EnvVars: []string{"uflag"}},
  3449  			toParse: []string{"--flag", "2m"},
  3450  			expect:  `--flag value	(default: 1s)` + withEnvHint([]string{"uflag"}, ""),
  3451  			environ: map[string]string{
  3452  				"uflag": "2h4m10s",
  3453  			},
  3454  		},
  3455  		{
  3456  			name:    "path",
  3457  			flag:    &PathFlag{Name: "flag", Value: "/tmp/foo", EnvVars: []string{"uflag"}},
  3458  			toParse: []string{"--flag", "/bar/ddfr"},
  3459  			expect:  `--flag value	(default: "/tmp/foo")` + withEnvHint([]string{"uflag"}, ""),
  3460  			environ: map[string]string{
  3461  				"uflag": "/bar/t/err",
  3462  			},
  3463  		},
  3464  		{
  3465  			name:    "timestamp",
  3466  			flag:    &TimestampFlag{Name: "flag", Value: NewTimestamp(ts), Layout: time.RFC3339, EnvVars: []string{"tflag"}},
  3467  			toParse: []string{"--flag", "2006-11-02T15:04:05Z"},
  3468  			expect:  `--flag value	(default: 2005-01-02 15:04:05 +0000 UTC)` + withEnvHint([]string{"tflag"}, ""),
  3469  			environ: map[string]string{
  3470  				"tflag": "2010-01-02T15:04:05Z",
  3471  			},
  3472  		},
  3473  		{
  3474  			name:    "generic",
  3475  			flag:    &GenericFlag{Name: "flag", Value: &Parser{"11", "12"}, EnvVars: []string{"gflag"}},
  3476  			toParse: []string{"--flag", "15,16"},
  3477  			expect:  `--flag value	(default: 11,12)` + withEnvHint([]string{"gflag"}, ""),
  3478  			environ: map[string]string{
  3479  				"gflag": "13,14",
  3480  			},
  3481  		},
  3482  	}
  3483  	for i, v := range cases {
  3484  		for key, val := range v.environ {
  3485  			os.Setenv(key, val)
  3486  		}
  3487  		set := flag.NewFlagSet("test", 0)
  3488  		set.SetOutput(io.Discard)
  3489  		if err := v.flag.Apply(set); err != nil {
  3490  			t.Fatal(err)
  3491  		}
  3492  		if err := set.Parse(v.toParse); err != nil {
  3493  			t.Error(err)
  3494  		}
  3495  		if got := v.flag.String(); got != v.expect {
  3496  			t.Errorf("TestFlagDefaultValue %d %s\nexpect:%s\ngot:%s", i, v.name, v.expect, got)
  3497  		}
  3498  	}
  3499  }
  3500  
  3501  type flagValueTestCase struct {
  3502  	name    string
  3503  	flag    Flag
  3504  	toParse []string
  3505  	expect  string
  3506  }
  3507  
  3508  func TestFlagValue(t *testing.T) {
  3509  	cases := []*flagValueTestCase{
  3510  		&flagValueTestCase{
  3511  			name:    "stringSlice",
  3512  			flag:    &StringSliceFlag{Name: "flag", Value: NewStringSlice("default1", "default2")},
  3513  			toParse: []string{"--flag", "parsed,parsed2", "--flag", "parsed3,parsed4"},
  3514  			expect:  `[parsed parsed2 parsed3 parsed4]`,
  3515  		},
  3516  		&flagValueTestCase{
  3517  			name:    "float64Slice",
  3518  			flag:    &Float64SliceFlag{Name: "flag", Value: NewFloat64Slice(1.1, 2.2)},
  3519  			toParse: []string{"--flag", "13.3,14.4", "--flag", "15.5,16.6"},
  3520  			expect:  `[]float64{13.3, 14.4, 15.5, 16.6}`,
  3521  		},
  3522  		&flagValueTestCase{
  3523  			name:    "int64Slice",
  3524  			flag:    &Int64SliceFlag{Name: "flag", Value: NewInt64Slice(1, 2)},
  3525  			toParse: []string{"--flag", "13,14", "--flag", "15,16"},
  3526  			expect:  `[]int64{13, 14, 15, 16}`,
  3527  		},
  3528  		&flagValueTestCase{
  3529  			name:    "intSlice",
  3530  			flag:    &IntSliceFlag{Name: "flag", Value: NewIntSlice(1, 2)},
  3531  			toParse: []string{"--flag", "13,14", "--flag", "15,16"},
  3532  			expect:  `[]int{13, 14, 15, 16}`,
  3533  		},
  3534  		&flagValueTestCase{
  3535  			name:    "uint64Slice",
  3536  			flag:    &Uint64SliceFlag{Name: "flag", Value: NewUint64Slice(1, 2)},
  3537  			toParse: []string{"--flag", "13,14", "--flag", "15,16"},
  3538  			expect:  `[]uint64{13, 14, 15, 16}`,
  3539  		},
  3540  		&flagValueTestCase{
  3541  			name:    "uintSlice",
  3542  			flag:    &UintSliceFlag{Name: "flag", Value: NewUintSlice(1, 2)},
  3543  			toParse: []string{"--flag", "13,14", "--flag", "15,16"},
  3544  			expect:  `[]uint{13, 14, 15, 16}`,
  3545  		},
  3546  	}
  3547  	for i, v := range cases {
  3548  		set := flag.NewFlagSet("test", 0)
  3549  		set.SetOutput(io.Discard)
  3550  		_ = v.flag.Apply(set)
  3551  		if err := set.Parse(v.toParse); err != nil {
  3552  			t.Error(err)
  3553  		}
  3554  		f := set.Lookup("flag")
  3555  		if got := f.Value.String(); got != v.expect {
  3556  			t.Errorf("TestFlagValue %d-%s\nexpect:%s\ngot:%s", i, v.name, v.expect, got)
  3557  		}
  3558  	}
  3559  }
  3560  
  3561  func TestTimestampFlagApply_WithDestination(t *testing.T) {
  3562  	var destination Timestamp
  3563  	expectedResult, _ := time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
  3564  	fl := TimestampFlag{Name: "time", Aliases: []string{"t"}, Layout: time.RFC3339, Destination: &destination}
  3565  	set := flag.NewFlagSet("test", 0)
  3566  	if err := fl.Apply(set); err != nil {
  3567  		t.Error(err)
  3568  	}
  3569  
  3570  	err := set.Parse([]string{"--time", "2006-01-02T15:04:05Z"})
  3571  	expect(t, err, nil)
  3572  	expect(t, *fl.Destination.timestamp, expectedResult)
  3573  }
  3574  
  3575  func TestTimestampFlagApply_EnvWithDestination(t *testing.T) {
  3576  	var tsValue Timestamp
  3577  
  3578  	app := NewApp()
  3579  	app.Flags = []Flag{
  3580  		&TimestampFlag{
  3581  			Name:        "some-timestamp-flag",
  3582  			EnvVars:     []string{"SOME_TIMESTAMP_FLAG"},
  3583  			Layout:      time.RFC3339,
  3584  			Destination: &tsValue,
  3585  			Required:    true,
  3586  		},
  3587  	}
  3588  
  3589  	t.Setenv("SOME_TIMESTAMP_FLAG", "2021-03-02T06:20:00Z")
  3590  
  3591  	err := app.Run([]string{})
  3592  
  3593  	expect(t, err, nil)
  3594  	expect(t, tsValue.Value().Format(time.RFC3339), "2021-03-02T06:20:00Z")
  3595  }
  3596  
  3597  // Test issue #1254
  3598  // StringSlice() with UseShortOptionHandling causes duplicated entries, depending on the ordering of the flags
  3599  func TestSliceShortOptionHandle(t *testing.T) {
  3600  	wasCalled := false
  3601  	err := (&App{
  3602  		Commands: []*Command{
  3603  			{
  3604  				Name:                   "foobar",
  3605  				UseShortOptionHandling: true,
  3606  				Action: func(ctx *Context) error {
  3607  					wasCalled = true
  3608  					if ctx.Bool("i") != true {
  3609  						t.Error("bool i not set")
  3610  					}
  3611  					if ctx.Bool("t") != true {
  3612  						t.Error("bool i not set")
  3613  					}
  3614  					ss := ctx.StringSlice("net")
  3615  					if !reflect.DeepEqual(ss, []string{"foo"}) {
  3616  						t.Errorf("Got different slice(%v) than expected", ss)
  3617  					}
  3618  					return nil
  3619  				},
  3620  				Flags: []Flag{
  3621  					&StringSliceFlag{Name: "net"},
  3622  					&BoolFlag{Name: "i"},
  3623  					&BoolFlag{Name: "t"},
  3624  				},
  3625  			},
  3626  		},
  3627  	}).Run([]string{"run", "foobar", "--net=foo", "-it"})
  3628  	if err != nil {
  3629  		t.Fatal(err)
  3630  	}
  3631  	if !wasCalled {
  3632  		t.Fatal("Action callback was never called")
  3633  	}
  3634  }
  3635  
  3636  // Test issue #1541
  3637  func TestDefaultSliceFlagSeparator(t *testing.T) {
  3638  	separator := separatorSpec{}
  3639  	opts := []string{"opt1", "opt2", "opt3", "opt4"}
  3640  	ret := separator.flagSplitMultiValues(strings.Join(opts, ","))
  3641  	if len(ret) != 4 {
  3642  		t.Fatalf("split slice flag failed, want: 4, but get: %d", len(ret))
  3643  	}
  3644  	for idx, r := range ret {
  3645  		if r != opts[idx] {
  3646  			t.Fatalf("get %dth failed, wanted: %s, but get: %s", idx, opts[idx], r)
  3647  		}
  3648  	}
  3649  }
  3650  
  3651  func TestCustomizedSliceFlagSeparator(t *testing.T) {
  3652  	separator := separatorSpec{
  3653  		customized: true,
  3654  		sep:        ";",
  3655  	}
  3656  	opts := []string{"opt1", "opt2", "opt3,op", "opt4"}
  3657  	ret := separator.flagSplitMultiValues(strings.Join(opts, ";"))
  3658  	if len(ret) != 4 {
  3659  		t.Fatalf("split slice flag failed, want: 4, but get: %d", len(ret))
  3660  	}
  3661  	for idx, r := range ret {
  3662  		if r != opts[idx] {
  3663  			t.Fatalf("get %dth failed, wanted: %s, but get: %s", idx, opts[idx], r)
  3664  		}
  3665  	}
  3666  }
  3667  
  3668  func TestFlagSplitMultiValues_Disabled(t *testing.T) {
  3669  	separator := separatorSpec{
  3670  		customized: true,
  3671  		disabled:   true,
  3672  	}
  3673  
  3674  	opts := []string{"opt1", "opt2", "opt3,op", "opt4"}
  3675  	ret := separator.flagSplitMultiValues(strings.Join(opts, defaultSliceFlagSeparator))
  3676  	if len(ret) != 1 {
  3677  		t.Fatalf("failed to disable split slice flag, want: 1, but got: %d", len(ret))
  3678  	}
  3679  
  3680  	if ret[0] != strings.Join(opts, defaultSliceFlagSeparator) {
  3681  		t.Fatalf("failed to disable split slice flag, want: %s, but got: %s", strings.Join(opts, defaultSliceFlagSeparator), ret[0])
  3682  	}
  3683  }
  3684  

View as plain text