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 }