import fs from 'fs'; import path from 'path'; import test from 'ava'; import shell from '..'; import utils from './utils/utils'; const CWD = process.cwd(); test.beforeEach(t => { t.context.tmp = utils.getTempDir(); shell.config.resetForTesting(); shell.cp('-r', 'resources', t.context.tmp); process.chdir(CWD); }); test.afterEach.always(t => { shell.rm('-rf', t.context.tmp); }); // // Invalids // test('no args', t => { const result = shell.ln(); t.truthy(shell.error()); t.is(result.code, 1); }); test('too few args', t => { const result = shell.ln('file'); t.truthy(shell.error()); t.is(result.code, 1); }); test('only an option', t => { const result = shell.ln('-f'); t.truthy(shell.error()); t.is(result.code, 1); }); test('destination already exists', t => { const result = shell.ln(`${t.context.tmp}/file1`, `${t.context.tmp}/file2`); t.truthy(shell.error()); t.is(result.code, 1); }); test('non-existent source', t => { const result = shell.ln(`${t.context.tmp}/noexist`, `${t.context.tmp}/linkfile1`); t.truthy(shell.error()); t.is(result.code, 1); }); test('non-existent source (-sf)', t => { const result = shell.ln('-sf', 'no/exist', `${t.context.tmp}/badlink`); t.truthy(shell.error()); t.is(result.code, 1); }); test('non-existent source (-f)', t => { const result = shell.ln('-f', 'noexist', `${t.context.tmp}/badlink`); t.truthy(shell.error()); t.is(result.code, 1); }); // // Valids // test('basic usage', t => { const result = shell.ln(`${t.context.tmp}/file1`, `${t.context.tmp}/linkfile1`); t.truthy(fs.existsSync(`${t.context.tmp}/linkfile1`)); t.is( fs.readFileSync(`${t.context.tmp}/file1`).toString(), fs.readFileSync(`${t.context.tmp}/linkfile1`).toString() ); fs.writeFileSync(`${t.context.tmp}/file1`, 'new content 1'); t.is(fs.readFileSync(`${t.context.tmp}/linkfile1`).toString(), 'new content 1'); t.is(result.code, 0); }); test('With glob', t => { shell.rm(`${t.context.tmp}/linkfile1`); const result = shell.ln(`${t.context.tmp}/fi*1`, `${t.context.tmp}/linkfile1`); t.truthy(fs.existsSync(`${t.context.tmp}/linkfile1`)); t.is( fs.readFileSync(`${t.context.tmp}/file1`).toString(), fs.readFileSync(`${t.context.tmp}/linkfile1`).toString() ); fs.writeFileSync(`${t.context.tmp}/file1`, 'new content 1'); t.is(fs.readFileSync(`${t.context.tmp}/linkfile1`).toString(), 'new content 1'); t.is(result.code, 0); }); test('-s option', t => { utils.skipOnWinForEPERM(shell.ln.bind(shell, '-s', 'file2', `${t.context.tmp}/linkfile2`), () => { t.truthy(fs.existsSync(`${t.context.tmp}/linkfile2`)); t.is( fs.readFileSync(`${t.context.tmp}/file2`).toString(), fs.readFileSync(`${t.context.tmp}/linkfile2`).toString() ); fs.writeFileSync(`${t.context.tmp}/file2`, 'new content 2'); t.is(fs.readFileSync(`${t.context.tmp}/linkfile2`).toString(), 'new content 2'); }); }); test('Symbolic link directory test', t => { shell.mkdir(`${t.context.tmp}/ln`); shell.touch(`${t.context.tmp}/ln/hello`); const result = shell.ln('-s', 'ln', `${t.context.tmp}/dir1`); t.truthy(fs.existsSync(`${t.context.tmp}/ln/hello`)); t.truthy(fs.existsSync(`${t.context.tmp}/dir1/hello`)); t.is(result.code, 0); }); test('To current directory', t => { shell.cd(t.context.tmp); let result = shell.ln('-s', './', 'dest'); t.is(result.code, 0); shell.touch('testfile.txt'); t.truthy(fs.existsSync('testfile.txt')); t.truthy(fs.existsSync('dest/testfile.txt')); shell.rm('-f', 'dest'); shell.mkdir('dir1'); shell.cd('dir1'); result = shell.ln('-s', './', '../dest'); t.is(result.code, 0); shell.touch('insideDir.txt'); shell.cd('..'); t.truthy(fs.existsSync('testfile.txt')); t.truthy(fs.existsSync('dest/testfile.txt')); t.truthy(fs.existsSync('dir1/insideDir.txt')); t.falsy(fs.existsSync('dest/insideDir.txt')); shell.cd('..'); }); test('-f option', t => { const result = shell.ln('-f', `${t.context.tmp}/file1.js`, `${t.context.tmp}/file2.js`); t.is(result.code, 0); t.truthy(fs.existsSync(`${t.context.tmp}/file2.js`)); t.is( fs.readFileSync(`${t.context.tmp}/file1.js`).toString(), fs.readFileSync(`${t.context.tmp}/file2.js`).toString() ); fs.writeFileSync(`${t.context.tmp}/file1.js`, 'new content js'); t.is(fs.readFileSync(`${t.context.tmp}/file2.js`).toString(), 'new content js'); }); test('-sf option', t => { utils.skipOnWinForEPERM(shell.ln.bind(shell, '-sf', 'file1.txt', `${t.context.tmp}/file2.txt`), () => { t.truthy(fs.existsSync(`${t.context.tmp}/file2.txt`)); t.is( fs.readFileSync(`${t.context.tmp}/file1.txt`).toString(), fs.readFileSync(`${t.context.tmp}/file2.txt`).toString() ); fs.writeFileSync(`${t.context.tmp}/file1.txt`, 'new content txt'); t.is(fs.readFileSync(`${t.context.tmp}/file2.txt`).toString(), 'new content txt'); }); }); test('Abspath regression', t => { utils.skipOnWinForEPERM(shell.ln.bind(shell, '-sf', 'file1', path.resolve(`${t.context.tmp}/abspath`)), () => { t.truthy(fs.existsSync(`${t.context.tmp}/abspath`)); t.is( fs.readFileSync(`${t.context.tmp}/file1`).toString(), fs.readFileSync(`${t.context.tmp}/abspath`).toString() ); fs.writeFileSync(`${t.context.tmp}/file1`, 'new content 3'); t.is(fs.readFileSync(`${t.context.tmp}/abspath`).toString(), 'new content 3'); }); }); test('Relative regression', t => { utils.skipOnWinForEPERM(shell.ln.bind(shell, '-sf', 'file1.txt', `${t.context.tmp}/file2.txt`), () => { shell.mkdir('-p', `${t.context.tmp}/new`); // Move the symlink first, as the reverse confuses `mv`. shell.mv(`${t.context.tmp}/file2.txt`, `${t.context.tmp}/new/file2.txt`); shell.mv(`${t.context.tmp}/file1.txt`, `${t.context.tmp}/new/file1.txt`); t.truthy(fs.existsSync(`${t.context.tmp}/new/file2.txt`)); t.is( fs.readFileSync(`${t.context.tmp}/new/file1.txt`).toString(), fs.readFileSync(`${t.context.tmp}/new/file2.txt`).toString() ); fs.writeFileSync(`${t.context.tmp}/new/file1.txt`, 'new content txt'); t.is(fs.readFileSync(`${t.context.tmp}/new/file2.txt`).toString(), 'new content txt'); }); });