UNPKG

capitano

Version:

Powerful, non opitionated command line parser for serious applications

754 lines (583 loc) 24.6 kB
sinon = require('sinon') _ = require('lodash') chai = require('chai') chai.use(require('sinon-chai')) expect = chai.expect Signature = require('../lib/signature') Parameter = require('../lib/parameter') settings = require('../lib/settings') utils = require('../lib/utils') describe 'Signature:', -> describe '#constructor()', -> it 'should throw an error if no signature', -> expect -> new Signature() .to.throw(Error) it 'should throw an error if signature is not a string', -> expect -> new Signature([ 1, 2, 3 ]) .to.throw(Error) it 'should store each parameter', -> signature = new Signature('foo bar baz') expect(signature.parameters).to.have.length(3) it 'should store each parameter as instance of Parameter', -> signature = new Signature('foo bar baz') for parameter in signature.parameters expect(parameter).to.be.an.instanceof(Parameter) it 'should throw an error if the variadic parameter is not the last one', -> expect -> new Signature('foo <bar...> <baz>') .to.throw(Error) it 'should throw an error if there are multiple variadic parameters', -> expect -> new Signature('foo <bar...> <baz...>') .to.throw(Error) it 'should throw an error if there are multiple stdin parameters', -> expect -> new Signature('foo <|bar> [|baz]') .to.throw('Signature can only contain one stdin parameter') it 'should throw an error if the stdin parameter is not the last one', -> expect -> new Signature('foo <|bar> <baz>') .to.throw('The stdin parameter should be the last one') describe '#_addParameter()', -> it 'should add the parameter to the class', -> signature = new Signature('foo') expect(signature.parameters).to.have.length(1) signature._addParameter('<bar>') expect(signature.parameters).to.have.length(2) lastParameter = _.last(signature.parameters) expect(lastParameter.getValue()).to.equal('bar') expect(lastParameter.getType()).to.equal('parameter') expect(lastParameter.isRequired()).to.equal(true) expect(lastParameter.isVariadic()).to.equal(false) describe '#hasParameters()', -> it 'should return false if no parameters', -> signature = new Signature('foo') expect(signature.hasParameters()).to.be.false it 'should return true if required parameters', -> signature = new Signature('foo <bar>') expect(signature.hasParameters()).to.be.true it 'should return true if optional parameters', -> signature = new Signature('foo [bar]') expect(signature.hasParameters()).to.be.true it 'should return true if multiple required parameters', -> signature = new Signature('foo <bar> <baz>') expect(signature.hasParameters()).to.be.true it 'should return true if optional parameters', -> signature = new Signature('foo [bar] [baz]') expect(signature.hasParameters()).to.be.true it 'should return true if variadic required parameters', -> signature = new Signature('foo <bar...>') expect(signature.hasParameters()).to.be.true it 'should return true variadic parameters', -> signature = new Signature('foo [bar...]') expect(signature.hasParameters()).to.be.true describe '#hasVariadicParameters', -> it 'should return false if no parameters', -> signature = new Signature('foo') expect(signature.hasVariadicParameters()).to.be.false it 'should return false if required parameters', -> signature = new Signature('foo <bar>') expect(signature.hasVariadicParameters()).to.be.false it 'should return false if optional parameters', -> signature = new Signature('foo [bar]') expect(signature.hasVariadicParameters()).to.be.false it 'should return false if multiple required parameters', -> signature = new Signature('foo <bar> <baz>') expect(signature.hasVariadicParameters()).to.be.false it 'should return false if optional parameters', -> signature = new Signature('foo [bar] [baz]') expect(signature.hasVariadicParameters()).to.be.false it 'should return true if variadic required parameters', -> signature = new Signature('foo <bar...>') expect(signature.hasVariadicParameters()).to.be.true it 'should return true variadic parameters', -> signature = new Signature('foo [bar...]') expect(signature.hasVariadicParameters()).to.be.true describe '#allowsStdin()', -> it 'should return false if no parameters', -> signature = new Signature('foo') expect(signature.allowsStdin()).to.be.false it 'should return false if no stdin parameter', -> signature = new Signature('foo <bar>') expect(signature.allowsStdin()).to.be.false it 'should return false if required variadic parameter', -> signature = new Signature('foo <bar...>') expect(signature.allowsStdin()).to.be.false it 'should return false if optional variadic parameter', -> signature = new Signature('foo [bar...]') expect(signature.allowsStdin()).to.be.false it 'should return true if one optional stdin parameter', -> signature = new Signature('foo [|bar]') expect(signature.allowsStdin()).to.be.true it 'should return true if one required stdin parameter', -> signature = new Signature('foo <|bar>') expect(signature.allowsStdin()).to.be.true it 'should return true if one non stdin parameter and one stdin parameter', -> signature = new Signature('foo <bar> <|baz>') expect(signature.allowsStdin()).to.be.true describe '#toString()', -> it 'should convert a signature to string', -> signature = new Signature('foo <bar> [baz...]') expect(signature.toString()).to.equal('foo <bar> [baz...]') it 'should convert a wildcard to string', -> signature = new Signature('*') expect(signature.toString()).to.equal('*') describe '#isWildcard()', -> it 'should return true if it is wildcard', -> signature = new Signature(settings.signatures.wildcard) expect(signature.isWildcard()).to.be.true it 'should return false if it is not wildcard', -> signature = new Signature('foo <bar>') expect(signature.isWildcard()).to.be.false it 'should return false if it starts with a wildcard', -> signature = new Signature("#{settings.signatures.wildcard} foo") expect(signature.isWildcard()).to.be.false describe '#matches()', -> it 'should match agains a wildcard', (done) -> signature = new Signature('*') signature.matches 'foo hello', (result) -> expect(result).to.be.true done() describe 'given one word signatures', -> it 'should return true if matches', (done) -> signature = new Signature('foo <bar>') signature.matches 'foo hello', (result) -> expect(result).to.be.true done() it 'should return true if optional parameter is missing', (done) -> signature = new Signature('foo [bar]') signature.matches 'foo', (result) -> expect(result).to.be.true done() it 'should return true if required parameter is missing', (done) -> signature = new Signature('foo <bar>') signature.matches 'foo', (result) -> expect(result).to.be.true done() it 'should return false if no match', (done) -> signature = new Signature('foo <hello>') signature.matches 'bar hello', (result) -> expect(result).to.be.false done() it 'should return false if signature exceeds command', (done) -> signature = new Signature('app <id>') signature.matches 'app rm 91', (result) -> expect(result).to.be.false done() describe 'given multi word signatures', -> it 'should return true if matches', (done) -> signature = new Signature('foo bar <bar>') signature.matches 'foo bar hello', (result) -> expect(result).to.be.true done() describe 'given variadic signatures', -> it 'should return true if matches', (done) -> signature = new Signature('foo bar <bar...>') signature.matches 'foo bar hello world baz', (result) -> expect(result).to.be.true done() it 'should return true if missing optional variadic parameter', (done) -> signature = new Signature('foo bar [bar...]') signature.matches 'foo bar', (result) -> expect(result).to.be.true done() it 'should return true if missing required variadic parameter', (done) -> signature = new Signature('foo bar <bar...>') signature.matches 'foo bar', (result) -> expect(result).to.be.true done() describe '#compileParameters()', -> describe 'given a wildcard', -> beforeEach -> @signature = new Signature(settings.signatures.wildcard) it 'should return an empty object', (done) -> @signature.compileParameters 'foo', (error, result) -> expect(error).to.not.exist expect(result).to.deep.equal({}) done() describe 'given a signature with no parameters', -> beforeEach -> @signature = new Signature('foo') it 'should return an empty object if it matches', (done) -> @signature.compileParameters 'foo', (error, result) -> expect(error).to.not.exist expect(result).to.deep.equal({}) done() describe 'given a signature with one required parameter', -> beforeEach -> @signature = new Signature('foo <bar>') it 'should throw an error if prefix is different', (done) -> @signature.compileParameters 'bar hello', (error, result) -> expect(error).to.be.an.instanceof(Error) expect(result).to.not.exist done() it 'should throw an error if command exceeds', (done) -> @signature.compileParameters 'foo hello world', (error, result) -> expect(error).to.be.an.instanceof(Error) expect(result).to.not.exist done() it 'should throw an error if command misses parameter', (done) -> @signature.compileParameters 'foo', (error, result) -> expect(error).to.be.an.instanceof(Error) expect(error.message).to.equal('Missing bar') expect(result).to.not.exist done() it 'should return a single parameter if it matches', (done) -> @signature.compileParameters 'foo hello', (error, result) -> expect(error).to.not.exist expect(result).to.deep.equal bar: 'hello' done() describe 'given a signature with one optional parameter', -> beforeEach -> @signature = new Signature('foo [bar]') it 'should throw an error if prefix is different', (done) -> @signature.compileParameters 'bar hello', (error, result) -> expect(error).to.be.an.instanceof(Error) expect(result).to.not.exist done() it 'should throw an error if command exceeds', (done) -> @signature.compileParameters 'foo hello world', (error, result) -> expect(error).to.be.an.instanceof(Error) expect(result).to.not.exist done() it 'should return an empty object if command misses parameter', (done) -> @signature.compileParameters 'foo', (error, result) -> expect(error).to.not.exist expect(result).to.deep.equal({}) done() it 'should return a single parameter if it matches', (done) -> @signature.compileParameters 'foo hello', (error, result) -> expect(error).to.not.exist expect(result).to.deep.equal bar: 'hello' done() describe 'given a command with a stdin required parameter', -> beforeEach -> @signature = new Signature('foo <|bar>') describe 'if performStdin flag is false', -> beforeEach -> @utilsGetStdinStub = sinon.stub(utils, 'getStdin') afterEach -> @utilsGetStdinStub.restore() it 'should not call getStdin', (done) -> @signature.compileParameters 'foo', (error, result) => expect(@utilsGetStdinStub).to.not.have.been.called done() , false describe 'if performStdin flag is true', -> beforeEach -> @utilsGetStdinStub = sinon.stub(utils, 'getStdin') @utilsGetStdinStub.callsArgWithAsync(0, 'Hello World') afterEach -> @utilsGetStdinStub.restore() it 'should call getStdin', (done) -> @signature.compileParameters 'foo', (error, result) => expect(@utilsGetStdinStub).to.have.been.calledOnce done() , true describe 'if performStdin flag is undefined', -> beforeEach -> @utilsGetStdinStub = sinon.stub(utils, 'getStdin') @utilsGetStdinStub.callsArgWithAsync(0, 'Hello World') afterEach -> @utilsGetStdinStub.restore() it 'should call getStdin', (done) -> @signature.compileParameters 'foo', (error, result) => expect(@utilsGetStdinStub).to.have.been.calledOnce done() describe 'if stdin returns data', -> beforeEach -> @utilsGetStdinStub = sinon.stub(utils, 'getStdin') @utilsGetStdinStub.callsArgWithAsync(0, 'Hello World') afterEach -> @utilsGetStdinStub.restore() it 'should assign the parameter to the stdin output', (done) -> @signature.compileParameters 'foo', (error, result) -> expect(error).to.not.exist expect(result).to.deep.equal bar: 'Hello World' done() describe 'if stdin does not return data', -> beforeEach -> @utilsGetStdinStub = sinon.stub(utils, 'getStdin') @utilsGetStdinStub.callsArgWithAsync(0, undefined) afterEach -> @utilsGetStdinStub.restore() it 'should throw an error', (done) -> @signature.compileParameters 'foo', (error, result) -> expect(error).to.be.an.instanceof(Error) expect(error.message).to.equal('Missing bar') expect(result).to.not.exist done() describe 'given a command with a stdin optional parameter', -> beforeEach -> @signature = new Signature('foo [|bar]') describe 'if stdin returns data', -> beforeEach -> @utilsGetStdinStub = sinon.stub(utils, 'getStdin') @utilsGetStdinStub.callsArgWithAsync(0, 'Hello World') afterEach -> @utilsGetStdinStub.restore() it 'should assign the parameter to the stdin output', (done) -> @signature.compileParameters 'foo', (error, result) -> expect(error).to.not.exist expect(result).to.deep.equal bar: 'Hello World' done() describe 'if stdin does not return data', -> beforeEach -> @utilsGetStdinStub = sinon.stub(utils, 'getStdin') @utilsGetStdinStub.callsArgWithAsync(0, undefined) afterEach -> @utilsGetStdinStub.restore() it 'should do nothing', (done) -> @signature.compileParameters 'foo', (error, result) -> expect(error).to.not.exist expect(result).to.deep.equal({}) done() describe 'given a signature with a required parameter and a required stdin parameter', -> beforeEach -> @signature = new Signature('foo <bar> <|baz>') describe 'if stdin returns data', -> beforeEach -> @utilsGetStdinStub = sinon.stub(utils, 'getStdin') @utilsGetStdinStub.callsArgWithAsync(0, 'Hello World') afterEach -> @utilsGetStdinStub.restore() it 'should assign the parameter to the stdin output', (done) -> @signature.compileParameters 'foo hello', (error, result) -> expect(error).to.not.exist expect(result).to.deep.equal bar: 'hello' baz: 'Hello World' done() describe 'if stdin does not return data', -> beforeEach -> @utilsGetStdinStub = sinon.stub(utils, 'getStdin') @utilsGetStdinStub.callsArgWithAsync(0, undefined) afterEach -> @utilsGetStdinStub.restore() it 'should throw an error', (done) -> @signature.compileParameters 'foo hello', (error, result) -> expect(error).to.be.an.instanceof(Error) expect(error.message).to.equal('Missing baz') expect(result).to.not.exist done() describe 'given a signature with a required parameter and an optional stdin parameter', -> beforeEach -> @signature = new Signature('foo <bar> [|baz]') describe 'if stdin returns data', -> beforeEach -> @utilsGetStdinStub = sinon.stub(utils, 'getStdin') @utilsGetStdinStub.callsArgWithAsync(0, 'Hello World') afterEach -> @utilsGetStdinStub.restore() it 'should assign the parameter to the stdin output', (done) -> @signature.compileParameters 'foo hello', (error, result) -> expect(error).to.not.exist expect(result).to.deep.equal bar: 'hello' baz: 'Hello World' done() describe 'if stdin does not return data', -> beforeEach -> @utilsGetStdinStub = sinon.stub(utils, 'getStdin') @utilsGetStdinStub.callsArgWithAsync(0, undefined) afterEach -> @utilsGetStdinStub.restore() it 'should do nothing', (done) -> @signature.compileParameters 'foo hello', (error, result) -> expect(error).to.not.exist expect(result).to.deep.equal bar: 'hello' done() describe 'given a signature with multiple required parameters', -> beforeEach -> @signature = new Signature('foo <bar> <baz>') it 'should throw an error if prefix is different', (done) -> @signature.compileParameters 'bar hello world', (error, result) -> expect(error).to.be.an.instanceof(Error) expect(result).to.not.exist done() it 'should throw an error if command exceeds', (done) -> @signature.compileParameters 'foo hello world bar', (error, result) -> expect(error).to.be.an.instanceof(Error) expect(result).to.not.exist done() it 'should throw an error if command misses one parameter', (done) -> @signature.compileParameters 'foo hello', (error, result) -> expect(error).to.be.an.instanceof(Error) expect(error.message).to.equal('Missing baz') expect(result).to.not.exist done() it 'should throw an error if command misses both parameters', (done) -> @signature.compileParameters 'foo', (error, result) -> expect(error).to.be.an.instanceof(Error) expect(error.message).to.equal('Missing bar') expect(result).to.not.exist done() it 'should return both parameters if it matches', (done) -> @signature.compileParameters 'foo hello world', (error, result) -> expect(error).to.not.exist expect(result).to.deep.equal bar: 'hello' baz: 'world' done() describe 'given a signature with mixed parameters', -> beforeEach -> @signature = new Signature('foo <bar> [baz]') it 'should throw an error if prefix is different', (done) -> @signature.compileParameters 'bar hello world', (error, result) -> expect(error).to.be.an.instanceof(Error) expect(result).to.not.exist done() it 'should throw an error if command exceeds', (done) -> @signature.compileParameters 'foo hello world bar', (error, result) -> expect(error).to.be.an.instanceof(Error) expect(result).to.not.exist done() it 'should return one parameter if command misses one parameter', (done) -> @signature.compileParameters 'foo hello', (error, result) -> expect(error).to.not.exist expect(result).to.deep.equal bar: 'hello' done() it 'should throw an error if command misses both parameters', (done) -> @signature.compileParameters 'foo', (error, result) -> expect(error).to.be.an.instanceof(Error) expect(error.message).to.equal('Missing bar') expect(result).to.not.exist done() it 'should return both parameters if it matches', (done) -> @signature.compileParameters 'foo hello world', (error, result) -> expect(error).to.not.exist expect(result).to.deep.equal bar: 'hello' baz: 'world' done() describe 'given a signature with a variadic required parameter', -> beforeEach -> @signature = new Signature('foo <bar...>') it 'should throw an error if prefix is different', (done) -> @signature.compileParameters 'bar hello world', (error, result) -> expect(error).to.be.an.instanceof(Error) expect(result).to.not.exist done() it 'should all parameters together if command exceeds', (done) -> @signature.compileParameters 'foo hello world bar', (error, result) -> expect(error).to.not.exist expect(result).to.deep.equal bar: 'hello world bar' done() it 'should throw an error if command misses the parameter', (done) -> @signature.compileParameters 'foo', (error, result) -> expect(error).to.be.an.instanceof(Error) expect(error.message).to.equal('Missing bar') expect(result).to.not.exist done() it 'should return all parameters together if it matches', (done) -> @signature.compileParameters 'foo hello world', (error, result) -> expect(error).to.not.exist expect(result).to.deep.equal bar: 'hello world' done() describe 'given a multi-word signature with a variadic required parameter', -> beforeEach -> @signature = new Signature('foo bar <baz...>') it 'should throw an error if prefix is different', (done) -> @signature.compileParameters 'foo baz hello world', (error, result) -> expect(error).to.be.an.instanceof(Error) expect(result).to.not.exist done() it 'should all parameters together if command exceeds', (done) -> @signature.compileParameters 'foo bar hello world', (error, result) -> expect(error).to.not.exist expect(result).to.deep.equal baz: 'hello world' done() it 'should throw an error if command misses the parameter', (done) -> @signature.compileParameters 'foo bar', (error, result) -> expect(error).to.be.an.instanceof(Error) expect(error.message).to.equal('Missing baz') expect(result).to.not.exist done() describe 'given a signature with a variadic optional parameter', -> beforeEach -> @signature = new Signature('foo [bar...]') it 'should throw an error if prefix is different', (done) -> @signature.compileParameters 'bar hello world', (error, result) -> expect(error).to.be.an.instanceof(Error) expect(result).to.not.exist done() it 'should all parameters together if command exceeds', (done) -> @signature.compileParameters 'foo hello world bar', (error, result) -> expect(error).to.not.exist expect(result).to.deep.equal bar: 'hello world bar' done() it 'should return an empty object if command misses the parameter', (done) -> @signature.compileParameters 'foo', (error, result) -> expect(error).to.not.exist expect(result).to.deep.equal({}) done() it 'should return all parameters together if it matches', (done) -> @signature.compileParameters 'foo hello world', (error, result) -> expect(error).to.not.exist expect(result).to.deep.equal bar: 'hello world' done() describe 'given number commands', -> it 'should parse the numbers automatically', (done) -> signature = new Signature('foo <bar>') signature.compileParameters 'foo 019', (error, result) -> expect(error).to.not.exist expect(result).to.deep.equal bar: 19 bar_raw: '019' done() it 'should match with a string that starts with a number', (done) -> signature = new Signature('<foo>') signature.compileParameters '1bar', (error, result) -> expect(error).to.not.exist expect(result).to.deep.equal(foo: '1bar') done() describe 'given path commands', -> it 'should be able to parse absolute paths', (done) -> signature = new Signature('foo <bar>') signature.compileParameters 'foo /Users/me/foo/bar', (error, result) -> expect(error).to.not.exist expect(result).to.deep.equal bar: '/Users/me/foo/bar' done() it 'should be able to parse relative paths', (done) -> signature = new Signature('foo <bar>') signature.compileParameters 'foo ../hello/world', (error, result) -> expect(error).to.not.exist expect(result).to.deep.equal bar: '../hello/world' done() it 'should be able to parse home relative paths', (done) -> signature = new Signature('foo <bar>') signature.compileParameters 'foo ~/.ssh/id_rsa.pub', (error, result) -> expect(error).to.not.exist expect(result).to.deep.equal bar: '~/.ssh/id_rsa.pub' done() describe 'given quoted multi word command words', -> it 'should parse single quoted multi words correctly', (done) -> signature = new Signature('foo <bar>') signature.compileParameters 'foo \'hello world\'', (error, result) -> expect(error).to.not.exist expect(result).to.deep.equal bar: 'hello world' done() it 'should parse double quoted multi words correctly', (done) -> signature = new Signature('foo <bar>') signature.compileParameters 'foo "hello world"', (error, result) -> expect(error).to.not.exist expect(result).to.deep.equal bar: 'hello world' done()