-
Notifications
You must be signed in to change notification settings - Fork 772
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Closes #523
- Loading branch information
Showing
22 changed files
with
1,716 additions
and
410 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,66 +1,76 @@ | ||
'use strict' | ||
|
||
const fs = require('fs') | ||
const fs = require(process.cwd()) | ||
const os = require('os') | ||
const path = require('path') | ||
const utimes = require('../../util/utimes') | ||
const assert = require('assert') | ||
const copySync = require('../copy-sync') | ||
const nodeVersion = process.versions.node | ||
const nodeVersionMajor = parseInt(nodeVersion.split('.')[0], 10) | ||
|
||
/* global beforeEach, describe, it */ | ||
/* global beforeEach, afterEach, describe, it */ | ||
|
||
if (process.arch === 'ia32') console.warn('32 bit arch; skipping copySync timestamp tests') | ||
if (nodeVersionMajor < 8) console.warn(`old node version (v${nodeVersion}); skipping copySync timestamp tests`) | ||
|
||
const describeIf64 = process.arch === 'ia32' ? describe.skip : describe | ||
const describeIfPractical = (process.arch === 'ia32' || nodeVersionMajor < 8) ? describe.skip : describe | ||
|
||
describeIf64('copySync', () => { | ||
let TEST_DIR | ||
describeIfPractical('copySync() - preserveTimestamps option', () => { | ||
let TEST_DIR, src, dest | ||
|
||
beforeEach(done => { | ||
TEST_DIR = path.join(os.tmpdir(), 'fs-extra', 'copy-sync-preserve-time') | ||
require(process.cwd()).emptyDir(TEST_DIR, done) | ||
fs.emptyDir(TEST_DIR, done) | ||
}) | ||
|
||
describe('> modification option', () => { | ||
const SRC_FIXTURES_DIR = path.join(__dirname, './fixtures') | ||
const FILES = ['a-file', path.join('a-folder', 'another-file'), path.join('a-folder', 'another-folder', 'file3')] | ||
afterEach(done => fs.remove(TEST_DIR, done)) | ||
|
||
describe('> when modified option is turned off', () => { | ||
it('should have different timestamps on copy', () => { | ||
const from = path.join(SRC_FIXTURES_DIR) | ||
copySync(from, TEST_DIR, {preserveTimestamps: false}) | ||
const FILES = ['a-file', path.join('a-folder', 'another-file'), path.join('a-folder', 'another-folder', 'file3')] | ||
|
||
describe('> when preserveTimestamps option is false', () => { | ||
it('should have different timestamps on copy', done => { | ||
src = path.join(TEST_DIR, 'src') | ||
dest = path.join(TEST_DIR, 'dest') | ||
FILES.forEach(f => fs.ensureFileSync(path.join(src, f))) | ||
|
||
setTimeout(() => { | ||
fs.copySync(src, dest, {preserveTimestamps: false}) | ||
FILES.forEach(testFile({preserveTimestamps: false})) | ||
}) | ||
done() | ||
}, 100) | ||
}) | ||
}) | ||
|
||
describe('> when modified option is turned on', () => { | ||
it('should have the same timestamps on copy', () => { | ||
const from = path.join(SRC_FIXTURES_DIR) | ||
copySync(from, TEST_DIR, {preserveTimestamps: true}) | ||
FILES.forEach(testFile({preserveTimestamps: true})) | ||
}) | ||
describe('> when preserveTimestamps option is true', () => { | ||
it('should have the same timestamps on copy', () => { | ||
src = path.join(TEST_DIR, 'src') | ||
dest = path.join(TEST_DIR, 'dest') | ||
FILES.forEach(f => fs.ensureFileSync(path.join(src, f))) | ||
|
||
fs.copySync(src, dest, {preserveTimestamps: true}) | ||
FILES.forEach(testFile({preserveTimestamps: true})) | ||
}) | ||
}) | ||
|
||
function testFile (options) { | ||
return function (file) { | ||
const a = path.join(SRC_FIXTURES_DIR, file) | ||
const b = path.join(TEST_DIR, file) | ||
const fromStat = fs.statSync(a) | ||
const toStat = fs.statSync(b) | ||
if (options.preserveTimestamps) { | ||
// https://github.com/nodejs/io.js/issues/2069 | ||
if (process.platform !== 'win32') { | ||
assert.strictEqual(toStat.mtime.getTime(), fromStat.mtime.getTime()) | ||
assert.strictEqual(toStat.atime.getTime(), fromStat.atime.getTime()) | ||
} else { | ||
assert.strictEqual(toStat.mtime.getTime(), utimes.timeRemoveMillis(fromStat.mtime.getTime())) | ||
assert.strictEqual(toStat.atime.getTime(), utimes.timeRemoveMillis(fromStat.atime.getTime())) | ||
} | ||
function testFile (options) { | ||
return function (file) { | ||
const a = path.join(src, file) | ||
const b = path.join(dest, file) | ||
const fromStat = fs.statSync(a) | ||
const toStat = fs.statSync(b) | ||
if (options.preserveTimestamps) { | ||
// https://github.com/nodejs/io.js/issues/2069 | ||
if (process.platform !== 'win32') { | ||
assert.strictEqual(toStat.mtime.getTime(), fromStat.mtime.getTime()) | ||
assert.strictEqual(toStat.atime.getTime(), fromStat.atime.getTime()) | ||
} else { | ||
assert.notEqual(toStat.mtime.getTime(), fromStat.mtime.getTime()) | ||
// the access time might actually be the same, so check only modification time | ||
assert.strictEqual(toStat.mtime.getTime(), utimes.timeRemoveMillis(fromStat.mtime.getTime())) | ||
assert.strictEqual(toStat.atime.getTime(), utimes.timeRemoveMillis(fromStat.atime.getTime())) | ||
} | ||
} else { | ||
assert.notEqual(toStat.mtime.getTime(), fromStat.mtime.getTime()) | ||
// the access time might actually be the same, so check only modification time | ||
} | ||
} | ||
}) | ||
} | ||
}) |
181 changes: 181 additions & 0 deletions
181
lib/copy-sync/__tests__/copy-sync-prevent-copying-identical.test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
'use strict' | ||
|
||
const assert = require('assert') | ||
const os = require('os') | ||
const path = require('path') | ||
const fs = require(process.cwd()) | ||
const klawSync = require('klaw-sync') | ||
|
||
/* global beforeEach, afterEach, describe, it */ | ||
|
||
describe('+ copySync() - prevent copying identical files and dirs', () => { | ||
let TEST_DIR = '' | ||
let src = '' | ||
let dest = '' | ||
|
||
beforeEach(done => { | ||
TEST_DIR = path.join(os.tmpdir(), 'fs-extra', 'copy-sync-prevent-copying-identical') | ||
fs.emptyDir(TEST_DIR, done) | ||
}) | ||
|
||
afterEach(done => fs.remove(TEST_DIR, done)) | ||
|
||
it('should return an error if src and dest are the same', () => { | ||
const fileSrc = path.join(TEST_DIR, 'TEST_fs-extra_copy_sync') | ||
const fileDest = path.join(TEST_DIR, 'TEST_fs-extra_copy_sync') | ||
try { | ||
fs.copySync(fileSrc, fileDest) | ||
} catch (err) { | ||
assert.equal(err.message, 'Source and destination must not be the same.') | ||
} | ||
}) | ||
|
||
// src is directory: | ||
// src is regular, dest is symlink | ||
// src is symlink, dest is regular | ||
// src is symlink, dest is symlink | ||
|
||
describe('> when the source is a directory', () => { | ||
describe(`>> when src is regular and dest is a symlink that points to src`, () => { | ||
it('should not copy and return', () => { | ||
src = path.join(TEST_DIR, 'src') | ||
fs.mkdirsSync(src) | ||
const subdir = path.join(TEST_DIR, 'src', 'subdir') | ||
fs.mkdirsSync(subdir) | ||
fs.writeFileSync(path.join(subdir, 'file.txt'), 'some data') | ||
|
||
const destLink = path.join(TEST_DIR, 'dest-symlink') | ||
fs.symlinkSync(src, destLink, 'dir') | ||
|
||
const oldlen = klawSync(src).length | ||
|
||
fs.copySync(src, destLink) | ||
|
||
const newlen = klawSync(src).length | ||
assert.strictEqual(newlen, oldlen) | ||
const link = fs.readlinkSync(destLink) | ||
assert.strictEqual(link, src) | ||
}) | ||
}) | ||
|
||
describe(`>> when src is a symlink that points to a regular dest`, () => { | ||
it('should throw error', () => { | ||
dest = path.join(TEST_DIR, 'dest') | ||
fs.mkdirsSync(dest) | ||
const subdir = path.join(TEST_DIR, 'dest', 'subdir') | ||
fs.mkdirsSync(subdir) | ||
fs.writeFileSync(path.join(subdir, 'file.txt'), 'some data') | ||
|
||
const srcLink = path.join(TEST_DIR, 'src-symlink') | ||
fs.symlinkSync(dest, srcLink, 'dir') | ||
|
||
const oldlen = klawSync(dest).length | ||
|
||
try { | ||
fs.copySync(srcLink, dest) | ||
} catch (err) { | ||
assert(err) | ||
} | ||
|
||
// assert nothing copied | ||
const newlen = klawSync(dest).length | ||
assert.strictEqual(newlen, oldlen) | ||
const link = fs.readlinkSync(srcLink) | ||
assert.strictEqual(link, dest) | ||
}) | ||
}) | ||
|
||
describe('>> when src and dest are symlinks that point to the exact same path', () => { | ||
it('should not copy and return', () => { | ||
src = path.join(TEST_DIR, 'src') | ||
fs.mkdirsSync(src) | ||
const srcLink = path.join(TEST_DIR, 'src_symlink') | ||
fs.symlinkSync(src, srcLink, 'dir') | ||
const destLink = path.join(TEST_DIR, 'dest_symlink') | ||
fs.symlinkSync(src, destLink, 'dir') | ||
|
||
const srclenBefore = klawSync(srcLink).length | ||
const destlenBefore = klawSync(destLink).length | ||
|
||
fs.copySync(srcLink, destLink) | ||
|
||
const srclenAfter = klawSync(srcLink).length | ||
assert.strictEqual(srclenAfter, srclenBefore, 'src length should not change') | ||
const destlenAfter = klawSync(destLink).length | ||
assert.strictEqual(destlenAfter, destlenBefore, 'dest length should not change') | ||
|
||
const srcln = fs.readlinkSync(srcLink) | ||
assert.strictEqual(srcln, src) | ||
const destln = fs.readlinkSync(destLink) | ||
assert.strictEqual(destln, src) | ||
}) | ||
}) | ||
}) | ||
|
||
// src is file: | ||
// src is regular, dest is symlink | ||
// src is symlink, dest is regular | ||
// src is symlink, dest is symlink | ||
|
||
describe('> when the source is a file', () => { | ||
describe(`>> when src is regular and dest is a symlink that points to src`, () => { | ||
it('should not copy and return', () => { | ||
src = path.join(TEST_DIR, 'src', 'somefile.txt') | ||
fs.ensureFileSync(src) | ||
fs.writeFileSync(src, 'some data') | ||
|
||
const destLink = path.join(TEST_DIR, 'dest-symlink') | ||
fs.symlinkSync(src, destLink, 'file') | ||
|
||
fs.copySync(src, destLink) | ||
|
||
const link = fs.readlinkSync(destLink) | ||
assert.strictEqual(link, src) | ||
assert(fs.readFileSync(link, 'utf8'), 'some data') | ||
}) | ||
}) | ||
|
||
describe(`>> when src is a symlink that points to a regular dest`, () => { | ||
it('should throw error', () => { | ||
dest = path.join(TEST_DIR, 'dest', 'somefile.txt') | ||
fs.ensureFileSync(dest) | ||
fs.writeFileSync(dest, 'some data') | ||
|
||
const srcLink = path.join(TEST_DIR, 'src-symlink') | ||
fs.symlinkSync(dest, srcLink, 'file') | ||
|
||
try { | ||
fs.copySync(srcLink, dest) | ||
} catch (err) { | ||
assert.ok(err) | ||
} | ||
const link = fs.readlinkSync(srcLink) | ||
assert.strictEqual(link, dest) | ||
assert(fs.readFileSync(link, 'utf8'), 'some data') | ||
}) | ||
}) | ||
|
||
describe('>> when src and dest are symlinks that point to the exact same path', () => { | ||
it('should not copy and return', () => { | ||
src = path.join(TEST_DIR, 'src', 'srcfile.txt') | ||
fs.ensureFileSync(src) | ||
fs.writeFileSync(src, 'src data') | ||
|
||
const srcLink = path.join(TEST_DIR, 'src_symlink') | ||
fs.symlinkSync(src, srcLink, 'file') | ||
|
||
const destLink = path.join(TEST_DIR, 'dest_symlink') | ||
fs.symlinkSync(src, destLink, 'file') | ||
|
||
fs.copySync(srcLink, destLink) | ||
|
||
const srcln = fs.readlinkSync(srcLink) | ||
assert.strictEqual(srcln, src) | ||
const destln = fs.readlinkSync(destLink) | ||
assert.strictEqual(destln, src) | ||
assert(fs.readFileSync(srcln, 'utf8'), 'src data') | ||
assert(fs.readFileSync(destln, 'utf8'), 'src data') | ||
}) | ||
}) | ||
}) | ||
}) |
Oops, something went wrong.