You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

1204 lines
31 KiB

  1. package cli
  2. import (
  3. "fmt"
  4. "os"
  5. "reflect"
  6. "runtime"
  7. "strings"
  8. "testing"
  9. "time"
  10. )
  11. var boolFlagTests = []struct {
  12. name string
  13. expected string
  14. }{
  15. {"help", "--help\t"},
  16. {"h", "-h\t"},
  17. }
  18. func TestBoolFlagHelpOutput(t *testing.T) {
  19. for _, test := range boolFlagTests {
  20. flag := BoolFlag{Name: test.name}
  21. output := flag.String()
  22. if output != test.expected {
  23. t.Errorf("%q does not match %q", output, test.expected)
  24. }
  25. }
  26. }
  27. func TestFlagsFromEnv(t *testing.T) {
  28. var flagTests = []struct {
  29. input string
  30. output interface{}
  31. flag Flag
  32. err error
  33. }{
  34. {"", false, BoolFlag{Name: "debug", EnvVar: "DEBUG"}, nil},
  35. {"1", true, BoolFlag{Name: "debug", EnvVar: "DEBUG"}, nil},
  36. {"false", false, BoolFlag{Name: "debug", EnvVar: "DEBUG"}, nil},
  37. {"foobar", true, BoolFlag{Name: "debug", EnvVar: "DEBUG"}, fmt.Errorf(`could not parse foobar as bool value for flag debug: strconv.ParseBool: parsing "foobar": invalid syntax`)},
  38. {"", false, BoolTFlag{Name: "debug", EnvVar: "DEBUG"}, nil},
  39. {"1", true, BoolTFlag{Name: "debug", EnvVar: "DEBUG"}, nil},
  40. {"false", false, BoolTFlag{Name: "debug", EnvVar: "DEBUG"}, nil},
  41. {"foobar", true, BoolTFlag{Name: "debug", EnvVar: "DEBUG"}, fmt.Errorf(`could not parse foobar as bool value for flag debug: strconv.ParseBool: parsing "foobar": invalid syntax`)},
  42. {"1s", 1 * time.Second, DurationFlag{Name: "time", EnvVar: "TIME"}, nil},
  43. {"foobar", false, DurationFlag{Name: "time", EnvVar: "TIME"}, fmt.Errorf(`could not parse foobar as duration for flag time: time: invalid duration foobar`)},
  44. {"1.2", 1.2, Float64Flag{Name: "seconds", EnvVar: "SECONDS"}, nil},
  45. {"1", 1.0, Float64Flag{Name: "seconds", EnvVar: "SECONDS"}, nil},
  46. {"foobar", 0, Float64Flag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Errorf(`could not parse foobar as float64 value for flag seconds: strconv.ParseFloat: parsing "foobar": invalid syntax`)},
  47. {"1", int64(1), Int64Flag{Name: "seconds", EnvVar: "SECONDS"}, nil},
  48. {"1.2", 0, Int64Flag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Errorf(`could not parse 1.2 as int value for flag seconds: strconv.ParseInt: parsing "1.2": invalid syntax`)},
  49. {"foobar", 0, Int64Flag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Errorf(`could not parse foobar as int value for flag seconds: strconv.ParseInt: parsing "foobar": invalid syntax`)},
  50. {"1", 1, IntFlag{Name: "seconds", EnvVar: "SECONDS"}, nil},
  51. {"1.2", 0, IntFlag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Errorf(`could not parse 1.2 as int value for flag seconds: strconv.ParseInt: parsing "1.2": invalid syntax`)},
  52. {"foobar", 0, IntFlag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Errorf(`could not parse foobar as int value for flag seconds: strconv.ParseInt: parsing "foobar": invalid syntax`)},
  53. {"1,2", IntSlice{1, 2}, IntSliceFlag{Name: "seconds", EnvVar: "SECONDS"}, nil},
  54. {"1.2,2", IntSlice{}, IntSliceFlag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Errorf(`could not parse 1.2,2 as int slice value for flag seconds: strconv.ParseInt: parsing "1.2": invalid syntax`)},
  55. {"foobar", IntSlice{}, IntSliceFlag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Errorf(`could not parse foobar as int slice value for flag seconds: strconv.ParseInt: parsing "foobar": invalid syntax`)},
  56. {"1,2", Int64Slice{1, 2}, Int64SliceFlag{Name: "seconds", EnvVar: "SECONDS"}, nil},
  57. {"1.2,2", Int64Slice{}, Int64SliceFlag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Errorf(`could not parse 1.2,2 as int64 slice value for flag seconds: strconv.ParseInt: parsing "1.2": invalid syntax`)},
  58. {"foobar", Int64Slice{}, Int64SliceFlag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Errorf(`could not parse foobar as int64 slice value for flag seconds: strconv.ParseInt: parsing "foobar": invalid syntax`)},
  59. {"foo", "foo", StringFlag{Name: "name", EnvVar: "NAME"}, nil},
  60. {"foo,bar", StringSlice{"foo", "bar"}, StringSliceFlag{Name: "names", EnvVar: "NAMES"}, nil},
  61. {"1", uint(1), UintFlag{Name: "seconds", EnvVar: "SECONDS"}, nil},
  62. {"1.2", 0, UintFlag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Errorf(`could not parse 1.2 as uint value for flag seconds: strconv.ParseUint: parsing "1.2": invalid syntax`)},
  63. {"foobar", 0, UintFlag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Errorf(`could not parse foobar as uint value for flag seconds: strconv.ParseUint: parsing "foobar": invalid syntax`)},
  64. {"1", uint64(1), Uint64Flag{Name: "seconds", EnvVar: "SECONDS"}, nil},
  65. {"1.2", 0, Uint64Flag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Errorf(`could not parse 1.2 as uint64 value for flag seconds: strconv.ParseUint: parsing "1.2": invalid syntax`)},
  66. {"foobar", 0, Uint64Flag{Name: "seconds", EnvVar: "SECONDS"}, fmt.Errorf(`could not parse foobar as uint64 value for flag seconds: strconv.ParseUint: parsing "foobar": invalid syntax`)},
  67. {"foo,bar", &Parser{"foo", "bar"}, GenericFlag{Name: "names", Value: &Parser{}, EnvVar: "NAMES"}, nil},
  68. }
  69. for _, test := range flagTests {
  70. os.Clearenv()
  71. os.Setenv(reflect.ValueOf(test.flag).FieldByName("EnvVar").String(), test.input)
  72. a := App{
  73. Flags: []Flag{test.flag},
  74. Action: func(ctx *Context) error {
  75. if !reflect.DeepEqual(ctx.value(test.flag.GetName()), test.output) {
  76. t.Errorf("expected %+v to be parsed as %+v, instead was %+v", test.input, test.output, ctx.value(test.flag.GetName()))
  77. }
  78. return nil
  79. },
  80. }
  81. err := a.Run([]string{"run"})
  82. if !reflect.DeepEqual(test.err, err) {
  83. t.Errorf("expected error %s, got error %s", test.err, err)
  84. }
  85. }
  86. }
  87. var stringFlagTests = []struct {
  88. name string
  89. usage string
  90. value string
  91. expected string
  92. }{
  93. {"foo", "", "", "--foo value\t"},
  94. {"f", "", "", "-f value\t"},
  95. {"f", "The total `foo` desired", "all", "-f foo\tThe total foo desired (default: \"all\")"},
  96. {"test", "", "Something", "--test value\t(default: \"Something\")"},
  97. {"config,c", "Load configuration from `FILE`", "", "--config FILE, -c FILE\tLoad configuration from FILE"},
  98. {"config,c", "Load configuration from `CONFIG`", "config.json", "--config CONFIG, -c CONFIG\tLoad configuration from CONFIG (default: \"config.json\")"},
  99. }
  100. func TestStringFlagHelpOutput(t *testing.T) {
  101. for _, test := range stringFlagTests {
  102. flag := StringFlag{Name: test.name, Usage: test.usage, Value: test.value}
  103. output := flag.String()
  104. if output != test.expected {
  105. t.Errorf("%q does not match %q", output, test.expected)
  106. }
  107. }
  108. }
  109. func TestStringFlagWithEnvVarHelpOutput(t *testing.T) {
  110. os.Clearenv()
  111. os.Setenv("APP_FOO", "derp")
  112. for _, test := range stringFlagTests {
  113. flag := StringFlag{Name: test.name, Value: test.value, EnvVar: "APP_FOO"}
  114. output := flag.String()
  115. expectedSuffix := " [$APP_FOO]"
  116. if runtime.GOOS == "windows" {
  117. expectedSuffix = " [%APP_FOO%]"
  118. }
  119. if !strings.HasSuffix(output, expectedSuffix) {
  120. t.Errorf("%s does not end with"+expectedSuffix, output)
  121. }
  122. }
  123. }
  124. var stringSliceFlagTests = []struct {
  125. name string
  126. value *StringSlice
  127. expected string
  128. }{
  129. {"foo", func() *StringSlice {
  130. s := &StringSlice{}
  131. s.Set("")
  132. return s
  133. }(), "--foo value\t"},
  134. {"f", func() *StringSlice {
  135. s := &StringSlice{}
  136. s.Set("")
  137. return s
  138. }(), "-f value\t"},
  139. {"f", func() *StringSlice {
  140. s := &StringSlice{}
  141. s.Set("Lipstick")
  142. return s
  143. }(), "-f value\t(default: \"Lipstick\")"},
  144. {"test", func() *StringSlice {
  145. s := &StringSlice{}
  146. s.Set("Something")
  147. return s
  148. }(), "--test value\t(default: \"Something\")"},
  149. }
  150. func TestStringSliceFlagHelpOutput(t *testing.T) {
  151. for _, test := range stringSliceFlagTests {
  152. flag := StringSliceFlag{Name: test.name, Value: test.value}
  153. output := flag.String()
  154. if output != test.expected {
  155. t.Errorf("%q does not match %q", output, test.expected)
  156. }
  157. }
  158. }
  159. func TestStringSliceFlagWithEnvVarHelpOutput(t *testing.T) {
  160. os.Clearenv()
  161. os.Setenv("APP_QWWX", "11,4")
  162. for _, test := range stringSliceFlagTests {
  163. flag := StringSliceFlag{Name: test.name, Value: test.value, EnvVar: "APP_QWWX"}
  164. output := flag.String()
  165. expectedSuffix := " [$APP_QWWX]"
  166. if runtime.GOOS == "windows" {
  167. expectedSuffix = " [%APP_QWWX%]"
  168. }
  169. if !strings.HasSuffix(output, expectedSuffix) {
  170. t.Errorf("%q does not end with"+expectedSuffix, output)
  171. }
  172. }
  173. }
  174. var intFlagTests = []struct {
  175. name string
  176. expected string
  177. }{
  178. {"hats", "--hats value\t(default: 9)"},
  179. {"H", "-H value\t(default: 9)"},
  180. }
  181. func TestIntFlagHelpOutput(t *testing.T) {
  182. for _, test := range intFlagTests {
  183. flag := IntFlag{Name: test.name, Value: 9}
  184. output := flag.String()
  185. if output != test.expected {
  186. t.Errorf("%s does not match %s", output, test.expected)
  187. }
  188. }
  189. }
  190. func TestIntFlagWithEnvVarHelpOutput(t *testing.T) {
  191. os.Clearenv()
  192. os.Setenv("APP_BAR", "2")
  193. for _, test := range intFlagTests {
  194. flag := IntFlag{Name: test.name, EnvVar: "APP_BAR"}
  195. output := flag.String()
  196. expectedSuffix := " [$APP_BAR]"
  197. if runtime.GOOS == "windows" {
  198. expectedSuffix = " [%APP_BAR%]"
  199. }
  200. if !strings.HasSuffix(output, expectedSuffix) {
  201. t.Errorf("%s does not end with"+expectedSuffix, output)
  202. }
  203. }
  204. }
  205. var int64FlagTests = []struct {
  206. name string
  207. expected string
  208. }{
  209. {"hats", "--hats value\t(default: 8589934592)"},
  210. {"H", "-H value\t(default: 8589934592)"},
  211. }
  212. func TestInt64FlagHelpOutput(t *testing.T) {
  213. for _, test := range int64FlagTests {
  214. flag := Int64Flag{Name: test.name, Value: 8589934592}
  215. output := flag.String()
  216. if output != test.expected {
  217. t.Errorf("%s does not match %s", output, test.expected)
  218. }
  219. }
  220. }
  221. func TestInt64FlagWithEnvVarHelpOutput(t *testing.T) {
  222. os.Clearenv()
  223. os.Setenv("APP_BAR", "2")
  224. for _, test := range int64FlagTests {
  225. flag := IntFlag{Name: test.name, EnvVar: "APP_BAR"}
  226. output := flag.String()
  227. expectedSuffix := " [$APP_BAR]"
  228. if runtime.GOOS == "windows" {
  229. expectedSuffix = " [%APP_BAR%]"
  230. }
  231. if !strings.HasSuffix(output, expectedSuffix) {
  232. t.Errorf("%s does not end with"+expectedSuffix, output)
  233. }
  234. }
  235. }
  236. var uintFlagTests = []struct {
  237. name string
  238. expected string
  239. }{
  240. {"nerfs", "--nerfs value\t(default: 41)"},
  241. {"N", "-N value\t(default: 41)"},
  242. }
  243. func TestUintFlagHelpOutput(t *testing.T) {
  244. for _, test := range uintFlagTests {
  245. flag := UintFlag{Name: test.name, Value: 41}
  246. output := flag.String()
  247. if output != test.expected {
  248. t.Errorf("%s does not match %s", output, test.expected)
  249. }
  250. }
  251. }
  252. func TestUintFlagWithEnvVarHelpOutput(t *testing.T) {
  253. os.Clearenv()
  254. os.Setenv("APP_BAR", "2")
  255. for _, test := range uintFlagTests {
  256. flag := UintFlag{Name: test.name, EnvVar: "APP_BAR"}
  257. output := flag.String()
  258. expectedSuffix := " [$APP_BAR]"
  259. if runtime.GOOS == "windows" {
  260. expectedSuffix = " [%APP_BAR%]"
  261. }
  262. if !strings.HasSuffix(output, expectedSuffix) {
  263. t.Errorf("%s does not end with"+expectedSuffix, output)
  264. }
  265. }
  266. }
  267. var uint64FlagTests = []struct {
  268. name string
  269. expected string
  270. }{
  271. {"gerfs", "--gerfs value\t(default: 8589934582)"},
  272. {"G", "-G value\t(default: 8589934582)"},
  273. }
  274. func TestUint64FlagHelpOutput(t *testing.T) {
  275. for _, test := range uint64FlagTests {
  276. flag := Uint64Flag{Name: test.name, Value: 8589934582}
  277. output := flag.String()
  278. if output != test.expected {
  279. t.Errorf("%s does not match %s", output, test.expected)
  280. }
  281. }
  282. }
  283. func TestUint64FlagWithEnvVarHelpOutput(t *testing.T) {
  284. os.Clearenv()
  285. os.Setenv("APP_BAR", "2")
  286. for _, test := range uint64FlagTests {
  287. flag := UintFlag{Name: test.name, EnvVar: "APP_BAR"}
  288. output := flag.String()
  289. expectedSuffix := " [$APP_BAR]"
  290. if runtime.GOOS == "windows" {
  291. expectedSuffix = " [%APP_BAR%]"
  292. }
  293. if !strings.HasSuffix(output, expectedSuffix) {
  294. t.Errorf("%s does not end with"+expectedSuffix, output)
  295. }
  296. }
  297. }
  298. var durationFlagTests = []struct {
  299. name string
  300. expected string
  301. }{
  302. {"hooting", "--hooting value\t(default: 1s)"},
  303. {"H", "-H value\t(default: 1s)"},
  304. }
  305. func TestDurationFlagHelpOutput(t *testing.T) {
  306. for _, test := range durationFlagTests {
  307. flag := DurationFlag{Name: test.name, Value: 1 * time.Second}
  308. output := flag.String()
  309. if output != test.expected {
  310. t.Errorf("%q does not match %q", output, test.expected)
  311. }
  312. }
  313. }
  314. func TestDurationFlagWithEnvVarHelpOutput(t *testing.T) {
  315. os.Clearenv()
  316. os.Setenv("APP_BAR", "2h3m6s")
  317. for _, test := range durationFlagTests {
  318. flag := DurationFlag{Name: test.name, EnvVar: "APP_BAR"}
  319. output := flag.String()
  320. expectedSuffix := " [$APP_BAR]"
  321. if runtime.GOOS == "windows" {
  322. expectedSuffix = " [%APP_BAR%]"
  323. }
  324. if !strings.HasSuffix(output, expectedSuffix) {
  325. t.Errorf("%s does not end with"+expectedSuffix, output)
  326. }
  327. }
  328. }
  329. var intSliceFlagTests = []struct {
  330. name string
  331. value *IntSlice
  332. expected string
  333. }{
  334. {"heads", &IntSlice{}, "--heads value\t"},
  335. {"H", &IntSlice{}, "-H value\t"},
  336. {"H, heads", func() *IntSlice {
  337. i := &IntSlice{}
  338. i.Set("9")
  339. i.Set("3")
  340. return i
  341. }(), "-H value, --heads value\t(default: 9, 3)"},
  342. }
  343. func TestIntSliceFlagHelpOutput(t *testing.T) {
  344. for _, test := range intSliceFlagTests {
  345. flag := IntSliceFlag{Name: test.name, Value: test.value}
  346. output := flag.String()
  347. if output != test.expected {
  348. t.Errorf("%q does not match %q", output, test.expected)
  349. }
  350. }
  351. }
  352. func TestIntSliceFlagWithEnvVarHelpOutput(t *testing.T) {
  353. os.Clearenv()
  354. os.Setenv("APP_SMURF", "42,3")
  355. for _, test := range intSliceFlagTests {
  356. flag := IntSliceFlag{Name: test.name, Value: test.value, EnvVar: "APP_SMURF"}
  357. output := flag.String()
  358. expectedSuffix := " [$APP_SMURF]"
  359. if runtime.GOOS == "windows" {
  360. expectedSuffix = " [%APP_SMURF%]"
  361. }
  362. if !strings.HasSuffix(output, expectedSuffix) {
  363. t.Errorf("%q does not end with"+expectedSuffix, output)
  364. }
  365. }
  366. }
  367. var int64SliceFlagTests = []struct {
  368. name string
  369. value *Int64Slice
  370. expected string
  371. }{
  372. {"heads", &Int64Slice{}, "--heads value\t"},
  373. {"H", &Int64Slice{}, "-H value\t"},
  374. {"H, heads", func() *Int64Slice {
  375. i := &Int64Slice{}
  376. i.Set("2")
  377. i.Set("17179869184")
  378. return i
  379. }(), "-H value, --heads value\t(default: 2, 17179869184)"},
  380. }
  381. func TestInt64SliceFlagHelpOutput(t *testing.T) {
  382. for _, test := range int64SliceFlagTests {
  383. flag := Int64SliceFlag{Name: test.name, Value: test.value}
  384. output := flag.String()
  385. if output != test.expected {
  386. t.Errorf("%q does not match %q", output, test.expected)
  387. }
  388. }
  389. }
  390. func TestInt64SliceFlagWithEnvVarHelpOutput(t *testing.T) {
  391. os.Clearenv()
  392. os.Setenv("APP_SMURF", "42,17179869184")
  393. for _, test := range int64SliceFlagTests {
  394. flag := Int64SliceFlag{Name: test.name, Value: test.value, EnvVar: "APP_SMURF"}
  395. output := flag.String()
  396. expectedSuffix := " [$APP_SMURF]"
  397. if runtime.GOOS == "windows" {
  398. expectedSuffix = " [%APP_SMURF%]"
  399. }
  400. if !strings.HasSuffix(output, expectedSuffix) {
  401. t.Errorf("%q does not end with"+expectedSuffix, output)
  402. }
  403. }
  404. }
  405. var float64FlagTests = []struct {
  406. name string
  407. expected string
  408. }{
  409. {"hooting", "--hooting value\t(default: 0.1)"},
  410. {"H", "-H value\t(default: 0.1)"},
  411. }
  412. func TestFloat64FlagHelpOutput(t *testing.T) {
  413. for _, test := range float64FlagTests {
  414. flag := Float64Flag{Name: test.name, Value: float64(0.1)}
  415. output := flag.String()
  416. if output != test.expected {
  417. t.Errorf("%q does not match %q", output, test.expected)
  418. }
  419. }
  420. }
  421. func TestFloat64FlagWithEnvVarHelpOutput(t *testing.T) {
  422. os.Clearenv()
  423. os.Setenv("APP_BAZ", "99.4")
  424. for _, test := range float64FlagTests {
  425. flag := Float64Flag{Name: test.name, EnvVar: "APP_BAZ"}
  426. output := flag.String()
  427. expectedSuffix := " [$APP_BAZ]"
  428. if runtime.GOOS == "windows" {
  429. expectedSuffix = " [%APP_BAZ%]"
  430. }
  431. if !strings.HasSuffix(output, expectedSuffix) {
  432. t.Errorf("%s does not end with"+expectedSuffix, output)
  433. }
  434. }
  435. }
  436. var genericFlagTests = []struct {
  437. name string
  438. value Generic
  439. expected string
  440. }{
  441. {"toads", &Parser{"abc", "def"}, "--toads value\ttest flag (default: abc,def)"},
  442. {"t", &Parser{"abc", "def"}, "-t value\ttest flag (default: abc,def)"},
  443. }
  444. func TestGenericFlagHelpOutput(t *testing.T) {
  445. for _, test := range genericFlagTests {
  446. flag := GenericFlag{Name: test.name, Value: test.value, Usage: "test flag"}
  447. output := flag.String()
  448. if output != test.expected {
  449. t.Errorf("%q does not match %q", output, test.expected)
  450. }
  451. }
  452. }
  453. func TestGenericFlagWithEnvVarHelpOutput(t *testing.T) {
  454. os.Clearenv()
  455. os.Setenv("APP_ZAP", "3")
  456. for _, test := range genericFlagTests {
  457. flag := GenericFlag{Name: test.name, EnvVar: "APP_ZAP"}
  458. output := flag.String()
  459. expectedSuffix := " [$APP_ZAP]"
  460. if runtime.GOOS == "windows" {
  461. expectedSuffix = " [%APP_ZAP%]"
  462. }
  463. if !strings.HasSuffix(output, expectedSuffix) {
  464. t.Errorf("%s does not end with"+expectedSuffix, output)
  465. }
  466. }
  467. }
  468. func TestParseMultiString(t *testing.T) {
  469. (&App{
  470. Flags: []Flag{
  471. StringFlag{Name: "serve, s"},
  472. },
  473. Action: func(ctx *Context) error {
  474. if ctx.String("serve") != "10" {
  475. t.Errorf("main name not set")
  476. }
  477. if ctx.String("s") != "10" {
  478. t.Errorf("short name not set")
  479. }
  480. return nil
  481. },
  482. }).Run([]string{"run", "-s", "10"})
  483. }
  484. func TestParseDestinationString(t *testing.T) {
  485. var dest string
  486. a := App{
  487. Flags: []Flag{
  488. StringFlag{
  489. Name: "dest",
  490. Destination: &dest,
  491. },
  492. },
  493. Action: func(ctx *Context) error {
  494. if dest != "10" {
  495. t.Errorf("expected destination String 10")
  496. }
  497. return nil
  498. },
  499. }
  500. a.Run([]string{"run", "--dest", "10"})
  501. }
  502. func TestParseMultiStringFromEnv(t *testing.T) {
  503. os.Clearenv()
  504. os.Setenv("APP_COUNT", "20")
  505. (&App{
  506. Flags: []Flag{
  507. StringFlag{Name: "count, c", EnvVar: "APP_COUNT"},
  508. },
  509. Action: func(ctx *Context) error {
  510. if ctx.String("count") != "20" {
  511. t.Errorf("main name not set")
  512. }
  513. if ctx.String("c") != "20" {
  514. t.Errorf("short name not set")
  515. }
  516. return nil
  517. },
  518. }).Run([]string{"run"})
  519. }
  520. func TestParseMultiStringFromEnvCascade(t *testing.T) {
  521. os.Clearenv()
  522. os.Setenv("APP_COUNT", "20")
  523. (&App{
  524. Flags: []Flag{
  525. StringFlag{Name: "count, c", EnvVar: "COMPAT_COUNT,APP_COUNT"},
  526. },
  527. Action: func(ctx *Context) error {
  528. if ctx.String("count") != "20" {
  529. t.Errorf("main name not set")
  530. }
  531. if ctx.String("c") != "20" {
  532. t.Errorf("short name not set")
  533. }
  534. return nil
  535. },
  536. }).Run([]string{"run"})
  537. }
  538. func TestParseMultiStringSlice(t *testing.T) {
  539. (&App{
  540. Flags: []Flag{
  541. StringSliceFlag{Name: "serve, s", Value: &StringSlice{}},
  542. },
  543. Action: func(ctx *Context) error {
  544. if !reflect.DeepEqual(ctx.StringSlice("serve"), []string{"10", "20"}) {
  545. t.Errorf("main name not set")
  546. }
  547. if !reflect.DeepEqual(ctx.StringSlice("s"), []string{"10", "20"}) {
  548. t.Errorf("short name not set")
  549. }
  550. return nil
  551. },
  552. }).Run([]string{"run", "-s", "10", "-s", "20"})
  553. }
  554. func TestParseMultiStringSliceFromEnv(t *testing.T) {
  555. os.Clearenv()
  556. os.Setenv("APP_INTERVALS", "20,30,40")
  557. (&App{
  558. Flags: []Flag{
  559. StringSliceFlag{Name: "intervals, i", Value: &StringSlice{}, EnvVar: "APP_INTERVALS"},
  560. },
  561. Action: func(ctx *Context) error {
  562. if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
  563. t.Errorf("main name not set from env")
  564. }
  565. if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) {
  566. t.Errorf("short name not set from env")
  567. }
  568. return nil
  569. },
  570. }).Run([]string{"run"})
  571. }
  572. func TestParseMultiStringSliceFromEnvCascade(t *testing.T) {
  573. os.Clearenv()
  574. os.Setenv("APP_INTERVALS", "20,30,40")
  575. (&App{
  576. Flags: []Flag{
  577. StringSliceFlag{Name: "intervals, i", Value: &StringSlice{}, EnvVar: "COMPAT_INTERVALS,APP_INTERVALS"},
  578. },
  579. Action: func(ctx *Context) error {
  580. if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
  581. t.Errorf("main name not set from env")
  582. }
  583. if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) {
  584. t.Errorf("short name not set from env")
  585. }
  586. return nil
  587. },
  588. }).Run([]string{"run"})
  589. }
  590. func TestParseMultiInt(t *testing.T) {
  591. a := App{
  592. Flags: []Flag{
  593. IntFlag{Name: "serve, s"},
  594. },
  595. Action: func(ctx *Context) error {
  596. if ctx.Int("serve") != 10 {
  597. t.Errorf("main name not set")
  598. }
  599. if ctx.Int("s") != 10 {
  600. t.Errorf("short name not set")
  601. }
  602. return nil
  603. },
  604. }
  605. a.Run([]string{"run", "-s", "10"})
  606. }
  607. func TestParseDestinationInt(t *testing.T) {
  608. var dest int
  609. a := App{
  610. Flags: []Flag{
  611. IntFlag{
  612. Name: "dest",
  613. Destination: &dest,
  614. },
  615. },
  616. Action: func(ctx *Context) error {
  617. if dest != 10 {
  618. t.Errorf("expected destination Int 10")
  619. }
  620. return nil
  621. },
  622. }
  623. a.Run([]string{"run", "--dest", "10"})
  624. }
  625. func TestParseMultiIntFromEnv(t *testing.T) {
  626. os.Clearenv()
  627. os.Setenv("APP_TIMEOUT_SECONDS", "10")
  628. a := App{
  629. Flags: []Flag{
  630. IntFlag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"},
  631. },
  632. Action: func(ctx *Context) error {
  633. if ctx.Int("timeout") != 10 {
  634. t.Errorf("main name not set")
  635. }
  636. if ctx.Int("t") != 10 {
  637. t.Errorf("short name not set")
  638. }
  639. return nil
  640. },
  641. }
  642. a.Run([]string{"run"})
  643. }
  644. func TestParseMultiIntFromEnvCascade(t *testing.T) {
  645. os.Clearenv()
  646. os.Setenv("APP_TIMEOUT_SECONDS", "10")
  647. a := App{
  648. Flags: []Flag{
  649. IntFlag{Name: "timeout, t", EnvVar: "COMPAT_TIMEOUT_SECONDS,APP_TIMEOUT_SECONDS"},
  650. },
  651. Action: func(ctx *Context) error {
  652. if ctx.Int("timeout") != 10 {
  653. t.Errorf("main name not set")
  654. }
  655. if ctx.Int("t") != 10 {
  656. t.Errorf("short name not set")
  657. }
  658. return nil
  659. },
  660. }
  661. a.Run([]string{"run"})
  662. }
  663. func TestParseMultiIntSlice(t *testing.T) {
  664. (&App{
  665. Flags: []Flag{
  666. IntSliceFlag{Name: "serve, s", Value: &IntSlice{}},
  667. },
  668. Action: func(ctx *Context) error {
  669. if !reflect.DeepEqual(ctx.IntSlice("serve"), []int{10, 20}) {
  670. t.Errorf("main name not set")
  671. }
  672. if !reflect.DeepEqual(ctx.IntSlice("s"), []int{10, 20}) {
  673. t.Errorf("short name not set")
  674. }
  675. return nil
  676. },
  677. }).Run([]string{"run", "-s", "10", "-s", "20"})
  678. }
  679. func TestParseMultiIntSliceFromEnv(t *testing.T) {
  680. os.Clearenv()
  681. os.Setenv("APP_INTERVALS", "20,30,40")
  682. (&App{
  683. Flags: []Flag{
  684. IntSliceFlag{Name: "intervals, i", Value: &IntSlice{}, EnvVar: "APP_INTERVALS"},
  685. },
  686. Action: func(ctx *Context) error {
  687. if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) {
  688. t.Errorf("main name not set from env")
  689. }
  690. if !reflect.DeepEqual(ctx.IntSlice("i"), []int{20, 30, 40}) {
  691. t.Errorf("short name not set from env")
  692. }
  693. return nil
  694. },
  695. }).Run([]string{"run"})
  696. }
  697. func TestParseMultiIntSliceFromEnvCascade(t *testing.T) {
  698. os.Clearenv()
  699. os.Setenv("APP_INTERVALS", "20,30,40")
  700. (&App{
  701. Flags: []Flag{
  702. IntSliceFlag{Name: "intervals, i", Value: &IntSlice{}, EnvVar: "COMPAT_INTERVALS,APP_INTERVALS"},
  703. },
  704. Action: func(ctx *Context) error {
  705. if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) {
  706. t.Errorf("main name not set from env")
  707. }
  708. if !reflect.DeepEqual(ctx.IntSlice("i"), []int{20, 30, 40}) {
  709. t.Errorf("short name not set from env")
  710. }
  711. return nil
  712. },
  713. }).Run([]string{"run"})
  714. }
  715. func TestParseMultiInt64Slice(t *testing.T) {
  716. (&App{
  717. Flags: []Flag{
  718. Int64SliceFlag{Name: "serve, s", Value: &Int64Slice{}},
  719. },
  720. Action: func(ctx *Context) error {
  721. if !reflect.DeepEqual(ctx.Int64Slice("serve"), []int64{10, 17179869184}) {
  722. t.Errorf("main name not set")
  723. }
  724. if !reflect.DeepEqual(ctx.Int64Slice("s"), []int64{10, 17179869184}) {
  725. t.Errorf("short name not set")
  726. }
  727. return nil
  728. },
  729. }).Run([]string{"run", "-s", "10", "-s", "17179869184"})
  730. }
  731. func TestParseMultiInt64SliceFromEnv(t *testing.T) {
  732. os.Clearenv()
  733. os.Setenv("APP_INTERVALS", "20,30,17179869184")
  734. (&App{
  735. Flags: []Flag{
  736. Int64SliceFlag{Name: "intervals, i", Value: &Int64Slice{}, EnvVar: "APP_INTERVALS"},
  737. },
  738. Action: func(ctx *Context) error {
  739. if !reflect.DeepEqual(ctx.Int64Slice("intervals"), []int64{20, 30, 17179869184}) {
  740. t.Errorf("main name not set from env")
  741. }
  742. if !reflect.DeepEqual(ctx.Int64Slice("i"), []int64{20, 30, 17179869184}) {
  743. t.Errorf("short name not set from env")
  744. }
  745. return nil
  746. },
  747. }).Run([]string{"run"})
  748. }
  749. func TestParseMultiInt64SliceFromEnvCascade(t *testing.T) {
  750. os.Clearenv()
  751. os.Setenv("APP_INTERVALS", "20,30,17179869184")
  752. (&App{
  753. Flags: []Flag{
  754. Int64SliceFlag{Name: "intervals, i", Value: &Int64Slice{}, EnvVar: "COMPAT_INTERVALS,APP_INTERVALS"},
  755. },
  756. Action: func(ctx *Context) error {
  757. if !reflect.DeepEqual(ctx.Int64Slice("intervals"), []int64{20, 30, 17179869184}) {
  758. t.Errorf("main name not set from env")
  759. }
  760. if !reflect.DeepEqual(ctx.Int64Slice("i"), []int64{20, 30, 17179869184}) {
  761. t.Errorf("short name not set from env")
  762. }
  763. return nil
  764. },
  765. }).Run([]string{"run"})
  766. }
  767. func TestParseMultiFloat64(t *testing.T) {
  768. a := App{
  769. Flags: []Flag{
  770. Float64Flag{Name: "serve, s"},
  771. },
  772. Action: func(ctx *Context) error {
  773. if ctx.Float64("serve") != 10.2 {
  774. t.Errorf("main name not set")
  775. }
  776. if ctx.Float64("s") != 10.2 {
  777. t.Errorf("short name not set")
  778. }
  779. return nil
  780. },
  781. }
  782. a.Run([]string{"run", "-s", "10.2"})
  783. }
  784. func TestParseDestinationFloat64(t *testing.T) {
  785. var dest float64
  786. a := App{
  787. Flags: []Flag{
  788. Float64Flag{
  789. Name: "dest",
  790. Destination: &dest,
  791. },
  792. },
  793. Action: func(ctx *Context) error {
  794. if dest != 10.2 {
  795. t.Errorf("expected destination Float64 10.2")
  796. }
  797. return nil
  798. },
  799. }
  800. a.Run([]string{"run", "--dest", "10.2"})
  801. }
  802. func TestParseMultiFloat64FromEnv(t *testing.T) {
  803. os.Clearenv()
  804. os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
  805. a := App{
  806. Flags: []Flag{
  807. Float64Flag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"},
  808. },
  809. Action: func(ctx *Context) error {
  810. if ctx.Float64("timeout") != 15.5 {
  811. t.Errorf("main name not set")
  812. }
  813. if ctx.Float64("t") != 15.5 {
  814. t.Errorf("short name not set")
  815. }
  816. return nil
  817. },
  818. }
  819. a.Run([]string{"run"})
  820. }
  821. func TestParseMultiFloat64FromEnvCascade(t *testing.T) {
  822. os.Clearenv()
  823. os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
  824. a := App{
  825. Flags: []Flag{
  826. Float64Flag{Name: "timeout, t", EnvVar: "COMPAT_TIMEOUT_SECONDS,APP_TIMEOUT_SECONDS"},
  827. },
  828. Action: func(ctx *Context) error {
  829. if ctx.Float64("timeout") != 15.5 {
  830. t.Errorf("main name not set")
  831. }
  832. if ctx.Float64("t") != 15.5 {
  833. t.Errorf("short name not set")
  834. }
  835. return nil
  836. },
  837. }
  838. a.Run([]string{"run"})
  839. }
  840. func TestParseMultiBool(t *testing.T) {
  841. a := App{
  842. Flags: []Flag{
  843. BoolFlag{Name: "serve, s"},
  844. },
  845. Action: func(ctx *Context) error {
  846. if ctx.Bool("serve") != true {
  847. t.Errorf("main name not set")
  848. }
  849. if ctx.Bool("s") != true {
  850. t.Errorf("short name not set")
  851. }
  852. return nil
  853. },
  854. }
  855. a.Run([]string{"run", "--serve"})
  856. }
  857. func TestParseDestinationBool(t *testing.T) {
  858. var dest bool
  859. a := App{
  860. Flags: []Flag{
  861. BoolFlag{
  862. Name: "dest",
  863. Destination: &dest,
  864. },
  865. },
  866. Action: func(ctx *Context) error {
  867. if dest != true {
  868. t.Errorf("expected destination Bool true")
  869. }
  870. return nil
  871. },
  872. }
  873. a.Run([]string{"run", "--dest"})
  874. }
  875. func TestParseMultiBoolFromEnv(t *testing.T) {
  876. os.Clearenv()
  877. os.Setenv("APP_DEBUG", "1")
  878. a := App{
  879. Flags: []Flag{
  880. BoolFlag{Name: "debug, d", EnvVar: "APP_DEBUG"},
  881. },
  882. Action: func(ctx *Context) error {
  883. if ctx.Bool("debug") != true {
  884. t.Errorf("main name not set from env")
  885. }
  886. if ctx.Bool("d") != true {
  887. t.Errorf("short name not set from env")
  888. }
  889. return nil
  890. },
  891. }
  892. a.Run([]string{"run"})
  893. }
  894. func TestParseMultiBoolFromEnvCascade(t *testing.T) {
  895. os.Clearenv()
  896. os.Setenv("APP_DEBUG", "1")
  897. a := App{
  898. Flags: []Flag{
  899. BoolFlag{Name: "debug, d", EnvVar: "COMPAT_DEBUG,APP_DEBUG"},
  900. },
  901. Action: func(ctx *Context) error {
  902. if ctx.Bool("debug") != true {
  903. t.Errorf("main name not set from env")
  904. }
  905. if ctx.Bool("d") != true {
  906. t.Errorf("short name not set from env")
  907. }
  908. return nil
  909. },
  910. }
  911. a.Run([]string{"run"})
  912. }
  913. func TestParseBoolTFromEnv(t *testing.T) {
  914. var boolTFlagTests = []struct {
  915. input string
  916. output bool
  917. }{
  918. {"", false},
  919. {"1", true},
  920. {"false", false},
  921. {"true", true},
  922. }
  923. for _, test := range boolTFlagTests {
  924. os.Clearenv()
  925. os.Setenv("DEBUG", test.input)
  926. a := App{
  927. Flags: []Flag{
  928. BoolTFlag{Name: "debug, d", EnvVar: "DEBUG"},
  929. },
  930. Action: func(ctx *Context) error {
  931. if ctx.Bool("debug") != test.output {
  932. t.Errorf("expected %+v to be parsed as %+v, instead was %+v", test.input, test.output, ctx.Bool("debug"))
  933. }
  934. if ctx.Bool("d") != test.output {
  935. t.Errorf("expected %+v to be parsed as %+v, instead was %+v", test.input, test.output, ctx.Bool("d"))
  936. }
  937. return nil
  938. },
  939. }
  940. a.Run([]string{"run"})
  941. }
  942. }
  943. func TestParseMultiBoolT(t *testing.T) {
  944. a := App{
  945. Flags: []Flag{
  946. BoolTFlag{Name: "serve, s"},
  947. },
  948. Action: func(ctx *Context) error {
  949. if ctx.BoolT("serve") != true {
  950. t.Errorf("main name not set")
  951. }
  952. if ctx.BoolT("s") != true {
  953. t.Errorf("short name not set")
  954. }
  955. return nil
  956. },
  957. }
  958. a.Run([]string{"run", "--serve"})
  959. }
  960. func TestParseDestinationBoolT(t *testing.T) {
  961. var dest bool
  962. a := App{
  963. Flags: []Flag{
  964. BoolTFlag{
  965. Name: "dest",
  966. Destination: &dest,
  967. },
  968. },
  969. Action: func(ctx *Context) error {
  970. if dest != true {
  971. t.Errorf("expected destination BoolT true")
  972. }
  973. return nil
  974. },
  975. }
  976. a.Run([]string{"run", "--dest"})
  977. }
  978. func TestParseMultiBoolTFromEnv(t *testing.T) {
  979. os.Clearenv()
  980. os.Setenv("APP_DEBUG", "0")
  981. a := App{
  982. Flags: []Flag{
  983. BoolTFlag{Name: "debug, d", EnvVar: "APP_DEBUG"},
  984. },
  985. Action: func(ctx *Context) error {
  986. if ctx.BoolT("debug") != false {
  987. t.Errorf("main name not set from env")
  988. }
  989. if ctx.BoolT("d") != false {
  990. t.Errorf("short name not set from env")
  991. }
  992. return nil
  993. },
  994. }
  995. a.Run([]string{"run"})
  996. }
  997. func TestParseMultiBoolTFromEnvCascade(t *testing.T) {
  998. os.Clearenv()
  999. os.Setenv("APP_DEBUG", "0")
  1000. a := App{
  1001. Flags: []Flag{
  1002. BoolTFlag{Name: "debug, d", EnvVar: "COMPAT_DEBUG,APP_DEBUG"},
  1003. },
  1004. Action: func(ctx *Context) error {
  1005. if ctx.BoolT("debug") != false {
  1006. t.Errorf("main name not set from env")
  1007. }
  1008. if ctx.BoolT("d") != false {
  1009. t.Errorf("short name not set from env")
  1010. }
  1011. return nil
  1012. },
  1013. }
  1014. a.Run([]string{"run"})
  1015. }
  1016. type Parser [2]string
  1017. func (p *Parser) Set(value string) error {
  1018. parts := strings.Split(value, ",")
  1019. if len(parts) != 2 {
  1020. return fmt.Errorf("invalid format")
  1021. }
  1022. (*p)[0] = parts[0]
  1023. (*p)[1] = parts[1]
  1024. return nil
  1025. }
  1026. func (p *Parser) String() string {
  1027. return fmt.Sprintf("%s,%s", p[0], p[1])
  1028. }
  1029. func (p *Parser) Get() interface{} {
  1030. return p
  1031. }
  1032. func TestParseGeneric(t *testing.T) {
  1033. a := App{
  1034. Flags: []Flag{
  1035. GenericFlag{Name: "serve, s", Value: &Parser{}},
  1036. },
  1037. Action: func(ctx *Context) error {
  1038. if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"10", "20"}) {
  1039. t.Errorf("main name not set")
  1040. }
  1041. if !reflect.DeepEqual(ctx.Generic("s"), &Parser{"10", "20"}) {
  1042. t.Errorf("short name not set")
  1043. }
  1044. return nil
  1045. },
  1046. }
  1047. a.Run([]string{"run", "-s", "10,20"})
  1048. }
  1049. func TestParseGenericFromEnv(t *testing.T) {
  1050. os.Clearenv()
  1051. os.Setenv("APP_SERVE", "20,30")
  1052. a := App{
  1053. Flags: []Flag{
  1054. GenericFlag{Name: "serve, s", Value: &Parser{}, EnvVar: "APP_SERVE"},
  1055. },
  1056. Action: func(ctx *Context) error {
  1057. if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"20", "30"}) {
  1058. t.Errorf("main name not set from env")
  1059. }
  1060. if !reflect.DeepEqual(ctx.Generic("s"), &Parser{"20", "30"}) {
  1061. t.Errorf("short name not set from env")
  1062. }
  1063. return nil
  1064. },
  1065. }
  1066. a.Run([]string{"run"})
  1067. }
  1068. func TestParseGenericFromEnvCascade(t *testing.T) {
  1069. os.Clearenv()
  1070. os.Setenv("APP_FOO", "99,2000")
  1071. a := App{
  1072. Flags: []Flag{
  1073. GenericFlag{Name: "foos", Value: &Parser{}, EnvVar: "COMPAT_FOO,APP_FOO"},
  1074. },
  1075. Action: func(ctx *Context) error {
  1076. if !reflect.DeepEqual(ctx.Generic("foos"), &Parser{"99", "2000"}) {
  1077. t.Errorf("value not set from env")
  1078. }
  1079. return nil
  1080. },
  1081. }
  1082. a.Run([]string{"run"})
  1083. }