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.

225 lines
6.5 KiB

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