mock-fs-require-fix
Version:
Fork of the tschaub/mock-fs project.
1,784 lines (1,468 loc) • 87.7 kB
JavaScript
'use strict';
var Writable = require('stream').Writable;
var assert = require('../helper').assert;
var fs = require('fs');
var fork = require('child_process').fork;
var mock = require('../../lib/index');
var os = require('os');
var path = require('path');
var testParentPerms = (fs.access && fs.accessSync && process.getuid && process.getgid);
describe('The API', function() {
describe('mock()', function() {
it('configures the real fs module with a mock file system', function() {
mock({
'fake-file-for-testing-only': 'file content'
});
assert.isTrue(fs.existsSync('fake-file-for-testing-only'));
mock.restore();
});
it('creates process.cwd() and os.tmpdir() by default', function() {
mock();
assert.isTrue(fs.statSync(process.cwd()).isDirectory());
var tmp;
if (os.tmpdir) {
tmp = os.tmpdir();
} else if (os.tmpDir) {
tmp = os.tmpDir();
}
if (tmp) {
assert.isTrue(fs.statSync(tmp).isDirectory());
}
mock.restore();
});
it('passes the createCwd option to the FileSystem constructor', function() {
mock({}, {createCwd: false});
assert.isFalse(fs.existsSync(process.cwd()));
mock.restore();
});
it('passes the createTmp option to the FileSystem constructor', function() {
mock({}, {createTmp: false});
var tmp;
if (os.tmpdir) {
tmp = os.tmpdir();
} else if (os.tmpDir) {
tmp = os.tmpDir();
}
if (tmp) {
assert.isFalse(fs.existsSync(tmp));
}
mock.restore();
});
it('uses the real fs module in require() calls', function() {
mock({foo: 'bar'});
var pkg = require('../../package.json');
assert.equal(pkg.name, 'mock-fs-require-fix');
mock.restore();
});
it('uses the mocked fs module after recent core require() calls', function(done) {
var child = fork('../../fixtures/mock-fs-parent.js', {
cwd: __dirname,
silent: true
});
var called = false;
child.on('exit', function() {
if (called) return;
called = true;
done(new Error('Sandbox was ignored'));
});
child.stderr.on('data', function() {
if (called) return;
called = true;
done(null);
});
});
it('uses the mocked fs module after recent fs require() calls', function(done) {
var child = fork('../../fixtures/mock-fs-parent-nested.js', {
cwd: __dirname,
silent: true
});
var called = false;
child.on('exit', function() {
if (called) return;
called = true;
done(new Error('Sandbox was ignored'));
});
child.stderr.on('data', function() {
if (called) return;
called = true;
done(null);
});
});
});
describe('mock.restore()', function() {
it('restores bindings for the real file system', function() {
mock({
'fake-file-for-testing-only': 'file content'
});
assert.isTrue(fs.existsSync('fake-file-for-testing-only'));
mock.restore();
assert.isFalse(fs.existsSync('fake-file-for-testing-only'));
});
});
describe('mock.file()', function() {
afterEach(mock.restore);
it('lets you create files with additional properties', function(done) {
mock({
'path/to/file.txt': mock.file({
content: 'file content',
mtime: new Date(8675309),
mode: parseInt('0644', 8)
})
});
fs.stat('path/to/file.txt', function(err, stats) {
if (err) {
return done(err);
}
assert.isTrue(stats.isFile());
assert.isFalse(stats.isDirectory());
assert.equal(stats.mtime.getTime(), 8675309);
assert.equal(stats.mode & parseInt('0777', 8), parseInt('0644', 8));
done();
});
});
});
describe('mock.directory()', function() {
afterEach(mock.restore);
it('lets you create directories with more properties', function(done) {
mock({
'path/to/dir': mock.directory({
mtime: new Date(8675309),
mode: parseInt('0644', 8)
})
});
fs.stat('path/to/dir', function(err, stats) {
if (err) {
return done(err);
}
assert.isFalse(stats.isFile());
assert.isTrue(stats.isDirectory());
assert.equal(stats.mtime.getTime(), 8675309);
assert.equal(stats.mode & parseInt('0777', 8), parseInt('0644', 8));
done();
});
});
it('works with a trailing slash', function() {
mock({
'path/to/dir/': mock.directory({
mtime: new Date(8675309),
mode: parseInt('0644', 8)
})
});
assert.isTrue(fs.statSync('path/to/dir').isDirectory());
assert.isTrue(fs.statSync('path/to/dir/').isDirectory());
});
it('works without a trailing slash', function() {
mock({
'path/to/dir': mock.directory({
mtime: new Date(8675309),
mode: parseInt('0644', 8)
})
});
assert.isTrue(fs.statSync('path/to/dir').isDirectory());
assert.isTrue(fs.statSync('path/to/dir/').isDirectory());
});
});
describe('mock.symlink()', function() {
afterEach(mock.restore);
it('lets you create symbolic links', function() {
mock({
'path/to/file': 'content',
'path/to/link': mock.symlink({path: './file'})
});
var stats = fs.statSync('path/to/link');
assert.isTrue(stats.isFile());
assert.equal(String(fs.readFileSync('path/to/link')), 'content');
});
});
describe('mock.fs()', function() {
it('generates a mock fs module with a mock file system', function(done) {
var mockFs = mock.fs({
'path/to/file.txt': 'file content'
});
mockFs.exists('path/to/file.txt', function(exists) {
assert.isTrue(exists);
done();
});
});
it('passes options to the FileSystem constructor', function() {
var mockFs = mock.fs({
'/path/to/file.txt': 'file content'
}, {
createCwd: false,
createTmp: false
});
assert.isTrue(mockFs.existsSync('/path/to/file.txt'));
assert.deepEqual(mockFs.readdirSync('/'), ['path']);
});
it('accepts an arbitrary nesting of files and directories', function() {
var mockFs = mock.fs({
'dir-one': {
'dir-two': {
'some-file.txt': 'file content here'
}
},
'empty-dir': {}
});
assert.isTrue(mockFs.existsSync('dir-one/dir-two/some-file.txt'));
assert.isTrue(mockFs.statSync('dir-one/dir-two/some-file.txt').isFile());
assert.isTrue(mockFs.statSync('dir-one/dir-two').isDirectory());
assert.isTrue(mockFs.statSync('empty-dir').isDirectory());
});
});
});
describe('Mocking the file system', function() {
if (fs.access && fs.accessSync && process.getuid && process.getgid) {
// TODO: drop condition when dropping Node < 0.12 support
// TODO: figure out how fs.access() works on Windows (without gid/uid)
describe('fs.access(path[, mode], callback)', function() {
beforeEach(function() {
mock({
'path/to/accessible/file': 'can access',
'path/to/000': mock.file({
mode: parseInt('0000', 8),
content: 'no permissions'
}),
'path/to/111': mock.file({
mode: parseInt('0111', 8),
content: 'execute only'
}),
'path/to/write/only': mock.file({
mode: parseInt('0222', 8),
content: 'write only'
}),
'path/to/333': mock.file({
mode: parseInt('0333', 8),
content: 'write and execute'
}),
'path/to/444': mock.file({
mode: parseInt('0444', 8),
content: 'read only'
}),
'path/to/555': mock.file({
mode: parseInt('0555', 8),
content: 'read and execute'
}),
'path/to/666': mock.file({
mode: parseInt('0666', 8),
content: 'read and write'
}),
'path/to/777': mock.file({
mode: parseInt('0777', 8),
content: 'read, write, and execute'
}),
'unreadable': mock.directory({mode: parseInt('0000', 8), items: {
'readable-child': mock.file({
mode: parseInt('0777', 8),
content: 'read, write, and execute'
})
}})
});
});
afterEach(mock.restore);
it('works for an accessible file', function(done) {
fs.access('path/to/accessible/file', done);
});
it('works 000 (and no mode arg)', function(done) {
fs.access('path/to/000', done);
});
it('works F_OK and 000', function(done) {
fs.access('path/to/000', fs.F_OK, done);
});
it('generates EACCES for R_OK and 000', function(done) {
fs.access('path/to/000', fs.R_OK, function(err) {
assert.instanceOf(err, Error);
assert.equal(err.code, 'EACCES');
done();
});
});
it('generates EACCES for W_OK and 000', function(done) {
fs.access('path/to/000', fs.W_OK, function(err) {
assert.instanceOf(err, Error);
assert.equal(err.code, 'EACCES');
done();
});
});
it('generates EACCES for X_OK and 000', function(done) {
fs.access('path/to/000', fs.X_OK, function(err) {
assert.instanceOf(err, Error);
assert.equal(err.code, 'EACCES');
done();
});
});
it('works 111 (and no mode arg)', function(done) {
fs.access('path/to/111', done);
});
it('works F_OK and 111', function(done) {
fs.access('path/to/111', fs.F_OK, done);
});
it('works X_OK and 111', function(done) {
fs.access('path/to/111', fs.X_OK, done);
});
it('generates EACCES for R_OK and 111', function(done) {
fs.access('path/to/111', fs.R_OK, function(err) {
assert.instanceOf(err, Error);
assert.equal(err.code, 'EACCES');
done();
});
});
it('generates EACCES for W_OK and 111', function(done) {
fs.access('path/to/111', fs.W_OK, function(err) {
assert.instanceOf(err, Error);
assert.equal(err.code, 'EACCES');
done();
});
});
it('works for 222 (and no mode arg)', function(done) {
fs.access('path/to/write/only', done);
});
it('works F_OK and 222', function(done) {
fs.access('path/to/write/only', fs.F_OK, done);
});
it('works W_OK and 222', function(done) {
fs.access('path/to/write/only', fs.W_OK, done);
});
it('generates EACCES for R_OK and 222', function(done) {
fs.access('path/to/write/only', fs.R_OK, function(err) {
assert.instanceOf(err, Error);
assert.equal(err.code, 'EACCES');
done();
});
});
it('generates EACCES for X_OK and 222', function(done) {
fs.access('path/to/write/only', fs.X_OK, function(err) {
assert.instanceOf(err, Error);
assert.equal(err.code, 'EACCES');
done();
});
});
it('works for 333 (and no mode arg)', function(done) {
fs.access('path/to/333', done);
});
it('works F_OK and 333', function(done) {
fs.access('path/to/333', fs.F_OK, done);
});
it('works W_OK and 333', function(done) {
fs.access('path/to/333', fs.W_OK, done);
});
it('works X_OK and 333', function(done) {
fs.access('path/to/333', fs.X_OK, done);
});
it('works X_OK | W_OK and 333', function(done) {
fs.access('path/to/333', fs.X_OK | fs.W_OK, done);
});
it('generates EACCES for R_OK and 333', function(done) {
fs.access('path/to/333', fs.R_OK, function(err) {
assert.instanceOf(err, Error);
assert.equal(err.code, 'EACCES');
done();
});
});
it('works for 444 (and no mode arg)', function(done) {
fs.access('path/to/444', done);
});
it('works F_OK and 444', function(done) {
fs.access('path/to/444', fs.F_OK, done);
});
it('works R_OK and 444', function(done) {
fs.access('path/to/444', fs.R_OK, done);
});
it('generates EACCES for W_OK and 444', function(done) {
fs.access('path/to/444', fs.W_OK, function(err) {
assert.instanceOf(err, Error);
assert.equal(err.code, 'EACCES');
done();
});
});
it('generates EACCES for X_OK and 444', function(done) {
fs.access('path/to/444', fs.X_OK, function(err) {
assert.instanceOf(err, Error);
assert.equal(err.code, 'EACCES');
done();
});
});
it('works for 555 (and no mode arg)', function(done) {
fs.access('path/to/555', done);
});
it('works F_OK and 555', function(done) {
fs.access('path/to/555', fs.F_OK, done);
});
it('works R_OK and 555', function(done) {
fs.access('path/to/555', fs.R_OK, done);
});
it('works X_OK and 555', function(done) {
fs.access('path/to/555', fs.X_OK, done);
});
it('works R_OK | X_OK and 555', function(done) {
fs.access('path/to/555', fs.R_OK | fs.X_OK, done);
});
it('generates EACCES for W_OK and 555', function(done) {
fs.access('path/to/555', fs.W_OK, function(err) {
assert.instanceOf(err, Error);
assert.equal(err.code, 'EACCES');
done();
});
});
it('works for 666 (and no mode arg)', function(done) {
fs.access('path/to/666', done);
});
it('works F_OK and 666', function(done) {
fs.access('path/to/666', fs.F_OK, done);
});
it('works R_OK and 666', function(done) {
fs.access('path/to/666', fs.R_OK, done);
});
it('works W_OK and 666', function(done) {
fs.access('path/to/666', fs.W_OK, done);
});
it('works R_OK | W_OK and 666', function(done) {
fs.access('path/to/666', fs.R_OK | fs.W_OK, done);
});
it('generates EACCES for X_OK and 666', function(done) {
fs.access('path/to/666', fs.X_OK, function(err) {
assert.instanceOf(err, Error);
assert.equal(err.code, 'EACCES');
done();
});
});
it('works for 777 (and no mode arg)', function(done) {
fs.access('path/to/777', done);
});
it('works F_OK and 777', function(done) {
fs.access('path/to/777', fs.F_OK, done);
});
it('works R_OK and 777', function(done) {
fs.access('path/to/777', fs.R_OK, done);
});
it('works W_OK and 777', function(done) {
fs.access('path/to/777', fs.W_OK, done);
});
it('works X_OK and 777', function(done) {
fs.access('path/to/777', fs.X_OK, done);
});
it('works X_OK | W_OK and 777', function(done) {
fs.access('path/to/777', fs.X_OK | fs.W_OK, done);
});
it('works X_OK | R_OK and 777', function(done) {
fs.access('path/to/777', fs.X_OK | fs.R_OK, done);
});
it('works R_OK | W_OK and 777', function(done) {
fs.access('path/to/777', fs.R_OK | fs.W_OK, done);
});
it('works R_OK | W_OK | X_OK and 777', function(done) {
fs.access('path/to/777', fs.R_OK | fs.W_OK | fs.X_OK, done);
});
it('generates EACCESS for F_OK and an unreadable parent', function(done) {
fs.access('unreadable/readable-child', function(err) {
assert.instanceOf(err, Error);
assert.equal(err.code, 'EACCES');
done();
});
});
});
describe('fs.accessSync(path[, mode])', function() {
beforeEach(function() {
mock({
'path/to/777': mock.file({
mode: parseInt('0777', 8),
content: 'all access'
}),
'path/to/000': mock.file({
mode: parseInt('0000', 8),
content: 'no permissions'
})
});
});
afterEach(mock.restore);
it('works for an accessible file', function() {
fs.accessSync('path/to/777');
fs.accessSync('path/to/777', fs.F_OK);
fs.accessSync('path/to/777', fs.X_OK);
fs.accessSync('path/to/777', fs.W_OK);
fs.accessSync('path/to/777', fs.X_OK | fs.W_OK);
fs.accessSync('path/to/777', fs.R_OK);
fs.accessSync('path/to/777', fs.X_OK | fs.R_OK);
fs.accessSync('path/to/777', fs.W_OK | fs.R_OK);
fs.accessSync('path/to/777', fs.X_OK | fs.W_OK | fs.R_OK);
});
it('throws EACCESS for all but F_OK for 000', function() {
fs.accessSync('path/to/000');
assert.throws(function() {
fs.accessSync('path/to/000', fs.X_OK);
});
assert.throws(function() {
fs.accessSync('path/to/000', fs.W_OK);
});
assert.throws(function() {
fs.accessSync('path/to/000', fs.X_OK | fs.W_OK);
});
assert.throws(function() {
fs.accessSync('path/to/000', fs.R_OK);
});
assert.throws(function() {
fs.accessSync('path/to/000', fs.X_OK | fs.R_OK);
});
assert.throws(function() {
fs.accessSync('path/to/000', fs.W_OK | fs.R_OK);
});
assert.throws(function() {
fs.accessSync('path/to/000', fs.X_OK | fs.W_OK | fs.R_OK);
});
});
});
}
describe('fs.rename(oldPath, newPath, callback)', function() {
beforeEach(function() {
mock({
'path/to/a.bin': new Buffer([1, 2, 3]),
'empty': {},
'nested': {
'dir': mock.directory({
mtime: new Date(1),
items: {'file.txt': ''}
})
}
});
});
afterEach(mock.restore);
it('allows files to be renamed', function(done) {
fs.rename('path/to/a.bin', 'path/to/b.bin', function(err) {
assert.isTrue(!err);
assert.isFalse(fs.existsSync('path/to/a.bin'));
assert.isTrue(fs.existsSync('path/to/b.bin'));
done();
});
});
it('updates mtime of parent directory', function(done) {
var oldTime = fs.statSync('nested/dir').mtime;
fs.rename('nested/dir/file.txt', 'nested/dir/renamed.txt', function(err) {
assert.isTrue(!err);
assert.isFalse(fs.existsSync('nested/dir/file.txt'));
assert.isTrue(fs.existsSync('nested/dir/renamed.txt'));
var newTime = fs.statSync('nested/dir').mtime;
assert.isTrue(newTime > oldTime);
done();
});
});
it('calls callback with error if old path does not exist', function(done) {
fs.rename('bogus', 'empty', function(err) {
assert.instanceOf(err, Error);
done();
});
});
it('overwrites existing files', function(done) {
fs.rename('path/to/a.bin', 'nested/dir/file.txt', function(err) {
assert.isTrue(!err);
assert.isFalse(fs.existsSync('path/to/a.bin'));
assert.isTrue(fs.existsSync('nested/dir/file.txt'));
done();
});
});
it('allows directories to be renamed', function(done) {
fs.rename('path/to', 'path/foo', function(err) {
assert.isTrue(!err);
assert.isFalse(fs.existsSync('path/to'));
assert.isTrue(fs.existsSync('path/foo'));
assert.deepEqual(fs.readdirSync('path/foo'), ['a.bin']);
done();
});
});
it('calls callback with error if new directory not empty', function(done) {
fs.rename('path', 'nested', function(err) {
assert.instanceOf(err, Error);
done();
});
});
});
describe('fs.renameSync(oldPath, newPath)', function() {
beforeEach(function() {
mock({
'path/to/a.bin': new Buffer([1, 2, 3]),
'empty': {},
'nested': {
'dir': {
'file.txt': ''
}
},
'link': mock.symlink({path: './path/to/a.bin'})
});
});
afterEach(mock.restore);
it('allows files to be renamed', function() {
fs.renameSync('path/to/a.bin', 'path/to/b.bin');
assert.isFalse(fs.existsSync('path/to/a.bin'));
assert.isTrue(fs.existsSync('path/to/b.bin'));
});
it('overwrites existing files', function() {
fs.renameSync('path/to/a.bin', 'nested/dir/file.txt');
assert.isFalse(fs.existsSync('path/to/a.bin'));
assert.isTrue(fs.existsSync('nested/dir/file.txt'));
});
it('allows directories to be renamed', function() {
fs.renameSync('path/to', 'path/foo');
assert.isFalse(fs.existsSync('path/to'));
assert.isTrue(fs.existsSync('path/foo'));
assert.deepEqual(fs.readdirSync('path/foo'), ['a.bin']);
});
it('replaces existing directories (if empty)', function() {
fs.renameSync('path/to', 'empty');
assert.isFalse(fs.existsSync('path/to'));
assert.isTrue(fs.existsSync('empty'));
assert.deepEqual(fs.readdirSync('empty'), ['a.bin']);
});
it('renames symbolic links', function() {
fs.renameSync('link', 'renamed');
assert.isTrue(fs.existsSync('renamed'));
assert.isFalse(fs.existsSync('link'));
assert.isTrue(fs.existsSync('path/to/a.bin'));
});
it('throws if old path does not exist', function() {
assert.throws(function() {
fs.renameSync('bogus', 'empty');
});
});
it('throws if new path basename is not directory', function() {
assert.throws(function() {
fs.renameSync('path/to/a.bin', 'bogus/a.bin');
});
});
it('throws if new dir is not empty dir', function() {
assert.throws(function() {
fs.renameSync('path/to', 'nested');
});
});
});
describe('fs.stat(path, callback)', function() {
beforeEach(function() {
mock({
'/path/to/file.txt': mock.file({
ctime: new Date(1),
mtime: new Date(2),
atime: new Date(3),
uid: 42,
gid: 43
}),
'/dir/symlink': mock.symlink({path: '/path/to/file.txt'}),
'/empty': {}
});
});
afterEach(mock.restore);
it('creates an instance of fs.Stats', function(done) {
fs.stat('/path/to/file.txt', function(err, stats) {
if (err) {
return done(err);
}
assert.instanceOf(stats, fs.Stats);
done();
});
});
it('identifies files', function(done) {
fs.stat('/path/to/file.txt', function(err, stats) {
if (err) {
return done(err);
}
assert.isTrue(stats.isFile());
assert.isFalse(stats.isDirectory());
done();
});
});
it('identifies directories', function(done) {
fs.stat('/empty', function(err, stats) {
if (err) {
return done(err);
}
assert.isTrue(stats.isDirectory());
assert.isFalse(stats.isFile());
done();
});
});
it('provides file stats', function(done) {
fs.stat('/path/to/file.txt', function(err, stats) {
if (err) {
return done(err);
}
assert.equal(stats.ctime.getTime(), 1);
assert.equal(stats.mtime.getTime(), 2);
assert.equal(stats.atime.getTime(), 3);
assert.equal(stats.uid, 42);
assert.equal(stats.gid, 43);
assert.equal(stats.nlink, 1);
assert.isNumber(stats.blocks);
assert.isNumber(stats.blksize);
assert.isNumber(stats.rdev);
done();
});
});
it('provides directory stats', function(done) {
fs.stat('/path', function(err, stats) {
if (err) {
return done(err);
}
assert.instanceOf(stats.ctime, Date);
assert.instanceOf(stats.mtime, Date);
assert.instanceOf(stats.atime, Date);
if (process.getuid) {
assert.isNumber(stats.uid);
} else {
assert.isUndefined(stats.uid);
}
if (process.getgid) {
assert.isNumber(stats.gid);
} else {
assert.isUndefined(stats.gid);
}
assert.equal(stats.nlink, 3);
assert.isNumber(stats.blocks);
assert.isNumber(stats.blksize);
assert.isNumber(stats.rdev);
done();
});
});
});
describe('fs.fstat(fd, callback)', function() {
beforeEach(function() {
mock({
'path/to/file.txt': 'file content',
'empty': {}
});
});
afterEach(mock.restore);
it('accepts a file descriptor for a file (r)', function(done) {
var fd = fs.openSync('path/to/file.txt', 'r');
fs.fstat(fd, function(err, stats) {
if (err) {
return done(err);
}
assert.isTrue(stats.isFile());
assert.equal(stats.size, 12);
done();
});
});
it('accepts a file descriptor for a directory (r)', function(done) {
var fd = fs.openSync('path/to', 'r');
fs.fstat(fd, function(err, stats) {
if (err) {
return done(err);
}
assert.isTrue(stats.isDirectory());
assert.isTrue(stats.size > 0);
done();
});
});
it('fails for bad file descriptor', function(done) {
var fd = fs.openSync('path/to/file.txt', 'r');
fs.closeSync(fd);
fs.fstat(fd, function(err, stats) {
assert.instanceOf(err, Error);
done();
});
});
});
describe('fs.fstatSync(fd)', function() {
beforeEach(function() {
mock({
'path/to/file.txt': 'file content',
'empty': {}
});
});
afterEach(mock.restore);
it('accepts a file descriptor for a file (r)', function() {
var fd = fs.openSync('path/to/file.txt', 'r');
var stats = fs.fstatSync(fd);
assert.isTrue(stats.isFile());
assert.equal(stats.size, 12);
});
it('accepts a file descriptor for a directory (r)', function() {
var fd = fs.openSync('path/to', 'r');
var stats = fs.fstatSync(fd);
assert.isTrue(stats.isDirectory());
assert.isTrue(stats.size > 0);
});
it('fails for bad file descriptor', function() {
var fd = fs.openSync('path/to/file.txt', 'r');
fs.closeSync(fd);
assert.throws(function() {
fs.fstatSync(fd);
});
});
});
describe('fs.exists(path, callback)', function() {
beforeEach(function() {
mock({
'path/to/a.bin': new Buffer([1, 2, 3]),
'empty': {},
'nested': {
'dir': {
'file.txt': ''
}
}
});
});
afterEach(mock.restore);
it('calls with true if file exists', function(done) {
fs.exists(path.join('path', 'to', 'a.bin'), function(exists) {
assert.isTrue(exists);
done();
});
});
it('calls with true if directory exists', function(done) {
fs.exists('path', function(exists) {
assert.isTrue(exists);
done();
});
});
it('calls with true if empty directory exists', function(done) {
fs.exists('empty', function(exists) {
assert.isTrue(exists);
done();
});
});
it('calls with true if nested directory exists', function(done) {
fs.exists(path.join('nested', 'dir'), function(exists) {
assert.isTrue(exists);
done();
});
});
it('calls with true if file exists', function(done) {
fs.exists(path.join('path', 'to', 'a.bin'), function(exists) {
assert.isTrue(exists);
done();
});
});
it('calls with true if empty file exists', function(done) {
fs.exists(path.join('nested', 'dir', 'file.txt'), function(exists) {
assert.isTrue(exists);
done();
});
});
it('calls with false for bogus path', function(done) {
fs.exists(path.join('bogus', 'path'), function(exists) {
assert.isFalse(exists);
done();
});
});
it('calls with false for bogus path (II)', function(done) {
fs.exists(path.join('nested', 'dir', 'none'), function(exists) {
assert.isFalse(exists);
done();
});
});
});
describe('fs.existsSync(path)', function() {
beforeEach(function() {
mock({
'path/to/a.bin': new Buffer([1, 2, 3]),
'empty': {},
'nested': {
'dir': {
'file.txt': ''
}
}
});
});
afterEach(mock.restore);
it('returns true if file exists', function() {
assert.isTrue(fs.existsSync(path.join('path', 'to', 'a.bin')));
});
it('returns true if directory exists', function() {
assert.isTrue(fs.existsSync('path'));
});
it('returns true if empty directory exists', function() {
assert.isTrue(fs.existsSync('empty'));
});
it('returns true if nested directory exists', function() {
assert.isTrue(fs.existsSync(path.join('nested', 'dir')));
});
it('returns true if file exists', function() {
assert.isTrue(fs.existsSync(path.join('path', 'to', 'a.bin')));
});
it('returns true if empty file exists', function() {
assert.isTrue(fs.existsSync(path.join('nested', 'dir', 'file.txt')));
});
it('returns false for bogus path', function() {
assert.isFalse(fs.existsSync(path.join('bogus', 'path')));
});
it('returns false for bogus path (II)', function() {
assert.isFalse(fs.existsSync(path.join('nested', 'dir', 'none')));
});
});
describe('fs.readdirSync(path)', function() {
beforeEach(function() {
mock({
'path/to/file.txt': 'file content',
'nested': {
'sub': {
'dir': {
'one.txt': 'one content',
'two.txt': 'two content',
'empty': {}
}
}
}
});
});
afterEach(mock.restore);
it('lists directory contents', function() {
var items = fs.readdirSync(path.join('path', 'to'));
assert.isArray(items);
assert.deepEqual(items, ['file.txt']);
});
it('lists nested directory contents', function() {
var items = fs.readdirSync(path.join('nested', 'sub', 'dir'));
assert.isArray(items);
assert.deepEqual(items, ['empty', 'one.txt', 'two.txt']);
});
it('throws for bogus path', function() {
assert.throws(function() {
fs.readdirSync('bogus');
});
});
});
describe('fs.readdir(path, callback)', function() {
beforeEach(function() {
mock({
'path/to/file.txt': 'file content',
'nested': {
'sub': {
'dir': {
'one.txt': 'one content',
'two.txt': 'two content',
'empty': {}
}
}
}
});
});
afterEach(mock.restore);
it('lists directory contents', function(done) {
fs.readdir(path.join('path', 'to'), function(err, items) {
assert.isNull(err);
assert.isArray(items);
assert.deepEqual(items, ['file.txt']);
done();
});
});
it('lists nested directory contents', function(done) {
fs.readdir(path.join('nested', 'sub', 'dir'), function(err, items) {
assert.isNull(err);
assert.isArray(items);
assert.deepEqual(items, ['empty', 'one.txt', 'two.txt']);
done();
});
});
it('calls with an error for bogus path', function(done) {
fs.readdir('bogus', function(err, items) {
assert.instanceOf(err, Error);
assert.isUndefined(items);
done();
});
});
});
describe('fs.readdirSync(path)', function() {
beforeEach(function() {
mock({
'path/to/file.txt': 'file content',
'nested': {
'sub': {
'dir': {
'one.txt': 'one content',
'two.txt': 'two content',
'empty': {}
}
}
}
});
});
afterEach(mock.restore);
it('lists directory contents', function() {
var items = fs.readdirSync(path.join('path', 'to'));
assert.isArray(items);
assert.deepEqual(items, ['file.txt']);
});
it('lists nested directory contents', function() {
var items = fs.readdirSync(path.join('nested', 'sub', 'dir'));
assert.isArray(items);
assert.deepEqual(items, ['empty', 'one.txt', 'two.txt']);
});
it('throws for bogus path', function() {
assert.throws(function() {
fs.readdirSync('bogus');
});
});
});
describe('fs.open(path, flags, [mode], callback)', function() {
beforeEach(function() {
mock({
'path/to/file.txt': 'file content',
'nested': {
'sub': {
'dir': {
'one.txt': 'one content',
'two.txt': 'two content',
'empty': {}
}
}
}
});
});
afterEach(mock.restore);
it('opens an existing file for reading (r)', function(done) {
fs.open('nested/sub/dir/one.txt', 'r', function(err, fd) {
if (err) {
return done(err);
}
assert.isNumber(fd);
done();
});
});
it('fails if file does not exist (r)', function(done) {
fs.open('bogus.txt', 'r', function(err, fd) {
assert.instanceOf(err, Error);
done();
});
});
it('creates a new file for writing (w)', function(done) {
fs.open('path/to/new.txt', 'w', parseInt('0666', 8), function(err, fd) {
if (err) {
return done(err);
}
assert.isNumber(fd);
assert.isTrue(fs.existsSync('path/to/new.txt'));
done();
});
});
it('opens an existing file for writing (w)', function(done) {
fs.open('path/to/one.txt', 'w', parseInt('0666', 8), function(err, fd) {
if (err) {
return done(err);
}
assert.isNumber(fd);
done();
});
});
it('fails if file exists (wx)', function(done) {
fs.open('path/to/one.txt', 'wx', parseInt('0666', 8), function(err, fd) {
if (err) {
return done(err);
}
assert.isNumber(fd);
done();
});
});
});
describe('fs.openSync(path, flags, [mode])', function() {
beforeEach(function() {
mock({
'path/to/file.txt': 'file content',
'nested': {
'sub': {
'dir': {
'one.txt': 'one content',
'two.txt': 'two content',
'empty': {}
}
}
}
});
});
afterEach(mock.restore);
it('opens an existing file for reading (r)', function() {
var fd = fs.openSync('path/to/file.txt', 'r');
assert.isNumber(fd);
});
it('fails if file does not exist (r)', function() {
assert.throws(function() {
fs.openSync('bogus.txt', 'r');
});
});
it('creates a new file for writing (w)', function() {
var fd = fs.openSync('nested/sub/new.txt', 'w', parseInt('0666', 8));
assert.isNumber(fd);
assert.isTrue(fs.existsSync('nested/sub/new.txt'));
});
it('opens an existing file for writing (w)', function() {
var fd = fs.openSync('path/to/one.txt', 'w', parseInt('0666', 8));
assert.isNumber(fd);
});
it('fails if file exists (wx)', function() {
assert.throws(function() {
fs.openSync('path/to/file.txt', 'wx', parseInt('0666', 8));
});
});
});
describe('fs.close(fd, callback)', function() {
beforeEach(function() {
mock({'dir': {}});
});
afterEach(mock.restore);
it('closes a file descriptor', function(done) {
var fd = fs.openSync('dir/file.txt', 'w');
fs.close(fd, function(err) {
done(err);
});
});
it('fails for closed file descriptors', function(done) {
var fd = fs.openSync('dir/file.txt', 'w');
fs.close(fd, function(err) {
if (err) {
return done(err);
}
fs.close(fd, function(err2) {
assert.instanceOf(err2, Error);
done();
});
});
});
});
describe('fs.closeSync(fd)', function() {
beforeEach(function() {
mock({'dir': {}});
});
afterEach(mock.restore);
it('closes a file descriptor', function() {
var fd = fs.openSync('dir/file.txt', 'w');
fs.closeSync(fd);
});
it('fails for closed file descriptors', function() {
var fd = fs.openSync('dir/file.txt', 'w');
fs.closeSync(fd);
assert.throws(function() {
fs.closeSync(fd);
});
});
});
describe('fs.read(fd, buffer, offset, length, position, callback)', function() {
beforeEach(function() {
mock({
'path/to/file.txt': 'file content'
});
});
afterEach(mock.restore);
it('allows file contents to be read', function(done) {
fs.open('path/to/file.txt', 'r', function(err, fd) {
if (err) {
return done(err);
}
var buffer = new Buffer(12);
fs.read(fd, buffer, 0, 12, 0, function(err2, bytesRead, buf) {
if (err2) {
return done(err2);
}
assert.equal(bytesRead, 12);
assert.equal(buf, buffer);
assert.equal(String(buffer), 'file content');
done();
});
});
});
it('allows file contents to be read w/ offset', function(done) {
fs.open('path/to/file.txt', 'r', function(err, fd) {
if (err) {
return done(err);
}
var buffer = new Buffer(12);
fs.read(fd, buffer, 5, 12, 0, function(err2, bytesRead, buf) {
if (err2) {
return done(err2);
}
assert.equal(bytesRead, 7);
assert.equal(buf, buffer);
assert.equal(String(buffer.slice(5)), 'file co');
done();
});
});
});
it('allows file contents to be read w/ length', function(done) {
fs.open('path/to/file.txt', 'r', function(err, fd) {
if (err) {
return done(err);
}
var buffer = new Buffer(12);
fs.read(fd, buffer, 0, 4, 0, function(err2, bytesRead, buf) {
if (err2) {
return done(err2);
}
assert.equal(bytesRead, 4);
assert.equal(buf, buffer);
assert.equal(String(buffer.slice(0, 4)), 'file');
done();
});
});
});
it('allows file contents to be read w/ offset & length', function(done) {
fs.open('path/to/file.txt', 'r', function(err, fd) {
if (err) {
return done(err);
}
var buffer = new Buffer(12);
fs.read(fd, buffer, 2, 4, 0, function(err2, bytesRead, buf) {
if (err2) {
return done(err2);
}
assert.equal(bytesRead, 4);
assert.equal(buf, buffer);
assert.equal(String(buffer.slice(2, 6)), 'file');
done();
});
});
});
it('allows file contents to be read w/ position', function(done) {
fs.open('path/to/file.txt', 'r', function(err, fd) {
if (err) {
return done(err);
}
var buffer = new Buffer(7);
fs.read(fd, buffer, 0, 7, 5, function(err2, bytesRead, buf) {
if (err2) {
return done(err2);
}
assert.equal(bytesRead, 7);
assert.equal(buf, buffer);
assert.equal(String(buffer), 'content');
done();
});
});
});
it('allows read w/ offset, length, & position', function(done) {
fs.open('path/to/file.txt', 'r', function(err, fd) {
if (err) {
return done(err);
}
var buffer = new Buffer(12);
fs.read(fd, buffer, 2, 7, 5, function(err2, bytesRead, buf) {
if (err2) {
return done(err2);
}
assert.equal(bytesRead, 7);
assert.equal(buf, buffer);
assert.equal(String(buffer.slice(2, 9)), 'content');
done();
});
});
});
it('fails for closed file descriptor', function(done) {
var fd = fs.openSync('path/to/file.txt', 'r');
fs.closeSync(fd);
fs.read(fd, new Buffer(12), 0, 12, 0, function(err, bytesRead, buf) {
assert.instanceOf(err, Error);
assert.equal(0, bytesRead);
done();
});
});
it('fails if not open for reading', function(done) {
var fd = fs.openSync('path/to/file.txt', 'w');
fs.read(fd, new Buffer(12), 0, 12, 0, function(err, bytesRead, buf) {
assert.instanceOf(err, Error);
assert.equal(0, bytesRead);
done();
});
});
});
describe('fs.readSync(fd, buffer, offset, length, position)', function() {
beforeEach(function() {
mock({
'path/to/file.txt': 'file content'
});
});
afterEach(mock.restore);
it('allows a file to be read synchronously', function() {
var fd = fs.openSync('path/to/file.txt', 'r');
var buffer = new Buffer(12);
var read = fs.readSync(fd, buffer, 0, 12, 0);
assert.equal(read, 12);
assert.equal(String(buffer), 'file content');
});
it('allows a file to be read in two parts', function() {
var fd = fs.openSync('path/to/file.txt', 'r');
var first = new Buffer(4);
fs.readSync(fd, first, 0, 4, 0);
assert.equal(String(first), 'file');
var second = new Buffer(7);
fs.readSync(fd, second, 0, 7, 5);
assert.equal(String(second), 'content');
});
it('treats null position as current position', function() {
var fd = fs.openSync('path/to/file.txt', 'r');
var first = new Buffer(4);
fs.readSync(fd, first, 0, 4, null);
assert.equal(String(first), 'file');
// consume the space
assert.equal(fs.readSync(fd, new Buffer(1), 0, 1, null), 1);
var second = new Buffer(7);
fs.readSync(fd, second, 0, 7, null);
assert.equal(String(second), 'content');
});
});
describe('fs.readFile(filename, [options], callback)', function() {
// this is provided by fs.open, fs.fstat, and fs.read
// so more heavily tested elsewhere
beforeEach(function() {
mock({
'path/to/file.txt': 'file content'
});
});
afterEach(mock.restore);
it('allows a file to be read asynchronously', function(done) {
fs.readFile('path/to/file.txt', function(err, data) {
if (err) {
return done(err);
}
assert.isTrue(Buffer.isBuffer(data));
assert.equal(String(data), 'file content');
done();
});
});
it('fails for directory', function(done) {
fs.readFile('path/to', function(err, data) {
assert.instanceOf(err, Error);
done();
});
});
it('fails for bad path', function(done) {
fs.readFile('path/to/bogus', function(err, data) {
assert.instanceOf(err, Error);
done();
});
});
});
describe('fs.readFileSync(filename, [options])', function() {
// this is provided by fs.openSync, fs.fstatSync, and fs.readSync
// so more heavily tested elsewhere
beforeEach(function() {
mock({
'path/to/file.txt': 'file content'
});
});
afterEach(mock.restore);
it('allows a file to be read synchronously', function() {
var data = fs.readFileSync('path/to/file.txt');
assert.isTrue(Buffer.isBuffer(data));
assert.equal(String(data), 'file content');
});
it('fails for directory', function() {
assert.throws(function() {
fs.readFileSync('path/to');
});
});
it('fails for bad path', function() {
assert.throws(function() {
fs.readFileSync('path/to/bogus');
});
});
});
describe('fs.write(fd, buffer, offset, length, position, callback)', function() {
beforeEach(function() {
mock({
'path/to/file.txt': 'file content'
});
});
afterEach(mock.restore);
it('writes a buffer to a file', function(done) {
var fd = fs.openSync('path/new-file.txt', 'w');
var buffer = new Buffer('new file');
fs.write(fd, buffer, 0, buffer.length, null, function(err, written, buf) {
if (err) {
return done(err);
}
assert.equal(written, 8);
assert.equal(buf, buffer);
assert.equal(String(fs.readFileSync('path/new-file.txt')), 'new file');
done();
});
});
it('can write a portion of a buffer to a file', function(done) {
fs.open('path/new-file.txt', 'w', function(err, fd) {
if (err) {
return done(err);
}
var buffer = new Buffer('new file');
fs.write(fd, buffer, 1, 5, null, function(err2, written, buf) {
if (err2) {
return done(err2);
}
assert.equal(written, 5);
assert.equal(buf, buffer);
assert.equal(String(fs.readFileSync('path/new-file.txt')), 'ew fi');
done();
});
});
});
it('can append to a file', function(done) {
fs.open('path/to/file.txt', 'a', function(err, fd) {
if (err) {
return done(err);
}
var buffer = new Buffer(' more');
fs.write(fd, buffer, 0, 5, null, function(err2, written, buf) {
if (err2) {
return done(err2);
}
assert.equal(written, 5);
assert.equal(buf, buffer);
assert.equal(String(fs.readFileSync('path/to/file.txt')),
'file content more');
done();
});
});
});
it('fails if file not open for writing', function(done) {
fs.open('path/to/file.txt', 'r', function(err, fd) {
if (err) {
return done(err);
}
fs.write(fd, new Buffer('oops'), 0, 4, null, function(err2) {
assert.instanceOf(err2, Error);
done();
});
});
});
});
describe('fs.writeSync(fd, buffer, offset, length, position)', function() {
beforeEach(function() {
mock({
'path/to/file.txt': 'file content'
});
});
afterEach(mock.restore);
it('writes a buffer to a file', function() {
var buffer = new Buffer('new file');
var fd = fs.openSync('path/new-file.txt', 'w');
var written = fs.writeSync(fd, buffer, 0, buffer.length);
assert.equal(written, 8);
assert.equal(String(fs.readFileSync('path/new-file.txt')), 'new file');
});
it('can write a portion of a buffer to a file', function() {
var buffer = new Buffer('new file');
var fd = fs.openSync('path/new-file.txt', 'w');
var written = fs.writeSync(fd, buffer, 1, 5);
assert.equal(written, 5);
assert.equal(String(fs.readFileSync('path/new-file.txt')), 'ew fi');
});
it('can append to a file', function() {
var buffer = new Buffer(' more');
var fd = fs.openSync('path/to/file.txt', 'a');
var written = fs.writeSync(fd, buffer, 0, 5);
assert.equal(written, 5);
assert.equal(String(fs.readFileSync('path/to/file.txt')),
'file content more');
});
it('fails if file not open for writing', function() {
var fd = fs.openSync('path/to/file.txt', 'r');
assert.throws(function() {
fs.writeSync(fd, new Buffer('oops'), 0, 4);
});
});
});
describe('fs.write(fd, data[, position[, encoding]], callback)', function() {
beforeEach(function() {
mock({
'path/to/file.txt': 'file content'
});
});
afterEach(mock.restore);
it('writes a string to a file', function(done) {
fs.open('path/new-file.txt', 'w', function(err, fd) {
if (err) {
return done(err);
}
var string = 'new file';
fs.write(fd, string, null, 'utf-8', function(err