12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259 |
- // Copyright 2009 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package pflag
- import (
- "bytes"
- "fmt"
- "io"
- "io/ioutil"
- "net"
- "os"
- "reflect"
- "sort"
- "strconv"
- "strings"
- "testing"
- "time"
- )
- var (
- testBool = Bool("test_bool", false, "bool value")
- testInt = Int("test_int", 0, "int value")
- testInt64 = Int64("test_int64", 0, "int64 value")
- testUint = Uint("test_uint", 0, "uint value")
- testUint64 = Uint64("test_uint64", 0, "uint64 value")
- testString = String("test_string", "0", "string value")
- testFloat = Float64("test_float64", 0, "float64 value")
- testDuration = Duration("test_duration", 0, "time.Duration value")
- testOptionalInt = Int("test_optional_int", 0, "optional int value")
- normalizeFlagNameInvocations = 0
- )
- func boolString(s string) string {
- if s == "0" {
- return "false"
- }
- return "true"
- }
- func TestEverything(t *testing.T) {
- m := make(map[string]*Flag)
- desired := "0"
- visitor := func(f *Flag) {
- if len(f.Name) > 5 && f.Name[0:5] == "test_" {
- m[f.Name] = f
- ok := false
- switch {
- case f.Value.String() == desired:
- ok = true
- case f.Name == "test_bool" && f.Value.String() == boolString(desired):
- ok = true
- case f.Name == "test_duration" && f.Value.String() == desired+"s":
- ok = true
- }
- if !ok {
- t.Error("Visit: bad value", f.Value.String(), "for", f.Name)
- }
- }
- }
- VisitAll(visitor)
- if len(m) != 9 {
- t.Error("VisitAll misses some flags")
- for k, v := range m {
- t.Log(k, *v)
- }
- }
- m = make(map[string]*Flag)
- Visit(visitor)
- if len(m) != 0 {
- t.Errorf("Visit sees unset flags")
- for k, v := range m {
- t.Log(k, *v)
- }
- }
- // Now set all flags
- Set("test_bool", "true")
- Set("test_int", "1")
- Set("test_int64", "1")
- Set("test_uint", "1")
- Set("test_uint64", "1")
- Set("test_string", "1")
- Set("test_float64", "1")
- Set("test_duration", "1s")
- Set("test_optional_int", "1")
- desired = "1"
- Visit(visitor)
- if len(m) != 9 {
- t.Error("Visit fails after set")
- for k, v := range m {
- t.Log(k, *v)
- }
- }
- // Now test they're visited in sort order.
- var flagNames []string
- Visit(func(f *Flag) { flagNames = append(flagNames, f.Name) })
- if !sort.StringsAreSorted(flagNames) {
- t.Errorf("flag names not sorted: %v", flagNames)
- }
- }
- func TestUsage(t *testing.T) {
- called := false
- ResetForTesting(func() { called = true })
- if GetCommandLine().Parse([]string{"--x"}) == nil {
- t.Error("parse did not fail for unknown flag")
- }
- if called {
- t.Error("did call Usage while using ContinueOnError")
- }
- }
- func TestAddFlagSet(t *testing.T) {
- oldSet := NewFlagSet("old", ContinueOnError)
- newSet := NewFlagSet("new", ContinueOnError)
- oldSet.String("flag1", "flag1", "flag1")
- oldSet.String("flag2", "flag2", "flag2")
- newSet.String("flag2", "flag2", "flag2")
- newSet.String("flag3", "flag3", "flag3")
- oldSet.AddFlagSet(newSet)
- if len(oldSet.formal) != 3 {
- t.Errorf("Unexpected result adding a FlagSet to a FlagSet %v", oldSet)
- }
- }
- func TestAnnotation(t *testing.T) {
- f := NewFlagSet("shorthand", ContinueOnError)
- if err := f.SetAnnotation("missing-flag", "key", nil); err == nil {
- t.Errorf("Expected error setting annotation on non-existent flag")
- }
- f.StringP("stringa", "a", "", "string value")
- if err := f.SetAnnotation("stringa", "key", nil); err != nil {
- t.Errorf("Unexpected error setting new nil annotation: %v", err)
- }
- if annotation := f.Lookup("stringa").Annotations["key"]; annotation != nil {
- t.Errorf("Unexpected annotation: %v", annotation)
- }
- f.StringP("stringb", "b", "", "string2 value")
- if err := f.SetAnnotation("stringb", "key", []string{"value1"}); err != nil {
- t.Errorf("Unexpected error setting new annotation: %v", err)
- }
- if annotation := f.Lookup("stringb").Annotations["key"]; !reflect.DeepEqual(annotation, []string{"value1"}) {
- t.Errorf("Unexpected annotation: %v", annotation)
- }
- if err := f.SetAnnotation("stringb", "key", []string{"value2"}); err != nil {
- t.Errorf("Unexpected error updating annotation: %v", err)
- }
- if annotation := f.Lookup("stringb").Annotations["key"]; !reflect.DeepEqual(annotation, []string{"value2"}) {
- t.Errorf("Unexpected annotation: %v", annotation)
- }
- }
- func testParse(f *FlagSet, t *testing.T) {
- if f.Parsed() {
- t.Error("f.Parse() = true before Parse")
- }
- boolFlag := f.Bool("bool", false, "bool value")
- bool2Flag := f.Bool("bool2", false, "bool2 value")
- bool3Flag := f.Bool("bool3", false, "bool3 value")
- intFlag := f.Int("int", 0, "int value")
- int8Flag := f.Int8("int8", 0, "int value")
- int16Flag := f.Int16("int16", 0, "int value")
- int32Flag := f.Int32("int32", 0, "int value")
- int64Flag := f.Int64("int64", 0, "int64 value")
- uintFlag := f.Uint("uint", 0, "uint value")
- uint8Flag := f.Uint8("uint8", 0, "uint value")
- uint16Flag := f.Uint16("uint16", 0, "uint value")
- uint32Flag := f.Uint32("uint32", 0, "uint value")
- uint64Flag := f.Uint64("uint64", 0, "uint64 value")
- stringFlag := f.String("string", "0", "string value")
- float32Flag := f.Float32("float32", 0, "float32 value")
- float64Flag := f.Float64("float64", 0, "float64 value")
- ipFlag := f.IP("ip", net.ParseIP("127.0.0.1"), "ip value")
- maskFlag := f.IPMask("mask", ParseIPv4Mask("0.0.0.0"), "mask value")
- durationFlag := f.Duration("duration", 5*time.Second, "time.Duration value")
- optionalIntNoValueFlag := f.Int("optional-int-no-value", 0, "int value")
- f.Lookup("optional-int-no-value").NoOptDefVal = "9"
- optionalIntWithValueFlag := f.Int("optional-int-with-value", 0, "int value")
- f.Lookup("optional-int-no-value").NoOptDefVal = "9"
- extra := "one-extra-argument"
- args := []string{
- "--bool",
- "--bool2=true",
- "--bool3=false",
- "--int=22",
- "--int8=-8",
- "--int16=-16",
- "--int32=-32",
- "--int64=0x23",
- "--uint", "24",
- "--uint8=8",
- "--uint16=16",
- "--uint32=32",
- "--uint64=25",
- "--string=hello",
- "--float32=-172e12",
- "--float64=2718e28",
- "--ip=10.11.12.13",
- "--mask=255.255.255.0",
- "--duration=2m",
- "--optional-int-no-value",
- "--optional-int-with-value=42",
- extra,
- }
- if err := f.Parse(args); err != nil {
- t.Fatal(err)
- }
- if !f.Parsed() {
- t.Error("f.Parse() = false after Parse")
- }
- if *boolFlag != true {
- t.Error("bool flag should be true, is ", *boolFlag)
- }
- if v, err := f.GetBool("bool"); err != nil || v != *boolFlag {
- t.Error("GetBool does not work.")
- }
- if *bool2Flag != true {
- t.Error("bool2 flag should be true, is ", *bool2Flag)
- }
- if *bool3Flag != false {
- t.Error("bool3 flag should be false, is ", *bool2Flag)
- }
- if *intFlag != 22 {
- t.Error("int flag should be 22, is ", *intFlag)
- }
- if v, err := f.GetInt("int"); err != nil || v != *intFlag {
- t.Error("GetInt does not work.")
- }
- if *int8Flag != -8 {
- t.Error("int8 flag should be 0x23, is ", *int8Flag)
- }
- if *int16Flag != -16 {
- t.Error("int16 flag should be -16, is ", *int16Flag)
- }
- if v, err := f.GetInt8("int8"); err != nil || v != *int8Flag {
- t.Error("GetInt8 does not work.")
- }
- if v, err := f.GetInt16("int16"); err != nil || v != *int16Flag {
- t.Error("GetInt16 does not work.")
- }
- if *int32Flag != -32 {
- t.Error("int32 flag should be 0x23, is ", *int32Flag)
- }
- if v, err := f.GetInt32("int32"); err != nil || v != *int32Flag {
- t.Error("GetInt32 does not work.")
- }
- if *int64Flag != 0x23 {
- t.Error("int64 flag should be 0x23, is ", *int64Flag)
- }
- if v, err := f.GetInt64("int64"); err != nil || v != *int64Flag {
- t.Error("GetInt64 does not work.")
- }
- if *uintFlag != 24 {
- t.Error("uint flag should be 24, is ", *uintFlag)
- }
- if v, err := f.GetUint("uint"); err != nil || v != *uintFlag {
- t.Error("GetUint does not work.")
- }
- if *uint8Flag != 8 {
- t.Error("uint8 flag should be 8, is ", *uint8Flag)
- }
- if v, err := f.GetUint8("uint8"); err != nil || v != *uint8Flag {
- t.Error("GetUint8 does not work.")
- }
- if *uint16Flag != 16 {
- t.Error("uint16 flag should be 16, is ", *uint16Flag)
- }
- if v, err := f.GetUint16("uint16"); err != nil || v != *uint16Flag {
- t.Error("GetUint16 does not work.")
- }
- if *uint32Flag != 32 {
- t.Error("uint32 flag should be 32, is ", *uint32Flag)
- }
- if v, err := f.GetUint32("uint32"); err != nil || v != *uint32Flag {
- t.Error("GetUint32 does not work.")
- }
- if *uint64Flag != 25 {
- t.Error("uint64 flag should be 25, is ", *uint64Flag)
- }
- if v, err := f.GetUint64("uint64"); err != nil || v != *uint64Flag {
- t.Error("GetUint64 does not work.")
- }
- if *stringFlag != "hello" {
- t.Error("string flag should be `hello`, is ", *stringFlag)
- }
- if v, err := f.GetString("string"); err != nil || v != *stringFlag {
- t.Error("GetString does not work.")
- }
- if *float32Flag != -172e12 {
- t.Error("float32 flag should be -172e12, is ", *float32Flag)
- }
- if v, err := f.GetFloat32("float32"); err != nil || v != *float32Flag {
- t.Errorf("GetFloat32 returned %v but float32Flag was %v", v, *float32Flag)
- }
- if *float64Flag != 2718e28 {
- t.Error("float64 flag should be 2718e28, is ", *float64Flag)
- }
- if v, err := f.GetFloat64("float64"); err != nil || v != *float64Flag {
- t.Errorf("GetFloat64 returned %v but float64Flag was %v", v, *float64Flag)
- }
- if !(*ipFlag).Equal(net.ParseIP("10.11.12.13")) {
- t.Error("ip flag should be 10.11.12.13, is ", *ipFlag)
- }
- if v, err := f.GetIP("ip"); err != nil || !v.Equal(*ipFlag) {
- t.Errorf("GetIP returned %v but ipFlag was %v", v, *ipFlag)
- }
- if (*maskFlag).String() != ParseIPv4Mask("255.255.255.0").String() {
- t.Error("mask flag should be 255.255.255.0, is ", (*maskFlag).String())
- }
- if v, err := f.GetIPv4Mask("mask"); err != nil || v.String() != (*maskFlag).String() {
- t.Errorf("GetIP returned %v maskFlag was %v error was %v", v, *maskFlag, err)
- }
- if *durationFlag != 2*time.Minute {
- t.Error("duration flag should be 2m, is ", *durationFlag)
- }
- if v, err := f.GetDuration("duration"); err != nil || v != *durationFlag {
- t.Error("GetDuration does not work.")
- }
- if _, err := f.GetInt("duration"); err == nil {
- t.Error("GetInt parsed a time.Duration?!?!")
- }
- if *optionalIntNoValueFlag != 9 {
- t.Error("optional int flag should be the default value, is ", *optionalIntNoValueFlag)
- }
- if *optionalIntWithValueFlag != 42 {
- t.Error("optional int flag should be 42, is ", *optionalIntWithValueFlag)
- }
- if len(f.Args()) != 1 {
- t.Error("expected one argument, got", len(f.Args()))
- } else if f.Args()[0] != extra {
- t.Errorf("expected argument %q got %q", extra, f.Args()[0])
- }
- }
- func testParseAll(f *FlagSet, t *testing.T) {
- if f.Parsed() {
- t.Error("f.Parse() = true before Parse")
- }
- f.BoolP("boola", "a", false, "bool value")
- f.BoolP("boolb", "b", false, "bool2 value")
- f.BoolP("boolc", "c", false, "bool3 value")
- f.BoolP("boold", "d", false, "bool4 value")
- f.StringP("stringa", "s", "0", "string value")
- f.StringP("stringz", "z", "0", "string value")
- f.StringP("stringx", "x", "0", "string value")
- f.StringP("stringy", "y", "0", "string value")
- f.Lookup("stringx").NoOptDefVal = "1"
- args := []string{
- "-ab",
- "-cs=xx",
- "--stringz=something",
- "-d=true",
- "-x",
- "-y",
- "ee",
- }
- want := []string{
- "boola", "true",
- "boolb", "true",
- "boolc", "true",
- "stringa", "xx",
- "stringz", "something",
- "boold", "true",
- "stringx", "1",
- "stringy", "ee",
- }
- got := []string{}
- store := func(flag *Flag, value string) error {
- got = append(got, flag.Name)
- if len(value) > 0 {
- got = append(got, value)
- }
- return nil
- }
- if err := f.ParseAll(args, store); err != nil {
- t.Errorf("expected no error, got %s", err)
- }
- if !f.Parsed() {
- t.Errorf("f.Parse() = false after Parse")
- }
- if !reflect.DeepEqual(got, want) {
- t.Errorf("f.ParseAll() fail to restore the args")
- t.Errorf("Got: %v", got)
- t.Errorf("Want: %v", want)
- }
- }
- func testParseWithUnknownFlags(f *FlagSet, t *testing.T) {
- if f.Parsed() {
- t.Error("f.Parse() = true before Parse")
- }
- f.ParseErrorsWhitelist.UnknownFlags = true
- f.BoolP("boola", "a", false, "bool value")
- f.BoolP("boolb", "b", false, "bool2 value")
- f.BoolP("boolc", "c", false, "bool3 value")
- f.BoolP("boold", "d", false, "bool4 value")
- f.BoolP("boole", "e", false, "bool4 value")
- f.StringP("stringa", "s", "0", "string value")
- f.StringP("stringz", "z", "0", "string value")
- f.StringP("stringx", "x", "0", "string value")
- f.StringP("stringy", "y", "0", "string value")
- f.StringP("stringo", "o", "0", "string value")
- f.Lookup("stringx").NoOptDefVal = "1"
- args := []string{
- "-ab",
- "-cs=xx",
- "--stringz=something",
- "--unknown1",
- "unknown1Value",
- "-d=true",
- "-x",
- "--unknown2=unknown2Value",
- "-u=unknown3Value",
- "-p",
- "unknown4Value",
- "-q", //another unknown with bool value
- "-y",
- "ee",
- "--unknown7=unknown7value",
- "--stringo=ovalue",
- "--unknown8=unknown8value",
- "--boole",
- "--unknown6",
- }
- want := []string{
- "boola", "true",
- "boolb", "true",
- "boolc", "true",
- "stringa", "xx",
- "stringz", "something",
- "boold", "true",
- "stringx", "1",
- "stringy", "ee",
- "stringo", "ovalue",
- "boole", "true",
- }
- got := []string{}
- store := func(flag *Flag, value string) error {
- got = append(got, flag.Name)
- if len(value) > 0 {
- got = append(got, value)
- }
- return nil
- }
- if err := f.ParseAll(args, store); err != nil {
- t.Errorf("expected no error, got %s", err)
- }
- if !f.Parsed() {
- t.Errorf("f.Parse() = false after Parse")
- }
- if !reflect.DeepEqual(got, want) {
- t.Errorf("f.ParseAll() fail to restore the args")
- t.Errorf("Got: %v", got)
- t.Errorf("Want: %v", want)
- }
- }
- func TestShorthand(t *testing.T) {
- f := NewFlagSet("shorthand", ContinueOnError)
- if f.Parsed() {
- t.Error("f.Parse() = true before Parse")
- }
- boolaFlag := f.BoolP("boola", "a", false, "bool value")
- boolbFlag := f.BoolP("boolb", "b", false, "bool2 value")
- boolcFlag := f.BoolP("boolc", "c", false, "bool3 value")
- booldFlag := f.BoolP("boold", "d", false, "bool4 value")
- stringaFlag := f.StringP("stringa", "s", "0", "string value")
- stringzFlag := f.StringP("stringz", "z", "0", "string value")
- extra := "interspersed-argument"
- notaflag := "--i-look-like-a-flag"
- args := []string{
- "-ab",
- extra,
- "-cs",
- "hello",
- "-z=something",
- "-d=true",
- "--",
- notaflag,
- }
- f.SetOutput(ioutil.Discard)
- if err := f.Parse(args); err != nil {
- t.Error("expected no error, got ", err)
- }
- if !f.Parsed() {
- t.Error("f.Parse() = false after Parse")
- }
- if *boolaFlag != true {
- t.Error("boola flag should be true, is ", *boolaFlag)
- }
- if *boolbFlag != true {
- t.Error("boolb flag should be true, is ", *boolbFlag)
- }
- if *boolcFlag != true {
- t.Error("boolc flag should be true, is ", *boolcFlag)
- }
- if *booldFlag != true {
- t.Error("boold flag should be true, is ", *booldFlag)
- }
- if *stringaFlag != "hello" {
- t.Error("stringa flag should be `hello`, is ", *stringaFlag)
- }
- if *stringzFlag != "something" {
- t.Error("stringz flag should be `something`, is ", *stringzFlag)
- }
- if len(f.Args()) != 2 {
- t.Error("expected one argument, got", len(f.Args()))
- } else if f.Args()[0] != extra {
- t.Errorf("expected argument %q got %q", extra, f.Args()[0])
- } else if f.Args()[1] != notaflag {
- t.Errorf("expected argument %q got %q", notaflag, f.Args()[1])
- }
- if f.ArgsLenAtDash() != 1 {
- t.Errorf("expected argsLenAtDash %d got %d", f.ArgsLenAtDash(), 1)
- }
- }
- func TestShorthandLookup(t *testing.T) {
- f := NewFlagSet("shorthand", ContinueOnError)
- if f.Parsed() {
- t.Error("f.Parse() = true before Parse")
- }
- f.BoolP("boola", "a", false, "bool value")
- f.BoolP("boolb", "b", false, "bool2 value")
- args := []string{
- "-ab",
- }
- f.SetOutput(ioutil.Discard)
- if err := f.Parse(args); err != nil {
- t.Error("expected no error, got ", err)
- }
- if !f.Parsed() {
- t.Error("f.Parse() = false after Parse")
- }
- flag := f.ShorthandLookup("a")
- if flag == nil {
- t.Errorf("f.ShorthandLookup(\"a\") returned nil")
- }
- if flag.Name != "boola" {
- t.Errorf("f.ShorthandLookup(\"a\") found %q instead of \"boola\"", flag.Name)
- }
- flag = f.ShorthandLookup("")
- if flag != nil {
- t.Errorf("f.ShorthandLookup(\"\") did not return nil")
- }
- defer func() {
- recover()
- }()
- flag = f.ShorthandLookup("ab")
- // should NEVER get here. lookup should panic. defer'd func should recover it.
- t.Errorf("f.ShorthandLookup(\"ab\") did not panic")
- }
- func TestParse(t *testing.T) {
- ResetForTesting(func() { t.Error("bad parse") })
- testParse(GetCommandLine(), t)
- }
- func TestParseAll(t *testing.T) {
- ResetForTesting(func() { t.Error("bad parse") })
- testParseAll(GetCommandLine(), t)
- }
- func TestIgnoreUnknownFlags(t *testing.T) {
- ResetForTesting(func() { t.Error("bad parse") })
- testParseWithUnknownFlags(GetCommandLine(), t)
- }
- func TestFlagSetParse(t *testing.T) {
- testParse(NewFlagSet("test", ContinueOnError), t)
- }
- func TestChangedHelper(t *testing.T) {
- f := NewFlagSet("changedtest", ContinueOnError)
- f.Bool("changed", false, "changed bool")
- f.Bool("settrue", true, "true to true")
- f.Bool("setfalse", false, "false to false")
- f.Bool("unchanged", false, "unchanged bool")
- args := []string{"--changed", "--settrue", "--setfalse=false"}
- if err := f.Parse(args); err != nil {
- t.Error("f.Parse() = false after Parse")
- }
- if !f.Changed("changed") {
- t.Errorf("--changed wasn't changed!")
- }
- if !f.Changed("settrue") {
- t.Errorf("--settrue wasn't changed!")
- }
- if !f.Changed("setfalse") {
- t.Errorf("--setfalse wasn't changed!")
- }
- if f.Changed("unchanged") {
- t.Errorf("--unchanged was changed!")
- }
- if f.Changed("invalid") {
- t.Errorf("--invalid was changed!")
- }
- if f.ArgsLenAtDash() != -1 {
- t.Errorf("Expected argsLenAtDash: %d but got %d", -1, f.ArgsLenAtDash())
- }
- }
- func replaceSeparators(name string, from []string, to string) string {
- result := name
- for _, sep := range from {
- result = strings.Replace(result, sep, to, -1)
- }
- // Type convert to indicate normalization has been done.
- return result
- }
- func wordSepNormalizeFunc(f *FlagSet, name string) NormalizedName {
- seps := []string{"-", "_"}
- name = replaceSeparators(name, seps, ".")
- normalizeFlagNameInvocations++
- return NormalizedName(name)
- }
- func testWordSepNormalizedNames(args []string, t *testing.T) {
- f := NewFlagSet("normalized", ContinueOnError)
- if f.Parsed() {
- t.Error("f.Parse() = true before Parse")
- }
- withDashFlag := f.Bool("with-dash-flag", false, "bool value")
- // Set this after some flags have been added and before others.
- f.SetNormalizeFunc(wordSepNormalizeFunc)
- withUnderFlag := f.Bool("with_under_flag", false, "bool value")
- withBothFlag := f.Bool("with-both_flag", false, "bool value")
- if err := f.Parse(args); err != nil {
- t.Fatal(err)
- }
- if !f.Parsed() {
- t.Error("f.Parse() = false after Parse")
- }
- if *withDashFlag != true {
- t.Error("withDashFlag flag should be true, is ", *withDashFlag)
- }
- if *withUnderFlag != true {
- t.Error("withUnderFlag flag should be true, is ", *withUnderFlag)
- }
- if *withBothFlag != true {
- t.Error("withBothFlag flag should be true, is ", *withBothFlag)
- }
- }
- func TestWordSepNormalizedNames(t *testing.T) {
- args := []string{
- "--with-dash-flag",
- "--with-under-flag",
- "--with-both-flag",
- }
- testWordSepNormalizedNames(args, t)
- args = []string{
- "--with_dash_flag",
- "--with_under_flag",
- "--with_both_flag",
- }
- testWordSepNormalizedNames(args, t)
- args = []string{
- "--with-dash_flag",
- "--with-under_flag",
- "--with-both_flag",
- }
- testWordSepNormalizedNames(args, t)
- }
- func aliasAndWordSepFlagNames(f *FlagSet, name string) NormalizedName {
- seps := []string{"-", "_"}
- oldName := replaceSeparators("old-valid_flag", seps, ".")
- newName := replaceSeparators("valid-flag", seps, ".")
- name = replaceSeparators(name, seps, ".")
- switch name {
- case oldName:
- name = newName
- }
- return NormalizedName(name)
- }
- func TestCustomNormalizedNames(t *testing.T) {
- f := NewFlagSet("normalized", ContinueOnError)
- if f.Parsed() {
- t.Error("f.Parse() = true before Parse")
- }
- validFlag := f.Bool("valid-flag", false, "bool value")
- f.SetNormalizeFunc(aliasAndWordSepFlagNames)
- someOtherFlag := f.Bool("some-other-flag", false, "bool value")
- args := []string{"--old_valid_flag", "--some-other_flag"}
- if err := f.Parse(args); err != nil {
- t.Fatal(err)
- }
- if *validFlag != true {
- t.Errorf("validFlag is %v even though we set the alias --old_valid_falg", *validFlag)
- }
- if *someOtherFlag != true {
- t.Error("someOtherFlag should be true, is ", *someOtherFlag)
- }
- }
- // Every flag we add, the name (displayed also in usage) should normalized
- func TestNormalizationFuncShouldChangeFlagName(t *testing.T) {
- // Test normalization after addition
- f := NewFlagSet("normalized", ContinueOnError)
- f.Bool("valid_flag", false, "bool value")
- if f.Lookup("valid_flag").Name != "valid_flag" {
- t.Error("The new flag should have the name 'valid_flag' instead of ", f.Lookup("valid_flag").Name)
- }
- f.SetNormalizeFunc(wordSepNormalizeFunc)
- if f.Lookup("valid_flag").Name != "valid.flag" {
- t.Error("The new flag should have the name 'valid.flag' instead of ", f.Lookup("valid_flag").Name)
- }
- // Test normalization before addition
- f = NewFlagSet("normalized", ContinueOnError)
- f.SetNormalizeFunc(wordSepNormalizeFunc)
- f.Bool("valid_flag", false, "bool value")
- if f.Lookup("valid_flag").Name != "valid.flag" {
- t.Error("The new flag should have the name 'valid.flag' instead of ", f.Lookup("valid_flag").Name)
- }
- }
- // Related to https://github.com/spf13/cobra/issues/521.
- func TestNormalizationSharedFlags(t *testing.T) {
- f := NewFlagSet("set f", ContinueOnError)
- g := NewFlagSet("set g", ContinueOnError)
- nfunc := wordSepNormalizeFunc
- testName := "valid_flag"
- normName := nfunc(nil, testName)
- if testName == string(normName) {
- t.Error("TestNormalizationSharedFlags meaningless: the original and normalized flag names are identical:", testName)
- }
- f.Bool(testName, false, "bool value")
- g.AddFlagSet(f)
- f.SetNormalizeFunc(nfunc)
- g.SetNormalizeFunc(nfunc)
- if len(f.formal) != 1 {
- t.Error("Normalizing flags should not result in duplications in the flag set:", f.formal)
- }
- if f.orderedFormal[0].Name != string(normName) {
- t.Error("Flag name not normalized")
- }
- for k := range f.formal {
- if k != "valid.flag" {
- t.Errorf("The key in the flag map should have been normalized: wanted \"%s\", got \"%s\" instead", normName, k)
- }
- }
- if !reflect.DeepEqual(f.formal, g.formal) || !reflect.DeepEqual(f.orderedFormal, g.orderedFormal) {
- t.Error("Two flag sets sharing the same flags should stay consistent after being normalized. Original set:", f.formal, "Duplicate set:", g.formal)
- }
- }
- func TestNormalizationSetFlags(t *testing.T) {
- f := NewFlagSet("normalized", ContinueOnError)
- nfunc := wordSepNormalizeFunc
- testName := "valid_flag"
- normName := nfunc(nil, testName)
- if testName == string(normName) {
- t.Error("TestNormalizationSetFlags meaningless: the original and normalized flag names are identical:", testName)
- }
- f.Bool(testName, false, "bool value")
- f.Set(testName, "true")
- f.SetNormalizeFunc(nfunc)
- if len(f.formal) != 1 {
- t.Error("Normalizing flags should not result in duplications in the flag set:", f.formal)
- }
- if f.orderedFormal[0].Name != string(normName) {
- t.Error("Flag name not normalized")
- }
- for k := range f.formal {
- if k != "valid.flag" {
- t.Errorf("The key in the flag map should have been normalized: wanted \"%s\", got \"%s\" instead", normName, k)
- }
- }
- if !reflect.DeepEqual(f.formal, f.actual) {
- t.Error("The map of set flags should get normalized. Formal:", f.formal, "Actual:", f.actual)
- }
- }
- // Declare a user-defined flag type.
- type flagVar []string
- func (f *flagVar) String() string {
- return fmt.Sprint([]string(*f))
- }
- func (f *flagVar) Set(value string) error {
- *f = append(*f, value)
- return nil
- }
- func (f *flagVar) Type() string {
- return "flagVar"
- }
- func TestUserDefined(t *testing.T) {
- var flags FlagSet
- flags.Init("test", ContinueOnError)
- var v flagVar
- flags.VarP(&v, "v", "v", "usage")
- if err := flags.Parse([]string{"--v=1", "-v2", "-v", "3"}); err != nil {
- t.Error(err)
- }
- if len(v) != 3 {
- t.Fatal("expected 3 args; got ", len(v))
- }
- expect := "[1 2 3]"
- if v.String() != expect {
- t.Errorf("expected value %q got %q", expect, v.String())
- }
- }
- func TestSetOutput(t *testing.T) {
- var flags FlagSet
- var buf bytes.Buffer
- flags.SetOutput(&buf)
- flags.Init("test", ContinueOnError)
- flags.Parse([]string{"--unknown"})
- if out := buf.String(); !strings.Contains(out, "--unknown") {
- t.Logf("expected output mentioning unknown; got %q", out)
- }
- }
- // This tests that one can reset the flags. This still works but not well, and is
- // superseded by FlagSet.
- func TestChangingArgs(t *testing.T) {
- ResetForTesting(func() { t.Fatal("bad parse") })
- oldArgs := os.Args
- defer func() { os.Args = oldArgs }()
- os.Args = []string{"cmd", "--before", "subcmd"}
- before := Bool("before", false, "")
- if err := GetCommandLine().Parse(os.Args[1:]); err != nil {
- t.Fatal(err)
- }
- cmd := Arg(0)
- os.Args = []string{"subcmd", "--after", "args"}
- after := Bool("after", false, "")
- Parse()
- args := Args()
- if !*before || cmd != "subcmd" || !*after || len(args) != 1 || args[0] != "args" {
- t.Fatalf("expected true subcmd true [args] got %v %v %v %v", *before, cmd, *after, args)
- }
- }
- // Test that -help invokes the usage message and returns ErrHelp.
- func TestHelp(t *testing.T) {
- var helpCalled = false
- fs := NewFlagSet("help test", ContinueOnError)
- fs.Usage = func() { helpCalled = true }
- var flag bool
- fs.BoolVar(&flag, "flag", false, "regular flag")
- // Regular flag invocation should work
- err := fs.Parse([]string{"--flag=true"})
- if err != nil {
- t.Fatal("expected no error; got ", err)
- }
- if !flag {
- t.Error("flag was not set by --flag")
- }
- if helpCalled {
- t.Error("help called for regular flag")
- helpCalled = false // reset for next test
- }
- // Help flag should work as expected.
- err = fs.Parse([]string{"--help"})
- if err == nil {
- t.Fatal("error expected")
- }
- if err != ErrHelp {
- t.Fatal("expected ErrHelp; got ", err)
- }
- if !helpCalled {
- t.Fatal("help was not called")
- }
- // If we define a help flag, that should override.
- var help bool
- fs.BoolVar(&help, "help", false, "help flag")
- helpCalled = false
- err = fs.Parse([]string{"--help"})
- if err != nil {
- t.Fatal("expected no error for defined --help; got ", err)
- }
- if helpCalled {
- t.Fatal("help was called; should not have been for defined help flag")
- }
- }
- func TestNoInterspersed(t *testing.T) {
- f := NewFlagSet("test", ContinueOnError)
- f.SetInterspersed(false)
- f.Bool("true", true, "always true")
- f.Bool("false", false, "always false")
- err := f.Parse([]string{"--true", "break", "--false"})
- if err != nil {
- t.Fatal("expected no error; got ", err)
- }
- args := f.Args()
- if len(args) != 2 || args[0] != "break" || args[1] != "--false" {
- t.Fatal("expected interspersed options/non-options to fail")
- }
- }
- func TestTermination(t *testing.T) {
- f := NewFlagSet("termination", ContinueOnError)
- boolFlag := f.BoolP("bool", "l", false, "bool value")
- if f.Parsed() {
- t.Error("f.Parse() = true before Parse")
- }
- arg1 := "ls"
- arg2 := "-l"
- args := []string{
- "--",
- arg1,
- arg2,
- }
- f.SetOutput(ioutil.Discard)
- if err := f.Parse(args); err != nil {
- t.Fatal("expected no error; got ", err)
- }
- if !f.Parsed() {
- t.Error("f.Parse() = false after Parse")
- }
- if *boolFlag {
- t.Error("expected boolFlag=false, got true")
- }
- if len(f.Args()) != 2 {
- t.Errorf("expected 2 arguments, got %d: %v", len(f.Args()), f.Args())
- }
- if f.Args()[0] != arg1 {
- t.Errorf("expected argument %q got %q", arg1, f.Args()[0])
- }
- if f.Args()[1] != arg2 {
- t.Errorf("expected argument %q got %q", arg2, f.Args()[1])
- }
- if f.ArgsLenAtDash() != 0 {
- t.Errorf("expected argsLenAtDash %d got %d", 0, f.ArgsLenAtDash())
- }
- }
- func getDeprecatedFlagSet() *FlagSet {
- f := NewFlagSet("bob", ContinueOnError)
- f.Bool("badflag", true, "always true")
- f.MarkDeprecated("badflag", "use --good-flag instead")
- return f
- }
- func TestDeprecatedFlagInDocs(t *testing.T) {
- f := getDeprecatedFlagSet()
- out := new(bytes.Buffer)
- f.SetOutput(out)
- f.PrintDefaults()
- if strings.Contains(out.String(), "badflag") {
- t.Errorf("found deprecated flag in usage!")
- }
- }
- func TestUnHiddenDeprecatedFlagInDocs(t *testing.T) {
- f := getDeprecatedFlagSet()
- flg := f.Lookup("badflag")
- if flg == nil {
- t.Fatalf("Unable to lookup 'bob' in TestUnHiddenDeprecatedFlagInDocs")
- }
- flg.Hidden = false
- out := new(bytes.Buffer)
- f.SetOutput(out)
- f.PrintDefaults()
- defaults := out.String()
- if !strings.Contains(defaults, "badflag") {
- t.Errorf("Did not find deprecated flag in usage!")
- }
- if !strings.Contains(defaults, "use --good-flag instead") {
- t.Errorf("Did not find 'use --good-flag instead' in defaults")
- }
- }
- func TestDeprecatedFlagShorthandInDocs(t *testing.T) {
- f := NewFlagSet("bob", ContinueOnError)
- name := "noshorthandflag"
- f.BoolP(name, "n", true, "always true")
- f.MarkShorthandDeprecated("noshorthandflag", fmt.Sprintf("use --%s instead", name))
- out := new(bytes.Buffer)
- f.SetOutput(out)
- f.PrintDefaults()
- if strings.Contains(out.String(), "-n,") {
- t.Errorf("found deprecated flag shorthand in usage!")
- }
- }
- func parseReturnStderr(t *testing.T, f *FlagSet, args []string) (string, error) {
- oldStderr := os.Stderr
- r, w, _ := os.Pipe()
- os.Stderr = w
- err := f.Parse(args)
- outC := make(chan string)
- // copy the output in a separate goroutine so printing can't block indefinitely
- go func() {
- var buf bytes.Buffer
- io.Copy(&buf, r)
- outC <- buf.String()
- }()
- w.Close()
- os.Stderr = oldStderr
- out := <-outC
- return out, err
- }
- func TestDeprecatedFlagUsage(t *testing.T) {
- f := NewFlagSet("bob", ContinueOnError)
- f.Bool("badflag", true, "always true")
- usageMsg := "use --good-flag instead"
- f.MarkDeprecated("badflag", usageMsg)
- args := []string{"--badflag"}
- out, err := parseReturnStderr(t, f, args)
- if err != nil {
- t.Fatal("expected no error; got ", err)
- }
- if !strings.Contains(out, usageMsg) {
- t.Errorf("usageMsg not printed when using a deprecated flag!")
- }
- }
- func TestDeprecatedFlagShorthandUsage(t *testing.T) {
- f := NewFlagSet("bob", ContinueOnError)
- name := "noshorthandflag"
- f.BoolP(name, "n", true, "always true")
- usageMsg := fmt.Sprintf("use --%s instead", name)
- f.MarkShorthandDeprecated(name, usageMsg)
- args := []string{"-n"}
- out, err := parseReturnStderr(t, f, args)
- if err != nil {
- t.Fatal("expected no error; got ", err)
- }
- if !strings.Contains(out, usageMsg) {
- t.Errorf("usageMsg not printed when using a deprecated flag!")
- }
- }
- func TestDeprecatedFlagUsageNormalized(t *testing.T) {
- f := NewFlagSet("bob", ContinueOnError)
- f.Bool("bad-double_flag", true, "always true")
- f.SetNormalizeFunc(wordSepNormalizeFunc)
- usageMsg := "use --good-flag instead"
- f.MarkDeprecated("bad_double-flag", usageMsg)
- args := []string{"--bad_double_flag"}
- out, err := parseReturnStderr(t, f, args)
- if err != nil {
- t.Fatal("expected no error; got ", err)
- }
- if !strings.Contains(out, usageMsg) {
- t.Errorf("usageMsg not printed when using a deprecated flag!")
- }
- }
- // Name normalization function should be called only once on flag addition
- func TestMultipleNormalizeFlagNameInvocations(t *testing.T) {
- normalizeFlagNameInvocations = 0
- f := NewFlagSet("normalized", ContinueOnError)
- f.SetNormalizeFunc(wordSepNormalizeFunc)
- f.Bool("with_under_flag", false, "bool value")
- if normalizeFlagNameInvocations != 1 {
- t.Fatal("Expected normalizeFlagNameInvocations to be 1; got ", normalizeFlagNameInvocations)
- }
- }
- //
- func TestHiddenFlagInUsage(t *testing.T) {
- f := NewFlagSet("bob", ContinueOnError)
- f.Bool("secretFlag", true, "shhh")
- f.MarkHidden("secretFlag")
- out := new(bytes.Buffer)
- f.SetOutput(out)
- f.PrintDefaults()
- if strings.Contains(out.String(), "secretFlag") {
- t.Errorf("found hidden flag in usage!")
- }
- }
- //
- func TestHiddenFlagUsage(t *testing.T) {
- f := NewFlagSet("bob", ContinueOnError)
- f.Bool("secretFlag", true, "shhh")
- f.MarkHidden("secretFlag")
- args := []string{"--secretFlag"}
- out, err := parseReturnStderr(t, f, args)
- if err != nil {
- t.Fatal("expected no error; got ", err)
- }
- if strings.Contains(out, "shhh") {
- t.Errorf("usage message printed when using a hidden flag!")
- }
- }
- const defaultOutput = ` --A for bootstrapping, allow 'any' type
- --Alongflagname disable bounds checking
- -C, --CCC a boolean defaulting to true (default true)
- --D path set relative path for local imports
- -E, --EEE num[=1234] a num with NoOptDefVal (default 4321)
- --F number a non-zero number (default 2.7)
- --G float a float that defaults to zero
- --IP ip IP address with no default
- --IPMask ipMask Netmask address with no default
- --IPNet ipNet IP network with no default
- --Ints ints int slice with zero default
- --N int a non-zero int (default 27)
- --ND1 string[="bar"] a string with NoOptDefVal (default "foo")
- --ND2 num[=4321] a num with NoOptDefVal (default 1234)
- --StringArray stringArray string array with zero default
- --StringSlice strings string slice with zero default
- --Z int an int that defaults to zero
- --custom custom custom Value implementation
- --customP custom a VarP with default (default 10)
- --maxT timeout set timeout for dial
- -v, --verbose count verbosity
- `
- // Custom value that satisfies the Value interface.
- type customValue int
- func (cv *customValue) String() string { return fmt.Sprintf("%v", *cv) }
- func (cv *customValue) Set(s string) error {
- v, err := strconv.ParseInt(s, 0, 64)
- *cv = customValue(v)
- return err
- }
- func (cv *customValue) Type() string { return "custom" }
- func TestPrintDefaults(t *testing.T) {
- fs := NewFlagSet("print defaults test", ContinueOnError)
- var buf bytes.Buffer
- fs.SetOutput(&buf)
- fs.Bool("A", false, "for bootstrapping, allow 'any' type")
- fs.Bool("Alongflagname", false, "disable bounds checking")
- fs.BoolP("CCC", "C", true, "a boolean defaulting to true")
- fs.String("D", "", "set relative `path` for local imports")
- fs.Float64("F", 2.7, "a non-zero `number`")
- fs.Float64("G", 0, "a float that defaults to zero")
- fs.Int("N", 27, "a non-zero int")
- fs.IntSlice("Ints", []int{}, "int slice with zero default")
- fs.IP("IP", nil, "IP address with no default")
- fs.IPMask("IPMask", nil, "Netmask address with no default")
- fs.IPNet("IPNet", net.IPNet{}, "IP network with no default")
- fs.Int("Z", 0, "an int that defaults to zero")
- fs.Duration("maxT", 0, "set `timeout` for dial")
- fs.String("ND1", "foo", "a string with NoOptDefVal")
- fs.Lookup("ND1").NoOptDefVal = "bar"
- fs.Int("ND2", 1234, "a `num` with NoOptDefVal")
- fs.Lookup("ND2").NoOptDefVal = "4321"
- fs.IntP("EEE", "E", 4321, "a `num` with NoOptDefVal")
- fs.ShorthandLookup("E").NoOptDefVal = "1234"
- fs.StringSlice("StringSlice", []string{}, "string slice with zero default")
- fs.StringArray("StringArray", []string{}, "string array with zero default")
- fs.CountP("verbose", "v", "verbosity")
- var cv customValue
- fs.Var(&cv, "custom", "custom Value implementation")
- cv2 := customValue(10)
- fs.VarP(&cv2, "customP", "", "a VarP with default")
- fs.PrintDefaults()
- got := buf.String()
- if got != defaultOutput {
- fmt.Println("\n" + got)
- fmt.Println("\n" + defaultOutput)
- t.Errorf("got %q want %q\n", got, defaultOutput)
- }
- }
- func TestVisitAllFlagOrder(t *testing.T) {
- fs := NewFlagSet("TestVisitAllFlagOrder", ContinueOnError)
- fs.SortFlags = false
- // https://github.com/spf13/pflag/issues/120
- fs.SetNormalizeFunc(func(f *FlagSet, name string) NormalizedName {
- return NormalizedName(name)
- })
- names := []string{"C", "B", "A", "D"}
- for _, name := range names {
- fs.Bool(name, false, "")
- }
- i := 0
- fs.VisitAll(func(f *Flag) {
- if names[i] != f.Name {
- t.Errorf("Incorrect order. Expected %v, got %v", names[i], f.Name)
- }
- i++
- })
- }
- func TestVisitFlagOrder(t *testing.T) {
- fs := NewFlagSet("TestVisitFlagOrder", ContinueOnError)
- fs.SortFlags = false
- names := []string{"C", "B", "A", "D"}
- for _, name := range names {
- fs.Bool(name, false, "")
- fs.Set(name, "true")
- }
- i := 0
- fs.Visit(func(f *Flag) {
- if names[i] != f.Name {
- t.Errorf("Incorrect order. Expected %v, got %v", names[i], f.Name)
- }
- i++
- })
- }
|