node-getopt-long
Version:
Sophisticated command line argument parser
295 lines (286 loc) • 9.24 kB
JavaScript
/* global require, describe, it, beforeEach, afterEach, process */
var _ = require('underscore');
var assert = require('assert');
var getoptLong = require('../lib/getopt-long.js');
var test_data = [
{
'name' : 'Simple',
'args' : [['long|l', 'A long named option']],
'params': [
],
'cmdline': [
{
name: 'passed long option',
argv: ['--long']
},
{
name: 'passed short option',
argv: ['-l' ]
}
],
},
{
'name' : 'Simple object',
'args' : [['long|l', {description: 'A long named option'}]],
'params': [
],
'cmdline': [
{
name : 'passed long option',
argv : ['--long'],
params: { long: true }
},
{
name : 'passed short option',
argv : ['-l', 'a'],
extra : ['a'],
params: { long: true }
}
],
},
{
'name' : 'Object with value arguments',
'args' : [
['long|l', {description: 'A long named option'}],
['int|i=i', {description: 'A long named option'}],
],
'cmdline': [
{
name : 'passed short option',
argv : ['-l', '-i', '1'],
extra : [],
params: { long: true, int: 1 }
},
{
name : 'passed short option',
argv : ['-li1'],
extra : [],
params: { long: true, int: 1 }
}
],
},
{
'name' : 'Object with value arguments',
'args' : [
['long|l', {description: 'A long named option'}],
['verbose|v+', {description: 'A long named option'}],
],
'cmdline': [
{
name : 'passed short option',
argv : ['-l', '-v', '-v'],
extra : [],
params: { long: true, verbose: 2 }
},
{
name : 'passed short option',
argv : ['-vlv'],
extra : [],
params: { long: true, verbose: 2 }
},
{
name : 'Error on unknown arg',
argv : ['-q'],
error : 'Unknown argument -q\n'
},
{
name : 'terminate on --',
argv : ['-vlv', '--', 'garbage', '--ignore'],
extra : ['garbage', '--ignore'],
params: { long: true, verbose: 2 }
}
],
},
{
'name' : 'Default values',
'args' : [
['long|l=s', {description: 'A long named option'}],
['other|o=i', {description: 'An other named option'}],
],
'config' : {
defaults : {
long : 'Long',
other: 6
}
},
'cmdline': [
{
name : 'passed short option',
argv : [],
extra : [],
params: { long: 'Long', other: 6 }
},
{
name : 'passed short option',
argv : ['-l', 'my long'],
extra : [],
params: { long: 'my long', other: 6 }
},
{
name : 'passed short option',
argv : ['--long', 'my long', '-o3'],
extra : [],
params: { long: 'my long', other: 3 }
},
{
name : 'terminate on --',
argv : ['--other', 3],
extra : [],
params: { long: 'Long', other: 3 }
}
],
},
{
'name' : 'Sub command values',
'args' : [
['long|l=s', {description: 'A long named option'}],
['other|o=i', {description: 'An other named option'}],
['verbose|v+', 'Verbose option that might be supplied by sub-command'],
],
'config' : {
subCommand: true,
},
'cmdline': [
{
name : 'No sub-command passed',
argv : ['-v'],
extra : [],
params: { verbose: 1 }
},
{
name : 'sub-command passed',
argv : ['-v', 'sub'],
extra : ['sub'],
params: { verbose: 1 }
},
{
name : 'sub-command passed with extra verbose',
argv : ['-v', 'sub', '-v'],
extra : ['sub', '-v'],
params: { verbose: 1 }
}
],
}
];
_.each(test_data, function(data) {
describe(data.name, function() {
var exit = process.exit,
outWrite = process.stdout.write,
errWrite = process.stderr.write,
exitedWith,
outText,
errText;
beforeEach(function() {
// hack in alt exit method for testing
process.exit = function(code) {
exitedWith = code;
};
process.stdout.write = function(text) {
outText = text;
};
process.stderr.write = function(text) {
errText = text;
};
});
afterEach(function() {
// restore real exit
process.exit = exit;
process.stdout.write = outWrite;
process.stderr.write = errWrite;
});
_.each(data.cmdline, function(test) {
it(test.name, function() {
var error, opt, result;
try {
test.argv.unshift('node', 'test');
if (data.config) {
data.config.argv = test.argv;
}
else {
process.argv = test.argv;
}
opt = getoptLong.configure(data.args, data.config);
if (test.hasOwnProperty('extra')) {
test.extra.unshift('node', 'test');
}
result = opt.process();
error = false;
}
catch (e) {
error = e;
}
if (error && !test.error) {
console.log({error: error, opt: opt.parameters, params: result, argv: process.argv, test: test});
}
if (test.error) {
assert.equal(errText, test.error, 'Get the expected error');
}
else {
assert.equal(error, false, 'No error creating object');
}
if (test.params) {
assert.deepEqual(test.params, result, 'Get the expected params set ('+JSON.stringify(test.params)+' vs '+JSON.stringify(result)+')');
}
if (test.extra) {
assert.deepEqual(
test.extra,
data.config ? opt.argv : process.argv,
'Get the expected leftover arguments set'
);
}
});
});
_.each(data.params, function(test) {
it(test.name, function() {
var error, opt;
try {
opt = getoptLong.options(data.args);
}
catch (e) {
error = e;
}
assert.true(!error, test.error);
assert.equal(test.value, opt[test.param], 'Test that ' + test.param + ' is equal to ' + test.value + ' (actual is ' + opt[test.param] + ')');
});
});
});
});
describe('Simplest usage', function() {
it('use options', function() {
var opt = {}, error = false;
try {
process.argv = ['node', 'test', '--long'];
opt = getoptLong.options([
['long|l', 'Long options']
], {defaults: {} });
}
catch (e) {
error = e;
}
assert.equal(error, false, 'No errors using option');
assert.deepEqual(opt, {long: true}, 'Get the answer that we expect');
});
});
describe('Protections', function() {
beforeEach(function() {
Array.prototype.junk = true;
Object.prototype.garbage = true;
});
afterEach(function() {
delete Array.prototype.junk;
delete Object.prototype.junk;
});
it('not own properties ignored', function() {
var error = false;
try {
var opt = new getoptLong.get();
opt.configure([['log|l', { description: 'long option' }]]);
process.argv = ['node', 'test', '-l'];
opt.process();
}
catch (e) {
error = e;
}
assert.equal(error, false, 'No error given when array has extra prototype property');
});
});