OSDN Git Service

Hulk did something
[bytom/vapor.git] / vendor / github.com / spf13 / pflag / flag_test.go
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.
4
5 package pflag
6
7 import (
8         "bytes"
9         "fmt"
10         "io"
11         "io/ioutil"
12         "net"
13         "os"
14         "reflect"
15         "sort"
16         "strconv"
17         "strings"
18         "testing"
19         "time"
20 )
21
22 var (
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
33 )
34
35 func boolString(s string) string {
36         if s == "0" {
37                 return "false"
38         }
39         return "true"
40 }
41
42 func TestEverything(t *testing.T) {
43         m := make(map[string]*Flag)
44         desired := "0"
45         visitor := func(f *Flag) {
46                 if len(f.Name) > 5 && f.Name[0:5] == "test_" {
47                         m[f.Name] = f
48                         ok := false
49                         switch {
50                         case f.Value.String() == desired:
51                                 ok = true
52                         case f.Name == "test_bool" && f.Value.String() == boolString(desired):
53                                 ok = true
54                         case f.Name == "test_duration" && f.Value.String() == desired+"s":
55                                 ok = true
56                         }
57                         if !ok {
58                                 t.Error("Visit: bad value", f.Value.String(), "for", f.Name)
59                         }
60                 }
61         }
62         VisitAll(visitor)
63         if len(m) != 9 {
64                 t.Error("VisitAll misses some flags")
65                 for k, v := range m {
66                         t.Log(k, *v)
67                 }
68         }
69         m = make(map[string]*Flag)
70         Visit(visitor)
71         if len(m) != 0 {
72                 t.Errorf("Visit sees unset flags")
73                 for k, v := range m {
74                         t.Log(k, *v)
75                 }
76         }
77         // Now set all flags
78         Set("test_bool", "true")
79         Set("test_int", "1")
80         Set("test_int64", "1")
81         Set("test_uint", "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")
87         desired = "1"
88         Visit(visitor)
89         if len(m) != 9 {
90                 t.Error("Visit fails after set")
91                 for k, v := range m {
92                         t.Log(k, *v)
93                 }
94         }
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)
100         }
101 }
102
103 func TestUsage(t *testing.T) {
104         called := false
105         ResetForTesting(func() { called = true })
106         if GetCommandLine().Parse([]string{"--x"}) == nil {
107                 t.Error("parse did not fail for unknown flag")
108         }
109         if called {
110                 t.Error("did call Usage while using ContinueOnError")
111         }
112 }
113
114 func TestAddFlagSet(t *testing.T) {
115         oldSet := NewFlagSet("old", ContinueOnError)
116         newSet := NewFlagSet("new", ContinueOnError)
117
118         oldSet.String("flag1", "flag1", "flag1")
119         oldSet.String("flag2", "flag2", "flag2")
120
121         newSet.String("flag2", "flag2", "flag2")
122         newSet.String("flag3", "flag3", "flag3")
123
124         oldSet.AddFlagSet(newSet)
125
126         if len(oldSet.formal) != 3 {
127                 t.Errorf("Unexpected result adding a FlagSet to a FlagSet %v", oldSet)
128         }
129 }
130
131 func TestAnnotation(t *testing.T) {
132         f := NewFlagSet("shorthand", ContinueOnError)
133
134         if err := f.SetAnnotation("missing-flag", "key", nil); err == nil {
135                 t.Errorf("Expected error setting annotation on non-existent flag")
136         }
137
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)
141         }
142         if annotation := f.Lookup("stringa").Annotations["key"]; annotation != nil {
143                 t.Errorf("Unexpected annotation: %v", annotation)
144         }
145
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)
149         }
150         if annotation := f.Lookup("stringb").Annotations["key"]; !reflect.DeepEqual(annotation, []string{"value1"}) {
151                 t.Errorf("Unexpected annotation: %v", annotation)
152         }
153
154         if err := f.SetAnnotation("stringb", "key", []string{"value2"}); err != nil {
155                 t.Errorf("Unexpected error updating annotation: %v", err)
156         }
157         if annotation := f.Lookup("stringb").Annotations["key"]; !reflect.DeepEqual(annotation, []string{"value2"}) {
158                 t.Errorf("Unexpected annotation: %v", annotation)
159         }
160 }
161
162 func testParse(f *FlagSet, t *testing.T) {
163         if f.Parsed() {
164                 t.Error("f.Parse() = true before Parse")
165         }
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"
190         args := []string{
191                 "--bool",
192                 "--bool2=true",
193                 "--bool3=false",
194                 "--int=22",
195                 "--int8=-8",
196                 "--int16=-16",
197                 "--int32=-32",
198                 "--int64=0x23",
199                 "--uint", "24",
200                 "--uint8=8",
201                 "--uint16=16",
202                 "--uint32=32",
203                 "--uint64=25",
204                 "--string=hello",
205                 "--float32=-172e12",
206                 "--float64=2718e28",
207                 "--ip=10.11.12.13",
208                 "--mask=255.255.255.0",
209                 "--duration=2m",
210                 "--optional-int-no-value",
211                 "--optional-int-with-value=42",
212                 extra,
213         }
214         if err := f.Parse(args); err != nil {
215                 t.Fatal(err)
216         }
217         if !f.Parsed() {
218                 t.Error("f.Parse() = false after Parse")
219         }
220         if *boolFlag != true {
221                 t.Error("bool flag should be true, is ", *boolFlag)
222         }
223         if v, err := f.GetBool("bool"); err != nil || v != *boolFlag {
224                 t.Error("GetBool does not work.")
225         }
226         if *bool2Flag != true {
227                 t.Error("bool2 flag should be true, is ", *bool2Flag)
228         }
229         if *bool3Flag != false {
230                 t.Error("bool3 flag should be false, is ", *bool2Flag)
231         }
232         if *intFlag != 22 {
233                 t.Error("int flag should be 22, is ", *intFlag)
234         }
235         if v, err := f.GetInt("int"); err != nil || v != *intFlag {
236                 t.Error("GetInt does not work.")
237         }
238         if *int8Flag != -8 {
239                 t.Error("int8 flag should be 0x23, is ", *int8Flag)
240         }
241         if *int16Flag != -16 {
242                 t.Error("int16 flag should be -16, is ", *int16Flag)
243         }
244         if v, err := f.GetInt8("int8"); err != nil || v != *int8Flag {
245                 t.Error("GetInt8 does not work.")
246         }
247         if v, err := f.GetInt16("int16"); err != nil || v != *int16Flag {
248                 t.Error("GetInt16 does not work.")
249         }
250         if *int32Flag != -32 {
251                 t.Error("int32 flag should be 0x23, is ", *int32Flag)
252         }
253         if v, err := f.GetInt32("int32"); err != nil || v != *int32Flag {
254                 t.Error("GetInt32 does not work.")
255         }
256         if *int64Flag != 0x23 {
257                 t.Error("int64 flag should be 0x23, is ", *int64Flag)
258         }
259         if v, err := f.GetInt64("int64"); err != nil || v != *int64Flag {
260                 t.Error("GetInt64 does not work.")
261         }
262         if *uintFlag != 24 {
263                 t.Error("uint flag should be 24, is ", *uintFlag)
264         }
265         if v, err := f.GetUint("uint"); err != nil || v != *uintFlag {
266                 t.Error("GetUint does not work.")
267         }
268         if *uint8Flag != 8 {
269                 t.Error("uint8 flag should be 8, is ", *uint8Flag)
270         }
271         if v, err := f.GetUint8("uint8"); err != nil || v != *uint8Flag {
272                 t.Error("GetUint8 does not work.")
273         }
274         if *uint16Flag != 16 {
275                 t.Error("uint16 flag should be 16, is ", *uint16Flag)
276         }
277         if v, err := f.GetUint16("uint16"); err != nil || v != *uint16Flag {
278                 t.Error("GetUint16 does not work.")
279         }
280         if *uint32Flag != 32 {
281                 t.Error("uint32 flag should be 32, is ", *uint32Flag)
282         }
283         if v, err := f.GetUint32("uint32"); err != nil || v != *uint32Flag {
284                 t.Error("GetUint32 does not work.")
285         }
286         if *uint64Flag != 25 {
287                 t.Error("uint64 flag should be 25, is ", *uint64Flag)
288         }
289         if v, err := f.GetUint64("uint64"); err != nil || v != *uint64Flag {
290                 t.Error("GetUint64 does not work.")
291         }
292         if *stringFlag != "hello" {
293                 t.Error("string flag should be `hello`, is ", *stringFlag)
294         }
295         if v, err := f.GetString("string"); err != nil || v != *stringFlag {
296                 t.Error("GetString does not work.")
297         }
298         if *float32Flag != -172e12 {
299                 t.Error("float32 flag should be -172e12, is ", *float32Flag)
300         }
301         if v, err := f.GetFloat32("float32"); err != nil || v != *float32Flag {
302                 t.Errorf("GetFloat32 returned %v but float32Flag was %v", v, *float32Flag)
303         }
304         if *float64Flag != 2718e28 {
305                 t.Error("float64 flag should be 2718e28, is ", *float64Flag)
306         }
307         if v, err := f.GetFloat64("float64"); err != nil || v != *float64Flag {
308                 t.Errorf("GetFloat64 returned %v but float64Flag was %v", v, *float64Flag)
309         }
310         if !(*ipFlag).Equal(net.ParseIP("10.11.12.13")) {
311                 t.Error("ip flag should be 10.11.12.13, is ", *ipFlag)
312         }
313         if v, err := f.GetIP("ip"); err != nil || !v.Equal(*ipFlag) {
314                 t.Errorf("GetIP returned %v but ipFlag was %v", v, *ipFlag)
315         }
316         if (*maskFlag).String() != ParseIPv4Mask("255.255.255.0").String() {
317                 t.Error("mask flag should be 255.255.255.0, is ", (*maskFlag).String())
318         }
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)
321         }
322         if *durationFlag != 2*time.Minute {
323                 t.Error("duration flag should be 2m, is ", *durationFlag)
324         }
325         if v, err := f.GetDuration("duration"); err != nil || v != *durationFlag {
326                 t.Error("GetDuration does not work.")
327         }
328         if _, err := f.GetInt("duration"); err == nil {
329                 t.Error("GetInt parsed a time.Duration?!?!")
330         }
331         if *optionalIntNoValueFlag != 9 {
332                 t.Error("optional int flag should be the default value, is ", *optionalIntNoValueFlag)
333         }
334         if *optionalIntWithValueFlag != 42 {
335                 t.Error("optional int flag should be 42, is ", *optionalIntWithValueFlag)
336         }
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])
341         }
342 }
343
344 func testParseAll(f *FlagSet, t *testing.T) {
345         if f.Parsed() {
346                 t.Error("f.Parse() = true before Parse")
347         }
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"
357         args := []string{
358                 "-ab",
359                 "-cs=xx",
360                 "--stringz=something",
361                 "-d=true",
362                 "-x",
363                 "-y",
364                 "ee",
365         }
366         want := []string{
367                 "boola", "true",
368                 "boolb", "true",
369                 "boolc", "true",
370                 "stringa", "xx",
371                 "stringz", "something",
372                 "boold", "true",
373                 "stringx", "1",
374                 "stringy", "ee",
375         }
376         got := []string{}
377         store := func(flag *Flag, value string) error {
378                 got = append(got, flag.Name)
379                 if len(value) > 0 {
380                         got = append(got, value)
381                 }
382                 return nil
383         }
384         if err := f.ParseAll(args, store); err != nil {
385                 t.Errorf("expected no error, got %s", err)
386         }
387         if !f.Parsed() {
388                 t.Errorf("f.Parse() = false after Parse")
389         }
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)
394         }
395 }
396
397 func TestShorthand(t *testing.T) {
398         f := NewFlagSet("shorthand", ContinueOnError)
399         if f.Parsed() {
400                 t.Error("f.Parse() = true before Parse")
401         }
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"
410         args := []string{
411                 "-ab",
412                 extra,
413                 "-cs",
414                 "hello",
415                 "-z=something",
416                 "-d=true",
417                 "--",
418                 notaflag,
419         }
420         f.SetOutput(ioutil.Discard)
421         if err := f.Parse(args); err != nil {
422                 t.Error("expected no error, got ", err)
423         }
424         if !f.Parsed() {
425                 t.Error("f.Parse() = false after Parse")
426         }
427         if *boolaFlag != true {
428                 t.Error("boola flag should be true, is ", *boolaFlag)
429         }
430         if *boolbFlag != true {
431                 t.Error("boolb flag should be true, is ", *boolbFlag)
432         }
433         if *boolcFlag != true {
434                 t.Error("boolc flag should be true, is ", *boolcFlag)
435         }
436         if *booldFlag != true {
437                 t.Error("boold flag should be true, is ", *booldFlag)
438         }
439         if *stringaFlag != "hello" {
440                 t.Error("stringa flag should be `hello`, is ", *stringaFlag)
441         }
442         if *stringzFlag != "something" {
443                 t.Error("stringz flag should be `something`, is ", *stringzFlag)
444         }
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])
451         }
452         if f.ArgsLenAtDash() != 1 {
453                 t.Errorf("expected argsLenAtDash %d got %d", f.ArgsLenAtDash(), 1)
454         }
455 }
456
457 func TestShorthandLookup(t *testing.T) {
458         f := NewFlagSet("shorthand", ContinueOnError)
459         if f.Parsed() {
460                 t.Error("f.Parse() = true before Parse")
461         }
462         f.BoolP("boola", "a", false, "bool value")
463         f.BoolP("boolb", "b", false, "bool2 value")
464         args := []string{
465                 "-ab",
466         }
467         f.SetOutput(ioutil.Discard)
468         if err := f.Parse(args); err != nil {
469                 t.Error("expected no error, got ", err)
470         }
471         if !f.Parsed() {
472                 t.Error("f.Parse() = false after Parse")
473         }
474         flag := f.ShorthandLookup("a")
475         if flag == nil {
476                 t.Errorf("f.ShorthandLookup(\"a\") returned nil")
477         }
478         if flag.Name != "boola" {
479                 t.Errorf("f.ShorthandLookup(\"a\") found %q instead of \"boola\"", flag.Name)
480         }
481         flag = f.ShorthandLookup("")
482         if flag != nil {
483                 t.Errorf("f.ShorthandLookup(\"\") did not return nil")
484         }
485         defer func() {
486                 recover()
487         }()
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")
491 }
492
493 func TestParse(t *testing.T) {
494         ResetForTesting(func() { t.Error("bad parse") })
495         testParse(GetCommandLine(), t)
496 }
497
498 func TestParseAll(t *testing.T) {
499         ResetForTesting(func() { t.Error("bad parse") })
500         testParseAll(GetCommandLine(), t)
501 }
502
503 func TestFlagSetParse(t *testing.T) {
504         testParse(NewFlagSet("test", ContinueOnError), t)
505 }
506
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")
513
514         args := []string{"--changed", "--settrue", "--setfalse=false"}
515         if err := f.Parse(args); err != nil {
516                 t.Error("f.Parse() = false after Parse")
517         }
518         if !f.Changed("changed") {
519                 t.Errorf("--changed wasn't changed!")
520         }
521         if !f.Changed("settrue") {
522                 t.Errorf("--settrue wasn't changed!")
523         }
524         if !f.Changed("setfalse") {
525                 t.Errorf("--setfalse wasn't changed!")
526         }
527         if f.Changed("unchanged") {
528                 t.Errorf("--unchanged was changed!")
529         }
530         if f.Changed("invalid") {
531                 t.Errorf("--invalid was changed!")
532         }
533         if f.ArgsLenAtDash() != -1 {
534                 t.Errorf("Expected argsLenAtDash: %d but got %d", -1, f.ArgsLenAtDash())
535         }
536 }
537
538 func replaceSeparators(name string, from []string, to string) string {
539         result := name
540         for _, sep := range from {
541                 result = strings.Replace(result, sep, to, -1)
542         }
543         // Type convert to indicate normalization has been done.
544         return result
545 }
546
547 func wordSepNormalizeFunc(f *FlagSet, name string) NormalizedName {
548         seps := []string{"-", "_"}
549         name = replaceSeparators(name, seps, ".")
550         normalizeFlagNameInvocations++
551
552         return NormalizedName(name)
553 }
554
555 func testWordSepNormalizedNames(args []string, t *testing.T) {
556         f := NewFlagSet("normalized", ContinueOnError)
557         if f.Parsed() {
558                 t.Error("f.Parse() = true before Parse")
559         }
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 {
566                 t.Fatal(err)
567         }
568         if !f.Parsed() {
569                 t.Error("f.Parse() = false after Parse")
570         }
571         if *withDashFlag != true {
572                 t.Error("withDashFlag flag should be true, is ", *withDashFlag)
573         }
574         if *withUnderFlag != true {
575                 t.Error("withUnderFlag flag should be true, is ", *withUnderFlag)
576         }
577         if *withBothFlag != true {
578                 t.Error("withBothFlag flag should be true, is ", *withBothFlag)
579         }
580 }
581
582 func TestWordSepNormalizedNames(t *testing.T) {
583         args := []string{
584                 "--with-dash-flag",
585                 "--with-under-flag",
586                 "--with-both-flag",
587         }
588         testWordSepNormalizedNames(args, t)
589
590         args = []string{
591                 "--with_dash_flag",
592                 "--with_under_flag",
593                 "--with_both_flag",
594         }
595         testWordSepNormalizedNames(args, t)
596
597         args = []string{
598                 "--with-dash_flag",
599                 "--with-under_flag",
600                 "--with-both_flag",
601         }
602         testWordSepNormalizedNames(args, t)
603 }
604
605 func aliasAndWordSepFlagNames(f *FlagSet, name string) NormalizedName {
606         seps := []string{"-", "_"}
607
608         oldName := replaceSeparators("old-valid_flag", seps, ".")
609         newName := replaceSeparators("valid-flag", seps, ".")
610
611         name = replaceSeparators(name, seps, ".")
612         switch name {
613         case oldName:
614                 name = newName
615         }
616
617         return NormalizedName(name)
618 }
619
620 func TestCustomNormalizedNames(t *testing.T) {
621         f := NewFlagSet("normalized", ContinueOnError)
622         if f.Parsed() {
623                 t.Error("f.Parse() = true before Parse")
624         }
625
626         validFlag := f.Bool("valid-flag", false, "bool value")
627         f.SetNormalizeFunc(aliasAndWordSepFlagNames)
628         someOtherFlag := f.Bool("some-other-flag", false, "bool value")
629
630         args := []string{"--old_valid_flag", "--some-other_flag"}
631         if err := f.Parse(args); err != nil {
632                 t.Fatal(err)
633         }
634
635         if *validFlag != true {
636                 t.Errorf("validFlag is %v even though we set the alias --old_valid_falg", *validFlag)
637         }
638         if *someOtherFlag != true {
639                 t.Error("someOtherFlag should be true, is ", *someOtherFlag)
640         }
641 }
642
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)
647
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)
651         }
652
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)
656         }
657
658         // Test normalization before addition
659         f = NewFlagSet("normalized", ContinueOnError)
660         f.SetNormalizeFunc(wordSepNormalizeFunc)
661
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)
665         }
666 }
667
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)
677         }
678
679         f.Bool(testName, false, "bool value")
680         g.AddFlagSet(f)
681
682         f.SetNormalizeFunc(nfunc)
683         g.SetNormalizeFunc(nfunc)
684
685         if len(f.formal) != 1 {
686                 t.Error("Normalizing flags should not result in duplications in the flag set:", f.formal)
687         }
688         if f.orderedFormal[0].Name != string(normName) {
689                 t.Error("Flag name not normalized")
690         }
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)
694                 }
695         }
696
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)
699         }
700 }
701
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)
709         }
710
711         f.Bool(testName, false, "bool value")
712         f.Set(testName, "true")
713         f.SetNormalizeFunc(nfunc)
714
715         if len(f.formal) != 1 {
716                 t.Error("Normalizing flags should not result in duplications in the flag set:", f.formal)
717         }
718         if f.orderedFormal[0].Name != string(normName) {
719                 t.Error("Flag name not normalized")
720         }
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)
724                 }
725         }
726
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)
729         }
730 }
731
732 // Declare a user-defined flag type.
733 type flagVar []string
734
735 func (f *flagVar) String() string {
736         return fmt.Sprint([]string(*f))
737 }
738
739 func (f *flagVar) Set(value string) error {
740         *f = append(*f, value)
741         return nil
742 }
743
744 func (f *flagVar) Type() string {
745         return "flagVar"
746 }
747
748 func TestUserDefined(t *testing.T) {
749         var flags FlagSet
750         flags.Init("test", ContinueOnError)
751         var v flagVar
752         flags.VarP(&v, "v", "v", "usage")
753         if err := flags.Parse([]string{"--v=1", "-v2", "-v", "3"}); err != nil {
754                 t.Error(err)
755         }
756         if len(v) != 3 {
757                 t.Fatal("expected 3 args; got ", len(v))
758         }
759         expect := "[1 2 3]"
760         if v.String() != expect {
761                 t.Errorf("expected value %q got %q", expect, v.String())
762         }
763 }
764
765 func TestSetOutput(t *testing.T) {
766         var flags FlagSet
767         var buf bytes.Buffer
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)
773         }
774 }
775
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") })
780         oldArgs := os.Args
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 {
785                 t.Fatal(err)
786         }
787         cmd := Arg(0)
788         os.Args = []string{"subcmd", "--after", "args"}
789         after := Bool("after", false, "")
790         Parse()
791         args := Args()
792
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)
795         }
796 }
797
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 }
803         var flag bool
804         fs.BoolVar(&flag, "flag", false, "regular flag")
805         // Regular flag invocation should work
806         err := fs.Parse([]string{"--flag=true"})
807         if err != nil {
808                 t.Fatal("expected no error; got ", err)
809         }
810         if !flag {
811                 t.Error("flag was not set by --flag")
812         }
813         if helpCalled {
814                 t.Error("help called for regular flag")
815                 helpCalled = false // reset for next test
816         }
817         // Help flag should work as expected.
818         err = fs.Parse([]string{"--help"})
819         if err == nil {
820                 t.Fatal("error expected")
821         }
822         if err != ErrHelp {
823                 t.Fatal("expected ErrHelp; got ", err)
824         }
825         if !helpCalled {
826                 t.Fatal("help was not called")
827         }
828         // If we define a help flag, that should override.
829         var help bool
830         fs.BoolVar(&help, "help", false, "help flag")
831         helpCalled = false
832         err = fs.Parse([]string{"--help"})
833         if err != nil {
834                 t.Fatal("expected no error for defined --help; got ", err)
835         }
836         if helpCalled {
837                 t.Fatal("help was called; should not have been for defined help flag")
838         }
839 }
840
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"})
847         if err != nil {
848                 t.Fatal("expected no error; got ", err)
849         }
850         args := f.Args()
851         if len(args) != 2 || args[0] != "break" || args[1] != "--false" {
852                 t.Fatal("expected interspersed options/non-options to fail")
853         }
854 }
855
856 func TestTermination(t *testing.T) {
857         f := NewFlagSet("termination", ContinueOnError)
858         boolFlag := f.BoolP("bool", "l", false, "bool value")
859         if f.Parsed() {
860                 t.Error("f.Parse() = true before Parse")
861         }
862         arg1 := "ls"
863         arg2 := "-l"
864         args := []string{
865                 "--",
866                 arg1,
867                 arg2,
868         }
869         f.SetOutput(ioutil.Discard)
870         if err := f.Parse(args); err != nil {
871                 t.Fatal("expected no error; got ", err)
872         }
873         if !f.Parsed() {
874                 t.Error("f.Parse() = false after Parse")
875         }
876         if *boolFlag {
877                 t.Error("expected boolFlag=false, got true")
878         }
879         if len(f.Args()) != 2 {
880                 t.Errorf("expected 2 arguments, got %d: %v", len(f.Args()), f.Args())
881         }
882         if f.Args()[0] != arg1 {
883                 t.Errorf("expected argument %q got %q", arg1, f.Args()[0])
884         }
885         if f.Args()[1] != arg2 {
886                 t.Errorf("expected argument %q got %q", arg2, f.Args()[1])
887         }
888         if f.ArgsLenAtDash() != 0 {
889                 t.Errorf("expected argsLenAtDash %d got %d", 0, f.ArgsLenAtDash())
890         }
891 }
892
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")
897
898         out := new(bytes.Buffer)
899         f.SetOutput(out)
900         f.PrintDefaults()
901
902         if strings.Contains(out.String(), "badflag") {
903                 t.Errorf("found deprecated flag in usage!")
904         }
905 }
906
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))
912
913         out := new(bytes.Buffer)
914         f.SetOutput(out)
915         f.PrintDefaults()
916
917         if strings.Contains(out.String(), "-n,") {
918                 t.Errorf("found deprecated flag shorthand in usage!")
919         }
920 }
921
922 func parseReturnStderr(t *testing.T, f *FlagSet, args []string) (string, error) {
923         oldStderr := os.Stderr
924         r, w, _ := os.Pipe()
925         os.Stderr = w
926
927         err := f.Parse(args)
928
929         outC := make(chan string)
930         // copy the output in a separate goroutine so printing can't block indefinitely
931         go func() {
932                 var buf bytes.Buffer
933                 io.Copy(&buf, r)
934                 outC <- buf.String()
935         }()
936
937         w.Close()
938         os.Stderr = oldStderr
939         out := <-outC
940
941         return out, err
942 }
943
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)
949
950         args := []string{"--badflag"}
951         out, err := parseReturnStderr(t, f, args)
952         if err != nil {
953                 t.Fatal("expected no error; got ", err)
954         }
955
956         if !strings.Contains(out, usageMsg) {
957                 t.Errorf("usageMsg not printed when using a deprecated flag!")
958         }
959 }
960
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)
967
968         args := []string{"-n"}
969         out, err := parseReturnStderr(t, f, args)
970         if err != nil {
971                 t.Fatal("expected no error; got ", err)
972         }
973
974         if !strings.Contains(out, usageMsg) {
975                 t.Errorf("usageMsg not printed when using a deprecated flag!")
976         }
977 }
978
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)
985
986         args := []string{"--bad_double_flag"}
987         out, err := parseReturnStderr(t, f, args)
988         if err != nil {
989                 t.Fatal("expected no error; got ", err)
990         }
991
992         if !strings.Contains(out, usageMsg) {
993                 t.Errorf("usageMsg not printed when using a deprecated flag!")
994         }
995 }
996
997 // Name normalization function should be called only once on flag addition
998 func TestMultipleNormalizeFlagNameInvocations(t *testing.T) {
999         normalizeFlagNameInvocations = 0
1000
1001         f := NewFlagSet("normalized", ContinueOnError)
1002         f.SetNormalizeFunc(wordSepNormalizeFunc)
1003         f.Bool("with_under_flag", false, "bool value")
1004
1005         if normalizeFlagNameInvocations != 1 {
1006                 t.Fatal("Expected normalizeFlagNameInvocations to be 1; got ", normalizeFlagNameInvocations)
1007         }
1008 }
1009
1010 //
1011 func TestHiddenFlagInUsage(t *testing.T) {
1012         f := NewFlagSet("bob", ContinueOnError)
1013         f.Bool("secretFlag", true, "shhh")
1014         f.MarkHidden("secretFlag")
1015
1016         out := new(bytes.Buffer)
1017         f.SetOutput(out)
1018         f.PrintDefaults()
1019
1020         if strings.Contains(out.String(), "secretFlag") {
1021                 t.Errorf("found hidden flag in usage!")
1022         }
1023 }
1024
1025 //
1026 func TestHiddenFlagUsage(t *testing.T) {
1027         f := NewFlagSet("bob", ContinueOnError)
1028         f.Bool("secretFlag", true, "shhh")
1029         f.MarkHidden("secretFlag")
1030
1031         args := []string{"--secretFlag"}
1032         out, err := parseReturnStderr(t, f, args)
1033         if err != nil {
1034                 t.Fatal("expected no error; got ", err)
1035         }
1036
1037         if strings.Contains(out, "shhh") {
1038                 t.Errorf("usage message printed when using a hidden flag!")
1039         }
1040 }
1041
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
1063 `
1064
1065 // Custom value that satisfies the Value interface.
1066 type customValue int
1067
1068 func (cv *customValue) String() string { return fmt.Sprintf("%v", *cv) }
1069
1070 func (cv *customValue) Set(s string) error {
1071         v, err := strconv.ParseInt(s, 0, 64)
1072         *cv = customValue(v)
1073         return err
1074 }
1075
1076 func (cv *customValue) Type() string { return "custom" }
1077
1078 func TestPrintDefaults(t *testing.T) {
1079         fs := NewFlagSet("print defaults test", ContinueOnError)
1080         var buf bytes.Buffer
1081         fs.SetOutput(&buf)
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")
1104
1105         var cv customValue
1106         fs.Var(&cv, "custom", "custom Value implementation")
1107
1108         cv2 := customValue(10)
1109         fs.VarP(&cv2, "customP", "", "a VarP with default")
1110
1111         fs.PrintDefaults()
1112         got := buf.String()
1113         if got != defaultOutput {
1114                 fmt.Println("\n" + got)
1115                 fmt.Println("\n" + defaultOutput)
1116                 t.Errorf("got %q want %q\n", got, defaultOutput)
1117         }
1118 }
1119
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)
1126         })
1127
1128         names := []string{"C", "B", "A", "D"}
1129         for _, name := range names {
1130                 fs.Bool(name, false, "")
1131         }
1132
1133         i := 0
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)
1137                 }
1138                 i++
1139         })
1140 }
1141
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")
1149         }
1150
1151         i := 0
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)
1155                 }
1156                 i++
1157         })
1158 }