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.

226 lines
6.4 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. viper.Reset()
  45. args := append([]string{cmd.Use}, tc.args...)
  46. err := RunWithArgs(cmd, args, tc.env)
  47. require.Nil(err, i)
  48. assert.Equal(tc.expected, foo, i)
  49. }
  50. }
  51. func TestSetupConfig(t *testing.T) {
  52. assert, require := assert.New(t), require.New(t)
  53. // we pre-create two config files we can refer to in the rest of
  54. // the test cases.
  55. cval1, cval2 := "fubble", "wubble"
  56. conf1, err := WriteDemoConfig(map[string]string{"boo": cval1})
  57. require.Nil(err)
  58. // even with some ignored fields, should be no problem
  59. conf2, err := WriteDemoConfig(map[string]string{"boo": cval2, "foo": "bar"})
  60. require.Nil(err)
  61. cases := []struct {
  62. args []string
  63. env map[string]string
  64. expected string
  65. }{
  66. {nil, nil, ""},
  67. // setting on the command line
  68. {[]string{"--boo", "haha"}, nil, "haha"},
  69. {[]string{"--root", conf1}, nil, cval1},
  70. // test both variants of the prefix
  71. {nil, map[string]string{"RD_BOO": "bang"}, "bang"},
  72. {nil, map[string]string{"RD_ROOT": conf1}, cval1},
  73. {nil, map[string]string{"RDROOT": conf2}, cval2},
  74. {nil, map[string]string{"RDHOME": conf1}, cval1},
  75. // and when both are set??? HOME wins every time!
  76. {[]string{"--root", conf1}, map[string]string{"RDHOME": conf2}, cval2},
  77. }
  78. for idx, tc := range cases {
  79. i := strconv.Itoa(idx)
  80. // test command that store value of foobar in local variable
  81. var foo string
  82. boo := &cobra.Command{
  83. Use: "reader",
  84. RunE: func(cmd *cobra.Command, args []string) error {
  85. foo = viper.GetString("boo")
  86. return nil
  87. },
  88. }
  89. boo.Flags().String("boo", "", "Some test value from config")
  90. cmd := PrepareBaseCmd(boo, "RD", "/qwerty/asdfgh") // some missing dir...
  91. viper.Reset()
  92. args := append([]string{cmd.Use}, tc.args...)
  93. err := RunWithArgs(cmd, args, tc.env)
  94. require.Nil(err, i)
  95. assert.Equal(tc.expected, foo, i)
  96. }
  97. }
  98. type DemoConfig struct {
  99. Name string `mapstructure:"name"`
  100. Age int `mapstructure:"age"`
  101. Unused int `mapstructure:"unused"`
  102. }
  103. func TestSetupUnmarshal(t *testing.T) {
  104. assert, require := assert.New(t), require.New(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(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(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{"--root", 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_ROOT": 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. viper.Reset()
  162. args := append([]string{cmd.Use}, tc.args...)
  163. err := RunWithArgs(cmd, args, tc.env)
  164. require.Nil(err, i)
  165. assert.Equal(tc.expected, cfg, i)
  166. }
  167. }
  168. func TestSetupTrace(t *testing.T) {
  169. assert, require := assert.New(t), require.New(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. viper.Reset()
  192. args := append([]string{cmd.Use}, tc.args...)
  193. out, err := RunCaptureWithArgs(cmd, args, tc.env)
  194. require.NotNil(err, i)
  195. msg := strings.Split(out, "\n")
  196. desired := fmt.Sprintf("ERROR: %s", tc.expected)
  197. assert.Equal(desired, msg[0], i)
  198. if tc.long && assert.True(len(msg) > 2, i) {
  199. // the next line starts the stack trace...
  200. assert.Contains(msg[1], "TestSetupTrace", i)
  201. assert.Contains(msg[2], "setup_test.go", i)
  202. }
  203. }
  204. }