...

Source file src/github.com/spf13/pflag/flag_test.go

Documentation: github.com/spf13/pflag

     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 testParseWithUnknownFlags(f *FlagSet, t *testing.T) {
   398  	if f.Parsed() {
   399  		t.Error("f.Parse() = true before Parse")
   400  	}
   401  	f.ParseErrorsWhitelist.UnknownFlags = true
   402  
   403  	f.BoolP("boola", "a", false, "bool value")
   404  	f.BoolP("boolb", "b", false, "bool2 value")
   405  	f.BoolP("boolc", "c", false, "bool3 value")
   406  	f.BoolP("boold", "d", false, "bool4 value")
   407  	f.BoolP("boole", "e", false, "bool4 value")
   408  	f.StringP("stringa", "s", "0", "string value")
   409  	f.StringP("stringz", "z", "0", "string value")
   410  	f.StringP("stringx", "x", "0", "string value")
   411  	f.StringP("stringy", "y", "0", "string value")
   412  	f.StringP("stringo", "o", "0", "string value")
   413  	f.Lookup("stringx").NoOptDefVal = "1"
   414  	args := []string{
   415  		"-ab",
   416  		"-cs=xx",
   417  		"--stringz=something",
   418  		"--unknown1",
   419  		"unknown1Value",
   420  		"-d=true",
   421  		"-x",
   422  		"--unknown2=unknown2Value",
   423  		"-u=unknown3Value",
   424  		"-p",
   425  		"unknown4Value",
   426  		"-q", //another unknown with bool value
   427  		"-y",
   428  		"ee",
   429  		"--unknown7=unknown7value",
   430  		"--stringo=ovalue",
   431  		"--unknown8=unknown8value",
   432  		"--boole",
   433  		"--unknown6",
   434  		"",
   435  		"-uuuuu",
   436  		"",
   437  		"--unknown10",
   438  		"--unknown11",
   439  	}
   440  	want := []string{
   441  		"boola", "true",
   442  		"boolb", "true",
   443  		"boolc", "true",
   444  		"stringa", "xx",
   445  		"stringz", "something",
   446  		"boold", "true",
   447  		"stringx", "1",
   448  		"stringy", "ee",
   449  		"stringo", "ovalue",
   450  		"boole", "true",
   451  	}
   452  	got := []string{}
   453  	store := func(flag *Flag, value string) error {
   454  		got = append(got, flag.Name)
   455  		if len(value) > 0 {
   456  			got = append(got, value)
   457  		}
   458  		return nil
   459  	}
   460  	if err := f.ParseAll(args, store); err != nil {
   461  		t.Errorf("expected no error, got %s", err)
   462  	}
   463  	if !f.Parsed() {
   464  		t.Errorf("f.Parse() = false after Parse")
   465  	}
   466  	if !reflect.DeepEqual(got, want) {
   467  		t.Errorf("f.ParseAll() fail to restore the args")
   468  		t.Errorf("Got:  %v", got)
   469  		t.Errorf("Want: %v", want)
   470  	}
   471  }
   472  
   473  func TestShorthand(t *testing.T) {
   474  	f := NewFlagSet("shorthand", ContinueOnError)
   475  	if f.Parsed() {
   476  		t.Error("f.Parse() = true before Parse")
   477  	}
   478  	boolaFlag := f.BoolP("boola", "a", false, "bool value")
   479  	boolbFlag := f.BoolP("boolb", "b", false, "bool2 value")
   480  	boolcFlag := f.BoolP("boolc", "c", false, "bool3 value")
   481  	booldFlag := f.BoolP("boold", "d", false, "bool4 value")
   482  	stringaFlag := f.StringP("stringa", "s", "0", "string value")
   483  	stringzFlag := f.StringP("stringz", "z", "0", "string value")
   484  	extra := "interspersed-argument"
   485  	notaflag := "--i-look-like-a-flag"
   486  	args := []string{
   487  		"-ab",
   488  		extra,
   489  		"-cs",
   490  		"hello",
   491  		"-z=something",
   492  		"-d=true",
   493  		"--",
   494  		notaflag,
   495  	}
   496  	f.SetOutput(ioutil.Discard)
   497  	if err := f.Parse(args); err != nil {
   498  		t.Error("expected no error, got ", err)
   499  	}
   500  	if !f.Parsed() {
   501  		t.Error("f.Parse() = false after Parse")
   502  	}
   503  	if *boolaFlag != true {
   504  		t.Error("boola flag should be true, is ", *boolaFlag)
   505  	}
   506  	if *boolbFlag != true {
   507  		t.Error("boolb flag should be true, is ", *boolbFlag)
   508  	}
   509  	if *boolcFlag != true {
   510  		t.Error("boolc flag should be true, is ", *boolcFlag)
   511  	}
   512  	if *booldFlag != true {
   513  		t.Error("boold flag should be true, is ", *booldFlag)
   514  	}
   515  	if *stringaFlag != "hello" {
   516  		t.Error("stringa flag should be `hello`, is ", *stringaFlag)
   517  	}
   518  	if *stringzFlag != "something" {
   519  		t.Error("stringz flag should be `something`, is ", *stringzFlag)
   520  	}
   521  	if len(f.Args()) != 2 {
   522  		t.Error("expected one argument, got", len(f.Args()))
   523  	} else if f.Args()[0] != extra {
   524  		t.Errorf("expected argument %q got %q", extra, f.Args()[0])
   525  	} else if f.Args()[1] != notaflag {
   526  		t.Errorf("expected argument %q got %q", notaflag, f.Args()[1])
   527  	}
   528  	if f.ArgsLenAtDash() != 1 {
   529  		t.Errorf("expected argsLenAtDash %d got %d", f.ArgsLenAtDash(), 1)
   530  	}
   531  }
   532  
   533  func TestShorthandLookup(t *testing.T) {
   534  	f := NewFlagSet("shorthand", ContinueOnError)
   535  	if f.Parsed() {
   536  		t.Error("f.Parse() = true before Parse")
   537  	}
   538  	f.BoolP("boola", "a", false, "bool value")
   539  	f.BoolP("boolb", "b", false, "bool2 value")
   540  	args := []string{
   541  		"-ab",
   542  	}
   543  	f.SetOutput(ioutil.Discard)
   544  	if err := f.Parse(args); err != nil {
   545  		t.Error("expected no error, got ", err)
   546  	}
   547  	if !f.Parsed() {
   548  		t.Error("f.Parse() = false after Parse")
   549  	}
   550  	flag := f.ShorthandLookup("a")
   551  	if flag == nil {
   552  		t.Errorf("f.ShorthandLookup(\"a\") returned nil")
   553  	}
   554  	if flag.Name != "boola" {
   555  		t.Errorf("f.ShorthandLookup(\"a\") found %q instead of \"boola\"", flag.Name)
   556  	}
   557  	flag = f.ShorthandLookup("")
   558  	if flag != nil {
   559  		t.Errorf("f.ShorthandLookup(\"\") did not return nil")
   560  	}
   561  	defer func() {
   562  		recover()
   563  	}()
   564  	flag = f.ShorthandLookup("ab")
   565  	// should NEVER get here. lookup should panic. defer'd func should recover it.
   566  	t.Errorf("f.ShorthandLookup(\"ab\") did not panic")
   567  }
   568  
   569  func TestParse(t *testing.T) {
   570  	ResetForTesting(func() { t.Error("bad parse") })
   571  	testParse(GetCommandLine(), t)
   572  }
   573  
   574  func TestParseAll(t *testing.T) {
   575  	ResetForTesting(func() { t.Error("bad parse") })
   576  	testParseAll(GetCommandLine(), t)
   577  }
   578  
   579  func TestIgnoreUnknownFlags(t *testing.T) {
   580  	ResetForTesting(func() { t.Error("bad parse") })
   581  	testParseWithUnknownFlags(GetCommandLine(), t)
   582  }
   583  
   584  func TestFlagSetParse(t *testing.T) {
   585  	testParse(NewFlagSet("test", ContinueOnError), t)
   586  }
   587  
   588  func TestChangedHelper(t *testing.T) {
   589  	f := NewFlagSet("changedtest", ContinueOnError)
   590  	f.Bool("changed", false, "changed bool")
   591  	f.Bool("settrue", true, "true to true")
   592  	f.Bool("setfalse", false, "false to false")
   593  	f.Bool("unchanged", false, "unchanged bool")
   594  
   595  	args := []string{"--changed", "--settrue", "--setfalse=false"}
   596  	if err := f.Parse(args); err != nil {
   597  		t.Error("f.Parse() = false after Parse")
   598  	}
   599  	if !f.Changed("changed") {
   600  		t.Errorf("--changed wasn't changed!")
   601  	}
   602  	if !f.Changed("settrue") {
   603  		t.Errorf("--settrue wasn't changed!")
   604  	}
   605  	if !f.Changed("setfalse") {
   606  		t.Errorf("--setfalse wasn't changed!")
   607  	}
   608  	if f.Changed("unchanged") {
   609  		t.Errorf("--unchanged was changed!")
   610  	}
   611  	if f.Changed("invalid") {
   612  		t.Errorf("--invalid was changed!")
   613  	}
   614  	if f.ArgsLenAtDash() != -1 {
   615  		t.Errorf("Expected argsLenAtDash: %d but got %d", -1, f.ArgsLenAtDash())
   616  	}
   617  }
   618  
   619  func replaceSeparators(name string, from []string, to string) string {
   620  	result := name
   621  	for _, sep := range from {
   622  		result = strings.Replace(result, sep, to, -1)
   623  	}
   624  	// Type convert to indicate normalization has been done.
   625  	return result
   626  }
   627  
   628  func wordSepNormalizeFunc(f *FlagSet, name string) NormalizedName {
   629  	seps := []string{"-", "_"}
   630  	name = replaceSeparators(name, seps, ".")
   631  	normalizeFlagNameInvocations++
   632  
   633  	return NormalizedName(name)
   634  }
   635  
   636  func testWordSepNormalizedNames(args []string, t *testing.T) {
   637  	f := NewFlagSet("normalized", ContinueOnError)
   638  	if f.Parsed() {
   639  		t.Error("f.Parse() = true before Parse")
   640  	}
   641  	withDashFlag := f.Bool("with-dash-flag", false, "bool value")
   642  	// Set this after some flags have been added and before others.
   643  	f.SetNormalizeFunc(wordSepNormalizeFunc)
   644  	withUnderFlag := f.Bool("with_under_flag", false, "bool value")
   645  	withBothFlag := f.Bool("with-both_flag", false, "bool value")
   646  	if err := f.Parse(args); err != nil {
   647  		t.Fatal(err)
   648  	}
   649  	if !f.Parsed() {
   650  		t.Error("f.Parse() = false after Parse")
   651  	}
   652  	if *withDashFlag != true {
   653  		t.Error("withDashFlag flag should be true, is ", *withDashFlag)
   654  	}
   655  	if *withUnderFlag != true {
   656  		t.Error("withUnderFlag flag should be true, is ", *withUnderFlag)
   657  	}
   658  	if *withBothFlag != true {
   659  		t.Error("withBothFlag flag should be true, is ", *withBothFlag)
   660  	}
   661  }
   662  
   663  func TestWordSepNormalizedNames(t *testing.T) {
   664  	args := []string{
   665  		"--with-dash-flag",
   666  		"--with-under-flag",
   667  		"--with-both-flag",
   668  	}
   669  	testWordSepNormalizedNames(args, t)
   670  
   671  	args = []string{
   672  		"--with_dash_flag",
   673  		"--with_under_flag",
   674  		"--with_both_flag",
   675  	}
   676  	testWordSepNormalizedNames(args, t)
   677  
   678  	args = []string{
   679  		"--with-dash_flag",
   680  		"--with-under_flag",
   681  		"--with-both_flag",
   682  	}
   683  	testWordSepNormalizedNames(args, t)
   684  }
   685  
   686  func aliasAndWordSepFlagNames(f *FlagSet, name string) NormalizedName {
   687  	seps := []string{"-", "_"}
   688  
   689  	oldName := replaceSeparators("old-valid_flag", seps, ".")
   690  	newName := replaceSeparators("valid-flag", seps, ".")
   691  
   692  	name = replaceSeparators(name, seps, ".")
   693  	switch name {
   694  	case oldName:
   695  		name = newName
   696  	}
   697  
   698  	return NormalizedName(name)
   699  }
   700  
   701  func TestCustomNormalizedNames(t *testing.T) {
   702  	f := NewFlagSet("normalized", ContinueOnError)
   703  	if f.Parsed() {
   704  		t.Error("f.Parse() = true before Parse")
   705  	}
   706  
   707  	validFlag := f.Bool("valid-flag", false, "bool value")
   708  	f.SetNormalizeFunc(aliasAndWordSepFlagNames)
   709  	someOtherFlag := f.Bool("some-other-flag", false, "bool value")
   710  
   711  	args := []string{"--old_valid_flag", "--some-other_flag"}
   712  	if err := f.Parse(args); err != nil {
   713  		t.Fatal(err)
   714  	}
   715  
   716  	if *validFlag != true {
   717  		t.Errorf("validFlag is %v even though we set the alias --old_valid_falg", *validFlag)
   718  	}
   719  	if *someOtherFlag != true {
   720  		t.Error("someOtherFlag should be true, is ", *someOtherFlag)
   721  	}
   722  }
   723  
   724  // Every flag we add, the name (displayed also in usage) should normalized
   725  func TestNormalizationFuncShouldChangeFlagName(t *testing.T) {
   726  	// Test normalization after addition
   727  	f := NewFlagSet("normalized", ContinueOnError)
   728  
   729  	f.Bool("valid_flag", false, "bool value")
   730  	if f.Lookup("valid_flag").Name != "valid_flag" {
   731  		t.Error("The new flag should have the name 'valid_flag' instead of ", f.Lookup("valid_flag").Name)
   732  	}
   733  
   734  	f.SetNormalizeFunc(wordSepNormalizeFunc)
   735  	if f.Lookup("valid_flag").Name != "valid.flag" {
   736  		t.Error("The new flag should have the name 'valid.flag' instead of ", f.Lookup("valid_flag").Name)
   737  	}
   738  
   739  	// Test normalization before addition
   740  	f = NewFlagSet("normalized", ContinueOnError)
   741  	f.SetNormalizeFunc(wordSepNormalizeFunc)
   742  
   743  	f.Bool("valid_flag", false, "bool value")
   744  	if f.Lookup("valid_flag").Name != "valid.flag" {
   745  		t.Error("The new flag should have the name 'valid.flag' instead of ", f.Lookup("valid_flag").Name)
   746  	}
   747  }
   748  
   749  // Related to https://github.com/spf13/cobra/issues/521.
   750  func TestNormalizationSharedFlags(t *testing.T) {
   751  	f := NewFlagSet("set f", ContinueOnError)
   752  	g := NewFlagSet("set g", ContinueOnError)
   753  	nfunc := wordSepNormalizeFunc
   754  	testName := "valid_flag"
   755  	normName := nfunc(nil, testName)
   756  	if testName == string(normName) {
   757  		t.Error("TestNormalizationSharedFlags meaningless: the original and normalized flag names are identical:", testName)
   758  	}
   759  
   760  	f.Bool(testName, false, "bool value")
   761  	g.AddFlagSet(f)
   762  
   763  	f.SetNormalizeFunc(nfunc)
   764  	g.SetNormalizeFunc(nfunc)
   765  
   766  	if len(f.formal) != 1 {
   767  		t.Error("Normalizing flags should not result in duplications in the flag set:", f.formal)
   768  	}
   769  	if f.orderedFormal[0].Name != string(normName) {
   770  		t.Error("Flag name not normalized")
   771  	}
   772  	for k := range f.formal {
   773  		if k != "valid.flag" {
   774  			t.Errorf("The key in the flag map should have been normalized: wanted \"%s\", got \"%s\" instead", normName, k)
   775  		}
   776  	}
   777  
   778  	if !reflect.DeepEqual(f.formal, g.formal) || !reflect.DeepEqual(f.orderedFormal, g.orderedFormal) {
   779  		t.Error("Two flag sets sharing the same flags should stay consistent after being normalized. Original set:", f.formal, "Duplicate set:", g.formal)
   780  	}
   781  }
   782  
   783  func TestNormalizationSetFlags(t *testing.T) {
   784  	f := NewFlagSet("normalized", ContinueOnError)
   785  	nfunc := wordSepNormalizeFunc
   786  	testName := "valid_flag"
   787  	normName := nfunc(nil, testName)
   788  	if testName == string(normName) {
   789  		t.Error("TestNormalizationSetFlags meaningless: the original and normalized flag names are identical:", testName)
   790  	}
   791  
   792  	f.Bool(testName, false, "bool value")
   793  	f.Set(testName, "true")
   794  	f.SetNormalizeFunc(nfunc)
   795  
   796  	if len(f.formal) != 1 {
   797  		t.Error("Normalizing flags should not result in duplications in the flag set:", f.formal)
   798  	}
   799  	if f.orderedFormal[0].Name != string(normName) {
   800  		t.Error("Flag name not normalized")
   801  	}
   802  	for k := range f.formal {
   803  		if k != "valid.flag" {
   804  			t.Errorf("The key in the flag map should have been normalized: wanted \"%s\", got \"%s\" instead", normName, k)
   805  		}
   806  	}
   807  
   808  	if !reflect.DeepEqual(f.formal, f.actual) {
   809  		t.Error("The map of set flags should get normalized. Formal:", f.formal, "Actual:", f.actual)
   810  	}
   811  }
   812  
   813  // Declare a user-defined flag type.
   814  type flagVar []string
   815  
   816  func (f *flagVar) String() string {
   817  	return fmt.Sprint([]string(*f))
   818  }
   819  
   820  func (f *flagVar) Set(value string) error {
   821  	*f = append(*f, value)
   822  	return nil
   823  }
   824  
   825  func (f *flagVar) Type() string {
   826  	return "flagVar"
   827  }
   828  
   829  func TestUserDefined(t *testing.T) {
   830  	var flags FlagSet
   831  	flags.Init("test", ContinueOnError)
   832  	var v flagVar
   833  	flags.VarP(&v, "v", "v", "usage")
   834  	if err := flags.Parse([]string{"--v=1", "-v2", "-v", "3"}); err != nil {
   835  		t.Error(err)
   836  	}
   837  	if len(v) != 3 {
   838  		t.Fatal("expected 3 args; got ", len(v))
   839  	}
   840  	expect := "[1 2 3]"
   841  	if v.String() != expect {
   842  		t.Errorf("expected value %q got %q", expect, v.String())
   843  	}
   844  }
   845  
   846  func TestSetOutput(t *testing.T) {
   847  	var flags FlagSet
   848  	var buf bytes.Buffer
   849  	flags.SetOutput(&buf)
   850  	flags.Init("test", ContinueOnError)
   851  	flags.Parse([]string{"--unknown"})
   852  	if out := buf.String(); !strings.Contains(out, "--unknown") {
   853  		t.Logf("expected output mentioning unknown; got %q", out)
   854  	}
   855  }
   856  
   857  // This tests that one can reset the flags. This still works but not well, and is
   858  // superseded by FlagSet.
   859  func TestChangingArgs(t *testing.T) {
   860  	ResetForTesting(func() { t.Fatal("bad parse") })
   861  	oldArgs := os.Args
   862  	defer func() { os.Args = oldArgs }()
   863  	os.Args = []string{"cmd", "--before", "subcmd"}
   864  	before := Bool("before", false, "")
   865  	if err := GetCommandLine().Parse(os.Args[1:]); err != nil {
   866  		t.Fatal(err)
   867  	}
   868  	cmd := Arg(0)
   869  	os.Args = []string{"subcmd", "--after", "args"}
   870  	after := Bool("after", false, "")
   871  	Parse()
   872  	args := Args()
   873  
   874  	if !*before || cmd != "subcmd" || !*after || len(args) != 1 || args[0] != "args" {
   875  		t.Fatalf("expected true subcmd true [args] got %v %v %v %v", *before, cmd, *after, args)
   876  	}
   877  }
   878  
   879  // Test that -help invokes the usage message and returns ErrHelp.
   880  func TestHelp(t *testing.T) {
   881  	var helpCalled = false
   882  	fs := NewFlagSet("help test", ContinueOnError)
   883  	fs.Usage = func() { helpCalled = true }
   884  	var flag bool
   885  	fs.BoolVar(&flag, "flag", false, "regular flag")
   886  	// Regular flag invocation should work
   887  	err := fs.Parse([]string{"--flag=true"})
   888  	if err != nil {
   889  		t.Fatal("expected no error; got ", err)
   890  	}
   891  	if !flag {
   892  		t.Error("flag was not set by --flag")
   893  	}
   894  	if helpCalled {
   895  		t.Error("help called for regular flag")
   896  		helpCalled = false // reset for next test
   897  	}
   898  	// Help flag should work as expected.
   899  	err = fs.Parse([]string{"--help"})
   900  	if err == nil {
   901  		t.Fatal("error expected")
   902  	}
   903  	if err != ErrHelp {
   904  		t.Fatal("expected ErrHelp; got ", err)
   905  	}
   906  	if !helpCalled {
   907  		t.Fatal("help was not called")
   908  	}
   909  	// If we define a help flag, that should override.
   910  	var help bool
   911  	fs.BoolVar(&help, "help", false, "help flag")
   912  	helpCalled = false
   913  	err = fs.Parse([]string{"--help"})
   914  	if err != nil {
   915  		t.Fatal("expected no error for defined --help; got ", err)
   916  	}
   917  	if helpCalled {
   918  		t.Fatal("help was called; should not have been for defined help flag")
   919  	}
   920  }
   921  
   922  func TestNoInterspersed(t *testing.T) {
   923  	f := NewFlagSet("test", ContinueOnError)
   924  	f.SetInterspersed(false)
   925  	f.Bool("true", true, "always true")
   926  	f.Bool("false", false, "always false")
   927  	err := f.Parse([]string{"--true", "break", "--false"})
   928  	if err != nil {
   929  		t.Fatal("expected no error; got ", err)
   930  	}
   931  	args := f.Args()
   932  	if len(args) != 2 || args[0] != "break" || args[1] != "--false" {
   933  		t.Fatal("expected interspersed options/non-options to fail")
   934  	}
   935  }
   936  
   937  func TestTermination(t *testing.T) {
   938  	f := NewFlagSet("termination", ContinueOnError)
   939  	boolFlag := f.BoolP("bool", "l", false, "bool value")
   940  	if f.Parsed() {
   941  		t.Error("f.Parse() = true before Parse")
   942  	}
   943  	arg1 := "ls"
   944  	arg2 := "-l"
   945  	args := []string{
   946  		"--",
   947  		arg1,
   948  		arg2,
   949  	}
   950  	f.SetOutput(ioutil.Discard)
   951  	if err := f.Parse(args); err != nil {
   952  		t.Fatal("expected no error; got ", err)
   953  	}
   954  	if !f.Parsed() {
   955  		t.Error("f.Parse() = false after Parse")
   956  	}
   957  	if *boolFlag {
   958  		t.Error("expected boolFlag=false, got true")
   959  	}
   960  	if len(f.Args()) != 2 {
   961  		t.Errorf("expected 2 arguments, got %d: %v", len(f.Args()), f.Args())
   962  	}
   963  	if f.Args()[0] != arg1 {
   964  		t.Errorf("expected argument %q got %q", arg1, f.Args()[0])
   965  	}
   966  	if f.Args()[1] != arg2 {
   967  		t.Errorf("expected argument %q got %q", arg2, f.Args()[1])
   968  	}
   969  	if f.ArgsLenAtDash() != 0 {
   970  		t.Errorf("expected argsLenAtDash %d got %d", 0, f.ArgsLenAtDash())
   971  	}
   972  }
   973  
   974  func getDeprecatedFlagSet() *FlagSet {
   975  	f := NewFlagSet("bob", ContinueOnError)
   976  	f.Bool("badflag", true, "always true")
   977  	f.MarkDeprecated("badflag", "use --good-flag instead")
   978  	return f
   979  }
   980  func TestDeprecatedFlagInDocs(t *testing.T) {
   981  	f := getDeprecatedFlagSet()
   982  
   983  	out := new(bytes.Buffer)
   984  	f.SetOutput(out)
   985  	f.PrintDefaults()
   986  
   987  	if strings.Contains(out.String(), "badflag") {
   988  		t.Errorf("found deprecated flag in usage!")
   989  	}
   990  }
   991  
   992  func TestUnHiddenDeprecatedFlagInDocs(t *testing.T) {
   993  	f := getDeprecatedFlagSet()
   994  	flg := f.Lookup("badflag")
   995  	if flg == nil {
   996  		t.Fatalf("Unable to lookup 'bob' in TestUnHiddenDeprecatedFlagInDocs")
   997  	}
   998  	flg.Hidden = false
   999  
  1000  	out := new(bytes.Buffer)
  1001  	f.SetOutput(out)
  1002  	f.PrintDefaults()
  1003  
  1004  	defaults := out.String()
  1005  	if !strings.Contains(defaults, "badflag") {
  1006  		t.Errorf("Did not find deprecated flag in usage!")
  1007  	}
  1008  	if !strings.Contains(defaults, "use --good-flag instead") {
  1009  		t.Errorf("Did not find 'use --good-flag instead' in defaults")
  1010  	}
  1011  }
  1012  
  1013  func TestDeprecatedFlagShorthandInDocs(t *testing.T) {
  1014  	f := NewFlagSet("bob", ContinueOnError)
  1015  	name := "noshorthandflag"
  1016  	f.BoolP(name, "n", true, "always true")
  1017  	f.MarkShorthandDeprecated("noshorthandflag", fmt.Sprintf("use --%s instead", name))
  1018  
  1019  	out := new(bytes.Buffer)
  1020  	f.SetOutput(out)
  1021  	f.PrintDefaults()
  1022  
  1023  	if strings.Contains(out.String(), "-n,") {
  1024  		t.Errorf("found deprecated flag shorthand in usage!")
  1025  	}
  1026  }
  1027  
  1028  func parseReturnStderr(t *testing.T, f *FlagSet, args []string) (string, error) {
  1029  	oldStderr := os.Stderr
  1030  	r, w, _ := os.Pipe()
  1031  	os.Stderr = w
  1032  
  1033  	err := f.Parse(args)
  1034  
  1035  	outC := make(chan string)
  1036  	// copy the output in a separate goroutine so printing can't block indefinitely
  1037  	go func() {
  1038  		var buf bytes.Buffer
  1039  		io.Copy(&buf, r)
  1040  		outC <- buf.String()
  1041  	}()
  1042  
  1043  	w.Close()
  1044  	os.Stderr = oldStderr
  1045  	out := <-outC
  1046  
  1047  	return out, err
  1048  }
  1049  
  1050  func TestDeprecatedFlagUsage(t *testing.T) {
  1051  	f := NewFlagSet("bob", ContinueOnError)
  1052  	f.Bool("badflag", true, "always true")
  1053  	usageMsg := "use --good-flag instead"
  1054  	f.MarkDeprecated("badflag", usageMsg)
  1055  
  1056  	args := []string{"--badflag"}
  1057  	out, err := parseReturnStderr(t, f, args)
  1058  	if err != nil {
  1059  		t.Fatal("expected no error; got ", err)
  1060  	}
  1061  
  1062  	if !strings.Contains(out, usageMsg) {
  1063  		t.Errorf("usageMsg not printed when using a deprecated flag!")
  1064  	}
  1065  }
  1066  
  1067  func TestDeprecatedFlagShorthandUsage(t *testing.T) {
  1068  	f := NewFlagSet("bob", ContinueOnError)
  1069  	name := "noshorthandflag"
  1070  	f.BoolP(name, "n", true, "always true")
  1071  	usageMsg := fmt.Sprintf("use --%s instead", name)
  1072  	f.MarkShorthandDeprecated(name, usageMsg)
  1073  
  1074  	args := []string{"-n"}
  1075  	out, err := parseReturnStderr(t, f, args)
  1076  	if err != nil {
  1077  		t.Fatal("expected no error; got ", err)
  1078  	}
  1079  
  1080  	if !strings.Contains(out, usageMsg) {
  1081  		t.Errorf("usageMsg not printed when using a deprecated flag!")
  1082  	}
  1083  }
  1084  
  1085  func TestDeprecatedFlagUsageNormalized(t *testing.T) {
  1086  	f := NewFlagSet("bob", ContinueOnError)
  1087  	f.Bool("bad-double_flag", true, "always true")
  1088  	f.SetNormalizeFunc(wordSepNormalizeFunc)
  1089  	usageMsg := "use --good-flag instead"
  1090  	f.MarkDeprecated("bad_double-flag", usageMsg)
  1091  
  1092  	args := []string{"--bad_double_flag"}
  1093  	out, err := parseReturnStderr(t, f, args)
  1094  	if err != nil {
  1095  		t.Fatal("expected no error; got ", err)
  1096  	}
  1097  
  1098  	if !strings.Contains(out, usageMsg) {
  1099  		t.Errorf("usageMsg not printed when using a deprecated flag!")
  1100  	}
  1101  }
  1102  
  1103  // Name normalization function should be called only once on flag addition
  1104  func TestMultipleNormalizeFlagNameInvocations(t *testing.T) {
  1105  	normalizeFlagNameInvocations = 0
  1106  
  1107  	f := NewFlagSet("normalized", ContinueOnError)
  1108  	f.SetNormalizeFunc(wordSepNormalizeFunc)
  1109  	f.Bool("with_under_flag", false, "bool value")
  1110  
  1111  	if normalizeFlagNameInvocations != 1 {
  1112  		t.Fatal("Expected normalizeFlagNameInvocations to be 1; got ", normalizeFlagNameInvocations)
  1113  	}
  1114  }
  1115  
  1116  //
  1117  func TestHiddenFlagInUsage(t *testing.T) {
  1118  	f := NewFlagSet("bob", ContinueOnError)
  1119  	f.Bool("secretFlag", true, "shhh")
  1120  	f.MarkHidden("secretFlag")
  1121  
  1122  	out := new(bytes.Buffer)
  1123  	f.SetOutput(out)
  1124  	f.PrintDefaults()
  1125  
  1126  	if strings.Contains(out.String(), "secretFlag") {
  1127  		t.Errorf("found hidden flag in usage!")
  1128  	}
  1129  }
  1130  
  1131  //
  1132  func TestHiddenFlagUsage(t *testing.T) {
  1133  	f := NewFlagSet("bob", ContinueOnError)
  1134  	f.Bool("secretFlag", true, "shhh")
  1135  	f.MarkHidden("secretFlag")
  1136  
  1137  	args := []string{"--secretFlag"}
  1138  	out, err := parseReturnStderr(t, f, args)
  1139  	if err != nil {
  1140  		t.Fatal("expected no error; got ", err)
  1141  	}
  1142  
  1143  	if strings.Contains(out, "shhh") {
  1144  		t.Errorf("usage message printed when using a hidden flag!")
  1145  	}
  1146  }
  1147  
  1148  const defaultOutput = `      --A                         for bootstrapping, allow 'any' type
  1149        --Alongflagname             disable bounds checking
  1150    -C, --CCC                       a boolean defaulting to true (default true)
  1151        --D path                    set relative path for local imports
  1152    -E, --EEE num[=1234]            a num with NoOptDefVal (default 4321)
  1153        --F number                  a non-zero number (default 2.7)
  1154        --G float                   a float that defaults to zero
  1155        --IP ip                     IP address with no default
  1156        --IPMask ipMask             Netmask address with no default
  1157        --IPNet ipNet               IP network with no default
  1158        --Ints ints                 int slice with zero default
  1159        --N int                     a non-zero int (default 27)
  1160        --ND1 string[="bar"]        a string with NoOptDefVal (default "foo")
  1161        --ND2 num[=4321]            a num with NoOptDefVal (default 1234)
  1162        --StringArray stringArray   string array with zero default
  1163        --StringSlice strings       string slice with zero default
  1164        --Z int                     an int that defaults to zero
  1165        --custom custom             custom Value implementation
  1166        --customP custom            a VarP with default (default 10)
  1167        --maxT timeout              set timeout for dial
  1168    -v, --verbose count             verbosity
  1169  `
  1170  
  1171  // Custom value that satisfies the Value interface.
  1172  type customValue int
  1173  
  1174  func (cv *customValue) String() string { return fmt.Sprintf("%v", *cv) }
  1175  
  1176  func (cv *customValue) Set(s string) error {
  1177  	v, err := strconv.ParseInt(s, 0, 64)
  1178  	*cv = customValue(v)
  1179  	return err
  1180  }
  1181  
  1182  func (cv *customValue) Type() string { return "custom" }
  1183  
  1184  func TestPrintDefaults(t *testing.T) {
  1185  	fs := NewFlagSet("print defaults test", ContinueOnError)
  1186  	var buf bytes.Buffer
  1187  	fs.SetOutput(&buf)
  1188  	fs.Bool("A", false, "for bootstrapping, allow 'any' type")
  1189  	fs.Bool("Alongflagname", false, "disable bounds checking")
  1190  	fs.BoolP("CCC", "C", true, "a boolean defaulting to true")
  1191  	fs.String("D", "", "set relative `path` for local imports")
  1192  	fs.Float64("F", 2.7, "a non-zero `number`")
  1193  	fs.Float64("G", 0, "a float that defaults to zero")
  1194  	fs.Int("N", 27, "a non-zero int")
  1195  	fs.IntSlice("Ints", []int{}, "int slice with zero default")
  1196  	fs.IP("IP", nil, "IP address with no default")
  1197  	fs.IPMask("IPMask", nil, "Netmask address with no default")
  1198  	fs.IPNet("IPNet", net.IPNet{}, "IP network with no default")
  1199  	fs.Int("Z", 0, "an int that defaults to zero")
  1200  	fs.Duration("maxT", 0, "set `timeout` for dial")
  1201  	fs.String("ND1", "foo", "a string with NoOptDefVal")
  1202  	fs.Lookup("ND1").NoOptDefVal = "bar"
  1203  	fs.Int("ND2", 1234, "a `num` with NoOptDefVal")
  1204  	fs.Lookup("ND2").NoOptDefVal = "4321"
  1205  	fs.IntP("EEE", "E", 4321, "a `num` with NoOptDefVal")
  1206  	fs.ShorthandLookup("E").NoOptDefVal = "1234"
  1207  	fs.StringSlice("StringSlice", []string{}, "string slice with zero default")
  1208  	fs.StringArray("StringArray", []string{}, "string array with zero default")
  1209  	fs.CountP("verbose", "v", "verbosity")
  1210  
  1211  	var cv customValue
  1212  	fs.Var(&cv, "custom", "custom Value implementation")
  1213  
  1214  	cv2 := customValue(10)
  1215  	fs.VarP(&cv2, "customP", "", "a VarP with default")
  1216  
  1217  	fs.PrintDefaults()
  1218  	got := buf.String()
  1219  	if got != defaultOutput {
  1220  		fmt.Println("\n" + got)
  1221  		fmt.Println("\n" + defaultOutput)
  1222  		t.Errorf("got %q want %q\n", got, defaultOutput)
  1223  	}
  1224  }
  1225  
  1226  func TestVisitAllFlagOrder(t *testing.T) {
  1227  	fs := NewFlagSet("TestVisitAllFlagOrder", ContinueOnError)
  1228  	fs.SortFlags = false
  1229  	// https://github.com/spf13/pflag/issues/120
  1230  	fs.SetNormalizeFunc(func(f *FlagSet, name string) NormalizedName {
  1231  		return NormalizedName(name)
  1232  	})
  1233  
  1234  	names := []string{"C", "B", "A", "D"}
  1235  	for _, name := range names {
  1236  		fs.Bool(name, false, "")
  1237  	}
  1238  
  1239  	i := 0
  1240  	fs.VisitAll(func(f *Flag) {
  1241  		if names[i] != f.Name {
  1242  			t.Errorf("Incorrect order. Expected %v, got %v", names[i], f.Name)
  1243  		}
  1244  		i++
  1245  	})
  1246  }
  1247  
  1248  func TestVisitFlagOrder(t *testing.T) {
  1249  	fs := NewFlagSet("TestVisitFlagOrder", ContinueOnError)
  1250  	fs.SortFlags = false
  1251  	names := []string{"C", "B", "A", "D"}
  1252  	for _, name := range names {
  1253  		fs.Bool(name, false, "")
  1254  		fs.Set(name, "true")
  1255  	}
  1256  
  1257  	i := 0
  1258  	fs.Visit(func(f *Flag) {
  1259  		if names[i] != f.Name {
  1260  			t.Errorf("Incorrect order. Expected %v, got %v", names[i], f.Name)
  1261  		}
  1262  		i++
  1263  	})
  1264  }
  1265  

View as plain text