1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
23 testBool = Bool("test_bool", false, "bool value")
24 testInt = Int("test_int", 0, "int value")
25 testInt64 = Int64("test_int64", 0, "int64 value")
26 testUint = Uint("test_uint", 0, "uint value")
27 testUint64 = Uint64("test_uint64", 0, "uint64 value")
28 testString = String("test_string", "0", "string value")
29 testFloat = Float64("test_float64", 0, "float64 value")
30 testDuration = Duration("test_duration", 0, "time.Duration value")
31 testOptionalInt = Int("test_optional_int", 0, "optional int value")
32 normalizeFlagNameInvocations = 0
35 func boolString(s string) string {
42 func TestEverything(t *testing.T) {
43 m := make(map[string]*Flag)
45 visitor := func(f *Flag) {
46 if len(f.Name) > 5 && f.Name[0:5] == "test_" {
50 case f.Value.String() == desired:
52 case f.Name == "test_bool" && f.Value.String() == boolString(desired):
54 case f.Name == "test_duration" && f.Value.String() == desired+"s":
58 t.Error("Visit: bad value", f.Value.String(), "for", f.Name)
64 t.Error("VisitAll misses some flags")
69 m = make(map[string]*Flag)
72 t.Errorf("Visit sees unset flags")
78 Set("test_bool", "true")
80 Set("test_int64", "1")
82 Set("test_uint64", "1")
83 Set("test_string", "1")
84 Set("test_float64", "1")
85 Set("test_duration", "1s")
86 Set("test_optional_int", "1")
90 t.Error("Visit fails after set")
95 // Now test they're visited in sort order.
96 var flagNames []string
97 Visit(func(f *Flag) { flagNames = append(flagNames, f.Name) })
98 if !sort.StringsAreSorted(flagNames) {
99 t.Errorf("flag names not sorted: %v", flagNames)
103 func TestUsage(t *testing.T) {
105 ResetForTesting(func() { called = true })
106 if GetCommandLine().Parse([]string{"--x"}) == nil {
107 t.Error("parse did not fail for unknown flag")
110 t.Error("did call Usage while using ContinueOnError")
114 func TestAddFlagSet(t *testing.T) {
115 oldSet := NewFlagSet("old", ContinueOnError)
116 newSet := NewFlagSet("new", ContinueOnError)
118 oldSet.String("flag1", "flag1", "flag1")
119 oldSet.String("flag2", "flag2", "flag2")
121 newSet.String("flag2", "flag2", "flag2")
122 newSet.String("flag3", "flag3", "flag3")
124 oldSet.AddFlagSet(newSet)
126 if len(oldSet.formal) != 3 {
127 t.Errorf("Unexpected result adding a FlagSet to a FlagSet %v", oldSet)
131 func TestAnnotation(t *testing.T) {
132 f := NewFlagSet("shorthand", ContinueOnError)
134 if err := f.SetAnnotation("missing-flag", "key", nil); err == nil {
135 t.Errorf("Expected error setting annotation on non-existent flag")
138 f.StringP("stringa", "a", "", "string value")
139 if err := f.SetAnnotation("stringa", "key", nil); err != nil {
140 t.Errorf("Unexpected error setting new nil annotation: %v", err)
142 if annotation := f.Lookup("stringa").Annotations["key"]; annotation != nil {
143 t.Errorf("Unexpected annotation: %v", annotation)
146 f.StringP("stringb", "b", "", "string2 value")
147 if err := f.SetAnnotation("stringb", "key", []string{"value1"}); err != nil {
148 t.Errorf("Unexpected error setting new annotation: %v", err)
150 if annotation := f.Lookup("stringb").Annotations["key"]; !reflect.DeepEqual(annotation, []string{"value1"}) {
151 t.Errorf("Unexpected annotation: %v", annotation)
154 if err := f.SetAnnotation("stringb", "key", []string{"value2"}); err != nil {
155 t.Errorf("Unexpected error updating annotation: %v", err)
157 if annotation := f.Lookup("stringb").Annotations["key"]; !reflect.DeepEqual(annotation, []string{"value2"}) {
158 t.Errorf("Unexpected annotation: %v", annotation)
162 func testParse(f *FlagSet, t *testing.T) {
164 t.Error("f.Parse() = true before Parse")
166 boolFlag := f.Bool("bool", false, "bool value")
167 bool2Flag := f.Bool("bool2", false, "bool2 value")
168 bool3Flag := f.Bool("bool3", false, "bool3 value")
169 intFlag := f.Int("int", 0, "int value")
170 int8Flag := f.Int8("int8", 0, "int value")
171 int16Flag := f.Int16("int16", 0, "int value")
172 int32Flag := f.Int32("int32", 0, "int value")
173 int64Flag := f.Int64("int64", 0, "int64 value")
174 uintFlag := f.Uint("uint", 0, "uint value")
175 uint8Flag := f.Uint8("uint8", 0, "uint value")
176 uint16Flag := f.Uint16("uint16", 0, "uint value")
177 uint32Flag := f.Uint32("uint32", 0, "uint value")
178 uint64Flag := f.Uint64("uint64", 0, "uint64 value")
179 stringFlag := f.String("string", "0", "string value")
180 float32Flag := f.Float32("float32", 0, "float32 value")
181 float64Flag := f.Float64("float64", 0, "float64 value")
182 ipFlag := f.IP("ip", net.ParseIP("127.0.0.1"), "ip value")
183 maskFlag := f.IPMask("mask", ParseIPv4Mask("0.0.0.0"), "mask value")
184 durationFlag := f.Duration("duration", 5*time.Second, "time.Duration value")
185 optionalIntNoValueFlag := f.Int("optional-int-no-value", 0, "int value")
186 f.Lookup("optional-int-no-value").NoOptDefVal = "9"
187 optionalIntWithValueFlag := f.Int("optional-int-with-value", 0, "int value")
188 f.Lookup("optional-int-no-value").NoOptDefVal = "9"
189 extra := "one-extra-argument"
208 "--mask=255.255.255.0",
210 "--optional-int-no-value",
211 "--optional-int-with-value=42",
214 if err := f.Parse(args); err != nil {
218 t.Error("f.Parse() = false after Parse")
220 if *boolFlag != true {
221 t.Error("bool flag should be true, is ", *boolFlag)
223 if v, err := f.GetBool("bool"); err != nil || v != *boolFlag {
224 t.Error("GetBool does not work.")
226 if *bool2Flag != true {
227 t.Error("bool2 flag should be true, is ", *bool2Flag)
229 if *bool3Flag != false {
230 t.Error("bool3 flag should be false, is ", *bool2Flag)
233 t.Error("int flag should be 22, is ", *intFlag)
235 if v, err := f.GetInt("int"); err != nil || v != *intFlag {
236 t.Error("GetInt does not work.")
239 t.Error("int8 flag should be 0x23, is ", *int8Flag)
241 if *int16Flag != -16 {
242 t.Error("int16 flag should be -16, is ", *int16Flag)
244 if v, err := f.GetInt8("int8"); err != nil || v != *int8Flag {
245 t.Error("GetInt8 does not work.")
247 if v, err := f.GetInt16("int16"); err != nil || v != *int16Flag {
248 t.Error("GetInt16 does not work.")
250 if *int32Flag != -32 {
251 t.Error("int32 flag should be 0x23, is ", *int32Flag)
253 if v, err := f.GetInt32("int32"); err != nil || v != *int32Flag {
254 t.Error("GetInt32 does not work.")
256 if *int64Flag != 0x23 {
257 t.Error("int64 flag should be 0x23, is ", *int64Flag)
259 if v, err := f.GetInt64("int64"); err != nil || v != *int64Flag {
260 t.Error("GetInt64 does not work.")
263 t.Error("uint flag should be 24, is ", *uintFlag)
265 if v, err := f.GetUint("uint"); err != nil || v != *uintFlag {
266 t.Error("GetUint does not work.")
269 t.Error("uint8 flag should be 8, is ", *uint8Flag)
271 if v, err := f.GetUint8("uint8"); err != nil || v != *uint8Flag {
272 t.Error("GetUint8 does not work.")
274 if *uint16Flag != 16 {
275 t.Error("uint16 flag should be 16, is ", *uint16Flag)
277 if v, err := f.GetUint16("uint16"); err != nil || v != *uint16Flag {
278 t.Error("GetUint16 does not work.")
280 if *uint32Flag != 32 {
281 t.Error("uint32 flag should be 32, is ", *uint32Flag)
283 if v, err := f.GetUint32("uint32"); err != nil || v != *uint32Flag {
284 t.Error("GetUint32 does not work.")
286 if *uint64Flag != 25 {
287 t.Error("uint64 flag should be 25, is ", *uint64Flag)
289 if v, err := f.GetUint64("uint64"); err != nil || v != *uint64Flag {
290 t.Error("GetUint64 does not work.")
292 if *stringFlag != "hello" {
293 t.Error("string flag should be `hello`, is ", *stringFlag)
295 if v, err := f.GetString("string"); err != nil || v != *stringFlag {
296 t.Error("GetString does not work.")
298 if *float32Flag != -172e12 {
299 t.Error("float32 flag should be -172e12, is ", *float32Flag)
301 if v, err := f.GetFloat32("float32"); err != nil || v != *float32Flag {
302 t.Errorf("GetFloat32 returned %v but float32Flag was %v", v, *float32Flag)
304 if *float64Flag != 2718e28 {
305 t.Error("float64 flag should be 2718e28, is ", *float64Flag)
307 if v, err := f.GetFloat64("float64"); err != nil || v != *float64Flag {
308 t.Errorf("GetFloat64 returned %v but float64Flag was %v", v, *float64Flag)
310 if !(*ipFlag).Equal(net.ParseIP("10.11.12.13")) {
311 t.Error("ip flag should be 10.11.12.13, is ", *ipFlag)
313 if v, err := f.GetIP("ip"); err != nil || !v.Equal(*ipFlag) {
314 t.Errorf("GetIP returned %v but ipFlag was %v", v, *ipFlag)
316 if (*maskFlag).String() != ParseIPv4Mask("255.255.255.0").String() {
317 t.Error("mask flag should be 255.255.255.0, is ", (*maskFlag).String())
319 if v, err := f.GetIPv4Mask("mask"); err != nil || v.String() != (*maskFlag).String() {
320 t.Errorf("GetIP returned %v maskFlag was %v error was %v", v, *maskFlag, err)
322 if *durationFlag != 2*time.Minute {
323 t.Error("duration flag should be 2m, is ", *durationFlag)
325 if v, err := f.GetDuration("duration"); err != nil || v != *durationFlag {
326 t.Error("GetDuration does not work.")
328 if _, err := f.GetInt("duration"); err == nil {
329 t.Error("GetInt parsed a time.Duration?!?!")
331 if *optionalIntNoValueFlag != 9 {
332 t.Error("optional int flag should be the default value, is ", *optionalIntNoValueFlag)
334 if *optionalIntWithValueFlag != 42 {
335 t.Error("optional int flag should be 42, is ", *optionalIntWithValueFlag)
337 if len(f.Args()) != 1 {
338 t.Error("expected one argument, got", len(f.Args()))
339 } else if f.Args()[0] != extra {
340 t.Errorf("expected argument %q got %q", extra, f.Args()[0])
344 func testParseAll(f *FlagSet, t *testing.T) {
346 t.Error("f.Parse() = true before Parse")
348 f.BoolP("boola", "a", false, "bool value")
349 f.BoolP("boolb", "b", false, "bool2 value")
350 f.BoolP("boolc", "c", false, "bool3 value")
351 f.BoolP("boold", "d", false, "bool4 value")
352 f.StringP("stringa", "s", "0", "string value")
353 f.StringP("stringz", "z", "0", "string value")
354 f.StringP("stringx", "x", "0", "string value")
355 f.StringP("stringy", "y", "0", "string value")
356 f.Lookup("stringx").NoOptDefVal = "1"
360 "--stringz=something",
371 "stringz", "something",
377 store := func(flag *Flag, value string) error {
378 got = append(got, flag.Name)
380 got = append(got, value)
384 if err := f.ParseAll(args, store); err != nil {
385 t.Errorf("expected no error, got %s", err)
388 t.Errorf("f.Parse() = false after Parse")
390 if !reflect.DeepEqual(got, want) {
391 t.Errorf("f.ParseAll() fail to restore the args")
392 t.Errorf("Got: %v", got)
393 t.Errorf("Want: %v", want)
397 func TestShorthand(t *testing.T) {
398 f := NewFlagSet("shorthand", ContinueOnError)
400 t.Error("f.Parse() = true before Parse")
402 boolaFlag := f.BoolP("boola", "a", false, "bool value")
403 boolbFlag := f.BoolP("boolb", "b", false, "bool2 value")
404 boolcFlag := f.BoolP("boolc", "c", false, "bool3 value")
405 booldFlag := f.BoolP("boold", "d", false, "bool4 value")
406 stringaFlag := f.StringP("stringa", "s", "0", "string value")
407 stringzFlag := f.StringP("stringz", "z", "0", "string value")
408 extra := "interspersed-argument"
409 notaflag := "--i-look-like-a-flag"
420 f.SetOutput(ioutil.Discard)
421 if err := f.Parse(args); err != nil {
422 t.Error("expected no error, got ", err)
425 t.Error("f.Parse() = false after Parse")
427 if *boolaFlag != true {
428 t.Error("boola flag should be true, is ", *boolaFlag)
430 if *boolbFlag != true {
431 t.Error("boolb flag should be true, is ", *boolbFlag)
433 if *boolcFlag != true {
434 t.Error("boolc flag should be true, is ", *boolcFlag)
436 if *booldFlag != true {
437 t.Error("boold flag should be true, is ", *booldFlag)
439 if *stringaFlag != "hello" {
440 t.Error("stringa flag should be `hello`, is ", *stringaFlag)
442 if *stringzFlag != "something" {
443 t.Error("stringz flag should be `something`, is ", *stringzFlag)
445 if len(f.Args()) != 2 {
446 t.Error("expected one argument, got", len(f.Args()))
447 } else if f.Args()[0] != extra {
448 t.Errorf("expected argument %q got %q", extra, f.Args()[0])
449 } else if f.Args()[1] != notaflag {
450 t.Errorf("expected argument %q got %q", notaflag, f.Args()[1])
452 if f.ArgsLenAtDash() != 1 {
453 t.Errorf("expected argsLenAtDash %d got %d", f.ArgsLenAtDash(), 1)
457 func TestShorthandLookup(t *testing.T) {
458 f := NewFlagSet("shorthand", ContinueOnError)
460 t.Error("f.Parse() = true before Parse")
462 f.BoolP("boola", "a", false, "bool value")
463 f.BoolP("boolb", "b", false, "bool2 value")
467 f.SetOutput(ioutil.Discard)
468 if err := f.Parse(args); err != nil {
469 t.Error("expected no error, got ", err)
472 t.Error("f.Parse() = false after Parse")
474 flag := f.ShorthandLookup("a")
476 t.Errorf("f.ShorthandLookup(\"a\") returned nil")
478 if flag.Name != "boola" {
479 t.Errorf("f.ShorthandLookup(\"a\") found %q instead of \"boola\"", flag.Name)
481 flag = f.ShorthandLookup("")
483 t.Errorf("f.ShorthandLookup(\"\") did not return nil")
488 flag = f.ShorthandLookup("ab")
489 // should NEVER get here. lookup should panic. defer'd func should recover it.
490 t.Errorf("f.ShorthandLookup(\"ab\") did not panic")
493 func TestParse(t *testing.T) {
494 ResetForTesting(func() { t.Error("bad parse") })
495 testParse(GetCommandLine(), t)
498 func TestParseAll(t *testing.T) {
499 ResetForTesting(func() { t.Error("bad parse") })
500 testParseAll(GetCommandLine(), t)
503 func TestFlagSetParse(t *testing.T) {
504 testParse(NewFlagSet("test", ContinueOnError), t)
507 func TestChangedHelper(t *testing.T) {
508 f := NewFlagSet("changedtest", ContinueOnError)
509 f.Bool("changed", false, "changed bool")
510 f.Bool("settrue", true, "true to true")
511 f.Bool("setfalse", false, "false to false")
512 f.Bool("unchanged", false, "unchanged bool")
514 args := []string{"--changed", "--settrue", "--setfalse=false"}
515 if err := f.Parse(args); err != nil {
516 t.Error("f.Parse() = false after Parse")
518 if !f.Changed("changed") {
519 t.Errorf("--changed wasn't changed!")
521 if !f.Changed("settrue") {
522 t.Errorf("--settrue wasn't changed!")
524 if !f.Changed("setfalse") {
525 t.Errorf("--setfalse wasn't changed!")
527 if f.Changed("unchanged") {
528 t.Errorf("--unchanged was changed!")
530 if f.Changed("invalid") {
531 t.Errorf("--invalid was changed!")
533 if f.ArgsLenAtDash() != -1 {
534 t.Errorf("Expected argsLenAtDash: %d but got %d", -1, f.ArgsLenAtDash())
538 func replaceSeparators(name string, from []string, to string) string {
540 for _, sep := range from {
541 result = strings.Replace(result, sep, to, -1)
543 // Type convert to indicate normalization has been done.
547 func wordSepNormalizeFunc(f *FlagSet, name string) NormalizedName {
548 seps := []string{"-", "_"}
549 name = replaceSeparators(name, seps, ".")
550 normalizeFlagNameInvocations++
552 return NormalizedName(name)
555 func testWordSepNormalizedNames(args []string, t *testing.T) {
556 f := NewFlagSet("normalized", ContinueOnError)
558 t.Error("f.Parse() = true before Parse")
560 withDashFlag := f.Bool("with-dash-flag", false, "bool value")
561 // Set this after some flags have been added and before others.
562 f.SetNormalizeFunc(wordSepNormalizeFunc)
563 withUnderFlag := f.Bool("with_under_flag", false, "bool value")
564 withBothFlag := f.Bool("with-both_flag", false, "bool value")
565 if err := f.Parse(args); err != nil {
569 t.Error("f.Parse() = false after Parse")
571 if *withDashFlag != true {
572 t.Error("withDashFlag flag should be true, is ", *withDashFlag)
574 if *withUnderFlag != true {
575 t.Error("withUnderFlag flag should be true, is ", *withUnderFlag)
577 if *withBothFlag != true {
578 t.Error("withBothFlag flag should be true, is ", *withBothFlag)
582 func TestWordSepNormalizedNames(t *testing.T) {
588 testWordSepNormalizedNames(args, t)
595 testWordSepNormalizedNames(args, t)
602 testWordSepNormalizedNames(args, t)
605 func aliasAndWordSepFlagNames(f *FlagSet, name string) NormalizedName {
606 seps := []string{"-", "_"}
608 oldName := replaceSeparators("old-valid_flag", seps, ".")
609 newName := replaceSeparators("valid-flag", seps, ".")
611 name = replaceSeparators(name, seps, ".")
617 return NormalizedName(name)
620 func TestCustomNormalizedNames(t *testing.T) {
621 f := NewFlagSet("normalized", ContinueOnError)
623 t.Error("f.Parse() = true before Parse")
626 validFlag := f.Bool("valid-flag", false, "bool value")
627 f.SetNormalizeFunc(aliasAndWordSepFlagNames)
628 someOtherFlag := f.Bool("some-other-flag", false, "bool value")
630 args := []string{"--old_valid_flag", "--some-other_flag"}
631 if err := f.Parse(args); err != nil {
635 if *validFlag != true {
636 t.Errorf("validFlag is %v even though we set the alias --old_valid_falg", *validFlag)
638 if *someOtherFlag != true {
639 t.Error("someOtherFlag should be true, is ", *someOtherFlag)
643 // Every flag we add, the name (displayed also in usage) should normalized
644 func TestNormalizationFuncShouldChangeFlagName(t *testing.T) {
645 // Test normalization after addition
646 f := NewFlagSet("normalized", ContinueOnError)
648 f.Bool("valid_flag", false, "bool value")
649 if f.Lookup("valid_flag").Name != "valid_flag" {
650 t.Error("The new flag should have the name 'valid_flag' instead of ", f.Lookup("valid_flag").Name)
653 f.SetNormalizeFunc(wordSepNormalizeFunc)
654 if f.Lookup("valid_flag").Name != "valid.flag" {
655 t.Error("The new flag should have the name 'valid.flag' instead of ", f.Lookup("valid_flag").Name)
658 // Test normalization before addition
659 f = NewFlagSet("normalized", ContinueOnError)
660 f.SetNormalizeFunc(wordSepNormalizeFunc)
662 f.Bool("valid_flag", false, "bool value")
663 if f.Lookup("valid_flag").Name != "valid.flag" {
664 t.Error("The new flag should have the name 'valid.flag' instead of ", f.Lookup("valid_flag").Name)
668 // Related to https://github.com/spf13/cobra/issues/521.
669 func TestNormalizationSharedFlags(t *testing.T) {
670 f := NewFlagSet("set f", ContinueOnError)
671 g := NewFlagSet("set g", ContinueOnError)
672 nfunc := wordSepNormalizeFunc
673 testName := "valid_flag"
674 normName := nfunc(nil, testName)
675 if testName == string(normName) {
676 t.Error("TestNormalizationSharedFlags meaningless: the original and normalized flag names are identical:", testName)
679 f.Bool(testName, false, "bool value")
682 f.SetNormalizeFunc(nfunc)
683 g.SetNormalizeFunc(nfunc)
685 if len(f.formal) != 1 {
686 t.Error("Normalizing flags should not result in duplications in the flag set:", f.formal)
688 if f.orderedFormal[0].Name != string(normName) {
689 t.Error("Flag name not normalized")
691 for k := range f.formal {
692 if k != "valid.flag" {
693 t.Errorf("The key in the flag map should have been normalized: wanted \"%s\", got \"%s\" instead", normName, k)
697 if !reflect.DeepEqual(f.formal, g.formal) || !reflect.DeepEqual(f.orderedFormal, g.orderedFormal) {
698 t.Error("Two flag sets sharing the same flags should stay consistent after being normalized. Original set:", f.formal, "Duplicate set:", g.formal)
702 func TestNormalizationSetFlags(t *testing.T) {
703 f := NewFlagSet("normalized", ContinueOnError)
704 nfunc := wordSepNormalizeFunc
705 testName := "valid_flag"
706 normName := nfunc(nil, testName)
707 if testName == string(normName) {
708 t.Error("TestNormalizationSetFlags meaningless: the original and normalized flag names are identical:", testName)
711 f.Bool(testName, false, "bool value")
712 f.Set(testName, "true")
713 f.SetNormalizeFunc(nfunc)
715 if len(f.formal) != 1 {
716 t.Error("Normalizing flags should not result in duplications in the flag set:", f.formal)
718 if f.orderedFormal[0].Name != string(normName) {
719 t.Error("Flag name not normalized")
721 for k := range f.formal {
722 if k != "valid.flag" {
723 t.Errorf("The key in the flag map should have been normalized: wanted \"%s\", got \"%s\" instead", normName, k)
727 if !reflect.DeepEqual(f.formal, f.actual) {
728 t.Error("The map of set flags should get normalized. Formal:", f.formal, "Actual:", f.actual)
732 // Declare a user-defined flag type.
733 type flagVar []string
735 func (f *flagVar) String() string {
736 return fmt.Sprint([]string(*f))
739 func (f *flagVar) Set(value string) error {
740 *f = append(*f, value)
744 func (f *flagVar) Type() string {
748 func TestUserDefined(t *testing.T) {
750 flags.Init("test", ContinueOnError)
752 flags.VarP(&v, "v", "v", "usage")
753 if err := flags.Parse([]string{"--v=1", "-v2", "-v", "3"}); err != nil {
757 t.Fatal("expected 3 args; got ", len(v))
760 if v.String() != expect {
761 t.Errorf("expected value %q got %q", expect, v.String())
765 func TestSetOutput(t *testing.T) {
768 flags.SetOutput(&buf)
769 flags.Init("test", ContinueOnError)
770 flags.Parse([]string{"--unknown"})
771 if out := buf.String(); !strings.Contains(out, "--unknown") {
772 t.Logf("expected output mentioning unknown; got %q", out)
776 // This tests that one can reset the flags. This still works but not well, and is
777 // superseded by FlagSet.
778 func TestChangingArgs(t *testing.T) {
779 ResetForTesting(func() { t.Fatal("bad parse") })
781 defer func() { os.Args = oldArgs }()
782 os.Args = []string{"cmd", "--before", "subcmd"}
783 before := Bool("before", false, "")
784 if err := GetCommandLine().Parse(os.Args[1:]); err != nil {
788 os.Args = []string{"subcmd", "--after", "args"}
789 after := Bool("after", false, "")
793 if !*before || cmd != "subcmd" || !*after || len(args) != 1 || args[0] != "args" {
794 t.Fatalf("expected true subcmd true [args] got %v %v %v %v", *before, cmd, *after, args)
798 // Test that -help invokes the usage message and returns ErrHelp.
799 func TestHelp(t *testing.T) {
800 var helpCalled = false
801 fs := NewFlagSet("help test", ContinueOnError)
802 fs.Usage = func() { helpCalled = true }
804 fs.BoolVar(&flag, "flag", false, "regular flag")
805 // Regular flag invocation should work
806 err := fs.Parse([]string{"--flag=true"})
808 t.Fatal("expected no error; got ", err)
811 t.Error("flag was not set by --flag")
814 t.Error("help called for regular flag")
815 helpCalled = false // reset for next test
817 // Help flag should work as expected.
818 err = fs.Parse([]string{"--help"})
820 t.Fatal("error expected")
823 t.Fatal("expected ErrHelp; got ", err)
826 t.Fatal("help was not called")
828 // If we define a help flag, that should override.
830 fs.BoolVar(&help, "help", false, "help flag")
832 err = fs.Parse([]string{"--help"})
834 t.Fatal("expected no error for defined --help; got ", err)
837 t.Fatal("help was called; should not have been for defined help flag")
841 func TestNoInterspersed(t *testing.T) {
842 f := NewFlagSet("test", ContinueOnError)
843 f.SetInterspersed(false)
844 f.Bool("true", true, "always true")
845 f.Bool("false", false, "always false")
846 err := f.Parse([]string{"--true", "break", "--false"})
848 t.Fatal("expected no error; got ", err)
851 if len(args) != 2 || args[0] != "break" || args[1] != "--false" {
852 t.Fatal("expected interspersed options/non-options to fail")
856 func TestTermination(t *testing.T) {
857 f := NewFlagSet("termination", ContinueOnError)
858 boolFlag := f.BoolP("bool", "l", false, "bool value")
860 t.Error("f.Parse() = true before Parse")
869 f.SetOutput(ioutil.Discard)
870 if err := f.Parse(args); err != nil {
871 t.Fatal("expected no error; got ", err)
874 t.Error("f.Parse() = false after Parse")
877 t.Error("expected boolFlag=false, got true")
879 if len(f.Args()) != 2 {
880 t.Errorf("expected 2 arguments, got %d: %v", len(f.Args()), f.Args())
882 if f.Args()[0] != arg1 {
883 t.Errorf("expected argument %q got %q", arg1, f.Args()[0])
885 if f.Args()[1] != arg2 {
886 t.Errorf("expected argument %q got %q", arg2, f.Args()[1])
888 if f.ArgsLenAtDash() != 0 {
889 t.Errorf("expected argsLenAtDash %d got %d", 0, f.ArgsLenAtDash())
893 func TestDeprecatedFlagInDocs(t *testing.T) {
894 f := NewFlagSet("bob", ContinueOnError)
895 f.Bool("badflag", true, "always true")
896 f.MarkDeprecated("badflag", "use --good-flag instead")
898 out := new(bytes.Buffer)
902 if strings.Contains(out.String(), "badflag") {
903 t.Errorf("found deprecated flag in usage!")
907 func TestDeprecatedFlagShorthandInDocs(t *testing.T) {
908 f := NewFlagSet("bob", ContinueOnError)
909 name := "noshorthandflag"
910 f.BoolP(name, "n", true, "always true")
911 f.MarkShorthandDeprecated("noshorthandflag", fmt.Sprintf("use --%s instead", name))
913 out := new(bytes.Buffer)
917 if strings.Contains(out.String(), "-n,") {
918 t.Errorf("found deprecated flag shorthand in usage!")
922 func parseReturnStderr(t *testing.T, f *FlagSet, args []string) (string, error) {
923 oldStderr := os.Stderr
929 outC := make(chan string)
930 // copy the output in a separate goroutine so printing can't block indefinitely
938 os.Stderr = oldStderr
944 func TestDeprecatedFlagUsage(t *testing.T) {
945 f := NewFlagSet("bob", ContinueOnError)
946 f.Bool("badflag", true, "always true")
947 usageMsg := "use --good-flag instead"
948 f.MarkDeprecated("badflag", usageMsg)
950 args := []string{"--badflag"}
951 out, err := parseReturnStderr(t, f, args)
953 t.Fatal("expected no error; got ", err)
956 if !strings.Contains(out, usageMsg) {
957 t.Errorf("usageMsg not printed when using a deprecated flag!")
961 func TestDeprecatedFlagShorthandUsage(t *testing.T) {
962 f := NewFlagSet("bob", ContinueOnError)
963 name := "noshorthandflag"
964 f.BoolP(name, "n", true, "always true")
965 usageMsg := fmt.Sprintf("use --%s instead", name)
966 f.MarkShorthandDeprecated(name, usageMsg)
968 args := []string{"-n"}
969 out, err := parseReturnStderr(t, f, args)
971 t.Fatal("expected no error; got ", err)
974 if !strings.Contains(out, usageMsg) {
975 t.Errorf("usageMsg not printed when using a deprecated flag!")
979 func TestDeprecatedFlagUsageNormalized(t *testing.T) {
980 f := NewFlagSet("bob", ContinueOnError)
981 f.Bool("bad-double_flag", true, "always true")
982 f.SetNormalizeFunc(wordSepNormalizeFunc)
983 usageMsg := "use --good-flag instead"
984 f.MarkDeprecated("bad_double-flag", usageMsg)
986 args := []string{"--bad_double_flag"}
987 out, err := parseReturnStderr(t, f, args)
989 t.Fatal("expected no error; got ", err)
992 if !strings.Contains(out, usageMsg) {
993 t.Errorf("usageMsg not printed when using a deprecated flag!")
997 // Name normalization function should be called only once on flag addition
998 func TestMultipleNormalizeFlagNameInvocations(t *testing.T) {
999 normalizeFlagNameInvocations = 0
1001 f := NewFlagSet("normalized", ContinueOnError)
1002 f.SetNormalizeFunc(wordSepNormalizeFunc)
1003 f.Bool("with_under_flag", false, "bool value")
1005 if normalizeFlagNameInvocations != 1 {
1006 t.Fatal("Expected normalizeFlagNameInvocations to be 1; got ", normalizeFlagNameInvocations)
1011 func TestHiddenFlagInUsage(t *testing.T) {
1012 f := NewFlagSet("bob", ContinueOnError)
1013 f.Bool("secretFlag", true, "shhh")
1014 f.MarkHidden("secretFlag")
1016 out := new(bytes.Buffer)
1020 if strings.Contains(out.String(), "secretFlag") {
1021 t.Errorf("found hidden flag in usage!")
1026 func TestHiddenFlagUsage(t *testing.T) {
1027 f := NewFlagSet("bob", ContinueOnError)
1028 f.Bool("secretFlag", true, "shhh")
1029 f.MarkHidden("secretFlag")
1031 args := []string{"--secretFlag"}
1032 out, err := parseReturnStderr(t, f, args)
1034 t.Fatal("expected no error; got ", err)
1037 if strings.Contains(out, "shhh") {
1038 t.Errorf("usage message printed when using a hidden flag!")
1042 const defaultOutput = ` --A for bootstrapping, allow 'any' type
1043 --Alongflagname disable bounds checking
1044 -C, --CCC a boolean defaulting to true (default true)
1045 --D path set relative path for local imports
1046 -E, --EEE num[=1234] a num with NoOptDefVal (default 4321)
1047 --F number a non-zero number (default 2.7)
1048 --G float a float that defaults to zero
1049 --IP ip IP address with no default
1050 --IPMask ipMask Netmask address with no default
1051 --IPNet ipNet IP network with no default
1052 --Ints ints int slice with zero default
1053 --N int a non-zero int (default 27)
1054 --ND1 string[="bar"] a string with NoOptDefVal (default "foo")
1055 --ND2 num[=4321] a num with NoOptDefVal (default 1234)
1056 --StringArray stringArray string array with zero default
1057 --StringSlice strings string slice with zero default
1058 --Z int an int that defaults to zero
1059 --custom custom custom Value implementation
1060 --customP custom a VarP with default (default 10)
1061 --maxT timeout set timeout for dial
1062 -v, --verbose count verbosity
1065 // Custom value that satisfies the Value interface.
1066 type customValue int
1068 func (cv *customValue) String() string { return fmt.Sprintf("%v", *cv) }
1070 func (cv *customValue) Set(s string) error {
1071 v, err := strconv.ParseInt(s, 0, 64)
1072 *cv = customValue(v)
1076 func (cv *customValue) Type() string { return "custom" }
1078 func TestPrintDefaults(t *testing.T) {
1079 fs := NewFlagSet("print defaults test", ContinueOnError)
1080 var buf bytes.Buffer
1082 fs.Bool("A", false, "for bootstrapping, allow 'any' type")
1083 fs.Bool("Alongflagname", false, "disable bounds checking")
1084 fs.BoolP("CCC", "C", true, "a boolean defaulting to true")
1085 fs.String("D", "", "set relative `path` for local imports")
1086 fs.Float64("F", 2.7, "a non-zero `number`")
1087 fs.Float64("G", 0, "a float that defaults to zero")
1088 fs.Int("N", 27, "a non-zero int")
1089 fs.IntSlice("Ints", []int{}, "int slice with zero default")
1090 fs.IP("IP", nil, "IP address with no default")
1091 fs.IPMask("IPMask", nil, "Netmask address with no default")
1092 fs.IPNet("IPNet", net.IPNet{}, "IP network with no default")
1093 fs.Int("Z", 0, "an int that defaults to zero")
1094 fs.Duration("maxT", 0, "set `timeout` for dial")
1095 fs.String("ND1", "foo", "a string with NoOptDefVal")
1096 fs.Lookup("ND1").NoOptDefVal = "bar"
1097 fs.Int("ND2", 1234, "a `num` with NoOptDefVal")
1098 fs.Lookup("ND2").NoOptDefVal = "4321"
1099 fs.IntP("EEE", "E", 4321, "a `num` with NoOptDefVal")
1100 fs.ShorthandLookup("E").NoOptDefVal = "1234"
1101 fs.StringSlice("StringSlice", []string{}, "string slice with zero default")
1102 fs.StringArray("StringArray", []string{}, "string array with zero default")
1103 fs.CountP("verbose", "v", "verbosity")
1106 fs.Var(&cv, "custom", "custom Value implementation")
1108 cv2 := customValue(10)
1109 fs.VarP(&cv2, "customP", "", "a VarP with default")
1113 if got != defaultOutput {
1114 fmt.Println("\n" + got)
1115 fmt.Println("\n" + defaultOutput)
1116 t.Errorf("got %q want %q\n", got, defaultOutput)
1120 func TestVisitAllFlagOrder(t *testing.T) {
1121 fs := NewFlagSet("TestVisitAllFlagOrder", ContinueOnError)
1122 fs.SortFlags = false
1123 // https://github.com/spf13/pflag/issues/120
1124 fs.SetNormalizeFunc(func(f *FlagSet, name string) NormalizedName {
1125 return NormalizedName(name)
1128 names := []string{"C", "B", "A", "D"}
1129 for _, name := range names {
1130 fs.Bool(name, false, "")
1134 fs.VisitAll(func(f *Flag) {
1135 if names[i] != f.Name {
1136 t.Errorf("Incorrect order. Expected %v, got %v", names[i], f.Name)
1142 func TestVisitFlagOrder(t *testing.T) {
1143 fs := NewFlagSet("TestVisitFlagOrder", ContinueOnError)
1144 fs.SortFlags = false
1145 names := []string{"C", "B", "A", "D"}
1146 for _, name := range names {
1147 fs.Bool(name, false, "")
1148 fs.Set(name, "true")
1152 fs.Visit(func(f *Flag) {
1153 if names[i] != f.Name {
1154 t.Errorf("Incorrect order. Expected %v, got %v", names[i], f.Name)