shelljs/test/cp.js
Nate Fischer ac0ff873f1 refactor: add config.reset() and .resetForTesting() (#641)
Add .reset() and .resetForTesting() to shell.config and use .resetForTesting()
as a standard set-up for unit tests.
2017-01-07 22:40:38 -08:00

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);
});