UNPKG

13.2 kBtext/coffeescriptView Raw
1_ = require('lodash')
2_.str = require('underscore.string')
3chai = require('chai')
4expect = chai.expect
5parse = require('../lib/parse')
6state = require('../lib/state')
7Option = require('../lib/option')
8Signature = require('../lib/signature')
9settings = require('../lib/settings')
10
11describe 'Parse:', ->
12
13 describe '#normalizeInput()', ->
14
15 it 'should handle strings', ->
16 result = parse.normalizeInput('-x 3 -y 4')
17 expect(result).to.deep.equal([ '-x', '3', '-y', '4' ])
18
19 it 'should handle arrays', ->
20 result = parse.normalizeInput([ '-x', '3', '-y', '4' ])
21 expect(result).to.deep.equal([ '-x', '3', '-y', '4' ])
22
23 it 'should discard first arguments if process.argv', ->
24 result = parse.normalizeInput(process.argv)
25 expect(result).to.deep.equal(process.argv.slice(2))
26
27 it 'should throw an error if invalid input', ->
28 expect ->
29 parse.normalizeInput({ hello: 'world' })
30 .to.throw(Error)
31
32 describe '#parse()', ->
33
34 describe 'options', ->
35
36 beforeEach ->
37 state.globalOptions = []
38
39 it 'should be able to parse options', ->
40 argv = parse.split('-x 3 -y 4')
41 result = parse.parse(argv)
42 expect(result).to.deep.equal
43 global: {}
44 options:
45 x: 3
46 y: 4
47
48 it 'should be able to parse boolean options', ->
49 argv = parse.split('-x --foo')
50 result = parse.parse(argv)
51 expect(result).to.deep.equal
52 global: {}
53 options:
54 x: true
55 foo: true
56
57 it 'should be able to compile global options', ->
58 state.globalOptions.push new Option
59 signature: new Signature('quiet')
60 boolean: true
61
62 argv = parse.split('foo --quiet')
63 result = parse.parse(argv)
64 expect(result).to.deep.equal
65 global:
66 quiet: true
67 options:
68 quiet: true
69 command: 'foo'
70
71 it 'should be able to compile global options with aliases', ->
72 state.globalOptions.push new Option
73 signature: new Signature('quiet')
74 boolean: true
75 alias: 'q'
76
77 argv = parse.split('foo -q')
78 result = parse.parse(argv)
79 expect(result).to.deep.equal
80 global:
81 quiet: true
82 options:
83 q: true
84 command: 'foo'
85
86 describe 'commands', ->
87
88 it 'should be able to parse commands', ->
89 argv = parse.split('auth login')
90 result = parse.parse(argv)
91 expect(result).to.deep.equal
92 command: 'auth login'
93 options: {}
94 global: {}
95
96 it 'should be able to parse commands with suffix options', ->
97 argv = parse.split('auth login -f -n 10')
98 result = parse.parse(argv)
99 expect(result).to.deep.equal
100 command: 'auth login'
101 global: {}
102 options:
103 f: true
104 n: 10
105
106 it 'should be able to parse commands with prefix options', ->
107 argv = parse.split('-f -n 10 auth login')
108 result = parse.parse(argv)
109 expect(result).to.deep.equal
110 command: 'auth login'
111 global: {}
112 options:
113 f: true
114 n: 10
115
116 it 'should be able to parse commands with infix options', ->
117 argv = parse.split('auth -f -n 10 login')
118 result = parse.parse(argv)
119 expect(result).to.deep.equal
120 command: 'auth login'
121 global: {}
122 options:
123 f: true
124 n: 10
125
126 it 'should be able to parse commands with arguments', ->
127 argv = parse.split('auth login <credentials>')
128 result = parse.parse(argv)
129 expect(result).to.deep.equal
130 command: 'auth login <credentials>'
131 global: {}
132 options: {}
133
134 it 'should be able to parse commands with multiple arguments', ->
135 argv = parse.split('auth login <credentials> <foo>')
136 result = parse.parse(argv)
137 expect(result).to.deep.equal
138 command: 'auth login <credentials> <foo>'
139 global: {}
140 options: {}
141
142 it 'should be able to parse commands with optional arguments', ->
143 argv = parse.split('auth login [foo]')
144 result = parse.parse(argv)
145 expect(result).to.deep.equal
146 command: 'auth login [foo]'
147 global: {}
148 options: {}
149
150 it 'should be able to parse commands with multiple arguments', ->
151 argv = parse.split('transfer <from name> <to name>')
152 result = parse.parse(argv)
153 expect(result).to.deep.equal
154 command: 'transfer <from name> <to name>'
155 global: {}
156 options: {}
157
158 it 'should be able to parse commands with optional arguments', ->
159 argv = parse.split('greet [their name]')
160 result = parse.parse(argv)
161 expect(result).to.deep.equal
162 command: 'greet [their name]'
163 global: {}
164 options: {}
165
166 it 'should not discard single quotes when parsing the command', ->
167 argv = parse.split('hello \'John Doe\'')
168 result = parse.parse(argv)
169 expect(result).to.deep.equal
170 command: 'hello "John Doe"'
171 global: {}
172 options: {}
173
174 it 'should not discard double quotes when parsing the command', ->
175 argv = parse.split('hello "John Doe"')
176 result = parse.parse(argv)
177 expect(result).to.deep.equal
178 command: 'hello "John Doe"'
179 global: {}
180 options: {}
181
182 it 'should not parse numbers in scientific notation automatically', ->
183 argv = parse.split('hello -x 43e8273')
184 result = parse.parse(argv)
185 expect(result).to.deep.equal
186 command: 'hello'
187 global: {}
188 options:
189 x: '43e8273'
190
191 it 'should parse float numbers automatically', ->
192 argv = parse.split('hello -x 1.5')
193 result = parse.parse(argv)
194 expect(result).to.deep.equal
195 command: 'hello'
196 global: {}
197 options:
198 x: 1.5
199
200 describe '#split()', ->
201
202 it 'should return an empty array if no signature', ->
203 signature = undefined
204 result = []
205 expect(parse.split(signature)).to.deep.equal(result)
206
207 it 'should split a wildcard signature correctly', ->
208 signature = settings.signatures.wildcard
209 result = [ settings.signatures.wildcard ]
210 expect(parse.split(signature)).to.deep.equal(result)
211
212 it 'should split signatures correctly', ->
213 signature = 'foo <bar>'
214 result = [ 'foo', '<bar>' ]
215 expect(parse.split(signature)).to.deep.equal(result)
216
217 it 'should split multi word required parameters', ->
218 signature = '<hello world> <foo bar baz>'
219 result = [ '<hello world>', '<foo bar baz>' ]
220 expect(parse.split(signature)).to.deep.equal(result)
221
222 it 'should split multi word optional parameters', ->
223 signature = '[hello world] [foo bar baz]'
224 result = [ '[hello world]', '[foo bar baz]' ]
225 expect(parse.split(signature)).to.deep.equal(result)
226
227 it 'should split multi word variadic required parameters', ->
228 signature = '<hello world...> <foo bar baz...>'
229 result = [ '<hello world...>', '<foo bar baz...>' ]
230 expect(parse.split(signature)).to.deep.equal(result)
231
232 it 'should split multi word optional parameters', ->
233 signature = '[hello world...] [foo bar baz...]'
234 result = [ '[hello world...]', '[foo bar baz...]' ]
235 expect(parse.split(signature)).to.deep.equal(result)
236
237 it 'should split absolute paths parameters correctly', ->
238 signature = 'foo /Users/me/foo/bar'
239 result = [ 'foo', '/Users/me/foo/bar' ]
240 expect(parse.split(signature)).to.deep.equal(result)
241
242 it 'should split absolute paths (win32) parameters correctly', ->
243 signature = 'foo C:\\Users\\me\\foo\\bar'
244 result = [ 'foo', 'C:\\Users\\me\\foo\\bar' ]
245 expect(parse.split(signature)).to.deep.equal(result)
246
247 it 'should split relative paths parameters correctly', ->
248 signature = 'foo ../hello/world'
249 result = [ 'foo', '../hello/world' ]
250 expect(parse.split(signature)).to.deep.equal(result)
251
252 it 'should split home relative paths parameters correctly', ->
253 signature = 'foo ~/.ssh/id_rsa.pub'
254 result = [ 'foo', '~/.ssh/id_rsa.pub' ]
255 expect(parse.split(signature)).to.deep.equal(result)
256
257 it 'should split words surrounded by quotes correctly', ->
258 signature = 'foo \'hello world\''
259 result = [ 'foo', 'hello world' ]
260 expect(parse.split(signature)).to.deep.equal(result)
261
262 it 'should split words surrounded by double quotes correctly', ->
263 signature = 'foo "hello world"'
264 result = [ 'foo', 'hello world' ]
265 expect(parse.split(signature)).to.deep.equal(result)
266
267 describe '#parseOptions()', ->
268
269 it 'should not throw if options is undefined', ->
270 definedOptions = []
271 definedOptions.push new Option
272 signature: new Signature('foo')
273 boolean: true
274
275 expect ->
276 parse.parseOptions(definedOptions, undefined)
277 .to.not.throw(Error)
278
279 it 'should return an empty object if defined options is empty', ->
280 options =
281 hello: 'world'
282 quiet: true
283 expect(parse.parseOptions([], options)).to.deep.equal({})
284
285 it 'should return an empty object if options is empty', ->
286 definedOptions = []
287 definedOptions.push new Option
288 signature: new Signature('foo')
289 parameter: 'bar'
290 expect(parse.parseOptions(definedOptions, [])).to.deep.equal({})
291
292 it 'should parse simple options (without aliases)', ->
293 definedOptions = []
294 definedOptions.push new Option
295 signature: new Signature('foo')
296 parameter: 'bar'
297
298 definedOptions.push new Option
299 signature: new Signature('quiet')
300 boolean: true
301
302 options =
303 foo: 'baz'
304 quiet: true
305
306 result = parse.parseOptions(definedOptions, options)
307 expect(result).to.deep.equal
308 foo: 'baz'
309 quiet: true
310
311 it 'should parse options starting with a number correctly', ->
312 definedOptions = []
313 definedOptions.push new Option
314 signature: new Signature('foo')
315 parameter: 'bar'
316
317 options =
318 foo: '10foobar'
319
320 result = parse.parseOptions(definedOptions, options)
321 expect(result).to.deep.equal
322 foo: '10foobar'
323
324 it 'should parse options containing integers as numbers', ->
325 definedOptions = []
326 definedOptions.push new Option
327 signature: new Signature('foo')
328 parameter: 'bar'
329
330 options =
331 foo: '10'
332
333 result = parse.parseOptions(definedOptions, options)
334 expect(result).to.deep.equal
335 foo: 10
336
337 it 'should discard non matched options', ->
338 definedOptions = []
339 definedOptions.push new Option
340 signature: new Signature('foo')
341 parameter: 'bar'
342
343 definedOptions.push new Option
344 signature: new Signature('hello')
345 parameter: 'world'
346
347 definedOptions.push new Option
348 signature: new Signature('quiet')
349 boolean: true
350
351 options =
352 foo: 'baz'
353 quiet: 'hello'
354 hello: true
355
356 result = parse.parseOptions(definedOptions, options)
357 expect(result).to.deep.equal
358 foo: 'baz'
359
360 it 'shoud omit extra defined options', ->
361 definedOptions = []
362 definedOptions.push new Option
363 signature: new Signature('foo')
364 parameter: 'bar'
365
366 definedOptions.push new Option
367 signature: new Signature('quiet')
368 boolean: true
369
370 options =
371 foo: 'baz'
372
373 result = parse.parseOptions(definedOptions, options)
374 expect(result).to.deep.equal
375 foo: 'baz'
376
377 it 'should handle string aliases', ->
378 definedOptions = []
379 definedOptions.push new Option
380 signature: new Signature('foo')
381 parameter: 'bar'
382 alias: 'f'
383
384 options =
385 f: 'baz'
386
387 result = parse.parseOptions(definedOptions, options)
388 expect(result).to.deep.equal
389 foo: 'baz'
390
391 it 'should handle array aliases', ->
392 definedOptions = []
393 definedOptions.push new Option
394 signature: new Signature('foo')
395 parameter: 'bar'
396 alias: [ 'a', 'b', 'c' ]
397
398 options =
399 b: 'baz'
400
401 result = parse.parseOptions(definedOptions, options)
402 expect(result).to.deep.equal
403 foo: 'baz'
404
405 it 'should handle multiletter aliases', ->
406 definedOptions = []
407 definedOptions.push new Option
408 signature: new Signature('foo')
409 parameter: 'bar'
410 alias: 'hello'
411
412 options =
413 hello: 'world'
414
415 result = parse.parseOptions(definedOptions, options)
416 expect(result).to.deep.equal
417 foo: 'world'
418
419 it 'should give precedence to long names', ->
420 definedOptions = []
421 definedOptions.push new Option
422 signature: new Signature('foo')
423 parameter: 'bar'
424 alias: [ 'a', 'b', 'c' ]
425
426 options =
427 foo: 'bar'
428 b: 'baz'
429
430 result = parse.parseOptions(definedOptions, options)
431 expect(result).to.deep.equal
432 foo: 'bar'
433
434 it 'should parse numbers automatically', ->
435 definedOptions = []
436 definedOptions.push new Option
437 signature: new Signature('foo')
438 parameter: 'bar'
439
440 options =
441 foo: '25'
442
443 result = parse.parseOptions(definedOptions, options)
444 expect(result).to.deep.equal
445 foo: 25
446
447 describe 'given an option required key', ->
448
449 it 'should throw a generic error if true', ->
450 definedOptions = []
451 definedOptions.push new Option
452 signature: new Signature('foo')
453 parameter: 'bar'
454 required: true
455
456 options =
457 hello: 'world'
458
459 expect ->
460 parse.parseOptions(definedOptions, options)
461 .to.throw('Option foo is required')
462
463 it 'should not throw if false', ->
464 definedOptions = []
465 definedOptions.push new Option
466 signature: new Signature('foo')
467 parameter: 'bar'
468 required: false
469
470 options =
471 hello: 'world'
472
473 expect ->
474 parse.parseOptions(definedOptions, options)
475 .to.not.throw('Option foo is required')
476
477 it 'should throw a custom error if required is a string', ->
478 definedOptions = []
479 definedOptions.push new Option
480 signature: new Signature('foo')
481 parameter: 'bar'
482 required: 'Custom error!'
483
484 options =
485 hello: 'world'
486
487 expect ->
488 parse.parseOptions(definedOptions, options)
489 .to.throw('Custom error!')