github.com/vipernet-xyz/tm@v0.34.24/libs/cli/setup_test.go (about)

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