|
| 1 | +'use strict' |
| 2 | + |
| 3 | +const fs = require('../../') |
| 4 | +const os = require('os') |
| 5 | +const path = require('path') |
| 6 | +const utimesSync = require('../../util/utimes').utimesMillisSync |
| 7 | +const assert = require('assert') |
| 8 | +const fse = require('../../index') |
| 9 | + |
| 10 | +/* global beforeEach, afterEach, describe, it */ |
| 11 | + |
| 12 | +if (process.arch === 'ia32') console.warn('32 bit arch; skipping move timestamp tests') |
| 13 | + |
| 14 | +const describeIfPractical = process.arch === 'ia32' ? describe.skip : describe |
| 15 | + |
| 16 | +describeIfPractical('move() - across different devices', () => { |
| 17 | + let TEST_DIR, SRC, DEST, FILES |
| 18 | + let __skipTests = false |
| 19 | + const differentDevicePath = '/mnt' |
| 20 | + |
| 21 | + // must set this up, if not, exit silently |
| 22 | + if (!fs.existsSync(differentDevicePath)) { |
| 23 | + console.log('Skipping cross-device move test') |
| 24 | + __skipTests = true |
| 25 | + } |
| 26 | + |
| 27 | + // make sure we have permission on device |
| 28 | + try { |
| 29 | + fs.writeFileSync(path.join(differentDevicePath, 'file'), 'hi') |
| 30 | + } catch { |
| 31 | + console.log("Can't write to device. Skipping move test.") |
| 32 | + __skipTests = true |
| 33 | + } |
| 34 | + |
| 35 | + function setupFixture (readonly) { |
| 36 | + TEST_DIR = path.join(os.tmpdir(), 'fs-extra', 'move-sync-preserve-timestamp') |
| 37 | + SRC = path.join(differentDevicePath, 'some/weird/dir-really-weird') |
| 38 | + DEST = path.join(TEST_DIR, 'dest') |
| 39 | + FILES = ['a-file', path.join('a-folder', 'another-file'), path.join('a-folder', 'another-folder', 'file3')] |
| 40 | + const timestamp = Date.now() / 1000 - 5 |
| 41 | + FILES.forEach(f => { |
| 42 | + const filePath = path.join(SRC, f) |
| 43 | + fs.ensureFileSync(filePath) |
| 44 | + // rewind timestamps to make sure that coarser OS timestamp resolution |
| 45 | + // does not alter results |
| 46 | + utimesSync(filePath, timestamp, timestamp) |
| 47 | + if (readonly) { |
| 48 | + fs.chmodSync(filePath, 0o444) |
| 49 | + } |
| 50 | + }) |
| 51 | + } |
| 52 | + |
| 53 | + const _it = __skipTests ? it.skip : it |
| 54 | + |
| 55 | + afterEach(() => { |
| 56 | + fse.removeSync(TEST_DIR) |
| 57 | + fse.removeSync(SRC) |
| 58 | + }) |
| 59 | + |
| 60 | + describe('> default behaviour', () => { |
| 61 | + ;[ |
| 62 | + { subcase: 'writable', readonly: false }, |
| 63 | + { subcase: 'readonly', readonly: true } |
| 64 | + ].forEach(params => { |
| 65 | + describe(`>> with ${params.subcase} source files`, () => { |
| 66 | + beforeEach(() => setupFixture(params.readonly)) |
| 67 | + |
| 68 | + _it('should have the same timestamps after move', done => { |
| 69 | + const originalTimestamps = FILES.map(file => { |
| 70 | + const originalPath = path.join(SRC, file) |
| 71 | + const originalStat = fs.statSync(originalPath) |
| 72 | + return { |
| 73 | + mtime: originalStat.mtime.getTime(), |
| 74 | + atime: originalStat.atime.getTime() |
| 75 | + } |
| 76 | + }) |
| 77 | + fse.move(SRC, DEST, {}, (err) => { |
| 78 | + if (err) return done(err) |
| 79 | + FILES.forEach(testFile({}, originalTimestamps)) |
| 80 | + done() |
| 81 | + }) |
| 82 | + }) |
| 83 | + }) |
| 84 | + }) |
| 85 | + }) |
| 86 | + |
| 87 | + function testFile (options, originalTimestamps) { |
| 88 | + return function (file, idx) { |
| 89 | + const originalTimestamp = originalTimestamps[idx] |
| 90 | + const currentPath = path.join(DEST, file) |
| 91 | + const currentStats = fs.statSync(currentPath) |
| 92 | + assert.strictEqual(currentStats.mtime.getTime(), originalTimestamp.mtime, 'different mtime values') |
| 93 | + assert.strictEqual(currentStats.atime.getTime(), originalTimestamp.atime, 'different atime values') |
| 94 | + } |
| 95 | + } |
| 96 | +}) |
0 commit comments