mirror of
https://github.com/shelljs/shelljs.git
synced 2025-12-08 20:35:51 +00:00
No change to logic. This is a small refactor to use stricter "expectation" arguments for calls to t.throws().
340 lines
8.3 KiB
JavaScript
340 lines
8.3 KiB
JavaScript
const test = require('ava');
|
|
|
|
const shell = require('..');
|
|
const common = require('../src/common');
|
|
const utils = require('./utils/utils');
|
|
|
|
test.beforeEach(() => {
|
|
shell.config.silent = true;
|
|
common.state.error = null;
|
|
common.state.errorCode = 0;
|
|
});
|
|
|
|
test.afterEach(() => {
|
|
common.config.resetForTesting();
|
|
});
|
|
|
|
//
|
|
// Invalids
|
|
//
|
|
|
|
test('too few args', t => {
|
|
t.throws(() => {
|
|
common.expand();
|
|
}, { instanceOf: TypeError });
|
|
});
|
|
|
|
test('should be a list', t => {
|
|
t.throws(() => {
|
|
common.expand('test/resources');
|
|
}, { instanceOf: TypeError });
|
|
});
|
|
|
|
test('parseOptions (invalid option in options object)', t => {
|
|
t.throws(() => {
|
|
common.parseOptions({ q: 'some string value' }, {
|
|
R: 'recursive',
|
|
f: 'force',
|
|
r: 'reverse',
|
|
});
|
|
}, { instanceOf: common.CommandError });
|
|
});
|
|
|
|
test('parseOptions (without a hyphen in the string)', t => {
|
|
t.throws(() => {
|
|
common.parseOptions('f', {
|
|
f: 'force',
|
|
});
|
|
}, { instanceOf: Error });
|
|
});
|
|
|
|
test('parseOptions (opt is not a string/object)', t => {
|
|
t.throws(() => {
|
|
common.parseOptions(1, {
|
|
f: 'force',
|
|
});
|
|
}, { instanceOf: TypeError });
|
|
});
|
|
|
|
test('parseOptions (map is not an object)', t => {
|
|
t.throws(() => {
|
|
common.parseOptions('-f', 27);
|
|
}, { instanceOf: TypeError });
|
|
});
|
|
|
|
test('parseOptions (errorOptions is not an object)', t => {
|
|
t.throws(() => {
|
|
common.parseOptions('-f', {
|
|
f: 'force',
|
|
}, 'not a valid errorOptions');
|
|
}, { instanceOf: TypeError });
|
|
});
|
|
|
|
test('parseOptions (unrecognized string option)', t => {
|
|
t.throws(() => {
|
|
common.parseOptions('-z', {
|
|
f: 'force',
|
|
});
|
|
}, { instanceOf: common.CommandError });
|
|
});
|
|
|
|
test('parseOptions (unrecognized option in Object)', t => {
|
|
t.throws(() => {
|
|
common.parseOptions({ '-c': 7 }, {
|
|
f: 'force',
|
|
});
|
|
});
|
|
});
|
|
|
|
test('parseOptions (invalid type)', t => {
|
|
t.throws(() => {
|
|
common.parseOptions(12, {
|
|
R: 'recursive',
|
|
f: 'force',
|
|
r: 'reverse',
|
|
});
|
|
});
|
|
});
|
|
|
|
test('convertErrorOutput: no args', t => {
|
|
t.throws(() => {
|
|
common.convertErrorOutput();
|
|
}, { instanceOf: TypeError });
|
|
});
|
|
|
|
test('convertErrorOutput: input must be a vanilla string', t => {
|
|
t.throws(() => {
|
|
common.convertErrorOutput(3);
|
|
}, { instanceOf: TypeError });
|
|
|
|
t.throws(() => {
|
|
common.convertErrorOutput({});
|
|
}, { instanceOf: TypeError });
|
|
});
|
|
|
|
//
|
|
// Valids
|
|
//
|
|
|
|
//
|
|
// common.convertErrorOutput()
|
|
//
|
|
test('convertErrorOutput: nothing to convert', t => {
|
|
const input = 'hello world';
|
|
const result = common.convertErrorOutput(input);
|
|
t.is(result, input);
|
|
});
|
|
|
|
test('convertErrorOutput: does not change forward slash', t => {
|
|
const input = 'dir/sub/file.txt';
|
|
const result = common.convertErrorOutput(input);
|
|
t.is(result, input);
|
|
});
|
|
|
|
test('convertErrorOutput: changes backslashes to forward slashes', t => {
|
|
const input = 'dir\\sub\\file.txt';
|
|
const result = common.convertErrorOutput(input);
|
|
t.is(result, 'dir/sub/file.txt');
|
|
});
|
|
|
|
//
|
|
// common.expand()
|
|
//
|
|
test('single file, array syntax', t => {
|
|
const result = common.expand(['test/resources/file1.txt']);
|
|
t.deepEqual(result, ['test/resources/file1.txt']);
|
|
});
|
|
|
|
test('multiple file, glob syntax, * for file name', t => {
|
|
const result = common.expand(['test/resources/file*.txt']);
|
|
t.deepEqual(result.sort(), ['test/resources/file1.txt', 'test/resources/file2.txt'].sort());
|
|
});
|
|
|
|
test('multiple file, glob syntax, * for directory name', t => {
|
|
const result = common.expand(['test/r*/file*.txt']);
|
|
t.deepEqual(result.sort(), ['test/resources/file1.txt', 'test/resources/file2.txt'].sort());
|
|
});
|
|
|
|
test('multiple file, glob syntax, ** for directory name', t => {
|
|
const result = common.expand(['test/resources/**/file*.js']);
|
|
t.deepEqual(
|
|
result.sort(),
|
|
['test/resources/file1.js', 'test/resources/file2.js', 'test/resources/ls/file1.js', 'test/resources/ls/file2.js'].sort()
|
|
);
|
|
});
|
|
|
|
test('broken links still expand', t => {
|
|
const result = common.expand(['test/resources/b*dlink']);
|
|
t.deepEqual(result, ['test/resources/badlink']);
|
|
});
|
|
|
|
test('empty array', t => {
|
|
const result = common.expand([]);
|
|
t.deepEqual(result, []);
|
|
});
|
|
|
|
test('empty string', t => {
|
|
const result = common.expand(['']);
|
|
t.deepEqual(result, ['']);
|
|
});
|
|
|
|
test('non-string', t => {
|
|
const result = common.expand([5]);
|
|
t.deepEqual(result, [5]);
|
|
});
|
|
|
|
//
|
|
// common.buffer()
|
|
//
|
|
test('common.buffer returns buffer', t => {
|
|
const buf = common.buffer();
|
|
t.truthy(buf instanceof Buffer);
|
|
t.is(buf.length, 64 * 1024);
|
|
});
|
|
|
|
test('common.buffer with explicit length', t => {
|
|
const buf = common.buffer(20);
|
|
t.truthy(buf instanceof Buffer);
|
|
t.is(buf.length, 20);
|
|
});
|
|
|
|
test('common.buffer with different config.bufLength', t => {
|
|
common.config.bufLength = 20;
|
|
const buf = common.buffer();
|
|
t.truthy(buf instanceof Buffer);
|
|
t.is(buf.length, 20);
|
|
});
|
|
|
|
test('common.parseOptions (normal case)', t => {
|
|
const result = common.parseOptions('-Rf', {
|
|
R: 'recursive',
|
|
f: 'force',
|
|
r: 'reverse',
|
|
});
|
|
|
|
t.truthy(result.recursive);
|
|
t.truthy(result.force);
|
|
t.falsy(result.reverse);
|
|
});
|
|
|
|
test('common.parseOptions (with mutually-negating options)', t => {
|
|
const result = common.parseOptions('-f', {
|
|
n: 'no_force',
|
|
f: '!no_force',
|
|
R: 'recursive',
|
|
});
|
|
|
|
t.falsy(result.recursive);
|
|
t.falsy(result.no_force);
|
|
t.is(result.force, undefined); // this key shouldn't exist
|
|
});
|
|
|
|
test(
|
|
'common.parseOptions (the last of the conflicting options should hold)',
|
|
t => {
|
|
const options = {
|
|
n: 'no_force',
|
|
f: '!no_force',
|
|
R: 'recursive',
|
|
};
|
|
let result = common.parseOptions('-fn', options);
|
|
t.false(result.recursive);
|
|
t.truthy(result.no_force);
|
|
t.is(result.force, undefined); // this key shouldn't exist
|
|
result = common.parseOptions('-nf', options);
|
|
t.false(result.recursive);
|
|
t.false(result.no_force);
|
|
t.is(result.force, undefined); // this key shouldn't exist
|
|
}
|
|
);
|
|
|
|
test('common.parseOptions using an object to hold options', t => {
|
|
const result = common.parseOptions({ '-v': 'some text here' }, {
|
|
v: 'value',
|
|
f: 'force',
|
|
r: 'reverse',
|
|
});
|
|
|
|
t.is(result.value, 'some text here');
|
|
t.false(result.force);
|
|
t.false(result.reverse);
|
|
});
|
|
|
|
test('common.parseOptions throws when passed a string not starting with "-"', t => {
|
|
t.throws(() => {
|
|
common.parseOptions('a', { '-a': 'throws' });
|
|
}, { instanceOf: Error }, "Options string must start with a '-'");
|
|
});
|
|
|
|
test('common.parseOptions allows long options', t => {
|
|
const result = common.parseOptions({ value: true }, {
|
|
v: 'value',
|
|
});
|
|
t.truthy(result.value);
|
|
});
|
|
|
|
test('common.parseOptions allows long options with values', t => {
|
|
const someObject = {};
|
|
const result = common.parseOptions({ value: someObject }, {
|
|
v: 'value',
|
|
});
|
|
t.is(result.value, someObject);
|
|
});
|
|
|
|
test('common.parseOptions throws for unknown long option', t => {
|
|
t.throws(() => {
|
|
common.parseOptions({ throws: true }, {
|
|
v: 'value',
|
|
});
|
|
}, { instanceOf: common.CommandError });
|
|
});
|
|
|
|
test('common.parseOptions with -- argument', t => {
|
|
const result = common.parseOptions('--', {
|
|
R: 'recursive',
|
|
f: 'force',
|
|
r: 'reverse',
|
|
});
|
|
|
|
t.falsy(result.recursive);
|
|
t.falsy(result.force);
|
|
t.falsy(result.reverse);
|
|
});
|
|
|
|
test('Some basic tests on the ShellString type', t => {
|
|
const result = shell.ShellString('foo');
|
|
t.is(result.toString(), 'foo');
|
|
t.is(result.stdout, 'foo');
|
|
t.is(result.stderr, undefined);
|
|
t.truthy(result.to);
|
|
t.truthy(result.toEnd);
|
|
});
|
|
|
|
test('Commands that fail will still output error messages to stderr', async t => {
|
|
const script = "require('./global'); ls('noexist'); cd('noexist');";
|
|
const result = await utils.runScript(script);
|
|
t.is(result.stdout, '');
|
|
t.is(
|
|
result.stderr,
|
|
'ls: no such file or directory: noexist\ncd: no such file or directory: noexist\n'
|
|
);
|
|
});
|
|
|
|
test('execPath value makes sense', t => {
|
|
// TODO(nate): change this test if we add electron support in the unit tests
|
|
t.is(shell.config.execPath, process.execPath);
|
|
t.is(typeof shell.config.execPath, 'string');
|
|
});
|
|
|
|
test('Changing shell.config.execPath does not modify process', t => {
|
|
shell.config.execPath = 'foo';
|
|
t.not(shell.config.execPath, process.execPath);
|
|
});
|
|
|
|
test('CommandError is a subclass of Error', t => {
|
|
const e = new common.CommandError(new common.ShellString('some value'));
|
|
t.truthy(e instanceof common.CommandError);
|
|
t.truthy(e instanceof Error);
|
|
t.is(e.constructor, common.CommandError);
|
|
});
|