mirror of
https://github.com/shelljs/shelljs.git
synced 2026-01-18 16:03:37 +00:00
Add .reset() and .resetForTesting() to shell.config and use .resetForTesting() as a standard set-up for unit tests.
656 lines
24 KiB
JavaScript
656 lines
24 KiB
JavaScript
import fs from 'fs';
|
|
|
|
import test from 'ava';
|
|
|
|
import shell from '..';
|
|
import common from '../src/common';
|
|
import utils from './utils/utils';
|
|
|
|
const oldMaxDepth = shell.config.maxdepth;
|
|
const CWD = process.cwd();
|
|
|
|
test.beforeEach(t => {
|
|
t.context.tmp = utils.getTempDir();
|
|
shell.config.resetForTesting();
|
|
shell.mkdir(t.context.tmp);
|
|
});
|
|
|
|
test.afterEach.always(t => {
|
|
process.chdir(CWD);
|
|
shell.rm('-rf', t.context.tmp);
|
|
shell.config.maxdepth = oldMaxDepth;
|
|
});
|
|
|
|
//
|
|
// Invalids
|
|
//
|
|
|
|
test('no args', t => {
|
|
const result = shell.cp();
|
|
t.truthy(shell.error());
|
|
t.is(result.code, 1);
|
|
t.is(result.stderr, 'cp: missing <source> and/or <dest>');
|
|
});
|
|
|
|
test('no destination', t => {
|
|
const result = shell.cp('file1');
|
|
t.truthy(shell.error());
|
|
t.is(result.code, 1);
|
|
t.is(result.stderr, 'cp: missing <source> and/or <dest>');
|
|
});
|
|
|
|
test('only an option', t => {
|
|
const result = shell.cp('-f');
|
|
t.truthy(shell.error());
|
|
t.is(result.code, 1);
|
|
t.is(result.stderr, 'cp: missing <source> and/or <dest>');
|
|
});
|
|
|
|
test('invalid option', t => {
|
|
const result = shell.cp('-@', 'resources/file1', `${t.context.tmp}/file1`);
|
|
t.truthy(shell.error());
|
|
t.is(result.code, 1);
|
|
t.falsy(fs.existsSync(`${t.context.tmp}/file1`));
|
|
t.is(result.stderr, 'cp: option not recognized: @');
|
|
});
|
|
|
|
test('invalid option', t => {
|
|
const result = shell.cp('-Z', 'asdfasdf', `${t.context.tmp}/file2`);
|
|
t.truthy(shell.error());
|
|
t.is(result.code, 1);
|
|
t.falsy(fs.existsSync(`${t.context.tmp}/file2`));
|
|
t.is(result.stderr, 'cp: option not recognized: Z');
|
|
});
|
|
|
|
test('source does not exist', t => {
|
|
const result = shell.cp('asdfasdf', t.context.tmp);
|
|
t.truthy(shell.error());
|
|
t.is(result.code, 1);
|
|
t.is(utils.numLines(result.stderr), 1);
|
|
t.falsy(fs.existsSync(`${t.context.tmp}/asdfasdf`));
|
|
t.is(result.stderr, 'cp: no such file or directory: asdfasdf');
|
|
});
|
|
|
|
test('sources does not exist', t => {
|
|
const result = shell.cp('asdfasdf1', 'asdfasdf2', t.context.tmp);
|
|
t.truthy(shell.error());
|
|
t.is(result.code, 1);
|
|
t.is(utils.numLines(result.stderr), 2);
|
|
t.falsy(fs.existsSync(`${t.context.tmp}/asdfasdf1`));
|
|
t.falsy(fs.existsSync(`${t.context.tmp}/asdfasdf2`));
|
|
t.is(
|
|
result.stderr,
|
|
'cp: no such file or directory: asdfasdf1\ncp: no such file or directory: asdfasdf2'
|
|
);
|
|
});
|
|
|
|
test('too many sources', t => {
|
|
const result = shell.cp('asdfasdf1', 'asdfasdf2', 'resources/file1');
|
|
t.truthy(shell.error());
|
|
t.is(result.code, 1);
|
|
t.is(result.stderr, 'cp: dest is not a directory (too many sources)');
|
|
});
|
|
|
|
test('too many sources #2', t => {
|
|
const result = shell.cp('resources/file1', 'resources/file2', `${t.context.tmp}/a_file`);
|
|
t.truthy(shell.error());
|
|
t.is(result.code, 1);
|
|
t.falsy(fs.existsSync(`${t.context.tmp}/a_file`));
|
|
t.is(result.stderr, 'cp: dest is not a directory (too many sources)');
|
|
});
|
|
|
|
//
|
|
// Valids
|
|
//
|
|
|
|
test('dest already exists', t => {
|
|
const oldContents = shell.cat('resources/file2').toString();
|
|
const result = shell.cp('-n', 'resources/file1', 'resources/file2');
|
|
t.falsy(shell.error());
|
|
t.is(result.code, 0);
|
|
t.is(result.stderr, '');
|
|
t.is(shell.cat('resources/file2').toString(), oldContents);
|
|
});
|
|
|
|
test('-f by default', t => {
|
|
shell.cp('resources/file2', 'resources/copyfile2');
|
|
const result = shell.cp('resources/file1', 'resources/file2'); // dest already exists
|
|
t.falsy(shell.error());
|
|
t.is(result.code, 0);
|
|
t.falsy(result.stderr);
|
|
t.is(shell.cat('resources/file1').toString(), shell.cat('resources/file2').toString()); // after cp
|
|
shell.mv('resources/copyfile2', 'resources/file2'); // restore
|
|
t.falsy(shell.error());
|
|
});
|
|
|
|
test('-f (explicitly)', t => {
|
|
shell.cp('resources/file2', 'resources/copyfile2');
|
|
const result = shell.cp('-f', 'resources/file1', 'resources/file2'); // dest already exists
|
|
t.falsy(shell.error());
|
|
t.falsy(result.stderr);
|
|
t.is(result.code, 0);
|
|
t.is(shell.cat('resources/file1').toString(), shell.cat('resources/file2').toString()); // after cp
|
|
shell.mv('resources/copyfile2', 'resources/file2'); // restore
|
|
t.falsy(shell.error());
|
|
t.is(result.code, 0);
|
|
});
|
|
|
|
test('simple - to dir', t => {
|
|
const result = shell.cp('resources/file1', t.context.tmp);
|
|
t.falsy(shell.error());
|
|
t.falsy(result.stderr);
|
|
t.is(result.code, 0);
|
|
t.truthy(fs.existsSync(`${t.context.tmp}/file1`));
|
|
});
|
|
|
|
test('simple - to file', t => {
|
|
const result = shell.cp('resources/file2', `${t.context.tmp}/file2`);
|
|
t.falsy(shell.error());
|
|
t.falsy(result.stderr);
|
|
t.is(result.code, 0);
|
|
t.truthy(fs.existsSync(`${t.context.tmp}/file2`));
|
|
});
|
|
|
|
test('simple - file list', t => {
|
|
const result = shell.cp('resources/file1', 'resources/file2', t.context.tmp);
|
|
t.falsy(shell.error());
|
|
t.falsy(result.stderr);
|
|
t.is(result.code, 0);
|
|
t.truthy(fs.existsSync(`${t.context.tmp}/file1`));
|
|
t.truthy(fs.existsSync(`${t.context.tmp}/file2`));
|
|
});
|
|
|
|
test('simple - file list, array syntax', t => {
|
|
const result = shell.cp(['resources/file1', 'resources/file2'], t.context.tmp);
|
|
t.falsy(shell.error());
|
|
t.falsy(result.stderr);
|
|
t.is(result.code, 0);
|
|
t.truthy(fs.existsSync(`${t.context.tmp}/file1`));
|
|
t.truthy(fs.existsSync(`${t.context.tmp}/file2`));
|
|
});
|
|
|
|
test('-f option', t => {
|
|
shell.cp('resources/file2', `${t.context.tmp}/file3`);
|
|
t.truthy(fs.existsSync(`${t.context.tmp}/file3`));
|
|
const result = shell.cp('-f', 'resources/file2', `${t.context.tmp}/file3`); // file exists, but -f specified
|
|
t.falsy(shell.error());
|
|
t.falsy(result.stderr);
|
|
t.is(result.code, 0);
|
|
t.truthy(fs.existsSync(`${t.context.tmp}/file3`));
|
|
});
|
|
|
|
test('glob', t => {
|
|
const result = shell.cp('resources/file?', t.context.tmp);
|
|
t.falsy(shell.error());
|
|
t.falsy(result.stderr);
|
|
t.is(result.code, 0);
|
|
t.truthy(fs.existsSync(`${t.context.tmp}/file1`));
|
|
t.truthy(fs.existsSync(`${t.context.tmp}/file2`));
|
|
t.falsy(fs.existsSync(`${t.context.tmp}/file1.js`));
|
|
t.falsy(fs.existsSync(`${t.context.tmp}/file2.js`));
|
|
t.falsy(fs.existsSync(`${t.context.tmp}/file1.txt`));
|
|
t.falsy(fs.existsSync(`${t.context.tmp}/file2.txt`));
|
|
});
|
|
|
|
test('wildcard', t => {
|
|
shell.rm(`${t.context.tmp}/file1`, `${t.context.tmp}/file2`);
|
|
const result = shell.cp('resources/file*', t.context.tmp);
|
|
t.falsy(shell.error());
|
|
t.falsy(result.stderr);
|
|
t.is(result.code, 0);
|
|
t.truthy(fs.existsSync(`${t.context.tmp}/file1`));
|
|
t.truthy(fs.existsSync(`${t.context.tmp}/file2`));
|
|
t.truthy(fs.existsSync(`${t.context.tmp}/file1.js`));
|
|
t.truthy(fs.existsSync(`${t.context.tmp}/file2.js`));
|
|
t.truthy(fs.existsSync(`${t.context.tmp}/file1.txt`));
|
|
t.truthy(fs.existsSync(`${t.context.tmp}/file2.txt`));
|
|
});
|
|
|
|
test('recursive, with regular files', t => {
|
|
const result = shell.cp('-R', 'resources/file1', 'resources/file2', t.context.tmp);
|
|
t.falsy(shell.error());
|
|
t.falsy(result.stderr);
|
|
t.is(result.code, 0);
|
|
t.truthy(fs.existsSync(`${t.context.tmp}/file1`));
|
|
t.truthy(fs.existsSync(`${t.context.tmp}/file2`));
|
|
});
|
|
|
|
test('recursive, nothing exists', t => {
|
|
const result = shell.cp('-R', 'resources/cp', t.context.tmp);
|
|
t.falsy(shell.error());
|
|
t.falsy(result.stderr);
|
|
t.is(result.code, 0);
|
|
t.is(shell.ls('-R', 'resources/cp').toString(), shell.ls('-R', `${t.context.tmp}/cp`).toString());
|
|
});
|
|
|
|
test(
|
|
'recursive, nothing exists, source ends in \'/\' (see Github issue #15)',
|
|
t => {
|
|
const result = shell.cp('-R', 'resources/cp/', `${t.context.tmp}/`);
|
|
t.falsy(shell.error());
|
|
t.falsy(result.stderr);
|
|
t.is(result.code, 0);
|
|
t.is(shell.ls('-R', 'resources/cp').toString(), shell.ls('-R', `${t.context.tmp}/cp`).toString());
|
|
}
|
|
);
|
|
|
|
test(
|
|
'recursive, globbing regular files with extension (see Github issue #376)',
|
|
t => {
|
|
const result = shell.cp('-R', 'resources/file*.txt', t.context.tmp);
|
|
t.falsy(shell.error());
|
|
t.falsy(result.stderr);
|
|
t.is(result.code, 0);
|
|
t.truthy(fs.existsSync(`${t.context.tmp}/file1.txt`));
|
|
t.truthy(fs.existsSync(`${t.context.tmp}/file2.txt`));
|
|
}
|
|
);
|
|
|
|
test(
|
|
'recursive, copying one regular file (also related to Github issue #376)',
|
|
t => {
|
|
const result = shell.cp('-R', 'resources/file1.txt', t.context.tmp);
|
|
t.falsy(shell.error());
|
|
t.falsy(result.stderr);
|
|
t.is(result.code, 0);
|
|
t.truthy(fs.existsSync(`${t.context.tmp}/file1.txt`));
|
|
t.falsy(fs.statSync(`${t.context.tmp}/file1.txt`).isDirectory()); // don't let it be a dir
|
|
}
|
|
);
|
|
|
|
test('recursive, everything exists, no force flag', t => {
|
|
const result = shell.cp('-R', 'resources/cp', t.context.tmp);
|
|
t.falsy(shell.error()); // crash test only
|
|
t.falsy(result.stderr);
|
|
t.is(result.code, 0);
|
|
});
|
|
|
|
test('-R implies to not follow links', t => {
|
|
if (process.platform !== 'win32') {
|
|
shell.cp('-R', 'resources/cp/*', t.context.tmp);
|
|
t.truthy(fs.lstatSync(`${t.context.tmp}/links/sym.lnk`).isSymbolicLink()); // this one is a link
|
|
t.falsy((fs.lstatSync(`${t.context.tmp}/fakeLinks/sym.lnk`).isSymbolicLink())); // this one isn't
|
|
t.not(
|
|
shell.cat(`${t.context.tmp}/links/sym.lnk`).toString(),
|
|
shell.cat(`${t.context.tmp}/fakeLinks/sym.lnk`).toString()
|
|
);
|
|
const result = shell.cp('-R', `${t.context.tmp}/links/*`, `${t.context.tmp}/fakeLinks`);
|
|
t.falsy(shell.error());
|
|
t.falsy(result.stderr);
|
|
t.is(result.code, 0);
|
|
t.truthy(fs.lstatSync(`${t.context.tmp}/links/sym.lnk`).isSymbolicLink()); // this one is a link
|
|
t.truthy(fs.lstatSync(`${t.context.tmp}/fakeLinks/sym.lnk`).isSymbolicLink()); // this one is now a link
|
|
t.is(
|
|
shell.cat(`${t.context.tmp}/links/sym.lnk`).toString(),
|
|
shell.cat(`${t.context.tmp}/fakeLinks/sym.lnk`).toString()
|
|
);
|
|
}
|
|
});
|
|
|
|
test('Missing -R implies -L', t => {
|
|
if (process.platform !== 'win32') {
|
|
// Recursive, everything exists, overwrite a real file *by following a link*
|
|
// Because missing the -R implies -L.
|
|
shell.cp('-R', 'resources/cp/*', t.context.tmp);
|
|
t.truthy(fs.lstatSync(`${t.context.tmp}/links/sym.lnk`).isSymbolicLink()); // this one is a link
|
|
t.falsy((fs.lstatSync(`${t.context.tmp}/fakeLinks/sym.lnk`).isSymbolicLink())); // this one isn't
|
|
t.not(
|
|
shell.cat(`${t.context.tmp}/links/sym.lnk`).toString(),
|
|
shell.cat(`${t.context.tmp}/fakeLinks/sym.lnk`).toString()
|
|
);
|
|
const result = shell.cp(`${t.context.tmp}/links/*`, `${t.context.tmp}/fakeLinks`); // don't use -R
|
|
t.falsy(shell.error());
|
|
t.falsy(result.stderr);
|
|
t.is(result.code, 0);
|
|
t.truthy(fs.lstatSync(`${t.context.tmp}/links/sym.lnk`).isSymbolicLink()); // this one is a link
|
|
t.falsy(fs.lstatSync(`${t.context.tmp}/fakeLinks/sym.lnk`).isSymbolicLink()); // this one is still not a link
|
|
// But it still follows the link
|
|
t.is(
|
|
shell.cat(`${t.context.tmp}/links/sym.lnk`).toString(),
|
|
shell.cat(`${t.context.tmp}/fakeLinks/sym.lnk`).toString()
|
|
);
|
|
}
|
|
});
|
|
|
|
test('recursive, everything exists, with force flag', t => {
|
|
let result = shell.cp('-R', 'resources/cp', t.context.tmp);
|
|
shell.ShellString('changing things around').to(`${t.context.tmp}/cp/dir_a/z`);
|
|
t.not(shell.cat('resources/cp/dir_a/z').toString(), shell.cat(`${t.context.tmp}/cp/dir_a/z`).toString()); // before cp
|
|
result = shell.cp('-Rf', 'resources/cp', t.context.tmp);
|
|
t.falsy(shell.error());
|
|
t.falsy(result.stderr);
|
|
t.is(result.code, 0);
|
|
t.is(shell.cat('resources/cp/dir_a/z').toString(), shell.cat(`${t.context.tmp}/cp/dir_a/z`).toString()); // after cp
|
|
});
|
|
|
|
test(
|
|
'recursive, creates dest dir since it\'s only one level deep (see Github issue #44)',
|
|
t => {
|
|
const result = shell.cp('-r', 'resources/issue44', `${t.context.tmp}/dir2`);
|
|
t.falsy(shell.error());
|
|
t.falsy(result.stderr);
|
|
t.is(result.code, 0);
|
|
t.is(shell.ls('-R', 'resources/issue44').toString(), shell.ls('-R', `${t.context.tmp}/dir2`).toString());
|
|
t.is(
|
|
shell.cat('resources/issue44/main.js').toString(),
|
|
shell.cat(`${t.context.tmp}/dir2/main.js`).toString()
|
|
);
|
|
}
|
|
);
|
|
|
|
test(
|
|
'recursive, does *not* create dest dir since it\'s too deep (see Github issue #44)',
|
|
t => {
|
|
const result = shell.cp('-r', 'resources/issue44', `${t.context.tmp}/dir2/dir3`);
|
|
t.truthy(shell.error());
|
|
t.is(
|
|
result.stderr,
|
|
`cp: cannot create directory '${t.context.tmp}/dir2/dir3': No such file or directory`
|
|
);
|
|
t.is(result.code, 1);
|
|
t.falsy(fs.existsSync(`${t.context.tmp}/dir2`));
|
|
}
|
|
);
|
|
|
|
test('recursive, copies entire directory', t => {
|
|
const result = shell.cp('-r', 'resources/cp/dir_a', `${t.context.tmp}/dest`);
|
|
t.falsy(shell.error());
|
|
t.falsy(result.stderr);
|
|
t.is(result.code, 0);
|
|
t.truthy(fs.existsSync(`${t.context.tmp}/dest/z`));
|
|
});
|
|
|
|
test('recursive, with trailing slash, does the exact same', t => {
|
|
const result = shell.cp('-r', 'resources/cp/dir_a/', `${t.context.tmp}/dest`);
|
|
t.is(result.code, 0);
|
|
t.falsy(shell.error());
|
|
t.truthy(fs.existsSync(`${t.context.tmp}/dest/z`));
|
|
});
|
|
|
|
test(
|
|
'On Windows, permission bits are quite different so skip those tests for now',
|
|
t => {
|
|
if (common.platform !== 'win') {
|
|
// preserve mode bits
|
|
const execBit = parseInt('001', 8);
|
|
t.is(fs.statSync('resources/cp-mode-bits/executable').mode & execBit, execBit);
|
|
shell.cp('resources/cp-mode-bits/executable', `${t.context.tmp}/executable`);
|
|
t.is(
|
|
fs.statSync('resources/cp-mode-bits/executable').mode,
|
|
fs.statSync(`${t.context.tmp}/executable`).mode
|
|
);
|
|
}
|
|
}
|
|
);
|
|
|
|
test('Make sure hidden files are copied recursively', t => {
|
|
shell.rm('-rf', t.context.tmp);
|
|
const result = shell.cp('-r', 'resources/ls/', t.context.tmp);
|
|
t.falsy(shell.error());
|
|
t.falsy(result.stderr);
|
|
t.is(result.code, 0);
|
|
t.truthy(fs.existsSync(`${t.context.tmp}/.hidden_file`));
|
|
});
|
|
|
|
test('no-recursive will copy regular files only', t => {
|
|
const result = shell.cp('resources/file1.txt', 'resources/ls/', t.context.tmp);
|
|
t.is(result.code, 1);
|
|
t.truthy(shell.error());
|
|
t.falsy(fs.existsSync(`${t.context.tmp}/.hidden_file`)); // doesn't copy dir contents
|
|
t.falsy(fs.existsSync(`${t.context.tmp}/ls`)); // doesn't copy dir itself
|
|
t.truthy(fs.existsSync(`${t.context.tmp}/file1.txt`));
|
|
});
|
|
|
|
test('no-recursive will copy regular files only', t => {
|
|
const result = shell.cp('resources/file1.txt', 'resources/file2.txt', 'resources/cp',
|
|
'resources/ls/', t.context.tmp);
|
|
|
|
t.is(result.code, 1);
|
|
t.truthy(shell.error());
|
|
t.falsy(fs.existsSync(`${t.context.tmp}/.hidden_file`)); // doesn't copy dir contents
|
|
t.falsy(fs.existsSync(`${t.context.tmp}/ls`)); // doesn't copy dir itself
|
|
t.falsy(fs.existsSync(`${t.context.tmp}/a`)); // doesn't copy dir contents
|
|
t.falsy(fs.existsSync(`${t.context.tmp}/cp`)); // doesn't copy dir itself
|
|
t.truthy(fs.existsSync(`${t.context.tmp}/file1.txt`));
|
|
t.truthy(fs.existsSync(`${t.context.tmp}/file2.txt`));
|
|
});
|
|
|
|
test('-R implies -P', t => {
|
|
if (process.platform !== 'win32') {
|
|
shell.cp('-R', 'resources/cp/links/sym.lnk', t.context.tmp);
|
|
t.truthy(fs.lstatSync(`${t.context.tmp}/sym.lnk`).isSymbolicLink());
|
|
}
|
|
});
|
|
|
|
test('using -P explicitly works', t => {
|
|
if (process.platform !== 'win32') {
|
|
shell.cp('-P', 'resources/cp/links/sym.lnk', t.context.tmp);
|
|
t.truthy(fs.lstatSync(`${t.context.tmp}/sym.lnk`).isSymbolicLink());
|
|
}
|
|
});
|
|
|
|
test('using -PR on a link to a folder does not follow the link', t => {
|
|
if (process.platform !== 'win32') {
|
|
shell.cp('-PR', 'resources/cp/symFolder', t.context.tmp);
|
|
t.truthy(fs.lstatSync(`${t.context.tmp}/symFolder`).isSymbolicLink());
|
|
}
|
|
});
|
|
|
|
test('-L overrides -P for copying directory', t => {
|
|
if (process.platform !== 'win32') {
|
|
shell.cp('-LPR', 'resources/cp/symFolder', t.context.tmp);
|
|
t.falsy(fs.lstatSync(`${t.context.tmp}/symFolder`).isSymbolicLink());
|
|
t.falsy(fs.lstatSync(`${t.context.tmp}/symFolder/sym.lnk`).isSymbolicLink());
|
|
}
|
|
});
|
|
|
|
test('Recursive, copies entire directory with no symlinks and -L option does not cause change in behavior', t => {
|
|
if (process.platform !== 'win32') {
|
|
const result = shell.cp('-rL', 'resources/cp/dir_a', `${t.context.tmp}/dest`);
|
|
t.falsy(shell.error());
|
|
t.falsy(result.stderr);
|
|
t.is(result.code, 0);
|
|
t.truthy(fs.existsSync(`${t.context.tmp}/dest/z`));
|
|
}
|
|
});
|
|
|
|
test('-u flag won\'t overwrite newer files', t => {
|
|
shell.touch(`${t.context.tmp}/file1.js`);
|
|
shell.cp('-u', 'resources/file1.js', t.context.tmp);
|
|
t.falsy(shell.error());
|
|
t.not(shell.cat('resources/file1.js').toString(), shell.cat(`${t.context.tmp}/file1.js`).toString());
|
|
});
|
|
|
|
test('-u flag does overwrite older files', t => {
|
|
shell.touch({ '-d': new Date(10) }, `${t.context.tmp}/file1.js`); // really old file
|
|
shell.cp('-u', 'resources/file1.js', t.context.tmp);
|
|
t.falsy(shell.error());
|
|
t.is(shell.cat('resources/file1.js').toString(), shell.cat(`${t.context.tmp}/file1.js`).toString());
|
|
});
|
|
|
|
test('-u flag works even if it\'s not overwriting a file', t => {
|
|
t.falsy(fs.existsSync(`${t.context.tmp}/file1.js`));
|
|
shell.cp('-u', 'resources/file1.js', t.context.tmp);
|
|
t.falsy(shell.error());
|
|
t.is(shell.cat('resources/file1.js').toString(), shell.cat(`${t.context.tmp}/file1.js`).toString());
|
|
});
|
|
|
|
test('-u flag works correctly recursively', t => {
|
|
shell.mkdir(`${t.context.tmp}/foo`);
|
|
[1, 2, 3].forEach(num => {
|
|
new shell.ShellString('old\n').to(`${t.context.tmp}/foo/file${num}`);
|
|
shell.touch({ '-d': new Date(10) }, `${t.context.tmp}/foo/file${num}`);
|
|
});
|
|
shell.mkdir(`${t.context.tmp}/bar`);
|
|
[1, 2, 3].forEach(num => {
|
|
new shell.ShellString('new\n').to(`${t.context.tmp}/bar/file${num}`);
|
|
shell.touch({ '-d': new Date(1000) }, `${t.context.tmp}/bar/file${num}`);
|
|
});
|
|
// put one new one in the foo directory
|
|
new shell.ShellString('newest\n').to(`${t.context.tmp}/foo/file3`);
|
|
shell.touch({ '-d': new Date(10000) }, `${t.context.tmp}/foo/file3`);
|
|
shell.cp('-u', `${t.context.tmp}/foo/*`, `${t.context.tmp}/bar`);
|
|
t.falsy(shell.error());
|
|
t.is(shell.cat(`${t.context.tmp}/bar/*`).toString(), 'new\nnew\nnewest\n');
|
|
});
|
|
|
|
test('using -R on a link to a folder *does* follow the link', t => {
|
|
shell.cp('-R', 'resources/cp/symFolder', t.context.tmp);
|
|
t.falsy(fs.lstatSync(`${t.context.tmp}/symFolder`).isSymbolicLink());
|
|
});
|
|
|
|
test('Without -R, -L is implied', t => {
|
|
shell.cp('resources/cp/links/sym.lnk', t.context.tmp);
|
|
t.falsy(fs.lstatSync(`${t.context.tmp}/sym.lnk`).isSymbolicLink());
|
|
});
|
|
|
|
test('-L explicitly works', t => {
|
|
shell.cp('-L', 'resources/cp/links/sym.lnk', t.context.tmp);
|
|
t.falsy(fs.lstatSync(`${t.context.tmp}/sym.lnk`).isSymbolicLink());
|
|
});
|
|
|
|
test('using -LR does not imply -P', t => {
|
|
shell.cp('-LR', 'resources/cp/links/sym.lnk', t.context.tmp);
|
|
t.falsy(fs.lstatSync(`${t.context.tmp}/sym.lnk`).isSymbolicLink());
|
|
});
|
|
|
|
test('using -LR also works recursively on directories containing links', t => {
|
|
shell.cp('-LR', 'resources/cp/links', t.context.tmp);
|
|
t.falsy(fs.lstatSync(`${t.context.tmp}/links/sym.lnk`).isSymbolicLink());
|
|
});
|
|
|
|
test('-L always overrides a -P', t => {
|
|
shell.cp('-LP', 'resources/cp/links/sym.lnk', t.context.tmp);
|
|
t.falsy(fs.lstatSync(`${t.context.tmp}/sym.lnk`).isSymbolicLink());
|
|
shell.cp('-LPR', 'resources/cp/links/sym.lnk', t.context.tmp);
|
|
t.falsy(fs.lstatSync(`${t.context.tmp}/sym.lnk`).isSymbolicLink());
|
|
});
|
|
|
|
test('Make sure max depth does not limit shallow directory structures', t => {
|
|
shell.config.maxdepth = 3;
|
|
const TMP = t.context.tmp;
|
|
shell.mkdir(`${TMP}/foo`);
|
|
for (let k = 0; k < 5; k++) {
|
|
shell.mkdir(`${TMP}/foo/dir${k}`);
|
|
}
|
|
shell.cp('-r', `${TMP}/foo`, `${TMP}/bar`);
|
|
t.is(shell.ls(`${TMP}/foo`).stdout, shell.ls(`${TMP}/bar`).stdout);
|
|
});
|
|
|
|
test('Test max depth.', t => {
|
|
shell.config.maxdepth = 32;
|
|
let directory = '';
|
|
for (let i = 1; i < 40; i++) {
|
|
directory += '/' + i;
|
|
}
|
|
let directory32deep = '';
|
|
for (let i = 1; i < 32; i++) {
|
|
directory32deep += '/' + i;
|
|
}
|
|
shell.mkdir('-p', `${t.context.tmp}/0${directory}`);
|
|
shell.cp('-r', `${t.context.tmp}/0`, `${t.context.tmp}/copytestdepth`);
|
|
// Check full directory exists.
|
|
t.truthy(shell.test('-d', `${t.context.tmp}/0/${directory}`));
|
|
// Check full copy of directory does not exist.
|
|
t.falsy(shell.test('-d', `${t.context.tmp}/copytestdepth${directory}`));
|
|
// Check last directory to exist is below maxdepth.
|
|
t.truthy(shell.test('-d', `${t.context.tmp}/copytestdepth${directory32deep}`));
|
|
t.falsy(shell.test('-d', `${t.context.tmp}/copytestdepth${directory32deep}/32`));
|
|
utils.skipOnWinForEPERM(shell.ln.bind(shell, '-s', `${t.context.tmp}/0`, `${t.context.tmp}/symlinktest`), () => {
|
|
if (!shell.test('-L', `${t.context.tmp}/symlinktest`)) {
|
|
t.fail();
|
|
}
|
|
|
|
// Create symlinks to check for cycle.
|
|
shell.cd(`${t.context.tmp}/0/1/2/3/4`);
|
|
t.falsy(shell.error());
|
|
shell.ln('-s', '../../../2', 'link');
|
|
t.falsy(shell.error());
|
|
shell.ln('-s', './5/6/7', 'link1');
|
|
t.falsy(shell.error());
|
|
shell.cd('../../../../../..');
|
|
t.falsy(shell.error());
|
|
t.truthy(shell.test('-d', t.context.tmp));
|
|
|
|
shell.cp('-r', `${t.context.tmp}/0/1`, `${t.context.tmp}/copytestdepth`);
|
|
t.falsy(shell.error());
|
|
t.truthy(shell.test('-d', `${t.context.tmp}/copytestdepth/1/2/3/4/link/3/4/link/3/4`));
|
|
});
|
|
});
|
|
|
|
test('cp -L follows symlinks', t => {
|
|
utils.skipOnWinForEPERM(shell.ln.bind(shell, '-s', `${t.context.tmp}/0`, `${t.context.tmp}/symlinktest`), () => {
|
|
shell.mkdir('-p', `${t.context.tmp}/sub`);
|
|
shell.mkdir('-p', `${t.context.tmp}/new`);
|
|
shell.cp('-f', 'resources/file1.txt', `${t.context.tmp}/sub/file.txt`);
|
|
shell.cd(`${t.context.tmp}/sub`);
|
|
shell.ln('-s', 'file.txt', 'foo.lnk');
|
|
shell.ln('-s', 'file.txt', 'sym.lnk');
|
|
shell.cd('..');
|
|
shell.cp('-L', 'sub/*', 'new/');
|
|
shell.cd('new');
|
|
|
|
shell.cp('-f', '../../resources/file2.txt', 'file.txt');
|
|
t.is(shell.cat('file.txt').toString(), 'test2\n');
|
|
// Ensure other files have not changed.
|
|
t.is(shell.cat('foo.lnk').toString(), 'test1\n');
|
|
t.is(shell.cat('sym.lnk').toString(), 'test1\n');
|
|
t.falsy(shell.test('-L', 'foo.lnk'));
|
|
t.falsy(shell.test('-L', 'sym.lnk'));
|
|
shell.cd('../..');
|
|
});
|
|
});
|
|
|
|
test('Test with recursive option and symlinks.', t => {
|
|
utils.skipOnWinForEPERM(shell.ln.bind(shell, '-s', `${t.context.tmp}/0`, `${t.context.tmp}/symlinktest`), () => {
|
|
shell.mkdir('-p', `${t.context.tmp}/sub/sub1`);
|
|
shell.cp('-f', 'resources/file1.txt', `${t.context.tmp}/sub/file.txt`);
|
|
shell.cp('-f', 'resources/file1.txt', `${t.context.tmp}/sub/sub1/file.txt`);
|
|
shell.cd(`${t.context.tmp}/sub`);
|
|
shell.ln('-s', 'file.txt', 'foo.lnk');
|
|
shell.ln('-s', 'file.txt', 'sym.lnk');
|
|
shell.cd('sub1');
|
|
shell.ln('-s', '../file.txt', 'foo.lnk');
|
|
shell.ln('-s', '../file.txt', 'sym.lnk');
|
|
|
|
// Ensure file reads from proper source
|
|
t.is(shell.cat('file.txt').toString(), 'test1\n');
|
|
t.is(shell.cat('foo.lnk').toString(), 'test1\n');
|
|
t.is(shell.cat('sym.lnk').toString(), 'test1\n');
|
|
t.truthy(shell.test('-L', 'foo.lnk'));
|
|
t.truthy(shell.test('-L', 'sym.lnk'));
|
|
shell.cd('../..');
|
|
shell.cp('-rL', 'sub/', 'new/');
|
|
shell.cd('new');
|
|
|
|
// Ensure copies of files are symlinks by updating file contents.
|
|
shell.cp('-f', '../../resources/file2.txt', 'file.txt');
|
|
t.is(shell.cat('file.txt').toString(), 'test2\n');
|
|
// Ensure other files have not changed.
|
|
t.is(shell.cat('foo.lnk').toString(), 'test1\n');
|
|
t.is(shell.cat('sym.lnk').toString(), 'test1\n');
|
|
|
|
// Ensure the links are converted to files.
|
|
t.falsy(shell.test('-L', 'foo.lnk'));
|
|
t.falsy(shell.test('-L', 'sym.lnk'));
|
|
|
|
// Ensure other files have not changed.
|
|
shell.cd('sub1');
|
|
shell.cp('-f', '../../../resources/file2.txt', 'file.txt');
|
|
t.is(shell.cat('file.txt').toString(), 'test2\n');
|
|
t.is(shell.cat('foo.lnk').toString(), 'test1\n');
|
|
t.is(shell.cat('sym.lnk').toString(), 'test1\n');
|
|
|
|
// Ensure the links are converted to files
|
|
t.falsy(shell.test('-L', 'foo.lnk'));
|
|
t.falsy(shell.test('-L', 'sym.lnk'));
|
|
});
|
|
});
|
|
|
|
test('recursive, with a non-normalized path', t => {
|
|
const result = shell.cp('-R', 'resources/../resources/./cp', t.context.tmp);
|
|
t.falsy(shell.error()); // crash test only
|
|
t.falsy(result.stderr);
|
|
t.is(result.code, 0);
|
|
});
|