flag_test.go 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944
  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. package pflag
  5. import (
  6. "bytes"
  7. "fmt"
  8. "io"
  9. "io/ioutil"
  10. "net"
  11. "os"
  12. "reflect"
  13. "sort"
  14. "strconv"
  15. "strings"
  16. "testing"
  17. "time"
  18. )
  19. var (
  20. testBool = Bool("test_bool", false, "bool value")
  21. testInt = Int("test_int", 0, "int value")
  22. testInt64 = Int64("test_int64", 0, "int64 value")
  23. testUint = Uint("test_uint", 0, "uint value")
  24. testUint64 = Uint64("test_uint64", 0, "uint64 value")
  25. testString = String("test_string", "0", "string value")
  26. testFloat = Float64("test_float64", 0, "float64 value")
  27. testDuration = Duration("test_duration", 0, "time.Duration value")
  28. testOptionalInt = Int("test_optional_int", 0, "optional int value")
  29. normalizeFlagNameInvocations = 0
  30. )
  31. func boolString(s string) string {
  32. if s == "0" {
  33. return "false"
  34. }
  35. return "true"
  36. }
  37. func TestEverything(t *testing.T) {
  38. m := make(map[string]*Flag)
  39. desired := "0"
  40. visitor := func(f *Flag) {
  41. if len(f.Name) > 5 && f.Name[0:5] == "test_" {
  42. m[f.Name] = f
  43. ok := false
  44. switch {
  45. case f.Value.String() == desired:
  46. ok = true
  47. case f.Name == "test_bool" && f.Value.String() == boolString(desired):
  48. ok = true
  49. case f.Name == "test_duration" && f.Value.String() == desired+"s":
  50. ok = true
  51. }
  52. if !ok {
  53. t.Error("Visit: bad value", f.Value.String(), "for", f.Name)
  54. }
  55. }
  56. }
  57. VisitAll(visitor)
  58. if len(m) != 9 {
  59. t.Error("VisitAll misses some flags")
  60. for k, v := range m {
  61. t.Log(k, *v)
  62. }
  63. }
  64. m = make(map[string]*Flag)
  65. Visit(visitor)
  66. if len(m) != 0 {
  67. t.Errorf("Visit sees unset flags")
  68. for k, v := range m {
  69. t.Log(k, *v)
  70. }
  71. }
  72. // Now set all flags
  73. Set("test_bool", "true")
  74. Set("test_int", "1")
  75. Set("test_int64", "1")
  76. Set("test_uint", "1")
  77. Set("test_uint64", "1")
  78. Set("test_string", "1")
  79. Set("test_float64", "1")
  80. Set("test_duration", "1s")
  81. Set("test_optional_int", "1")
  82. desired = "1"
  83. Visit(visitor)
  84. if len(m) != 9 {
  85. t.Error("Visit fails after set")
  86. for k, v := range m {
  87. t.Log(k, *v)
  88. }
  89. }
  90. // Now test they're visited in sort order.
  91. var flagNames []string
  92. Visit(func(f *Flag) { flagNames = append(flagNames, f.Name) })
  93. if !sort.StringsAreSorted(flagNames) {
  94. t.Errorf("flag names not sorted: %v", flagNames)
  95. }
  96. }
  97. func TestUsage(t *testing.T) {
  98. called := false
  99. ResetForTesting(func() { called = true })
  100. if GetCommandLine().Parse([]string{"--x"}) == nil {
  101. t.Error("parse did not fail for unknown flag")
  102. }
  103. if !called {
  104. t.Error("did not call Usage for unknown flag")
  105. }
  106. }
  107. func TestAddFlagSet(t *testing.T) {
  108. oldSet := NewFlagSet("old", ContinueOnError)
  109. newSet := NewFlagSet("new", ContinueOnError)
  110. oldSet.String("flag1", "flag1", "flag1")
  111. oldSet.String("flag2", "flag2", "flag2")
  112. newSet.String("flag2", "flag2", "flag2")
  113. newSet.String("flag3", "flag3", "flag3")
  114. oldSet.AddFlagSet(newSet)
  115. if len(oldSet.formal) != 3 {
  116. t.Errorf("Unexpected result adding a FlagSet to a FlagSet %v", oldSet)
  117. }
  118. }
  119. func TestAnnotation(t *testing.T) {
  120. f := NewFlagSet("shorthand", ContinueOnError)
  121. if err := f.SetAnnotation("missing-flag", "key", nil); err == nil {
  122. t.Errorf("Expected error setting annotation on non-existent flag")
  123. }
  124. f.StringP("stringa", "a", "", "string value")
  125. if err := f.SetAnnotation("stringa", "key", nil); err != nil {
  126. t.Errorf("Unexpected error setting new nil annotation: %v", err)
  127. }
  128. if annotation := f.Lookup("stringa").Annotations["key"]; annotation != nil {
  129. t.Errorf("Unexpected annotation: %v", annotation)
  130. }
  131. f.StringP("stringb", "b", "", "string2 value")
  132. if err := f.SetAnnotation("stringb", "key", []string{"value1"}); err != nil {
  133. t.Errorf("Unexpected error setting new annotation: %v", err)
  134. }
  135. if annotation := f.Lookup("stringb").Annotations["key"]; !reflect.DeepEqual(annotation, []string{"value1"}) {
  136. t.Errorf("Unexpected annotation: %v", annotation)
  137. }
  138. if err := f.SetAnnotation("stringb", "key", []string{"value2"}); err != nil {
  139. t.Errorf("Unexpected error updating annotation: %v", err)
  140. }
  141. if annotation := f.Lookup("stringb").Annotations["key"]; !reflect.DeepEqual(annotation, []string{"value2"}) {
  142. t.Errorf("Unexpected annotation: %v", annotation)
  143. }
  144. }
  145. func testParse(f *FlagSet, t *testing.T) {
  146. if f.Parsed() {
  147. t.Error("f.Parse() = true before Parse")
  148. }
  149. boolFlag := f.Bool("bool", false, "bool value")
  150. bool2Flag := f.Bool("bool2", false, "bool2 value")
  151. bool3Flag := f.Bool("bool3", false, "bool3 value")
  152. intFlag := f.Int("int", 0, "int value")
  153. int8Flag := f.Int8("int8", 0, "int value")
  154. int32Flag := f.Int32("int32", 0, "int value")
  155. int64Flag := f.Int64("int64", 0, "int64 value")
  156. uintFlag := f.Uint("uint", 0, "uint value")
  157. uint8Flag := f.Uint8("uint8", 0, "uint value")
  158. uint16Flag := f.Uint16("uint16", 0, "uint value")
  159. uint32Flag := f.Uint32("uint32", 0, "uint value")
  160. uint64Flag := f.Uint64("uint64", 0, "uint64 value")
  161. stringFlag := f.String("string", "0", "string value")
  162. float32Flag := f.Float32("float32", 0, "float32 value")
  163. float64Flag := f.Float64("float64", 0, "float64 value")
  164. ipFlag := f.IP("ip", net.ParseIP("127.0.0.1"), "ip value")
  165. maskFlag := f.IPMask("mask", ParseIPv4Mask("0.0.0.0"), "mask value")
  166. durationFlag := f.Duration("duration", 5*time.Second, "time.Duration value")
  167. optionalIntNoValueFlag := f.Int("optional-int-no-value", 0, "int value")
  168. f.Lookup("optional-int-no-value").NoOptDefVal = "9"
  169. optionalIntWithValueFlag := f.Int("optional-int-with-value", 0, "int value")
  170. f.Lookup("optional-int-no-value").NoOptDefVal = "9"
  171. extra := "one-extra-argument"
  172. args := []string{
  173. "--bool",
  174. "--bool2=true",
  175. "--bool3=false",
  176. "--int=22",
  177. "--int8=-8",
  178. "--int32=-32",
  179. "--int64=0x23",
  180. "--uint", "24",
  181. "--uint8=8",
  182. "--uint16=16",
  183. "--uint32=32",
  184. "--uint64=25",
  185. "--string=hello",
  186. "--float32=-172e12",
  187. "--float64=2718e28",
  188. "--ip=10.11.12.13",
  189. "--mask=255.255.255.0",
  190. "--duration=2m",
  191. "--optional-int-no-value",
  192. "--optional-int-with-value=42",
  193. extra,
  194. }
  195. if err := f.Parse(args); err != nil {
  196. t.Fatal(err)
  197. }
  198. if !f.Parsed() {
  199. t.Error("f.Parse() = false after Parse")
  200. }
  201. if *boolFlag != true {
  202. t.Error("bool flag should be true, is ", *boolFlag)
  203. }
  204. if v, err := f.GetBool("bool"); err != nil || v != *boolFlag {
  205. t.Error("GetBool does not work.")
  206. }
  207. if *bool2Flag != true {
  208. t.Error("bool2 flag should be true, is ", *bool2Flag)
  209. }
  210. if *bool3Flag != false {
  211. t.Error("bool3 flag should be false, is ", *bool2Flag)
  212. }
  213. if *intFlag != 22 {
  214. t.Error("int flag should be 22, is ", *intFlag)
  215. }
  216. if v, err := f.GetInt("int"); err != nil || v != *intFlag {
  217. t.Error("GetInt does not work.")
  218. }
  219. if *int8Flag != -8 {
  220. t.Error("int8 flag should be 0x23, is ", *int8Flag)
  221. }
  222. if v, err := f.GetInt8("int8"); err != nil || v != *int8Flag {
  223. t.Error("GetInt8 does not work.")
  224. }
  225. if *int32Flag != -32 {
  226. t.Error("int32 flag should be 0x23, is ", *int32Flag)
  227. }
  228. if v, err := f.GetInt32("int32"); err != nil || v != *int32Flag {
  229. t.Error("GetInt32 does not work.")
  230. }
  231. if *int64Flag != 0x23 {
  232. t.Error("int64 flag should be 0x23, is ", *int64Flag)
  233. }
  234. if v, err := f.GetInt64("int64"); err != nil || v != *int64Flag {
  235. t.Error("GetInt64 does not work.")
  236. }
  237. if *uintFlag != 24 {
  238. t.Error("uint flag should be 24, is ", *uintFlag)
  239. }
  240. if v, err := f.GetUint("uint"); err != nil || v != *uintFlag {
  241. t.Error("GetUint does not work.")
  242. }
  243. if *uint8Flag != 8 {
  244. t.Error("uint8 flag should be 8, is ", *uint8Flag)
  245. }
  246. if v, err := f.GetUint8("uint8"); err != nil || v != *uint8Flag {
  247. t.Error("GetUint8 does not work.")
  248. }
  249. if *uint16Flag != 16 {
  250. t.Error("uint16 flag should be 16, is ", *uint16Flag)
  251. }
  252. if v, err := f.GetUint16("uint16"); err != nil || v != *uint16Flag {
  253. t.Error("GetUint16 does not work.")
  254. }
  255. if *uint32Flag != 32 {
  256. t.Error("uint32 flag should be 32, is ", *uint32Flag)
  257. }
  258. if v, err := f.GetUint32("uint32"); err != nil || v != *uint32Flag {
  259. t.Error("GetUint32 does not work.")
  260. }
  261. if *uint64Flag != 25 {
  262. t.Error("uint64 flag should be 25, is ", *uint64Flag)
  263. }
  264. if v, err := f.GetUint64("uint64"); err != nil || v != *uint64Flag {
  265. t.Error("GetUint64 does not work.")
  266. }
  267. if *stringFlag != "hello" {
  268. t.Error("string flag should be `hello`, is ", *stringFlag)
  269. }
  270. if v, err := f.GetString("string"); err != nil || v != *stringFlag {
  271. t.Error("GetString does not work.")
  272. }
  273. if *float32Flag != -172e12 {
  274. t.Error("float32 flag should be -172e12, is ", *float32Flag)
  275. }
  276. if v, err := f.GetFloat32("float32"); err != nil || v != *float32Flag {
  277. t.Errorf("GetFloat32 returned %v but float32Flag was %v", v, *float32Flag)
  278. }
  279. if *float64Flag != 2718e28 {
  280. t.Error("float64 flag should be 2718e28, is ", *float64Flag)
  281. }
  282. if v, err := f.GetFloat64("float64"); err != nil || v != *float64Flag {
  283. t.Errorf("GetFloat64 returned %v but float64Flag was %v", v, *float64Flag)
  284. }
  285. if !(*ipFlag).Equal(net.ParseIP("10.11.12.13")) {
  286. t.Error("ip flag should be 10.11.12.13, is ", *ipFlag)
  287. }
  288. if v, err := f.GetIP("ip"); err != nil || !v.Equal(*ipFlag) {
  289. t.Errorf("GetIP returned %v but ipFlag was %v", v, *ipFlag)
  290. }
  291. if (*maskFlag).String() != ParseIPv4Mask("255.255.255.0").String() {
  292. t.Error("mask flag should be 255.255.255.0, is ", (*maskFlag).String())
  293. }
  294. if v, err := f.GetIPv4Mask("mask"); err != nil || v.String() != (*maskFlag).String() {
  295. t.Errorf("GetIP returned %v maskFlag was %v error was %v", v, *maskFlag, err)
  296. }
  297. if *durationFlag != 2*time.Minute {
  298. t.Error("duration flag should be 2m, is ", *durationFlag)
  299. }
  300. if v, err := f.GetDuration("duration"); err != nil || v != *durationFlag {
  301. t.Error("GetDuration does not work.")
  302. }
  303. if _, err := f.GetInt("duration"); err == nil {
  304. t.Error("GetInt parsed a time.Duration?!?!")
  305. }
  306. if *optionalIntNoValueFlag != 9 {
  307. t.Error("optional int flag should be the default value, is ", *optionalIntNoValueFlag)
  308. }
  309. if *optionalIntWithValueFlag != 42 {
  310. t.Error("optional int flag should be 42, is ", *optionalIntWithValueFlag)
  311. }
  312. if len(f.Args()) != 1 {
  313. t.Error("expected one argument, got", len(f.Args()))
  314. } else if f.Args()[0] != extra {
  315. t.Errorf("expected argument %q got %q", extra, f.Args()[0])
  316. }
  317. }
  318. func TestShorthand(t *testing.T) {
  319. f := NewFlagSet("shorthand", ContinueOnError)
  320. if f.Parsed() {
  321. t.Error("f.Parse() = true before Parse")
  322. }
  323. boolaFlag := f.BoolP("boola", "a", false, "bool value")
  324. boolbFlag := f.BoolP("boolb", "b", false, "bool2 value")
  325. boolcFlag := f.BoolP("boolc", "c", false, "bool3 value")
  326. booldFlag := f.BoolP("boold", "d", false, "bool4 value")
  327. stringaFlag := f.StringP("stringa", "s", "0", "string value")
  328. stringzFlag := f.StringP("stringz", "z", "0", "string value")
  329. extra := "interspersed-argument"
  330. notaflag := "--i-look-like-a-flag"
  331. args := []string{
  332. "-ab",
  333. extra,
  334. "-cs",
  335. "hello",
  336. "-z=something",
  337. "-d=true",
  338. "--",
  339. notaflag,
  340. }
  341. f.SetOutput(ioutil.Discard)
  342. if err := f.Parse(args); err != nil {
  343. t.Error("expected no error, got ", err)
  344. }
  345. if !f.Parsed() {
  346. t.Error("f.Parse() = false after Parse")
  347. }
  348. if *boolaFlag != true {
  349. t.Error("boola flag should be true, is ", *boolaFlag)
  350. }
  351. if *boolbFlag != true {
  352. t.Error("boolb flag should be true, is ", *boolbFlag)
  353. }
  354. if *boolcFlag != true {
  355. t.Error("boolc flag should be true, is ", *boolcFlag)
  356. }
  357. if *booldFlag != true {
  358. t.Error("boold flag should be true, is ", *booldFlag)
  359. }
  360. if *stringaFlag != "hello" {
  361. t.Error("stringa flag should be `hello`, is ", *stringaFlag)
  362. }
  363. if *stringzFlag != "something" {
  364. t.Error("stringz flag should be `something`, is ", *stringzFlag)
  365. }
  366. if len(f.Args()) != 2 {
  367. t.Error("expected one argument, got", len(f.Args()))
  368. } else if f.Args()[0] != extra {
  369. t.Errorf("expected argument %q got %q", extra, f.Args()[0])
  370. } else if f.Args()[1] != notaflag {
  371. t.Errorf("expected argument %q got %q", notaflag, f.Args()[1])
  372. }
  373. if f.ArgsLenAtDash() != 1 {
  374. t.Errorf("expected argsLenAtDash %d got %d", f.ArgsLenAtDash(), 1)
  375. }
  376. }
  377. func TestParse(t *testing.T) {
  378. ResetForTesting(func() { t.Error("bad parse") })
  379. testParse(GetCommandLine(), t)
  380. }
  381. func TestFlagSetParse(t *testing.T) {
  382. testParse(NewFlagSet("test", ContinueOnError), t)
  383. }
  384. func TestChangedHelper(t *testing.T) {
  385. f := NewFlagSet("changedtest", ContinueOnError)
  386. _ = f.Bool("changed", false, "changed bool")
  387. _ = f.Bool("settrue", true, "true to true")
  388. _ = f.Bool("setfalse", false, "false to false")
  389. _ = f.Bool("unchanged", false, "unchanged bool")
  390. args := []string{"--changed", "--settrue", "--setfalse=false"}
  391. if err := f.Parse(args); err != nil {
  392. t.Error("f.Parse() = false after Parse")
  393. }
  394. if !f.Changed("changed") {
  395. t.Errorf("--changed wasn't changed!")
  396. }
  397. if !f.Changed("settrue") {
  398. t.Errorf("--settrue wasn't changed!")
  399. }
  400. if !f.Changed("setfalse") {
  401. t.Errorf("--setfalse wasn't changed!")
  402. }
  403. if f.Changed("unchanged") {
  404. t.Errorf("--unchanged was changed!")
  405. }
  406. if f.Changed("invalid") {
  407. t.Errorf("--invalid was changed!")
  408. }
  409. if f.ArgsLenAtDash() != -1 {
  410. t.Errorf("Expected argsLenAtDash: %d but got %d", -1, f.ArgsLenAtDash())
  411. }
  412. }
  413. func replaceSeparators(name string, from []string, to string) string {
  414. result := name
  415. for _, sep := range from {
  416. result = strings.Replace(result, sep, to, -1)
  417. }
  418. // Type convert to indicate normalization has been done.
  419. return result
  420. }
  421. func wordSepNormalizeFunc(f *FlagSet, name string) NormalizedName {
  422. seps := []string{"-", "_"}
  423. name = replaceSeparators(name, seps, ".")
  424. normalizeFlagNameInvocations++
  425. return NormalizedName(name)
  426. }
  427. func testWordSepNormalizedNames(args []string, t *testing.T) {
  428. f := NewFlagSet("normalized", ContinueOnError)
  429. if f.Parsed() {
  430. t.Error("f.Parse() = true before Parse")
  431. }
  432. withDashFlag := f.Bool("with-dash-flag", false, "bool value")
  433. // Set this after some flags have been added and before others.
  434. f.SetNormalizeFunc(wordSepNormalizeFunc)
  435. withUnderFlag := f.Bool("with_under_flag", false, "bool value")
  436. withBothFlag := f.Bool("with-both_flag", false, "bool value")
  437. if err := f.Parse(args); err != nil {
  438. t.Fatal(err)
  439. }
  440. if !f.Parsed() {
  441. t.Error("f.Parse() = false after Parse")
  442. }
  443. if *withDashFlag != true {
  444. t.Error("withDashFlag flag should be true, is ", *withDashFlag)
  445. }
  446. if *withUnderFlag != true {
  447. t.Error("withUnderFlag flag should be true, is ", *withUnderFlag)
  448. }
  449. if *withBothFlag != true {
  450. t.Error("withBothFlag flag should be true, is ", *withBothFlag)
  451. }
  452. }
  453. func TestWordSepNormalizedNames(t *testing.T) {
  454. args := []string{
  455. "--with-dash-flag",
  456. "--with-under-flag",
  457. "--with-both-flag",
  458. }
  459. testWordSepNormalizedNames(args, t)
  460. args = []string{
  461. "--with_dash_flag",
  462. "--with_under_flag",
  463. "--with_both_flag",
  464. }
  465. testWordSepNormalizedNames(args, t)
  466. args = []string{
  467. "--with-dash_flag",
  468. "--with-under_flag",
  469. "--with-both_flag",
  470. }
  471. testWordSepNormalizedNames(args, t)
  472. }
  473. func aliasAndWordSepFlagNames(f *FlagSet, name string) NormalizedName {
  474. seps := []string{"-", "_"}
  475. oldName := replaceSeparators("old-valid_flag", seps, ".")
  476. newName := replaceSeparators("valid-flag", seps, ".")
  477. name = replaceSeparators(name, seps, ".")
  478. switch name {
  479. case oldName:
  480. name = newName
  481. break
  482. }
  483. return NormalizedName(name)
  484. }
  485. func TestCustomNormalizedNames(t *testing.T) {
  486. f := NewFlagSet("normalized", ContinueOnError)
  487. if f.Parsed() {
  488. t.Error("f.Parse() = true before Parse")
  489. }
  490. validFlag := f.Bool("valid-flag", false, "bool value")
  491. f.SetNormalizeFunc(aliasAndWordSepFlagNames)
  492. someOtherFlag := f.Bool("some-other-flag", false, "bool value")
  493. args := []string{"--old_valid_flag", "--some-other_flag"}
  494. if err := f.Parse(args); err != nil {
  495. t.Fatal(err)
  496. }
  497. if *validFlag != true {
  498. t.Errorf("validFlag is %v even though we set the alias --old_valid_falg", *validFlag)
  499. }
  500. if *someOtherFlag != true {
  501. t.Error("someOtherFlag should be true, is ", *someOtherFlag)
  502. }
  503. }
  504. // Every flag we add, the name (displayed also in usage) should normalized
  505. func TestNormalizationFuncShouldChangeFlagName(t *testing.T) {
  506. // Test normalization after addition
  507. f := NewFlagSet("normalized", ContinueOnError)
  508. f.Bool("valid_flag", false, "bool value")
  509. if f.Lookup("valid_flag").Name != "valid_flag" {
  510. t.Error("The new flag should have the name 'valid_flag' instead of ", f.Lookup("valid_flag").Name)
  511. }
  512. f.SetNormalizeFunc(wordSepNormalizeFunc)
  513. if f.Lookup("valid_flag").Name != "valid.flag" {
  514. t.Error("The new flag should have the name 'valid.flag' instead of ", f.Lookup("valid_flag").Name)
  515. }
  516. // Test normalization before addition
  517. f = NewFlagSet("normalized", ContinueOnError)
  518. f.SetNormalizeFunc(wordSepNormalizeFunc)
  519. f.Bool("valid_flag", false, "bool value")
  520. if f.Lookup("valid_flag").Name != "valid.flag" {
  521. t.Error("The new flag should have the name 'valid.flag' instead of ", f.Lookup("valid_flag").Name)
  522. }
  523. }
  524. // Declare a user-defined flag type.
  525. type flagVar []string
  526. func (f *flagVar) String() string {
  527. return fmt.Sprint([]string(*f))
  528. }
  529. func (f *flagVar) Set(value string) error {
  530. *f = append(*f, value)
  531. return nil
  532. }
  533. func (f *flagVar) Type() string {
  534. return "flagVar"
  535. }
  536. func TestUserDefined(t *testing.T) {
  537. var flags FlagSet
  538. flags.Init("test", ContinueOnError)
  539. var v flagVar
  540. flags.VarP(&v, "v", "v", "usage")
  541. if err := flags.Parse([]string{"--v=1", "-v2", "-v", "3"}); err != nil {
  542. t.Error(err)
  543. }
  544. if len(v) != 3 {
  545. t.Fatal("expected 3 args; got ", len(v))
  546. }
  547. expect := "[1 2 3]"
  548. if v.String() != expect {
  549. t.Errorf("expected value %q got %q", expect, v.String())
  550. }
  551. }
  552. func TestSetOutput(t *testing.T) {
  553. var flags FlagSet
  554. var buf bytes.Buffer
  555. flags.SetOutput(&buf)
  556. flags.Init("test", ContinueOnError)
  557. flags.Parse([]string{"--unknown"})
  558. if out := buf.String(); !strings.Contains(out, "--unknown") {
  559. t.Logf("expected output mentioning unknown; got %q", out)
  560. }
  561. }
  562. // This tests that one can reset the flags. This still works but not well, and is
  563. // superseded by FlagSet.
  564. func TestChangingArgs(t *testing.T) {
  565. ResetForTesting(func() { t.Fatal("bad parse") })
  566. oldArgs := os.Args
  567. defer func() { os.Args = oldArgs }()
  568. os.Args = []string{"cmd", "--before", "subcmd"}
  569. before := Bool("before", false, "")
  570. if err := GetCommandLine().Parse(os.Args[1:]); err != nil {
  571. t.Fatal(err)
  572. }
  573. cmd := Arg(0)
  574. os.Args = []string{"subcmd", "--after", "args"}
  575. after := Bool("after", false, "")
  576. Parse()
  577. args := Args()
  578. if !*before || cmd != "subcmd" || !*after || len(args) != 1 || args[0] != "args" {
  579. t.Fatalf("expected true subcmd true [args] got %v %v %v %v", *before, cmd, *after, args)
  580. }
  581. }
  582. // Test that -help invokes the usage message and returns ErrHelp.
  583. func TestHelp(t *testing.T) {
  584. var helpCalled = false
  585. fs := NewFlagSet("help test", ContinueOnError)
  586. fs.Usage = func() { helpCalled = true }
  587. var flag bool
  588. fs.BoolVar(&flag, "flag", false, "regular flag")
  589. // Regular flag invocation should work
  590. err := fs.Parse([]string{"--flag=true"})
  591. if err != nil {
  592. t.Fatal("expected no error; got ", err)
  593. }
  594. if !flag {
  595. t.Error("flag was not set by --flag")
  596. }
  597. if helpCalled {
  598. t.Error("help called for regular flag")
  599. helpCalled = false // reset for next test
  600. }
  601. // Help flag should work as expected.
  602. err = fs.Parse([]string{"--help"})
  603. if err == nil {
  604. t.Fatal("error expected")
  605. }
  606. if err != ErrHelp {
  607. t.Fatal("expected ErrHelp; got ", err)
  608. }
  609. if !helpCalled {
  610. t.Fatal("help was not called")
  611. }
  612. // If we define a help flag, that should override.
  613. var help bool
  614. fs.BoolVar(&help, "help", false, "help flag")
  615. helpCalled = false
  616. err = fs.Parse([]string{"--help"})
  617. if err != nil {
  618. t.Fatal("expected no error for defined --help; got ", err)
  619. }
  620. if helpCalled {
  621. t.Fatal("help was called; should not have been for defined help flag")
  622. }
  623. }
  624. func TestNoInterspersed(t *testing.T) {
  625. f := NewFlagSet("test", ContinueOnError)
  626. f.SetInterspersed(false)
  627. f.Bool("true", true, "always true")
  628. f.Bool("false", false, "always false")
  629. err := f.Parse([]string{"--true", "break", "--false"})
  630. if err != nil {
  631. t.Fatal("expected no error; got ", err)
  632. }
  633. args := f.Args()
  634. if len(args) != 2 || args[0] != "break" || args[1] != "--false" {
  635. t.Fatal("expected interspersed options/non-options to fail")
  636. }
  637. }
  638. func TestTermination(t *testing.T) {
  639. f := NewFlagSet("termination", ContinueOnError)
  640. boolFlag := f.BoolP("bool", "l", false, "bool value")
  641. if f.Parsed() {
  642. t.Error("f.Parse() = true before Parse")
  643. }
  644. arg1 := "ls"
  645. arg2 := "-l"
  646. args := []string{
  647. "--",
  648. arg1,
  649. arg2,
  650. }
  651. f.SetOutput(ioutil.Discard)
  652. if err := f.Parse(args); err != nil {
  653. t.Fatal("expected no error; got ", err)
  654. }
  655. if !f.Parsed() {
  656. t.Error("f.Parse() = false after Parse")
  657. }
  658. if *boolFlag {
  659. t.Error("expected boolFlag=false, got true")
  660. }
  661. if len(f.Args()) != 2 {
  662. t.Errorf("expected 2 arguments, got %d: %v", len(f.Args()), f.Args())
  663. }
  664. if f.Args()[0] != arg1 {
  665. t.Errorf("expected argument %q got %q", arg1, f.Args()[0])
  666. }
  667. if f.Args()[1] != arg2 {
  668. t.Errorf("expected argument %q got %q", arg2, f.Args()[1])
  669. }
  670. if f.ArgsLenAtDash() != 0 {
  671. t.Errorf("expected argsLenAtDash %d got %d", 0, f.ArgsLenAtDash())
  672. }
  673. }
  674. func TestDeprecatedFlagInDocs(t *testing.T) {
  675. f := NewFlagSet("bob", ContinueOnError)
  676. f.Bool("badflag", true, "always true")
  677. f.MarkDeprecated("badflag", "use --good-flag instead")
  678. out := new(bytes.Buffer)
  679. f.SetOutput(out)
  680. f.PrintDefaults()
  681. if strings.Contains(out.String(), "badflag") {
  682. t.Errorf("found deprecated flag in usage!")
  683. }
  684. }
  685. func TestDeprecatedFlagShorthandInDocs(t *testing.T) {
  686. f := NewFlagSet("bob", ContinueOnError)
  687. name := "noshorthandflag"
  688. f.BoolP(name, "n", true, "always true")
  689. f.MarkShorthandDeprecated("noshorthandflag", fmt.Sprintf("use --%s instead", name))
  690. out := new(bytes.Buffer)
  691. f.SetOutput(out)
  692. f.PrintDefaults()
  693. if strings.Contains(out.String(), "-n,") {
  694. t.Errorf("found deprecated flag shorthand in usage!")
  695. }
  696. }
  697. func parseReturnStderr(t *testing.T, f *FlagSet, args []string) (string, error) {
  698. oldStderr := os.Stderr
  699. r, w, _ := os.Pipe()
  700. os.Stderr = w
  701. err := f.Parse(args)
  702. outC := make(chan string)
  703. // copy the output in a separate goroutine so printing can't block indefinitely
  704. go func() {
  705. var buf bytes.Buffer
  706. io.Copy(&buf, r)
  707. outC <- buf.String()
  708. }()
  709. w.Close()
  710. os.Stderr = oldStderr
  711. out := <-outC
  712. return out, err
  713. }
  714. func TestDeprecatedFlagUsage(t *testing.T) {
  715. f := NewFlagSet("bob", ContinueOnError)
  716. f.Bool("badflag", true, "always true")
  717. usageMsg := "use --good-flag instead"
  718. f.MarkDeprecated("badflag", usageMsg)
  719. args := []string{"--badflag"}
  720. out, err := parseReturnStderr(t, f, args)
  721. if err != nil {
  722. t.Fatal("expected no error; got ", err)
  723. }
  724. if !strings.Contains(out, usageMsg) {
  725. t.Errorf("usageMsg not printed when using a deprecated flag!")
  726. }
  727. }
  728. func TestDeprecatedFlagShorthandUsage(t *testing.T) {
  729. f := NewFlagSet("bob", ContinueOnError)
  730. name := "noshorthandflag"
  731. f.BoolP(name, "n", true, "always true")
  732. usageMsg := fmt.Sprintf("use --%s instead", name)
  733. f.MarkShorthandDeprecated(name, usageMsg)
  734. args := []string{"-n"}
  735. out, err := parseReturnStderr(t, f, args)
  736. if err != nil {
  737. t.Fatal("expected no error; got ", err)
  738. }
  739. if !strings.Contains(out, usageMsg) {
  740. t.Errorf("usageMsg not printed when using a deprecated flag!")
  741. }
  742. }
  743. func TestDeprecatedFlagUsageNormalized(t *testing.T) {
  744. f := NewFlagSet("bob", ContinueOnError)
  745. f.Bool("bad-double_flag", true, "always true")
  746. f.SetNormalizeFunc(wordSepNormalizeFunc)
  747. usageMsg := "use --good-flag instead"
  748. f.MarkDeprecated("bad_double-flag", usageMsg)
  749. args := []string{"--bad_double_flag"}
  750. out, err := parseReturnStderr(t, f, args)
  751. if err != nil {
  752. t.Fatal("expected no error; got ", err)
  753. }
  754. if !strings.Contains(out, usageMsg) {
  755. t.Errorf("usageMsg not printed when using a deprecated flag!")
  756. }
  757. }
  758. // Name normalization function should be called only once on flag addition
  759. func TestMultipleNormalizeFlagNameInvocations(t *testing.T) {
  760. normalizeFlagNameInvocations = 0
  761. f := NewFlagSet("normalized", ContinueOnError)
  762. f.SetNormalizeFunc(wordSepNormalizeFunc)
  763. f.Bool("with_under_flag", false, "bool value")
  764. if normalizeFlagNameInvocations != 1 {
  765. t.Fatal("Expected normalizeFlagNameInvocations to be 1; got ", normalizeFlagNameInvocations)
  766. }
  767. }
  768. //
  769. func TestHiddenFlagInUsage(t *testing.T) {
  770. f := NewFlagSet("bob", ContinueOnError)
  771. f.Bool("secretFlag", true, "shhh")
  772. f.MarkHidden("secretFlag")
  773. out := new(bytes.Buffer)
  774. f.SetOutput(out)
  775. f.PrintDefaults()
  776. if strings.Contains(out.String(), "secretFlag") {
  777. t.Errorf("found hidden flag in usage!")
  778. }
  779. }
  780. //
  781. func TestHiddenFlagUsage(t *testing.T) {
  782. f := NewFlagSet("bob", ContinueOnError)
  783. f.Bool("secretFlag", true, "shhh")
  784. f.MarkHidden("secretFlag")
  785. args := []string{"--secretFlag"}
  786. out, err := parseReturnStderr(t, f, args)
  787. if err != nil {
  788. t.Fatal("expected no error; got ", err)
  789. }
  790. if strings.Contains(out, "shhh") {
  791. t.Errorf("usage message printed when using a hidden flag!")
  792. }
  793. }
  794. const defaultOutput = ` --A for bootstrapping, allow 'any' type
  795. --Alongflagname disable bounds checking
  796. -C, --CCC a boolean defaulting to true (default true)
  797. --D path set relative path for local imports
  798. --F number a non-zero number (default 2.7)
  799. --G float a float that defaults to zero
  800. --IP ip IP address with no default
  801. --IPMask ipMask Netmask address with no default
  802. --IPNet ipNet IP network with no default
  803. --Ints intSlice int slice with zero default
  804. --N int a non-zero int (default 27)
  805. --ND1 string[="bar"] a string with NoOptDefVal (default "foo")
  806. --ND2 num[=4321] a num with NoOptDefVal (default 1234)
  807. --StringArray stringArray string array with zero default
  808. --StringSlice stringSlice string slice with zero default
  809. --Z int an int that defaults to zero
  810. --custom custom custom Value implementation
  811. --maxT timeout set timeout for dial
  812. `
  813. // Custom value that satisfies the Value interface.
  814. type customValue int
  815. func (cv *customValue) String() string { return fmt.Sprintf("%v", *cv) }
  816. func (cv *customValue) Set(s string) error {
  817. v, err := strconv.ParseInt(s, 0, 64)
  818. *cv = customValue(v)
  819. return err
  820. }
  821. func (cv *customValue) Type() string { return "custom" }
  822. func TestPrintDefaults(t *testing.T) {
  823. fs := NewFlagSet("print defaults test", ContinueOnError)
  824. var buf bytes.Buffer
  825. fs.SetOutput(&buf)
  826. fs.Bool("A", false, "for bootstrapping, allow 'any' type")
  827. fs.Bool("Alongflagname", false, "disable bounds checking")
  828. fs.BoolP("CCC", "C", true, "a boolean defaulting to true")
  829. fs.String("D", "", "set relative `path` for local imports")
  830. fs.Float64("F", 2.7, "a non-zero `number`")
  831. fs.Float64("G", 0, "a float that defaults to zero")
  832. fs.Int("N", 27, "a non-zero int")
  833. fs.IntSlice("Ints", []int{}, "int slice with zero default")
  834. fs.IP("IP", nil, "IP address with no default")
  835. fs.IPMask("IPMask", nil, "Netmask address with no default")
  836. fs.IPNet("IPNet", net.IPNet{}, "IP network with no default")
  837. fs.Int("Z", 0, "an int that defaults to zero")
  838. fs.Duration("maxT", 0, "set `timeout` for dial")
  839. fs.String("ND1", "foo", "a string with NoOptDefVal")
  840. fs.Lookup("ND1").NoOptDefVal = "bar"
  841. fs.Int("ND2", 1234, "a `num` with NoOptDefVal")
  842. fs.Lookup("ND2").NoOptDefVal = "4321"
  843. fs.StringSlice("StringSlice", []string{}, "string slice with zero default")
  844. fs.StringArray("StringArray", []string{}, "string array with zero default")
  845. var cv customValue
  846. fs.Var(&cv, "custom", "custom Value implementation")
  847. fs.PrintDefaults()
  848. got := buf.String()
  849. if got != defaultOutput {
  850. fmt.Println("\n" + got)
  851. fmt.Println("\n" + defaultOutput)
  852. t.Errorf("got %q want %q\n", got, defaultOutput)
  853. }
  854. }