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.

239 lines
7.0 KiB

  1. package cli
  2. import (
  3. "fmt"
  4. "strconv"
  5. "strings"
  6. "testing"
  7. "github.com/pkg/errors"
  8. "github.com/spf13/cobra"
  9. "github.com/spf13/viper"
  10. "github.com/stretchr/testify/assert"
  11. "github.com/stretchr/testify/require"
  12. )
  13. func TestSetupEnv(t *testing.T) {
  14. assert, require := assert.New(t), require.New(t)
  15. cases := []struct {
  16. args []string
  17. env map[string]string
  18. expected string
  19. }{
  20. {nil, nil, ""},
  21. {[]string{"--foobar", "bang!"}, nil, "bang!"},
  22. // make sure reset is good
  23. {nil, nil, ""},
  24. // test both variants of the prefix
  25. {nil, map[string]string{"DEMO_FOOBAR": "good"}, "good"},
  26. {nil, map[string]string{"DEMOFOOBAR": "silly"}, "silly"},
  27. // and that cli overrides env...
  28. {[]string{"--foobar", "important"},
  29. map[string]string{"DEMO_FOOBAR": "ignored"}, "important"},
  30. }
  31. for idx, tc := range cases {
  32. i := strconv.Itoa(idx)
  33. // test command that store value of foobar in local variable
  34. var foo string
  35. demo := &cobra.Command{
  36. Use: "demo",
  37. RunE: func(cmd *cobra.Command, args []string) error {
  38. foo = viper.GetString("foobar")
  39. return nil
  40. },
  41. }
  42. demo.Flags().String("foobar", "", "Some test value from config")
  43. cmd := PrepareBaseCmd(demo, "DEMO", "/qwerty/asdfgh") // some missing dir..
  44. cmd.Exit = func(int) {}
  45. viper.Reset()
  46. args := append([]string{cmd.Use}, tc.args...)
  47. err := RunWithArgs(cmd, args, tc.env)
  48. require.Nil(err, i)
  49. assert.Equal(tc.expected, foo, i)
  50. }
  51. }
  52. func TestSetupConfig(t *testing.T) {
  53. assert, require := assert.New(t), require.New(t)
  54. // we pre-create two config files we can refer to in the rest of
  55. // the test cases.
  56. cval1, cval2 := "fubble", "wubble"
  57. conf1, err := WriteDemoConfig(map[string]string{"boo": cval1})
  58. require.Nil(err)
  59. // make sure it handles dashed-words in the config, and ignores random info
  60. conf2, err := WriteDemoConfig(map[string]string{"boo": cval2, "foo": "bar", "two-words": "WORD"})
  61. require.Nil(err)
  62. cases := []struct {
  63. args []string
  64. env map[string]string
  65. expected string
  66. expectedTwo string
  67. }{
  68. {nil, nil, "", ""},
  69. // setting on the command line
  70. {[]string{"--boo", "haha"}, nil, "haha", ""},
  71. {[]string{"--two-words", "rocks"}, nil, "", "rocks"},
  72. {[]string{"--root", conf1}, nil, cval1, ""},
  73. // test both variants of the prefix
  74. {nil, map[string]string{"RD_BOO": "bang"}, "bang", ""},
  75. {nil, map[string]string{"RD_TWO_WORDS": "fly"}, "", "fly"},
  76. {nil, map[string]string{"RDTWO_WORDS": "fly"}, "", "fly"},
  77. {nil, map[string]string{"RD_ROOT": conf1}, cval1, ""},
  78. {nil, map[string]string{"RDROOT": conf2}, cval2, "WORD"},
  79. {nil, map[string]string{"RDHOME": conf1}, cval1, ""},
  80. // and when both are set??? HOME wins every time!
  81. {[]string{"--root", conf1}, map[string]string{"RDHOME": conf2}, cval2, "WORD"},
  82. }
  83. for idx, tc := range cases {
  84. i := strconv.Itoa(idx)
  85. // test command that store value of foobar in local variable
  86. var foo, two string
  87. boo := &cobra.Command{
  88. Use: "reader",
  89. RunE: func(cmd *cobra.Command, args []string) error {
  90. foo = viper.GetString("boo")
  91. two = viper.GetString("two-words")
  92. return nil
  93. },
  94. }
  95. boo.Flags().String("boo", "", "Some test value from config")
  96. boo.Flags().String("two-words", "", "Check out env handling -")
  97. cmd := PrepareBaseCmd(boo, "RD", "/qwerty/asdfgh") // some missing dir...
  98. cmd.Exit = func(int) {}
  99. viper.Reset()
  100. args := append([]string{cmd.Use}, tc.args...)
  101. err := RunWithArgs(cmd, args, tc.env)
  102. require.Nil(err, i)
  103. assert.Equal(tc.expected, foo, i)
  104. assert.Equal(tc.expectedTwo, two, i)
  105. }
  106. }
  107. type DemoConfig struct {
  108. Name string `mapstructure:"name"`
  109. Age int `mapstructure:"age"`
  110. Unused int `mapstructure:"unused"`
  111. }
  112. func TestSetupUnmarshal(t *testing.T) {
  113. assert, require := assert.New(t), require.New(t)
  114. // we pre-create two config files we can refer to in the rest of
  115. // the test cases.
  116. cval1, cval2 := "someone", "else"
  117. conf1, err := WriteDemoConfig(map[string]string{"name": cval1})
  118. require.Nil(err)
  119. // even with some ignored fields, should be no problem
  120. conf2, err := WriteDemoConfig(map[string]string{"name": cval2, "foo": "bar"})
  121. require.Nil(err)
  122. // unused is not declared on a flag and remains from base
  123. base := DemoConfig{
  124. Name: "default",
  125. Age: 42,
  126. Unused: -7,
  127. }
  128. c := func(name string, age int) DemoConfig {
  129. r := base
  130. // anything set on the flags as a default is used over
  131. // the default config object
  132. r.Name = "from-flag"
  133. if name != "" {
  134. r.Name = name
  135. }
  136. if age != 0 {
  137. r.Age = age
  138. }
  139. return r
  140. }
  141. cases := []struct {
  142. args []string
  143. env map[string]string
  144. expected DemoConfig
  145. }{
  146. {nil, nil, c("", 0)},
  147. // setting on the command line
  148. {[]string{"--name", "haha"}, nil, c("haha", 0)},
  149. {[]string{"--root", conf1}, nil, c(cval1, 0)},
  150. // test both variants of the prefix
  151. {nil, map[string]string{"MR_AGE": "56"}, c("", 56)},
  152. {nil, map[string]string{"MR_ROOT": conf1}, c(cval1, 0)},
  153. {[]string{"--age", "17"}, map[string]string{"MRHOME": conf2}, c(cval2, 17)},
  154. }
  155. for idx, tc := range cases {
  156. i := strconv.Itoa(idx)
  157. // test command that store value of foobar in local variable
  158. cfg := base
  159. marsh := &cobra.Command{
  160. Use: "marsh",
  161. RunE: func(cmd *cobra.Command, args []string) error {
  162. return viper.Unmarshal(&cfg)
  163. },
  164. }
  165. marsh.Flags().String("name", "from-flag", "Some test value from config")
  166. // if we want a flag to use the proper default, then copy it
  167. // from the default config here
  168. marsh.Flags().Int("age", base.Age, "Some test value from config")
  169. cmd := PrepareBaseCmd(marsh, "MR", "/qwerty/asdfgh") // some missing dir...
  170. cmd.Exit = func(int) {}
  171. viper.Reset()
  172. args := append([]string{cmd.Use}, tc.args...)
  173. err := RunWithArgs(cmd, args, tc.env)
  174. require.Nil(err, i)
  175. assert.Equal(tc.expected, cfg, i)
  176. }
  177. }
  178. func TestSetupTrace(t *testing.T) {
  179. assert, require := assert.New(t), require.New(t)
  180. cases := []struct {
  181. args []string
  182. env map[string]string
  183. long bool
  184. expected string
  185. }{
  186. {nil, nil, false, "Trace flag = false"},
  187. {[]string{"--trace"}, nil, true, "Trace flag = true"},
  188. {[]string{"--no-such-flag"}, nil, false, "unknown flag: --no-such-flag"},
  189. {nil, map[string]string{"DBG_TRACE": "true"}, true, "Trace flag = true"},
  190. }
  191. for idx, tc := range cases {
  192. i := strconv.Itoa(idx)
  193. // test command that store value of foobar in local variable
  194. trace := &cobra.Command{
  195. Use: "trace",
  196. RunE: func(cmd *cobra.Command, args []string) error {
  197. return errors.Errorf("Trace flag = %t", viper.GetBool(TraceFlag))
  198. },
  199. }
  200. cmd := PrepareBaseCmd(trace, "DBG", "/qwerty/asdfgh") // some missing dir..
  201. cmd.Exit = func(int) {}
  202. viper.Reset()
  203. args := append([]string{cmd.Use}, tc.args...)
  204. stdout, stderr, err := RunCaptureWithArgs(cmd, args, tc.env)
  205. require.NotNil(err, i)
  206. require.Equal("", stdout, i)
  207. require.NotEqual("", stderr, i)
  208. msg := strings.Split(stderr, "\n")
  209. desired := fmt.Sprintf("ERROR: %s", tc.expected)
  210. assert.Equal(desired, msg[0], i)
  211. if tc.long && assert.True(len(msg) > 2, i) {
  212. // the next line starts the stack trace...
  213. assert.Contains(msg[1], "TestSetupTrace", i)
  214. assert.Contains(msg[2], "setup_test.go", i)
  215. }
  216. }
  217. }