github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/commands/cli/parse_test.go (about)

     1  package cli
     2  
     3  import (
     4  	"io"
     5  	"io/ioutil"
     6  	"os"
     7  	"strings"
     8  	"testing"
     9  
    10  	"github.com/ipfs/go-ipfs/commands"
    11  )
    12  
    13  type kvs map[string]interface{}
    14  type words []string
    15  
    16  func sameWords(a words, b words) bool {
    17  	if len(a) != len(b) {
    18  		return false
    19  	}
    20  	for i, w := range a {
    21  		if w != b[i] {
    22  			return false
    23  		}
    24  	}
    25  	return true
    26  }
    27  
    28  func sameKVs(a kvs, b kvs) bool {
    29  	if len(a) != len(b) {
    30  		return false
    31  	}
    32  	for k, v := range a {
    33  		if v != b[k] {
    34  			return false
    35  		}
    36  	}
    37  	return true
    38  }
    39  
    40  func TestSameWords(t *testing.T) {
    41  	a := []string{"v1", "v2"}
    42  	b := []string{"v1", "v2", "v3"}
    43  	c := []string{"v2", "v3"}
    44  	d := []string{"v2"}
    45  	e := []string{"v2", "v3"}
    46  	f := []string{"v2", "v1"}
    47  
    48  	test := func(a words, b words, v bool) {
    49  		if sameWords(a, b) != v {
    50  			t.Errorf("sameWords('%v', '%v') != %v", a, b, v)
    51  		}
    52  	}
    53  
    54  	test(a, b, false)
    55  	test(a, a, true)
    56  	test(a, c, false)
    57  	test(b, c, false)
    58  	test(c, d, false)
    59  	test(c, e, true)
    60  	test(b, e, false)
    61  	test(a, b, false)
    62  	test(a, f, false)
    63  	test(e, f, false)
    64  	test(f, f, true)
    65  }
    66  
    67  func TestOptionParsing(t *testing.T) {
    68  	subCmd := &commands.Command{}
    69  	cmd := &commands.Command{
    70  		Options: []commands.Option{
    71  			commands.StringOption("string", "s", "a string"),
    72  			commands.BoolOption("bool", "b", "a bool"),
    73  		},
    74  		Subcommands: map[string]*commands.Command{
    75  			"test": subCmd,
    76  		},
    77  	}
    78  
    79  	testHelper := func(args string, expectedOpts kvs, expectedWords words, expectErr bool) {
    80  		_, opts, input, _, err := parseOpts(strings.Split(args, " "), cmd)
    81  		if expectErr {
    82  			if err == nil {
    83  				t.Errorf("Command line '%v' parsing should have failed", args)
    84  			}
    85  		} else if err != nil {
    86  			t.Errorf("Command line '%v' failed to parse: %v", args, err)
    87  		} else if !sameWords(input, expectedWords) || !sameKVs(opts, expectedOpts) {
    88  			t.Errorf("Command line '%v':\n  parsed as  %v %v\n  instead of %v %v",
    89  				args, opts, input, expectedOpts, expectedWords)
    90  		}
    91  	}
    92  
    93  	testFail := func(args string) {
    94  		testHelper(args, kvs{}, words{}, true)
    95  	}
    96  
    97  	test := func(args string, expectedOpts kvs, expectedWords words) {
    98  		testHelper(args, expectedOpts, expectedWords, false)
    99  	}
   100  
   101  	test("-", kvs{}, words{"-"})
   102  	testFail("-b -b")
   103  	test("beep boop", kvs{}, words{"beep", "boop"})
   104  	test("test beep boop", kvs{}, words{"beep", "boop"})
   105  	testFail("-s")
   106  	test("-s foo", kvs{"s": "foo"}, words{})
   107  	test("-sfoo", kvs{"s": "foo"}, words{})
   108  	test("-s=foo", kvs{"s": "foo"}, words{})
   109  	test("-b", kvs{"b": ""}, words{})
   110  	test("-bs foo", kvs{"b": "", "s": "foo"}, words{})
   111  	test("-sb", kvs{"s": "b"}, words{})
   112  	test("-b foo", kvs{"b": ""}, words{"foo"})
   113  	test("--bool foo", kvs{"bool": ""}, words{"foo"})
   114  	testFail("--bool=foo")
   115  	testFail("--string")
   116  	test("--string foo", kvs{"string": "foo"}, words{})
   117  	test("--string=foo", kvs{"string": "foo"}, words{})
   118  	test("-- -b", kvs{}, words{"-b"})
   119  	test("foo -b", kvs{"b": ""}, words{"foo"})
   120  }
   121  
   122  func TestArgumentParsing(t *testing.T) {
   123  	rootCmd := &commands.Command{
   124  		Subcommands: map[string]*commands.Command{
   125  			"noarg": {},
   126  			"onearg": {
   127  				Arguments: []commands.Argument{
   128  					commands.StringArg("a", true, false, "some arg"),
   129  				},
   130  			},
   131  			"twoargs": {
   132  				Arguments: []commands.Argument{
   133  					commands.StringArg("a", true, false, "some arg"),
   134  					commands.StringArg("b", true, false, "another arg"),
   135  				},
   136  			},
   137  			"variadic": {
   138  				Arguments: []commands.Argument{
   139  					commands.StringArg("a", true, true, "some arg"),
   140  				},
   141  			},
   142  			"optional": {
   143  				Arguments: []commands.Argument{
   144  					commands.StringArg("b", false, true, "another arg"),
   145  				},
   146  			},
   147  			"optionalsecond": {
   148  				Arguments: []commands.Argument{
   149  					commands.StringArg("a", true, false, "some arg"),
   150  					commands.StringArg("b", false, false, "another arg"),
   151  				},
   152  			},
   153  			"reversedoptional": {
   154  				Arguments: []commands.Argument{
   155  					commands.StringArg("a", false, false, "some arg"),
   156  					commands.StringArg("b", true, false, "another arg"),
   157  				},
   158  			},
   159  			"stdinenabled": {
   160  				Arguments: []commands.Argument{
   161  					commands.StringArg("a", true, true, "some arg").EnableStdin(),
   162  				},
   163  			},
   164  			"stdinenabled2args": &commands.Command{
   165  				Arguments: []commands.Argument{
   166  					commands.StringArg("a", true, false, "some arg"),
   167  					commands.StringArg("b", true, true, "another arg").EnableStdin(),
   168  				},
   169  			},
   170  			"stdinenablednotvariadic": &commands.Command{
   171  				Arguments: []commands.Argument{
   172  					commands.StringArg("a", true, false, "some arg").EnableStdin(),
   173  				},
   174  			},
   175  			"stdinenablednotvariadic2args": &commands.Command{
   176  				Arguments: []commands.Argument{
   177  					commands.StringArg("a", true, false, "some arg"),
   178  					commands.StringArg("b", true, false, "another arg").EnableStdin(),
   179  				},
   180  			},
   181  		},
   182  	}
   183  
   184  	test := func(cmd words, f *os.File, res words) {
   185  		if f != nil {
   186  			if _, err := f.Seek(0, os.SEEK_SET); err != nil {
   187  				t.Fatal(err)
   188  			}
   189  		}
   190  		req, _, _, err := Parse(cmd, f, rootCmd)
   191  		if err != nil {
   192  			t.Errorf("Command '%v' should have passed parsing: %v", cmd, err)
   193  		}
   194  		if !sameWords(req.Arguments(), res) {
   195  			t.Errorf("Arguments parsed from '%v' are '%v' instead of '%v'", cmd, req.Arguments(), res)
   196  		}
   197  	}
   198  
   199  	testFail := func(cmd words, msg string) {
   200  		_, _, _, err := Parse(cmd, nil, rootCmd)
   201  		if err == nil {
   202  			t.Errorf("Should have failed: %v", msg)
   203  		}
   204  	}
   205  
   206  	test([]string{"noarg"}, nil, []string{})
   207  	testFail([]string{"noarg", "value!"}, "provided an arg, but command didn't define any")
   208  
   209  	test([]string{"onearg", "value!"}, nil, []string{"value!"})
   210  	testFail([]string{"onearg"}, "didn't provide any args, arg is required")
   211  
   212  	test([]string{"twoargs", "value1", "value2"}, nil, []string{"value1", "value2"})
   213  	testFail([]string{"twoargs", "value!"}, "only provided 1 arg, needs 2")
   214  	testFail([]string{"twoargs"}, "didn't provide any args, 2 required")
   215  
   216  	test([]string{"variadic", "value!"}, nil, []string{"value!"})
   217  	test([]string{"variadic", "value1", "value2", "value3"}, nil, []string{"value1", "value2", "value3"})
   218  	testFail([]string{"variadic"}, "didn't provide any args, 1 required")
   219  
   220  	test([]string{"optional", "value!"}, nil, []string{"value!"})
   221  	test([]string{"optional"}, nil, []string{})
   222  	test([]string{"optional", "value1", "value2"}, nil, []string{"value1", "value2"})
   223  
   224  	test([]string{"optionalsecond", "value!"}, nil, []string{"value!"})
   225  	test([]string{"optionalsecond", "value1", "value2"}, nil, []string{"value1", "value2"})
   226  	testFail([]string{"optionalsecond"}, "didn't provide any args, 1 required")
   227  	testFail([]string{"optionalsecond", "value1", "value2", "value3"}, "provided too many args, takes 2 maximum")
   228  
   229  	test([]string{"reversedoptional", "value1", "value2"}, nil, []string{"value1", "value2"})
   230  	test([]string{"reversedoptional", "value!"}, nil, []string{"value!"})
   231  
   232  	testFail([]string{"reversedoptional"}, "didn't provide any args, 1 required")
   233  	testFail([]string{"reversedoptional", "value1", "value2", "value3"}, "provided too many args, only takes 1")
   234  
   235  	// Use a temp file to simulate stdin
   236  	fileToSimulateStdin := func(t *testing.T, content string) *os.File {
   237  		fstdin, err := ioutil.TempFile("", "")
   238  		if err != nil {
   239  			t.Fatal(err)
   240  		}
   241  		defer os.Remove(fstdin.Name())
   242  
   243  		if _, err := io.WriteString(fstdin, content); err != nil {
   244  			t.Fatal(err)
   245  		}
   246  		return fstdin
   247  	}
   248  
   249  	test([]string{"stdinenabled", "value1", "value2"}, nil, []string{"value1", "value2"})
   250  
   251  	fstdin := fileToSimulateStdin(t, "stdin1")
   252  	test([]string{"stdinenabled"}, fstdin, []string{"stdin1"})
   253  	test([]string{"stdinenabled", "value1"}, fstdin, []string{"value1"})
   254  	test([]string{"stdinenabled", "value1", "value2"}, fstdin, []string{"value1", "value2"})
   255  
   256  	fstdin = fileToSimulateStdin(t, "stdin1\nstdin2")
   257  	test([]string{"stdinenabled"}, fstdin, []string{"stdin1", "stdin2"})
   258  
   259  	fstdin = fileToSimulateStdin(t, "stdin1\nstdin2\nstdin3")
   260  	test([]string{"stdinenabled"}, fstdin, []string{"stdin1", "stdin2", "stdin3"})
   261  
   262  	test([]string{"stdinenabled2args", "value1", "value2"}, nil, []string{"value1", "value2"})
   263  
   264  	fstdin = fileToSimulateStdin(t, "stdin1")
   265  	test([]string{"stdinenabled2args", "value1"}, fstdin, []string{"value1", "stdin1"})
   266  	test([]string{"stdinenabled2args", "value1", "value2"}, fstdin, []string{"value1", "value2"})
   267  	test([]string{"stdinenabled2args", "value1", "value2", "value3"}, fstdin, []string{"value1", "value2", "value3"})
   268  
   269  	fstdin = fileToSimulateStdin(t, "stdin1\nstdin2")
   270  	test([]string{"stdinenabled2args", "value1"}, fstdin, []string{"value1", "stdin1", "stdin2"})
   271  
   272  	test([]string{"stdinenablednotvariadic", "value1"}, nil, []string{"value1"})
   273  
   274  	fstdin = fileToSimulateStdin(t, "stdin1")
   275  	test([]string{"stdinenablednotvariadic"}, fstdin, []string{"stdin1"})
   276  	test([]string{"stdinenablednotvariadic", "value1"}, fstdin, []string{"value1"})
   277  
   278  	test([]string{"stdinenablednotvariadic2args", "value1", "value2"}, nil, []string{"value1", "value2"})
   279  
   280  	fstdin = fileToSimulateStdin(t, "stdin1")
   281  	test([]string{"stdinenablednotvariadic2args", "value1"}, fstdin, []string{"value1", "stdin1"})
   282  	test([]string{"stdinenablednotvariadic2args", "value1", "value2"}, fstdin, []string{"value1", "value2"})
   283  
   284  	fstdin = fileToSimulateStdin(t, "stdin1")
   285  	test([]string{"noarg"}, fstdin, []string{})
   286  
   287  	fstdin = fileToSimulateStdin(t, "stdin1")
   288  	test([]string{"optionalsecond", "value1", "value2"}, fstdin, []string{"value1", "value2"})
   289  }