From 8a6beccbacf4199d1748254314b70ccbf5f669db Mon Sep 17 00:00:00 2001 From: Blaine Bublitz Date: Mon, 11 Jul 2016 15:25:37 -0700 Subject: [PATCH 1/3] Update: Refactor and reword tests --- .travis.yml | 4 +- lib/prepare-write.js | 4 +- package.json | 10 +- test/dest-modes.js | 490 ++++----- test/dest-owner.js | 80 +- test/dest-times.js | 199 ++-- test/dest.js | 1361 ++++++++++--------------- test/file-operations.js | 754 ++++++++------ test/fixtures/not-owned/not-owned.txt | 1 + test/fixtures/test.coffee | 1 - test/fixtures/test.txt | 1 + test/fixtures/wow/suchempty | 1 - test/integration.js | 52 + test/not-owned.js | 100 +- test/not-owned/not-owned.txt | 1 - test/spy.js | 32 - test/src-symlinks.js | 107 ++ test/src.js | 622 +++++------ test/symlink.js | 642 +++++------- test/utils/apply-umask.js | 11 + test/utils/cleanup.js | 17 + test/utils/is-directory-mock.js | 7 + test/utils/is-windows.js | 7 + test/utils/mock-error.js | 8 + test/utils/stat-mode.js | 15 + test/utils/test-constants.js | 66 ++ test/utils/test-streams.js | 53 + 27 files changed, 2212 insertions(+), 2434 deletions(-) create mode 100644 test/fixtures/not-owned/not-owned.txt delete mode 100644 test/fixtures/test.coffee create mode 100644 test/fixtures/test.txt delete mode 100644 test/fixtures/wow/suchempty create mode 100644 test/integration.js delete mode 100644 test/not-owned/not-owned.txt delete mode 100644 test/spy.js create mode 100644 test/src-symlinks.js create mode 100644 test/utils/apply-umask.js create mode 100644 test/utils/cleanup.js create mode 100644 test/utils/is-directory-mock.js create mode 100644 test/utils/is-windows.js create mode 100644 test/utils/mock-error.js create mode 100644 test/utils/stat-mode.js create mode 100644 test/utils/test-constants.js create mode 100644 test/utils/test-streams.js diff --git a/.travis.yml b/.travis.yml index 8b179380..0263c9c7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ node_js: - '0.10' before_script: - find test -type d -exec chmod g+s {} \; - - sudo chown root test/not-owned/ - - sudo chown root test/not-owned/not-owned.txt + - sudo chown root test/fixtures/not-owned/ + - sudo chown root test/fixtures/not-owned/not-owned.txt after_script: - npm run coveralls diff --git a/lib/prepare-write.js b/lib/prepare-write.js index dd9b03f5..734fffea 100644 --- a/lib/prepare-write.js +++ b/lib/prepare-write.js @@ -44,7 +44,9 @@ function prepareWrite(outFolder, file, opt, callback) { file.stat.mode = options.mode; file.flag = options.flag; file.cwd = cwd; - file.base = basePath; + // Ensure the base always ends with a separator + // TODO: add a test for this + file.base = path.normalize(basePath + path.sep); file.path = writePath; fo.mkdirp(writeFolder, options.dirMode, onMkdirp); diff --git a/package.json b/package.json index 66917339..8aa1b0c4 100644 --- a/package.json +++ b/package.json @@ -31,23 +31,17 @@ "vinyl": "^1.0.0" }, "devDependencies": { - "buffer-equal": "^0.0.1", - "default-resolution": "^1.0.1", "del": "^2.2.0", "eslint": "^1.10.3", "eslint-config-gulp": "^2.0.0", "expect": "^1.14.0", - "from2": "^2.1.1", "github-changes": "^1.0.1", "istanbul": "^0.3.0", "istanbul-coveralls": "^1.0.1", "jscs": "^2.4.0", "jscs-preset-gulp": "^1.0.0", - "mocha": "^2.0.0", - "mocha-lcov-reporter": "^1.0.0", - "rimraf": "^2.2.5", - "should": "^7.0.0", - "sinon": "^1.10.3" + "mississippi": "^1.2.0", + "mocha": "^2.0.0" }, "scripts": { "lint": "eslint . && jscs index.js lib/ test/", diff --git a/test/dest-modes.js b/test/dest-modes.js index 5154a327..c8df96c5 100644 --- a/test/dest-modes.js +++ b/test/dest-modes.js @@ -1,369 +1,312 @@ 'use strict'; -var os = require('os'); -var path = require('path'); - var fs = require('graceful-fs'); -var del = require('del'); var File = require('vinyl'); var expect = require('expect'); -var through = require('through2'); +var miss = require('mississippi'); var vfs = require('../'); -var constants = require('../lib/constants'); - -function wipeOut() { - this.timeout(20000); - - expect.restoreSpies(); - - // Async del to get sort-of-fix for https://github.com/isaacs/rimraf/issues/72 - return del(path.join(__dirname, './fixtures/highwatermark')) - .then(function() { - return del(path.join(__dirname, './out-fixtures/')); - }); -} - -var MASK_MODE = parseInt('7777', 8); - -function masked(mode) { - return mode & MASK_MODE; -} -var isWindows = (os.platform() === 'win32'); -var isDarwin = (os.platform() === 'darwin'); +var cleanup = require('./utils/cleanup'); +var statMode = require('./utils/stat-mode'); +var mockError = require('./utils/mock-error'); +var isWindows = require('./utils/is-windows'); +var applyUmask = require('./utils/apply-umask'); +var isDirectory = require('./utils/is-directory-mock'); +var testConstants = require('./utils/test-constants'); + +var from = miss.from; +var pipe = miss.pipe; +var concat = miss.concat; + +var inputBase = testConstants.inputBase; +var outputBase = testConstants.outputBase; +var inputPath = testConstants.inputPath; +var outputPath = testConstants.outputPath; +var inputDirpath = testConstants.inputDirpath; +var outputDirpath = testConstants.outputDirpath; +var inputNestedPath = testConstants.inputNestedPath; +var outputNestedPath = testConstants.outputNestedPath; +var contents = testConstants.contents; + +var clean = cleanup([outputBase]); describe('.dest() with custom modes', function() { - beforeEach(wipeOut); - afterEach(wipeOut); - it('should set the mode of a written buffer file if set on the vinyl object', function(done) { + beforeEach(clean); + afterEach(clean); + + it('sets the mode of a written buffer file if set on the vinyl object', function(done) { + // Changing the mode of a file is not supported by node.js in Windows. + // Windows is treated as though it does not have permission to make this operation. if (isWindows) { - console.log('Changing the mode of a file is not supported by node.js in Windows.'); - console.log('Windows is treated as though it does not have permission to make this operation.'); this.skip(); return; } - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - var inputBase = path.join(__dirname, './fixtures/'); - var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); - var expectedContents = fs.readFileSync(inputPath); - var expectedMode = parseInt('677', 8) & ~process.umask(); + var expectedMode = applyUmask('677'); - var expectedFile = new File({ + var file = new File({ base: inputBase, - cwd: __dirname, path: inputPath, - contents: expectedContents, + contents: new Buffer(contents), stat: { mode: expectedMode, }, }); - var onEnd = function() { - expect(masked(fs.lstatSync(expectedPath).mode).toString(8)).toEqual(expectedMode.toString(8)); - done(); - }; + function assert() { + expect(statMode(outputPath)).toEqual(expectedMode); + } - var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); - stream.on('end', onEnd); - stream.write(expectedFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.dest(outputBase, { cwd: __dirname }), + concat(assert), + ], done); }); - - - it('should set the sticky bit on the mode of a written stream file if set on the vinyl object', function(done) { + it('sets the sticky bit on the mode of a written stream file if set on the vinyl object', function(done) { if (isWindows) { this.skip(); return; } - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - var inputBase = path.join(__dirname, './fixtures/'); - var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); - var expectedContents = fs.readFileSync(inputPath); - var expectedMode = parseInt('1677', 8) & ~process.umask(); + var expectedMode = applyUmask('1677'); - var contentStream = through.obj(); - var expectedFile = new File({ + var file = new File({ base: inputBase, - cwd: __dirname, path: inputPath, - contents: contentStream, + contents: from([contents]), stat: { mode: expectedMode, }, }); - var onEnd = function() { - expect(masked(fs.lstatSync(expectedPath).mode).toString(8)).toEqual(expectedMode.toString(8)); - done(); - }; - - var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); - stream.on('end', onEnd); - stream.write(expectedFile); - setTimeout(function() { - contentStream.write(expectedContents); - contentStream.end(); - }, 100); - stream.end(); + function assert() { + expect(statMode(outputPath)).toEqual(expectedMode); + } + + pipe([ + from.obj([file]), + vfs.dest(outputBase, { cwd: __dirname }), + concat(assert), + ], done); }); - it('should set the mode of a written stream file if set on the vinyl object', function(done) { + it('sets the mode of a written stream file if set on the vinyl object', function(done) { if (isWindows) { this.skip(); return; } - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - var inputBase = path.join(__dirname, './fixtures/'); - var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); - var expectedContents = fs.readFileSync(inputPath); - var expectedMode = parseInt('677', 8) & ~process.umask(); + var expectedMode = applyUmask('677'); - var contentStream = through.obj(); - var expectedFile = new File({ + var file = new File({ base: inputBase, - cwd: __dirname, path: inputPath, - contents: contentStream, + contents: from([contents]), stat: { mode: expectedMode, }, }); - var onEnd = function() { - expect(masked(fs.lstatSync(expectedPath).mode).toString(8)).toEqual(expectedMode.toString(8)); - done(); - }; - - var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); - stream.on('end', onEnd); - stream.write(expectedFile); - setTimeout(function() { - contentStream.write(expectedContents); - contentStream.end(); - }, 100); - stream.end(); + function assert() { + expect(statMode(outputPath)).toEqual(expectedMode); + } + + pipe([ + from.obj([file]), + vfs.dest(outputBase, { cwd: __dirname }), + concat(assert), + ], done); }); - it('should set the mode of a written directory if set on the vinyl object', function(done) { + it('sets the mode of a written directory if set on the vinyl object', function(done) { if (isWindows) { this.skip(); return; } - var inputPath = path.join(__dirname, './fixtures/test'); - var inputBase = path.join(__dirname, './fixtures/'); - var expectedPath = path.join(__dirname, './out-fixtures/test'); - var expectedMode = parseInt('677', 8) & ~process.umask(); + var expectedMode = applyUmask('677'); - var expectedFile = new File({ + var file = new File({ base: inputBase, - cwd: __dirname, - path: inputPath, + path: inputDirpath, contents: null, stat: { - isDirectory: function() { - return true; - }, + isDirectory: isDirectory, mode: expectedMode, }, }); - var onEnd = function() { - expect(masked(fs.lstatSync(expectedPath).mode).toString(8)).toEqual(expectedMode.toString(8)); - done(); - }; + function assert() { + expect(statMode(outputDirpath)).toEqual(expectedMode); + } - var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); - stream.on('end', onEnd); - stream.write(expectedFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.dest(outputBase, { cwd: __dirname }), + concat(assert), + ], done); }); - it('should set sticky bit on the mode of a written directory if set on the vinyl object', function(done) { + it('sets sticky bit on the mode of a written directory if set on the vinyl object', function(done) { if (isWindows) { this.skip(); return; } - var inputPath = path.join(__dirname, './fixtures/test'); - var inputBase = path.join(__dirname, './fixtures/'); - var expectedPath = path.join(__dirname, './out-fixtures/test'); - var expectedMode = parseInt('1677', 8) & ~process.umask(); + var expectedMode = applyUmask('1677'); - var expectedFile = new File({ + var file = new File({ base: inputBase, - cwd: __dirname, - path: inputPath, + path: inputDirpath, contents: null, stat: { - isDirectory: function() { - return true; - }, + isDirectory: isDirectory, mode: expectedMode, }, }); - var onEnd = function() { - expect(masked(fs.lstatSync(expectedPath).mode).toString(8)).toEqual(expectedMode.toString(8)); - done(); - }; + function assert() { + expect(statMode(outputDirpath)).toEqual(expectedMode); + } - var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); - stream.on('end', onEnd); - stream.write(expectedFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.dest(outputBase, { cwd: __dirname }), + concat(assert), + ], done); }); - it('should write new files with the mode specified in options', function(done) { + it('writes new files with the mode specified in options', function(done) { if (isWindows) { this.skip(); return; } - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - var inputBase = path.join(__dirname, './fixtures/'); - var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); - var expectedContents = fs.readFileSync(inputPath); - var expectedMode = parseInt('777', 8) & ~process.umask(); + var expectedMode = applyUmask('777'); - var expectedFile = new File({ + var file = new File({ base: inputBase, - cwd: __dirname, path: inputPath, - contents: expectedContents, + contents: new Buffer(contents), }); - var onEnd = function() { - expect(masked(fs.lstatSync(expectedPath).mode).toString(8)).toEqual(expectedMode.toString(8)); - done(); - }; + function assert() { + expect(statMode(outputPath)).toEqual(expectedMode); + } - var stream = vfs.dest('./out-fixtures/', { cwd: __dirname, mode: expectedMode }); - stream.on('end', onEnd); - stream.write(expectedFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.dest(outputBase, { cwd: __dirname, mode: expectedMode }), + concat(assert), + ], done); }); - it('should update file mode to match the vinyl mode', function(done) { + it('updates the file mode to match the vinyl mode', function(done) { if (isWindows) { this.skip(); return; } - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - var inputBase = path.join(__dirname, './fixtures/'); - var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); - var expectedContents = fs.readFileSync(inputPath); - var expectedBase = path.join(__dirname, './out-fixtures'); - var startMode = parseInt('655', 8); - var expectedMode = parseInt('722', 8); + var startMode = applyUmask('655'); + var expectedMode = applyUmask('722'); - var expectedFile = new File({ + var file = new File({ base: inputBase, - cwd: __dirname, path: inputPath, - contents: expectedContents, + contents: new Buffer(contents), stat: { mode: expectedMode, }, }); - var onEnd = function() { - expect(masked(fs.lstatSync(expectedPath).mode).toString(8)).toEqual(expectedMode.toString(8)); - done(); - }; + function assert() { + expect(statMode(outputPath)).toEqual(expectedMode); + } - fs.mkdirSync(expectedBase); - fs.closeSync(fs.openSync(expectedPath, 'w')); - fs.chmodSync(expectedPath, startMode); + fs.mkdirSync(outputBase); + fs.closeSync(fs.openSync(outputPath, 'w')); + fs.chmodSync(outputPath, startMode); - var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); - stream.on('end', onEnd); - stream.write(expectedFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.dest(outputBase, { cwd: __dirname }), + concat(assert), + ], done); }); - it('should update directory mode to match the vinyl mode', function(done) { + it('updates the directory mode to match the vinyl mode', function(done) { if (isWindows) { this.skip(); return; } - var inputBase = path.join(__dirname, './fixtures/'); - var inputPath = path.join(__dirname, './fixtures/wow'); - var expectedPath = path.join(__dirname, './out-fixtures/wow'); - var expectedBase = path.join(__dirname, './out-fixtures'); + var startMode = applyUmask('2777'); + var expectedMode = applyUmask('727'); - var firstFile = new File({ + var file1 = new File({ base: inputBase, - cwd: __dirname, - path: expectedPath, - stat: fs.statSync(inputPath), + path: outputDirpath, + stat: { + isDirectory: isDirectory, + mode: startMode, + }, + }); + var file2 = new File({ + base: inputBase, + path: outputDirpath, + stat: { + isDirectory: isDirectory, + mode: expectedMode, + }, }); - var startMode = firstFile.stat.mode; - var expectedMode = parseInt('727', 8); - - var expectedFile = new File(firstFile); - expectedFile.stat.mode = (startMode & ~parseInt('7777', 8)) | expectedMode; - - var onEnd = function() { - expect(masked(fs.lstatSync(expectedPath).mode).toString(8)).toEqual(expectedMode.toString(8)); - done(); - }; - fs.mkdirSync(expectedBase); + function assert() { + expect(statMode(outputDirpath)).toEqual(expectedMode); + } - var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); - stream.on('end', onEnd); - stream.write(firstFile); - stream.write(expectedFile); - stream.end(); + pipe([ + from.obj([file1, file2]), + vfs.dest(outputBase, { cwd: __dirname }), + concat(assert), + ], done); }); - it('should use different modes for files and directories', function(done) { + it('uses different modes for files and directories', function(done) { if (isWindows) { this.skip(); return; } - var inputBase = path.join(__dirname, './fixtures'); - var inputPath = path.join(__dirname, './fixtures/wow/suchempty'); - var expectedBase = path.join(__dirname, './out-fixtures/wow'); - var expectedPath = path.join(__dirname, './out-fixtures/wow/suchempty'); - var expectedDirMode = parseInt('2777', 8) & ~process.umask(); - var expectedFileMode = constants.DEFAULT_FILE_MODE & ~process.umask(); + var expectedDirMode = applyUmask('2777'); + var expectedFileMode = applyUmask('755'); - var firstFile = new File({ + var file = new File({ base: inputBase, - cwd: __dirname, - path: inputPath, - contents: fs.readFileSync(inputPath), - stat: fs.statSync(inputPath), + path: inputNestedPath, + contents: new Buffer(contents), }); - var onEnd = function() { - expect(masked(fs.lstatSync(expectedBase).mode).toString(8)).toEqual(expectedDirMode.toString(8)); - expect(masked(fs.lstatSync(expectedPath).mode).toString(8)).toEqual(expectedFileMode.toString(8)); - done(); - }; + function assert() { + expect(statMode(outputDirpath)).toEqual(expectedDirMode); + expect(statMode(outputNestedPath)).toEqual(expectedFileMode); + } - var stream = vfs.dest('./out-fixtures/', { - cwd: __dirname, - mode: expectedFileMode, - dirMode: expectedDirMode, - }); - stream.on('end', onEnd); - stream.write(firstFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.dest(outputBase, { + cwd: __dirname, + mode: expectedFileMode, + dirMode: expectedDirMode, + }), + concat(assert), + ], done); }); - it('should not fchmod a matching file', function(done) { + it('does not fchmod a matching file', function(done) { if (isWindows) { this.skip(); return; @@ -371,35 +314,30 @@ describe('.dest() with custom modes', function() { var fchmodSpy = expect.spyOn(fs, 'fchmod').andCallThrough(); - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - var inputBase = path.join(__dirname, './fixtures/'); - var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); - var expectedContents = fs.readFileSync(inputPath); - var expectedMode = parseInt('777', 8) & ~process.umask(); + var expectedMode = applyUmask('777'); - var expectedFile = new File({ + var file = new File({ base: inputBase, - cwd: __dirname, path: inputPath, - contents: expectedContents, + contents: new Buffer(contents), stat: { mode: expectedMode, }, }); - var onEnd = function() { + function assert() { expect(fchmodSpy.calls.length).toEqual(0); - expect(masked(fs.lstatSync(expectedPath).mode).toString(8)).toEqual(expectedMode.toString(8)); - done(); - }; + expect(statMode(outputPath)).toEqual(expectedMode); + } - var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); - stream.on('end', onEnd); - stream.write(expectedFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.dest(outputBase, { cwd: __dirname }), + concat(assert), + ], done); }); - it('should see a file with special chmod (setuid/setgid/sticky) as distinct', function(done) { + it('sees a file with special chmod (setuid/setgid/sticky) as distinct', function(done) { if (isWindows) { this.skip(); return; @@ -407,76 +345,64 @@ describe('.dest() with custom modes', function() { var fchmodSpy = expect.spyOn(fs, 'fchmod').andCallThrough(); - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - var inputBase = path.join(__dirname, './fixtures/'); - var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); - var expectedContents = fs.readFileSync(inputPath); - var expectedBase = path.join(__dirname, './out-fixtures'); - var expectedMode = parseInt('3722', 8); - var normalMode = parseInt('722', 8); + var startMode = applyUmask('3722'); + var expectedMode = applyUmask('722'); - var expectedFile = new File({ + var file = new File({ base: inputBase, - cwd: __dirname, path: inputPath, - contents: expectedContents, + contents: new Buffer(contents), stat: { - mode: normalMode, + mode: expectedMode, }, }); - var onEnd = function() { + function assert() { expect(fchmodSpy.calls.length).toEqual(1); - done(); - }; + } - fs.mkdirSync(expectedBase); - fs.closeSync(fs.openSync(expectedPath, 'w')); - fs.chmodSync(expectedPath, expectedMode); + fs.mkdirSync(outputBase); + fs.closeSync(fs.openSync(outputPath, 'w')); + fs.chmodSync(outputPath, startMode); - var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); - stream.on('end', onEnd); - stream.write(expectedFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.dest(outputBase, { cwd: __dirname }), + concat(assert), + ], done); }); - it('should report fchmod errors', function(done) { + it('reports fchmod errors', function(done) { if (isWindows) { this.skip(); return; } - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - var inputBase = path.join(__dirname, './fixtures/'); - var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); - var expectedContents = fs.readFileSync(inputPath); - var expectedBase = path.join(__dirname, './out-fixtures'); - var expectedMode = parseInt('722', 8); + var expectedMode = applyUmask('722'); - var fchmodSpy = expect.spyOn(fs, 'fchmod').andCall(function() { - var callback = arguments[arguments.length - 1]; - callback(new Error('mocked error')); - }); + var fchmodSpy = expect.spyOn(fs, 'fchmod').andCall(mockError); - var expectedFile = new File({ + var file = new File({ base: inputBase, - cwd: __dirname, path: inputPath, - contents: expectedContents, + contents: new Buffer(contents), stat: { mode: expectedMode, }, }); - fs.mkdirSync(expectedBase); - fs.closeSync(fs.openSync(expectedPath, 'w')); - - var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); - stream.on('error', function(err) { + function assert(err) { expect(err).toExist(); expect(fchmodSpy.calls.length).toEqual(1); done(); - }); - stream.write(expectedFile); + } + + fs.mkdirSync(outputBase); + fs.closeSync(fs.openSync(outputPath, 'w')); + + pipe([ + from.obj([file]), + vfs.dest(outputBase, { cwd: __dirname }), + ], assert); }); }); diff --git a/test/dest-owner.js b/test/dest-owner.js index 3705c81b..7ee03f16 100644 --- a/test/dest-owner.js +++ b/test/dest-owner.js @@ -1,99 +1,89 @@ 'use strict'; -var os = require('os'); -var path = require('path'); - var fs = require('graceful-fs'); -var del = require('del'); var File = require('vinyl'); var expect = require('expect'); +var miss = require('mississippi'); var vfs = require('../'); -function wipeOut() { - this.timeout(20000); +var cleanup = require('./utils/cleanup'); +var isWindows = require('./utils/is-windows'); +var testConstants = require('./utils/test-constants'); - expect.restoreSpies(); +var from = miss.from; +var pipe = miss.pipe; +var concat = miss.concat; - // Async del to get sort-of-fix for https://github.com/isaacs/rimraf/issues/72 - return del(path.join(__dirname, './out-fixtures/')); -} +var inputBase = testConstants.inputBase; +var outputBase = testConstants.outputBase; +var inputPath = testConstants.inputPath; +var contents = testConstants.contents; -var isWindows = (os.platform() === 'win32'); +var clean = cleanup([outputBase]); describe('.dest() with custom owner', function() { - beforeEach(wipeOut); - afterEach(wipeOut); - it('should call fchown when the uid and/or gid are provided on the vinyl stat', function(done) { + beforeEach(clean); + afterEach(clean); + + it('calls fchown when the uid and/or gid are provided on the vinyl stat', function(done) { if (isWindows) { this.skip(); return; } - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - var inputBase = path.join(__dirname, './fixtures/'); - var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); - var expectedContents = fs.readFileSync(inputPath); - var fchownSpy = expect.spyOn(fs, 'fchown').andCallThrough(); - var expectedFile = new File({ + var file = new File({ base: inputBase, - cwd: __dirname, path: inputPath, - contents: expectedContents, + contents: new Buffer(contents), stat: { uid: 1001, gid: 1001, }, }); - var onEnd = function() { + function assert() { expect(fchownSpy.calls.length).toEqual(1); expect(fchownSpy.calls[0].arguments[1]).toEqual(1001); expect(fchownSpy.calls[0].arguments[2]).toEqual(1001); - done(); - }; + } - var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); - stream.on('end', onEnd); - stream.write(expectedFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.dest(outputBase), + concat(assert), + ], done); }); - it('should not call fchown when the uid and gid provided on the vinyl stat are invalid', function(done) { + it('does not call fchown when the uid and gid provided on the vinyl stat are invalid', function(done) { if (isWindows) { this.skip(); return; } - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - var inputBase = path.join(__dirname, './fixtures/'); - var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); - var expectedContents = fs.readFileSync(inputPath); - var fchownSpy = expect.spyOn(fs, 'fchown').andCallThrough(); - var expectedFile = new File({ + var file = new File({ base: inputBase, - cwd: __dirname, path: inputPath, - contents: expectedContents, + contents: new Buffer(contents), stat: { uid: -1, gid: -1, }, }); - var onEnd = function() { + function assert() { expect(fchownSpy.calls.length).toEqual(0); - done(); - }; + } - var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); - stream.on('end', onEnd); - stream.write(expectedFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.dest(outputBase), + concat(assert), + ], done); }); }); diff --git a/test/dest-times.js b/test/dest-times.js index 5829e845..d95b2efc 100644 --- a/test/dest-times.js +++ b/test/dest-times.js @@ -1,223 +1,204 @@ 'use strict'; -var os = require('os'); -var path = require('path'); - var fs = require('graceful-fs'); -var del = require('del'); var File = require('vinyl'); var expect = require('expect'); +var miss = require('mississippi'); var vfs = require('../'); -function wipeOut() { - this.timeout(20000); +var cleanup = require('./utils/cleanup'); +var isWindows = require('./utils/is-windows'); +var testConstants = require('./utils/test-constants'); - expect.restoreSpies(); +var from = miss.from; +var pipe = miss.pipe; +var concat = miss.concat; - // Async del to get sort-of-fix for https://github.com/isaacs/rimraf/issues/72 - return del(path.join(__dirname, './out-fixtures/')); -} +var inputBase = testConstants.inputBase; +var outputBase = testConstants.outputBase; +var inputPath = testConstants.inputPath; +var outputPath = testConstants.outputPath; +var contents = testConstants.contents; -var isWindows = (os.platform() === 'win32'); +var clean = cleanup([outputBase]); describe('.dest() with custom times', function() { - beforeEach(wipeOut); - afterEach(wipeOut); - it('should not call futimes when no mtime is provided on the vinyl stat', function(done) { + beforeEach(clean); + afterEach(clean); + + it('does not call futimes when no mtime is provided on the vinyl stat', function(done) { + // Changing the time of a directory errors in Windows. + // Windows is treated as though it does not have permission to make this operation. if (isWindows) { - console.log('Changing the time of a directory errors in Windows.'); - console.log('Windows is treated as though it does not have permission to make this operation.'); this.skip(); return; } - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - var inputBase = path.join(__dirname, './fixtures/'); - var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); - var expectedContents = fs.readFileSync(inputPath); var earlier = Date.now() - 1001; var futimesSpy = expect.spyOn(fs, 'futimes').andCallThrough(); - var expectedFile = new File({ + var file = new File({ base: inputBase, - cwd: __dirname, path: inputPath, - contents: expectedContents, + contents: new Buffer(contents), stat: {}, }); - var onEnd = function() { - var stats = fs.lstatSync(expectedPath); + function assert() { + var stats = fs.lstatSync(outputPath); expect(futimesSpy.calls.length).toEqual(0); expect(stats.atime.getTime()).toBeGreaterThan(earlier); expect(stats.mtime.getTime()).toBeGreaterThan(earlier); - done(); - }; + } - var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); - stream.on('end', onEnd); - stream.write(expectedFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.dest(outputBase, { cwd: __dirname }), + concat(assert), + ], done); }); - it('should call futimes when an mtime is provided on the vinyl stat', function(done) { + it('calls futimes when an mtime is provided on the vinyl stat', function(done) { if (isWindows) { this.skip(); return; } - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - var inputBase = path.join(__dirname, './fixtures/'); - var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); - var expectedContents = fs.readFileSync(inputPath); - var expectedMtime = fs.lstatSync(inputPath).mtime; + // Use the mtime of this file to have proper resolution + var mtime = fs.statSync(__filename).mtime; var futimesSpy = expect.spyOn(fs, 'futimes').andCallThrough(); - var expectedFile = new File({ + var file = new File({ base: inputBase, - cwd: __dirname, path: inputPath, - contents: expectedContents, + contents: new Buffer(contents), stat: { - mtime: expectedMtime, + mtime: mtime, }, }); - var onEnd = function() { - var stats = fs.lstatSync(expectedPath); + function assert() { + var stats = fs.lstatSync(outputPath); expect(futimesSpy.calls.length).toEqual(1); - expect(stats.mtime.getTime()).toEqual(expectedMtime.getTime()); - expect(expectedFile.stat.mtime).toEqual(expectedMtime); - done(); - }; + expect(stats.mtime.getTime()).toEqual(mtime.getTime()); + expect(file.stat.mtime).toEqual(mtime); + } - var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); - stream.on('end', onEnd); - stream.write(expectedFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.dest(outputBase, { cwd: __dirname }), + concat(assert), + ], done); }); - it('should not call futimes when provided mtime on the vinyl stat is invalid', function(done) { + it('does not call futimes when provided mtime on the vinyl stat is invalid', function(done) { if (isWindows) { this.skip(); return; } - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - var inputBase = path.join(__dirname, './fixtures/'); - var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); - var expectedContents = fs.readFileSync(inputPath); var earlier = Date.now() - 1001; var futimesSpy = expect.spyOn(fs, 'futimes').andCallThrough(); - var expectedFile = new File({ + var file = new File({ base: inputBase, - cwd: __dirname, path: inputPath, - contents: expectedContents, + contents: new Buffer(contents), stat: { mtime: new Date(undefined), }, }); - var onEnd = function() { - var stats = fs.lstatSync(expectedPath); + function assert() { + var stats = fs.lstatSync(outputPath); expect(futimesSpy.calls.length).toEqual(0); expect(stats.mtime.getTime()).toBeGreaterThan(earlier); - done(); - }; + } - var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); - stream.on('end', onEnd); - stream.write(expectedFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.dest(outputBase, { cwd: __dirname }), + concat(assert), + ], done); }); - it('should call futimes when provided mtime on the vinyl stat is valid but provided atime is invalid', function(done) { + it('calls futimes when provided mtime on the vinyl stat is valid but provided atime is invalid', function(done) { if (isWindows) { this.skip(); return; } - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - var inputBase = path.join(__dirname, './fixtures/'); - var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); - var expectedContents = fs.readFileSync(inputPath); - var expectedMtime = fs.lstatSync(inputPath).mtime; + // Use the mtime of this file to have proper resolution + var mtime = fs.lstatSync(__filename).mtime; var invalidAtime = new Date(undefined); var futimesSpy = expect.spyOn(fs, 'futimes').andCallThrough(); - var expectedFile = new File({ + var file = new File({ base: inputBase, - cwd: __dirname, path: inputPath, - contents: expectedContents, + contents: new Buffer(contents), stat: { atime: invalidAtime, - mtime: expectedMtime, + mtime: mtime, }, }); - var onEnd = function() { - var stats = fs.lstatSync(expectedPath); + function assert() { + var stats = fs.lstatSync(outputPath); expect(futimesSpy.calls.length).toEqual(1); - expect(stats.mtime.getTime()).toEqual(expectedMtime.getTime()); - done(); - }; + expect(stats.mtime.getTime()).toEqual(mtime.getTime()); + } - var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); - stream.on('end', onEnd); - stream.write(expectedFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.dest(outputBase, { cwd: __dirname }), + concat(assert), + ], done); }); - it('should write file atime and mtime using the vinyl stat', function(done) { + it('writes file atime and mtime using the vinyl stat', function(done) { if (isWindows) { this.skip(); return; } - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - var inputBase = path.join(__dirname, './fixtures/'); - var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); - var expectedContents = fs.readFileSync(inputPath); - var expectedAtime = fs.lstatSync(inputPath).atime; - var expectedMtime = fs.lstatSync(inputPath).mtime; + // Use the atime/mtime of this file to have proper resolution + var atime = fs.lstatSync(__filename).atime; + var mtime = fs.lstatSync(__filename).mtime; - var expectedFile = new File({ + var file = new File({ base: inputBase, - cwd: __dirname, path: inputPath, - contents: expectedContents, + contents: new Buffer(contents), stat: { - atime: expectedAtime, - mtime: expectedMtime, + atime: atime, + mtime: mtime, }, }); - var onEnd = function() { - var stats = fs.lstatSync(expectedPath); + function assert() { + var stats = fs.lstatSync(outputPath); - expect(stats.atime.getTime()).toEqual(expectedAtime.getTime()); - expect(stats.mtime.getTime()).toEqual(expectedMtime.getTime()); - expect(expectedFile.stat.mtime).toEqual(expectedMtime); - expect(expectedFile.stat.atime).toEqual(expectedAtime); - done(); + expect(stats.atime.getTime()).toEqual(atime.getTime()); + expect(stats.mtime.getTime()).toEqual(mtime.getTime()); + expect(file.stat.mtime).toEqual(mtime); + expect(file.stat.atime).toEqual(atime); }; - var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); - stream.on('end', onEnd); - stream.write(expectedFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.dest(outputBase, { cwd: __dirname }), + concat(assert), + ], done); }); }); diff --git a/test/dest.js b/test/dest.js index 0705ca2a..d0802f69 100644 --- a/test/dest.js +++ b/test/dest.js @@ -1,858 +1,649 @@ 'use strict'; -var spies = require('./spy'); -var chmodSpy = spies.chmodSpy; -var fchmodSpy = spies.fchmodSpy; -var futimesSpy = spies.futimesSpy; -var fstatSpy = spies.fstatSpy; - -var vfs = require('../'); - -var os = require('os'); var path = require('path'); + var fs = require('graceful-fs'); -var del = require('del'); -var Writeable = require('readable-stream/writable'); +var File = require('vinyl'); var expect = require('expect'); +var miss = require('mississippi'); -var bufEqual = require('buffer-equal'); -var through = require('through2'); -var File = require('vinyl'); -var from = require('from2'); - -var should = require('should'); -require('mocha'); - -var wipeOut = function() { - this.timeout(20000); - spies.setError('false'); - fstatSpy.reset(); - chmodSpy.reset(); - fchmodSpy.reset(); - futimesSpy.reset(); - expect.restoreSpies(); - - // Async del to get sort-of-fix for https://github.com/isaacs/rimraf/issues/72 - return del(path.join(__dirname, './fixtures/highwatermark')) - .then(function() { - return del(path.join(__dirname, './out-fixtures/')); - }); -}; +var vfs = require('../'); + +var cleanup = require('./utils/cleanup'); +var statMode = require('./utils/stat-mode'); +var mockError = require('./utils/mock-error'); +var applyUmask = require('./utils/apply-umask'); +var testStreams = require('./utils/test-streams'); +var isDirectory = require('./utils/is-directory-mock'); +var testConstants = require('./utils/test-constants'); -var dataWrap = function(fn) { - return function(data, enc, cb) { - fn(data); - cb(); - }; -}; +var from = miss.from; +var pipe = miss.pipe; +var concat = miss.concat; -var realMode = function(n) { - return n & parseInt('777', 8); -}; +var count = testStreams.count; +var rename = testStreams.rename; +var includes = testStreams.includes; +var slowCount = testStreams.slowCount; function noop() {} -describe('dest stream', function() { - beforeEach(wipeOut); - afterEach(wipeOut); +var outputRelative = testConstants.outputRelative; +var inputBase = testConstants.inputBase; +var outputBase = testConstants.outputBase; +var inputPath = testConstants.inputPath; +var outputPath = testConstants.outputPath; +var outputRenamePath = testConstants.outputRenamePath; +var inputDirpath = testConstants.inputDirpath; +var outputDirpath = testConstants.outputDirpath; +var contents = testConstants.contents; - it.skip('should explode on invalid folder (empty)', function(done) { +var clean = cleanup([outputBase]); + +describe('.dest()', function() { + + beforeEach(clean); + afterEach(clean); + + // TODO: make this work correctly + it.skip('throws on invalid folder (empty)', function(done) { var stream; try { stream = vfs.dest(); } catch (err) { - should.exist(err); - should.not.exist(stream); + expect(err).toExist(); + expect(stream).toNotExist(); done(); } }); - it.skip('should explode on invalid folder (empty string)', function(done) { + // TODO: make this work correctly + it.skip('throws on invalid folder (empty string)', function(done) { var stream; try { stream = vfs.dest(''); } catch (err) { - should.exist(err); - should.not.exist(stream); + expect(err).toExist(); + expect(stream).toNotExist(); done(); } }); - it('should not explode if the sourcemap option is true', function(done) { - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - - var expectedFile = new File({ - base: __dirname, - cwd: __dirname, + it('accepts the sourcemap option as true', function(done) { + var file = new File({ + base: inputBase, path: inputPath, contents: null, }); - var buffered = []; - - var onEnd = function() { - buffered.length.should.equal(1); - buffered[0].should.equal(expectedFile); - done(); - }; - - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); + function assert(files) { + expect(files.length).toEqual(1); + expect(files).toInclude(file); + } - var stream = vfs.dest(path.join(__dirname, './out-fixtures/'), { sourcemaps: true }); - stream.pipe(bufferStream); - stream.write(expectedFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.dest(outputBase, { sourcemaps: true }), + concat(assert), + ], done); }); - it('should not explode if the sourcemap option is string', function(done) { - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - - var expectedFile = new File({ - base: __dirname, - cwd: __dirname, + it('accepts the sourcemap option as a string', function(done) { + var file = new File({ + base: inputBase, path: inputPath, contents: null, }); - var buffered = []; - - var onEnd = function() { - buffered.length.should.equal(1); - buffered[0].should.equal(expectedFile); - done(); - }; - - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); + function assert(files) { + expect(files.length).toEqual(1); + expect(files).toInclude(file); + } - var stream = vfs.dest(path.join(__dirname, './out-fixtures/'), { sourcemaps: '.' }); - stream.pipe(bufferStream); - stream.write(expectedFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.dest(outputBase, { sourcemaps: '.' }), + concat(assert), + ], done); }); - it('should not explode if sourcemap option is an object', function(done) { - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - + it('accepts the sourcemap option as an object', function(done) { var options = { sourcemaps: { addComment: false, }, }; - var expectedFile = new File({ - base: __dirname, - cwd: __dirname, + var file = new File({ + base: inputBase, path: inputPath, contents: null, }); - var buffered = []; - - var onEnd = function() { - buffered.length.should.equal(1); - buffered[0].should.equal(expectedFile); - done(); - }; - - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); + function assert(files) { + expect(files.length).toEqual(1); + expect(files).toInclude(file); + } - var stream = vfs.dest(path.join(__dirname, './out-fixtures/'), options); - stream.pipe(bufferStream); - stream.write(expectedFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.dest(outputBase, options), + concat(assert), + ], done); }); - it('should pass through writes with cwd', function(done) { - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - - var expectedFile = new File({ - base: __dirname, - cwd: __dirname, + it('passes through writes with cwd', function(done) { + var file = new File({ + base: inputBase, path: inputPath, contents: null, }); - var buffered = []; - - var onEnd = function() { - buffered.length.should.equal(1); - buffered[0].should.equal(expectedFile); - done(); - }; - - var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); + function assert(files) { + expect(files.length).toEqual(1); + expect(files).toInclude(file); + expect(files[0].cwd).toEqual(__dirname, 'cwd should have changed'); + } - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); - stream.pipe(bufferStream); - stream.write(expectedFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.dest(outputRelative, { cwd: __dirname }), + concat(assert), + ], done); }); - it('should pass through writes with default cwd', function(done) { - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - - var expectedFile = new File({ - base: __dirname, - cwd: __dirname, + it('passes through writes with default cwd', function(done) { + var file = new File({ + base: inputBase, path: inputPath, contents: null, }); - var buffered = []; - - var onEnd = function() { - buffered.length.should.equal(1); - buffered[0].should.equal(expectedFile); - done(); - }; - - var stream = vfs.dest(path.join(__dirname, './out-fixtures/')); + function assert(files) { + expect(files.length).toEqual(1); + expect(files).toInclude(file); + expect(files[0].cwd).toEqual(process.cwd(), 'cwd should not have changed'); + } - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); - stream.pipe(bufferStream); - stream.write(expectedFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.dest(outputBase), + concat(assert), + ], done); }); - it('should not write null files', function(done) { - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - var inputBase = path.join(__dirname, './fixtures/'); - var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); - var expectedCwd = __dirname; - var expectedBase = path.join(__dirname, './out-fixtures'); - - var expectedFile = new File({ + it('does not write null files', function(done) { + var file = new File({ base: inputBase, - cwd: __dirname, path: inputPath, contents: null, }); - var buffered = []; + function assert(files) { + var exists = fs.existsSync(outputPath); - var onEnd = function() { - buffered.length.should.equal(1); - buffered[0].should.equal(expectedFile); - buffered[0].cwd.should.equal(expectedCwd, 'cwd should have changed'); - buffered[0].base.should.equal(expectedBase, 'base should have changed'); - buffered[0].path.should.equal(expectedPath, 'path should have changed'); - fs.existsSync(expectedPath).should.equal(false); - done(); + expect(files.length).toEqual(1); + expect(files).toInclude(file); + expect(files[0].base).toEqual(outputBase, 'base should have changed'); + expect(files[0].path).toEqual(outputPath, 'path should have changed'); + expect(exists).toEqual(false); }; - var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); - - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); - stream.pipe(bufferStream); - stream.write(expectedFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.dest(outputBase), + concat(assert), + ], done); }); - it('should write buffer files to the right folder with relative cwd', function(done) { - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - var inputBase = path.join(__dirname, './fixtures/'); - var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); - var expectedCwd = __dirname; - var expectedBase = path.join(__dirname, './out-fixtures'); - var expectedContents = fs.readFileSync(inputPath); + it('writes buffer files to the right folder with relative cwd', function(done) { + var cwd = path.relative(process.cwd(), __dirname); - var expectedFile = new File({ + var file = new File({ base: inputBase, - cwd: __dirname, path: inputPath, - contents: expectedContents, + contents: new Buffer(contents), }); - var buffered = []; - - var onEnd = function() { - buffered.length.should.equal(1); - buffered[0].should.equal(expectedFile); - buffered[0].cwd.should.equal(expectedCwd, 'cwd should have changed'); - buffered[0].base.should.equal(expectedBase, 'base should have changed'); - buffered[0].path.should.equal(expectedPath, 'path should have changed'); - fs.existsSync(expectedPath).should.equal(true); - bufEqual(fs.readFileSync(expectedPath), expectedContents).should.equal(true); - done(); - }; + function assert(files) { + var outputContents = fs.readFileSync(outputPath, 'utf8'); - var stream = vfs.dest('./out-fixtures/', { cwd: path.relative(process.cwd(), __dirname) }); + expect(files.length).toEqual(1); + expect(files).toInclude(file); + expect(files[0].cwd).toEqual(__dirname, 'cwd should have changed'); + expect(files[0].base).toEqual(outputBase, 'base should have changed'); + expect(files[0].path).toEqual(outputPath, 'path should have changed'); + expect(outputContents).toEqual(contents); + } - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); - stream.pipe(bufferStream); - stream.write(expectedFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.dest(outputRelative, { cwd: cwd }), + concat(assert), + ], done); }); - it('should write buffer files to the right folder with function and relative cwd', function(done) { - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - var inputBase = path.join(__dirname, './fixtures/'); - var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); - var expectedCwd = __dirname; - var expectedBase = path.join(__dirname, './out-fixtures'); - var expectedContents = fs.readFileSync(inputPath); + it('writes buffer files to the right folder with function and relative cwd', function(done) { + var cwd = path.relative(process.cwd(), __dirname); - var expectedFile = new File({ + var file = new File({ base: inputBase, - cwd: __dirname, path: inputPath, - contents: expectedContents, + contents: new Buffer(contents), }); - var buffered = []; + function outputFn(f) { + expect(f).toExist(); + expect(f).toExist(file); + return outputRelative; + } - var onEnd = function() { - buffered.length.should.equal(1); - buffered[0].should.equal(expectedFile); - buffered[0].cwd.should.equal(expectedCwd, 'cwd should have changed'); - buffered[0].base.should.equal(expectedBase, 'base should have changed'); - buffered[0].path.should.equal(expectedPath, 'path should have changed'); - fs.existsSync(expectedPath).should.equal(true); - bufEqual(fs.readFileSync(expectedPath), expectedContents).should.equal(true); - done(); - }; + function assert(files) { + var outputContents = fs.readFileSync(outputPath, 'utf8'); - var stream = vfs.dest(function(file) { - should.exist(file); - file.should.equal(expectedFile); - return './out-fixtures'; - }, { cwd: path.relative(process.cwd(), __dirname) }); + expect(files.length).toEqual(1); + expect(files).toInclude(file); + expect(files[0].cwd).toEqual(__dirname, 'cwd should have changed'); + expect(files[0].base).toEqual(outputBase, 'base should have changed'); + expect(files[0].path).toEqual(outputPath, 'path should have changed'); + expect(outputContents).toEqual(contents); + } - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); - stream.pipe(bufferStream); - stream.write(expectedFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.dest(outputFn, { cwd: cwd }), + concat(assert), + ], done); }); - it('should write buffer files to the right folder', function(done) { - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - var inputBase = path.join(__dirname, './fixtures/'); - var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); - var expectedContents = fs.readFileSync(inputPath); - var expectedCwd = __dirname; - var expectedBase = path.join(__dirname, './out-fixtures'); - - var expectedFile = new File({ + it('writes buffer files to the right folder', function(done) { + var file = new File({ base: inputBase, - cwd: __dirname, path: inputPath, - contents: expectedContents, + contents: new Buffer(contents), }); - var buffered = []; + function assert(files) { + var outputContents = fs.readFileSync(outputPath, 'utf8'); - var onEnd = function() { - buffered.length.should.equal(1); - buffered[0].should.equal(expectedFile); - buffered[0].cwd.should.equal(expectedCwd, 'cwd should have changed'); - buffered[0].base.should.equal(expectedBase, 'base should have changed'); - buffered[0].path.should.equal(expectedPath, 'path should have changed'); - fs.existsSync(expectedPath).should.equal(true); - bufEqual(fs.readFileSync(expectedPath), expectedContents).should.equal(true); - done(); - }; - - var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); + expect(files.length).toEqual(1); + expect(files).toInclude(file); + expect(files[0].base).toEqual(outputBase, 'base should have changed'); + expect(files[0].path).toEqual(outputPath, 'path should have changed'); + expect(outputContents).toEqual(contents); + } - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); - stream.pipe(bufferStream); - stream.write(expectedFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.dest(outputBase), + concat(assert), + ], done); }); - it('should write streaming files to the right folder', function(done) { - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - var inputBase = path.join(__dirname, './fixtures/'); - var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); - var expectedContents = fs.readFileSync(inputPath); - var expectedCwd = __dirname; - var expectedBase = path.join(__dirname, './out-fixtures'); - - var contentStream = through.obj(); - var expectedFile = new File({ + it('writes streaming files to the right folder', function(done) { + var file = new File({ base: inputBase, - cwd: __dirname, path: inputPath, - contents: contentStream, + contents: from([contents]), }); - var buffered = []; + function assert(files) { + var outputContents = fs.readFileSync(outputPath, 'utf8'); - var onEnd = function() { - buffered.length.should.equal(1); - buffered[0].should.equal(expectedFile); - buffered[0].cwd.should.equal(expectedCwd, 'cwd should have changed'); - buffered[0].base.should.equal(expectedBase, 'base should have changed'); - buffered[0].path.should.equal(expectedPath, 'path should have changed'); - fs.existsSync(expectedPath).should.equal(true); - bufEqual(fs.readFileSync(expectedPath), expectedContents).should.equal(true); - done(); + expect(files.length).toEqual(1); + expect(files).toInclude(file); + expect(files[0].base).toEqual(outputBase, 'base should have changed'); + expect(files[0].path).toEqual(outputPath, 'path should have changed'); + expect(outputContents).toEqual(contents); }; - var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); - - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered))); - bufferStream.on('finish', onEnd); - stream.pipe(bufferStream); - stream.write(expectedFile); - setTimeout(function() { - contentStream.write(expectedContents); - contentStream.end(); - }, 100); - stream.end(); + pipe([ + from.obj([file]), + vfs.dest(outputBase), + concat(assert), + ], done); }); - it('should write directories to the right folder', function(done) { - var inputPath = path.join(__dirname, './fixtures/test'); - var inputBase = path.join(__dirname, './fixtures/'); - var expectedPath = path.join(__dirname, './out-fixtures/test'); - var expectedCwd = __dirname; - var expectedBase = path.join(__dirname, './out-fixtures'); - - var expectedFile = new File({ + it('writes directories to the right folder', function(done) { + var file = new File({ base: inputBase, - cwd: __dirname, - path: inputPath, + path: inputDirpath, contents: null, stat: { - isDirectory: function() { - return true; - }, + isDirectory: isDirectory, }, }); - var buffered = []; - - var onEnd = function() { - buffered.length.should.equal(1); - buffered[0].should.equal(expectedFile); - buffered[0].cwd.should.equal(expectedCwd, 'cwd should have changed'); - buffered[0].base.should.equal(expectedBase, 'base should have changed'); - buffered[0].path.should.equal(expectedPath, 'path should have changed'); - fs.existsSync(expectedPath).should.equal(true); - fs.lstatSync(expectedPath).isDirectory().should.equal(true); - done(); - }; + function assert(files) { + var stats = fs.lstatSync(outputDirpath); - var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); + expect(files.length).toEqual(1); + expect(files).toInclude(file); + expect(files[0].base).toEqual(outputBase, 'base should have changed'); + // TODO: normalize this path + expect(files[0].path).toEqual(outputDirpath, 'path should have changed'); + expect(stats.isDirectory()).toEqual(true); + } - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); - stream.pipe(bufferStream); - stream.write(expectedFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.dest(outputBase), + concat(assert), + ], done); }); - it('should allow piping multiple dests in streaming mode', function(done) { - var inputPath1 = path.join(__dirname, './out-fixtures/multiple-first'); - var inputPath2 = path.join(__dirname, './out-fixtures/multiple-second'); - var inputBase = path.join(__dirname, './out-fixtures/'); - var srcPath = path.join(__dirname, './fixtures/test.coffee'); - var stream1 = vfs.dest('./out-fixtures/', { cwd: __dirname }); - var stream2 = vfs.dest('./out-fixtures/', { cwd: __dirname }); - var content = fs.readFileSync(srcPath); - var rename = through.obj(function(file, _, next) { - file.path = inputPath2; - this.push(file); - next(); - }); - - stream1.on('data', function(file) { - file.path.should.equal(inputPath1); - }); - - stream1.pipe(rename).pipe(stream2); - stream2.on('data', function(file) { - file.path.should.equal(inputPath2); - }).once('end', function() { - fs.readFileSync(inputPath1, 'utf8').should.equal(content.toString()); - fs.readFileSync(inputPath2, 'utf8').should.equal(content.toString()); - done(); - }); - + it('allows piping multiple dests in streaming mode', function(done) { var file = new File({ base: inputBase, - path: inputPath1, - cwd: __dirname, - contents: content, + path: inputPath, + contents: new Buffer(contents), }); - stream1.write(file); - stream1.end(); + function assert() { + var outputContents1 = fs.readFileSync(outputPath, 'utf8'); + var outputContents2 = fs.readFileSync(outputRenamePath, 'utf8'); + expect(outputContents1).toEqual(contents); + expect(outputContents2).toEqual(contents); + } + + pipe([ + from.obj([file]), + includes({ path: inputPath }), + vfs.dest(outputBase), + rename(outputRenamePath), + includes({ path: outputRenamePath }), + vfs.dest(outputBase), + concat(assert), + ], done); }); - it('should write new files with the default user mode', function(done) { - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - var inputBase = path.join(__dirname, './fixtures/'); - var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); - var expectedContents = fs.readFileSync(inputPath); - var expectedMode = parseInt('666', 8) & (~process.umask()); + it('writes new files with the default user mode', function(done) { + var expectedMode = applyUmask('666'); - var expectedFile = new File({ + var file = new File({ base: inputBase, - cwd: __dirname, path: inputPath, - contents: expectedContents, + contents: new Buffer(contents), }); - var buffered = []; - - var onEnd = function() { - buffered.length.should.equal(1); - buffered[0].should.equal(expectedFile); - fs.existsSync(expectedPath).should.equal(true); - realMode(fs.lstatSync(expectedPath).mode).toString(8).should.equal(expectedMode.toString(8)); - done(); - }; - - chmodSpy.reset(); - var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); - - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); + function assert(files) { + expect(files.length).toEqual(1); + expect(files).toInclude(file); + expect(statMode(outputPath)).toEqual(expectedMode); + } - stream.pipe(bufferStream); - stream.write(expectedFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.dest(outputBase), + concat(assert), + ], done); }); - it('should report IO errors', function(done) { - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - var inputBase = path.join(__dirname, './fixtures/'); - var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); - var expectedContents = fs.readFileSync(inputPath); - var expectedBase = path.join(__dirname, './out-fixtures'); - - var expectedFile = new File({ + it('reports i/o errors', function(done) { + var file = new File({ base: inputBase, - cwd: __dirname, path: inputPath, - contents: expectedContents, + contents: new Buffer(contents), }); - fs.mkdirSync(expectedBase); - fs.closeSync(fs.openSync(expectedPath, 'w')); - fs.chmodSync(expectedPath, 0); - - var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); - stream.on('error', function(err) { + function assert(err) { expect(err).toExist(); done(); - }); - stream.write(expectedFile); + } + + fs.mkdirSync(outputBase); + fs.closeSync(fs.openSync(outputPath, 'w')); + fs.chmodSync(outputPath, 0); + + pipe([ + from.obj([file]), + vfs.dest(outputBase), + ], assert); }); - it('should report stat errors', function(done) { - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - var inputBase = path.join(__dirname, './fixtures/'); - var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); - var expectedContents = fs.readFileSync(inputPath); - var expectedBase = path.join(__dirname, './out-fixtures'); - var expectedMode = parseInt('722', 8); + it('reports stat errors', function(done) { + var expectedMode = applyUmask('722'); + + var fstatSpy = expect.spyOn(fs, 'fstat').andCall(mockError); - var expectedFile = new File({ + var file = new File({ base: inputBase, - cwd: __dirname, path: inputPath, - contents: expectedContents, + contents: new Buffer(contents), stat: { mode: expectedMode, }, }); - fs.mkdirSync(expectedBase); - fs.closeSync(fs.openSync(expectedPath, 'w')); + function assert(err) { + expect(err).toExist(); + expect(fstatSpy.calls.length).toEqual(1); + done(); + } - spies.setError(function(mod, fn) { - if (fn === 'fstat' && typeof arguments[2] === 'number') { - return new Error('stat error'); - } - }); + fs.mkdirSync(outputBase); + fs.closeSync(fs.openSync(outputPath, 'w')); - var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); - stream.on('error', function(err) { - err.message.should.equal('stat error'); - done(); - }); - stream.write(expectedFile); + pipe([ + from.obj([file]), + vfs.dest(outputBase), + ], assert); }); - it('should not overwrite files with overwrite option set to false', function(done) { - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - var inputBase = path.join(__dirname, './fixtures/'); - var inputContents = fs.readFileSync(inputPath); - - var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); - var expectedBase = path.join(__dirname, './out-fixtures'); + it('does not overwrite files with overwrite option set to false', function(done) { var existingContents = 'Lorem Ipsum'; - var inputFile = new File({ + var file = new File({ base: inputBase, - cwd: __dirname, path: inputPath, - contents: inputContents, + contents: new Buffer(contents), }); - var buffered = []; + function assert(files) { + var outputContents = fs.readFileSync(outputPath, 'utf8'); - var onEnd = function() { - buffered.length.should.equal(1); - bufEqual(fs.readFileSync(expectedPath), new Buffer(existingContents)).should.equal(true); - done(); - }; + expect(files.length).toEqual(1); + expect(outputContents).toEqual(existingContents); + } // Write expected file which should not be overwritten - fs.mkdirSync(expectedBase); - fs.writeFileSync(expectedPath, existingContents); - - var stream = vfs.dest('./out-fixtures/', { cwd: __dirname, overwrite: false }); + fs.mkdirSync(outputBase); + fs.writeFileSync(outputPath, existingContents); - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); - stream.pipe(bufferStream); - stream.write(inputFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.dest(outputBase, { overwrite: false }), + concat(assert), + ], done); }); - it('should overwrite files with overwrite option set to true', function(done) { - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - var inputBase = path.join(__dirname, './fixtures/'); - var inputContents = fs.readFileSync(inputPath); - - var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); - var expectedBase = path.join(__dirname, './out-fixtures'); + it('overwrites files with overwrite option set to true', function(done) { var existingContents = 'Lorem Ipsum'; - var inputFile = new File({ + var file = new File({ base: inputBase, - cwd: __dirname, path: inputPath, - contents: inputContents, + contents: new Buffer(contents), }); - var buffered = []; + function assert(files) { + var outputContents = fs.readFileSync(outputPath, 'utf8'); - var onEnd = function() { - buffered.length.should.equal(1); - bufEqual(fs.readFileSync(expectedPath), new Buffer(inputContents)).should.equal(true); - done(); - }; + expect(files.length).toEqual(1); + expect(outputContents).toEqual(contents); + } // This should be overwritten - fs.mkdirSync(expectedBase); - fs.writeFileSync(expectedPath, existingContents); + fs.mkdirSync(outputBase); + fs.writeFileSync(outputPath, existingContents); - var stream = vfs.dest('./out-fixtures/', { cwd: __dirname, overwrite: true }); - - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); - stream.pipe(bufferStream); - stream.write(inputFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.dest(outputBase, { overwrite: true }), + concat(assert), + ], done); }); - it('should not overwrite files with overwrite option set to a function that returns false', function(done) { - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - var inputBase = path.join(__dirname, './fixtures/'); - var inputContents = fs.readFileSync(inputPath); - - var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); - var expectedBase = path.join(__dirname, './out-fixtures'); + it('does not overwrite files with overwrite option set to a function that returns false', function(done) { var existingContents = 'Lorem Ipsum'; - var inputFile = new File({ + var file = new File({ base: inputBase, - cwd: __dirname, path: inputPath, - contents: inputContents, + contents: new Buffer(contents), }); - var buffered = []; + function overwrite(f) { + expect(f).toEqual(file); + return false; + } - var onEnd = function() { - buffered.length.should.equal(1); - bufEqual(fs.readFileSync(expectedPath), new Buffer(existingContents)).should.equal(true); - done(); - }; + function assert(files) { + var outputContents = fs.readFileSync(outputPath, 'utf8'); - // Write expected file which should not be overwritten - fs.mkdirSync(expectedBase); - fs.writeFileSync(expectedPath, existingContents); + expect(files.length).toEqual(1); + expect(outputContents).toEqual(existingContents); + } - var stream = vfs.dest('./out-fixtures/', { cwd: __dirname, overwrite: function() { - return false; - }, }); + // Write expected file which should not be overwritten + fs.mkdirSync(outputBase); + fs.writeFileSync(outputPath, existingContents); - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); - stream.pipe(bufferStream); - stream.write(inputFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.dest(outputBase, { overwrite: overwrite }), + concat(assert), + ], done); }); - it('should overwrite files with overwrite option set to a function that returns true', function(done) { - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - var inputBase = path.join(__dirname, './fixtures/'); - var inputContents = fs.readFileSync(inputPath); - - var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); - var expectedBase = path.join(__dirname, './out-fixtures'); + it('overwrites files with overwrite option set to a function that returns true', function(done) { var existingContents = 'Lorem Ipsum'; - var inputFile = new File({ + var file = new File({ base: inputBase, - cwd: __dirname, path: inputPath, - contents: inputContents, + contents: new Buffer(contents), }); - var buffered = []; + function overwrite(f) { + expect(f).toEqual(file); + return true; + } - var onEnd = function() { - buffered.length.should.equal(1); - bufEqual(fs.readFileSync(expectedPath), new Buffer(inputContents)).should.equal(true); - done(); - }; + function assert(files) { + var outputContents = fs.readFileSync(outputPath, 'utf8'); - // This should be overwritten - fs.mkdirSync(expectedBase); - fs.writeFileSync(expectedPath, existingContents); + expect(files.length).toEqual(1); + expect(outputContents).toEqual(contents); + } - var stream = vfs.dest('./out-fixtures/', { cwd: __dirname, overwrite: function() { - return true; - }, }); + // This should be overwritten + fs.mkdirSync(outputBase); + fs.writeFileSync(outputPath, existingContents); - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); - stream.pipe(bufferStream); - stream.write(inputFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.dest(outputBase, { overwrite: overwrite }), + concat(assert), + ], done); }); - it('should create symlinks when the `symlink` attribute is set on the file', function(done) { - var inputPath = path.join(__dirname, './fixtures/test-create-dir-symlink'); - var inputBase = path.join(__dirname, './fixtures/'); + it('creates symlinks when the `symlink` attribute is set on the file', function(done) { var inputRelativeSymlinkPath = 'wow'; - var expectedPath = path.join(__dirname, './out-fixtures/test-create-dir-symlink'); - - var inputFile = new File({ + var file = new File({ base: inputBase, - cwd: __dirname, - path: inputPath, - contents: null, // '' + path: inputDirpath, + contents: null, }); - // `src()` adds this side-effect with `keepSymlinks` option set to false - inputFile.symlink = inputRelativeSymlinkPath; - - var buffered = []; + // `src()` adds this side-effect with `followSymlinks` option set to false + file.symlink = inputRelativeSymlinkPath; - var onEnd = function() { - fs.readlink(buffered[0].path, function() { - buffered[0].symlink.should.equal(inputFile.symlink); - buffered[0].path.should.equal(expectedPath); - done(); - }); - }; + function assert(files) { + var symlink = fs.readlinkSync(outputDirpath); - var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); - - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); + expect(files.length).toEqual(1); + expect(file.symlink).toEqual(symlink); + expect(files[0].symlink).toEqual(symlink); + expect(files[0].path).toEqual(outputDirpath); + } - stream.on('error', done); - stream.pipe(bufferStream); - stream.write(inputFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.dest(outputBase), + concat(assert), + ], done); }); - it('should emit finish event', function(done) { - var srcPath = path.join(__dirname, './fixtures/test.coffee'); - var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); + it('emits a finish event', function(done) { + var destStream = vfs.dest(outputBase); - stream.once('finish', function() { - done(); - }); + destStream.once('finish', done); var file = new File({ - path: srcPath, - cwd: __dirname, + base: inputBase, + path: inputPath, contents: new Buffer('1234567890'), }); - stream.write(file); - stream.end(); + pipe([ + from.obj([file]), + destStream, + ]); }); it('does not get clogged by highWaterMark', function(done) { - fs.mkdirSync(path.join(__dirname, './fixtures/highwatermark')); - for (var idx = 0; idx < 17; idx++) { - fs.writeFileSync(path.join(__dirname, './fixtures/highwatermark/', 'file' + idx + '.txt')); + var expectedCount = 17; + var highwatermarkFiles = []; + for (var idx = 0; idx < expectedCount; idx++) { + var file = new File({ + base: inputBase, + path: inputPath, + contents: new Buffer(contents), + }); + highwatermarkFiles.push(file); } - var srcPath = path.join(__dirname, './fixtures/highwatermark/*.txt'); - var srcStream = vfs.src(srcPath); - var destStream = vfs.dest('./out-fixtures/', { cwd: __dirname }); - - var fileCount = 0; - var countFiles = through.obj(function(file, enc, cb) { - fileCount++; - - cb(null, file); - }); - - destStream.once('finish', function() { - fileCount.should.equal(17); - done(); - }); - - srcStream.pipe(countFiles).pipe(destStream); + pipe([ + from.obj(highwatermarkFiles), + count(expectedCount), + // Must be in the Writable position to test this + // So concat-stream cannot be used + vfs.dest(outputBase), + ], done); }); it('allows backpressure when piped to another, slower stream', function(done) { this.timeout(20000); - fs.mkdirSync(path.join(__dirname, './fixtures/highwatermark')); - for (var idx = 0; idx < 24; idx++) { - fs.writeFileSync(path.join(__dirname, './fixtures/highwatermark/', 'file' + idx + '.txt')); + var expectedCount = 24; + var highwatermarkFiles = []; + for (var idx = 0; idx < expectedCount; idx++) { + var file = new File({ + base: inputBase, + path: inputPath, + contents: new Buffer(contents), + }); + highwatermarkFiles.push(file); } - var srcPath = path.join(__dirname, './fixtures/highwatermark/*.txt'); - var srcStream = vfs.src(srcPath); - var destStream = vfs.dest('./out-fixtures/', { cwd: __dirname }); - - var fileCount = 0; - var countFiles = through.obj(function(file, enc, cb) { - fileCount++; - - cb(null, file); - }); - - var slowFileCount = 0; - var slowCountFiles = new Writeable({ - objectMode: true, - write: function(file, enc, cb) { - slowFileCount++; - - setTimeout(function() { - cb(null, file); - }, 250); - }, - }); - - slowCountFiles.once('finish', function() { - fileCount.should.equal(24); - slowFileCount.should.equal(24); - done(); - }); - - srcStream - .pipe(countFiles) - .pipe(destStream) - .pipe(slowCountFiles); + pipe([ + from.obj(highwatermarkFiles), + count(expectedCount), + vfs.dest(outputBase), + slowCount(expectedCount), + ], done); }); - it('should respect readable listeners on destination stream', function(done) { - var srcPath = path.join(__dirname, './fixtures/test.coffee'); - var srcStream = vfs.src(srcPath); - var destStream = vfs.dest('./out-fixtures/', { cwd: __dirname }); + it('respects readable listeners on destination stream', function(done) { + var file = new File({ + base: inputBase, + path: inputDirpath, + contents: null, + }); - srcStream - .pipe(destStream); + var destStream = vfs.dest(outputBase); var readables = 0; destStream.on('readable', function() { @@ -863,60 +654,65 @@ describe('dest stream', function() { } }); - destStream.on('error', done); + function assert(err) { + expect(readables).toEqual(1); + done(err); + } - destStream.on('finish', function() { - readables.should.equal(1); - done(); - }); + pipe([ + from.obj([file]), + destStream, + ], assert); }); - it('should respect data listeners on destination stream', function(done) { - var srcPath = path.join(__dirname, './fixtures/test.coffee'); - var srcStream = vfs.src(srcPath); - var destStream = vfs.dest('./out-fixtures/', { cwd: __dirname }); + it('respects data listeners on destination stream', function(done) { + var file = new File({ + base: inputBase, + path: inputDirpath, + contents: null, + }); - srcStream - .pipe(destStream); + var destStream = vfs.dest(outputBase); var datas = 0; destStream.on('data', function() { datas++; }); - destStream.on('error', done); + function assert(err) { + expect(datas).toEqual(1); + done(err); + } - destStream.on('finish', function() { - datas.should.equal(1); - done(); - }); + pipe([ + from.obj([file]), + destStream, + ], assert); }); it('sinks the stream if all the readable event handlers are removed', function(done) { - fs.mkdirSync(path.join(__dirname, './fixtures/highwatermark')); - for (var idx = 0; idx < 17; idx++) { - fs.writeFileSync(path.join(__dirname, './fixtures/highwatermark/', 'file' + idx + '.txt')); + var expectedCount = 17; + var highwatermarkFiles = []; + for (var idx = 0; idx < expectedCount; idx++) { + var file = new File({ + base: inputBase, + path: inputPath, + contents: new Buffer(contents), + }); + highwatermarkFiles.push(file); } - var srcPath = path.join(__dirname, './fixtures/highwatermark/*.txt'); - var srcStream = vfs.src(srcPath); - var destStream = vfs.dest('./out-fixtures/', { cwd: __dirname }); - - var fileCount = 0; - var countFiles = through.obj(function(file, enc, cb) { - fileCount++; - - cb(null, file); - }); + var destStream = vfs.dest(outputBase); destStream.on('readable', noop); - destStream.once('finish', function() { - fileCount.should.equal(17); - done(); - }); - - srcStream.pipe(countFiles).pipe(destStream); + pipe([ + from.obj(highwatermarkFiles), + count(expectedCount), + // Must be in the Writable position to test this + // So concat-stream cannot be used + destStream, + ], done); process.nextTick(function() { destStream.removeListener('readable', noop); @@ -924,127 +720,86 @@ describe('dest stream', function() { }); it('sinks the stream if all the data event handlers are removed', function(done) { - - this.timeout(10000); - - fs.mkdirSync(path.join(__dirname, './fixtures/highwatermark')); - for (var idx = 0; idx < 17; idx++) { - fs.writeFileSync(path.join(__dirname, './fixtures/highwatermark/', 'file' + idx + '.txt')); - } - - var srcPath = path.join(__dirname, './fixtures/highwatermark/*.txt'); - var srcStream = vfs.src(srcPath); - var destStream = vfs.dest('./out-fixtures/', { cwd: __dirname }); - - var fileCount = 0; - function onData() { - fileCount++; + var expectedCount = 17; + var highwatermarkFiles = []; + for (var idx = 0; idx < expectedCount; idx++) { + var file = new File({ + base: inputBase, + path: inputPath, + contents: new Buffer(contents), + }); + highwatermarkFiles.push(file); } - var countFiles = through.obj(function(file, enc, cb) { - onData(); + var destStream = vfs.dest(outputBase); - cb(null, file); - }); + destStream.on('data', noop); - destStream.on('data', onData); - - destStream.once('finish', function() { - fileCount.should.equal(17); - done(); - }); - - srcStream.pipe(countFiles).pipe(destStream); + pipe([ + from.obj(highwatermarkFiles), + count(expectedCount), + // Must be in the Writable position to test this + // So concat-stream cannot be used + destStream, + ], done); process.nextTick(function() { - destStream.removeListener('data', onData); + destStream.removeListener('data', noop); }); }); - it('should pass options to through2', function(done) { - var srcPath = path.join(__dirname, './fixtures/test.coffee'); - var content = fs.readFileSync(srcPath); - var stream = vfs.dest('./out-fixtures/', { cwd: __dirname, objectMode: false }); - - stream.on('error', function(err) { - err.should.match(/Invalid non-string\/buffer chunk/); - done(); - }); - + // TODO: need a better way to pass these options through + // Or maybe not at all since we fixed highWaterMark + it('passes options to through2', function(done) { var file = new File({ - path: srcPath, - cwd: __dirname, - contents: content, + base: inputBase, + path: inputPath, + contents: new Buffer(contents), }); - stream.write(file); - stream.end(); - }); - - it('should successfully process unbuffered items', function(done) { - var srcPath = path.join(__dirname, './fixtures/*'); - var srcStream = vfs.src(srcPath, { buffer: false }); - var destStream = vfs.dest('./out-fixtures', { cwd: __dirname }); - - srcStream - .pipe(destStream) - .once('finish', done); - }); - - it('should not exhaust available file descriptors when streaming thousands of files', function(done) { - // This can be a very slow test on boxes with slow disk i/o - this.timeout(0); - - // Make a ton of files. Changed from hard links due to Windows failures - var numFiles = 6000; - fs.mkdirSync(path.join(__dirname, './out-fixtures')); - fs.mkdirSync(path.join(__dirname, './out-fixtures/in/')); - - for (var idx = 0; idx < numFiles; idx++) { - fs.writeFileSync(path.join(__dirname, './out-fixtures/in/test' + idx + '.coffee'), ''); + function assert(err) { + expect(err.message).toMatch(/Invalid non-string\/buffer chunk/); + done(); } - var srcStream = vfs.src(path.join(__dirname, './out-fixtures/in/*.coffee'), { buffer: false }); - var destStream = vfs.dest('./out-fixtures/out/', { cwd: __dirname }); - - var fileCount = 0; + pipe([ + from.obj([file]), + vfs.dest(outputBase, { objectMode: false }), + ], assert); + }); - srcStream - .pipe(through.obj(function(file, enc, cb) { - fileCount++; + it('successfully processes files with streaming contents', function(done) { + var file = new File({ + base: inputBase, + path: inputPath, + contents: from([contents]), + }); - cb(null, file); - })) - .pipe(destStream) - .once('finish', function() { - fileCount.should.equal(numFiles); - done(); - }); + pipe([ + from.obj([file]), + vfs.dest(outputBase), + ], done); }); it('errors if we cannot mkdirp', function(done) { - var mkdirSpy = expect.spyOn(fs, 'mkdir').andCall(function() { - var callback = arguments[arguments.length - 1]; - callback(new Error('mocked error')); - }); + var mkdirSpy = expect.spyOn(fs, 'mkdir').andCall(mockError); - var outputDir = path.join(__dirname, './out-fixtures/'); - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - - var expectedFile = new File({ - base: __dirname, - cwd: __dirname, + var file = new File({ + base: inputBase, path: inputPath, contents: null, }); - var stream = vfs.dest(outputDir); - stream.on('error', function(err) { + function assert(err) { expect(err).toExist(); expect(mkdirSpy.calls.length).toEqual(1); done(); - }); - stream.write(expectedFile); + } + + pipe([ + from.obj([file]), + vfs.dest(outputBase), + ], assert); }); it('errors if vinyl object is a directory and we cannot mkdirp', function(done) { @@ -1052,116 +807,100 @@ describe('dest stream', function() { var mkdirSpy = expect.spyOn(fs, 'mkdir').andCall(function() { if (mkdirSpy.calls.length > 1) { - var callback = arguments[arguments.length - 1]; - callback(new Error('mocked error')); + mockError.apply(this, arguments); } else { - ogMkdir.apply(null, arguments); + ogMkdir.apply(this, arguments); } }); - var outputDir = path.join(__dirname, './out-fixtures/'); - var inputPath = path.join(__dirname, './other-dir/'); - - var expectedFile = new File({ - base: __dirname, - cwd: __dirname, - path: inputPath, + var file = new File({ + base: inputBase, + path: inputDirpath, contents: null, stat: { - isDirectory: function() { - return true; - }, + isDirectory: isDirectory, }, }); - var stream = vfs.dest(outputDir); - stream.write(expectedFile); - stream.on('error', function(err) { + function assert(err) { expect(err).toExist(); expect(mkdirSpy.calls.length).toEqual(2); done(); - }); + } + + pipe([ + from.obj([file]), + vfs.dest(outputBase), + ], assert); }); // TODO: is this correct behavior? had to adjust it it('does not error if vinyl object is a directory and we cannot open it', function(done) { - var outputDir = path.join(__dirname, './out-fixtures/'); - var inputPath = path.join(__dirname, './other-dir/'); - - var expectedFile = new File({ - base: __dirname, - cwd: __dirname, - path: inputPath, + var file = new File({ + base: inputBase, + path: inputDirpath, contents: null, stat: { - isDirectory: function() { - return true; - }, - mode: parseInt('000', 8), + isDirectory: isDirectory, + mode: applyUmask('000'), }, }); - var stream = vfs.dest(outputDir); - stream.write(expectedFile); - stream.on('error', function(err) { - expect(err).toNotExist(); - done(err); - }); - stream.end(function() { - var exists = fs.existsSync(path.join(outputDir, './other-dir/')); + function assert() { + var exists = fs.existsSync(outputDirpath); expect(exists).toEqual(true); - done(); - }); + } + + pipe([ + from.obj([file]), + vfs.dest(outputBase), + concat(assert), + ], done); }); it('errors if vinyl object is a directory and open errors', function(done) { - var openSpy = expect.spyOn(fs, 'open').andCall(function(writePath, flag, cb) { - cb(new Error('mocked error')); - }); - - var outputDir = path.join(__dirname, './out-fixtures/'); - var inputPath = path.join(__dirname, './other-dir/'); + var openSpy = expect.spyOn(fs, 'open').andCall(mockError); - var expectedFile = new File({ - base: __dirname, - cwd: __dirname, - path: inputPath, + var file = new File({ + base: inputBase, + path: inputDirpath, contents: null, stat: { - isDirectory: function() { - return true; - }, + isDirectory: isDirectory, }, }); - var stream = vfs.dest(outputDir); - stream.write(expectedFile); - stream.on('error', function(err) { + function assert(err) { expect(err).toExist(); expect(openSpy.calls.length).toEqual(1); done(); - }); - }); + } - it('error if content stream errors', function(done) { - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - var inputBase = path.join(__dirname, './fixtures/'); + pipe([ + from.obj([file]), + vfs.dest(outputBase), + ], assert); + }); + it('errors if content stream errors', function(done) { var contentStream = from(function(size, cb) { cb(new Error('mocked error')); }); - var expectedFile = new File({ + + var file = new File({ base: inputBase, - cwd: __dirname, path: inputPath, contents: contentStream, }); - var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); - stream.write(expectedFile); - stream.on('error', function(err) { + function assert(err) { expect(err).toExist(); done(); - }); + } + + pipe([ + from.obj([file]), + vfs.dest(outputBase), + ], assert); }); }); diff --git a/test/file-operations.js b/test/file-operations.js index 10558b74..d4d69f86 100644 --- a/test/file-operations.js +++ b/test/file-operations.js @@ -1,18 +1,26 @@ 'use strict'; -var expect = require('expect'); +var path = require('path'); +var buffer = require('buffer'); -var os = require('os'); var fs = require('graceful-fs'); -var del = require('del'); -var path = require('path'); var File = require('vinyl'); -var buffer = require('buffer'); -var defaultResolution = require('default-resolution'); +var expect = require('expect'); +var miss = require('mississippi'); var fo = require('../lib/file-operations'); var constants = require('../lib/constants'); +var DEFAULT_DIR_MODE = constants.DEFAULT_DIR_MODE; +var DEFAULT_FILE_MODE = constants.DEFAULT_FILE_MODE; + +var cleanup = require('./utils/cleanup'); +var statMode = require('./utils/stat-mode'); +var mockError = require('./utils/mock-error'); +var isWindows = require('./utils/is-windows'); +var applyUmask = require('./utils/apply-umask'); +var testConstants = require('./utils/test-constants'); + var mkdirp = fo.mkdirp; var closeFd = fo.closeFd; var isOwner = fo.isOwner; @@ -22,24 +30,23 @@ var getTimesDiff = fo.getTimesDiff; var getOwnerDiff = fo.getOwnerDiff; var isValidUnixId = fo.isValidUnixId; var updateMetadata = fo.updateMetadata; +var createWriteStream = fo.createWriteStream; -var resolution = defaultResolution(); - -var DEFAULT_DIR_MODE = masked(constants.DEFAULT_DIR_MODE & ~process.umask()).toString(8); +var pipe = miss.pipe; +var from = miss.from; -function masked(mode) { - return mode & constants.MASK_MODE; -} +var outputBase = testConstants.outputBase; +var inputPath = testConstants.inputPath; +var outputPath = testConstants.outputPath; +var outputDirpath = testConstants.outputDirpath; +var outputNestedPath = testConstants.outputNestedPath; +var outputNestedDirpath = testConstants.outputNestedDirpath; +var contents = testConstants.contents; -function statHuman(filepath) { - var stats = fs.lstatSync(filepath); - return masked(stats.mode).toString(8); -} +var clean = cleanup([outputBase]); function noop() {} -var isWindows = (os.platform() === 'win32'); - describe('isOwner', function() { var ownerStat = { @@ -163,56 +170,70 @@ describe('isValidUnixId', function() { describe('getModeDiff', function() { it('returns 0 if both modes are the same', function(done) { - var fsMode = parseInt('777', 8); - var vfsMode = parseInt('777', 8); + var fsMode = applyUmask('777'); + var vfsMode = applyUmask('777'); var result = getModeDiff(fsMode, vfsMode); - expect(result.toString(8)).toEqual('0'); + expect(result).toEqual(0); done(); }); it('returns 0 if vinyl mode is not a number', function(done) { - var fsMode = parseInt('777', 8); + var fsMode = applyUmask('777'); var vfsMode = undefined; var result = getModeDiff(fsMode, vfsMode); - expect(result.toString(8)).toEqual('0'); + expect(result).toEqual(0); done(); }); it('returns a value greater than 0 if modes are different', function(done) { - var fsMode = parseInt('777', 8); - var vfsMode = parseInt('744', 8); + var fsMode = applyUmask('777'); + var vfsMode = applyUmask('744'); var result = getModeDiff(fsMode, vfsMode); - expect(result.toString(8)).toEqual('33'); + expect(result).toBeGreaterThan(0); + + done(); + }); + + it('returns the proper diff', function(done) { + var fsMode = applyUmask('777'); + var vfsMode = applyUmask('744'); + var expectedDiff = applyUmask('33'); + + var result = getModeDiff(fsMode, vfsMode); + + expect(result).toEqual(expectedDiff); done(); }); it('does not matter the order of diffing', function(done) { - var fsMode = parseInt('655', 8); - var vfsMode = parseInt('777', 8); + var fsMode = applyUmask('655'); + var vfsMode = applyUmask('777'); + var expectedDiff = applyUmask('122'); var result = getModeDiff(fsMode, vfsMode); - expect(result.toString(8)).toEqual('122'); + expect(result).toEqual(expectedDiff); done(); }); it('includes the sticky/setuid/setgid bits', function(done) { - var fsMode = parseInt('1777', 8); - var vfsMode = parseInt('4777', 8); + var fsMode = applyUmask('1777'); + var vfsMode = applyUmask('4777'); + var expectedDiff = applyUmask('5000'); var result = getModeDiff(fsMode, vfsMode); - expect(result.toString(8)).toEqual('5000'); + expect(result).toEqual(expectedDiff); done(); }); @@ -551,7 +572,6 @@ describe('getOwnerDiff', function() { done(); }); - }); describe('closeFd', function() { @@ -587,14 +607,14 @@ describe('closeFd', function() { it('calls the callback with propagated error if close succeeds', function(done) { var propagatedError = new Error(); - var fd = fs.openSync(path.join(__dirname, './fixtures/test.coffee'), 'r'); + var fd = fs.openSync(inputPath, 'r'); - var spy = expect.spyOn(fs, 'close').andCallThrough(); + var closeSpy = expect.spyOn(fs, 'close').andCallThrough(); closeFd(propagatedError, fd, function(err) { - spy.restore(); + closeSpy.restore(); - expect(spy.calls.length).toEqual(1); + expect(closeSpy.calls.length).toEqual(1); expect(err).toEqual(propagatedError); done(); @@ -602,7 +622,7 @@ describe('closeFd', function() { }); it('calls the callback with no error if close succeeds & no propagated error', function(done) { - var fd = fs.openSync(path.join(__dirname, './fixtures/test.coffee'), 'r'); + var fd = fs.openSync(inputPath, 'r'); var spy = expect.spyOn(fs, 'close').andCallThrough(); @@ -619,31 +639,22 @@ describe('closeFd', function() { describe('writeFile', function() { - var filepath; + beforeEach(clean); + afterEach(clean); beforeEach(function(done) { - filepath = path.join(__dirname, './fixtures/writeFile.txt'); - - done(); - }); - - afterEach(function() { - // Async del to get sort-of-fix for https://github.com/isaacs/rimraf/issues/72 - return del(filepath); + mkdirp(outputBase, done); }); it('writes a file to the filesystem, does not close and returns the fd', function(done) { - var expected = 'test'; - var content = new Buffer(expected); - - writeFile(filepath, content, function(err, fd) { + writeFile(outputPath, new Buffer(contents), function(err, fd) { expect(err).toNotExist(); expect(typeof fd === 'number').toEqual(true); fs.close(fd, function() { - var written = fs.readFileSync(filepath, 'utf-8'); + var written = fs.readFileSync(outputPath, 'utf8'); - expect(written).toEqual(expected); + expect(written).toEqual(contents); done(); }); @@ -651,17 +662,14 @@ describe('writeFile', function() { }); it('defaults to writing files with 0666 mode', function(done) { - var expected = parseInt('0666', 8) & (~process.umask()); - var content = new Buffer('test'); + var expected = applyUmask('666'); - writeFile(filepath, content, function(err, fd) { + writeFile(outputPath, new Buffer(contents), function(err, fd) { expect(err).toNotExist(); expect(typeof fd === 'number').toEqual(true); fs.close(fd, function() { - var stats = fs.lstatSync(filepath); - - expect(masked(stats.mode)).toEqual(expected); + expect(statMode(outputPath)).toEqual(expected); done(); }); @@ -669,26 +677,23 @@ describe('writeFile', function() { }); it('accepts a different mode in options', function(done) { + // Changing the mode of a file is not supported by node.js in Windows. if (isWindows) { - console.log('Changing the mode of a file is not supported by node.js in Windows.'); this.skip(); return; } - var expected = parseInt('0777', 8) & (~process.umask()); - var content = new Buffer('test'); + var expected = applyUmask('777'); var options = { - mode: parseInt('0777', 8), + mode: expected, }; - writeFile(filepath, content, options, function(err, fd) { + writeFile(outputPath, new Buffer(contents), options, function(err, fd) { expect(err).toNotExist(); expect(typeof fd === 'number').toEqual(true); fs.close(fd, function() { - var stats = fs.lstatSync(filepath); - - expect(masked(stats.mode)).toEqual(expected); + expect(statMode(outputPath)).toEqual(expected); done(); }); @@ -696,13 +701,13 @@ describe('writeFile', function() { }); it('defaults to opening files with write flag', function(done) { - var content = new Buffer('test'); + var length = contents.length; - writeFile(filepath, content, function(err, fd) { + writeFile(outputPath, new Buffer(contents), function(err, fd) { expect(err).toNotExist(); expect(typeof fd === 'number').toEqual(true); - fs.read(fd, new Buffer(4), 0, 4, 0, function(readErr) { + fs.read(fd, new Buffer(length), 0, length, 0, function(readErr) { expect(readErr).toExist(); fs.close(fd, done); @@ -711,20 +716,19 @@ describe('writeFile', function() { }); it('accepts a different flag in options', function(done) { - var expected = 'test'; - var content = new Buffer(expected); + var length = contents.length; var options = { flag: 'w+', }; - writeFile(filepath, content, options, function(err, fd) { + writeFile(outputPath, new Buffer(contents), options, function(err, fd) { expect(err).toNotExist(); expect(typeof fd === 'number').toEqual(true); - fs.read(fd, new Buffer(4), 0, 4, 0, function(readErr, _, written) { + fs.read(fd, new Buffer(length), 0, length, 0, function(readErr, _, written) { expect(readErr).toNotExist(); - expect(written.toString()).toEqual(expected); + expect(written.toString()).toEqual(contents); fs.close(fd, done); }); @@ -735,21 +739,20 @@ describe('writeFile', function() { var initial = 'test'; var toWrite = '-a-thing'; - fs.writeFileSync(filepath, initial, 'utf-8'); + fs.writeFileSync(outputPath, initial, 'utf8'); var expected = initial + toWrite; - var content = new Buffer(toWrite); var options = { flag: 'a', }; - writeFile(filepath, content, options, function(err, fd) { + writeFile(outputPath, new Buffer(toWrite), options, function(err, fd) { expect(err).toNotExist(); expect(typeof fd === 'number').toEqual(true); fs.close(fd, function() { - var written = fs.readFileSync(filepath, 'utf-8'); + var written = fs.readFileSync(outputPath, 'utf8'); expect(written).toEqual(expected); @@ -759,10 +762,9 @@ describe('writeFile', function() { }); it('does not pass a file descriptor if open call errors', function(done) { - filepath = path.join(__dirname, './not-exist-dir/writeFile.txt'); - var content = new Buffer('test'); + var notExistDir = path.join(__dirname, './not-exist-dir/writeFile.txt'); - writeFile(filepath, content, function(err, fd) { + writeFile(notExistDir, new Buffer(contents), function(err, fd) { expect(err).toExist(); expect(typeof fd === 'number').toEqual(false); @@ -771,13 +773,11 @@ describe('writeFile', function() { }); it('passes a file descriptor if write call errors', function(done) { - var existsFilepath = path.join(__dirname, './fixtures/test.coffee'); // File must exist - var content = new Buffer('test'); var options = { flag: 'r', }; - writeFile(existsFilepath, content, options, function(err, fd) { + writeFile(inputPath, new Buffer(contents), options, function(err, fd) { expect(err).toExist(); expect(typeof fd === 'number').toEqual(true); @@ -786,7 +786,7 @@ describe('writeFile', function() { }); it('passes an error if called with string as data', function(done) { - writeFile(filepath, 'test', function(err) { + writeFile(outputPath, contents, function(err) { expect(err).toExist(); done(); @@ -799,19 +799,19 @@ describe('writeFile', function() { return; } - var expected = 'test'; - var buf = new Buffer(expected); - var content = new buffer.SlowBuffer(4); - buf.copy(content, 0, 0, 4); + var length = contents.length; + var buf = new Buffer(contents); + var content = new buffer.SlowBuffer(length); + buf.copy(content, 0, 0, length); - writeFile(filepath, content, function(err, fd) { + writeFile(outputPath, content, function(err, fd) { expect(err).toNotExist(); expect(typeof fd === 'number').toEqual(true); fs.close(fd, function() { - var written = fs.readFileSync(filepath, 'utf-8'); + var written = fs.readFileSync(outputPath, 'utf8'); - expect(written).toEqual(expected); + expect(written).toEqual(contents); done(); }); @@ -819,8 +819,7 @@ describe('writeFile', function() { }); it('does not error if options is falsey', function(done) { - var content = new Buffer('test'); - writeFile(filepath, content, null, function(err, fd) { + writeFile(outputPath, new Buffer(contents), null, function(err, fd) { expect(err).toNotExist(); expect(typeof fd === 'number').toEqual(true); @@ -831,28 +830,14 @@ describe('writeFile', function() { describe('updateMetadata', function() { - var inputPath = path.join(__dirname, './fixtures/stats.txt'); - var file; + beforeEach(clean); + afterEach(clean); beforeEach(function(done) { - file = new File({ - base: __dirname, - cwd: __dirname, - path: inputPath, - contents: null, - stat: { - - }, - }); - - done(); + mkdirp(outputBase, done); }); afterEach(function(done) { - expect.restoreSpies(); - - del.sync(inputPath); - if (process.geteuid === noop) { delete process.geteuid; } @@ -861,16 +846,23 @@ describe('updateMetadata', function() { }); it('passes the error if fstat fails', function(done) { + // Changing the time of a directory errors in Windows. + // Changing the mode of a file is not supported by node.js in Windows. + // Windows is treated as though it does not have permission to make these operations. if (isWindows) { - console.log('Changing the time of a directory errors in Windows.'); - console.log('Changing the mode of a file is not supported by node.js in Windows.'); - console.log('Windows is treated as though it does not have permission to make these operations.'); this.skip(); return; } var fd = 9001; + var file = new File({ + base: outputBase, + path: outputPath, + contents: null, + stat: {}, + }); + updateMetadata(fd, file, function(err) { expect(err).toExist(); @@ -884,10 +876,17 @@ describe('updateMetadata', function() { return; } - var fd = fs.openSync(inputPath, 'w+'); + var file = new File({ + base: outputBase, + path: outputPath, + contents: null, + stat: {}, + }); + + var fd = fs.openSync(outputPath, 'w+'); var stats = fs.fstatSync(fd); - updateMetadata(fd, file, function(err) { + updateMetadata(fd, file, function() { // Not sure why .toEqual doesn't match these Object.keys(file.stat).forEach(function(key) { expect(file.stat[key]).toEqual(stats[key]); @@ -903,12 +902,19 @@ describe('updateMetadata', function() { return; } + var file = new File({ + base: outputBase, + path: outputPath, + contents: null, + stat: {}, + }); + var fchmodSpy = expect.spyOn(fs, 'fchmod').andCallThrough(); var futimesSpy = expect.spyOn(fs, 'futimes').andCallThrough(); - var fd = fs.openSync(inputPath, 'w+'); + var fd = fs.openSync(outputPath, 'w+'); - updateMetadata(fd, file, function(err) { + updateMetadata(fd, file, function() { expect(fchmodSpy.calls.length).toEqual(0); expect(futimesSpy.calls.length).toEqual(0); @@ -926,15 +932,24 @@ describe('updateMetadata', function() { process.geteuid = noop; } + var earlier = Date.now() - 1000; + + var file = new File({ + base: outputBase, + path: outputPath, + contents: null, + stat: { + mtime: new Date(earlier), + }, + }); + expect.spyOn(process, 'geteuid').andReturn(9002); var fchmodSpy = expect.spyOn(fs, 'fchmod').andCallThrough(); var futimesSpy = expect.spyOn(fs, 'futimes').andCallThrough(); - file.stat.mtime = new Date(Date.now() - 1000); - - var fd = fs.openSync(inputPath, 'w+'); + var fd = fs.openSync(outputPath, 'w+'); - updateMetadata(fd, file, function(err) { + updateMetadata(fd, file, function() { expect(fchmodSpy.calls.length).toEqual(0); expect(futimesSpy.calls.length).toEqual(0); @@ -950,24 +965,33 @@ describe('updateMetadata', function() { var futimesSpy = expect.spyOn(fs, 'futimes').andCallThrough(); - var now = Date.now(); - var then = now - 1000; - file.stat.mtime = new Date(then); - file.stat.atime = new Date(then); + // Use the mtime/atime of this file to have proper resolution + var stats = fs.statSync(__filename); + var mtime = stats.mtime; + var atime = stats.atime; + var mtimeEarlier = mtime.getTime() - 1000; + var atimeEarlier = atime.getTime() - 1000; - var fd = fs.openSync(inputPath, 'w+'); + var file = new File({ + base: outputBase, + path: outputPath, + contents: null, + stat: { + mtime: new Date(mtimeEarlier), + atime: new Date(atimeEarlier), + }, + }); - updateMetadata(fd, file, function(err) { + var fd = fs.openSync(outputPath, 'w+'); + + updateMetadata(fd, file, function() { expect(futimesSpy.calls.length).toEqual(1); var stats = fs.fstatSync(fd); - var mtimeMs = Date.parse(file.stat.mtime); - var mtime = resolution ? mtimeMs - (mtimeMs % resolution) : mtimeMs; - var atimeMs = Date.parse(file.stat.atime); - var atime = resolution ? atimeMs - (atimeMs % resolution) : atimeMs; - expect(file.stat.mtime).toEqual(new Date(then)); - expect(mtime).toEqual(Date.parse(stats.mtime)); - expect(file.stat.atime).toEqual(new Date(then)); - expect(atime).toEqual(Date.parse(stats.atime)); + + expect(file.stat.mtime).toEqual(new Date(mtimeEarlier)); + expect(stats.mtime.getTime()).toEqual(mtimeEarlier); + expect(file.stat.atime).toEqual(new Date(atimeEarlier)); + expect(stats.atime.getTime()).toEqual(atimeEarlier); fs.close(fd, done); }); @@ -979,16 +1003,22 @@ describe('updateMetadata', function() { return; } - var futimesSpy = expect.spyOn(fs, 'futimes').andCall(function(fd, atime, mtime, cb) { - cb(new Error('mocked error')); - }); + var futimesSpy = expect.spyOn(fs, 'futimes').andCall(mockError); var now = Date.now(); var then = now - 1000; - file.stat.mtime = new Date(then); - file.stat.atime = new Date(then); - var fd = fs.openSync(inputPath, 'w+'); + var file = new File({ + base: outputBase, + path: outputPath, + contents: null, + stat: { + mtime: new Date(then), + atime: new Date(then), + }, + }); + + var fd = fs.openSync(outputPath, 'w+'); expect(typeof fd === 'number').toEqual(true); updateMetadata(fd, file, function(err) { @@ -1007,12 +1037,20 @@ describe('updateMetadata', function() { var fchmodSpy = expect.spyOn(fs, 'fchmod').andCallThrough(); - var mode = parseInt('777', 8); - file.stat.mode = mode; + var mode = applyUmask('777'); + + var file = new File({ + base: outputBase, + path: outputPath, + contents: null, + stat: { + mode: mode, + }, + }); - var fd = fs.openSync(inputPath, 'w+'); + var fd = fs.openSync(outputPath, 'w+'); - updateMetadata(fd, file, function(err) { + updateMetadata(fd, file, function() { expect(fchmodSpy.calls.length).toEqual(1); var stats = fs.fstatSync(fd); expect(file.stat.mode).toEqual(stats.mode); @@ -1030,12 +1068,20 @@ describe('updateMetadata', function() { var fchmodSpy = expect.spyOn(fs, 'fchmod').andCallThrough(); - var mode = parseInt('1777', 8); - file.stat.mode = mode; + var mode = applyUmask('1777'); - var fd = fs.openSync(inputPath, 'w+'); + var file = new File({ + base: outputBase, + path: outputPath, + contents: null, + stat: { + mode: mode, + }, + }); - updateMetadata(fd, file, function(err) { + var fd = fs.openSync(outputPath, 'w+'); + + updateMetadata(fd, file, function() { expect(fchmodSpy.calls.length).toEqual(1); var stats = fs.fstatSync(fd); expect(file.stat.mode).toEqual(stats.mode); @@ -1050,15 +1096,21 @@ describe('updateMetadata', function() { return; } - var mode = parseInt('777', 8); - file.stat.mode = mode; - - var fd = fs.openSync(inputPath, 'w+'); + var mode = applyUmask('777'); - var fchmodSpy = expect.spyOn(fs, 'fchmod').andCall(function(fd, mode, cb) { - cb(new Error('mocked error')); + var file = new File({ + base: outputBase, + path: outputPath, + contents: null, + stat: { + mode: mode, + }, }); + var fd = fs.openSync(outputPath, 'w+'); + + var fchmodSpy = expect.spyOn(fs, 'fchmod').andCall(mockError); + updateMetadata(fd, file, function(err) { expect(err).toExist(); expect(fchmodSpy.calls.length).toEqual(1); @@ -1076,31 +1128,38 @@ describe('updateMetadata', function() { var fchmodSpy = expect.spyOn(fs, 'fchmod').andCallThrough(); var futimesSpy = expect.spyOn(fs, 'futimes').andCallThrough(); - var mode = parseInt('777', 8); - file.stat.mode = mode; + // Use the mtime/atime of this file to have proper resolution + var stats = fs.statSync(__filename); + var mtime = stats.mtime; + var atime = stats.atime; + var mtimeEarlier = mtime.getTime() - 1000; + var atimeEarlier = atime.getTime() - 1000; - var now = Date.now(); - var then = now - 1000; - file.stat.mtime = new Date(then); - file.stat.atime = new Date(then); + var mode = applyUmask('777'); + + var file = new File({ + base: outputBase, + path: outputPath, + contents: null, + stat: { + mtime: new Date(mtimeEarlier), + atime: new Date(atimeEarlier), + mode: mode, + }, + }); - var fd = fs.openSync(inputPath, 'w+'); + var fd = fs.openSync(outputPath, 'w+'); - updateMetadata(fd, file, function(err) { + updateMetadata(fd, file, function() { expect(fchmodSpy.calls.length).toEqual(1); expect(futimesSpy.calls.length).toEqual(1); var stats = fs.fstatSync(fd); - var mtimeMs = Date.parse(file.stat.mtime); - var mtime = resolution ? mtimeMs - (mtimeMs % resolution) : mtimeMs; - var atimeMs = Date.parse(file.stat.atime); - var atime = resolution ? atimeMs - (atimeMs % resolution) : atimeMs; - - expect(file.stat.mtime).toEqual(new Date(then)); - expect(mtime).toEqual(Date.parse(stats.mtime)); - expect(file.stat.atime).toEqual(new Date(then)); - expect(atime).toEqual(Date.parse(stats.atime)); - expect(file.stat.mode).toEqual(stats.mode); + + expect(file.stat.mtime).toEqual(new Date(mtimeEarlier)); + expect(stats.mtime.getTime()).toEqual(mtimeEarlier); + expect(file.stat.atime).toEqual(new Date(atimeEarlier)); + expect(stats.atime.getTime()).toEqual(atimeEarlier); fs.close(fd, done); }); @@ -1112,53 +1171,64 @@ describe('updateMetadata', function() { return; } - var expectedErr = new Error('mocked error'); + var mockedErr = new Error('mocked error'); var fchmodSpy = expect.spyOn(fs, 'fchmod').andCall(function(fd, mode, cb) { - cb(expectedErr); + cb(mockedErr); }); var futimesSpy = expect.spyOn(fs, 'futimes').andCallThrough(); - var mode = parseInt('777', 8); - file.stat.mode = mode; - var now = Date.now(); var then = now - 1000; - file.stat.mtime = new Date(then); - file.stat.atime = new Date(then); + var mode = applyUmask('777'); + + var file = new File({ + base: outputBase, + path: outputPath, + contents: null, + stat: { + mtime: new Date(then), + atime: new Date(then), + mode: mode, + }, + }); - var fd = fs.openSync(inputPath, 'w'); + var fd = fs.openSync(outputPath, 'w'); updateMetadata(fd, file, function(err) { expect(err).toExist(); - expect(err).toEqual(expectedErr); + expect(err).toEqual(mockedErr); expect(fchmodSpy.calls.length).toEqual(1); expect(futimesSpy.calls.length).toEqual(1); fs.close(fd, done); }); }); + + // TODO: forward fchown error tests }); describe('mkdirp', function() { - var fixtures = path.join(__dirname, './fixtures'); - var dir = path.join(fixtures, './bar'); + beforeEach(clean); + afterEach(clean); beforeEach(function(done) { - // Linux inherits the setgid of the directory and it messes up our assertions - // So we explixitly set the mode to 777 before each test - fs.chmod(fixtures, '777', done); - }); - - afterEach(function() { - return del(dir); + fs.mkdir(outputBase, function(err) { + if (err) { + return done(err); + } + + // Linux inherits the setgid of the directory and it messes up our assertions + // So we explixitly set the mode to 777 before each test + fs.chmod(outputBase, '777', done); + }); }); it('makes a single directory', function(done) { - mkdirp(dir, function(err) { + mkdirp(outputDirpath, function(err) { expect(err).toNotExist(); - expect(statHuman(dir)).toExist(); + expect(statMode(outputDirpath)).toExist(); done(); }); @@ -1170,19 +1240,20 @@ describe('mkdirp', function() { return; } - mkdirp(dir, function(err) { + var defaultMode = applyUmask(DEFAULT_DIR_MODE); + + mkdirp(outputDirpath, function(err) { expect(err).toNotExist(); - expect(statHuman(dir)).toEqual(DEFAULT_DIR_MODE); + expect(statMode(outputDirpath)).toEqual(defaultMode); done(); }); }); it('makes multiple directories', function(done) { - var nestedDir = path.join(dir, './baz/foo'); - mkdirp(nestedDir, function(err) { + mkdirp(outputNestedDirpath, function(err) { expect(err).toNotExist(); - expect(statHuman(nestedDir)).toExist(); + expect(statMode(outputNestedDirpath)).toExist(); done(); }); @@ -1194,10 +1265,11 @@ describe('mkdirp', function() { return; } - var nestedDir = path.join(dir, './baz/foo'); - mkdirp(nestedDir, function(err) { + var defaultMode = applyUmask(DEFAULT_DIR_MODE); + + mkdirp(outputNestedDirpath, function(err) { expect(err).toNotExist(); - expect(statHuman(nestedDir)).toEqual(DEFAULT_DIR_MODE); + expect(statMode(outputNestedDirpath)).toEqual(defaultMode); done(); }); @@ -1209,10 +1281,11 @@ describe('mkdirp', function() { return; } - var mode = parseInt('0700', 8); - mkdirp(dir, mode, function(err) { + var mode = applyUmask('700'); + + mkdirp(outputDirpath, mode, function(err) { expect(err).toNotExist(); - expect(statHuman(dir)).toEqual(masked(mode).toString(8)); + expect(statMode(outputDirpath)).toEqual(mode); done(); }); @@ -1224,10 +1297,11 @@ describe('mkdirp', function() { return; } - var mode = parseInt('2700', 8); - mkdirp(dir, mode, function(err) { + var mode = applyUmask('2700'); + + mkdirp(outputDirpath, mode, function(err) { expect(err).toNotExist(); - expect(statHuman(dir)).toEqual(masked(mode).toString(8)); + expect(statMode(outputDirpath)).toEqual(mode); done(); }); @@ -1239,13 +1313,14 @@ describe('mkdirp', function() { return; } - var mode = parseInt('0700', 8); - mkdirp(dir, mode, function(err) { + var mode = applyUmask('700'); + + mkdirp(outputDirpath, mode, function(err) { expect(err).toNotExist(); - mkdirp(dir, function(err2) { + mkdirp(outputDirpath, function(err2) { expect(err2).toNotExist(); - expect(statHuman(dir)).toEqual(masked(mode).toString(8)); + expect(statMode(outputDirpath)).toEqual(mode); done(); }); @@ -1258,11 +1333,11 @@ describe('mkdirp', function() { return; } - var nestedDir = path.join(dir, './baz/foo'); - var mode = parseInt('0700',8); - mkdirp(nestedDir, mode, function(err) { + var mode = applyUmask('700'); + + mkdirp(outputNestedDirpath, mode, function(err) { expect(err).toNotExist(); - expect(statHuman(nestedDir)).toEqual(masked(mode).toString(8)); + expect(statMode(outputNestedDirpath)).toEqual(mode); done(); }); @@ -1274,13 +1349,14 @@ describe('mkdirp', function() { return; } - var intermediateDir = path.join(dir, './baz'); - var nestedDir = path.join(intermediateDir, './foo'); - var mode = parseInt('0700',8); - mkdirp(nestedDir, mode, function(err) { + var intermediateDirpath = path.dirname(outputNestedDirpath); + var mode = applyUmask('700'); + var defaultMode = applyUmask(DEFAULT_DIR_MODE); + + mkdirp(outputNestedDirpath, mode, function(err) { expect(err).toNotExist(); - expect(statHuman(dir)).toEqual(DEFAULT_DIR_MODE); - expect(statHuman(intermediateDir)).toEqual(DEFAULT_DIR_MODE); + expect(statMode(outputDirpath)).toEqual(defaultMode); + expect(statMode(intermediateDirpath)).toEqual(defaultMode); done(); }); @@ -1292,14 +1368,16 @@ describe('mkdirp', function() { return; } - var mode = parseInt('0700',8); - mkdirp(dir, function(err) { + var mode = applyUmask('700'); + var defaultMode = applyUmask(DEFAULT_DIR_MODE); + + mkdirp(outputDirpath, function(err) { expect(err).toNotExist(); - expect(statHuman(dir)).toEqual(DEFAULT_DIR_MODE); + expect(statMode(outputDirpath)).toEqual(defaultMode); - mkdirp(dir, mode, function(err2) { + mkdirp(outputDirpath, mode, function(err2) { expect(err2).toNotExist(); - expect(statHuman(dir)).toEqual(masked(mode).toString(8)); + expect(statMode(outputDirpath)).toEqual(mode); done(); }); @@ -1307,14 +1385,13 @@ describe('mkdirp', function() { }); it('errors with EEXIST if file in path', function(done) { - var file = path.join(dir, './bar.txt'); - mkdirp(dir, function(err) { + mkdirp(outputDirpath, function(err) { expect(err).toNotExist(); - fs.writeFile(file, 'hello world', function(err2) { + fs.writeFile(outputNestedPath, contents, function(err2) { expect(err2).toNotExist(); - mkdirp(file, function(err3) { + mkdirp(outputNestedPath, function(err3) { expect(err3).toExist(); expect(err3.code).toEqual('EEXIST'); @@ -1330,19 +1407,19 @@ describe('mkdirp', function() { return; } - var file = path.join(dir, './bar.txt'); - var mode = parseInt('0700', 8); - mkdirp(dir, function(err) { + var mode = applyUmask('700'); + + mkdirp(outputDirpath, function(err) { expect(err).toNotExist(); - fs.writeFile(file, 'hello world', function(err2) { + fs.writeFile(outputNestedPath, contents, function(err2) { expect(err2).toNotExist(); - var expectedMode = statHuman(file); + var expectedMode = statMode(outputNestedPath); - mkdirp(file, mode, function(err3) { + mkdirp(outputNestedPath, mode, function(err3) { expect(err3).toExist(); - expect(statHuman(file)).toEqual(expectedMode); + expect(statMode(outputNestedPath)).toEqual(expectedMode); done(); }); @@ -1353,68 +1430,60 @@ describe('mkdirp', function() { describe('createWriteStream', function() { - // These tests needed to use the `close` event because - // the file descriptor was not closed on windows - - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - var expectedContents = fs.readFileSync(inputPath, 'utf-8'); - var outputDir = path.join(__dirname, './out-fixtures/'); - var outputPath = path.join(outputDir, './test.coffee'); + beforeEach(clean); + afterEach(clean); beforeEach(function(done) { // For some reason, the outputDir sometimes exists on Windows // So we use our mkdirp to create it - fo.mkdirp(outputDir, done); - }); - - afterEach(function() { - return del(outputDir); + mkdirp(outputBase, done); }); it('accepts just a file path and writes to it', function(done) { - var inStream = fs.createReadStream(inputPath); - var outStream = fo.createWriteStream(outputPath); - outStream.on('close', function() { - var contents = fs.readFileSync(outputPath, 'utf-8'); - expect(contents).toEqual(expectedContents); - done(); - }); + function assert(err) { + var outputContents = fs.readFileSync(outputPath, 'utf8'); + expect(outputContents).toEqual(contents); + done(err); + } - inStream.pipe(outStream); + pipe([ + from([contents]), + createWriteStream(outputPath), + ], assert); }); it('accepts flag option', function(done) { // Write 12 stars then 12345 because the length of expected is 12 fs.writeFileSync(outputPath, '************12345'); - var inStream = fs.createReadStream(inputPath); - // Replaces from the beginning of the file - var outStream = fo.createWriteStream(outputPath, { flag: 'r+' }); - - outStream.on('close', function() { - var contents = fs.readFileSync(outputPath, 'utf-8'); - expect(contents).toEqual(expectedContents + '12345'); - done(); - }); + function assert(err) { + var outputContents = fs.readFileSync(outputPath, 'utf8'); + expect(outputContents).toEqual(contents + '12345'); + done(err); + } - inStream.pipe(outStream); + pipe([ + from([contents]), + // Replaces from the beginning of the file + createWriteStream(outputPath, { flag: 'r+' }), + ], assert); }); it('accepts append flag as option & places cursor at the end', function(done) { fs.writeFileSync(outputPath, '12345'); - var inStream = fs.createReadStream(inputPath); - // Appends to the end of the file - var outStream = fo.createWriteStream(outputPath, { flag: 'a' }); - - outStream.on('close', function() { - var contents = fs.readFileSync(outputPath, 'utf-8'); - expect(contents).toEqual('12345' + expectedContents); - done(); - }); + function assert(err) { + var outputContents = fs.readFileSync(outputPath, 'utf8'); + expect(outputContents).toEqual('12345' + contents); + done(err); + } - inStream.pipe(outStream); + pipe([ + from([contents]), + // Appends to the end of the file + createWriteStream(outputPath, { flag: 'a' }), + ], assert); }); it('accepts mode option', function(done) { @@ -1424,87 +1493,96 @@ describe('createWriteStream', function() { return; } - var expectedMode = parseInt('777', 8) & ~process.umask(); - var inStream = fs.createReadStream(inputPath); - var outStream = fo.createWriteStream(outputPath, { mode: expectedMode }); + var mode = applyUmask('777'); - outStream.on('finish', function() { - var stat = fs.statSync(outputPath); - expect(masked(stat.mode)).toEqual(expectedMode); - done(); - }); + function assert(err) { + expect(statMode(outputPath)).toEqual(mode); + done(err); + } - inStream.pipe(outStream); + pipe([ + from([contents]), + createWriteStream(outputPath, { mode: mode }), + ], assert); }); it('uses default file mode if no mode options', function(done) { - var expectedMode = constants.DEFAULT_FILE_MODE & ~process.umask(); - var inStream = fs.createReadStream(inputPath); - var outStream = fo.createWriteStream(outputPath); + var defaultMode = applyUmask(DEFAULT_FILE_MODE); - outStream.on('close', function() { - var stat = fs.statSync(outputPath); - expect(masked(stat.mode)).toEqual(expectedMode); - done(); - }); + function assert(err) { + expect(statMode(outputPath)).toEqual(defaultMode); + done(err); + } - inStream.pipe(outStream); + pipe([ + from([contents]), + createWriteStream(outputPath), + ], assert); }); it('accepts a flush function that is called before close emitted', function(done) { var flushCalled = false; - var inStream = fs.createReadStream(inputPath); - var outStream = fo.createWriteStream(outputPath, {}, function(fd, cb) { + + var outStream = createWriteStream(outputPath, {}, function(fd, cb) { flushCalled = true; cb(); }); - outStream.on('close', function() { + function assert(err) { expect(flushCalled).toEqual(true); - done(); - }); + done(err); + } - inStream.pipe(outStream); + pipe([ + from([contents]), + outStream, + ], assert); }); it('can specify flush without options argument', function(done) { var flushCalled = false; - var inStream = fs.createReadStream(inputPath); - var outStream = fo.createWriteStream(outputPath, function(fd, cb) { + + var outStream = createWriteStream(outputPath, function(fd, cb) { flushCalled = true; cb(); }); - outStream.on('close', function() { + function assert(err) { expect(flushCalled).toEqual(true); - done(); - }); + done(err); + } - inStream.pipe(outStream); + pipe([ + from([contents]), + outStream, + ], assert); }); it('passes the file descriptor to flush', function(done) { var flushCalled = false; - var inStream = fs.createReadStream(inputPath); - var outStream = fo.createWriteStream(outputPath, function(fd, cb) { + + var outStream = createWriteStream(outputPath, function(fd, cb) { expect(fd).toBeA('number'); flushCalled = true; cb(); }); - outStream.on('close', function() { + function assert(err) { expect(flushCalled).toEqual(true); - done(); - }); + done(err); + } - inStream.pipe(outStream); + pipe([ + from([contents]), + outStream, + ], assert); }); it('passes a callback to flush to call when work is done', function(done) { var flushCalled = false; var timeoutCalled = false; - var inStream = fs.createReadStream(inputPath); - var outStream = fo.createWriteStream(outputPath, function(fd, cb) { + + var outStream = createWriteStream(outputPath, function(fd, cb) { flushCalled = true; setTimeout(function() { timeoutCalled = true; @@ -1512,42 +1590,44 @@ describe('createWriteStream', function() { }, 250); }); - outStream.on('close', function() { + function assert(err) { expect(flushCalled).toEqual(true); expect(timeoutCalled).toEqual(true); - done(); - }); + done(err); + } - inStream.pipe(outStream); + pipe([ + from([contents]), + outStream, + ], assert); }); it('emits an error if open fails', function(done) { - var badOutputPath = path.join(outputDir, './non-exist/test.coffee'); - var inStream = fs.createReadStream(inputPath); - var outStream = fo.createWriteStream(badOutputPath); + var badOutputPath = path.join(outputBase, './non-exist/test.coffee'); - // There is no file descriptor if open fails so mark done in the error - outStream.on('error', function(err) { + function assert(err) { expect(err).toBeAn(Error); done(); - }); + } - inStream.pipe(outStream); + pipe([ + from([contents]), + createWriteStream(badOutputPath), + ], assert); }); it('emits an error if write fails', function(done) { // Create the file so it can be opened with `r` - fs.writeFileSync(outputPath, expectedContents); + fs.writeFileSync(outputPath, contents); - var inStream = fs.createReadStream(inputPath); - var outStream = fo.createWriteStream(outputPath, { flag: 'r' }); - - outStream.on('error', function(err) { + function assert(err) { expect(err).toBeAn(Error); - }); - - outStream.on('close', done); + done(); + } - inStream.pipe(outStream); + pipe([ + from([contents]), + createWriteStream(outputPath, { flag: 'r' }), + ], assert); }); }); diff --git a/test/fixtures/not-owned/not-owned.txt b/test/fixtures/not-owned/not-owned.txt new file mode 100644 index 00000000..c57eff55 --- /dev/null +++ b/test/fixtures/not-owned/not-owned.txt @@ -0,0 +1 @@ +Hello World! \ No newline at end of file diff --git a/test/fixtures/test.coffee b/test/fixtures/test.coffee deleted file mode 100644 index 6769dd60..00000000 --- a/test/fixtures/test.coffee +++ /dev/null @@ -1 +0,0 @@ -Hello world! \ No newline at end of file diff --git a/test/fixtures/test.txt b/test/fixtures/test.txt new file mode 100644 index 00000000..980a0d5f --- /dev/null +++ b/test/fixtures/test.txt @@ -0,0 +1 @@ +Hello World! diff --git a/test/fixtures/wow/suchempty b/test/fixtures/wow/suchempty deleted file mode 100644 index 65bbcaab..00000000 --- a/test/fixtures/wow/suchempty +++ /dev/null @@ -1 +0,0 @@ -suchempty \ No newline at end of file diff --git a/test/integration.js b/test/integration.js new file mode 100644 index 00000000..7528cc37 --- /dev/null +++ b/test/integration.js @@ -0,0 +1,52 @@ +'use strict'; + +var path = require('path'); + +var fs = require('graceful-fs'); +var miss = require('mississippi'); + +var vfs = require('../'); + +var cleanup = require('./utils/cleanup'); +var testStreams = require('./utils/test-streams'); +var testConstants = require('./utils/test-constants'); + +var pipe = miss.pipe; + +var count = testStreams.count; + +var base = testConstants.outputBase; +var inputBase = path.join(base, './in/'); +var inputGlob = path.join(inputBase, './*.txt'); +var outputBase = path.join(base, './out/'); +var content = testConstants.content; + +var clean = cleanup([base]); + +describe('integrations', function() { + + beforeEach(clean); + afterEach(clean); + + it('does not exhaust available file descriptors when streaming thousands of files', function(done) { + // This can be a very slow test on boxes with slow disk i/o + this.timeout(0); + + // Make a ton of files. Changed from hard links due to Windows failures + var expectedCount = 6000; + + fs.mkdirSync(base); + fs.mkdirSync(inputBase); + + for (var idx = 0; idx < expectedCount; idx++) { + var filepath = path.join(inputBase, './test' + idx + '.txt'); + fs.writeFileSync(filepath, content); + } + + pipe([ + vfs.src(inputGlob, { buffer: false }), + count(expectedCount), + vfs.dest(outputBase), + ], done); + }); +}); diff --git a/test/not-owned.js b/test/not-owned.js index 5758e887..8efb3fb8 100644 --- a/test/not-owned.js +++ b/test/not-owned.js @@ -1,75 +1,93 @@ 'use strict'; -var path = require('path'); - -var expect = require('expect'); - var fs = require('graceful-fs'); var File = require('vinyl'); +var expect = require('expect'); +var miss = require('mississippi'); var vfs = require('../'); +var cleanup = require('./utils/cleanup'); +var applyUmask = require('./utils/apply-umask'); +var testConstants = require('./utils/test-constants'); + +var from = miss.from; +var pipe = miss.pipe; +var concat = miss.concat; + +var notOwnedBase = testConstants.notOwnedBase; +var notOwnedPath = testConstants.notOwnedPath; +var contents = testConstants.contents; + +var clean = cleanup(); + describe('.dest() on not owned files', function() { - var outDir = path.join(__dirname, './not-owned/'); - var outPath = path.join(outDir, 'not-owned.txt'); - var dirStats = fs.statSync(outDir); - var fileStats = fs.statSync(outPath); + var dirStats = fs.statSync(notOwnedBase); + var fileStats = fs.statSync(notOwnedPath); + + beforeEach(clean); + afterEach(clean); it('does not error if mtime is different', function(done) { if (dirStats.uid !== 0 || fileStats.uid !== 0) { - console.log('Test files not owned by root. ' + - 'Please chown ' + outDir + ' and' + outPath + ' and try again.'); + console.log('Test files not owned by root.'); + console.log('Please chown ' + notOwnedBase + ' and' + notOwnedPath + ' and try again.'); this.skip(); return; } - var expectedFile = new File({ - base: __dirname, - cwd: __dirname, - path: 'not-owned/not-owned.txt', - contents: new Buffer('Something new'), + var futimesSpy = expect.spyOn(fs, 'futimes').andCallThrough(); + + var earlier = Date.now() - 1000; + + var file = new File({ + base: notOwnedBase, + path: notOwnedPath, + contents: new Buffer(contents), stat: { - mtime: new Date(Date.now() - 1000), + mtime: new Date(earlier), }, }); - var stream = vfs.dest(outDir); - stream.write(expectedFile); - stream.on('error', function(err) { - expect(err).toNotExist(); - done(err); - }); - stream.on('end', done); - stream.end(); + function assert() { + expect(futimesSpy.calls.length).toEqual(0); + } + + pipe([ + from.obj([file]), + vfs.dest(notOwnedBase), + concat(assert), + ], done); }); it('does not error if mode is different', function(done) { if (dirStats.uid !== 0 || fileStats.uid !== 0) { - console.log('Test files not owned by root. ' + - 'Please chown ' + outDir + ' and' + outPath + ' and try again.'); + console.log('Test files not owned by root.'); + console.log('Please chown ' + notOwnedBase + ' and' + notOwnedPath + ' and try again.'); this.skip(); return; } - var expectedFile = new File({ - base: __dirname, - cwd: __dirname, - path: 'not-owned/not-owned.txt', - contents: new Buffer('Something new'), + var fchmodSpy = expect.spyOn(fs, 'fchmod').andCallThrough(); + + var file = new File({ + base: notOwnedBase, + path: notOwnedPath, + contents: new Buffer(contents), stat: { - mode: parseInt('777', 8), + mode: applyUmask('777'), }, }); - var stream = vfs.dest(outDir); - stream.write(expectedFile); - stream.on('error', function(err) { - expect(err).toNotExist(); - done(err); - }); - stream.on('end', done); - stream.end(); - }); + function assert() { + expect(fchmodSpy.calls.length).toEqual(0); + } + pipe([ + from.obj([file]), + vfs.dest(notOwnedBase), + concat(assert), + ], done); + }); }); diff --git a/test/not-owned/not-owned.txt b/test/not-owned/not-owned.txt deleted file mode 100644 index 88bf7d55..00000000 --- a/test/not-owned/not-owned.txt +++ /dev/null @@ -1 +0,0 @@ -Something new \ No newline at end of file diff --git a/test/spy.js b/test/spy.js deleted file mode 100644 index f64b6cec..00000000 --- a/test/spy.js +++ /dev/null @@ -1,32 +0,0 @@ -'use strict'; - -var fs = require('graceful-fs'); -var sinon = require('sinon'); - -var errorfn = false; - -function maybeCallAsync(module, func) { - var original = module[func]; - return sinon.stub(module, func, function() { - var args = Array.prototype.slice.call(arguments); - args.unshift(module, func); - var err = typeof errorfn === 'function' && - errorfn.apply(this, args); - if (!err) { - original.apply(this, arguments); - } else { - arguments[arguments.length - 1](err); - } - }); -} - -module.exports = { - setError: function(fn) { - errorfn = fn; - }, - chmodSpy: maybeCallAsync(fs, 'chmod'), - fchmodSpy: maybeCallAsync(fs, 'fchmod'), - futimesSpy: maybeCallAsync(fs, 'futimes'), - statSpy: maybeCallAsync(fs, 'stat'), - fstatSpy: maybeCallAsync(fs, 'fstat'), -}; diff --git a/test/src-symlinks.js b/test/src-symlinks.js new file mode 100644 index 00000000..01b005a6 --- /dev/null +++ b/test/src-symlinks.js @@ -0,0 +1,107 @@ +'use strict'; + +var fs = require('graceful-fs'); +var expect = require('expect'); +var miss = require('mississippi'); + +var vfs = require('../'); + +var cleanup = require('./utils/cleanup'); +var testConstants = require('./utils/test-constants'); + +var pipe = miss.pipe; +var concat = miss.concat; + +var outputBase = testConstants.outputBase; +var inputPath = testConstants.inputPath; +var inputDirpath = testConstants.inputDirpath; +var outputDirpath = testConstants.outputDirpath; +var symlinkNestedTarget = testConstants.symlinkNestedTarget; +var symlinkPath = testConstants.symlinkPath; +var symlinkDirpath = testConstants.symlinkDirpath; +var symlinkNestedFirst = testConstants.symlinkNestedFirst; +var symlinkNestedSecond = testConstants.symlinkNestedSecond; + +var clean = cleanup([outputBase]); + +describe('.src() with symlinks', function() { + + beforeEach(clean); + afterEach(clean); + + beforeEach(function(done) { + fs.mkdirSync(outputBase); + fs.mkdirSync(outputDirpath); + fs.symlinkSync(inputDirpath, symlinkDirpath); + fs.symlinkSync(inputPath, symlinkPath); + fs.symlinkSync(symlinkNestedTarget, symlinkNestedSecond); + fs.symlinkSync(symlinkNestedSecond, symlinkNestedFirst); + done(); + }); + + it('follows symlinks correctly', function(done) { + function assert(files) { + expect(files.length).toEqual(1); + // The path should be the symlink itself + expect(files[0].path).toEqual(symlinkNestedFirst); + // But the content should be what's in the actual file + expect(files[0].contents.toString()).toEqual('symlink works\n'); + // And the stats should have been updated + expect(files[0].stat.isSymbolicLink()).toEqual(false); + expect(files[0].stat.isFile()).toEqual(true); + } + + pipe([ + vfs.src(symlinkNestedFirst), + concat(assert), + ], done); + }); + + it('follows directory symlinks correctly', function(done) { + function assert(files) { + expect(files.length).toEqual(1); + // The path should be the symlink itself + expect(files[0].path).toEqual(symlinkDirpath); + // But the contents should be null + expect(files[0].contents).toEqual(null); + // And the stats should have been updated + expect(files[0].stat.isSymbolicLink()).toEqual(false); + expect(files[0].stat.isDirectory()).toEqual(true); + } + + pipe([ + vfs.src(symlinkDirpath), + concat(assert), + ], done); + }); + + it('preserves file symlinks with followSymlinks option set to false', function(done) { + var expectedRelativeSymlinkPath = fs.readlinkSync(symlinkPath); + + function assert(files) { + expect(files.length).toEqual(1); + expect(files[0].path).toEqual(symlinkPath); + expect(files[0].symlink).toEqual(expectedRelativeSymlinkPath); + } + + pipe([ + vfs.src(symlinkPath, { followSymlinks: false }), + concat(assert), + ], done); + }); + + it('preserves directory symlinks with followSymlinks option set to false', function(done) { + var expectedRelativeSymlinkPath = fs.readlinkSync(symlinkDirpath); + + function assert(files) { + expect(files.length).toEqual(1); + expect(files[0].path).toEqual(symlinkDirpath); + expect(files[0].symlink).toEqual(expectedRelativeSymlinkPath); + } + + pipe([ + vfs.src(symlinkDirpath, { followSymlinks: false }), + concat(assert), + ], done); + }); +}); diff --git a/test/src.js b/test/src.js index 251425e1..8abf4c93 100644 --- a/test/src.js +++ b/test/src.js @@ -1,512 +1,364 @@ 'use strict'; -var vfs = require('../'); - var path = require('path'); -var fs = require('graceful-fs'); -var bufEqual = require('buffer-equal'); -var through = require('through2'); +var fs = require('graceful-fs'); var File = require('vinyl'); +var expect = require('expect'); +var miss = require('mississippi'); + +var vfs = require('../'); + +var testConstants = require('./utils/test-constants'); -var should = require('should'); -require('mocha'); +var pipe = miss.pipe; +var from = miss.from; +var concat = miss.concat; +var through = miss.through; -var dataWrap = function(fn) { - return function(data, enc, cb) { - fn(data); - cb(); - }; -}; +var inputBase = testConstants.inputBase; +var inputPath = testConstants.inputPath; +var inputDirpath = testConstants.inputDirpath; +var bomInputPath = testConstants.bomInputPath; +var beEncodedInputPath = testConstants.beEncodedInputPath; +var leEncodedInputPath = testConstants.leEncodedInputPath; +var contents = testConstants.contents; -describe('source stream', function() { +describe('.src()', function() { - it('should explode on invalid glob (empty)', function(done) { + it('throws on invalid glob (empty)', function(done) { var stream; try { stream = vfs.src(); } catch (err) { - should.exist(err); - should.not.exist(stream); + expect(err).toExist(); + expect(stream).toNotExist(); done(); } }); - it('should explode on invalid glob (empty string)', function(done) { + it('throws on invalid glob (empty string)', function(done) { var stream; try { stream = vfs.src(''); } catch (err) { - should.exist(err); - should.not.exist(stream); + expect(err).toExist(); + expect(stream).toNotExist(); done(); } }); - it('should explode on invalid glob (number)', function(done) { + it('throws on invalid glob (number)', function(done) { var stream; try { stream = vfs.src(123); } catch (err) { - should.exist(err); - should.not.exist(stream); + expect(err).toExist(); + expect(stream).toNotExist(); done(); } }); - it('should explode on invalid glob (nested array)', function(done) { + it('throws on invalid glob (nested array)', function(done) { var stream; try { stream = vfs.src([['./fixtures/*.coffee']]); } catch (err) { - should.exist(err); - should.not.exist(stream); - err.message.should.containEql('Invalid glob argument'); + expect(err).toExist(); + expect(stream).toNotExist(); + expect(err.message).toInclude('Invalid glob argument'); done(); } }); - it('should explode on invalid glob (empty string in array)', function(done) { + it('throws on invalid glob (empty string in array)', function(done) { var stream; try { stream = vfs.src(['']); } catch (err) { - should.exist(err); - should.not.exist(stream); + expect(err).toExist(); + expect(stream).toNotExist(); done(); } }); - it('should explode on invalid glob (empty array)', function(done) { + it('throws on invalid glob (empty array)', function(done) { var stream; try { stream = vfs.src([]); } catch (err) { - should.exist(err); - should.not.exist(stream); + expect(err).toExist(); + expect(stream).toNotExist(); done(); } }); - it('should error on file not existing', function(done) { - var stream = vfs.src('./fixtures/noexist.coffee'); - stream.on('error', function(err) { - should.exist(err); + it('emits an error on file not existing', function(done) { + function assert(err) { + expect(err).toExist(); done(); - }); - }); - - it('should pass through writes', function(done) { - var expectedPath = path.join(__dirname, './fixtures/test.coffee'); - var expectedContent = fs.readFileSync(expectedPath); - var files = []; - var expectedFile = new File({ - base: __dirname, - cwd: __dirname, - path: expectedPath, - contents: expectedContent, - stat: fs.lstatSync(expectedPath), - }); + } - var stream = vfs.src(expectedPath, { cwd: __dirname, base: __dirname }); - stream.on('data', function(file) { - files.push(file); - }); - stream.once('end', function() { - files.length.should.equal(2); - files[0].should.eql(expectedFile); - bufEqual(files[0].contents, expectedContent).should.equal(true); - files[1].should.eql(expectedFile); - bufEqual(files[1].contents, expectedContent).should.equal(true); - done(); - }); - stream.write(expectedFile); + pipe([ + vfs.src('./fixtures/noexist.coffee'), + concat(), + ], assert); }); - it('should strip BOM from UTF-8-encoded files by default', function(done) { - var expectedPath = path.join(__dirname, './fixtures/bom-utf8.txt'); - var expectedContent = fs.readFileSync(expectedPath) - // U+FEFF takes up 3 bytes in UTF-8: http://mothereff.in/utf-8#%EF%BB%BF - .slice(3); + it('passes through writes', function(done) { + var file = new File({ + base: inputBase, + path: inputPath, + contents: new Buffer(contents), + stat: fs.statSync(inputPath), + }); - var buffered = []; + var srcStream = vfs.src(inputPath); - var onEnd = function() { - buffered.length.should.equal(1); - should.exist(buffered[0].stat); - buffered[0].path.should.equal(expectedPath); - buffered[0].isBuffer().should.equal(true); - bufEqual(buffered[0].contents, expectedContent).should.equal(true); - done(); - }; + function assert(files) { + expect(files.length).toEqual(2); + expect(files[0]).toEqual(file); + } - var stream = vfs.src('./fixtures/bom-utf8.txt', { cwd: __dirname }); + srcStream.write(file); - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); - stream.pipe(bufferStream); + pipe([ + srcStream, + concat(assert), + ], done); }); - it('should not strip BOM from UTF-8-encoded files if option is false', function(done) { - var expectedPath = path.join(__dirname, './fixtures/bom-utf8.txt'); - var expectedContent = fs.readFileSync(expectedPath); - - var buffered = []; + it('strips BOM from utf8-encoded files by default', function(done) { + // U+FEFF takes up 3 bytes in UTF-8: http://mothereff.in/utf-8#%EF%BB%BF + var expectedContent = fs.readFileSync(bomInputPath).slice(3); - var onEnd = function() { - buffered.length.should.equal(1); - should.exist(buffered[0].stat); - buffered[0].path.should.equal(expectedPath); - buffered[0].isBuffer().should.equal(true); - bufEqual(buffered[0].contents, expectedContent).should.equal(true); - done(); - }; - - var stream = vfs.src('./fixtures/bom-utf8.txt', { cwd: __dirname, stripBOM: false }); + function assert(files) { + expect(files.length).toEqual(1); + expect(files[0].contents).toMatch(expectedContent); + } - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); - stream.pipe(bufferStream); + pipe([ + vfs.src(bomInputPath), + concat(assert), + ], done); }); - it('should not strip anything that looks like a UTF-8-encoded BOM from UTF-16-BE-encoded files', function(done) { - // Note: this goes for any non-UTF-8 encoding, but testing for UTF-16-BE - // and UTF-16-LE is enough to demonstrate this is done properly. - var expectedPath = path.join(__dirname, './fixtures/bom-utf16be.txt'); - var expectedContent = fs.readFileSync(expectedPath); - - var buffered = []; + it('does not strip BOM from utf8-encoded files if option is false', function(done) { + var expectedContent = fs.readFileSync(bomInputPath); - var onEnd = function() { - buffered.length.should.equal(1); - should.exist(buffered[0].stat); - buffered[0].path.should.equal(expectedPath); - buffered[0].isBuffer().should.equal(true); - bufEqual(buffered[0].contents, expectedContent).should.equal(true); - done(); - }; - - var stream = vfs.src('./fixtures/bom-utf16be.txt', { cwd: __dirname }); + function assert(files) { + expect(files.length).toEqual(1); + expect(files[0].contents).toMatch(expectedContent); + } - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); - stream.pipe(bufferStream); + pipe([ + vfs.src(bomInputPath, { stripBOM: false }), + concat(assert), + ], done); }); - it('should not strip anything that looks like a UTF-8-encoded BOM from UTF-16-LE-encoded files', function(done) { - // Note: this goes for any non-UTF-8 encoding, but testing for UTF-16-BE - // and UTF-16-LE is enough to demonstrate this is done properly. - var expectedPath = path.join(__dirname, './fixtures/bom-utf16le.txt'); - var expectedContent = fs.readFileSync(expectedPath); - - var buffered = []; + // This goes for any non-UTF-8 encoding. + // UTF-16-BE is enough to demonstrate this is done properly. + it('does not strip anything that looks like a utf8-encoded BOM from utf16be-encoded files', function(done) { + var expectedContent = fs.readFileSync(beEncodedInputPath); - var onEnd = function() { - buffered.length.should.equal(1); - should.exist(buffered[0].stat); - buffered[0].path.should.equal(expectedPath); - buffered[0].isBuffer().should.equal(true); - bufEqual(buffered[0].contents, expectedContent).should.equal(true); - done(); + function assert(files) { + expect(files.length).toEqual(1); + expect(files[0].contents).toMatch(expectedContent); }; - var stream = vfs.src('./fixtures/bom-utf16le.txt', { cwd: __dirname }); - - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); - stream.pipe(bufferStream); + pipe([ + vfs.src(beEncodedInputPath), + concat(assert), + ], done); }); - it('should glob a file with default settings', function(done) { - var expectedPath = path.join(__dirname, './fixtures/test.coffee'); - var expectedContent = fs.readFileSync(expectedPath); - - var buffered = []; + // This goes for any non-UTF-8 encoding. + // UTF-16-LE is enough to demonstrate this is done properly. + it('does not strip anything that looks like a utf8-encoded BOM from utf16le-encoded files', function(done) { + var expectedContent = fs.readFileSync(leEncodedInputPath); - var onEnd = function() { - buffered.length.should.equal(1); - should.exist(buffered[0].stat); - buffered[0].path.should.equal(expectedPath); - buffered[0].isBuffer().should.equal(true); - bufEqual(buffered[0].contents, expectedContent).should.equal(true); - done(); - }; - - var stream = vfs.src('./fixtures/*.coffee', { cwd: __dirname }); + function assert(files) { + expect(files.length).toEqual(1); + expect(files[0].contents).toMatch(expectedContent); + } - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); - stream.pipe(bufferStream); + pipe([ + vfs.src(leEncodedInputPath), + concat(assert), + ], done); }); - it('should glob a file with default settings and relative cwd', function(done) { - var expectedPath = path.join(__dirname, './fixtures/test.coffee'); - var expectedContent = fs.readFileSync(expectedPath); - - var buffered = []; - - var onEnd = function() { - buffered.length.should.equal(1); - should.exist(buffered[0].stat); - buffered[0].path.should.equal(expectedPath); - buffered[0].isBuffer().should.equal(true); - bufEqual(buffered[0].contents, expectedContent).should.equal(true); - done(); - }; - - var stream = vfs.src('./fixtures/*.coffee', { cwd: path.relative(process.cwd(), __dirname) }); + it('globs files with default settings', function(done) { + function assert(files) { + expect(files.length).toEqual(4); + } - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); - stream.pipe(bufferStream); + pipe([ + vfs.src('./fixtures/*.txt', { cwd: __dirname }), + concat(assert), + ], done); }); - it('should glob a directory with default settings', function(done) { - var expectedPath = path.join(__dirname, './fixtures/wow/'); - - var buffered = []; - - var onEnd = function() { - buffered.length.should.equal(1); - buffered[0].path.should.equal(expectedPath); - buffered[0].isNull().should.equal(true); - buffered[0].isDirectory().should.equal(true); - done(); - }; + it('globs files with default settings and relative cwd', function(done) { + var cwd = path.relative(process.cwd(), __dirname); - var stream = vfs.src('./fixtures/wow/', { cwd: __dirname }); + function assert(files) { + expect(files.length).toEqual(4); + } - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); - stream.pipe(bufferStream); + pipe([ + vfs.src('./fixtures/*.txt', { cwd: cwd }), + concat(assert), + ], done); }); - it('should glob a file with with no contents', function(done) { - var expectedPath = path.join(__dirname, './fixtures/test.coffee'); - - var buffered = []; - - var onEnd = function() { - buffered.length.should.equal(1); - buffered[0].path.should.equal(expectedPath); - buffered[0].isNull().should.equal(true); - should.not.exist(buffered[0].contents); - done(); - }; + // TODO: need to normalize the path of a directory vinyl object + it('globs a directory with default settings', function(done) { + var inputDirGlob = path.join(inputBase, './f*/'); - var stream = vfs.src('./fixtures/*.coffee', { cwd: __dirname, read: false }); + function assert(files) { + expect(files.length).toEqual(1); + expect(files[0].isNull()).toEqual(true); + expect(files[0].isDirectory()).toEqual(true); + } - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); - stream.pipe(bufferStream); + pipe([ + vfs.src(inputDirGlob), + concat(assert), + ], done); }); - it('should glob a file changed after since', function(done) { - var expectedPath = path.join(__dirname, './fixtures/test.coffee'); - var expectedContent = fs.readFileSync(expectedPath); - var lastUpdateDate = new Date(+fs.statSync(expectedPath).mtime - 1000); + it('globs a directory with default settings and relative cwd', function(done) { + var cwd = path.relative(process.cwd(), __dirname); - var buffered = []; - - var onEnd = function() { - buffered.length.should.equal(1); - should.exist(buffered[0].stat); - buffered[0].path.should.equal(expectedPath); - buffered[0].isBuffer().should.equal(true); - bufEqual(buffered[0].contents, expectedContent).should.equal(true); - done(); - }; - - var stream = vfs.src('./fixtures/*.coffee', { cwd: __dirname, since: lastUpdateDate }); + function assert(files) { + expect(files.length).toEqual(1); + expect(files[0].isNull()).toEqual(true); + expect(files[0].isDirectory()).toEqual(true); + } - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); - stream.pipe(bufferStream); + pipe([ + vfs.src('./fixtures/f*/', { cwd: cwd }), + concat(assert), + ], done); }); - it('should not glob a file changed before since', function(done) { - var expectedPath = path.join(__dirname, './fixtures/test.coffee'); - var lastUpdateDate = new Date(+fs.statSync(expectedPath).mtime + 1000); - - var buffered = []; - - var onEnd = function() { - buffered.length.should.equal(0); - done(); - }; - - var stream = vfs.src('./fixtures/*.coffee', { cwd: __dirname, since: lastUpdateDate }); + it('streams a directory with default settings', function(done) { + function assert(files) { + expect(files.length).toEqual(1); + expect(files[0].path).toEqual(inputDirpath); + expect(files[0].isNull()).toEqual(true); + expect(files[0].isDirectory()).toEqual(true); + } - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); - stream.pipe(bufferStream); + pipe([ + vfs.src(inputDirpath), + concat(assert), + ], done); }); - it('should glob a file with streaming contents', function(done) { - var expectedPath = path.join(__dirname, './fixtures/test.coffee'); - var expectedContent = fs.readFileSync(expectedPath); - - var buffered = []; - - var onEnd = function() { - buffered.length.should.equal(1); - should.exist(buffered[0].stat); - buffered[0].path.should.equal(expectedPath); - buffered[0].isStream().should.equal(true); - - var contentBuffer = new Buffer([]); - var contentBufferStream = through(dataWrap(function(data) { - contentBuffer = Buffer.concat([contentBuffer, data]); - })); - buffered[0].contents.pipe(contentBufferStream); - buffered[0].contents.once('end', function() { - bufEqual(contentBuffer, expectedContent); - done(); - }); - }; - - var stream = vfs.src('./fixtures/*.coffee', { cwd: __dirname, buffer: false }); + it('streams file with with no contents using read: false option', function(done) { + function assert(files) { + expect(files.length).toEqual(1); + expect(files[0].path).toEqual(inputPath); + expect(files[0].isNull()).toEqual(true); + expect(files[0].contents).toNotExist(); + } - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); - stream.pipe(bufferStream); + pipe([ + vfs.src(inputPath, { read: false }), + concat(assert), + ], done); }); - it('should pass files through', function(done) { - var expectedPaths = [ - path.join(__dirname, './fixtures/test.coffee'), - path.join(__dirname, './fixtures/wow/suchempty'), - ]; - var expectedContents = expectedPaths.map(function(path/* More args here so can't pass function directly */) { - return fs.readFileSync(path); - }); - - var buffered = []; - - var onEnd = function() { - buffered.length.should.equal(2); - buffered.forEach(function(file) { - should.exist(file.stat); - file.isBuffer().should.equal(true); + it('streams a file changed after since', function(done) { + var lastUpdateDate = new Date(+fs.statSync(inputPath).mtime - 1000); - expectedPaths.some(function(expectedPath) { - return file.path === expectedPath; - }).should.equal(true); - - expectedContents.some(function(expectedContent) { - return bufEqual(file.contents, expectedContent); - }).should.equal(true); - }); - done(); - }; - - var stream1 = vfs.src('./fixtures/*.coffee', { cwd: __dirname }); - var stream2 = vfs.src('./fixtures/wow/*', { cwd: __dirname, passthrough: true }); + function assert(files) { + expect(files.length).toEqual(1); + expect(files[0].path).toEqual(inputPath); + } - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); - stream1.pipe(stream2).pipe(bufferStream); + pipe([ + vfs.src(inputPath, { since: lastUpdateDate }), + concat(assert), + ], done); }); - it('should not pass options.read on to through2', function(done) { - // Note: https://github.com/gulpjs/vinyl-fs/issues/153 - var canary = 0; - var expected = 1; - var read = function() { - canary++; - return 0; - }; + it('does not stream a file changed before since', function(done) { + var lastUpdateDate = new Date(+fs.statSync(inputPath).mtime + 1000); - var onEnd = function() { - canary.should.equal(expected); - done(); - }; + function assert(files) { + expect(files.length).toEqual(0); + } - var buffered = []; - var stream = vfs.src('./fixtures/test.coffee', { cwd: __dirname, read: read }); - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); - stream.pipe(bufferStream); + pipe([ + vfs.src(inputPath, { since: lastUpdateDate }), + concat(assert), + ], done); }); -}); - -describe('.src() symlinks', function() { - - var dirPath = path.join(__dirname, './fixtures/wow'); - var dirSymlinkPath = path.join(__dirname, './fixtures/test-symlink-dir'); + it('streams a file with streaming contents', function(done) { + var expectedContent = fs.readFileSync(inputPath); - var filePath = path.join(__dirname, './fixtures/test.coffee'); - var fileSymlinkPath = path.join(__dirname, './fixtures/test-symlink'); + function assertContent(contents) { + expect(contents).toMatch(expectedContent); + } - var symlinkFirstLayer = path.join(__dirname, './fixtures/test-multi-layer-symlink'); - var symlinkSecondLayer = path.join(__dirname, './fixtures/foo/baz-link.txt'); - var symlinkSecondLayerTarget = path.join(__dirname, './fixtures/foo/bar/baz.txt'); + function compareContents(file, enc, cb) { + pipe([ + file.contents, + concat(assertContent), + ], function(err) { + cb(err, file); + }); + } - beforeEach(function(done) { - fs.symlinkSync(dirPath, dirSymlinkPath); - fs.symlinkSync(filePath, fileSymlinkPath); - fs.symlinkSync(symlinkSecondLayerTarget, symlinkSecondLayer); - fs.symlinkSync(symlinkSecondLayer, symlinkFirstLayer); - done(); - }); + function assert(files) { + expect(files.length).toEqual(1); + expect(files[0].path).toEqual(inputPath); + expect(files[0].isStream()).toEqual(true); + } - afterEach(function(done) { - fs.unlinkSync(dirSymlinkPath); - fs.unlinkSync(fileSymlinkPath); - fs.unlinkSync(symlinkSecondLayer); - fs.unlinkSync(symlinkFirstLayer); - done(); + pipe([ + vfs.src(inputPath, { buffer: false }), + through.obj(compareContents), + concat(assert), + ], done); }); - it('should follow symlinks correctly', function(done) { - var linkTarget = './fixtures/test-multi-layer-symlink'; - var expectedPath = path.join(__dirname, linkTarget); - - var stream = vfs.src(linkTarget, { cwd: __dirname, base: __dirname }); - stream.on('data', function(file) { - file.base.should.equal(__dirname); - // The path should be the symlink itself - file.path.should.equal(expectedPath); - // But the content should be what's in the actual file - file.contents.toString().should.equal('symlink works\n'); - file.stat.isSymbolicLink().should.equal(false); - file.stat.isFile().should.equal(true); - done(); + it('passes files through', function(done) { + var file = new File({ + base: inputBase, + path: inputPath, + contents: fs.readFileSync(inputPath), + stat: fs.statSync(inputPath), }); - }); - it('should follow dir symlinks correctly', function(done) { - var linkTarget = './fixtures/test-symlink-dir'; - var expectedPath = path.join(__dirname, linkTarget); - - var stream = vfs.src(linkTarget, { cwd: __dirname, base: __dirname }); - stream.on('data', function(file) { - file.base.should.equal(__dirname); - // The path should be the symlink itself - file.path.should.equal(expectedPath); - // But the stats should have been updated - file.stat.isSymbolicLink().should.equal(false); - file.stat.isDirectory().should.equal(true); - done(); - }); - }); + function assert(files) { + expect(files.length).toEqual(2); + expect(files[0]).toEqual(file); + } + pipe([ + from.obj([file]), + vfs.src(inputPath, { passthrough: true }), + concat(assert), + ], done); + }); - it('should preserve file symlinks with followSymlinks option set to false', function(done) { - fs.readlink(fileSymlinkPath, function(err, expectedRelativeSymlinkPath) { - if (err) { - throw err; - } + it('does not pass options.read on to through2', function(done) { + // Reference: https://github.com/gulpjs/vinyl-fs/issues/153 + var read = expect.createSpy().andReturn(false); - var stream = vfs.src(fileSymlinkPath, { cwd: __dirname, followSymlinks: false }); - stream.on('data', function(file) { - file.path.should.equal(fileSymlinkPath); - file.symlink.should.equal(expectedRelativeSymlinkPath); - done(); - }); - }); - }); + function assert() { + expect(read.calls.length).toEqual(1); + } - it('should preserve dir symlinks with followSymlinks option set to false', function(done) { - fs.readlink(dirSymlinkPath, function(err, expectedRelativeSymlinkPath) { - if (err) { - throw err; - } - - var stream = vfs.src(dirSymlinkPath, { cwd: __dirname, followSymlinks: false }); - stream.on('data', function(file) { - file.path.should.equal(dirSymlinkPath); - file.symlink.should.equal(expectedRelativeSymlinkPath); - done(); - }); - }); + pipe([ + vfs.src(inputPath, { read: read }), + concat(assert), + ], done); }); }); diff --git a/test/symlink.js b/test/symlink.js index 50ea5843..315b097f 100644 --- a/test/symlink.js +++ b/test/symlink.js @@ -1,508 +1,394 @@ 'use strict'; -var spies = require('./spy'); -var chmodSpy = spies.chmodSpy; -var statSpy = spies.statSpy; - -var vfs = require('../'); - -var os = require('os'); var path = require('path'); -var fs = require('graceful-fs'); -var del = require('del'); -var bufEqual = require('buffer-equal'); -var through = require('through2'); -var assign = require('object-assign'); +var fs = require('graceful-fs'); var File = require('vinyl'); +var expect = require('expect'); +var miss = require('mississippi'); -var should = require('should'); -require('mocha'); - -function wipeOut() { - spies.setError('false'); - statSpy.reset(); - chmodSpy.reset(); +var vfs = require('../'); - return del(path.join(__dirname, './out-fixtures/')); -} +var cleanup = require('./utils/cleanup'); +var statMode = require('./utils/stat-mode'); +var isWindows = require('./utils/is-windows'); +var applyUmask = require('./utils/apply-umask'); +var isDirectory = require('./utils/is-directory-mock'); +var testConstants = require('./utils/test-constants'); -var dataWrap = function(fn) { - return function(data, enc, cb) { - fn(data); - cb(); - }; -}; +var from = miss.from; +var pipe = miss.pipe; +var concat = miss.concat; -var realMode = function(n) { - return n & parseInt('777', 8); -}; +var outputRelative = testConstants.outputRelative; +var inputBase = testConstants.inputBase; +var outputBase = testConstants.outputBase; +var inputPath = testConstants.inputPath; +var outputPath = testConstants.outputPath; +var inputDirpath = testConstants.inputDirpath; +var outputDirpath = testConstants.outputDirpath; +var contents = testConstants.contents; -var isWindows = (os.platform() === 'win32'); +var clean = cleanup([outputBase]); describe('symlink stream', function() { - beforeEach(wipeOut); - afterEach(wipeOut); - it.skip('should explode on invalid folder', function(done) { + beforeEach(clean); + afterEach(clean); + + // TODO: make this work correctly + it.skip('throws on invalid folder', function(done) { var stream; try { stream = vfs.symlink(); } catch (err) { - should.exist(err); - should.not.exist(stream); + expect(err).toExist(); + expect(stream).toNotExist(); done(); } }); - it('should pass through writes with cwd', function(done) { - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - - var expectedFile = new File({ - base: __dirname, - cwd: __dirname, + it('passes through writes with cwd', function(done) { + var file = new File({ + base: inputBase, path: inputPath, contents: null, }); - var buffered = []; - - var onEnd = function() { - buffered.length.should.equal(1); - buffered[0].should.equal(expectedFile); - done(); - }; - - var stream = vfs.symlink('./out-fixtures/', { cwd: __dirname }); + function assert(files) { + expect(files.length).toEqual(1); + expect(files).toInclude(file); + expect(files[0].cwd).toEqual(__dirname, 'cwd should have changed'); + } - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); - stream.pipe(bufferStream); - stream.write(expectedFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.symlink(outputRelative, { cwd: __dirname }), + concat(assert), + ], done); }); - it('should pass through writes with default cwd', function(done) { - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - - var expectedFile = new File({ - base: __dirname, - cwd: __dirname, + it('passes through writes with default cwd', function(done) { + var file = new File({ + base: inputBase, path: inputPath, contents: null, }); - var buffered = []; - - var onEnd = function() { - buffered.length.should.equal(1); - buffered[0].should.equal(expectedFile); - done(); - }; - - var stream = vfs.symlink(path.join(__dirname, './out-fixtures/')); + function assert(files) { + expect(files.length).toEqual(1); + expect(files).toInclude(file); + expect(files[0].cwd).toEqual(process.cwd(), 'cwd should not have changed'); + } - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); - stream.pipe(bufferStream); - stream.write(expectedFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.symlink(outputBase), + concat(assert), + ], done); }); - it('should make link to the right folder with relative cwd', function(done) { - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - var inputBase = path.join(__dirname, './fixtures/'); - var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); - var expectedBase = path.join(__dirname, './out-fixtures'); - var expectedContents = fs.readFileSync(inputPath); + it('creates a link to the right folder with relative cwd', function(done) { + var cwd = path.relative(process.cwd(), __dirname); - var expectedFile = new File({ + var file = new File({ base: inputBase, - cwd: __dirname, path: inputPath, - contents: expectedContents, + contents: null, }); - var buffered = []; - - var onEnd = function() { - buffered.length.should.equal(1); - buffered[0].should.equal(expectedFile); - buffered[0].cwd.should.equal(__dirname, 'cwd should have changed'); - buffered[0].base.should.equal(expectedBase, 'base should have changed'); - buffered[0].path.should.equal(expectedPath, 'path should have changed'); - fs.existsSync(expectedPath).should.equal(true); - bufEqual(fs.readFileSync(expectedPath), expectedContents).should.equal(true); - fs.readlinkSync(expectedPath).should.equal(inputPath); - done(); - }; - - var stream = vfs.symlink('./out-fixtures/', { cwd: path.relative(process.cwd(), __dirname) }); + function assert(files) { + var outputLink = fs.readlinkSync(outputPath); + expect(files.length).toEqual(1); + expect(files).toInclude(file); + expect(files[0].base).toEqual(outputBase, 'base should have changed'); + expect(files[0].path).toEqual(outputPath, 'path should have changed'); + expect(outputLink).toEqual(inputPath); + } - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); - stream.pipe(bufferStream); - stream.write(expectedFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.symlink(outputRelative, { cwd: cwd }), + concat(assert), + ], done); }); - it('should write buffer files to the right folder with function and relative cwd', function(done) { - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - var inputBase = path.join(__dirname, './fixtures/'); - var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); - var expectedBase = path.join(__dirname, './out-fixtures'); - var expectedContents = fs.readFileSync(inputPath); + it('creates a link to the right folder with function and relative cwd', function(done) { + var cwd = path.relative(process.cwd(), __dirname); - var expectedFile = new File({ + var file = new File({ base: inputBase, - cwd: __dirname, path: inputPath, - contents: expectedContents, + contents: null, }); - var buffered = []; - - var onEnd = function() { - buffered.length.should.equal(1); - buffered[0].should.equal(expectedFile); - buffered[0].cwd.should.equal(__dirname, 'cwd should have changed'); - buffered[0].base.should.equal(expectedBase, 'base should have changed'); - buffered[0].path.should.equal(expectedPath, 'path should have changed'); - fs.existsSync(expectedPath).should.equal(true); - bufEqual(fs.readFileSync(expectedPath), expectedContents).should.equal(true); - fs.readlinkSync(expectedPath).should.equal(inputPath); - done(); - }; - - var stream = vfs.symlink(function(file) { - should.exist(file); - file.should.equal(expectedFile); - return './out-fixtures'; - }, { cwd: path.relative(process.cwd(), __dirname) }); - - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); - stream.pipe(bufferStream); - stream.write(expectedFile); - stream.end(); - }); + function outputFn(f) { + expect(f).toExist(); + expect(f).toEqual(file); + return outputRelative; + } - it('should write buffer files to the right folder', function(done) { - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - var inputBase = path.join(__dirname, './fixtures/'); - var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); - var expectedContents = fs.readFileSync(inputPath); - var expectedBase = path.join(__dirname, './out-fixtures'); - var expectedMode = parseInt('677', 8) & ~process.umask(); + function assert(files) { + var outputLink = fs.readlinkSync(outputPath); - var expectedFile = new File({ + expect(files.length).toEqual(1); + expect(files).toInclude(file); + expect(files[0].base).toEqual(outputBase, 'base should have changed'); + expect(files[0].path).toEqual(outputPath, 'path should have changed'); + expect(outputLink).toEqual(inputPath); + } + + pipe([ + from.obj([file]), + vfs.symlink(outputFn, { cwd: cwd }), + concat(assert), + ], done); + }); + + // TODO: test for modes + it('creates a link for a file with buffered contents', function(done) { + var file = new File({ base: inputBase, - cwd: __dirname, path: inputPath, - contents: expectedContents, - stat: { - mode: expectedMode, - }, + contents: new Buffer(contents), }); - var buffered = []; - - var onEnd = function() { - buffered.length.should.equal(1); - buffered[0].should.equal(expectedFile); - buffered[0].cwd.should.equal(__dirname, 'cwd should have changed'); - buffered[0].base.should.equal(expectedBase, 'base should have changed'); - buffered[0].path.should.equal(expectedPath, 'path should have changed'); - fs.existsSync(expectedPath).should.equal(true); - bufEqual(fs.readFileSync(expectedPath), expectedContents).should.equal(true); - fs.readlinkSync(expectedPath).should.equal(inputPath); - done(); - }; + function assert(files) { + var outputLink = fs.readlinkSync(outputPath); - var stream = vfs.symlink('./out-fixtures/', { cwd: __dirname }); + expect(files.length).toEqual(1); + expect(files).toInclude(file); + expect(files[0].base).toEqual(outputBase, 'base should have changed'); + expect(files[0].path).toEqual(outputPath, 'path should have changed'); + expect(outputLink).toEqual(inputPath); + } - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); - stream.pipe(bufferStream); - stream.write(expectedFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.symlink(outputBase), + concat(assert), + ], done); }); - it('should write buffer files to the right folder relatively', function(done) { - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - var inputBase = path.join(__dirname, './fixtures/'); - var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); - var expectedContents = fs.readFileSync(inputPath); - var expectedBase = path.join(__dirname, './out-fixtures'); - var expectedMode = parseInt('677', 8) & ~process.umask(); - - var expectedFile = new File({ + it('can create relative links', function(done) { + var file = new File({ base: inputBase, - cwd: __dirname, path: inputPath, - contents: expectedContents, - stat: { - mode: expectedMode, - }, + contents: null, }); - var buffered = []; - - var onEnd = function() { - buffered.length.should.equal(1); - buffered[0].should.equal(expectedFile); - buffered[0].cwd.should.equal(__dirname, 'cwd should have changed'); - buffered[0].base.should.equal(expectedBase, 'base should have changed'); - buffered[0].path.should.equal(expectedPath, 'path should have changed'); - fs.existsSync(expectedPath).should.equal(true); - bufEqual(fs.readFileSync(expectedPath), expectedContents).should.equal(true); - fs.readlinkSync(expectedPath).should.equal(path.join('..', 'fixtures', 'test.coffee')); - done(); - }; + function assert(files) { + var outputLink = fs.readlinkSync(outputPath); - var stream = vfs.symlink('./out-fixtures/', assign({ cwd: __dirname }, { relative: true })); + expect(files.length).toEqual(1); + expect(files).toInclude(file); + expect(files[0].base).toEqual(outputBase, 'base should have changed'); + expect(files[0].path).toEqual(outputPath, 'path should have changed'); + expect(outputLink).toEqual(path.normalize('../fixtures/test.txt')); + } - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); - stream.pipe(bufferStream); - stream.write(expectedFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.symlink(outputBase, { relative: true }), + concat(assert), + ], done); }); - it('should write streaming files to the right folder', function(done) { - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - var inputBase = path.join(__dirname, './fixtures/'); - var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); - var expectedContents = fs.readFileSync(inputPath); - var expectedBase = path.join(__dirname, './out-fixtures'); - var expectedMode = parseInt('677', 8) & ~process.umask(); - - var contentStream = through.obj(); - var expectedFile = new File({ + it('creates a link for a file with streaming contents', function(done) { + var file = new File({ base: inputBase, - cwd: __dirname, path: inputPath, - contents: contentStream, - stat: { - mode: expectedMode, - }, + contents: from([contents]), }); - var buffered = []; - - var onEnd = function() { - buffered.length.should.equal(1); - buffered[0].should.equal(expectedFile); - buffered[0].cwd.should.equal(__dirname, 'cwd should have changed'); - buffered[0].base.should.equal(expectedBase, 'base should have changed'); - buffered[0].path.should.equal(expectedPath, 'path should have changed'); - fs.existsSync(expectedPath).should.equal(true); - bufEqual(fs.readFileSync(expectedPath), expectedContents).should.equal(true); - fs.readlinkSync(expectedPath).should.equal(inputPath); - done(); - }; - - var stream = vfs.symlink('./out-fixtures/', { cwd: __dirname }); - - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); - stream.pipe(bufferStream); - stream.write(expectedFile); - setTimeout(function() { - contentStream.write(expectedContents); - contentStream.end(); - }, 100); - stream.end(); - }); + function assert(files) { + var outputLink = fs.readlinkSync(outputPath); - it('should write directories to the right folder', function(done) { - var inputPath = path.join(__dirname, './fixtures/wow'); - var inputBase = path.join(__dirname, './fixtures/'); - var expectedPath = path.join(__dirname, './out-fixtures/wow'); - var expectedBase = path.join(__dirname, './out-fixtures'); - var expectedMode = parseInt('677', 8) & ~process.umask(); + expect(files.length).toEqual(1); + expect(files).toInclude(file); + expect(files[0].base).toEqual(outputBase, 'base should have changed'); + expect(files[0].path).toEqual(outputPath, 'path should have changed'); + expect(outputLink).toEqual(inputPath); + } - var expectedFile = new File({ + pipe([ + from.obj([file]), + vfs.symlink(outputBase), + concat(assert), + ], done); + }); + + it('creates a link for a directory', function(done) { + var file = new File({ base: inputBase, - cwd: __dirname, - path: inputPath, + path: inputDirpath, contents: null, stat: { - isDirectory: function() { - return true; - }, - mode: expectedMode, + isDirectory: isDirectory, }, }); - var buffered = []; - - var onEnd = function() { - buffered.length.should.equal(1); - buffered[0].should.equal(expectedFile); - buffered[0].cwd.should.equal(__dirname, 'cwd should have changed'); - buffered[0].base.should.equal(expectedBase, 'base should have changed'); - buffered[0].path.should.equal(expectedPath, 'path should have changed'); - fs.readlinkSync(expectedPath).should.equal(inputPath); - fs.lstatSync(expectedPath).isDirectory().should.equal(false); - fs.statSync(expectedPath).isDirectory().should.equal(true); - done(); - }; - - var stream = vfs.symlink('./out-fixtures/', { cwd: __dirname }); + function assert(files) { + var stats = fs.statSync(outputDirpath); + var lstats = fs.lstatSync(outputDirpath); + var outputLink = fs.readlinkSync(outputDirpath); + + expect(files.length).toEqual(1); + expect(files).toInclude(file); + expect(files[0].base).toEqual(outputBase, 'base should have changed'); + expect(files[0].path).toEqual(outputDirpath, 'path should have changed'); + expect(outputLink).toEqual(inputDirpath); + expect(stats.isDirectory()).toEqual(true); + expect(lstats.isDirectory()).toEqual(false); + } - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); - stream.pipe(bufferStream); - stream.write(expectedFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.symlink(outputBase), + concat(assert), + ], done); }); - it('should write directories to the right folder relatively', function(done) { - var inputPath = path.join(__dirname, './fixtures/wow'); - var inputBase = path.join(__dirname, './fixtures/'); - var expectedPath = path.join(__dirname, './out-fixtures/wow'); - var expectedBase = path.join(__dirname, './out-fixtures'); - var expectedMode = parseInt('677', 8) & ~process.umask(); - - var expectedFile = new File({ + it('can create relative links for directories', function(done) { + var file = new File({ base: inputBase, - cwd: __dirname, - path: inputPath, + path: inputDirpath, contents: null, stat: { - isDirectory: function() { - return true; - }, - mode: expectedMode, + isDirectory: isDirectory, }, }); - var buffered = []; - - var onEnd = function() { - buffered.length.should.equal(1); - buffered[0].should.equal(expectedFile); - buffered[0].cwd.should.equal(__dirname, 'cwd should have changed'); - buffered[0].base.should.equal(expectedBase, 'base should have changed'); - buffered[0].path.should.equal(expectedPath, 'path should have changed'); - fs.readlinkSync(expectedPath).should.equal(path.join('..', 'fixtures', 'wow')); - fs.lstatSync(expectedPath).isDirectory().should.equal(false); - fs.statSync(expectedPath).isDirectory().should.equal(true); - done(); - }; - - var stream = vfs.symlink('./out-fixtures/', assign({ cwd: __dirname }, { relative: true })); + function assert(files) { + var stats = fs.statSync(outputDirpath); + var lstats = fs.lstatSync(outputDirpath); + var outputLink = fs.readlinkSync(outputDirpath); + + expect(files.length).toEqual(1); + expect(files).toInclude(file); + expect(files[0].base).toEqual(outputBase, 'base should have changed'); + expect(files[0].path).toEqual(outputDirpath, 'path should have changed'); + expect(outputLink).toEqual(path.normalize('../fixtures/foo')); + expect(stats.isDirectory()).toEqual(true); + expect(lstats.isDirectory()).toEqual(false); + } - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); - stream.pipe(bufferStream); - stream.write(expectedFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.symlink(outputBase, { relative: true }), + concat(assert), + ], done); }); - it('should use different modes for files and directories', function(done) { + it('uses different modes for files and directories', function(done) { + // Changing the mode of a file is not supported by node.js in Windows. if (isWindows) { - console.log('Changing the mode of a file is not supported by node.js in Windows.'); this.skip(); return; } - var inputBase = path.join(__dirname, './fixtures'); - var inputPath = path.join(__dirname, './fixtures/wow/suchempty'); - var expectedBase = path.join(__dirname, './out-fixtures/wow'); - var expectedDirMode = parseInt('777', 8) & ~process.umask(); - var expectedFileMode = parseInt('677', 8) & ~process.umask(); + var dirMode = applyUmask('722'); + var fileMode = applyUmask('700'); - var firstFile = new File({ + var file = new File({ base: inputBase, - cwd: __dirname, path: inputPath, - stat: fs.statSync(inputPath), - }); - - var buffered = []; - - var onEnd = function() { - realMode(fs.lstatSync(expectedBase).mode).toString(8).should.equal(expectedDirMode.toString(8)); - realMode(buffered[0].stat.mode).toString(8).should.equal(expectedFileMode.toString(8)); - done(); - }; - - var stream = vfs.symlink('./out-fixtures/', { - cwd: __dirname, - mode: expectedFileMode, - dirMode: expectedDirMode, + contents: null, }); - var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); + function assert(files) { + expect(statMode(outputDirpath)).toEqual(dirMode); + // TODO: the file doesn't actually get the mode updated + expect(files[0].stat.mode).toEqual(fileMode); + } - stream.pipe(bufferStream); - stream.write(firstFile); - stream.end(); + pipe([ + from.obj([file]), + vfs.symlink(outputDirpath, { mode: fileMode, dirMode: dirMode }), + concat(assert), + ], done); }); - it('should report IO errors', function(done) { + it('reports IO errors', function(done) { + // Changing the mode of a file is not supported by node.js in Windows. + // This test is skipped on Windows because we have to chmod the file to 0. if (isWindows) { - console.log('Changing the mode of a file is not supported by node.js in Windows.'); - console.log('This test is skipped on Windows because we have to chmod the file to 0.'); this.skip(); return; } - var inputPath = path.join(__dirname, './fixtures/test.coffee'); - var inputBase = path.join(__dirname, './fixtures/'); - var expectedContents = fs.readFileSync(inputPath); - var expectedBase = path.join(__dirname, './out-fixtures'); - - var expectedFile = new File({ + var file = new File({ base: inputBase, - cwd: __dirname, path: inputPath, - contents: expectedContents, + contents: null, }); - fs.mkdirSync(expectedBase); - fs.chmodSync(expectedBase, 0); + fs.mkdirSync(outputBase); + fs.chmodSync(outputBase, 0); - var stream = vfs.symlink('./out-fixtures/', { cwd: __dirname }); - stream.on('error', function(err) { - err.code.should.equal('EACCES'); + function assert(err) { + expect(err.code).toEqual('EACCES'); done(); - }); - stream.write(expectedFile); - }); + } - ['end', 'finish'].forEach(function(eventName) { - it('should emit ' + eventName + ' event', function(done) { - var srcPath = path.join(__dirname, './fixtures/test.coffee'); - var stream = vfs.symlink('./out-fixtures/', { cwd: __dirname }); + pipe([ + from.obj([file]), + vfs.symlink(outputDirpath), + ], assert); + }); - stream.on(eventName, function() { - done(); - }); + it('emits an end event', function(done) { + var symlinkStream = vfs.symlink(outputBase); - var file = new File({ - path: srcPath, - cwd: __dirname, - contents: new Buffer('1234567890'), - }); + symlinkStream.on('end', done); - stream.write(file); - stream.end(); + var file = new File({ + base: inputBase, + path: inputPath, + contents: null, }); + + pipe([ + from.obj([file]), + symlinkStream, + ]); }); - it('should pass options to through2', function(done) { - var srcPath = path.join(__dirname, './fixtures/test.coffee'); - var content = fs.readFileSync(srcPath); - var stream = vfs.symlink('./out-fixtures/', { cwd: __dirname, objectMode: false }); + it('emits a finish event', function(done) { + var symlinkStream = vfs.symlink(outputBase); - stream.on('error', function(err) { - err.should.match(/Invalid non-string\/buffer chunk/); - done(); - }); + symlinkStream.on('finish', done); var file = new File({ - path: srcPath, - cwd: __dirname, - contents: content, + base: inputBase, + path: inputPath, + contents: null, }); - stream.write(file); - stream.end(); + pipe([ + from.obj([file]), + symlinkStream, + ]); }); + // TODO: need a better way to pass these options through + // Or maybe not at all since we fixed highWaterMark + it('passes options to through2', function(done) { + var file = new File({ + base: inputBase, + path: inputPath, + contents: null, + }); + + function assert(err) { + expect(err.message).toMatch(/Invalid non-string\/buffer chunk/); + done(); + } + + pipe([ + from.obj([file]), + vfs.symlink(outputBase, { objectMode: false }), + ], assert); + }); }); diff --git a/test/utils/apply-umask.js b/test/utils/apply-umask.js new file mode 100644 index 00000000..8cf524bf --- /dev/null +++ b/test/utils/apply-umask.js @@ -0,0 +1,11 @@ +'use strict'; + +function applyUmask(mode) { + if (typeof mode !== 'number') { + mode = parseInt(mode, 8); + } + + return (mode & ~process.umask()); +} + +module.exports = applyUmask; diff --git a/test/utils/cleanup.js b/test/utils/cleanup.js new file mode 100644 index 00000000..c6c78322 --- /dev/null +++ b/test/utils/cleanup.js @@ -0,0 +1,17 @@ +'use strict'; + +var del = require('del'); +var expect = require('expect'); + +function cleanup(globs) { + return function() { + this.timeout(20000); + + expect.restoreSpies(); + + // Async del to get sort-of-fix for https://github.com/isaacs/rimraf/issues/72 + return del(globs); + }; +} + +module.exports = cleanup; diff --git a/test/utils/is-directory-mock.js b/test/utils/is-directory-mock.js new file mode 100644 index 00000000..a71241df --- /dev/null +++ b/test/utils/is-directory-mock.js @@ -0,0 +1,7 @@ +'use strict'; + +function isDirectory() { + return true; +} + +module.exports = isDirectory; diff --git a/test/utils/is-windows.js b/test/utils/is-windows.js new file mode 100644 index 00000000..fdbb3e6f --- /dev/null +++ b/test/utils/is-windows.js @@ -0,0 +1,7 @@ +'use strict'; + +var os = require('os'); + +var isWindows = (os.platform() === 'win32'); + +module.exports = isWindows; diff --git a/test/utils/mock-error.js b/test/utils/mock-error.js new file mode 100644 index 00000000..5ad8e736 --- /dev/null +++ b/test/utils/mock-error.js @@ -0,0 +1,8 @@ +'use strict'; + +function mockError() { + var callback = arguments[arguments.length - 1]; + callback(new Error('mocked error')); +} + +module.exports = mockError; diff --git a/test/utils/stat-mode.js b/test/utils/stat-mode.js new file mode 100644 index 00000000..1b2ba270 --- /dev/null +++ b/test/utils/stat-mode.js @@ -0,0 +1,15 @@ +'use strict'; + +var fs = require('graceful-fs'); + +var constants = require('../../lib/constants'); + +function masked(mode) { + return mode & constants.MASK_MODE; +} + +function statMode(outputPath) { + return masked(fs.lstatSync(outputPath).mode); +} + +module.exports = statMode; diff --git a/test/utils/test-constants.js b/test/utils/test-constants.js new file mode 100644 index 00000000..541f4c51 --- /dev/null +++ b/test/utils/test-constants.js @@ -0,0 +1,66 @@ +'use strict'; + +var path = require('path'); + +// Input/output relative paths +var inputRelative = './fixtures/'; +var outputRelative = './out-fixtures/'; +// Input/Output base directories +var inputBase = path.join(__dirname, '..', inputRelative); +var outputBase = path.join(__dirname, '..', outputRelative); +// Used for file tests +var inputPath = path.join(inputBase, './test.txt'); +var outputPath = path.join(outputBase, './test.txt'); +// Used for directory tests +var inputDirpath = path.join(inputBase, './foo'); +var outputDirpath = path.join(outputBase, './foo'); +// Used for nested tests +var inputNestedPath = path.join(inputDirpath, './test.txt'); +var outputNestedPath = path.join(outputDirpath, './test.txt'); +// Used for nested directory tests +var inputNestedDirpath = path.join(inputDirpath, './bar/baz/'); +var outputNestedDirpath = path.join(outputDirpath, './bar/baz/'); +// Used for rename tests +var outputRenamePath = path.join(outputBase, './foo2.txt'); +// Used for not-owned tests +var notOwnedBase = path.join(inputBase, './not-owned/'); +var notOwnedPath = path.join(notOwnedBase, 'not-owned.txt'); +// Used for BOM tests +var bomInputPath = path.join(inputBase, './bom-utf8.txt'); +var beEncodedInputPath = path.join(inputBase, './bom-utf16be.txt'); +var leEncodedInputPath = path.join(inputBase, './bom-utf16le.txt'); +// Used for symlink tests +var symlinkNestedTarget = path.join(inputBase, './foo/bar/baz.txt'); +var symlinkPath = path.join(outputBase, './test-symlink'); +var symlinkDirpath = path.join(outputBase, './test-symlink-dir'); +var symlinkNestedFirst = path.join(outputBase, './test-multi-layer-symlink'); +var symlinkNestedSecond = path.join(outputBase, './foo/baz-link.txt'); +// Used for contents of files +var contents = 'Hello World!'; + +module.exports = { + inputRelative: inputRelative, + outputRelative: outputRelative, + inputBase: inputBase, + outputBase: outputBase, + inputPath: inputPath, + outputPath: outputPath, + inputDirpath: inputDirpath, + outputDirpath: outputDirpath, + inputNestedPath: inputNestedPath, + outputNestedPath: outputNestedPath, + outputRenamePath: outputRenamePath, + inputNestedDirpath: inputNestedDirpath, + outputNestedDirpath: outputNestedDirpath, + notOwnedBase: notOwnedBase, + notOwnedPath: notOwnedPath, + bomInputPath: bomInputPath, + beEncodedInputPath: beEncodedInputPath, + leEncodedInputPath: leEncodedInputPath, + symlinkNestedTarget: symlinkNestedTarget, + symlinkPath: symlinkPath, + symlinkDirpath: symlinkDirpath, + symlinkNestedFirst: symlinkNestedFirst, + symlinkNestedSecond: symlinkNestedSecond, + contents: contents, +}; diff --git a/test/utils/test-streams.js b/test/utils/test-streams.js new file mode 100644 index 00000000..0c68c2e9 --- /dev/null +++ b/test/utils/test-streams.js @@ -0,0 +1,53 @@ +'use strict'; + +var miss = require('mississippi'); +var expect = require('expect'); + +var to = miss.to; +var through = miss.through; + +function rename(filepath) { + return through.obj(function(file, enc, cb) { + file.path = filepath; + cb(null, file); + }); +} + +function includes(obj) { + return through.obj(function(file, enc, cb) { + expect(file).toInclude(obj); + cb(null, file); + }); +} + +function count(value) { + var count = 0; + return through.obj(function(file, enc, cb) { + count++; + cb(null, file); + }, function(cb) { + expect(count).toEqual(value); + cb(); + }); +} + +function slowCount(value) { + var count = 0; + return to.obj(function(file, enc, cb) { + count++; + + setTimeout(function() { + cb(null, file); + }, 250); + }, function(cb) { + expect(count).toEqual(value); + cb(); + }); +} + +module.exports = { + rename: rename, + includes: includes, + count: count, + slowCount: slowCount, +}; From 4b1b39a391413169d0d0eaf0dda6817fd9a0d965 Mon Sep 17 00:00:00 2001 From: Blaine Bublitz Date: Fri, 22 Jul 2016 15:30:41 -0700 Subject: [PATCH 2/3] Scaffold: Normalize project --- .editorconfig | 8 ++++--- .gitignore | 39 +++++++++++++++++++++++++------ .travis.yml | 3 ++- LICENSE | 35 ++++++++++++++-------------- README.md | 4 ++-- appveyor.yml | 1 + package.json | 54 ++++++++++++++++++++++++++----------------- test/default-value.js | 9 +++++--- 8 files changed, 99 insertions(+), 54 deletions(-) diff --git a/.editorconfig b/.editorconfig index 6c5424ed..5760be58 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,10 +1,12 @@ -# editorconfig.org +# http://editorconfig.org root = true [*] indent_style = space indent_size = 2 -end_of_line = lf charset = utf-8 trim_trailing_whitespace = true -insert_final_newline = true \ No newline at end of file +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.gitignore b/.gitignore index a559358c..e1db3ec5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,34 @@ -.DS_Store +# Logs +logs *.log -node_modules -build -*.node -*.orig -.idea -sandbox + +# Runtime data +pids +*.pid +*.seed + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul coverage + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directory +# Commenting this out is preferred by some people, see +# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- +node_modules + +# Users Environment Variables +.lock-wscript + +# Garbage files +.DS_Store + +# Generated by integration tests +test/out-fixtures/ diff --git a/.travis.yml b/.travis.yml index 0263c9c7..f4620140 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,8 @@ sudo: required language: node_js node_js: - - 'stable' + - '6' + - '5' - '4' - '0.12' - '0.10' diff --git a/LICENSE b/LICENSE index 3ebc3089..84b3420e 100755 --- a/LICENSE +++ b/LICENSE @@ -1,20 +1,21 @@ -Copyright (c) 2013-2016 Fractal +The MIT License (MIT) -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: +Copyright (c) 2013 Blaine Bublitz , Eric Schoffstall and other contributors -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index a5b61e8d..1ad0ba8c 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,7 @@ Type: `Boolean` Default: `false` -##### `options.followSymlinks` - `true` if you want +##### `options.followSymlinks` Whether or not to recursively resolve symlinks to their targets. Setting to `false` to preserve them as symlinks and make `file.symlink` equal the original symlink's target path. @@ -120,7 +120,7 @@ Type: `Boolean` Default: `true` -##### `options.dots` - `true` +##### `options.dots` Whether or not you want globs to match on dot files or not (e.g. `.gitignore`) diff --git a/appveyor.yml b/appveyor.yml index ebd6fc07..625fc104 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -8,6 +8,7 @@ environment: - nodejs_version: "0.12" - nodejs_version: "4" - nodejs_version: "5" + - nodejs_version: "6" install: - ps: Install-Product node $env:nodejs_version diff --git a/package.json b/package.json index 8aa1b0c4..d435e78a 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,30 @@ { "name": "vinyl-fs", - "description": "Vinyl adapter for the file system", "version": "2.4.3", - "homepage": "http://github.com/wearefractal/vinyl-fs", - "repository": "git://github.com/wearefractal/vinyl-fs.git", - "author": "Fractal (http://wearefractal.com/)", - "main": "./index.js", + "description": "Vinyl adapter for the file system.", + "author": "Gulp Team (http://gulpjs.com/)", + "contributors": [ + "Eric Schoffstall ", + "Blaine Bublitz " + ], + "repository": "gulpjs/vinyl-fs", + "license": "MIT", + "engines": { + "node": ">= 0.10" + }, + "main": "index.js", "files": [ + "LICENSE", "index.js", "lib" ], + "scripts": { + "lint": "eslint . && jscs index.js lib/ test/", + "pretest": "npm run lint", + "test": "mocha --async-only", + "cover": "istanbul cover _mocha --report lcovonly", + "coveralls": "npm run cover && istanbul-coveralls" + }, "dependencies": { "duplexify": "^3.2.0", "flush-write-stream": "^1.0.0", @@ -34,24 +49,21 @@ "del": "^2.2.0", "eslint": "^1.10.3", "eslint-config-gulp": "^2.0.0", - "expect": "^1.14.0", - "github-changes": "^1.0.1", - "istanbul": "^0.3.0", - "istanbul-coveralls": "^1.0.1", + "expect": "^1.19.0", + "istanbul": "^0.4.3", + "istanbul-coveralls": "^1.0.3", "jscs": "^2.4.0", "jscs-preset-gulp": "^1.0.0", "mississippi": "^1.2.0", - "mocha": "^2.0.0" - }, - "scripts": { - "lint": "eslint . && jscs index.js lib/ test/", - "test": "npm run lint && mocha", - "cover": "istanbul cover _mocha", - "coveralls": "npm run cover && istanbul-coveralls", - "changelog": "github-changes -o gulpjs -r vinyl-fs -b master -f ./CHANGELOG.md --order-semver --use-commit-body" - }, - "engines": { - "node": ">=0.10" + "mocha": "^2.4.5" }, - "license": "MIT" + "keywords": [ + "gulp", + "vinyl-adapter", + "vinyl", + "file", + "file system", + "fs", + "streams" + ] } diff --git a/test/default-value.js b/test/default-value.js index dde0a601..b3fa6645 100644 --- a/test/default-value.js +++ b/test/default-value.js @@ -6,16 +6,19 @@ var defaultValue = require('../lib/default-value'); describe('defaultVaule', function() { - it('returns the value if the value is not null', function() { + it('returns the value if the value is not null', function(done) { expect(defaultValue('defaultValue', 1)).toBe(1); + done(); }); - it('returns the default value if the value is undefined', function() { + it('returns the default value if the value is undefined', function(done) { expect(defaultValue('defaultValue', undefined)).toBe('defaultValue'); + done(); }); - it('returns the default value if the value is null', function() { + it('returns the default value if the value is null', function(done) { expect(defaultValue('defaultValue', null)).toBe('defaultValue'); + done(); }); }); From b4b1049cffed8c886d103f0bcd052284ecea7a4b Mon Sep 17 00:00:00 2001 From: Erik Kemperman Date: Sat, 23 Jul 2016 22:34:04 +0200 Subject: [PATCH 3/3] Build: Add space to not-owned notices (#196) --- test/not-owned.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/not-owned.js b/test/not-owned.js index 8efb3fb8..290a3dab 100644 --- a/test/not-owned.js +++ b/test/not-owned.js @@ -32,7 +32,7 @@ describe('.dest() on not owned files', function() { it('does not error if mtime is different', function(done) { if (dirStats.uid !== 0 || fileStats.uid !== 0) { console.log('Test files not owned by root.'); - console.log('Please chown ' + notOwnedBase + ' and' + notOwnedPath + ' and try again.'); + console.log('Please chown ' + notOwnedBase + ' and ' + notOwnedPath + ' and try again.'); this.skip(); return; } @@ -64,7 +64,7 @@ describe('.dest() on not owned files', function() { it('does not error if mode is different', function(done) { if (dirStats.uid !== 0 || fileStats.uid !== 0) { console.log('Test files not owned by root.'); - console.log('Please chown ' + notOwnedBase + ' and' + notOwnedPath + ' and try again.'); + console.log('Please chown ' + notOwnedBase + ' and ' + notOwnedPath + ' and try again.'); this.skip(); return; }