Skip to content

Commit

Permalink
Use sinon to stub fs calls (#19)
Browse files Browse the repository at this point in the history
  • Loading branch information
kevva authored and sindresorhus committed Sep 20, 2017
1 parent 61efc21 commit fdba27e
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 119 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"del": "^2.2.2",
"import-fresh": "^2.0.0",
"nyc": "^10.0.0",
"sinon": "^3.2.1",
"uuid": "^3.0.0",
"xo": "*"
}
Expand Down
57 changes: 17 additions & 40 deletions test/async.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import clearModule from 'clear-module';
import del from 'del';
import test from 'ava';
import uuid from 'uuid';
import sinon from 'sinon';
import m from '..';
import assertDateEqual from './helpers/assert';
import {buildEACCES, buildENOSPC, buildENOENT} from './helpers/fs-errors';
Expand Down Expand Up @@ -106,32 +107,24 @@ test('throw an Error if `src` does not exists', async t => {
t.regex(err.stack, /`NO_ENTRY`/, err);
});

test('rethrow mkdir EACCES errors', async t => {
const mkdir = fs.mkdir;
test.serial('rethrow mkdir EACCES errors', async t => {
const dirPath = '/root/NO_ACCESS_' + uuid.v4();
const dest = dirPath + '/' + uuid.v4();
const mkdirError = buildEACCES(dirPath);
let called = 0;

fs.mkdir = (path, mode, cb) => {
if (path === dirPath) {
called++;
cb(mkdirError);
return;
}

mkdir(path, mode, cb);
};
fs.mkdir = sinon.stub(fs, 'mkdir').throws(mkdirError);

const err = await t.throws(m('license', dest));
t.is(err.name, 'CpFileError', err);
t.is(err.errno, mkdirError.errno, err);
t.is(err.code, mkdirError.code, err);
t.is(err.path, mkdirError.path, err);
t.is(called, 1);
t.true(fs.mkdir.called);

fs.mkdir.restore();
});

test('rethrow ENOSPC errors', async t => {
test.serial('rethrow ENOSPC errors', async t => {
const createWriteStream = fs.createWriteStream;
const noSpaceError = buildENOSPC();
let called = false;
Expand All @@ -158,50 +151,34 @@ test('rethrow ENOSPC errors', async t => {
t.true(called);
});

test('rethrow stat errors', async t => {
const lstat = fs.lstat;
test.serial('rethrow stat errors', async t => {
const fstatError = buildENOENT();
let called = 0;

fs.writeFileSync(t.context.src, '');
fs.lstat = (path, cb) => {
if (path === t.context.src) {
called++;
cb(fstatError);
return;
}

lstat(path, cb);
};
fs.lstat = sinon.stub(fs, 'lstat').throws(fstatError);

clearModule('../fs');
const uncached = importFresh('..');
const err = await t.throws(uncached(t.context.src, t.context.dest));
t.is(err.name, 'CpFileError', err);
t.is(err.errno, fstatError.errno, err);
t.is(err.code, fstatError.code, err);
t.is(called, 1);
t.true(fs.lstat.called);

fs.lstat.restore();
});

test('rethrow utimes errors', async t => {
const utimes = fs.utimes;
test.serial('rethrow utimes errors', async t => {
const utimesError = buildENOENT();
let called = 0;

fs.utimes = (path, atime, mtime, cb) => {
if (path === t.context.dest) {
called++;
cb(utimesError);
return;
}

utimes(path, atime, mtime, cb);
};
fs.utimes = sinon.stub(fs, 'utimes').throws(utimesError);

clearModule('../fs');
const uncached = importFresh('..');
const err = await t.throws(uncached('license', t.context.dest));
t.is(called, 1);
t.is(err.name, 'CpFileError', err);
t.is(err.code, 'ENOENT', err);
t.true(fs.utimes.called);

fs.utimes.restore();
});
101 changes: 22 additions & 79 deletions test/sync.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import fs from 'graceful-fs';
import del from 'del';
import test from 'ava';
import uuid from 'uuid';
import sinon from 'sinon';
import m from '..';
import assertDateEqual from './helpers/assert';
import {buildEACCES, buildENOSPC, buildEBADF} from './helpers/fs-errors';
Expand Down Expand Up @@ -105,135 +106,77 @@ test('throw an Error if `src` does not exists', t => {
});

test('rethrow mkdir EACCES errors', t => {
const mkdirSync = fs.mkdirSync;
const dirPath = '/root/NO_ACCESS_' + uuid.v4();
const dest = dirPath + '/' + uuid.v4();
const mkdirError = buildEACCES(dirPath);
let called = 0;

fs.mkdirSync = (path, mode) => {
if (path === dirPath) {
called++;
throw mkdirError;
}

return mkdirSync(path, mode);
};
fs.mkdirSync = sinon.stub(fs, 'mkdirSync').throws(mkdirError);

const err = t.throws(() => m.sync('license', dest));
t.is(err.name, 'CpFileError', err);
t.is(err.errno, mkdirError.errno, err);
t.is(err.code, mkdirError.code, err);
t.is(err.path, mkdirError.path, err);
t.is(called, 1);
t.true(fs.mkdirSync.called);

fs.mkdirSync.restore();
});

test('rethrow ENOSPC errors', t => {
const openSync = fs.openSync;
const writeSync = fs.writeSync;
const fds = new Map();
const noSpaceError = buildENOSPC();
let called = 0;

fs.writeFileSync(t.context.src, '');
fs.openSync = (path, flags, mode) => {
const fd = openSync(path, flags, mode);
fds.set(fd, path);
return fd;
};
// eslint-disable-next-line max-params
fs.writeSync = (fd, buffer, offset, length, position) => {
if (fds.get(fd) === t.context.dest) {
called++;
// Throw Error:
throw noSpaceError;
}

return writeSync(fd, buffer, offset, length, position);
};
fs.writeSync = sinon.stub(fs, 'writeSync').throws(noSpaceError);

const err = t.throws(() => m.sync('license', t.context.dest));
t.is(err.name, 'CpFileError', err);
t.is(err.errno, noSpaceError.errno, err);
t.is(err.code, noSpaceError.code, err);
t.is(called, 1);
t.true(fs.writeSync.called);

fs.writeSync.restore();
});

test('rethrow stat errors', t => {
const openSync = fs.openSync;
const fstatSync = fs.fstatSync;
const fstatError = buildEBADF();
const fds = new Map();
let called = 0;

fs.writeFileSync(t.context.src, '');
fs.openSync = (path, flags, mode) => {
const fd = openSync(path, flags, mode);
fds.set(fd, path);
return fd;
};
fs.fstatSync = fd => {
if (fds.get(fd) === t.context.src) {
called++;
throw fstatError;
}

return fstatSync(fd);
};
fs.fstatSync = sinon.stub(fs, 'fstatSync').throws(fstatError);

const err = t.throws(() => m.sync(t.context.src, t.context.dest));
t.is(err.name, 'CpFileError', err);
t.is(err.errno, fstatError.errno, err);
t.is(err.code, fstatError.code, err);
t.is(called, 1);
t.true(fs.fstatSync.called);

fs.fstatSync.restore();
});

test('rethrow utimes errors', t => {
const openSync = fs.openSync;
const futimesSync = fs.futimesSync;
const futimesError = buildEBADF();
const fds = new Map();
let called = 0;

fs.openSync = (path, flags, mode) => {
const fd = openSync(path, flags, mode);
fds.set(fd, path);
return fd;
};
fs.futimesSync = (fd, atime, mtime) => {
if (fds.get(fd) === t.context.dest) {
called++;
throw futimesError;
}

return futimesSync(path, atime, mtime);
};

fs.futimesSync = sinon.stub(fs, 'futimesSync').throws(futimesError);

const err = t.throws(() => m.sync('license', t.context.dest));
t.is(err.name, 'CpFileError', err);
t.is(err.errno, futimesError.errno, err);
t.is(err.code, futimesError.code, err);
t.is(called, 1);
t.true(fs.futimesSync.called);

fs.futimesSync.restore();
});

test('rethrow EACCES errors of dest', t => {
const openSync = fs.openSync;
const openError = buildEACCES(t.context.dest);
let called = 0;

fs.openSync = (path, flags, mode) => {
if (path === t.context.dest) {
called++;
throw openError;
}

return openSync(path, flags, mode);
};
fs.openSync = sinon.stub(fs, 'openSync').throws(openError);

const err = t.throws(() => m.sync('license', t.context.dest));
t.is(err.name, 'CpFileError', err);
t.is(err.errno, openError.errno, err);
t.is(err.code, openError.code, err);
t.is(err.path, openError.path, err);
t.is(called, 1);
t.true(fs.openSync.called);

fs.openSync.restore();
});

0 comments on commit fdba27e

Please sign in to comment.