pax_global_header00006660000000000000000000000064135671336630014527gustar00rootroot0000000000000052 comment=7f281222dc50aadd895f761acbcba47da2233763 mock-fs-4.10.4/000077500000000000000000000000001356713366300131545ustar00rootroot00000000000000mock-fs-4.10.4/.gitignore000066400000000000000000000000251356713366300151410ustar00rootroot00000000000000/node_modules/ .idea mock-fs-4.10.4/.travis.yml000066400000000000000000000002551356713366300152670ustar00rootroot00000000000000os: - linux - windows - osx language: node_js node_js: - "6" - "8" - "10" - "12.9" # 12.10 introduced a breaking change on fs stat internal storage. - "12" mock-fs-4.10.4/benchmarks/000077500000000000000000000000001356713366300152715ustar00rootroot00000000000000mock-fs-4.10.4/benchmarks/read-integration-mock.js000066400000000000000000000007221356713366300220130ustar00rootroot00000000000000const assert = require('assert'); const fs = require('fs'); const mock = require('..'); /** * Timed test. This includes the mock setup and teardown as part of the overall * test time. * @param {function(Error)} done Callback. */ exports.test = function(done) { mock({ 'foo-mock.txt': 'foo' }); fs.readFile('foo-mock.txt', 'utf8', function(err, str) { assert.ifError(err); assert.equal(str, 'foo'); mock.restore(); done(); }); }; mock-fs-4.10.4/benchmarks/read-integration-real.js000066400000000000000000000013221356713366300220020ustar00rootroot00000000000000const assert = require('assert'); const fs = require('fs'); const path = require('path'); const rimraf = require('rimraf'); const tmpPath = '.tmp'; /** * Timed test. This includes the setup and teardown as part of the overall * test time. * @param {function(Error)} done Callback. */ exports.test = function(done) { fs.mkdir(tmpPath, function(mkdirErr) { assert.ifError(mkdirErr); const tmpFile = path.join(tmpPath, 'foo-real.txt'); fs.writeFile(tmpFile, 'foo', function(writeErr) { assert.ifError(writeErr); fs.readFile(tmpFile, 'utf8', function(readErr, str) { assert.ifError(readErr); assert.equal(str, 'foo'); rimraf(tmpPath, done); }); }); }); }; mock-fs-4.10.4/benchmarks/read-mock.js000066400000000000000000000010221356713366300174640ustar00rootroot00000000000000const assert = require('assert'); const fs = require('fs'); const mock = require('..'); /** * Test setup. Not timed. */ exports.beforeEach = function() { mock({ 'foo-mock.txt': 'foo' }); }; /** * Timed test. * @param {function(Error)} done Callback. */ exports.test = function(done) { fs.readFile('foo-mock.txt', 'utf8', function(err, str) { assert.ifError(err); assert.equal(str, 'foo'); done(); }); }; /** * Test teardown. Not timed. */ exports.afterEach = function() { mock.restore(); }; mock-fs-4.10.4/benchmarks/read-real.js000066400000000000000000000014711356713366300174660ustar00rootroot00000000000000const assert = require('assert'); const fs = require('fs'); const path = require('path'); const rimraf = require('rimraf'); const tmpPath = '.tmp'; /** * Test setup. Not timed. * @param {function(Error)} done Callback. */ exports.beforeEach = function(done) { fs.mkdir(tmpPath, function(err) { if (err) { return done(err); } fs.writeFile(path.join(tmpPath, 'foo-real.txt'), 'foo', done); }); }; /** * Timed test. * @param {function(Error)} done Callback. */ exports.test = function(done) { fs.readFile(path.join(tmpPath, 'foo-real.txt'), 'utf8', function(err, str) { assert.ifError(err); assert.equal(str, 'foo'); done(); }); }; /** * Test teardown. Not timed. * @param {function(Error)} done Callback. */ exports.afterEach = function(done) { rimraf(tmpPath, done); }; mock-fs-4.10.4/benchmarks/write-integration-mock.js000066400000000000000000000006201356713366300222270ustar00rootroot00000000000000const assert = require('assert'); const fs = require('fs'); const mock = require('..'); /** * Timed test. This includes the mock setup and teardown as part of the overall * test time. * @param {function(Error)} done Callback. */ exports.test = function(done) { mock(); fs.writeFile('foo-mock.txt', 'foo', function(err) { assert.ifError(err); mock.restore(); done(); }); }; mock-fs-4.10.4/benchmarks/write-integration-real.js000066400000000000000000000010401356713366300222160ustar00rootroot00000000000000const assert = require('assert'); const fs = require('fs'); const path = require('path'); const rimraf = require('rimraf'); const tmpPath = '.tmp'; /** * Timed test. This includes the setup and teardown as part of the overall * test time. * @param {function(Error)} done Callback. */ exports.test = function(done) { fs.mkdir(tmpPath, function(mkdirErr) { assert.ifError(mkdirErr); fs.writeFile(path.join(tmpPath, 'foo-real.txt'), 'foo', function(err) { assert.ifError(err); rimraf(tmpPath, done); }); }); }; mock-fs-4.10.4/benchmarks/write-mock.js000066400000000000000000000005721356713366300177140ustar00rootroot00000000000000const fs = require('fs'); const mock = require('..'); /** * Test setup. Not timed. */ exports.beforeEach = function() { mock(); }; /** * Timed test. * @param {function(Error)} done Callback. */ exports.test = function(done) { fs.writeFile('foo-mock.txt', 'foo', done); }; /** * Test teardown. Not timed. */ exports.afterEach = function() { mock.restore(); }; mock-fs-4.10.4/benchmarks/write-real.js000066400000000000000000000011011356713366300176730ustar00rootroot00000000000000const fs = require('fs'); const path = require('path'); const rimraf = require('rimraf'); const tmpPath = '.tmp'; /** * Test setup. Not timed. * @param {function(Error)} done Callback. */ exports.beforeEach = function(done) { fs.mkdir(tmpPath, done); }; /** * Timed test. * @param {function(Error)} done Callback. */ exports.test = function(done) { fs.writeFile(path.join(tmpPath, 'foo-real.txt'), 'foo', done); }; /** * Test teardown. Not timed. * @param {function(Error)} done Callback. */ exports.afterEach = function(done) { rimraf(tmpPath, done); }; mock-fs-4.10.4/changelog.md000066400000000000000000000226471356713366300154400ustar00rootroot00000000000000# Change Log ## 4.10.4 * Fix maybeCallback return (thanks @3cp, see [#281][#281]) ## 4.10.3 * Fix bad promise rejection on some fs.promises methods (thanks @3cp, see [#279][#279]) ## 4.10.2 * Fix timestamps for Node > 12.10 (thanks @3cp, see [#277][#277]) ## 4.10.1 * Fix for `fs.mkdir` with the `recursive` option on existing directories (thanks @3cp, see [#271][#271]) ## 4.10.0 * Support the `recursive` option for `fs.mkdir` (thanks @3cp, see [#268][#268]) ## 4.9.0 * Improve `readFile` support for Node 10+ (thanks @huochunpeng, see [#265][#265]) * Updated dev dependencies (see [#267][#267]) ## 4.8.0 * Fix compatibility issues with Node 10 and 11 (thanks @huochunpeng [#260][#260]) * Support experimental `fs.promises` (thanks @huochunpeng [#260][#260]) ## 4.7.0 * Fix for readdir on Node 10.10 (thanks @maxwellgerber [#251][#251]) * Fix for reading and writing using Uint8Array (thanks @maxwellgerber [#249][#249]) * Document how to properly restore the fs with Jest snapshot testing (thanks @tricoder42 [#247][#247]) * More informative error when opening a directory (thanks @maxwellgerber [#242][#242]) ## 4.6.0 Note that the mocked fs.createReadStream and fs.createWriteStream are not working properly with Node 10.5+. * Implement binding.copyFile ([#243][#243]) * Stat fixes for Node 10.5 (thanks @tomhughes, see [#241][#241]) ## 4.5.0 * Updates for Node 10 compatibility ([#237][#237]) * Throw ENOENT in readlink when item is missing (thanks @deployable, see [#232][#232]) * Add path to errors when it exists (thanks @deployable, see [#230][#230]) ## 4.4.2 * Throw if item content is invalid in config (thanks @mutantcornholio, see [#221][#221]) * Use const in readme (thanks @denar90, see [#222][#222]) ## 4.4.1 * Document that tests are run on Node 8.x as well. ## 4.4.0 * Fix stat issue with Node 8 (thanks @AGrzes, see [#209][#209]) * Make code prettier (see [#210][#210]) ## 4.3.0 * Add support for fs.mkdtemp() and fs.mkdtempSync (see [#207][#207]) ## 4.2.0 * Update fs.stat(), fs.lstat(), and fs.fstat() for Node 7.7+ (thanks @not-an-aardvark, see [#198][#198]) ## 4.1.0 * Correctly follow a symlink chain in `binding.open()` (thanks @vlindhol, see [#195][#195]) ## 4.0.0 In earlier versions of `mock-fs`, a monkey-patched version of the `fs` module was used to provide an in-memory filesystem. With each major release of Node, the `mock-fs` package needed to include a modified copy of the `fs` module. With the `mock-fs@4` release, this package no longer includes a modified copy of the `fs` module. Instead, this package overrides `process.binding('fs')`. While this is not part of Node's stable API, it has proven to be a more stable interface than the `fs` module itself (based on experience implementing it with Node 0.8 through 7.0). Upgrading from 3.x to 4.0 should be straightforward for most applications. There are several breaking changes that may be restored in future releases: * The `mock.fs()` function has been removed. * The object created by `fs.stat()` and friends is no longer an instance of `fs.Stats` (though it behaves as one). * Lazy `require()` calls do not work consistently. Detailed changes: * Only override `process.binding('fs')` ([#182][#182]) * Expose the root of the mocked filesystem (thanks @ciaranj, see [#194][#194]) ## 3.12.1 * Revert the require cache clearing behavior ([#181][#181]). ## 3.12.0 * Support for Node 7.x (thanks @goliney, see [#174][#174]). * Remove calls to `printDeprecation` ([#175][#175]). * Break early when checking version (thanks @isiahmeadows, see [#157][#157]). * Add a note about restoring `fs` (thanks @matheuss, see [#147][#147]). * Clear the require cache before overriding fs functions ([#141][#141]) ## 3.11.0 * Make `require()` calls use the real filesystem ([#139][#139]). * Reduce the manual `fs` module patching ([#140][#140]). ## 3.10.0 * Fixes for Node 6.3 ([#138][#138]). * Fix permissions issues on directories (thanks @as3richa, see [#105][#105]). ## 3.9.0 * Support for Node 6.x (thanks @tmcw, see [#107][#107]). ## 3.8.0 * Implement `binding.writeBuffers()` (see [#94][#94]). ## 3.7.0 * Add support for `fs.access()` and `fs.accessSync()` (thanks @shyiko, see [#78][#78] and [#80][#80]). ## 3.6.0 * Add `createCwd` and `createTmp` options to control the creation of `process.cwd()` and `os.tmpdir()` directories in the mocked filesystem (see [#72][#72]). * Update Travis and AppVeyor configurations (see [#73][#73]) * Remove unused dev dependency (see [#75][#75]) ## 3.5.0 * Support for Node 5.x (thanks @tmcw, see [#69][#69]). ## 3.4.0 * Support for Node 4.x (thanks @AlexMeah, see [#65][#65]). ## 3.3.0 * Traverse symlinks recursively (thanks @caitp, see [#57][#57]). * Upgrade to rewire@2.3.4 (thanks @mbarlock, see [#60][#60]). ## 3.2.0 * Support for io.js 3.0 (thanks @JustBlackBird, see [#61][#61]). ## 3.1.0 * Follow symlinks in `readdir()` and `readdirSync()` (thanks @caitp, see [#56][#56]). ## 3.0.0 * Override `process.cwd()` and `process.chdir()` to work with mocked filesystem (thanks @timkendrick, see [#41][#41]). * Add note about known incompatibilities (thanks @psalaets, see [#45][#45]). ## 2.7.0 * Support for io.js 2.0 (thanks @jwilsson, see [#38][#38]). ## 2.6.0 * Add `birthtime` to `Stats` objects (thanks @meandmycode, see [#33][#33]). ## 2.5.0 * Support for io.js 1.1 (thanks @andrewblond, see [#21][#21]). * Testing on Windows with AppVeyor (thanks @andrewblond, see [#22][#22]). ## 2.4.0 * Support for Node 0.12 (thanks @mlegenhausen, see [#18][#18]). ## 2.3.1 * Preserve arity of callbacks (see [#11][#11]). ## 2.3.0 * Fixes for Node 0.11.13 (see [#9][#9]). ## 2.2.0 * Respect file mode on POSIX-compliant systems (see [#7][#7]). * Add benchmarks comparing mock-fs and fs modules (see [#6][#6]). ## 2.1.2 * Added more complete license text. * Test on Node 0.9 and 0.11 in addition to 0.8 and 0.10. ## 2.1.1 * Added this changelog. * Removed unused gruntfile.js. ## 2.1.0 * Directory mtime is now updated when items are added, removed, or modified ([#2][#2]). * Fixed several issues on Windows (see [#3][#3]). One issue remains on Windows with Node 0.8 (see [#4][#4]). * Swapped out Grunt with a single script to run tasks (see [#5][#5]). ## 2.0.0 * Simplified API (see [#1][#1]). [#1]: https://github.com/tschaub/mock-fs/pull/1 [#2]: https://github.com/tschaub/mock-fs/pull/2 [#3]: https://github.com/tschaub/mock-fs/pull/3 [#4]: https://github.com/tschaub/mock-fs/issues/4 [#5]: https://github.com/tschaub/mock-fs/pull/5 [#6]: https://github.com/tschaub/mock-fs/pull/6 [#7]: https://github.com/tschaub/mock-fs/pull/7 [#9]: https://github.com/tschaub/mock-fs/issues/9 [#11]: https://github.com/tschaub/mock-fs/pull/11 [#18]: https://github.com/tschaub/mock-fs/pull/18 [#21]: https://github.com/tschaub/mock-fs/pull/21 [#22]: https://github.com/tschaub/mock-fs/pull/22 [#33]: https://github.com/tschaub/mock-fs/pull/33 [#38]: https://github.com/tschaub/mock-fs/pull/38 [#41]: https://github.com/tschaub/mock-fs/pull/41 [#45]: https://github.com/tschaub/mock-fs/pull/45 [#56]: https://github.com/tschaub/mock-fs/pull/56 [#61]: https://github.com/tschaub/mock-fs/pull/61 [#60]: https://github.com/tschaub/mock-fs/pull/60 [#57]: https://github.com/tschaub/mock-fs/pull/57 [#65]: https://github.com/tschaub/mock-fs/pull/65 [#69]: https://github.com/tschaub/mock-fs/pull/69 [#72]: https://github.com/tschaub/mock-fs/pull/72 [#73]: https://github.com/tschaub/mock-fs/pull/73 [#75]: https://github.com/tschaub/mock-fs/pull/75 [#78]: https://github.com/tschaub/mock-fs/pull/78 [#80]: https://github.com/tschaub/mock-fs/pull/80 [#94]: https://github.com/tschaub/mock-fs/pull/94 [#107]: https://github.com/tschaub/mock-fs/pull/107 [#105]: https://github.com/tschaub/mock-fs/pull/105 [#138]: https://github.com/tschaub/mock-fs/pull/138 [#139]: https://github.com/tschaub/mock-fs/pull/139 [#140]: https://github.com/tschaub/mock-fs/pull/140 [#141]: https://github.com/tschaub/mock-fs/pull/141 [#147]: https://github.com/tschaub/mock-fs/pull/147 [#157]: https://github.com/tschaub/mock-fs/pull/157 [#174]: https://github.com/tschaub/mock-fs/pull/174 [#175]: https://github.com/tschaub/mock-fs/pull/175 [#181]: https://github.com/tschaub/mock-fs/pull/181 [#182]: https://github.com/tschaub/mock-fs/pull/182 [#194]: https://github.com/tschaub/mock-fs/pull/194 [#195]: https://github.com/tschaub/mock-fs/pull/195 [#198]: https://github.com/tschaub/mock-fs/pull/198 [#207]: https://github.com/tschaub/mock-fs/pull/207 [#209]: https://github.com/tschaub/mock-fs/pull/209 [#210]: https://github.com/tschaub/mock-fs/pull/210 [#221]: https://github.com/tschaub/mock-fs/pull/221 [#222]: https://github.com/tschaub/mock-fs/pull/222 [#230]: https://github.com/tschaub/mock-fs/pull/230 [#232]: https://github.com/tschaub/mock-fs/pull/232 [#237]: https://github.com/tschaub/mock-fs/pull/237 [#243]: https://github.com/tschaub/mock-fs/pull/243 [#242]: https://github.com/tschaub/mock-fs/pull/242 [#247]: https://github.com/tschaub/mock-fs/pull/247 [#249]: https://github.com/tschaub/mock-fs/pull/249 [#251]: https://github.com/tschaub/mock-fs/pull/251 [#260]: https://github.com/tschaub/mock-fs/pull/260 [#265]: https://github.com/tschaub/mock-fs/pull/265 [#267]: https://github.com/tschaub/mock-fs/pull/267 [#268]: https://github.com/tschaub/mock-fs/pull/268 [#271]: https://github.com/tschaub/mock-fs/pull/271 [#277]: https://github.com/tschaub/mock-fs/pull/277 [#279]: https://github.com/tschaub/mock-fs/pull/279 [#281]: https://github.com/tschaub/mock-fs/pull/281 mock-fs-4.10.4/lib/000077500000000000000000000000001356713366300137225ustar00rootroot00000000000000mock-fs-4.10.4/lib/binding.js000066400000000000000000001273121356713366300157000ustar00rootroot00000000000000'use strict'; const path = require('path'); const File = require('./file'); const FileDescriptor = require('./descriptor'); const Directory = require('./directory'); const SymbolicLink = require('./symlink'); const FSError = require('./error'); const constants = require('constants'); const getPathParts = require('./filesystem').getPathParts; const bufferFrom = require('./buffer').from; const bufferAlloc = require('./buffer').alloc; /** Workaround for optimizations in node 8+ */ const fsBinding = process.binding('fs'); const kUsePromises = fsBinding.kUsePromises; let statValues; if (fsBinding.statValues) { statValues = fsBinding.statValues; // node 10+ } else if (fsBinding.getStatValues) { statValues = fsBinding.getStatValues(); // node 8 } else { statValues = []; } // nodejs v6,8,10 and v12 before v12.10.0 has length 28 // nodejs v12.10.0+ has length 36 const statContainsNs = statValues.length > 28; /** Introduction of BigUint64Array in 10.5 */ let BigUint64Array; if (global.BigUint64Array) { BigUint64Array = global.BigUint64Array; } else { BigUint64Array = function() {}; } const MAX_LINKS = 50; /** * Call the provided function and either return the result or call the callback * with it (depending on if a callback is provided). * @param {function()} callback Optional callback. * @param {Object} ctx Context object (optional), only for nodejs v10+. * @param {Object} thisArg This argument for the following function. * @param {function()} func Function to call. * @return {*} Return (if callback is not provided). */ function maybeCallback(callback, ctx, thisArg, func) { let err = null; let val; if (kUsePromises && callback === kUsePromises) { // support nodejs v10+ fs.promises try { val = func.call(thisArg); } catch (e) { err = e; } return new Promise(function(resolve, reject) { process.nextTick(function() { if (err) { reject(err); } else { resolve(val); } }); }); } else if (callback && typeof callback === 'function') { try { val = func.call(thisArg); } catch (e) { err = e; } process.nextTick(function() { if (val === undefined) { callback(err); } else { callback(err, val); } }); } else if (ctx && typeof ctx === 'object') { try { return func.call(thisArg); } catch (e) { // default to errno for UNKNOWN ctx.code = e.code || 'UNKNOWN'; ctx.errno = e.errno || FSError.codes.UNKNOWN.errno; } } else { return func.call(thisArg); } } /** * set syscall property on context object, only for nodejs v10+. * @param {Object} ctx Context object (optional), only for nodejs v10+. * @param {String} syscall Name of syscall. */ function markSyscall(ctx, syscall) { if (ctx && typeof ctx === 'object') { ctx.syscall = syscall; } } /** * Handle FSReqWrap oncomplete. * @param {Function} callback The callback. * @return {Function} The normalized callback. */ function normalizeCallback(callback) { if (callback && typeof callback.oncomplete === 'function') { // Unpack callback from FSReqWrap callback = callback.oncomplete.bind(callback); } return callback; } /** * Handle stat optimizations introduced in Node 8. * See https://github.com/nodejs/node/pull/11665. * @param {Function} callback The callback. * @return {Function} The wrapped callback. */ function wrapStatsCallback(callback) { if (callback && typeof callback.oncomplete === 'function') { // Unpack callback from FSReqWrap callback = callback.oncomplete.bind(callback); } if (typeof callback === 'function') { return function(err, stats) { if (stats) { fillStatsArray(stats, statValues); } callback.apply(this, arguments); }; } else { return callback; } } function notImplemented() { throw new Error('Method not implemented'); } /** * Create a new stats object. * @param {Object} config Stats properties. * @constructor */ function Stats(config) { for (const key in config) { this[key] = config[key]; } // node 10 expects an array internally // see https://github.com/nodejs/node/pull/19714 fillStatsArray(config, this); } /** * Check if mode indicates property. * @param {number} property Property to check. * @return {boolean} Property matches mode. */ Stats.prototype._checkModeProperty = function(property) { return (this.mode & constants.S_IFMT) === property; }; /** * @return {Boolean} Is a directory. */ Stats.prototype.isDirectory = function() { return this._checkModeProperty(constants.S_IFDIR); }; /** * @return {Boolean} Is a regular file. */ Stats.prototype.isFile = function() { return this._checkModeProperty(constants.S_IFREG); }; /** * @return {Boolean} Is a block device. */ Stats.prototype.isBlockDevice = function() { return this._checkModeProperty(constants.S_IFBLK); }; /** * @return {Boolean} Is a character device. */ Stats.prototype.isCharacterDevice = function() { return this._checkModeProperty(constants.S_IFCHR); }; /** * @return {Boolean} Is a symbolic link. */ Stats.prototype.isSymbolicLink = function() { return this._checkModeProperty(constants.S_IFLNK); }; /** * @return {Boolean} Is a named pipe. */ Stats.prototype.isFIFO = function() { return this._checkModeProperty(constants.S_IFIFO); }; /** * @return {Boolean} Is a socket. */ Stats.prototype.isSocket = function() { return this._checkModeProperty(constants.S_IFSOCK); }; // I don't know exactly what is going on. // If _openFiles is a property of binding instance, there is a strange // bug in nodejs v10+ that something cleaned up this._openFiles from // nowhere. It happens after second mockfs(), after first mockfs()+restore(). // So I moved _openFiles to a private var. The other two vars (_system, // _counter) do not hurt. // This fixed https://github.com/tschaub/mock-fs/issues/254 // But I did not dig deep enough to understand what exactly happened. let _system; let _openFiles = {}; let _counter = 0; /** * Create a new binding with the given file system. * @param {FileSystem} system Mock file system. * @constructor */ function Binding(system) { /** * Mock file system. * @type {FileSystem} */ _system = system; /** * Stats constructor. * @type {function} */ this.Stats = Stats; /** * Lookup of open files. * @type {Object.} */ _openFiles = {}; /** * Counter for file descriptors. * @type {number} */ _counter = 0; } /** * Get the file system underlying this binding. * @return {FileSystem} The underlying file system. */ Binding.prototype.getSystem = function() { return _system; }; /** * Reset the file system underlying this binding. * @param {FileSystem} system The new file system. */ Binding.prototype.setSystem = function(system) { _system = system; }; /** * Get a file descriptor. * @param {number} fd File descriptor identifier. * @return {FileDescriptor} File descriptor. */ function getDescriptorById(fd) { if (!_openFiles.hasOwnProperty(fd)) { throw new FSError('EBADF'); } return _openFiles[fd]; } /** * Keep track of a file descriptor as open. * @param {FileDescriptor} descriptor The file descriptor. * @return {number} Identifier for file descriptor. */ function trackDescriptor(descriptor) { const fd = ++_counter; _openFiles[fd] = descriptor; return fd; } /** * Stop tracking a file descriptor as open. * @param {number} fd Identifier for file descriptor. */ function untrackDescriptorById(fd) { if (!_openFiles.hasOwnProperty(fd)) { throw new FSError('EBADF'); } delete _openFiles[fd]; } /** * Resolve the canonicalized absolute pathname. * @param {string|Buffer} filepath The file path. * @param {string} encoding The encoding for the return. * @param {Object} ctx Context object (optional), only for nodejs v10+. * @return {string|Buffer} The real path. */ Binding.prototype.realpath = function(filepath, encoding, callback, ctx) { markSyscall(ctx, 'realpath'); return maybeCallback(normalizeCallback(callback), ctx, this, function() { let realPath; if (Buffer.isBuffer(filepath)) { filepath = filepath.toString(); } const resolved = path.resolve(filepath); const parts = getPathParts(resolved); let item = _system.getRoot(); let itemPath = '/'; let name, i, ii; for (i = 0, ii = parts.length; i < ii; ++i) { name = parts[i]; while (item instanceof SymbolicLink) { itemPath = path.resolve(path.dirname(itemPath), item.getPath()); item = _system.getItem(itemPath); } if (!item) { throw new FSError('ENOENT', filepath); } if (item instanceof Directory) { itemPath = path.resolve(itemPath, name); item = item.getItem(name); } else { throw new FSError('ENOTDIR', filepath); } } if (item) { while (item instanceof SymbolicLink) { itemPath = path.resolve(path.dirname(itemPath), item.getPath()); item = _system.getItem(itemPath); } realPath = itemPath; } else { throw new FSError('ENOENT', filepath); } if (process.platform === 'win32' && realPath.startsWith('\\\\?\\')) { // Remove win32 file namespace prefix \\?\ realPath = realPath.slice(4); } if (encoding === 'buffer') { realPath = bufferFrom(realPath); } return realPath; }); }; /** * Fill a Float64Array with stat information * This is based on the internal FillStatsArray function in Node. * https://github.com/nodejs/node/blob/4e05952a8a75af6df625415db612d3a9a1322682/src/node_file.cc#L533 * @param {Object} stats An object with file stats * @param {Float64Array} statValues A Float64Array where stat values should be inserted * @returns {void} */ function fillStatsArray(stats, statValues) { statValues[0] = stats.dev; statValues[1] = stats.mode; statValues[2] = stats.nlink; statValues[3] = stats.uid; statValues[4] = stats.gid; statValues[5] = stats.rdev; statValues[6] = stats.blksize; statValues[7] = stats.ino; statValues[8] = stats.size; statValues[9] = stats.blocks; if (statContainsNs) { // nodejs v12.10.0+ // This is based on the internal FillStatsArray function in Node. // https://github.com/nodejs/node/blob/3a2e75d9a5c31d20e429d505b82dd182e33f459a/src/node_file.h#L153-L187 statValues[10] = Math.floor(stats.atimeMs / 1000); statValues[11] = (stats.atimeMs % 1000) * 1000000; statValues[12] = Math.floor(stats.mtimeMs / 1000); statValues[13] = (stats.mtimeMs % 1000) * 1000000; statValues[14] = Math.floor(stats.ctimeMs / 1000); statValues[15] = (stats.ctimeMs % 1000) * 1000000; statValues[16] = Math.floor(stats.birthtimeMs / 1000); statValues[17] = (stats.birthtimeMs % 1000) * 1000000; } else { // nodejs before v12.10.0 // This is based on the internal FillStatsArray function in Node. // https://github.com/nodejs/node/blob/4e05952a8a75af6df625415db612d3a9a1322682/src/node_file.cc#L533 statValues[10] = stats.atimeMs; statValues[11] = stats.mtimeMs; statValues[12] = stats.ctimeMs; statValues[13] = stats.birthtimeMs; } } /** * Stat an item. * @param {string} filepath Path. * @param {function(Error, Stats)|Float64Array|BigUint64Array} callback Callback (optional). In Node 7.7.0+ this will be a Float64Array * that should be filled with stat values. * @param {Object} ctx Context object (optional), only for nodejs v10+. * @return {Stats|undefined} Stats or undefined (if sync). */ Binding.prototype.stat = function(filepath, options, callback, ctx) { // this seems wound not happen in nodejs v10+ if (arguments.length < 3) { callback = options; options = {}; } markSyscall(ctx, 'stat'); return maybeCallback(wrapStatsCallback(callback), ctx, this, function() { let item = _system.getItem(filepath); if (item instanceof SymbolicLink) { item = _system.getItem( path.resolve(path.dirname(filepath), item.getPath()) ); } if (!item) { throw new FSError('ENOENT', filepath); } const stats = item.getStats(); // In Node 7.7.0+, binding.stat accepts a Float64Array as the second argument, // which should be filled with stat values. // In prior versions of Node, binding.stat simply returns a Stats instance. if ( callback instanceof Float64Array || callback instanceof BigUint64Array ) { fillStatsArray(stats, callback); } else { fillStatsArray(stats, statValues); return new Stats(stats); } }); }; /** * Stat an item. * @param {number} fd File descriptor. * @param {function(Error, Stats)|Float64Array|BigUint64Array} callback Callback (optional). In Node 7.7.0+ this will be a Float64Array * that should be filled with stat values. * @param {Object} ctx Context object (optional), only for nodejs v10+. * @return {Stats|undefined} Stats or undefined (if sync). */ Binding.prototype.fstat = function(fd, options, callback, ctx) { if (arguments.length < 3) { callback = options; options = {}; } markSyscall(ctx, 'fstat'); return maybeCallback(wrapStatsCallback(callback), ctx, this, function() { const descriptor = getDescriptorById(fd); const item = descriptor.getItem(); const stats = item.getStats(); // In Node 7.7.0+, binding.stat accepts a Float64Array as the second argument, // which should be filled with stat values. // In prior versions of Node, binding.stat simply returns a Stats instance. if ( callback instanceof Float64Array || callback instanceof BigUint64Array ) { fillStatsArray(stats, callback); } else { fillStatsArray(stats, statValues); return new Stats(stats); } }); }; /** * Close a file descriptor. * @param {number} fd File descriptor. * @param {function(Error)} callback Callback (optional). * @param {Object} ctx Context object (optional), only for nodejs v10+. */ Binding.prototype.close = function(fd, callback, ctx) { markSyscall(ctx, 'close'); return maybeCallback(normalizeCallback(callback), ctx, this, function() { untrackDescriptorById(fd); }); }; /** * Open and possibly create a file. * @param {string} pathname File path. * @param {number} flags Flags. * @param {number} mode Mode. * @param {function(Error, string)} callback Callback (optional). * @param {Object} ctx Context object (optional), only for nodejs v10+. * @return {string} File descriptor (if sync). */ Binding.prototype.open = function(pathname, flags, mode, callback, ctx) { markSyscall(ctx, 'open'); return maybeCallback(normalizeCallback(callback), ctx, this, function() { const descriptor = new FileDescriptor(flags); let item = _system.getItem(pathname); while (item instanceof SymbolicLink) { item = _system.getItem( path.resolve(path.dirname(pathname), item.getPath()) ); } if (descriptor.isExclusive() && item) { throw new FSError('EEXIST', pathname); } if (descriptor.isCreate() && !item) { const parent = _system.getItem(path.dirname(pathname)); if (!parent) { throw new FSError('ENOENT', pathname); } if (!(parent instanceof Directory)) { throw new FSError('ENOTDIR', pathname); } item = new File(); if (mode) { item.setMode(mode); } parent.addItem(path.basename(pathname), item); } if (descriptor.isRead()) { if (!item) { throw new FSError('ENOENT', pathname); } if (!item.canRead()) { throw new FSError('EACCES', pathname); } } if (descriptor.isWrite() && !item.canWrite()) { throw new FSError('EACCES', pathname); } if ( item instanceof Directory && (descriptor.isTruncate() || descriptor.isAppend()) ) { throw new FSError('EISDIR', pathname); } if (descriptor.isTruncate()) { if (!(item instanceof File)) { throw new FSError('EBADF'); } item.setContent(''); } if (descriptor.isTruncate() || descriptor.isAppend()) { descriptor.setPosition(item.getContent().length); } descriptor.setItem(item); return trackDescriptor(descriptor); }); }; /** * Open a file handler. A new api in nodejs v10+ for fs.promises * @param {string} pathname File path. * @param {number} flags Flags. * @param {number} mode Mode. * @param {function} callback Callback (optional), expecting kUsePromises in nodejs v10+. */ Binding.prototype.openFileHandle = function(pathname, flags, mode, callback) { const self = this; return this.open(pathname, flags, mode, kUsePromises).then(function(fd) { // nodejs v10+ fs.promises FileHandler constructor only ask these three properties. return { getAsyncId: notImplemented, fd: fd, close: function() { return self.close(fd, kUsePromises); } }; }); }; /** * Read from a file descriptor. * @param {string} fd File descriptor. * @param {Buffer} buffer Buffer that the contents will be written to. * @param {number} offset Offset in the buffer to start writing to. * @param {number} length Number of bytes to read. * @param {?number} position Where to begin reading in the file. If null, * data will be read from the current file position. * @param {function(Error, number, Buffer)} callback Callback (optional) called * with any error, number of bytes read, and the buffer. * @param {Object} ctx Context object (optional), only for nodejs v10+. * @return {number} Number of bytes read (if sync). */ Binding.prototype.read = function( fd, buffer, offset, length, position, callback, ctx ) { markSyscall(ctx, 'read'); return maybeCallback(normalizeCallback(callback), ctx, this, function() { const descriptor = getDescriptorById(fd); if (!descriptor.isRead()) { throw new FSError('EBADF'); } const file = descriptor.getItem(); if (!(file instanceof File)) { // deleted or not a regular file throw new FSError('EBADF'); } if (typeof position !== 'number' || position < 0) { position = descriptor.getPosition(); } const content = file.getContent(); const start = Math.min(position, content.length); const end = Math.min(position + length, content.length); const read = start < end ? content.copy(buffer, offset, start, end) : 0; descriptor.setPosition(position + read); return read; }); }; /** * Write to a file descriptor given a buffer. * @param {string} src Source file. * @param {string} dest Destination file. * @param {number} flags Modifiers for copy operation. * @param {function(Error)} callback Callback (optional) called * with any error. * @param {Object} ctx Context object (optional), only for nodejs v10+. */ Binding.prototype.copyFile = function(src, dest, flags, callback, ctx) { markSyscall(ctx, 'copyfile'); return maybeCallback(normalizeCallback(callback), ctx, this, function() { const srcFd = this.open(src, constants.O_RDONLY); try { const srcDescriptor = getDescriptorById(srcFd); if (!srcDescriptor.isRead()) { throw new FSError('EBADF'); } const srcFile = srcDescriptor.getItem(); if (!(srcFile instanceof File)) { throw new FSError('EBADF'); } const srcContent = srcFile.getContent(); let destFlags = constants.O_WRONLY | constants.O_CREAT | constants.O_TRUNC; if ((flags & constants.COPYFILE_EXCL) === constants.COPYFILE_EXCL) { destFlags |= constants.O_EXCL; } const destFd = this.open(dest, destFlags); try { this.write(destFd, srcContent, 0, srcContent.length, 0); } finally { this.close(destFd); } } finally { this.close(srcFd); } }); }; /** * Write to a file descriptor given a buffer. * @param {string} fd File descriptor. * @param {Array} buffers Array of buffers with contents to write. * @param {?number} position Where to begin writing in the file. If null, * data will be written to the current file position. * @param {function(Error, number, Buffer)} callback Callback (optional) called * with any error, number of bytes written, and the buffer. * @param {Object} ctx Context object (optional), only for nodejs v10+. * @return {number} Number of bytes written (if sync). */ Binding.prototype.writeBuffers = function( fd, buffers, position, callback, ctx ) { markSyscall(ctx, 'write'); return maybeCallback(normalizeCallback(callback), ctx, this, function() { const descriptor = getDescriptorById(fd); if (!descriptor.isWrite()) { throw new FSError('EBADF'); } const file = descriptor.getItem(); if (!(file instanceof File)) { // not a regular file throw new FSError('EBADF'); } if (typeof position !== 'number' || position < 0) { position = descriptor.getPosition(); } let content = file.getContent(); const newContent = Buffer.concat(buffers); const newLength = position + newContent.length; if (content.length < newLength) { const tempContent = bufferAlloc(newLength); content.copy(tempContent); content = tempContent; } const written = newContent.copy(content, position); file.setContent(content); descriptor.setPosition(newLength); return written; }); }; /** * Write to a file descriptor given a buffer. * @param {string} fd File descriptor. * @param {Buffer} buffer Buffer with contents to write. * @param {number} offset Offset in the buffer to start writing from. * @param {number} length Number of bytes to write. * @param {?number} position Where to begin writing in the file. If null, * data will be written to the current file position. * @param {function(Error, number, Buffer)} callback Callback (optional) called * with any error, number of bytes written, and the buffer. * @param {Object} ctx Context object (optional), only for nodejs v10+. * @return {number} Number of bytes written (if sync). */ Binding.prototype.writeBuffer = function( fd, buffer, offset, length, position, callback, ctx ) { markSyscall(ctx, 'write'); return maybeCallback(normalizeCallback(callback), ctx, this, function() { const descriptor = getDescriptorById(fd); if (!descriptor.isWrite()) { throw new FSError('EBADF'); } const file = descriptor.getItem(); if (!(file instanceof File)) { // not a regular file throw new FSError('EBADF'); } if (typeof position !== 'number' || position < 0) { position = descriptor.getPosition(); } let content = file.getContent(); const newLength = position + length; if (content.length < newLength) { const newContent = bufferAlloc(newLength); content.copy(newContent); content = newContent; } const sourceEnd = Math.min(offset + length, buffer.length); const written = bufferFrom(buffer).copy( content, position, offset, sourceEnd ); file.setContent(content); descriptor.setPosition(newLength); return written; }); }; /** * Alias for writeBuffer (used in Node <= 0.10). * @param {string} fd File descriptor. * @param {Buffer} buffer Buffer with contents to write. * @param {number} offset Offset in the buffer to start writing from. * @param {number} length Number of bytes to write. * @param {?number} position Where to begin writing in the file. If null, * data will be written to the current file position. * @param {function(Error, number, Buffer)} callback Callback (optional) called * with any error, number of bytes written, and the buffer. * @param {Object} ctx Context object (optional), only for nodejs v10+. * @return {number} Number of bytes written (if sync). */ Binding.prototype.write = Binding.prototype.writeBuffer; /** * Write to a file descriptor given a string. * @param {string} fd File descriptor. * @param {string} string String with contents to write. * @param {number} position Where to begin writing in the file. If null, * data will be written to the current file position. * @param {string} encoding String encoding. * @param {function(Error, number, string)} callback Callback (optional) called * with any error, number of bytes written, and the string. * @return {number} Number of bytes written (if sync). */ Binding.prototype.writeString = function( fd, string, position, encoding, callback, ctx ) { markSyscall(ctx, 'write'); const buffer = bufferFrom(string, encoding); let wrapper; if (callback && callback !== kUsePromises) { if (callback.oncomplete) { callback = callback.oncomplete.bind(callback); } wrapper = function(err, written, returned) { callback(err, written, returned && string); }; } return this.writeBuffer(fd, buffer, 0, string.length, position, wrapper, ctx); }; /** * Rename a file. * @param {string} oldPath Old pathname. * @param {string} newPath New pathname. * @param {function(Error)} callback Callback (optional). * @param {Object} ctx Context object (optional), only for nodejs v10+. * @return {undefined} */ Binding.prototype.rename = function(oldPath, newPath, callback, ctx) { markSyscall(ctx, 'rename'); return maybeCallback(normalizeCallback(callback), ctx, this, function() { const oldItem = _system.getItem(oldPath); if (!oldItem) { throw new FSError('ENOENT', oldPath); } const oldParent = _system.getItem(path.dirname(oldPath)); const oldName = path.basename(oldPath); const newItem = _system.getItem(newPath); const newParent = _system.getItem(path.dirname(newPath)); const newName = path.basename(newPath); if (newItem) { // make sure they are the same type if (oldItem instanceof File) { if (newItem instanceof Directory) { throw new FSError('EISDIR', newPath); } } else if (oldItem instanceof Directory) { if (!(newItem instanceof Directory)) { throw new FSError('ENOTDIR', newPath); } if (newItem.list().length > 0) { throw new FSError('ENOTEMPTY', newPath); } } newParent.removeItem(newName); } else { if (!newParent) { throw new FSError('ENOENT', newPath); } if (!(newParent instanceof Directory)) { throw new FSError('ENOTDIR', newPath); } } oldParent.removeItem(oldName); newParent.addItem(newName, oldItem); }); }; /** * Read a directory. * @param {string} dirpath Path to directory. * @param {string} encoding The encoding ('utf-8' or 'buffer'). * @param {boolean} withFileTypes whether or not to return fs.Dirent objects * @param {function(Error, (Array.|Array.)} callback Callback * (optional) called with any error or array of items in the directory. * @param {Object} ctx Context object (optional), only for nodejs v10+. * @return {Array.|Array.} Array of items in directory (if sync). */ Binding.prototype.readdir = function( dirpath, encoding, withFileTypes, callback, ctx ) { // again, the shorter arguments would not happen in nodejs v10+ if (arguments.length === 2) { callback = encoding; encoding = 'utf-8'; } else if (arguments.length === 3) { callback = withFileTypes; } if (withFileTypes === true) { notImplemented(); } markSyscall(ctx, 'scandir'); return maybeCallback(normalizeCallback(callback), ctx, this, function() { let dpath = dirpath; let dir = _system.getItem(dirpath); while (dir instanceof SymbolicLink) { dpath = path.resolve(path.dirname(dpath), dir.getPath()); dir = _system.getItem(dpath); } if (!dir) { throw new FSError('ENOENT', dirpath); } if (!(dir instanceof Directory)) { throw new FSError('ENOTDIR', dirpath); } let list = dir.list(); if (encoding === 'buffer') { list = list.map(function(item) { return bufferFrom(item); }); } return list; }); }; /** * Create a directory. * @param {string} pathname Path to new directory. * @param {number} mode Permissions. * @param {boolean} recursive Recursively create deep directory. (added in nodejs v10+) * @param {function(Error)} callback Optional callback. * @param {Object} ctx Context object (optional), only for nodejs v10+. */ Binding.prototype.mkdir = function(pathname, mode, recursive, callback, ctx) { if (typeof recursive !== 'boolean') { // when running nodejs < 10 ctx = callback; callback = recursive; recursive = false; } markSyscall(ctx, 'mkdir'); return maybeCallback(normalizeCallback(callback), ctx, this, function() { const item = _system.getItem(pathname); if (item) { if (recursive && item instanceof Directory) { // silently pass existing folder in recursive mode return; } throw new FSError('EEXIST', pathname); } const _mkdir = function(_pathname) { const parentDir = path.dirname(_pathname); let parent = _system.getItem(parentDir); if (!parent) { if (!recursive) { throw new FSError('ENOENT', _pathname); } parent = _mkdir(parentDir, true); } this.access(parentDir, parseInt('0002', 8)); const dir = new Directory(); if (mode) { dir.setMode(mode); } return parent.addItem(path.basename(_pathname), dir); }.bind(this); _mkdir(pathname); }); }; /** * Remove a directory. * @param {string} pathname Path to directory. * @param {function(Error)} callback Optional callback. * @param {Object} ctx Context object (optional), only for nodejs v10+. */ Binding.prototype.rmdir = function(pathname, callback, ctx) { markSyscall(ctx, 'rmdir'); return maybeCallback(normalizeCallback(callback), ctx, this, function() { const item = _system.getItem(pathname); if (!item) { throw new FSError('ENOENT', pathname); } if (!(item instanceof Directory)) { throw new FSError('ENOTDIR', pathname); } if (item.list().length > 0) { throw new FSError('ENOTEMPTY', pathname); } this.access(path.dirname(pathname), parseInt('0002', 8)); const parent = _system.getItem(path.dirname(pathname)); parent.removeItem(path.basename(pathname)); }); }; const PATH_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; const MAX_ATTEMPTS = 62 * 62 * 62; /** * Create a directory based on a template. * See http://web.mit.edu/freebsd/head/lib/libc/stdio/mktemp.c * @param {string} template Path template (trailing Xs will be replaced). * @param {string} encoding The encoding ('utf-8' or 'buffer'). * @param {function(Error, string)} callback Optional callback. * @param {Object} ctx Context object (optional), only for nodejs v10+. */ Binding.prototype.mkdtemp = function(prefix, encoding, callback, ctx) { if (encoding && typeof encoding !== 'string') { callback = encoding; encoding = 'utf-8'; } markSyscall(ctx, 'mkdtemp'); return maybeCallback(normalizeCallback(callback), ctx, this, function() { prefix = prefix.replace(/X{0,6}$/, 'XXXXXX'); const parentPath = path.dirname(prefix); const parent = _system.getItem(parentPath); if (!parent) { throw new FSError('ENOENT', prefix); } if (!(parent instanceof Directory)) { throw new FSError('ENOTDIR', prefix); } this.access(parentPath, parseInt('0002', 8)); const template = path.basename(prefix); let unique = false; let count = 0; let name; while (!unique && count < MAX_ATTEMPTS) { let position = template.length - 1; let replacement = ''; while (template.charAt(position) === 'X') { replacement += PATH_CHARS.charAt( Math.floor(PATH_CHARS.length * Math.random()) ); position -= 1; } const candidate = template.slice(0, position + 1) + replacement; if (!parent.getItem(candidate)) { name = candidate; unique = true; } count += 1; } if (!name) { throw new FSError('EEXIST', prefix); } const dir = new Directory(); parent.addItem(name, dir); let uniquePath = path.join(parentPath, name); if (encoding === 'buffer') { uniquePath = bufferFrom(uniquePath); } return uniquePath; }); }; /** * Truncate a file. * @param {number} fd File descriptor. * @param {number} len Number of bytes. * @param {function(Error)} callback Optional callback. * @param {Object} ctx Context object (optional), only for nodejs v10+. */ Binding.prototype.ftruncate = function(fd, len, callback, ctx) { markSyscall(ctx, 'ftruncate'); return maybeCallback(normalizeCallback(callback), ctx, this, function() { const descriptor = getDescriptorById(fd); if (!descriptor.isWrite()) { throw new FSError('EINVAL'); } const file = descriptor.getItem(); if (!(file instanceof File)) { throw new FSError('EINVAL'); } const content = file.getContent(); const newContent = bufferAlloc(len); content.copy(newContent); file.setContent(newContent); }); }; /** * Legacy support. * @param {number} fd File descriptor. * @param {number} len Number of bytes. * @param {function(Error)} callback Optional callback. * @param {Object} ctx Context object (optional), only for nodejs v10+. */ Binding.prototype.truncate = Binding.prototype.ftruncate; /** * Change user and group owner. * @param {string} pathname Path. * @param {number} uid User id. * @param {number} gid Group id. * @param {function(Error)} callback Optional callback. * @param {Object} ctx Context object (optional), only for nodejs v10+. */ Binding.prototype.chown = function(pathname, uid, gid, callback, ctx) { markSyscall(ctx, 'chown'); return maybeCallback(normalizeCallback(callback), ctx, this, function() { const item = _system.getItem(pathname); if (!item) { throw new FSError('ENOENT', pathname); } item.setUid(uid); item.setGid(gid); }); }; /** * Change user and group owner. * @param {number} fd File descriptor. * @param {number} uid User id. * @param {number} gid Group id. * @param {function(Error)} callback Optional callback. * @param {Object} ctx Context object (optional), only for nodejs v10+. */ Binding.prototype.fchown = function(fd, uid, gid, callback, ctx) { markSyscall(ctx, 'fchown'); return maybeCallback(normalizeCallback(callback), ctx, this, function() { const descriptor = getDescriptorById(fd); const item = descriptor.getItem(); item.setUid(uid); item.setGid(gid); }); }; /** * Change permissions. * @param {string} pathname Path. * @param {number} mode Mode. * @param {function(Error)} callback Optional callback. * @param {Object} ctx Context object (optional), only for nodejs v10+. */ Binding.prototype.chmod = function(pathname, mode, callback, ctx) { markSyscall(ctx, 'chmod'); return maybeCallback(normalizeCallback(callback), ctx, this, function() { const item = _system.getItem(pathname); if (!item) { throw new FSError('ENOENT', pathname); } item.setMode(mode); }); }; /** * Change permissions. * @param {number} fd File descriptor. * @param {number} mode Mode. * @param {function(Error)} callback Optional callback. * @param {Object} ctx Context object (optional), only for nodejs v10+. */ Binding.prototype.fchmod = function(fd, mode, callback, ctx) { markSyscall(ctx, 'fchmod'); return maybeCallback(normalizeCallback(callback), ctx, this, function() { const descriptor = getDescriptorById(fd); const item = descriptor.getItem(); item.setMode(mode); }); }; /** * Delete a named item. * @param {string} pathname Path to item. * @param {function(Error)} callback Optional callback. * @param {Object} ctx Context object (optional), only for nodejs v10+. */ Binding.prototype.unlink = function(pathname, callback, ctx) { markSyscall(ctx, 'unlink'); return maybeCallback(normalizeCallback(callback), ctx, this, function() { const item = _system.getItem(pathname); if (!item) { throw new FSError('ENOENT', pathname); } if (item instanceof Directory) { throw new FSError('EPERM', pathname); } const parent = _system.getItem(path.dirname(pathname)); parent.removeItem(path.basename(pathname)); }); }; /** * Update timestamps. * @param {string} pathname Path to item. * @param {number} atime Access time (in seconds). * @param {number} mtime Modification time (in seconds). * @param {function(Error)} callback Optional callback. * @param {Object} ctx Context object (optional), only for nodejs v10+. */ Binding.prototype.utimes = function(pathname, atime, mtime, callback, ctx) { markSyscall(ctx, 'utimes'); return maybeCallback(normalizeCallback(callback), ctx, this, function() { const item = _system.getItem(pathname); if (!item) { throw new FSError('ENOENT', pathname); } item.setATime(new Date(atime * 1000)); item.setMTime(new Date(mtime * 1000)); }); }; /** * Update timestamps. * @param {number} fd File descriptor. * @param {number} atime Access time (in seconds). * @param {number} mtime Modification time (in seconds). * @param {function(Error)} callback Optional callback. * @param {Object} ctx Context object (optional), only for nodejs v10+. */ Binding.prototype.futimes = function(fd, atime, mtime, callback, ctx) { markSyscall(ctx, 'futimes'); return maybeCallback(normalizeCallback(callback), ctx, this, function() { const descriptor = getDescriptorById(fd); const item = descriptor.getItem(); item.setATime(new Date(atime * 1000)); item.setMTime(new Date(mtime * 1000)); }); }; /** * Synchronize in-core state with storage device. * @param {number} fd File descriptor. * @param {function(Error)} callback Optional callback. * @param {Object} ctx Context object (optional), only for nodejs v10+. */ Binding.prototype.fsync = function(fd, callback, ctx) { markSyscall(ctx, 'fsync'); return maybeCallback(normalizeCallback(callback), ctx, this, function() { getDescriptorById(fd); }); }; /** * Synchronize in-core metadata state with storage device. * @param {number} fd File descriptor. * @param {function(Error)} callback Optional callback. * @param {Object} ctx Context object (optional), only for nodejs v10+. */ Binding.prototype.fdatasync = function(fd, callback, ctx) { markSyscall(ctx, 'fdatasync'); return maybeCallback(normalizeCallback(callback), ctx, this, function() { getDescriptorById(fd); }); }; /** * Create a hard link. * @param {string} srcPath The existing file. * @param {string} destPath The new link to create. * @param {function(Error)} callback Optional callback. * @param {Object} ctx Context object (optional), only for nodejs v10+. */ Binding.prototype.link = function(srcPath, destPath, callback, ctx) { markSyscall(ctx, 'link'); return maybeCallback(normalizeCallback(callback), ctx, this, function() { const item = _system.getItem(srcPath); if (!item) { throw new FSError('ENOENT', srcPath); } if (item instanceof Directory) { throw new FSError('EPERM', srcPath); } if (_system.getItem(destPath)) { throw new FSError('EEXIST', destPath); } const parent = _system.getItem(path.dirname(destPath)); if (!parent) { throw new FSError('ENOENT', destPath); } if (!(parent instanceof Directory)) { throw new FSError('ENOTDIR', destPath); } parent.addItem(path.basename(destPath), item); }); }; /** * Create a symbolic link. * @param {string} srcPath Path from link to the source file. * @param {string} destPath Path for the generated link. * @param {string} type Ignored (used for Windows only). * @param {function(Error)} callback Optional callback. * @param {Object} ctx Context object (optional), only for nodejs v10+. */ Binding.prototype.symlink = function(srcPath, destPath, type, callback, ctx) { markSyscall(ctx, 'symlink'); return maybeCallback(normalizeCallback(callback), ctx, this, function() { if (_system.getItem(destPath)) { throw new FSError('EEXIST', destPath); } const parent = _system.getItem(path.dirname(destPath)); if (!parent) { throw new FSError('ENOENT', destPath); } if (!(parent instanceof Directory)) { throw new FSError('ENOTDIR', destPath); } const link = new SymbolicLink(); link.setPath(srcPath); parent.addItem(path.basename(destPath), link); }); }; /** * Read the contents of a symbolic link. * @param {string} pathname Path to symbolic link. * @param {string} encoding The encoding ('utf-8' or 'buffer'). * @param {function(Error, (string|Buffer))} callback Optional callback. * @param {Object} ctx Context object (optional), only for nodejs v10+. * @return {string|Buffer} Symbolic link contents (path to source). */ Binding.prototype.readlink = function(pathname, encoding, callback, ctx) { if (encoding && typeof encoding !== 'string') { // this would not happend in nodejs v10+ callback = encoding; encoding = 'utf-8'; } markSyscall(ctx, 'readlink'); return maybeCallback(normalizeCallback(callback), ctx, this, function() { const link = _system.getItem(pathname); if (!link) { throw new FSError('ENOENT', pathname); } if (!(link instanceof SymbolicLink)) { throw new FSError('EINVAL', pathname); } let linkPath = link.getPath(); if (encoding === 'buffer') { linkPath = bufferFrom(linkPath); } return linkPath; }); }; /** * Stat an item. * @param {string} filepath Path. * @param {function(Error, Stats)|Float64Array|BigUint64Array} callback Callback (optional). In Node 7.7.0+ this will be a Float64Array * that should be filled with stat values. * @param {Object} ctx Context object (optional), only for nodejs v10+. * @return {Stats|undefined} Stats or undefined (if sync). */ Binding.prototype.lstat = function(filepath, options, callback, ctx) { if (arguments.length < 3) { // this would not happend in nodejs v10+ callback = options; options = {}; } markSyscall(ctx, 'lstat'); return maybeCallback(wrapStatsCallback(callback), ctx, this, function() { const item = _system.getItem(filepath); if (!item) { throw new FSError('ENOENT', filepath); } const stats = item.getStats(); // In Node 7.7.0+, binding.stat accepts a Float64Array as the second argument, // which should be filled with stat values. // In prior versions of Node, binding.stat simply returns a Stats instance. if ( callback instanceof Float64Array || callback instanceof BigUint64Array ) { fillStatsArray(stats, callback); } else { fillStatsArray(stats, statValues); return new Stats(item.getStats()); } }); }; /** * Tests user permissions. * @param {string} filepath Path. * @param {number} mode Mode. * @param {function(Error)} callback Callback (optional). * @param {Object} ctx Context object (optional), only for nodejs v10+. */ Binding.prototype.access = function(filepath, mode, callback, ctx) { markSyscall(ctx, 'access'); return maybeCallback(normalizeCallback(callback), ctx, this, function() { let item = _system.getItem(filepath); let links = 0; while (item instanceof SymbolicLink) { if (links > MAX_LINKS) { throw new FSError('ELOOP', filepath); } filepath = path.resolve(path.dirname(filepath), item.getPath()); item = _system.getItem(filepath); ++links; } if (!item) { throw new FSError('ENOENT', filepath); } if (mode && process.getuid && process.getgid) { const itemMode = item.getMode(); if (item.getUid() === process.getuid()) { if ((itemMode & (mode * 64)) !== mode * 64) { throw new FSError('EACCES', filepath); } } else if (item.getGid() === process.getgid()) { if ((itemMode & (mode * 8)) !== mode * 8) { throw new FSError('EACCES', filepath); } } else { if ((itemMode & mode) !== mode) { throw new FSError('EACCES', filepath); } } } }); }; /** * Not yet implemented. * @type {function()} */ Binding.prototype.StatWatcher = notImplemented; /** * Export the binding constructor. * @type {function()} */ exports = module.exports = Binding; mock-fs-4.10.4/lib/buffer.js000066400000000000000000000003751356713366300155360ustar00rootroot00000000000000exports.from = Buffer.from || function(value, encoding) { if (encoding) { return new Buffer(value, encoding); } return new Buffer(value); }; exports.alloc = Buffer.alloc || function(size) { return new Buffer(size); }; mock-fs-4.10.4/lib/descriptor.js000066400000000000000000000050541356713366300164420ustar00rootroot00000000000000'use strict'; const constants = require('constants'); /** * Create a new file descriptor. * @param {number} flags Flags. * @constructor */ function FileDescriptor(flags) { /** * Flags. * @type {number} */ this._flags = flags; /** * File system item. * @type {Item} */ this._item = null; /** * Current file position. * @type {number} */ this._position = 0; } /** * Set the item. * @param {Item} item File system item. */ FileDescriptor.prototype.setItem = function(item) { this._item = item; }; /** * Get the item. * @return {Item} File system item. */ FileDescriptor.prototype.getItem = function() { return this._item; }; /** * Get the current file position. * @return {number} File position. */ FileDescriptor.prototype.getPosition = function() { return this._position; }; /** * Set the current file position. * @param {number} position File position. */ FileDescriptor.prototype.setPosition = function(position) { this._position = position; }; /** * Check if file opened for appending. * @return {boolean} Opened for appending. */ FileDescriptor.prototype.isAppend = function() { return (this._flags & constants.O_APPEND) === constants.O_APPEND; }; /** * Check if file opened for creation. * @return {boolean} Opened for creation. */ FileDescriptor.prototype.isCreate = function() { return (this._flags & constants.O_CREAT) === constants.O_CREAT; }; /** * Check if file opened for reading. * @return {boolean} Opened for reading. */ FileDescriptor.prototype.isRead = function() { // special treatment because O_RDONLY is 0 return ( this._flags === constants.O_RDONLY || this._flags === (constants.O_RDONLY | constants.O_SYNC) || (this._flags & constants.O_RDWR) === constants.O_RDWR ); }; /** * Check if file opened for writing. * @return {boolean} Opened for writing. */ FileDescriptor.prototype.isWrite = function() { return ( (this._flags & constants.O_WRONLY) === constants.O_WRONLY || (this._flags & constants.O_RDWR) === constants.O_RDWR ); }; /** * Check if file opened for truncating. * @return {boolean} Opened for truncating. */ FileDescriptor.prototype.isTruncate = function() { return (this._flags & constants.O_TRUNC) === constants.O_TRUNC; }; /** * Check if file opened with exclusive flag. * @return {boolean} Opened with exclusive. */ FileDescriptor.prototype.isExclusive = function() { return (this._flags & constants.O_EXCL) === constants.O_EXCL; }; /** * Export the constructor. * @type {function()} */ exports = module.exports = FileDescriptor; mock-fs-4.10.4/lib/directory.js000066400000000000000000000043571356713366300162750ustar00rootroot00000000000000'use strict'; const util = require('util'); const Item = require('./item'); const constants = require('constants'); /** * A directory. * @constructor */ function Directory() { Item.call(this); /** * Items in this directory. * @type {Object.} */ this._items = {}; /** * Permissions. */ this._mode = 511; // 0777 } util.inherits(Directory, Item); /** * Add an item to the directory. * @param {string} name The name to give the item. * @param {Item} item The item to add. * @return {Item} The added item. */ Directory.prototype.addItem = function(name, item) { if (this._items.hasOwnProperty(name)) { throw new Error('Item with the same name already exists: ' + name); } this._items[name] = item; ++item.links; if (item instanceof Directory) { // for '.' entry ++item.links; // for subdirectory ++this.links; } this.setMTime(new Date()); return item; }; /** * Get a named item. * @param {string} name Item name. * @return {Item} The named item (or null if none). */ Directory.prototype.getItem = function(name) { let item = null; if (this._items.hasOwnProperty(name)) { item = this._items[name]; } return item; }; /** * Remove an item. * @param {string} name Name of item to remove. * @return {Item} The orphan item. */ Directory.prototype.removeItem = function(name) { if (!this._items.hasOwnProperty(name)) { throw new Error('Item does not exist in directory: ' + name); } const item = this._items[name]; delete this._items[name]; --item.links; if (item instanceof Directory) { // for '.' entry --item.links; // for subdirectory --this.links; } this.setMTime(new Date()); return item; }; /** * Get list of item names in this directory. * @return {Array.} Item names. */ Directory.prototype.list = function() { return Object.keys(this._items).sort(); }; /** * Get directory stats. * @return {Object} Stats properties. */ Directory.prototype.getStats = function() { const stats = Item.prototype.getStats.call(this); stats.mode = this.getMode() | constants.S_IFDIR; stats.size = 1; stats.blocks = 1; return stats; }; /** * Export the constructor. * @type {function()} */ exports = module.exports = Directory; mock-fs-4.10.4/lib/error.js000066400000000000000000000024141356713366300154120ustar00rootroot00000000000000'use strict'; const uvBinding = process.binding('uv'); /** * Error codes from libuv. * @enum {number} */ const codes = {}; if (uvBinding.errmap) { // nodejs v8+ uvBinding.errmap.forEach(function(value, errno) { const code = value[0]; const message = value[1]; codes[code] = {errno: errno, message: message}; }); } else { // nodejs v4 and v6 Object.keys(uvBinding).forEach(function(key) { if (key.startsWith('UV_')) { const code = key.slice(3); const errno = uvBinding[key]; codes[code] = {errno: errno, message: key}; } }); } /** * Create an error. * @param {string} code Error code. * @param {string} path Path (optional). * @constructor */ function FSError(code, path) { if (!codes.hasOwnProperty(code)) { throw new Error('Programmer error, invalid error code: ' + code); } Error.call(this); const details = codes[code]; let message = code + ', ' + details.message; if (path) { message += " '" + path + "'"; } this.message = message; this.code = code; this.errno = details.errno; if (path !== undefined) { this.path = path; } Error.captureStackTrace(this, FSError); } FSError.prototype = new Error(); FSError.codes = codes; /** * Error constructor. */ exports = module.exports = FSError; mock-fs-4.10.4/lib/file.js000066400000000000000000000026421356713366300152030ustar00rootroot00000000000000'use strict'; const util = require('util'); const Item = require('./item'); const bufferFrom = require('./buffer').from; const bufferAlloc = require('./buffer').alloc; const EMPTY = bufferAlloc(0); const constants = require('constants'); /** * A directory. * @constructor */ function File() { Item.call(this); /** * File content. * @type {Buffer} */ this._content = EMPTY; } util.inherits(File, Item); /** * Get the file contents. * @return {Buffer} File contents. */ File.prototype.getContent = function() { this.setATime(new Date()); return this._content; }; /** * Set the file contents. * @param {string|Buffer} content File contents. */ File.prototype.setContent = function(content) { if (typeof content === 'string') { content = bufferFrom(content); } else if (!Buffer.isBuffer(content)) { throw new Error('File content must be a string or buffer'); } this._content = content; const now = Date.now(); this.setCTime(new Date(now)); this.setMTime(new Date(now)); }; /** * Get file stats. * @return {Object} Stats properties. */ File.prototype.getStats = function() { const size = this._content.length; const stats = Item.prototype.getStats.call(this); stats.mode = this.getMode() | constants.S_IFREG; stats.size = size; stats.blocks = Math.ceil(size / 512); return stats; }; /** * Export the constructor. * @type {function()} */ exports = module.exports = File; mock-fs-4.10.4/lib/filesystem.js000066400000000000000000000214061356713366300164470ustar00rootroot00000000000000'use strict'; const os = require('os'); const path = require('path'); const Directory = require('./directory'); const File = require('./file'); const FSError = require('./error'); const SymbolicLink = require('./symlink'); const isWindows = process.platform === 'win32'; function toNamespacedPath(filePath) { return path.toNamespacedPath ? path.toNamespacedPath(filePath) : path._makeLong(filePath); } function getPathParts(filepath) { const parts = toNamespacedPath(path.resolve(filepath)).split(path.sep); parts.shift(); if (isWindows) { // parts currently looks like ['', '?', 'c:', ...] parts.shift(); const q = parts.shift(); // should be '?' const base = '\\\\' + q + '\\' + parts.shift().toLowerCase(); parts.unshift(base); } if (parts[parts.length - 1] === '') { parts.pop(); } return parts; } /** * Create a new file system. * @param {Object} options Any filesystem options. * @param {boolean} options.createCwd Create a directory for `process.cwd()` * (defaults to `true`). * @param {boolean} options.createTmp Create a directory for `os.tmpdir()` * (defaults to `true`). * @constructor */ function FileSystem(options) { options = options || {}; const createCwd = 'createCwd' in options ? options.createCwd : true; const createTmp = 'createTmp' in options ? options.createTmp : true; const root = new Directory(); // populate with default directories const defaults = []; if (createCwd) { defaults.push(process.cwd()); } if (createTmp) { defaults.push((os.tmpdir && os.tmpdir()) || os.tmpDir()); } defaults.forEach(function(dir) { const parts = getPathParts(dir); let directory = root; for (let i = 0, ii = parts.length; i < ii; ++i) { const name = parts[i]; const candidate = directory.getItem(name); if (!candidate) { directory = directory.addItem(name, new Directory()); } else if (candidate instanceof Directory) { directory = candidate; } else { throw new Error('Failed to create directory: ' + dir); } } }); /** * Root directory. * @type {Directory} */ this._root = root; } /** * Get the root directory. * @return {Directory} The root directory. */ FileSystem.prototype.getRoot = function() { return this._root; }; /** * Get a file system item. * @param {string} filepath Path to item. * @return {Item} The item (or null if not found). */ FileSystem.prototype.getItem = function(filepath) { const parts = getPathParts(filepath); const currentParts = getPathParts(process.cwd()); let item = this._root; let itemPath = '/'; for (let i = 0, ii = parts.length; i < ii; ++i) { const name = parts[i]; while (item instanceof SymbolicLink) { // Symbolic link being traversed as a directory --- If link targets // another symbolic link, resolve target's path relative to the original // link's target, otherwise relative to the current item. itemPath = path.resolve(path.dirname(itemPath), item.getPath()); item = this.getItem(itemPath); } if (item) { if (item instanceof Directory && name !== currentParts[i]) { // make sure traversal is allowed if (!item.canExecute()) { throw new FSError('EACCES', filepath); } } if (item instanceof File) { throw new FSError('ENOTDIR', filepath); } item = item.getItem(name); } if (!item) { break; } itemPath = path.resolve(itemPath, name); } return item; }; /** * Populate a directory with an item. * @param {Directory} directory The directory to populate. * @param {string} name The name of the item. * @param {string|Buffer|function|Object} obj Instructions for creating the * item. */ function populate(directory, name, obj) { let item; if (typeof obj === 'string' || Buffer.isBuffer(obj)) { // contents for a file item = new File(); item.setContent(obj); } else if (typeof obj === 'function') { // item factory item = obj(); } else if (typeof obj === 'object') { // directory with more to populate item = new Directory(); for (const key in obj) { populate(item, key, obj[key]); } } else { throw new Error('Unsupported type: ' + typeof obj + ' of item ' + name); } /** * Special exception for redundant adding of empty directories. */ if ( item instanceof Directory && item.list().length === 0 && directory.getItem(name) instanceof Directory ) { // pass } else { directory.addItem(name, item); } } /** * Configure a mock file system. * @param {Object} paths Config object. * @param {Object} options Any filesystem options. * @param {boolean} options.createCwd Create a directory for `process.cwd()` * (defaults to `true`). * @param {boolean} options.createTmp Create a directory for `os.tmpdir()` * (defaults to `true`). * @return {FileSystem} Mock file system. */ FileSystem.create = function(paths, options) { const system = new FileSystem(options); for (const filepath in paths) { const parts = getPathParts(filepath); let directory = system._root; for (let i = 0, ii = parts.length - 1; i < ii; ++i) { const name = parts[i]; const candidate = directory.getItem(name); if (!candidate) { directory = directory.addItem(name, new Directory()); } else if (candidate instanceof Directory) { directory = candidate; } else { throw new Error('Failed to create directory: ' + filepath); } } populate(directory, parts[parts.length - 1], paths[filepath]); } return system; }; /** * Generate a factory for new files. * @param {Object} config File config. * @return {function():File} Factory that creates a new file. */ FileSystem.file = function(config) { config = config || {}; return function() { const file = new File(); if (config.hasOwnProperty('content')) { file.setContent(config.content); } if (config.hasOwnProperty('mode')) { file.setMode(config.mode); } else { file.setMode(438); // 0666 } if (config.hasOwnProperty('uid')) { file.setUid(config.uid); } if (config.hasOwnProperty('gid')) { file.setGid(config.gid); } if (config.hasOwnProperty('atime')) { file.setATime(config.atime); } if (config.hasOwnProperty('ctime')) { file.setCTime(config.ctime); } if (config.hasOwnProperty('mtime')) { file.setMTime(config.mtime); } if (config.hasOwnProperty('birthtime')) { file.setBirthtime(config.birthtime); } return file; }; }; /** * Generate a factory for new symbolic links. * @param {Object} config File config. * @return {function():File} Factory that creates a new symbolic link. */ FileSystem.symlink = function(config) { config = config || {}; return function() { const link = new SymbolicLink(); if (config.hasOwnProperty('mode')) { link.setMode(config.mode); } else { link.setMode(438); // 0666 } if (config.hasOwnProperty('uid')) { link.setUid(config.uid); } if (config.hasOwnProperty('gid')) { link.setGid(config.gid); } if (config.hasOwnProperty('path')) { link.setPath(config.path); } else { throw new Error('Missing "path" property'); } if (config.hasOwnProperty('atime')) { link.setATime(config.atime); } if (config.hasOwnProperty('ctime')) { link.setCTime(config.ctime); } if (config.hasOwnProperty('mtime')) { link.setMTime(config.mtime); } if (config.hasOwnProperty('birthtime')) { link.setBirthtime(config.birthtime); } return link; }; }; /** * Generate a factory for new directories. * @param {Object} config File config. * @return {function():Directory} Factory that creates a new directory. */ FileSystem.directory = function(config) { config = config || {}; return function() { const dir = new Directory(); if (config.hasOwnProperty('mode')) { dir.setMode(config.mode); } if (config.hasOwnProperty('uid')) { dir.setUid(config.uid); } if (config.hasOwnProperty('gid')) { dir.setGid(config.gid); } if (config.hasOwnProperty('items')) { for (const name in config.items) { populate(dir, name, config.items[name]); } } if (config.hasOwnProperty('atime')) { dir.setATime(config.atime); } if (config.hasOwnProperty('ctime')) { dir.setCTime(config.ctime); } if (config.hasOwnProperty('mtime')) { dir.setMTime(config.mtime); } if (config.hasOwnProperty('birthtime')) { dir.setBirthtime(config.birthtime); } return dir; }; }; /** * Module exports. * @type {function} */ exports = module.exports = FileSystem; exports.getPathParts = getPathParts; exports.toNamespacedPath = toNamespacedPath; mock-fs-4.10.4/lib/index.js000066400000000000000000000116431356713366300153740ustar00rootroot00000000000000'use strict'; const Binding = require('./binding'); const FSError = require('./error'); const FileSystem = require('./filesystem'); const realBinding = process.binding('fs'); const path = require('path'); const fs = require('fs'); const toNamespacedPath = FileSystem.toNamespacedPath; const realProcessProps = { cwd: process.cwd, chdir: process.chdir }; const realCreateWriteStream = fs.createWriteStream; const realStats = realBinding.Stats; const realStatWatcher = realBinding.StatWatcher; /** * Pre-patch fs binding. * This allows mock-fs to work properly under nodejs v10+ readFile * As ReadFileContext nodejs v10+ implementation traps original binding methods: * const { FSReqWrap, close, read } = process.binding('fs'); * Note this patch only solves issue for readFile, as the require of * ReadFileContext is delayed by readFile implementation. * if (!ReadFileContext) ReadFileContext = require('internal/fs/read_file_context') * * @param {string} key Property name. */ function patch(key) { const existingMethod = realBinding[key]; realBinding[key] = function() { if (this._mockedBinding) { return this._mockedBinding[key].apply(this, arguments); } else { return existingMethod.apply(this, arguments); } }.bind(realBinding); } for (const key in Binding.prototype) { if (typeof realBinding[key] === 'function') { // Stats and StatWatcher are constructors if (key !== 'Stats' && key !== 'StatWatcher') { patch(key); } } } function overrideBinding(binding) { realBinding._mockedBinding = binding; for (const key in binding) { if (typeof realBinding[key] === 'function') { // Stats and StatWatcher are constructors if (key === 'Stats' || key === 'StatWatcher') { realBinding[key] = binding[key]; } } else if (typeof realBinding[key] === 'undefined') { realBinding[key] = binding[key]; } } } function overrideProcess(cwd, chdir) { process.cwd = cwd; process.chdir = chdir; } /** * Have to disable write stream _writev on nodejs v10+. * * nodejs v8 lib/fs.js * note binding.writeBuffers will use mock-fs patched writeBuffers. * * const binding = process.binding('fs'); * function writev(fd, chunks, position, callback) { * // ... * binding.writeBuffers(fd, chunks, position, req); * } * * nodejs v10+ lib/internal/fs/streams.js * note it uses original writeBuffers, bypassed mock-fs patched writeBuffers. * * const {writeBuffers} = internalBinding('fs'); * function writev(fd, chunks, position, callback) { * // ... * writeBuffers(fd, chunks, position, req); * } * * Luckily _writev is an optional method on Writeable stream implementation. * When _writev is missing, it will fall back to make multiple _write calls. */ function overrideCreateWriteStream() { fs.createWriteStream = function(path, options) { const output = realCreateWriteStream(path, options); // disable _writev, this will over shadow WriteStream.prototype._writev output._writev = undefined; return output; }; } function restoreBinding() { delete realBinding._mockedBinding; realBinding.Stats = realStats; realBinding.StatWatcher = realStatWatcher; } function restoreProcess() { for (const key in realProcessProps) { process[key] = realProcessProps[key]; } } function restoreCreateWriteStream() { fs.createWriteStream = realCreateWriteStream; } /** * Swap out the fs bindings for a mock file system. * @param {Object} config Mock file system configuration. * @param {Object} options Any filesystem options. * @param {boolean} options.createCwd Create a directory for `process.cwd()` * (defaults to `true`). * @param {boolean} options.createTmp Create a directory for `os.tmpdir()` * (defaults to `true`). */ exports = module.exports = function mock(config, options) { const system = FileSystem.create(config, options); const binding = new Binding(system); overrideBinding(binding); let currentPath = process.cwd(); overrideProcess( function cwd() { return currentPath; }, function chdir(directory) { if (!binding.stat(toNamespacedPath(directory)).isDirectory()) { throw new FSError('ENOTDIR'); } currentPath = path.resolve(currentPath, directory); } ); overrideCreateWriteStream(); }; /** * Get hold of the mocked filesystem's 'root' * If fs hasn't currently been replaced, this will return an empty object */ exports.getMockRoot = function() { if (realBinding._mockedBinding) { return realBinding.getSystem().getRoot(); } else { return {}; } }; /** * Restore the fs bindings for the real file system. */ exports.restore = function() { restoreBinding(); restoreProcess(); restoreCreateWriteStream(); }; /** * Create a file factory. */ exports.file = FileSystem.file; /** * Create a directory factory. */ exports.directory = FileSystem.directory; /** * Create a symbolic link factory. */ exports.symlink = FileSystem.symlink; mock-fs-4.10.4/lib/item.js000066400000000000000000000135171356713366300152250ustar00rootroot00000000000000'use strict'; let counter = 0; /** * Permissions. * @enum {number} */ const permissions = { USER_READ: 256, // 0400 USER_WRITE: 128, // 0200 USER_EXEC: 64, // 0100 GROUP_READ: 32, // 0040 GROUP_WRITE: 16, // 0020 GROUP_EXEC: 8, // 0010 OTHER_READ: 4, // 0004 OTHER_WRITE: 2, // 0002 OTHER_EXEC: 1 // 0001 }; function getUid() { // force NaN on windows. return process.getuid ? process.getuid() : NaN; } function getGid() { // force NaN on windows. return process.getgid ? process.getgid() : NaN; } /** * A filesystem item. * @constructor */ function Item() { const now = Date.now(); /** * Access time. * @type {Date} */ this._atime = new Date(now); /** * Change time. * @type {Date} */ this._ctime = new Date(now); /** * Birth time. * @type {Date} */ this._birthtime = new Date(now); /** * Modification time. * @type {Date} */ this._mtime = new Date(now); /** * Permissions. */ this._mode = 438; // 0666 /** * User id. * @type {number} */ this._uid = getUid(); /** * Group id. * @type {number} */ this._gid = getGid(); /** * Item number. * @type {number} */ this._id = ++counter; /** * Number of links to this item. */ this.links = 0; } /** * Determine if the current user has read permission. * @return {boolean} The current user can read. */ Item.prototype.canRead = function() { const uid = getUid(); const gid = getGid(); let can = false; if (uid === 0) { can = true; } else if (uid === this._uid || uid !== uid) { // (uid !== uid) means uid is NaN, only for windows can = (permissions.USER_READ & this._mode) === permissions.USER_READ; } else if (gid === this._gid) { can = (permissions.GROUP_READ & this._mode) === permissions.GROUP_READ; } else { can = (permissions.OTHER_READ & this._mode) === permissions.OTHER_READ; } return can; }; /** * Determine if the current user has write permission. * @return {boolean} The current user can write. */ Item.prototype.canWrite = function() { const uid = getUid(); const gid = getGid(); let can = false; if (uid === 0) { can = true; } else if (uid === this._uid || uid !== uid) { // (uid !== uid) means uid is NaN, only for windows can = (permissions.USER_WRITE & this._mode) === permissions.USER_WRITE; } else if (gid === this._gid) { can = (permissions.GROUP_WRITE & this._mode) === permissions.GROUP_WRITE; } else { can = (permissions.OTHER_WRITE & this._mode) === permissions.OTHER_WRITE; } return can; }; /** * Determine if the current user has execute permission. * @return {boolean} The current user can execute. */ Item.prototype.canExecute = function() { const uid = getUid(); const gid = getGid(); let can = false; if (uid === 0) { can = true; } else if (uid === this._uid || uid !== uid) { // (uid !== uid) means uid is NaN, only for windows can = (permissions.USER_EXEC & this._mode) === permissions.USER_EXEC; } else if (gid === this._gid) { can = (permissions.GROUP_EXEC & this._mode) === permissions.GROUP_EXEC; } else { can = (permissions.OTHER_EXEC & this._mode) === permissions.OTHER_EXEC; } return can; }; /** * Get access time. * @return {Date} Access time. */ Item.prototype.getATime = function() { return this._atime; }; /** * Set access time. * @param {Date} atime Access time. */ Item.prototype.setATime = function(atime) { this._atime = atime; }; /** * Get change time. * @return {Date} Change time. */ Item.prototype.getCTime = function() { return this._ctime; }; /** * Set change time. * @param {Date} ctime Change time. */ Item.prototype.setCTime = function(ctime) { this._ctime = ctime; }; /** * Get birth time. * @return {Date} Birth time. */ Item.prototype.getBirthtime = function() { return this._birthtime; }; /** * Set change time. * @param {Date} birthtime Birth time. */ Item.prototype.setBirthtime = function(birthtime) { this._birthtime = birthtime; }; /** * Get modification time. * @return {Date} Modification time. */ Item.prototype.getMTime = function() { return this._mtime; }; /** * Set modification time. * @param {Date} mtime Modification time. */ Item.prototype.setMTime = function(mtime) { this._mtime = mtime; }; /** * Get mode (permission only, e.g 0666). * @return {number} Mode. */ Item.prototype.getMode = function() { return this._mode; }; /** * Set mode (permission only, e.g 0666). * @param {Date} mode Mode. */ Item.prototype.setMode = function(mode) { this.setCTime(new Date()); this._mode = mode; }; /** * Get user id. * @return {number} User id. */ Item.prototype.getUid = function() { return this._uid; }; /** * Set user id. * @param {number} uid User id. */ Item.prototype.setUid = function(uid) { this.setCTime(new Date()); this._uid = uid; }; /** * Get group id. * @return {number} Group id. */ Item.prototype.getGid = function() { return this._gid; }; /** * Set group id. * @param {number} gid Group id. */ Item.prototype.setGid = function(gid) { this.setCTime(new Date()); this._gid = gid; }; /** * Get item stats. * @return {Object} Stats properties. */ Item.prototype.getStats = function() { return { dev: 8675309, nlink: this.links, uid: this.getUid(), gid: this.getGid(), rdev: 0, blksize: 4096, ino: this._id, atime: this.getATime(), mtime: this.getMTime(), ctime: this.getCTime(), birthtime: this.getBirthtime(), atimeMs: +this.getATime(), mtimeMs: +this.getMTime(), ctimeMs: +this.getCTime(), birthtimeMs: +this.getBirthtime() }; }; /** * Get the item's string representation. * @return {string} String representation. */ Item.prototype.toString = function() { return '[' + this.constructor.name + ']'; }; /** * Export the constructor. * @type {function()} */ exports = module.exports = Item; mock-fs-4.10.4/lib/symlink.js000066400000000000000000000020711356713366300157460ustar00rootroot00000000000000'use strict'; const util = require('util'); const Item = require('./item'); const constants = require('constants'); /** * A directory. * @constructor */ function SymbolicLink() { Item.call(this); /** * Relative path to source. * @type {string} */ this._path = undefined; } util.inherits(SymbolicLink, Item); /** * Set the path to the source. * @param {string} pathname Path to source. */ SymbolicLink.prototype.setPath = function(pathname) { this._path = pathname; }; /** * Get the path to the source. * @return {string} Path to source. */ SymbolicLink.prototype.getPath = function() { return this._path; }; /** * Get symbolic link stats. * @return {Object} Stats properties. */ SymbolicLink.prototype.getStats = function() { const size = this._path.length; const stats = Item.prototype.getStats.call(this); stats.mode = this.getMode() | constants.S_IFLNK; stats.size = size; stats.blocks = Math.ceil(size / 512); return stats; }; /** * Export the constructor. * @type {function()} */ exports = module.exports = SymbolicLink; mock-fs-4.10.4/license.md000066400000000000000000000046551356713366300151320ustar00rootroot00000000000000# License for mock-fs The mock-fs module is distributed under the MIT license. Find the full source here: http://tschaub.mit-license.org/ Copyright Tim Schaub. 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 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. # Node's license This module includes parts of the Node library itself (specifically, the fs module is included from several different versions of Node). Find Node's license below: Copyright Joyent, Inc. and other Node contributors. All rights reserved. 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 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. mock-fs-4.10.4/package-lock.json000066400000000000000000002355251356713366300164040ustar00rootroot00000000000000{ "name": "mock-fs", "version": "4.10.4", "lockfileVersion": 1, "requires": true, "dependencies": { "@babel/code-frame": { "version": "7.5.5", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", "dev": true, "requires": { "@babel/highlight": "^7.0.0" } }, "@babel/highlight": { "version": "7.5.0", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", "dev": true, "requires": { "chalk": "^2.0.0", "esutils": "^2.0.2", "js-tokens": "^4.0.0" } }, "acorn": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz", "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==", "dev": true }, "acorn-jsx": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.1.0.tgz", "integrity": "sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw==", "dev": true }, "ajv": { "version": "6.10.2", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", "dev": true, "requires": { "fast-deep-equal": "^2.0.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "ansi-colors": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", "dev": true }, "ansi-escapes": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", "dev": true }, "ansi-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { "color-convert": "^1.9.0" } }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "requires": { "sprintf-js": "~1.0.2" } }, "array-includes": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", "dev": true, "requires": { "define-properties": "^1.1.2", "es-abstract": "^1.7.0" } }, "assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", "dev": true }, "astral-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", "dev": true }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", "dev": true }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true }, "camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, "chai": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", "dev": true, "requires": { "assertion-error": "^1.1.0", "check-error": "^1.0.2", "deep-eql": "^3.0.1", "get-func-name": "^2.0.0", "pathval": "^1.1.0", "type-detect": "^4.0.5" } }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, "chardet": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", "dev": true }, "check-error": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", "dev": true }, "cli-cursor": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", "dev": true, "requires": { "restore-cursor": "^2.0.0" } }, "cli-width": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", "dev": true }, "cliui": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", "dev": true, "requires": { "string-width": "^2.1.1", "strip-ansi": "^4.0.0", "wrap-ansi": "^2.0.0" } }, "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, "requires": { "color-name": "1.1.3" } }, "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, "contains-path": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", "dev": true }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, "requires": { "nice-try": "^1.0.4", "path-key": "^2.0.1", "semver": "^5.5.0", "shebang-command": "^1.2.0", "which": "^1.2.9" }, "dependencies": { "semver": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", "dev": true } } }, "debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { "ms": "^2.1.1" } }, "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, "deep-eql": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", "dev": true, "requires": { "type-detect": "^4.0.0" } }, "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, "define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", "dev": true, "requires": { "object-keys": "^1.0.12" } }, "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", "dev": true }, "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, "requires": { "esutils": "^2.0.2" } }, "emoji-regex": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", "dev": true }, "end-of-stream": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", "dev": true, "requires": { "once": "^1.4.0" } }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, "requires": { "is-arrayish": "^0.2.1" } }, "es-abstract": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", "dev": true, "requires": { "es-to-primitive": "^1.2.0", "function-bind": "^1.1.1", "has": "^1.0.3", "is-callable": "^1.1.4", "is-regex": "^1.0.4", "object-keys": "^1.0.12" } }, "es-to-primitive": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", "dev": true, "requires": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", "is-symbol": "^1.0.2" } }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, "eslint": { "version": "5.16.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz", "integrity": "sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", "ajv": "^6.9.1", "chalk": "^2.1.0", "cross-spawn": "^6.0.5", "debug": "^4.0.1", "doctrine": "^3.0.0", "eslint-scope": "^4.0.3", "eslint-utils": "^1.3.1", "eslint-visitor-keys": "^1.0.0", "espree": "^5.0.1", "esquery": "^1.0.1", "esutils": "^2.0.2", "file-entry-cache": "^5.0.1", "functional-red-black-tree": "^1.0.1", "glob": "^7.1.2", "globals": "^11.7.0", "ignore": "^4.0.6", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "inquirer": "^6.2.2", "js-yaml": "^3.13.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.3.0", "lodash": "^4.17.11", "minimatch": "^3.0.4", "mkdirp": "^0.5.1", "natural-compare": "^1.4.0", "optionator": "^0.8.2", "path-is-inside": "^1.0.2", "progress": "^2.0.0", "regexpp": "^2.0.1", "semver": "^5.5.1", "strip-ansi": "^4.0.0", "strip-json-comments": "^2.0.1", "table": "^5.2.3", "text-table": "^0.2.0" }, "dependencies": { "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true } } }, "eslint-config-prettier": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-4.1.0.tgz", "integrity": "sha512-zILwX9/Ocz4SV2vX7ox85AsrAgXV3f2o2gpIicdMIOra48WYqgUnWNH/cR/iHtmD2Vb3dLSC3LiEJnS05Gkw7w==", "dev": true, "requires": { "get-stdin": "^6.0.0" } }, "eslint-config-tschaub": { "version": "13.1.0", "resolved": "https://registry.npmjs.org/eslint-config-tschaub/-/eslint-config-tschaub-13.1.0.tgz", "integrity": "sha512-6vlG8FuEQqzB/87AHhs91Z50FZYPwlHk/ZLMDJ9H1ELtbGuqRBkFGBGOI+RxKCgQLdmS77mEDcehhnkBMvxzvA==", "dev": true, "requires": { "eslint-config-prettier": "^4.1.0", "eslint-plugin-import": "^2.17.2", "eslint-plugin-prettier": "^3.0.1", "prettier": "^1.17.0" } }, "eslint-import-resolver-node": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", "dev": true, "requires": { "debug": "^2.6.9", "resolve": "^1.5.0" }, "dependencies": { "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" } }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true } } }, "eslint-module-utils": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.4.0.tgz", "integrity": "sha512-14tltLm38Eu3zS+mt0KvILC3q8jyIAH518MlG+HO0p+yK885Lb1UHTY/UgR91eOyGdmxAPb+OLoW4znqIT6Ndw==", "dev": true, "requires": { "debug": "^2.6.8", "pkg-dir": "^2.0.0" }, "dependencies": { "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" } }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true } } }, "eslint-plugin-import": { "version": "2.17.2", "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.17.2.tgz", "integrity": "sha512-m+cSVxM7oLsIpmwNn2WXTJoReOF9f/CtLMo7qOVmKd1KntBy0hEcuNZ3erTmWjx+DxRO0Zcrm5KwAvI9wHcV5g==", "dev": true, "requires": { "array-includes": "^3.0.3", "contains-path": "^0.1.0", "debug": "^2.6.9", "doctrine": "1.5.0", "eslint-import-resolver-node": "^0.3.2", "eslint-module-utils": "^2.4.0", "has": "^1.0.3", "lodash": "^4.17.11", "minimatch": "^3.0.4", "read-pkg-up": "^2.0.0", "resolve": "^1.10.0" }, "dependencies": { "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" } }, "doctrine": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", "dev": true, "requires": { "esutils": "^2.0.2", "isarray": "^1.0.0" } }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true } } }, "eslint-plugin-prettier": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.0.1.tgz", "integrity": "sha512-/PMttrarPAY78PLvV3xfWibMOdMDl57hmlQ2XqFeA37wd+CJ7WSxV7txqjVPHi/AAFKd2lX0ZqfsOc/i5yFCSQ==", "dev": true, "requires": { "prettier-linter-helpers": "^1.0.0" } }, "eslint-scope": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", "dev": true, "requires": { "esrecurse": "^4.1.0", "estraverse": "^4.1.1" } }, "eslint-utils": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.2.tgz", "integrity": "sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q==", "dev": true, "requires": { "eslint-visitor-keys": "^1.0.0" } }, "eslint-visitor-keys": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", "dev": true }, "espree": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", "dev": true, "requires": { "acorn": "^6.0.7", "acorn-jsx": "^5.0.0", "eslint-visitor-keys": "^1.0.0" } }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, "esquery": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", "dev": true, "requires": { "estraverse": "^4.0.0" } }, "esrecurse": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", "dev": true, "requires": { "estraverse": "^4.1.0" } }, "estraverse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true }, "esutils": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", "dev": true }, "execa": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", "dev": true, "requires": { "cross-spawn": "^6.0.0", "get-stream": "^4.0.0", "is-stream": "^1.1.0", "npm-run-path": "^2.0.0", "p-finally": "^1.0.0", "signal-exit": "^3.0.0", "strip-eof": "^1.0.0" } }, "external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", "dev": true, "requires": { "chardet": "^0.7.0", "iconv-lite": "^0.4.24", "tmp": "^0.0.33" } }, "fast-deep-equal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", "dev": true }, "fast-diff": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", "dev": true }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", "dev": true }, "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, "figures": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", "dev": true, "requires": { "escape-string-regexp": "^1.0.5" } }, "file-entry-cache": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", "dev": true, "requires": { "flat-cache": "^2.0.1" } }, "find-up": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, "requires": { "locate-path": "^2.0.0" } }, "flat": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", "dev": true, "requires": { "is-buffer": "~2.0.3" } }, "flat-cache": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", "dev": true, "requires": { "flatted": "^2.0.0", "rimraf": "2.6.3", "write": "1.0.3" } }, "flatted": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", "dev": true }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, "functional-red-black-tree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, "get-func-name": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", "dev": true }, "get-stdin": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", "dev": true }, "get-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", "dev": true, "requires": { "pump": "^3.0.0" } }, "glob": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.0.4", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true }, "graceful-fs": { "version": "4.1.15", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", "dev": true }, "growl": { "version": "1.10.5", "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", "dev": true }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dev": true, "requires": { "function-bind": "^1.1.1" } }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, "has-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", "dev": true }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, "hosted-git-info": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", "dev": true }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" } }, "ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, "import-fresh": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz", "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==", "dev": true, "requires": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" } }, "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, "inquirer": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", "dev": true, "requires": { "ansi-escapes": "^3.2.0", "chalk": "^2.4.2", "cli-cursor": "^2.1.0", "cli-width": "^2.0.0", "external-editor": "^3.0.3", "figures": "^2.0.0", "lodash": "^4.17.12", "mute-stream": "0.0.7", "run-async": "^2.2.0", "rxjs": "^6.4.0", "string-width": "^2.1.0", "strip-ansi": "^5.1.0", "through": "^2.3.6" }, "dependencies": { "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { "ansi-regex": "^4.1.0" } } } }, "invert-kv": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", "dev": true }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, "is-buffer": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==", "dev": true }, "is-callable": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", "dev": true }, "is-date-object": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", "dev": true }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, "is-promise": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", "dev": true }, "is-regex": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", "dev": true, "requires": { "has": "^1.0.1" } }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, "is-symbol": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", "dev": true, "requires": { "has-symbols": "^1.0.0" } }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true }, "js-yaml": { "version": "3.13.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", "dev": true, "requires": { "argparse": "^1.0.7", "esprima": "^4.0.0" } }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, "json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, "lcid": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", "dev": true, "requires": { "invert-kv": "^2.0.0" } }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", "dev": true, "requires": { "prelude-ls": "~1.1.2", "type-check": "~0.3.2" } }, "load-json-file": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", "dev": true, "requires": { "graceful-fs": "^4.1.2", "parse-json": "^2.2.0", "pify": "^2.0.0", "strip-bom": "^3.0.0" } }, "locate-path": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", "dev": true, "requires": { "p-locate": "^2.0.0", "path-exists": "^3.0.0" } }, "lodash": { "version": "4.17.15", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "dev": true }, "log-symbols": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", "dev": true, "requires": { "chalk": "^2.0.1" } }, "map-age-cleaner": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", "dev": true, "requires": { "p-defer": "^1.0.0" } }, "mem": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", "dev": true, "requires": { "map-age-cleaner": "^0.1.1", "mimic-fn": "^2.0.0", "p-is-promise": "^2.0.0" }, "dependencies": { "mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true } } }, "mimic-fn": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", "dev": true }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true }, "mkdirp": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "requires": { "minimist": "0.0.8" } }, "mocha": { "version": "6.1.4", "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.1.4.tgz", "integrity": "sha512-PN8CIy4RXsIoxoFJzS4QNnCH4psUCPWc4/rPrst/ecSJJbLBkubMiyGCP2Kj/9YnWbotFqAoeXyXMucj7gwCFg==", "dev": true, "requires": { "ansi-colors": "3.2.3", "browser-stdout": "1.3.1", "debug": "3.2.6", "diff": "3.5.0", "escape-string-regexp": "1.0.5", "find-up": "3.0.0", "glob": "7.1.3", "growl": "1.10.5", "he": "1.2.0", "js-yaml": "3.13.1", "log-symbols": "2.2.0", "minimatch": "3.0.4", "mkdirp": "0.5.1", "ms": "2.1.1", "node-environment-flags": "1.0.5", "object.assign": "4.1.0", "strip-json-comments": "2.0.1", "supports-color": "6.0.0", "which": "1.3.1", "wide-align": "1.1.3", "yargs": "13.2.2", "yargs-parser": "13.0.0", "yargs-unparser": "1.5.0" }, "dependencies": { "debug": { "version": "3.2.6", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "dev": true, "requires": { "ms": "^2.1.1" } }, "find-up": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, "requires": { "locate-path": "^3.0.0" } }, "locate-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, "requires": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "p-limit": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", "dev": true, "requires": { "p-try": "^2.0.0" } }, "p-locate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, "requires": { "p-limit": "^2.0.0" } }, "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, "supports-color": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "dev": true, "requires": { "has-flag": "^3.0.0" } } } }, "ms": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", "dev": true }, "mute-stream": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", "dev": true }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, "node-environment-flags": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", "integrity": "sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==", "dev": true, "requires": { "object.getownpropertydescriptors": "^2.0.3", "semver": "^5.7.0" }, "dependencies": { "semver": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", "dev": true } } }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, "requires": { "hosted-git-info": "^2.1.4", "resolve": "^1.10.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" }, "dependencies": { "semver": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", "dev": true } } }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, "requires": { "path-key": "^2.0.0" } }, "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true }, "object.assign": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", "dev": true, "requires": { "define-properties": "^1.1.2", "function-bind": "^1.1.1", "has-symbols": "^1.0.0", "object-keys": "^1.0.11" } }, "object.getownpropertydescriptors": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", "dev": true, "requires": { "define-properties": "^1.1.2", "es-abstract": "^1.5.1" } }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { "wrappy": "1" } }, "onetime": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", "dev": true, "requires": { "mimic-fn": "^1.0.0" } }, "optionator": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", "dev": true, "requires": { "deep-is": "~0.1.3", "fast-levenshtein": "~2.0.4", "levn": "~0.3.0", "prelude-ls": "~1.1.2", "type-check": "~0.3.2", "wordwrap": "~1.0.0" } }, "os-locale": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", "dev": true, "requires": { "execa": "^1.0.0", "lcid": "^2.0.0", "mem": "^4.0.0" } }, "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, "p-defer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", "dev": true }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", "dev": true }, "p-is-promise": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", "dev": true }, "p-limit": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", "dev": true, "requires": { "p-try": "^1.0.0" } }, "p-locate": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", "dev": true, "requires": { "p-limit": "^1.1.0" } }, "p-try": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", "dev": true }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, "requires": { "callsites": "^3.0.0" } }, "parse-json": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", "dev": true, "requires": { "error-ex": "^1.2.0" } }, "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", "dev": true }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, "path-is-inside": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", "dev": true }, "path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", "dev": true }, "path-parse": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", "dev": true }, "path-type": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", "dev": true, "requires": { "pify": "^2.0.0" } }, "pathval": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", "dev": true }, "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true }, "pkg-dir": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", "dev": true, "requires": { "find-up": "^2.1.0" } }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", "dev": true }, "prettier": { "version": "1.17.0", "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.17.0.tgz", "integrity": "sha512-sXe5lSt2WQlCbydGETgfm1YBShgOX4HxQkFPvbxkcwgDvGDeqVau8h+12+lmSVlP3rHPz0oavfddSZg/q+Szjw==", "dev": true }, "prettier-linter-helpers": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", "dev": true, "requires": { "fast-diff": "^1.1.2" } }, "progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, "read-pkg": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", "dev": true, "requires": { "load-json-file": "^2.0.0", "normalize-package-data": "^2.3.2", "path-type": "^2.0.0" } }, "read-pkg-up": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", "dev": true, "requires": { "find-up": "^2.0.0", "read-pkg": "^2.0.0" } }, "regexpp": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", "dev": true }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "dev": true }, "require-main-filename": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "dev": true }, "resolve": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", "dev": true, "requires": { "path-parse": "^1.0.6" } }, "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, "restore-cursor": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", "dev": true, "requires": { "onetime": "^2.0.0", "signal-exit": "^3.0.2" } }, "rimraf": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "dev": true, "requires": { "glob": "^7.1.3" } }, "run-async": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", "dev": true, "requires": { "is-promise": "^2.1.0" } }, "rxjs": { "version": "6.5.3", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", "dev": true, "requires": { "tslib": "^1.9.0" } }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, "semver": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.0.0.tgz", "integrity": "sha512-0UewU+9rFapKFnlbirLi3byoOuhrSsli/z/ihNnvM24vgF+8sNBiI1LZPBSH9wJKUwaUbw+s3hToDLCXkrghrQ==", "dev": true }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { "shebang-regex": "^1.0.0" } }, "shebang-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, "slice-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", "dev": true, "requires": { "ansi-styles": "^3.2.0", "astral-regex": "^1.0.0", "is-fullwidth-code-point": "^2.0.0" } }, "spdx-correct": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" } }, "spdx-exceptions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", "dev": true }, "spdx-expression-parse": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", "dev": true, "requires": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "spdx-license-ids": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz", "integrity": "sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==", "dev": true }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^4.0.0" } }, "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { "ansi-regex": "^3.0.0" } }, "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true }, "strip-eof": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { "has-flag": "^3.0.0" } }, "table": { "version": "5.4.6", "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", "dev": true, "requires": { "ajv": "^6.10.2", "lodash": "^4.17.14", "slice-ansi": "^2.1.0", "string-width": "^3.0.0" }, "dependencies": { "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, "requires": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^5.1.0" } }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { "ansi-regex": "^4.1.0" } } } }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, "requires": { "os-tmpdir": "~1.0.2" } }, "tslib": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", "dev": true }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", "dev": true, "requires": { "prelude-ls": "~1.1.2" } }, "type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true }, "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", "dev": true, "requires": { "punycode": "^2.1.0" } }, "validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, "requires": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" } }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { "isexe": "^2.0.0" } }, "which-module": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, "wide-align": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", "dev": true, "requires": { "string-width": "^1.0.2 || 2" } }, "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", "dev": true }, "wrap-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "dev": true, "requires": { "string-width": "^1.0.1", "strip-ansi": "^3.0.1" }, "dependencies": { "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true }, "is-fullwidth-code-point": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "requires": { "number-is-nan": "^1.0.0" } }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", "strip-ansi": "^3.0.0" } }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { "ansi-regex": "^2.0.0" } } } }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, "write": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", "dev": true, "requires": { "mkdirp": "^0.5.1" } }, "y18n": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", "dev": true }, "yargs": { "version": "13.2.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.2.tgz", "integrity": "sha512-WyEoxgyTD3w5XRpAQNYUB9ycVH/PQrToaTXdYXRdOXvEy1l19br+VJsc0vcO8PTGg5ro/l/GY7F/JMEBmI0BxA==", "dev": true, "requires": { "cliui": "^4.0.0", "find-up": "^3.0.0", "get-caller-file": "^2.0.1", "os-locale": "^3.1.0", "require-directory": "^2.1.1", "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", "string-width": "^3.0.0", "which-module": "^2.0.0", "y18n": "^4.0.0", "yargs-parser": "^13.0.0" }, "dependencies": { "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, "find-up": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, "requires": { "locate-path": "^3.0.0" } }, "locate-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, "requires": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "p-limit": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", "dev": true, "requires": { "p-try": "^2.0.0" } }, "p-locate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, "requires": { "p-limit": "^2.0.0" } }, "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, "requires": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^5.1.0" } }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { "ansi-regex": "^4.1.0" } } } }, "yargs-parser": { "version": "13.0.0", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.0.0.tgz", "integrity": "sha512-w2LXjoL8oRdRQN+hOyppuXs+V/fVAYtpcrRxZuF7Kt/Oc+Jr2uAcVntaUTNT6w5ihoWfFDpNY8CPx1QskxZ/pw==", "dev": true, "requires": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" } }, "yargs-unparser": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.5.0.tgz", "integrity": "sha512-HK25qidFTCVuj/D1VfNiEndpLIeJN78aqgR23nL3y4N0U/91cOAzqfHlF8n2BvoNDcZmJKin3ddNSvOxSr8flw==", "dev": true, "requires": { "flat": "^4.1.0", "lodash": "^4.17.11", "yargs": "^12.0.5" }, "dependencies": { "find-up": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, "requires": { "locate-path": "^3.0.0" } }, "get-caller-file": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", "dev": true }, "locate-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, "requires": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "p-limit": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", "dev": true, "requires": { "p-try": "^2.0.0" } }, "p-locate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, "requires": { "p-limit": "^2.0.0" } }, "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, "require-main-filename": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", "dev": true }, "yargs": { "version": "12.0.5", "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", "dev": true, "requires": { "cliui": "^4.0.0", "decamelize": "^1.2.0", "find-up": "^3.0.0", "get-caller-file": "^1.0.1", "os-locale": "^3.0.0", "require-directory": "^2.1.1", "require-main-filename": "^1.0.1", "set-blocking": "^2.0.0", "string-width": "^2.0.0", "which-module": "^2.0.0", "y18n": "^3.2.1 || ^4.0.0", "yargs-parser": "^11.1.1" } }, "yargs-parser": { "version": "11.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", "dev": true, "requires": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" } } } } } } mock-fs-4.10.4/package.json000066400000000000000000000017001356713366300154400ustar00rootroot00000000000000{ "name": "mock-fs", "description": "A configurable mock file system. You know, for testing.", "version": "4.10.4", "main": "lib/index.js", "homepage": "https://github.com/tschaub/mock-fs", "author": { "name": "Tim Schaub", "url": "http://tschaub.net/" }, "keywords": [ "mock", "fs", "test", "fixtures", "file system", "memory" ], "repository": { "type": "git", "url": "git://github.com/tschaub/mock-fs.git" }, "bugs": { "url": "https://github.com/tschaub/mock-fs/issues" }, "license": "MIT", "files": [ "lib" ], "scripts": { "lint": "eslint benchmarks lib test", "pretest": "npm run lint", "test": "mocha --recursive test" }, "eslintConfig": { "extends": "tschaub" }, "devDependencies": { "chai": "^4.2.0", "eslint": "^5.16.0", "eslint-config-tschaub": "^13.1.0", "mocha": "^6.1.4", "rimraf": "^2.6.3", "semver": "^6.0.0" } } mock-fs-4.10.4/readme.md000066400000000000000000000244321356713366300147400ustar00rootroot00000000000000# `mock-fs` The `mock-fs` module allows Node's built-in [`fs` module](http://nodejs.org/api/fs.html) to be backed temporarily by an in-memory, mock file system. This lets you run tests against a set of mock files and directories instead of lugging around a bunch of test fixtures. ## Example The code below makes it so the `fs` module is temporarily backed by a mock file system with a few files and directories. ```js const mock = require('mock-fs'); mock({ 'path/to/fake/dir': { 'some-file.txt': 'file content here', 'empty-dir': {/** empty directory */} }, 'path/to/some.png': Buffer.from([8, 6, 7, 5, 3, 0, 9]), 'some/other/path': {/** another empty directory */} }); ``` When you are ready to restore the `fs` module (so that it is backed by your real file system), call [`mock.restore()`](#mockrestore). Note that calling this may be **mandatory** in some cases. See [istanbuljs/nyc#324](https://github.com/istanbuljs/nyc/issues/324#issuecomment-234018654) ```js // after a test runs mock.restore(); ``` ## Upgrading to version 4 Instead of overriding all methods of the built-in `fs` module, the library now overrides `process.binding('fs')`. The purpose of this change is to avoid conflicts with other libraries that override `fs` methods (e.g. `graceful-fs`) and to make it possible to work with multiple Node releases without maintaining copied and slightly modified versions of Node's `fs` module. Breaking changes: * The `mock.fs()` function has been removed. This returned an object with `fs`-like methods without overriding the built-in `fs` module. * The object created by `fs.Stats` is no longer an instance of `fs.Stats` (though it has all the same properties and methods). * Lazy `require()` do not use the real filesystem. * Tests are no longer run in Node < 4. Some of these breaking changes may be restored in a future release. ## Docs ### `mock(config, options)` Configure the `fs` module so it is backed by an in-memory file system. Calling `mock` sets up a mock file system with two directories by default: `process.cwd()` and `os.tmpdir()` (or `os.tmpDir()` for older Node). When called with no arguments, just these two directories are created. When called with a `config` object, additional files, directories, and symlinks are created. To avoid creating a directory for `process.cwd()` and `os.tmpdir()`, see the [`options`](#options) below. Property names of the `config` object are interpreted as relative paths to resources (relative from `process.cwd()`). Property values of the `config` object are interpreted as content or configuration for the generated resources. *Note that paths should always use forward slashes (`/`) - even on Windows.* ### `options` The second (optional) argument may include the properties below. * `createCwd` - `boolean` Create a directory for `process.cwd()`. This is `true` by default. * `createTmp` - `boolean` Create a directory for `os.tmpdir()`. This is `true` by default. ### Creating files When `config` property values are a `string` or `Buffer`, a file is created with the provided content. For example, the following configuration creates a single file with string content (in addition to the two default directories). ```js mock({ 'path/to/file.txt': 'file content here' }); ``` To create a file with additional properties (owner, permissions, atime, etc.), use the [`mock.file()`](#mockfileproperties) function described below. ### `mock.file(properties)` Create a factory for new files. Supported properties: * **content** - `string|Buffer` File contents. * **mode** - `number` File mode (permission and sticky bits). Defaults to `0666`. * **uid** - `number` The user id. Defaults to `process.getuid()`. * **gid** - `number` The group id. Defaults to `process.getgid()`. * **atime** - `Date` The last file access time. Defaults to `new Date()`. Updated when file contents are accessed. * **ctime** - `Date` The last file change time. Defaults to `new Date()`. Updated when file owner or permissions change. * **mtime** - `Date` The last file modification time. Defaults to `new Date()`. Updated when file contents change. * **birthtime** - `Date` The time of file creation. Defaults to `new Date()`. To create a mock filesystem with a very old file named `foo`, you could do something like this: ```js mock({ foo: mock.file({ content: 'file content here', ctime: new Date(1), mtime: new Date(1) }) }); ``` Note that if you want to create a file with the default properties, you can provide a `string` or `Buffer` directly instead of calling `mock.file()`. ### Creating directories When `config` property values are an `Object`, a directory is created. The structure of the object is the same as the `config` object itself. So an empty directory can be created with a simple object literal (`{}`). The following configuration creates a directory containing two files (in addition to the two default directories): ```js // note that this could also be written as // mock({'path/to/dir': { /** config */ }}) mock({ path: { to: { dir: { file1: 'text content', file2: Buffer.from([1, 2, 3, 4]) } } } }); ``` To create a directory with additional properties (owner, permissions, atime, etc.), use the [`mock.directory()`](mockdirectoryproperties) function described below. ### `mock.directory(properties)` Create a factory for new directories. Supported properties: * **mode** - `number` Directory mode (permission and sticky bits). Defaults to `0777`. * **uid** - `number` The user id. Defaults to `process.getuid()`. * **gid** - `number` The group id. Defaults to `process.getgid()`. * **atime** - `Date` The last directory access time. Defaults to `new Date()`. * **ctime** - `Date` The last directory change time. Defaults to `new Date()`. Updated when owner or permissions change. * **mtime** - `Date` The last directory modification time. Defaults to `new Date()`. Updated when an item is added, removed, or renamed. * **birthtime** - `Date` The time of directory creation. Defaults to `new Date()`. * **items** - `Object` Directory contents. Members will generate additional files, directories, or symlinks. To create a mock filesystem with a directory with the relative path `some/dir` that has a mode of `0755` and two child files, you could do something like this: ```js mock({ 'some/dir': mock.directory({ mode: 0755, items: { file1: 'file one content', file2: Buffer.from([8, 6, 7, 5, 3, 0, 9]) } }) }); ``` Note that if you want to create a directory with the default properties, you can provide an `Object` directly instead of calling `mock.directory()`. ### Creating symlinks Using a `string` or a `Buffer` is a shortcut for creating files with default properties. Using an `Object` is a shortcut for creating a directory with default properties. There is no shortcut for creating symlinks. To create a symlink, you need to call the [`mock.symlink()`](#mocksymlinkproperties) function described below. ### `mock.symlink(properties)` Create a factory for new symlinks. Supported properties: * **path** - `string` Path to the source (required). * **mode** - `number` Symlink mode (permission and sticky bits). Defaults to `0666`. * **uid** - `number` The user id. Defaults to `process.getuid()`. * **gid** - `number` The group id. Defaults to `process.getgid()`. * **atime** - `Date` The last symlink access time. Defaults to `new Date()`. * **ctime** - `Date` The last symlink change time. Defaults to `new Date()`. * **mtime** - `Date` The last symlink modification time. Defaults to `new Date()`. * **birthtime** - `Date` The time of symlink creation. Defaults to `new Date()`. To create a mock filesystem with a file and a symlink, you could do something like this: ```js mock({ 'some/dir': { 'regular-file': 'file contents', 'a-symlink': mock.symlink({ path: 'regular-file' }) } }); ``` ### Restoring the file system ### `mock.restore()` Restore the `fs` binding to the real file system. This undoes the effect of calling `mock()`. Typically, you would set up a mock file system before running a test and restore the original after. Using a test runner with `beforeEach` and `afterEach` hooks, this might look like the following: ```js beforeEach(function() { mock({ 'fake-file': 'file contents' }); }); afterEach(mock.restore); ``` ## Install Using `npm`: ``` npm install mock-fs --save-dev ``` ## Caveats When you require `mock-fs`, Node's own `fs` module is patched to allow the binding to the underlying file system to be swapped out. If you require `mock-fs` *before* any other modules that modify `fs` (e.g. `graceful-fs`), the mock should behave as expected. **Note** `mock-fs` is not compatible with `graceful-fs@3.x` but works with `graceful-fs@4.x`. Mock `fs.Stats` objects have the following properties: `dev`, `ino`, `nlink`, `mode`, `size`, `rdev`, `blksize`, `blocks`, `atime`, `ctime`, `mtime`, `birthtime`, `uid`, and `gid`. In addition, all of the `is*()` method are provided (e.g. `isDirectory()`, `isFile()`, et al.). Mock file access is controlled based on file mode where `process.getuid()` and `process.getgid()` are available (POSIX systems). On other systems (e.g. Windows) the file mode has no effect. Tested on Linux, OSX, and Windows using Node 6 through 11. Check the tickets for a list of [known issues](https://github.com/tschaub/mock-fs/issues). ### Using with Jest Snapshot Testing `.toMatchSnapshot` in [Jest](https://jestjs.io/docs/en/snapshot-testing) uses `fs` to load existing snapshots. If `mockFs` is active, Jest isn't able to load existing snapshots. In such case it accepts all snapshots without diffing the old ones, which breaks the concept of snapshot testing. Calling `mock.restore()` in `afterEach` is too late and it's necessary to call it before snapshot matching: ```js const actual = testedFunction() mock.restore() expect(actual).toMatchSnapshot() ``` Note: it's safe to call `mock.restore` multiple times, so it can still be called in `afterEach` and then manually in test cases which use snapshot testing. [![Current Status](https://secure.travis-ci.org/tschaub/mock-fs.png?branch=master)](https://travis-ci.org/tschaub/mock-fs) mock-fs-4.10.4/test/000077500000000000000000000000001356713366300141335ustar00rootroot00000000000000mock-fs-4.10.4/test/.eslintrc000066400000000000000000000000451356713366300157560ustar00rootroot00000000000000{ "env": { "mocha": true } } mock-fs-4.10.4/test/helper.js000066400000000000000000000046341356713366300157570ustar00rootroot00000000000000'use strict'; const chai = require('chai'); const constants = require('constants'); const semver = require('semver'); const fs = require('fs'); const hasPromise = !!fs.promises; /** @type {boolean} */ chai.config.includeStack = true; /** * Chai's assert function configured to include stacks on failure. * @type {function} */ exports.assert = chai.assert; const TEST = {it: it, xit: xit, describe: describe, xdescribe: xdescribe}; const NO_TEST = {it: xit, xit: xit, describe: xdescribe, xdescribe: xdescribe}; exports.inVersion = function(range) { if (semver.satisfies(process.version, range)) { return TEST; } else { return NO_TEST; } }; exports.withPromise = hasPromise ? TEST : NO_TEST; /** * Convert a string to flags for fs.open. * @param {string} str String. * @return {number} Flags. */ exports.flags = function(str) { switch (str) { case 'r': return constants.O_RDONLY; case 'rs': return constants.O_RDONLY | constants.O_SYNC; case 'r+': return constants.O_RDWR; case 'rs+': return constants.O_RDWR | constants.O_SYNC; case 'w': return constants.O_TRUNC | constants.O_CREAT | constants.O_WRONLY; case 'wx': // fall through case 'xw': return ( constants.O_TRUNC | constants.O_CREAT | constants.O_WRONLY | constants.O_EXCL ); case 'w+': return constants.O_TRUNC | constants.O_CREAT | constants.O_RDWR; case 'wx+': // fall through case 'xw+': return ( constants.O_TRUNC | constants.O_CREAT | constants.O_RDWR | constants.O_EXCL ); case 'a': return constants.O_APPEND | constants.O_CREAT | constants.O_WRONLY; case 'ax': // fall through case 'xa': return ( constants.O_APPEND | constants.O_CREAT | constants.O_WRONLY | constants.O_EXCL ); case 'a+': return constants.O_APPEND | constants.O_CREAT | constants.O_RDWR; case 'ax+': // fall through case 'xa+': return ( constants.O_APPEND | constants.O_CREAT | constants.O_RDWR | constants.O_EXCL ); default: throw new Error('Unsupported flag: ' + str); } }; exports.assertEqualPaths = function(actual, expected) { if (process.platform === 'win32') { chai.assert.equal(actual.toLowerCase(), expected.toLowerCase()); } else { chai.assert(actual, expected); } }; mock-fs-4.10.4/test/integration/000077500000000000000000000000001356713366300164565ustar00rootroot00000000000000mock-fs-4.10.4/test/integration/filecount.js000066400000000000000000000015641356713366300210120ustar00rootroot00000000000000'use strict'; const fs = require('fs'); const path = require('path'); function numFiles(dir, items, callback) { const total = items.length; let files = 0; let completed = 0; if (total === 0) { callback(null, 0); } items.forEach(function(item) { fs.stat(path.join(dir, item), function(err, stats) { if (err) { return callback(err); } if (stats && stats.isFile()) { ++files; } ++completed; if (completed === total) { callback(null, files); } }); }); } /** * Count the number of files in a directory. * @param {string} dir Path to directory. * @param {function(Error, number)} callback Callback. */ module.exports = exports = function(dir, callback) { fs.readdir(dir, function(err, items) { if (err) { return callback(err); } numFiles(dir, items, callback); }); }; mock-fs-4.10.4/test/integration/filecount.spec.js000066400000000000000000000024721356713366300217420ustar00rootroot00000000000000/* eslint-env mocha */ 'use strict'; const mock = require('../../lib/index'); const assert = require('../helper').assert; const count = require('./filecount'); describe('count(dir, callback)', function() { beforeEach(function() { mock({ 'path/to/dir': { 'one.txt': 'first file', 'two.txt': 'second file', 'empty-dir': {}, 'another-dir': { 'another.txt': 'more files' } } }); }); afterEach(mock.restore); it('counts files in a directory', function(done) { count('path/to/dir', function(err, num) { if (err) { return done(err); } assert.equal(num, 2); done(); }); }); it('counts files in another directory', function(done) { count('path/to/dir/another-dir', function(err, num) { if (err) { return done(err); } assert.equal(num, 1); done(); }); }); it('counts files in an empty directory', function(done) { count('path/to/dir/empty-dir', function(err, num) { if (err) { return done(err); } assert.equal(num, 0); done(); }); }); it('fails for bogus path', function(done) { count('path/to/dir/bogus', function(err, num) { assert.instanceOf(err, Error); assert.isUndefined(num); done(); }); }); }); mock-fs-4.10.4/test/lib/000077500000000000000000000000001356713366300147015ustar00rootroot00000000000000mock-fs-4.10.4/test/lib/binding.spec.js000066400000000000000000001573031356713366300176130ustar00rootroot00000000000000'use strict'; const path = require('path'); const Binding = require('../../lib/binding'); const Directory = require('../../lib/directory'); const SymbolicLink = require('../../lib/symlink'); const File = require('../../lib/file'); const FileSystem = require('../../lib/filesystem'); const helper = require('../helper'); const constants = require('constants'); const bufferFrom = require('../../lib/buffer').from; const bufferAlloc = require('../../lib/buffer').alloc; const assert = helper.assert; const assertEqualPaths = helper.assertEqualPaths; const flags = helper.flags; describe('Binding', function() { let system; beforeEach(function() { system = FileSystem.create({ 'mock-dir': { 'one.txt': 'one content', 'two.txt': FileSystem.file({ content: 'two content', mode: parseInt('0644', 8), atime: new Date(1), ctime: new Date(2), mtime: new Date(3), birthtime: new Date(4) }), 'one-link.txt': FileSystem.symlink({path: './one.txt'}), 'one-link2.txt': FileSystem.symlink({path: './one-link.txt'}), 'three.bin': bufferFrom([1, 2, 3]), empty: {}, 'non-empty': { 'a.txt': FileSystem.file({ content: 'a content', mode: parseInt('0644', 8), atime: new Date(1), ctime: new Date(2), mtime: new Date(3), birthtime: new Date(4) }), 'b.txt': 'b content' }, 'dir-link': FileSystem.symlink({path: './non-empty'}), 'dir-link2': FileSystem.symlink({path: './dir-link'}), 'dead-link': FileSystem.symlink({path: './non-a-real-file'}) } }); }); describe('constructor', function() { it('creates a new instance', function() { const binding = new Binding(system); assert.instanceOf(binding, Binding); }); }); describe('#getSystem()', function() { const binding = new Binding(system); assert.equal(binding.getSystem(), system); }); describe('#setSystem()', function() { const firstSystem = new FileSystem(); const binding = new Binding(firstSystem); assert.equal(binding.getSystem(), firstSystem); binding.setSystem(system); assert.equal(binding.getSystem(), system); }); describe('#Stats', function() { it('is a stats constructor', function() { const binding = new Binding(system); assert.isFunction(binding.Stats); }); }); describe('#stat()', function() { it('calls callback with a Stats instance', function(done) { const binding = new Binding(system); binding.stat(path.join('mock-dir', 'one.txt'), function(err, stats) { if (err) { return done(err); } assert.instanceOf(stats, binding.Stats); done(); }); }); it('returns a Stats instance when called synchronously', function() { const binding = new Binding(system); const stats = binding.stat(path.join('mock-dir', 'one.txt')); assert.instanceOf(stats, binding.Stats); }); it('identifies files (async)', function(done) { const binding = new Binding(system); binding.stat(path.join('mock-dir', 'one.txt'), function(err, stats) { if (err) { return done(err); } assert.equal(stats.mode & constants.S_IFMT, constants.S_IFREG); done(); }); }); it('identifies files (sync)', function() { const binding = new Binding(system); const stats = binding.stat(path.join('mock-dir', 'one.txt')); assert.equal(stats.mode & constants.S_IFMT, constants.S_IFREG); }); it('identifies directories (async)', function(done) { const binding = new Binding(system); binding.stat('mock-dir', function(err, stats) { if (err) { return done(err); } assert.equal(stats.mode & constants.S_IFMT, constants.S_IFDIR); done(); }); }); it('identifies directories (sync)', function() { const binding = new Binding(system); const stats = binding.stat('mock-dir'); assert.equal(stats.mode & constants.S_IFMT, constants.S_IFDIR); }); it('includes atime, ctime, mtime and birthtime', function(done) { const binding = new Binding(system); binding.stat(path.join('mock-dir', 'two.txt'), function(err, stats) { if (err) { return done(err); } assert.equal(stats.atime.getTime(), new Date(1).getTime()); assert.equal(stats.ctime.getTime(), new Date(2).getTime()); assert.equal(stats.mtime.getTime(), new Date(3).getTime()); assert.equal(stats.birthtime.getTime(), new Date(4).getTime()); done(); }); }); it('includes mode with file permissions (default)', function(done) { const binding = new Binding(system); binding.stat(path.join('mock-dir', 'one.txt'), function(err, stats) { if (err) { return done(err); } assert.equal(stats.mode & parseInt('0777', 8), parseInt('0666', 8)); done(); }); }); it('includes mode with file permissions (custom)', function(done) { const binding = new Binding(system); binding.stat(path.join('mock-dir', 'two.txt'), function(err, stats) { if (err) { return done(err); } assert.equal(stats.mode & parseInt('0777', 8), parseInt('0644', 8)); done(); }); }); it('includes size in bytes (async)', function(done) { const binding = new Binding(system); binding.stat(path.join('mock-dir', 'two.txt'), function(err, stats) { if (err) { return done(err); } assert.equal(stats.size, 11); done(); }); }); it('includes size in bytes (sync)', function() { const binding = new Binding(system); const stats = binding.stat(path.join('mock-dir', 'three.bin')); assert.equal(stats.size, 3); }); it('includes non-zero size for directories', function() { const binding = new Binding(system); const stats = binding.stat('mock-dir'); assert.isNumber(stats.size); assert.isTrue(stats.size > 0); }); it('includes uid for files', function() { const binding = new Binding(system); const stats = binding.stat(path.join('mock-dir', 'two.txt')); if (process.getuid) { assert.equal(stats.uid, process.getuid()); } }); it('includes uid for directories', function() { const binding = new Binding(system); const stats = binding.stat(path.join('mock-dir', 'empty')); if (process.getuid) { assert.equal(stats.uid, process.getuid()); } }); it('includes gid for files', function() { const binding = new Binding(system); const stats = binding.stat(path.join('mock-dir', 'two.txt')); if (process.getgid) { assert.equal(stats.gid, process.getgid()); } }); it('includes gid for directories', function() { const binding = new Binding(system); const stats = binding.stat(path.join('mock-dir', 'empty')); if (process.getgid) { assert.equal(stats.gid, process.getgid()); } }); it('retrieves stats of files relative to symbolic linked directories', function() { const binding = new Binding(system); const stats = binding.stat(path.join('mock-dir', 'dir-link', 'a.txt')); assert.equal(stats.mode & constants.S_IFMT, constants.S_IFREG); assert.equal(stats.mode & 0x1ff, parseInt('0644', 8)); if (process.getuid) { assert.equal(stats.uid, process.getuid()); } if (process.getgid) { assert.equal(stats.gid, process.getgid()); } }); }); describe('#realpath()', function() { it('returns the real path for a regular file', function(done) { const binding = new Binding(system); binding.realpath('mock-dir/one.txt', 'utf-8', function(err, realPath) { if (err) { return done(err); } assertEqualPaths(realPath, path.resolve('mock-dir/one.txt')); done(); }); }); it('returns the real path for a directory', function(done) { const binding = new Binding(system); binding.realpath('mock-dir/empty', 'utf-8', function(err, realPath) { if (err) { return done(err); } assertEqualPaths(realPath, path.resolve('mock-dir/empty')); done(); }); }); it('returns the real path for a symlinked file', function(done) { const binding = new Binding(system); binding.realpath('mock-dir/one-link.txt', 'utf-8', function( err, realPath ) { if (err) { return done(err); } assertEqualPaths(realPath, path.resolve('mock-dir/one.txt')); done(); }); }); it('returns the real path for a deeply symlinked file', function(done) { const binding = new Binding(system); binding.realpath('mock-dir/one-link2.txt', 'utf-8', function( err, realPath ) { if (err) { return done(err); } assertEqualPaths(realPath, path.resolve('mock-dir/one.txt')); done(); }); }); it('returns the real path for a symlinked directory', function(done) { const binding = new Binding(system); binding.realpath('mock-dir/dir-link', 'utf-8', function(err, realPath) { if (err) { return done(err); } assertEqualPaths(realPath, path.resolve('mock-dir/non-empty')); done(); }); }); it('returns the real path for a deeply symlinked directory', function(done) { const binding = new Binding(system); binding.realpath('mock-dir/dir-link2', 'utf-8', function(err, realPath) { if (err) { return done(err); } assertEqualPaths(realPath, path.resolve('mock-dir/non-empty')); done(); }); }); it('returns the real path for a file in a symlinked directory', function(done) { const binding = new Binding(system); binding.realpath('mock-dir/dir-link/b.txt', 'utf-8', function( err, realPath ) { if (err) { return done(err); } assertEqualPaths(realPath, path.resolve('mock-dir/non-empty/b.txt')); done(); }); }); it('accepts a buffer', function(done) { const binding = new Binding(system); binding.realpath(bufferFrom('mock-dir/one.txt'), 'utf-8', function( err, realPath ) { if (err) { return done(err); } assertEqualPaths(realPath, path.resolve('mock-dir/one.txt')); done(); }); }); it('can return a buffer', function(done) { const binding = new Binding(system); binding.realpath('mock-dir/one.txt', 'buffer', function(err, realPath) { if (err) { return done(err); } assert.equal(Buffer.isBuffer(realPath), true); assertEqualPaths(realPath.toString(), path.resolve('mock-dir/one.txt')); done(); }); }); it('throws ENOENT for a non-existent file', function(done) { const binding = new Binding(system); binding.realpath('mock-dir/bogus-path', 'utf-8', function(err, realPath) { if (!err || realPath) { return done(new Error('Expected ENOENT')); } assert.equal(err.code, 'ENOENT'); done(); }); }); it('throws ENOTDIR for a file treated like a directory', function(done) { const binding = new Binding(system); binding.realpath('mock-dir/one.txt/foo', 'utf-8', function( err, realPath ) { if (!err || realPath) { return done(new Error('Expected ENOTDIR')); } assert.equal(err.code, 'ENOTDIR'); done(); }); }); }); describe('#fstat()', function() { it('calls callback with a Stats instance', function(done) { const binding = new Binding(system); const fd = binding.open(path.join('mock-dir', 'one.txt'), flags('r')); binding.fstat(fd, function(err, stats) { if (err) { return done(err); } assert.instanceOf(stats, binding.Stats); done(); }); }); it('returns a Stats instance when called synchronously', function() { const binding = new Binding(system); const fd = binding.open(path.join('mock-dir', 'one.txt'), flags('r')); const stats = binding.fstat(fd); assert.instanceOf(stats, binding.Stats); }); it('identifies files (async)', function(done) { const binding = new Binding(system); const fd = binding.open(path.join('mock-dir', 'one.txt'), flags('r')); binding.fstat(fd, function(err, stats) { if (err) { return done(err); } assert.equal(stats.mode & constants.S_IFMT, constants.S_IFREG); done(); }); }); it('identifies directories (async)', function(done) { const binding = new Binding(system); const fd = binding.open('mock-dir', flags('r')); binding.fstat(fd, function(err, stats) { if (err) { return done(err); } assert.equal(stats.mode & constants.S_IFMT, constants.S_IFDIR); done(); }); }); it('includes size in bytes (async)', function(done) { const binding = new Binding(system); const fd = binding.open(path.join('mock-dir', 'two.txt'), flags('r')); binding.fstat(fd, function(err, stats) { if (err) { return done(err); } assert.equal(stats.size, 11); done(); }); }); it('includes size in bytes (sync)', function() { const binding = new Binding(system); const fd = binding.open(path.join('mock-dir', 'three.bin'), flags('r')); const stats = binding.fstat(fd); assert.equal(stats.size, 3); }); it('includes non-zero size for directories', function() { const binding = new Binding(system); const fd = binding.open('mock-dir', flags('r')); const stats = binding.fstat(fd); assert.isNumber(stats.size); assert.isTrue(stats.size > 0); }); }); describe('#readdir()', function() { it('calls callback with file list', function(done) { const binding = new Binding(system); binding.readdir('mock-dir', function(err, items) { assert.isNull(err); assert.isArray(items); assert.deepEqual(items.sort(), [ 'dead-link', 'dir-link', 'dir-link2', 'empty', 'non-empty', 'one-link.txt', 'one-link2.txt', 'one.txt', 'three.bin', 'two.txt' ]); done(); }); }); it('accepts "buffer" encoding', function(done) { const binding = new Binding(system); binding.readdir('mock-dir', 'buffer', function(err, items) { assert.isNull(err); assert.isArray(items); items.forEach(function(item) { assert.equal(Buffer.isBuffer(item), true); }); const strings = items.map(function(item) { return item.toString(); }); assert.deepEqual(strings.sort(), [ 'dead-link', 'dir-link', 'dir-link2', 'empty', 'non-empty', 'one-link.txt', 'one-link2.txt', 'one.txt', 'three.bin', 'two.txt' ]); done(); }); }); it('returns a file list (sync)', function() { const binding = new Binding(system); const items = binding.readdir('mock-dir'); assert.isArray(items); assert.deepEqual(items.sort(), [ 'dead-link', 'dir-link', 'dir-link2', 'empty', 'non-empty', 'one-link.txt', 'one-link2.txt', 'one.txt', 'three.bin', 'two.txt' ]); }); it('calls callback with file list for symbolic linked dir', function(done) { const binding = new Binding(system); binding.readdir(path.join('mock-dir', 'dir-link'), function(err, items) { assert.isNull(err); assert.isArray(items); assert.deepEqual(items.sort(), ['a.txt', 'b.txt']); done(); }); }); it('calls callback with file list for link to symbolic linked dir', function(done) { const binding = new Binding(system); binding.readdir(path.join('mock-dir', 'dir-link2'), function(err, items) { assert.isNull(err); assert.isArray(items); assert.deepEqual(items.sort(), ['a.txt', 'b.txt']); done(); }); }); it('calls callback with file list for symbolic linked dir (sync)', function() { const binding = new Binding(system); const items = binding.readdir(path.join('mock-dir', 'dir-link')); assert.isArray(items); assert.deepEqual(items.sort(), ['a.txt', 'b.txt']); }); it('calls callback with error for bogus dir', function(done) { const binding = new Binding(system); binding.readdir('bogus', function(err, items) { assert.instanceOf(err, Error); assert.isUndefined(items); done(); }); }); it('calls callback with error for file path', function(done) { const binding = new Binding(system); binding.readdir(path.join('mock-dir', 'one.txt'), function(err, items) { assert.instanceOf(err, Error); assert.isUndefined(items); done(); }); }); it('calls callback with error for dead symbolic link', function(done) { const binding = new Binding(system); binding.readdir(path.join('mock-dir', 'dead-link'), function(err, items) { assert.instanceOf(err, Error); assert.isUndefined(items); done(); }); }); it('calls callback with error for symbolic link to file', function(done) { const binding = new Binding(system); binding.readdir(path.join('mock-dir', 'one-link.txt'), function( err, items ) { assert.instanceOf(err, Error); assert.isUndefined(items); done(); }); }); it('calls callback with error for link to symbolic link to file', function(done) { const binding = new Binding(system); binding.readdir(path.join('mock-dir', 'one-link2.txt'), function( err, items ) { assert.instanceOf(err, Error); assert.isUndefined(items); done(); }); }); }); describe('#open()', function() { it('creates a file descriptor for reading (r)', function() { const binding = new Binding(system); const fd = binding.open(path.join('mock-dir', 'one.txt'), flags('r')); assert.isNumber(fd); }); it('generates error if file does not exist (r)', function() { const binding = new Binding(system); assert.throws(function() { binding.open('bogus', flags('r')); }); }); it('creates a file descriptor for reading and writing (r+)', function() { const binding = new Binding(system); const fd = binding.open(path.join('mock-dir', 'one.txt'), flags('r+')); assert.isNumber(fd); }); it('does not truncate (r+)', function() { const binding = new Binding(system); binding.open(path.join('mock-dir', 'two.txt'), flags('r+')); const file = system.getItem(path.join('mock-dir', 'two.txt')); assert.instanceOf(file, File); assert.equal(String(file.getContent()), 'two content'); }); it('generates error if file does not exist (r+)', function() { const binding = new Binding(system); assert.throws(function() { binding.open('bogus', flags('r+')); }); }); it('creates a file descriptor for reading (rs)', function() { const binding = new Binding(system); const fd = binding.open(path.join('mock-dir', 'two.txt'), flags('rs')); assert.isNumber(fd); }); it('generates error if file does not exist (rs)', function() { const binding = new Binding(system); assert.throws(function() { binding.open('bogus', flags('rs')); }); }); it('creates a file descriptor for reading and writing (rs+)', function() { const binding = new Binding(system); const fd = binding.open(path.join('mock-dir', 'two.txt'), flags('rs+')); assert.isNumber(fd); }); it('generates error if file does not exist (rs+)', function() { const binding = new Binding(system); assert.throws(function() { binding.open('bogus', flags('rs+')); }); }); it('opens a new file for writing (w)', function() { const binding = new Binding(system); binding.open('new.txt', flags('w'), parseInt('0644', 8)); const file = system.getItem('new.txt'); assert.instanceOf(file, File); assert.equal(file.getMode(), parseInt('0644', 8)); }); it('truncates an existing file for writing (w)', function() { const binding = new Binding(system); binding.open( path.join('mock-dir', 'two.txt'), flags('w'), parseInt('0666', 8) ); const file = system.getItem(path.join('mock-dir', 'two.txt')); assert.instanceOf(file, File); assert.equal(String(file.getContent()), ''); }); it('generates error if file is directory (w)', function() { const binding = new Binding(system); assert.throws(function() { binding.open('mock-dir', flags('w')); }); }); it('generates error if file exists (wx)', function() { const binding = new Binding(system); assert.throws(function() { binding.open(path.join('mock-dir', 'two.txt'), flags('wx')); }); }); it('opens a new file for reading and writing (w+)', function() { const binding = new Binding(system); binding.open('new.txt', flags('w+'), parseInt('0644', 8)); const file = system.getItem('new.txt'); assert.instanceOf(file, File); assert.equal(file.getMode(), parseInt('0644', 8)); assert.equal(String(file.getContent()), ''); }); it('truncates an existing file for writing (w+)', function() { const binding = new Binding(system); binding.open( path.join('mock-dir', 'one.txt'), flags('w+'), parseInt('0666', 8) ); const file = system.getItem(path.join('mock-dir', 'one.txt')); assert.instanceOf(file, File); assert.equal(String(file.getContent()), ''); }); it('opens a new file for reading and writing (wx+)', function() { const binding = new Binding(system); binding.open('new.txt', flags('wx+'), parseInt('0644', 8)); const file = system.getItem('new.txt'); assert.instanceOf(file, File); assert.equal(file.getMode(), parseInt('0644', 8)); assert.equal(String(file.getContent()), ''); }); it('generates error if file exists (wx+)', function() { const binding = new Binding(system); assert.throws(function() { binding.open( path.join('mock-dir', 'one.txt'), flags('wx+'), parseInt('0666', 8) ); }); }); it('opens a new file for appending (a)', function() { const binding = new Binding(system); binding.open('new.txt', flags('a'), parseInt('0666', 8)); const file = system.getItem('new.txt'); assert.instanceOf(file, File); assert.equal(file.getMode(), parseInt('0666', 8)); assert.equal(String(file.getContent()), ''); }); it('opens an existing file for appending (a)', function() { const binding = new Binding(system); binding.open( path.join('mock-dir', 'one.txt'), flags('a'), parseInt('0666', 8) ); const file = system.getItem(path.join('mock-dir', 'one.txt')); assert.instanceOf(file, File); assert.equal(String(file.getContent()), 'one content'); }); it('generates error if file is directory (a)', function() { const binding = new Binding(system); assert.throws(function() { binding.open('mock-dir', flags('a')); }); }); it('opens a new file for appending (ax)', function() { const binding = new Binding(system); binding.open('new.txt', flags('ax'), parseInt('0664', 8)); const file = system.getItem('new.txt'); assert.instanceOf(file, File); assert.equal(file.getMode(), parseInt('0664', 8)); assert.equal(String(file.getContent()), ''); }); it('generates error if file exists (ax)', function() { const binding = new Binding(system); assert.throws(function() { binding.open( path.join('mock-dir', 'one.txt'), flags('ax'), parseInt('0666', 8) ); }); }); it('opens a new file for appending and reading (a+)', function() { const binding = new Binding(system); binding.open('new.txt', flags('a+'), parseInt('0666', 8)); const file = system.getItem('new.txt'); assert.instanceOf(file, File); assert.equal(file.getMode(), parseInt('0666', 8)); assert.equal(String(file.getContent()), ''); }); it('opens an existing file for appending and reading (a+)', function() { const binding = new Binding(system); binding.open( path.join('mock-dir', 'one.txt'), flags('a+'), parseInt('0666', 8) ); const file = system.getItem(path.join('mock-dir', 'two.txt')); assert.instanceOf(file, File); assert.equal(String(file.getContent()), 'two content'); }); it('opens a new file for appending and reading (ax+)', function() { const binding = new Binding(system); binding.open('new.txt', flags('ax+'), parseInt('0666', 8)); const file = system.getItem('new.txt'); assert.instanceOf(file, File); assert.equal(file.getMode(), parseInt('0666', 8)); assert.equal(String(file.getContent()), ''); }); it('opens an existing file for appending and reading (ax+)', function() { const binding = new Binding(system); assert.throws(function() { binding.open( path.join('mock-dir', 'two.txt'), flags('ax+'), parseInt('0666', 8) ); }); }); }); describe('#close()', function() { it('closes an existing file descriptor', function() { const binding = new Binding(system); const fd = binding.open('new.txt', flags('w'), parseInt('0644', 8)); binding.close(fd); }); it('fails for closed file descriptor', function() { const binding = new Binding(system); const fd = binding.open('new.txt', flags('w'), parseInt('0644', 8)); binding.close(fd); assert.throws(function() { binding.close(fd); }); }); }); describe('#read()', function() { it('reads from a file', function() { const binding = new Binding(system); const fd = binding.open(path.join('mock-dir', 'two.txt'), flags('r')); const buffer = bufferAlloc(11); const read = binding.read(fd, buffer, 0, 11, 0); assert.equal(read, 11); assert.equal(String(buffer), 'two content'); }); it('reads into a Uint8Array', function() { const binding = new Binding(system); const fd = binding.open(path.join('mock-dir', 'three.bin'), flags('r')); const buffer = new Uint8Array(3); const read = binding.read(fd, buffer, 0, 3, 0); assert.equal(read, 3); assert.deepEqual(Array.from(buffer), [1, 2, 3]); }); it('interprets null position as current position', function() { const binding = new Binding(system); const fd = binding.open(path.join('mock-dir', 'one.txt'), flags('r')); const buffer = bufferAlloc(4); // chunk 1 assert.equal(binding.read(fd, buffer, 0, 11, null), 4); assert.equal(String(buffer), 'one '); // chunk 2 assert.equal(binding.read(fd, buffer, 0, 11, null), 4); assert.equal(String(buffer), 'cont'); // chunk 3 assert.equal(binding.read(fd, buffer, 0, 11, null), 3); assert.equal(String(buffer.slice(0, 3)), 'ent'); }); it('reads from a symbolic link', function() { const binding = new Binding(system); const fd = binding.open( path.join('mock-dir', 'one-link.txt'), flags('r') ); const buffer = bufferAlloc(11); const read = binding.read(fd, buffer, 0, 11, 0); assert.equal(read, 11); assert.equal(String(buffer), 'one content'); }); it('reads from a deeply linked symlink', function() { const binding = new Binding(system); const fd = binding.open( path.join('mock-dir', 'one-link2.txt'), flags('r') ); const buffer = bufferAlloc(11); const read = binding.read(fd, buffer, 0, 11, 0); assert.equal(read, 11); assert.equal(String(buffer), 'one content'); }); it('throws if not open for reading', function() { const binding = new Binding(system); const fd = binding.open(path.join('mock-dir', 'two.txt'), flags('w')); const buffer = bufferAlloc(11); assert.throws(function() { binding.read(fd, buffer, 0, 11, 0); }); }); it('throws ENOTDIR when trying to open an incorrect path (nested under existing file)', function() { const binding = new Binding(system); assert.throws(function() { binding.open( path.join('mock-dir', 'two.txt', 'bogus-path'), flags('r') ); }, 'ENOTDIR'); }); }); describe('#write()', function() { it('writes to a file', function() { const binding = new Binding(system); const fd = binding.open(path.join('mock-dir', 'new.txt'), flags('w')); const buffer = bufferFrom('new content'); const written = binding.write(fd, buffer, 0, 11, 0); assert.equal(written, 11); const file = system.getItem(path.join('mock-dir', 'new.txt')); assert.instanceOf(file, File); const content = file.getContent(); assert.isTrue(Buffer.isBuffer(content)); assert.equal(String(content), 'new content'); }); it('can take input from a Uint8Array', function() { const binding = new Binding(system); const fd = binding.open(path.join('mock-dir', 'new.txt'), flags('w')); const buffer = Uint8Array.from([1, 2, 3, 4, 5]); const written = binding.write(fd, buffer, 0, 5, 0); assert.equal(written, 5); const file = system.getItem(path.join('mock-dir', 'new.txt')); assert.instanceOf(file, File); const content = file.getContent(); assert.isTrue(Buffer.isBuffer(content)); assert.deepEqual(Array.from(content), [1, 2, 3, 4, 5]); }); it('can overwrite a file', function() { const binding = new Binding(system); const fd = binding.open(path.join('mock-dir', 'one.txt'), flags('w')); const buffer = bufferFrom('bingo'); const written = binding.write(fd, buffer, 0, 5, null); assert.equal(written, 5); const file = system.getItem(path.join('mock-dir', 'one.txt')); assert.instanceOf(file, File); const content = file.getContent(); assert.isTrue(Buffer.isBuffer(content)); assert.equal(String(content), 'bingo'); }); it('can append to a file', function() { const binding = new Binding(system); const fd = binding.open(path.join('mock-dir', 'one.txt'), flags('a')); const buffer = bufferFrom(' more'); const written = binding.write(fd, buffer, 0, 5, null); assert.equal(written, 5); const file = system.getItem(path.join('mock-dir', 'one.txt')); assert.instanceOf(file, File); const content = file.getContent(); assert.isTrue(Buffer.isBuffer(content)); assert.equal(String(content), 'one content more'); }); it('can overwrite part of a file', function() { const binding = new Binding(system); const fd = binding.open(path.join('mock-dir', 'one.txt'), flags('a')); const buffer = bufferFrom('new'); const written = binding.write(fd, buffer, 0, 3, 0); assert.equal(written, 3); const file = system.getItem(path.join('mock-dir', 'one.txt')); assert.instanceOf(file, File); const content = file.getContent(); assert.isTrue(Buffer.isBuffer(content)); assert.equal(String(content), 'new content'); }); it('throws if not open for writing', function() { const binding = new Binding(system); const fd = binding.open(path.join('mock-dir', 'two.txt'), flags('r')); const buffer = bufferFrom('some content'); assert.throws(function() { binding.write(fd, buffer, 0, 12, 0); }); }); }); describe('#writeBuffers()', function() { it('writes to a file', function() { const binding = new Binding(system); const fd = binding.open(path.join('mock-dir', 'new.txt'), flags('w')); const buffers = [bufferFrom('new '), bufferFrom('content')]; const written = binding.writeBuffers(fd, buffers); assert.equal(written, 11); const file = system.getItem(path.join('mock-dir', 'new.txt')); assert.instanceOf(file, File); const content = file.getContent(); assert.isTrue(Buffer.isBuffer(content)); assert.equal(String(content), 'new content'); }); it('can append to a file', function() { const binding = new Binding(system); const fd = binding.open(path.join('mock-dir', 'one.txt'), flags('a')); const buffers = [bufferFrom(' more'), bufferFrom(' content')]; const written = binding.writeBuffers(fd, buffers); assert.equal(written, 13); const file = system.getItem(path.join('mock-dir', 'one.txt')); assert.instanceOf(file, File); const content = file.getContent(); assert.isTrue(Buffer.isBuffer(content)); assert.equal(String(content), 'one content more content'); }); it('can overwrite part of a file', function() { const binding = new Binding(system); const fd = binding.open(path.join('mock-dir', 'one.txt'), flags('a')); const buffers = [bufferFrom('n'), bufferFrom('e'), bufferFrom('w')]; const written = binding.writeBuffers(fd, buffers, 0); assert.equal(written, 3); const file = system.getItem(path.join('mock-dir', 'one.txt')); assert.instanceOf(file, File); const content = file.getContent(); assert.isTrue(Buffer.isBuffer(content)); assert.equal(String(content), 'new content'); }); it('throws if not open for writing', function() { const binding = new Binding(system); const fd = binding.open(path.join('mock-dir', 'two.txt'), flags('r')); const buffers = [bufferFrom('some content')]; assert.throws(function() { binding.writeBuffers(fd, buffers); }); }); }); describe('#rename()', function() { it('allows files to be renamed', function(done) { const binding = new Binding(system); const oldPath = path.join('mock-dir', 'one.txt'); const newPath = path.join('mock-dir', 'empty', 'new.txt'); binding.rename(oldPath, newPath, function(_) { const stats = binding.stat(newPath); assert.equal(stats.mode & constants.S_IFMT, constants.S_IFREG); assert.equal(stats.size, 11); done(); }); }); it('allows files to be renamed (sync)', function() { const binding = new Binding(system); const oldPath = path.join('mock-dir', 'one.txt'); const newPath = path.join('mock-dir', 'new.txt'); binding.rename(oldPath, newPath); const stats = binding.stat(newPath); assert.equal(stats.mode & constants.S_IFMT, constants.S_IFREG); assert.equal(stats.size, 11); }); it('replaces existing files (sync)', function() { const binding = new Binding(system); const oldPath = path.join('mock-dir', 'one.txt'); const newPath = path.join('mock-dir', 'two.txt'); binding.rename(oldPath, newPath); const stats = binding.stat(newPath); assert.equal(stats.mode & constants.S_IFMT, constants.S_IFREG); assert.equal(stats.size, 11); }); it('allows directories to be renamed', function(done) { const binding = new Binding(system); const oldPath = path.join('mock-dir', 'empty'); const newPath = path.join('mock-dir', 'new'); binding.rename(oldPath, newPath, function(_) { const stats = binding.stat(newPath); assert.equal(stats.mode & constants.S_IFMT, constants.S_IFDIR); done(); }); }); it('allows directories to be renamed (sync)', function() { const binding = new Binding(system); const oldPath = path.join('mock-dir'); const newPath = path.join('new-dir'); binding.rename(oldPath, newPath); const stats = binding.stat(newPath); assert.equal(stats.mode & constants.S_IFMT, constants.S_IFDIR); const items = binding.readdir(newPath); assert.isArray(items); assert.deepEqual(items.sort(), [ 'dead-link', 'dir-link', 'dir-link2', 'empty', 'non-empty', 'one-link.txt', 'one-link2.txt', 'one.txt', 'three.bin', 'two.txt' ]); }); it('calls callback with error for bogus old path', function(done) { const binding = new Binding(system); const oldPath = path.join('mock-dir', 'bogus'); const newPath = path.join('mock-dir', 'new'); binding.rename(oldPath, newPath, function(err) { assert.instanceOf(err, Error); done(); }); }); it('calls callback with error for file->dir rename', function(done) { const binding = new Binding(system); const oldPath = path.join('mock-dir', 'one.txt'); const newPath = path.join('mock-dir', 'empty'); binding.rename(oldPath, newPath, function(err) { assert.instanceOf(err, Error); done(); }); }); it('calls callback with error for dir->file rename', function(done) { const binding = new Binding(system); const oldPath = path.join('mock-dir', 'one.txt'); const newPath = path.join('mock-dir', 'empty'); binding.rename(oldPath, newPath, function(err) { assert.instanceOf(err, Error); done(); }); }); }); describe('#mkdir()', function() { it('creates a new directory', function() { const binding = new Binding(system); const dirPath = path.join('mock-dir', 'foo'); binding.mkdir(dirPath, parseInt('0755', 8)); const dir = system.getItem(dirPath); assert.instanceOf(dir, Directory); assert.equal(dir.getMode(), parseInt('0755', 8)); }); it('fails if parent does not exist', function() { const binding = new Binding(system); const dirPath = path.join('bogus', 'path'); assert.throws(function() { binding.mkdir(dirPath, parseInt('0755', 8)); }); }); it('fails if directory exists', function() { const binding = new Binding(system); const dirPath = 'mock-dir'; assert.throws(function() { binding.mkdir(dirPath, parseInt('0755', 8)); }); }); it('fails if file exists', function() { const binding = new Binding(system); const dirPath = path.join('mock-dir', 'one.txt'); assert.throws(function() { binding.mkdir(dirPath, parseInt('0755', 8)); }); }); }); describe('#mkdir() recursive', function() { it('creates a new directory', function() { const binding = new Binding(system); const dirPath = path.join('mock-dir', 'foo'); binding.mkdir(dirPath, parseInt('0755', 8), true); const dir = system.getItem(dirPath); assert.instanceOf(dir, Directory); assert.equal(dir.getMode(), parseInt('0755', 8)); }); it('creates a new deep directory', function() { const binding = new Binding(system); const dirPath1 = path.join('mock-dir', 'foo'); const dirPath2 = path.join(dirPath1, 'bar'); const dirPath3 = path.join(dirPath2, 'loo'); binding.mkdir(dirPath3, parseInt('0755', 8), true); let dir = system.getItem(dirPath3); assert.instanceOf(dir, Directory); assert.equal(dir.getMode(), parseInt('0755', 8)); dir = system.getItem(dirPath2); assert.instanceOf(dir, Directory); assert.equal(dir.getMode(), parseInt('0755', 8)); dir = system.getItem(dirPath1); assert.instanceOf(dir, Directory); assert.equal(dir.getMode(), parseInt('0755', 8)); }); it('fails if permission does not allow recursive creation', function() { const binding = new Binding(system); const dirPath1 = path.join('mock-dir', 'foo'); const dirPath2 = path.join(dirPath1, 'bar'); const dirPath3 = path.join(dirPath2, 'loo'); assert.throws(function() { binding.mkdir(dirPath3, parseInt('0400', 8), true); }); }); it('fails if one parent is not a folder', function() { const binding = new Binding(system); const dirPath = path.join('mock-dir', 'one.txt', 'foo', 'bar'); assert.throws(function() { binding.mkdir(dirPath, parseInt('0755', 8), true); }); }); it('fails if file exists', function() { const binding = new Binding(system); const dirPath = path.join('mock-dir', 'non-empty', 'a.txt'); assert.throws(function() { binding.mkdir(dirPath, parseInt('0755', 8), true); }); }); it('passes silently if directory exists', function() { const binding = new Binding(system); const dirPath = path.join('mock-dir', 'non-empty'); assert.doesNotThrow(function() { binding.mkdir(dirPath, parseInt('0755', 8), true); }); }); }); describe('#mkdtemp()', function() { it('creates a new directory', function() { const binding = new Binding(system); const template = path.join('mock-dir', 'fooXXXXXX'); const dirPath = binding.mkdtemp(template); assert.notEqual(template, dirPath); const dir = system.getItem(dirPath); assert.instanceOf(dir, Directory); }); it('fails if parent does not exist', function() { const binding = new Binding(system); const dirPath = path.join('bogus', 'pathXXXXXX'); assert.throws(function() { binding.mkdtemp(dirPath); }); }); it('fails if file exists', function() { const binding = new Binding(system); const dirPath = path.join('mock-dir', 'one.txt', 'XXXXXX'); assert.throws(function() { binding.mkdtemp(dirPath); }); }); }); describe('#rmdir()', function() { it('removes an empty directory', function() { const binding = new Binding(system); const dirPath = path.join('mock-dir', 'empty'); binding.rmdir(dirPath); assert.isNull(system.getItem(dirPath)); }); it('fails if directory is not empty', function() { const binding = new Binding(system); const dirPath = 'mock-dir'; assert.throws(function() { binding.rmdir(dirPath); }); }); it('fails if directory does not exist', function() { const binding = new Binding(system); const dirPath = path.join('bogus', 'path'); assert.throws(function() { binding.rmdir(dirPath); }); }); it('fails if a file exists', function() { const binding = new Binding(system); const dirPath = path.join('mock-dir', 'one.txt'); assert.throws(function() { binding.rmdir(dirPath); }); }); }); describe('#ftruncate()', function() { it('truncates a file', function() { const binding = new Binding(system); const pathname = path.join('mock-dir', 'one.txt'); const fd = binding.open(pathname, flags('r+')); binding.ftruncate(fd, 3); const file = system.getItem(pathname); assert.equal(String(file.getContent()), 'one'); }); it('fails if directory', function() { const binding = new Binding(system); const fd = binding.open('mock-dir', flags('r')); assert.throws(function() { binding.ftruncate(fd, 3); }); }); it('fails if not open for writing', function() { const binding = new Binding(system); const pathname = path.join('mock-dir', 'one.txt'); const fd = binding.open(pathname, flags('r')); assert.throws(function() { binding.ftruncate(fd, 4); }); }); }); describe('#chown()', function() { it('sets the uid and gid for a file', function() { const binding = new Binding(system); const pathname = path.join('mock-dir', 'one.txt'); binding.chown(pathname, 3, 4); const file = system.getItem(pathname); assert.equal(file.getUid(), 3); assert.equal(file.getGid(), 4); }); it('sets the uid and gid for a directory', function() { const binding = new Binding(system); const pathname = path.join('mock-dir', 'empty'); binding.chown(pathname, 5, 6); const dir = system.getItem(pathname); assert.equal(dir.getUid(), 5); assert.equal(dir.getGid(), 6); }); }); describe('#fchown()', function() { it('sets the uid and gid for a file', function() { const binding = new Binding(system); const pathname = path.join('mock-dir', 'one.txt'); const fd = binding.open(pathname, flags('r')); binding.fchown(fd, 3, 4); const file = system.getItem(pathname); assert.equal(file.getUid(), 3); assert.equal(file.getGid(), 4); }); it('sets the uid and gid for a directory', function() { const binding = new Binding(system); const pathname = path.join('mock-dir', 'empty'); const fd = binding.open(pathname, flags('r')); binding.fchown(fd, 5, 6); const dir = system.getItem(pathname); assert.equal(dir.getUid(), 5); assert.equal(dir.getGid(), 6); }); }); describe('#chmod()', function() { it('sets the mode for a file', function() { const binding = new Binding(system); const pathname = path.join('mock-dir', 'two.txt'); binding.chmod(pathname, parseInt('0644', 8)); const file = system.getItem(pathname); assert.equal(file.getMode(), parseInt('0644', 8)); }); it('sets the mode for a directory', function() { const binding = new Binding(system); const pathname = path.join('mock-dir', 'empty'); binding.chmod(pathname, parseInt('0755', 8)); const dir = system.getItem(pathname); assert.equal(dir.getMode(), parseInt('0755', 8)); }); }); describe('#fchmod()', function() { it('sets the mode for a file', function() { const binding = new Binding(system); const pathname = path.join('mock-dir', 'one.txt'); const fd = binding.open(pathname, flags('r')); binding.fchmod(fd, parseInt('0664', 8)); const file = system.getItem(pathname); assert.equal(file.getMode(), parseInt('0664', 8)); }); it('sets the mode for a directory', function() { const binding = new Binding(system); const pathname = path.join('mock-dir', 'empty'); const fd = binding.open(pathname, flags('r')); binding.fchmod(fd, parseInt('0775', 8)); const dir = system.getItem(pathname); assert.equal(dir.getMode(), parseInt('0775', 8)); }); }); describe('#unlink()', function() { it('deletes a file', function() { const binding = new Binding(system); const pathname = path.join('mock-dir', 'one.txt'); binding.unlink(pathname); assert.isNull(system.getItem(pathname)); }); it('fails for directory', function() { const binding = new Binding(system); const pathname = path.join('mock-dir', 'empty'); assert.throws(function() { binding.unlink(pathname); }); }); it('fails for bogus path', function() { const binding = new Binding(system); const pathname = path.join('mock-dir', 'bogus.txt'); assert.throws(function() { binding.unlink(pathname); }); }); }); describe('#utimes()', function() { it('updates atime and mtime for a file', function() { const binding = new Binding(system); const pathname = path.join('mock-dir', 'one.txt'); binding.utimes(pathname, 100, 200); const item = system.getItem(pathname); assert.equal(item.getATime().getTime(), 100 * 1000); assert.equal(item.getMTime().getTime(), 200 * 1000); }); it('updates atime and mtime for a directory', function() { const binding = new Binding(system); const pathname = path.join('mock-dir', 'empty'); binding.utimes(pathname, 300, 400); const item = system.getItem(pathname); assert.equal(item.getATime().getTime(), 300 * 1000); assert.equal(item.getMTime().getTime(), 400 * 1000); }); it('fails for a bogus path', function() { const binding = new Binding(system); const pathname = path.join('mock-dir', 'bogus.txt'); assert.throws(function() { binding.utimes(pathname, 300, 400); }); }); }); describe('#futimes()', function() { it('updates atime and mtime for a file', function() { const binding = new Binding(system); const pathname = path.join('mock-dir', 'one.txt'); const fd = binding.open(pathname, flags('r')); binding.futimes(fd, 100, 200); const item = system.getItem(pathname); assert.equal(item.getATime().getTime(), 100 * 1000); assert.equal(item.getMTime().getTime(), 200 * 1000); }); it('updates atime and mtime for a directory', function() { const binding = new Binding(system); const pathname = path.join('mock-dir', 'empty'); const fd = binding.open(pathname, flags('r')); binding.futimes(fd, 300, 400); const item = system.getItem(pathname); assert.equal(item.getATime().getTime(), 300 * 1000); assert.equal(item.getMTime().getTime(), 400 * 1000); }); }); describe('#fsync()', function() { it('synchronize file state (noop)', function() { const binding = new Binding(system); const pathname = path.join('mock-dir', 'one.txt'); const fd = binding.open(pathname, flags('r')); binding.fsync(fd); }); it('fails for closed file descriptor', function() { const binding = new Binding(system); const pathname = path.join('mock-dir', 'one.txt'); const fd = binding.open(pathname, flags('r')); binding.close(fd); assert.throws(function() { binding.fsync(fd); }); }); }); describe('#fdatasync()', function() { it('synchronize file state (noop)', function() { const binding = new Binding(system); const pathname = path.join('mock-dir', 'one.txt'); const fd = binding.open(pathname, flags('r')); binding.fdatasync(fd); }); it('fails for closed file descriptor', function() { const binding = new Binding(system); const pathname = path.join('mock-dir', 'one.txt'); const fd = binding.open(pathname, flags('r')); binding.close(fd); assert.throws(function() { binding.fdatasync(fd); }); }); }); describe('#link()', function() { it('creates a link to a file', function() { const binding = new Binding(system); const source = path.join('mock-dir', 'one.txt'); const dest = path.join('mock-dir', 'link.txt'); binding.link(source, dest); const link = system.getItem(dest); assert.instanceOf(link, File); assert.equal(String(link.getContent()), 'one content'); }); it('fails if dest exists', function() { const binding = new Binding(system); const source = path.join('mock-dir', 'one.txt'); const dest = path.join('mock-dir', 'two.txt'); assert.throws(function() { binding.link(source, dest); }); }); it('fails if source is directory', function() { const binding = new Binding(system); const source = path.join('mock-dir', 'empty'); const dest = path.join('mock-dir', 'link'); assert.throws(function() { binding.link(source, dest); }); }); }); describe('#symlink()', function() { it('creates a symbolic link to a file', function() { const binding = new Binding(system); const source = path.join('.', 'one.txt'); const dest = path.join('mock-dir', 'link.txt'); binding.symlink(source, dest); const link = system.getItem(dest); assert.instanceOf(link, SymbolicLink); assert.equal(link.getPath(), source); }); it('fails if dest exists', function() { const binding = new Binding(system); const source = path.join('.', 'one.txt'); const dest = path.join('mock-dir', 'two.txt'); assert.throws(function() { binding.symlink(source, dest); }); }); it('works if source is directory', function() { const binding = new Binding(system); const source = path.join('mock-dir', 'empty'); const dest = path.join('mock-dir', 'link'); binding.symlink(source, dest); const link = system.getItem(dest); assert.instanceOf(link, SymbolicLink); assert.equal(link.getPath(), source); }); }); describe('#readlink()', function() { it('reads the symbolic link', function() { const binding = new Binding(system); const srcPath = binding.readlink(path.join('mock-dir', 'one-link.txt')); assert.equal(srcPath, './one.txt'); }); it('can return "buffer" encoding', function() { const binding = new Binding(system); const srcPath = binding.readlink( path.join('mock-dir', 'one-link.txt'), 'buffer' ); assert.equal(Buffer.isBuffer(srcPath), true); assert.equal(srcPath.toString(), './one.txt'); }); it('fails for regular files', function() { const binding = new Binding(system); assert.throws(function() { binding.readlink(path.join('mock-dir', 'one.txt')); }, /EINVAL/); }); it('fails for directories', function() { const binding = new Binding(system); assert.throws(function() { binding.readlink(path.join('mock-dir', 'empty')); }, /EINVAL/); }); it('fails for bogus paths', function() { const binding = new Binding(system); assert.throws(function() { binding.readlink(path.join('mock-dir', 'bogus')); }, /ENOENT/); }); }); describe('#lstat()', function() { it('stats symbolic links', function() { const binding = new Binding(system); const pathname = path.join('mock-dir', 'one-link.txt'); const stats = binding.lstat(pathname); assert.isTrue(stats.isSymbolicLink()); assert.isFalse(stats.isFile()); assert.equal(stats.size, binding.readlink(pathname).length); }); }); describe('#access()', function() { it('works if file exists', function() { const binding = new Binding(system); const pathname = path.join('mock-dir', 'one-link.txt'); binding.access(pathname); }); it('throws for dead link', function() { const binding = new Binding(system); const pathname = path.join('mock-dir', 'dead-link.txt'); assert.throws(function() { binding.access(pathname); }, /ENOENT/); }); if (process.getuid && process.getgid) { it('fails in case of insufficient user permissions', function() { const binding = new Binding(system); const item = system.getItem(path.join('mock-dir', 'one.txt')); item.setMode(parseInt('0077', 8)); assert.throws(function() { binding.access(path.join('mock-dir', 'one.txt'), 1); }, /EACCES/); }); it('fails in case of insufficient group permissions', function() { const binding = new Binding(system); const item = system.getItem(path.join('mock-dir', 'one.txt')); item.setUid(process.getuid() + 1); item.setMode(parseInt('0707', 8)); assert.throws(function() { binding.access(path.join('mock-dir', 'one.txt'), 2); }, /EACCES/); }); it('fails in case of insufficient permissions', function() { const binding = new Binding(system); const item = system.getItem(path.join('mock-dir', 'one.txt')); item.setUid(process.getuid() + 1); item.setGid(process.getgid() + 1); item.setMode(parseInt('0771', 8)); assert.throws(function() { binding.access(path.join('mock-dir', 'one.txt'), 5); }, /EACCES/); }); } it('fails for bogus paths', function() { const binding = new Binding(system); assert.throws(function() { binding.access(path.join('mock-dir', 'bogus')); }, /ENOENT/); }); }); }); mock-fs-4.10.4/test/lib/descriptor.spec.js000066400000000000000000000264451356713366300203610ustar00rootroot00000000000000'use strict'; const FileDescriptor = require('../../lib/descriptor'); const helper = require('../helper'); const assert = helper.assert; const flags = helper.flags; describe('FileDescriptor', function() { describe('constructor', function() { it('creates a new descriptor', function() { const fd = new FileDescriptor(flags('r')); assert.instanceOf(fd, FileDescriptor); }); }); describe('#getPosition()', function() { it('returns zero by default', function() { const fd = new FileDescriptor(flags('r')); assert.equal(fd.getPosition(), 0); }); }); describe('#setPosition()', function() { it('updates the position', function() { const fd = new FileDescriptor(flags('r')); fd.setPosition(10); assert.equal(fd.getPosition(), 10); }); }); describe('#isAppend()', function() { it('not opened for appending (r)', function() { const fd = new FileDescriptor(flags('r')); assert.isFalse(fd.isAppend()); }); it('not opened for appending (r+)', function() { const fd = new FileDescriptor(flags('r+')); assert.isFalse(fd.isAppend()); }); it('not opened for appending (rs)', function() { const fd = new FileDescriptor(flags('rs')); assert.isFalse(fd.isAppend()); }); it('not opened for appending (rs+)', function() { const fd = new FileDescriptor(flags('rs+')); assert.isFalse(fd.isAppend()); }); it('not opened for appending (w)', function() { const fd = new FileDescriptor(flags('w')); assert.isFalse(fd.isAppend()); }); it('not opened for appending (wx)', function() { const fd = new FileDescriptor(flags('wx')); assert.isFalse(fd.isAppend()); }); it('not opened for appending (w+)', function() { const fd = new FileDescriptor(flags('w+')); assert.isFalse(fd.isAppend()); }); it('not opened for appending (wx+)', function() { const fd = new FileDescriptor(flags('wx+')); assert.isFalse(fd.isAppend()); }); it('opened for appending (a)', function() { const fd = new FileDescriptor(flags('a')); assert.isTrue(fd.isAppend()); }); it('opened for appending (ax)', function() { const fd = new FileDescriptor(flags('ax')); assert.isTrue(fd.isAppend()); }); it('opened for appending (a+)', function() { const fd = new FileDescriptor(flags('a+')); assert.isTrue(fd.isAppend()); }); it('opened for appending (ax+)', function() { const fd = new FileDescriptor(flags('ax+')); assert.isTrue(fd.isAppend()); }); }); describe('#isTruncate()', function() { it('not opened for truncating (r)', function() { const fd = new FileDescriptor(flags('r')); assert.isFalse(fd.isTruncate()); }); it('not opened for truncating (r+)', function() { const fd = new FileDescriptor(flags('r+')); assert.isFalse(fd.isTruncate()); }); it('not opened for truncating (rs)', function() { const fd = new FileDescriptor(flags('rs')); assert.isFalse(fd.isTruncate()); }); it('not opened for truncating (rs+)', function() { const fd = new FileDescriptor(flags('rs+')); assert.isFalse(fd.isTruncate()); }); it('opened for truncating (w)', function() { const fd = new FileDescriptor(flags('w')); assert.isTrue(fd.isTruncate()); }); it('opened for truncating (wx)', function() { const fd = new FileDescriptor(flags('wx')); assert.isTrue(fd.isTruncate()); }); it('opened for truncating (w+)', function() { const fd = new FileDescriptor(flags('w+')); assert.isTrue(fd.isTruncate()); }); it('opened for truncating (wx+)', function() { const fd = new FileDescriptor(flags('wx+')); assert.isTrue(fd.isTruncate()); }); it('not opened for truncating (a)', function() { const fd = new FileDescriptor(flags('a')); assert.isFalse(fd.isTruncate()); }); it('not opened for truncating (ax)', function() { const fd = new FileDescriptor(flags('ax')); assert.isFalse(fd.isTruncate()); }); it('not opened for truncating (a+)', function() { const fd = new FileDescriptor(flags('a+')); assert.isFalse(fd.isTruncate()); }); it('not opened for truncating (ax+)', function() { const fd = new FileDescriptor(flags('ax+')); assert.isFalse(fd.isTruncate()); }); }); describe('#isCreate()', function() { it('not opened for creation (r)', function() { const fd = new FileDescriptor(flags('r')); assert.isFalse(fd.isCreate()); }); it('not opened for creation (r+)', function() { const fd = new FileDescriptor(flags('r+')); assert.isFalse(fd.isCreate()); }); it('not opened for creation (rs)', function() { const fd = new FileDescriptor(flags('rs')); assert.isFalse(fd.isCreate()); }); it('not opened for creation (rs+)', function() { const fd = new FileDescriptor(flags('rs+')); assert.isFalse(fd.isCreate()); }); it('opened for creation (w)', function() { const fd = new FileDescriptor(flags('w')); assert.isTrue(fd.isCreate()); }); it('opened for creation (wx)', function() { const fd = new FileDescriptor(flags('wx')); assert.isTrue(fd.isCreate()); }); it('opened for creation (w+)', function() { const fd = new FileDescriptor(flags('w+')); assert.isTrue(fd.isCreate()); }); it('opened for creation (wx+)', function() { const fd = new FileDescriptor(flags('wx+')); assert.isTrue(fd.isCreate()); }); it('opened for creation (a)', function() { const fd = new FileDescriptor(flags('a')); assert.isTrue(fd.isCreate()); }); it('opened for creation (ax)', function() { const fd = new FileDescriptor(flags('ax')); assert.isTrue(fd.isCreate()); }); it('opened for creation (a+)', function() { const fd = new FileDescriptor(flags('a+')); assert.isTrue(fd.isCreate()); }); it('opened for creation (ax+)', function() { const fd = new FileDescriptor(flags('ax+')); assert.isTrue(fd.isCreate()); }); }); describe('#isRead()', function() { it('opened for reading (r)', function() { const fd = new FileDescriptor(flags('r')); assert.isTrue(fd.isRead()); }); it('opened for reading (r+)', function() { const fd = new FileDescriptor(flags('r+')); assert.isTrue(fd.isRead()); }); it('opened for reading (rs)', function() { const fd = new FileDescriptor(flags('rs')); assert.isTrue(fd.isRead()); }); it('opened for reading (rs+)', function() { const fd = new FileDescriptor(flags('rs+')); assert.isTrue(fd.isRead()); }); it('not opened for reading (w)', function() { const fd = new FileDescriptor(flags('w')); assert.isFalse(fd.isRead()); }); it('not opened for reading (wx)', function() { const fd = new FileDescriptor(flags('wx')); assert.isFalse(fd.isRead()); }); it('opened for reading (w+)', function() { const fd = new FileDescriptor(flags('w+')); assert.isTrue(fd.isRead()); }); it('opened for reading (wx+)', function() { const fd = new FileDescriptor(flags('wx+')); assert.isTrue(fd.isRead()); }); it('not opened for reading (a)', function() { const fd = new FileDescriptor(flags('a')); assert.isFalse(fd.isRead()); }); it('not opened for reading (ax)', function() { const fd = new FileDescriptor(flags('ax')); assert.isFalse(fd.isRead()); }); it('opened for reading (a+)', function() { const fd = new FileDescriptor(flags('a+')); assert.isTrue(fd.isRead()); }); it('opened for reading (ax+)', function() { const fd = new FileDescriptor(flags('ax+')); assert.isTrue(fd.isRead()); }); }); describe('#isWrite()', function() { it('not opened for writing (r)', function() { const fd = new FileDescriptor(flags('r')); assert.isFalse(fd.isWrite()); }); it('opened for writing (r+)', function() { const fd = new FileDescriptor(flags('r+')); assert.isTrue(fd.isWrite()); }); it('not opened for writing (rs)', function() { const fd = new FileDescriptor(flags('rs')); assert.isFalse(fd.isWrite()); }); it('opened for writing (rs+)', function() { const fd = new FileDescriptor(flags('rs+')); assert.isTrue(fd.isWrite()); }); it('opened for writing (w)', function() { const fd = new FileDescriptor(flags('w')); assert.isTrue(fd.isWrite()); }); it('opened for writing (wx)', function() { const fd = new FileDescriptor(flags('wx')); assert.isTrue(fd.isWrite()); }); it('opened for writing (w+)', function() { const fd = new FileDescriptor(flags('w+')); assert.isTrue(fd.isWrite()); }); it('opened for writing (wx+)', function() { const fd = new FileDescriptor(flags('wx+')); assert.isTrue(fd.isWrite()); }); it('opened for writing (a)', function() { const fd = new FileDescriptor(flags('a')); assert.isTrue(fd.isWrite()); }); it('opened for writing (ax)', function() { const fd = new FileDescriptor(flags('ax')); assert.isTrue(fd.isWrite()); }); it('opened for writing (a+)', function() { const fd = new FileDescriptor(flags('a+')); assert.isTrue(fd.isWrite()); }); it('opened for writing (ax+)', function() { const fd = new FileDescriptor(flags('ax+')); assert.isTrue(fd.isWrite()); }); }); describe('#isExclusive()', function() { it('not opened exclusive (r)', function() { const fd = new FileDescriptor(flags('r')); assert.isFalse(fd.isExclusive()); }); it('not opened exclusive (r+)', function() { const fd = new FileDescriptor(flags('r+')); assert.isFalse(fd.isExclusive()); }); it('not opened exclusive (rs)', function() { const fd = new FileDescriptor(flags('rs')); assert.isFalse(fd.isExclusive()); }); it('not opened exclusive (rs+)', function() { const fd = new FileDescriptor(flags('rs+')); assert.isFalse(fd.isExclusive()); }); it('not opened exclusive (w)', function() { const fd = new FileDescriptor(flags('w')); assert.isFalse(fd.isExclusive()); }); it('opened exclusive (wx)', function() { const fd = new FileDescriptor(flags('wx')); assert.isTrue(fd.isExclusive()); }); it('not opened exclusive (w+)', function() { const fd = new FileDescriptor(flags('w+')); assert.isFalse(fd.isExclusive()); }); it('opened exclusive (wx+)', function() { const fd = new FileDescriptor(flags('wx+')); assert.isTrue(fd.isExclusive()); }); it('not opened exclusive (a)', function() { const fd = new FileDescriptor(flags('a')); assert.isFalse(fd.isExclusive()); }); it('opened exclusive (ax)', function() { const fd = new FileDescriptor(flags('ax')); assert.isTrue(fd.isExclusive()); }); it('not opened exclusive (a+)', function() { const fd = new FileDescriptor(flags('a+')); assert.isFalse(fd.isExclusive()); }); it('opened exclusive (ax+)', function() { const fd = new FileDescriptor(flags('ax+')); assert.isTrue(fd.isExclusive()); }); }); }); mock-fs-4.10.4/test/lib/directory.spec.js000066400000000000000000000071051356713366300201770ustar00rootroot00000000000000'use strict'; const Item = require('../../lib/item'); const Directory = require('../../lib/directory'); const File = require('../../lib/file'); const assert = require('../helper').assert; describe('Directory', function() { describe('constructor', function() { it('creates a named directory', function() { const dir = new Directory(); assert.instanceOf(dir, Directory); assert.instanceOf(dir, Item); }); }); describe('#addItem()', function() { it('allows a directory to be added', function() { const parent = new Directory(); const child = new Directory(); parent.addItem('child', child); assert.equal(parent.getItem('child'), child); }); it('allows a file to be added', function() { const parent = new Directory(); const child = new File(); parent.addItem('child', child); assert.equal(parent.getItem('child'), child); }); it('returns the added item', function() { const parent = new Directory(); const child = new File(); const got = parent.addItem('child', child); assert.equal(got, child); }); }); describe('#getItem()', function() { it('retrieves a named directory', function() { const parent = new Directory(); const child = new Directory(); parent.addItem('child', child); assert.equal(parent.getItem('child'), child); }); it('retrieves a named file', function() { const parent = new Directory(); const child = new File(); parent.addItem('child', child); assert.equal(parent.getItem('child'), child); }); it('returns null for missing item', function() { const parent = new Directory(); const child = new File(); parent.addItem('child', child); assert.isNull(parent.getItem('kid')); }); }); describe('#removeItem()', function() { it('allows a directory to be removed', function() { const parent = new Directory(); const child = new Directory(); parent.addItem('child', child); const removed = parent.removeItem('child'); assert.equal(removed, child); assert.isNull(parent.getItem('child')); }); it('allows a file to be removed', function() { const parent = new Directory(); const child = new File(); parent.addItem('child', child); const removed = parent.removeItem('child'); assert.equal(removed, child); assert.isNull(parent.getItem('child')); }); it('throws if item is not a child', function() { const parent = new Directory(); parent.addItem('one', new Directory()); parent.addItem('two', new File()); assert.throws(function() { parent.removeItem('three'); }); }); }); describe('#list()', function() { it('lists all items in a directory', function() { const dir = new Directory(); dir.addItem('one file', new File()); dir.addItem('another file', new File()); dir.addItem('a directory', new Directory()); dir.addItem('another directory', new Directory()); const list = dir.list(); assert.deepEqual(list.sort(), [ 'a directory', 'another directory', 'another file', 'one file' ]); }); it('works for empty dir', function() { const dir = new Directory(); assert.deepEqual(dir.list(), []); }); it('lists one level deep', function() { const d0 = new Directory(); const d1 = new Directory(); const d2 = new Directory(); d1.addItem('d2', d2); d0.addItem('d1', d1); assert.deepEqual(d0.list(), ['d1']); }); }); }); mock-fs-4.10.4/test/lib/file.spec.js000066400000000000000000000040001356713366300171010ustar00rootroot00000000000000'use strict'; const Item = require('../../lib/item'); const File = require('../../lib/file'); const assert = require('../helper').assert; const bufferFrom = require('../../lib/buffer').from; describe('File', function() { describe('constructor', function() { it('creates a named file', function() { const file = new File(); assert.instanceOf(file, File); assert.instanceOf(file, Item); }); }); describe('#getContent()', function() { it('gets the file content', function() { const file = new File(); const content = bufferFrom('bar'); file.setContent(content); assert.equal(file.getContent(), content); }); it('is initially empty', function() { const file = new File(); assert.equal(String(file.getContent()), ''); }); it('updates the atime', function() { const file = new File(); file.setContent('bar'); const old = new Date(1); file.setATime(old); file.getContent(); assert.isTrue(file.getATime() > old); }); }); describe('#setContent()', function() { it('accepts a string', function() { const file = new File(); file.setContent('bar'); const content = file.getContent(); assert.isTrue(Buffer.isBuffer(content)); assert.equal(String(content), 'bar'); }); it('accepts a buffer', function() { const file = new File(); file.setContent(bufferFrom('baz')); const content = file.getContent(); assert.isTrue(Buffer.isBuffer(content)); assert.equal(String(content), 'baz'); }); it('throws for other types', function() { assert.throws(function() { const file = new File(); file.setContent(123); }); }); it('updates the ctime and mtime', function() { const file = new File(); const old = new Date(1); file.setCTime(old); file.setMTime(old); file.setContent('bar'); assert.isTrue(file.getCTime() > old); assert.isTrue(file.getMTime() > old); }); }); }); mock-fs-4.10.4/test/lib/filesystem.spec.js000066400000000000000000000231611356713366300203570ustar00rootroot00000000000000'use strict'; const os = require('os'); const path = require('path'); const Directory = require('../../lib/directory'); const File = require('../../lib/file'); const FileSystem = require('../../lib/filesystem'); const assert = require('../helper').assert; describe('FileSystem', function() { describe('constructor', function() { it('creates a new instance', function() { const system = new FileSystem(); assert.instanceOf(system, FileSystem); }); it('accepts a createCwd option', function() { const cwd = process.cwd(); const withCwd = new FileSystem({createCwd: true}); const withoutCwd = new FileSystem({createCwd: false}); assert.instanceOf(withCwd.getItem(cwd), Directory); assert.isNull(withoutCwd.getItem(cwd)); }); it('accepts a createTmp option', function() { const tmp = os.tmpdir ? os.tmpdir() : os.tmpDir(); const withTmp = new FileSystem({createTmp: true}); const withoutTmp = new FileSystem({createTmp: false}); assert.instanceOf(withTmp.getItem(tmp), Directory); assert.isNull(withoutTmp.getItem(tmp)); }); }); describe('#getRoot()', function() { it('gets the root directory', function() { const system = new FileSystem(); assert.instanceOf(system.getRoot(), Directory); }); }); describe('#getItem()', function() { it('gets an item', function() { const system = FileSystem.create({ 'one/two/three.js': 'contents' }); const filepath = path.join('one', 'two', 'three.js'); const item = system.getItem(filepath); assert.instanceOf(item, File); }); it('returns null if not found', function() { const system = FileSystem.create({ 'one/two/three.js': 'contents' }); assert.isNull(system.getItem(path.join('one', 'two', 'four.js'))); assert.isNull(system.getItem(path.join('one', '2', 'three.js'))); assert.isNull(system.getItem(path.join('um', 'two', 'three.js'))); }); it('gets an item traversing links to symbolic links', function() { const system = FileSystem.create({ 'dir-link': FileSystem.symlink({path: './b/dir-link2'}), b: { 'dir-link2': FileSystem.symlink({path: './c/dir'}), c: { dir: { a: 'file a', b: { c: 'file c', d: 'file d' } } } } }); const file = system.getItem(path.join('dir-link', 'a')); assert.instanceOf(file, File); const dir = system.getItem(path.join('dir-link', 'b')); assert.instanceOf(dir, Directory); assert.deepEqual(dir.list().sort(), ['c', 'd']); }); }); }); describe('FileSystem.file', function() { it('creates a factory for files', function() { const factory = FileSystem.file(); assert.isFunction(factory); const file = factory(); assert.instanceOf(file, File); }); it('accepts a content member', function() { const factory = FileSystem.file({content: 'foo'}); assert.isFunction(factory); const file = factory(); assert.instanceOf(file, File); const content = file.getContent(); assert.isTrue(Buffer.isBuffer(content)); assert.equal(String(content), 'foo'); }); }); describe('FileSystem.directory', function() { it('creates a factory for directories', function() { const factory = FileSystem.directory(); assert.isFunction(factory); const dir = factory(); assert.instanceOf(dir, Directory); }); }); describe('FileSystem.create', function() { it('provides a convenient way to populate a file system', function() { const system = FileSystem.create({ 'path/to/one': { 'file.js': 'file.js content', dir: {} }, 'path/to/two.js': 'two.js content', 'path/to/three': {} }); assert.instanceOf(system, FileSystem); let filepath, item; // confirm 'path/to/one' directory was created filepath = path.join('path', 'to', 'one'); item = system.getItem(filepath); assert.instanceOf(item, Directory); assert.deepEqual(item.list().sort(), ['dir', 'file.js']); // confirm 'path/to/one/file.js' file was created filepath = path.join('path', 'to', 'one', 'file.js'); item = system.getItem(filepath); assert.instanceOf(item, File); assert.equal(String(item.getContent()), 'file.js content'); // confirm 'path/to/one/dir' directory was created filepath = path.join('path', 'to', 'one', 'dir'); item = system.getItem(filepath); assert.instanceOf(item, Directory); assert.deepEqual(item.list(), []); // confirm 'path/to/two.js' file was created filepath = path.join('path', 'to', 'two.js'); item = system.getItem(filepath); assert.instanceOf(item, File); assert.equal(String(item.getContent()), 'two.js content'); // confirm 'path/to/three' directory was created filepath = path.join('path', 'to', 'three'); item = system.getItem(filepath); assert.instanceOf(item, Directory); assert.deepEqual(item.list(), []); }); it('passes options to the FileSystem constructor', function() { const cwd = process.cwd(); const tmp = os.tmpdir ? os.tmpdir() : os.tmpDir(); const withoutCwd = FileSystem.create({}, {createCwd: false}); const withoutTmp = FileSystem.create({}, {createTmp: false}); assert.isNull(withoutCwd.getItem(cwd)); assert.instanceOf(withoutCwd.getItem(tmp), Directory); assert.isNull(withoutTmp.getItem(tmp)); assert.instanceOf(withoutTmp.getItem(cwd), Directory); }); it('accepts file factory', function() { const system = FileSystem.create({ 'path/to/file.js': FileSystem.file({content: 'foo'}) }); assert.instanceOf(system, FileSystem); const file = system.getItem(path.join('path', 'to', 'file.js')); assert.instanceOf(file, File); assert.equal(String(file.getContent()), 'foo'); }); it('accepts file factory with uid & gid', function() { const system = FileSystem.create({ 'path/to/file.js': FileSystem.file({ content: 'foo', uid: 42, gid: 43 }) }); assert.instanceOf(system, FileSystem); const file = system.getItem(path.join('path', 'to', 'file.js')); assert.instanceOf(file, File); assert.equal(String(file.getContent()), 'foo'); assert.equal(file.getUid(), 42); assert.equal(file.getGid(), 43); }); it('accepts directory factory', function() { const system = FileSystem.create({ 'path/to/dir': FileSystem.directory() }); assert.instanceOf(system, FileSystem); const dir = system.getItem(path.join('path', 'to', 'dir')); assert.instanceOf(dir, Directory); }); it('accepts directory factory with uid & gid', function() { const system = FileSystem.create({ 'path/to/dir': FileSystem.directory({ uid: 42, gid: 43 }) }); assert.instanceOf(system, FileSystem); const dir = system.getItem(path.join('path', 'to', 'dir')); assert.instanceOf(dir, Directory); assert.equal(dir.getUid(), 42); assert.equal(dir.getGid(), 43); }); it('accepts directory factory with additional items', function() { const system = FileSystem.create({ 'path/to/dir': FileSystem.directory({ mode: parseInt('0755', 8), items: { 'file.txt': 'file content', 'empty-dir': {} } }) }); assert.instanceOf(system, FileSystem); const dir = system.getItem(path.join('path', 'to', 'dir')); assert.instanceOf(dir, Directory); assert.equal(dir.getMode(), parseInt('0755', 8)); const file = system.getItem(path.join('path', 'to', 'dir', 'file.txt')); assert.instanceOf(file, File); assert.equal(String(file.getContent()), 'file content'); const empty = system.getItem(path.join('path', 'to', 'dir', 'empty-dir')); assert.instanceOf(empty, Directory); assert.deepEqual(empty.list(), []); }); it('correctly generates link counts', function() { const system = FileSystem.create({ '/dir-a.0': { 'dir-b.0': { 'dir-c.0': {}, 'dir-c.1': {}, 'file-c.0': 'content', 'file-c.1': 'content', 'symlink-c.0': FileSystem.symlink({path: 'file-c.0'}) } } }); /** * 3 links: /dir-a.0, /dir-a.0/., and /dir-a.0/dir-b.0/.. */ assert.equal(system.getItem('/dir-a.0').links, 3); /** * 4 links: /dir-a.0/dir-b.0, /dir-a.0/dir-b.0/., * /dir-a.0/dir-b.0/dir-c.0/.., and /dir-a.0/dir-b.0/dir-c.1/.. */ assert.equal(system.getItem('/dir-a.0/dir-b.0').links, 4); /** * 2 links: /dir-a.0/dir-b.0/dir-c.0 and /dir-a.0/dir-b.0/dir-c.0/. */ assert.equal(system.getItem('/dir-a.0/dir-b.0/dir-c.0').links, 2); /** * 2 links: /dir-a.0/dir-b.0/dir-c.0 and /dir-a.0/dir-b.0/dir-c.0/. */ assert.equal(system.getItem('/dir-a.0/dir-b.0/dir-c.0').links, 2); /** * 1 link: /dir-a.0/dir-b.0/file-c.0 */ assert.equal(system.getItem('/dir-a.0/dir-b.0/file-c.0').links, 1); /** * 1 link: /dir-a.0/dir-b.0/file-c.1 */ assert.equal(system.getItem('/dir-a.0/dir-b.0/file-c.1').links, 1); /** * 1 link: /dir-a.0/dir-b.0/symlink-c.0 */ assert.equal(system.getItem('/dir-a.0/dir-b.0/symlink-c.0').links, 1); }); it('throws if item content is not valid type', function() { assert.throws(function() { FileSystem.create({ '/dir-a.0': { 'dir-b.0': { 'file-c.0': undefined } } }); }); assert.throws(function() { FileSystem.create({ '/dir-a.0': { 'dir-b.0': { 'file-c.0': 123 } } }); }); }); }); mock-fs-4.10.4/test/lib/fs.access.spec.js000066400000000000000000000515611356713366300200500ustar00rootroot00000000000000'use strict'; const helper = require('../helper'); const fs = require('fs'); const mock = require('../../lib/index'); const assert = helper.assert; const withPromise = helper.withPromise; 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); }); withPromise.it('promise works for an accessible file', function(done) { fs.promises.access('path/to/accessible/file').then(done, done); }); it('works 000 (and no mode arg)', function(done) { fs.access('path/to/000', done); }); withPromise.it('promise works 000 (and no mode arg)', function(done) { fs.promises.access('path/to/000').then(done, done); }); it('works F_OK and 000', function(done) { fs.access('path/to/000', fs.F_OK, done); }); withPromise.it('promise works F_OK and 000', function(done) { fs.promises.access('path/to/000', fs.F_OK).then(done, 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(); }); }); withPromise.it('promise generates EACCES for R_OK and 000', function(done) { fs.promises.access('path/to/000', fs.R_OK).then( function() { assert.fail('should not succeed.'); done(); }, 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(); }); }); withPromise.it('promise generates EACCES for W_OK and 000', function(done) { fs.promises.access('path/to/000', fs.W_OK).then( function() { assert.fail('should not succeed.'); done(); }, 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(); }); }); withPromise.it('promise generates EACCES for X_OK and 000', function(done) { fs.promises.access('path/to/000', fs.X_OK).then( function() { assert.fail('should not succeed.'); done(); }, 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); }); withPromise.it('promise works 111 (and no mode arg)', function(done) { fs.promises.access('path/to/111').then(done, done); }); it('works F_OK and 111', function(done) { fs.access('path/to/111', fs.F_OK, done); }); withPromise.it('promise works F_OK and 111', function(done) { fs.promises.access('path/to/111', fs.F_OK).then(done, done); }); it('works X_OK and 111', function(done) { fs.access('path/to/111', fs.X_OK, done); }); withPromise.it('promise works X_OK and 111', function(done) { fs.promises.access('path/to/111', fs.X_OK).then(done, 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(); }); }); withPromise.it('promise generates EACCES for R_OK and 111', function(done) { fs.promises.access('path/to/111', fs.R_OK).then( function() { assert.fail('should not succeed.'); done(); }, 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(); }); }); withPromise.it('promise generates EACCES for W_OK and 111', function(done) { fs.promises.access('path/to/111', fs.W_OK).then( function() { assert.fail('should not succeed.'); done(); }, 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); }); withPromise.it('promise works for 222 (and no mode arg)', function(done) { fs.promises.access('path/to/write/only').then(done, done); }); it('works F_OK and 222', function(done) { fs.access('path/to/write/only', fs.F_OK, done); }); withPromise.it('promise works F_OK and 222', function(done) { fs.promises.access('path/to/write/only', fs.F_OK).then(done, done); }); it('works W_OK and 222', function(done) { fs.access('path/to/write/only', fs.W_OK, done); }); withPromise.it('promise works W_OK and 222', function(done) { fs.promises.access('path/to/write/only', fs.W_OK).then(done, 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(); }); }); withPromise.it('promise generates EACCES for R_OK and 222', function(done) { fs.promises.access('path/to/write/only', fs.R_OK).then( function() { assert.fail('should not succeed.'); done(); }, 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(); }); }); withPromise.it('promise generates EACCES for X_OK and 222', function(done) { fs.promises.access('path/to/write/only', fs.X_OK).then( function() { assert.fail('should not succeed.'); done(); }, 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); }); withPromise.it('promise works for 333 (and no mode arg)', function(done) { fs.promises.access('path/to/333').then(done, done); }); it('works F_OK and 333', function(done) { fs.access('path/to/333', fs.F_OK, done); }); withPromise.it('promise works F_OK and 333', function(done) { fs.promises.access('path/to/333', fs.F_OK).then(done, done); }); it('works W_OK and 333', function(done) { fs.access('path/to/333', fs.W_OK, done); }); withPromise.it('promise works W_OK and 333', function(done) { fs.promises.access('path/to/333', fs.W_OK).then(done, done); }); it('works X_OK and 333', function(done) { fs.access('path/to/333', fs.X_OK, done); }); withPromise.it('promise works X_OK and 333', function(done) { fs.promises.access('path/to/333', fs.X_OK).then(done, done); }); it('works X_OK | W_OK and 333', function(done) { fs.access('path/to/333', fs.X_OK | fs.W_OK, done); }); withPromise.it('promise works X_OK | W_OK and 333', function(done) { fs.promises.access('path/to/333', fs.X_OK | fs.W_OK).then(done, 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(); }); }); withPromise.it('promise generates EACCES for R_OK and 333', function(done) { fs.promises.access('path/to/333', fs.R_OK).then( function() { assert.fail('should not succeed.'); done(); }, 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); }); withPromise.it('promise works for 444 (and no mode arg)', function(done) { fs.promises.access('path/to/444').then(done, done); }); it('works F_OK and 444', function(done) { fs.access('path/to/444', fs.F_OK, done); }); withPromise.it('promise works F_OK and 444', function(done) { fs.promises.access('path/to/444', fs.F_OK).then(done, done); }); it('works R_OK and 444', function(done) { fs.access('path/to/444', fs.R_OK, done); }); withPromise.it('promise works R_OK and 444', function(done) { fs.promises.access('path/to/444', fs.R_OK).then(done, 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(); }); }); withPromise.it('promise generates EACCES for W_OK and 444', function(done) { fs.promises.access('path/to/444', fs.W_OK).then( function() { assert.fail('should not succeed.'); done(); }, 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(); }); }); withPromise.it('promise generates EACCES for X_OK and 444', function(done) { fs.promises.access('path/to/444', fs.X_OK).then( function() { assert.fail('should not succeed.'); done(); }, 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); }); withPromise.it('promise works for 555 (and no mode arg)', function(done) { fs.promises.access('path/to/555').then(done, done); }); it('works F_OK and 555', function(done) { fs.access('path/to/555', fs.F_OK, done); }); withPromise.it('promise works F_OK and 555', function(done) { fs.promises.access('path/to/555', fs.F_OK).then(done, done); }); it('works R_OK and 555', function(done) { fs.access('path/to/555', fs.R_OK, done); }); withPromise.it('promise works R_OK and 555', function(done) { fs.promises.access('path/to/555', fs.R_OK).then(done, done); }); it('works X_OK and 555', function(done) { fs.access('path/to/555', fs.X_OK, done); }); withPromise.it('promise works X_OK and 555', function(done) { fs.promises.access('path/to/555', fs.X_OK).then(done, done); }); it('works R_OK | X_OK and 555', function(done) { fs.access('path/to/555', fs.R_OK | fs.X_OK, done); }); withPromise.it('promise works R_OK | X_OK and 555', function(done) { fs.promises.access('path/to/555', fs.R_OK | fs.X_OK).then(done, 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(); }); }); withPromise.it('promise generates EACCES for W_OK and 555', function(done) { fs.promises.access('path/to/555', fs.W_OK).then( function() { assert.fail('should not succeed.'); done(); }, 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); }); withPromise.it('promise works for 666 (and no mode arg)', function(done) { fs.promises.access('path/to/666').then(done, done); }); it('works F_OK and 666', function(done) { fs.access('path/to/666', fs.F_OK, done); }); withPromise.it('promise works F_OK and 666', function(done) { fs.promises.access('path/to/666', fs.F_OK).then(done, done); }); it('works R_OK and 666', function(done) { fs.access('path/to/666', fs.R_OK, done); }); withPromise.it('promise works R_OK and 666', function(done) { fs.promises.access('path/to/666', fs.R_OK).then(done, done); }); it('works W_OK and 666', function(done) { fs.access('path/to/666', fs.W_OK, done); }); withPromise.it('promise works W_OK and 666', function(done) { fs.promises.access('path/to/666', fs.W_OK).then(done, done); }); it('works R_OK | W_OK and 666', function(done) { fs.access('path/to/666', fs.R_OK | fs.W_OK, done); }); withPromise.it('promise works R_OK | W_OK and 666', function(done) { fs.promises.access('path/to/666', fs.R_OK | fs.W_OK).then(done, 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(); }); }); withPromise.it('promise generates EACCES for X_OK and 666', function(done) { fs.promises.access('path/to/666', fs.X_OK).then( function() { assert.fail('should not succeed.'); done(); }, 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); }); withPromise.it('promise works for 777 (and no mode arg)', function(done) { fs.promises.access('path/to/777').then(done, done); }); it('works F_OK and 777', function(done) { fs.access('path/to/777', fs.F_OK, done); }); withPromise.it('promise works F_OK and 777', function(done) { fs.promises.access('path/to/777', fs.F_OK).then(done, done); }); it('works R_OK and 777', function(done) { fs.access('path/to/777', fs.R_OK, done); }); withPromise.it('promise works R_OK and 777', function(done) { fs.promises.access('path/to/777', fs.R_OK).then(done, done); }); it('works W_OK and 777', function(done) { fs.access('path/to/777', fs.W_OK, done); }); withPromise.it('promise works W_OK and 777', function(done) { fs.promises.access('path/to/777', fs.W_OK).then(done, done); }); it('works X_OK and 777', function(done) { fs.access('path/to/777', fs.X_OK, done); }); withPromise.it('promise works X_OK and 777', function(done) { fs.promises.access('path/to/777', fs.X_OK).then(done, done); }); it('works X_OK | W_OK and 777', function(done) { fs.access('path/to/777', fs.X_OK | fs.W_OK, done); }); withPromise.it('promise works X_OK | W_OK and 777', function(done) { fs.promises.access('path/to/777', fs.X_OK | fs.W_OK).then(done, done); }); it('works X_OK | R_OK and 777', function(done) { fs.access('path/to/777', fs.X_OK | fs.R_OK, done); }); withPromise.it('promise works X_OK | R_OK and 777', function(done) { fs.promises.access('path/to/777', fs.X_OK | fs.R_OK).then(done, done); }); it('works R_OK | W_OK and 777', function(done) { fs.access('path/to/777', fs.R_OK | fs.W_OK, done); }); withPromise.it('promise works R_OK | W_OK and 777', function(done) { fs.promises.access('path/to/777', fs.R_OK | fs.W_OK).then(done, 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); }); withPromise.it('promise works R_OK | W_OK | X_OK and 777', function(done) { fs.promises .access('path/to/777', fs.R_OK | fs.W_OK | fs.X_OK) .then(done, 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(); }); }); withPromise.it( 'promise generates EACCESS for F_OK and an unreadable parent', function(done) { fs.promises.access('unreadable/readable-child').then( function() { assert.fail('should not succeed.'); done(); }, 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' }), 'broken-link': mock.symlink({path: './path/to/nothing'}), 'circular-link': mock.symlink({path: './loop-link'}), 'loop-link': mock.symlink({path: './circular-link'}) }); }); 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 broken link', function() { assert.throws(function() { fs.accessSync('broken-link'); }); }); it('throws ELOOP for circular link', function() { assert.throws(function() { fs.accessSync('circular-link'); }); }); 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); }); }); }); } mock-fs-4.10.4/test/lib/fs.appendFile.spec.js000066400000000000000000000073371356713366300206600ustar00rootroot00000000000000'use strict'; const helper = require('../helper'); const fs = require('fs'); const mock = require('../../lib/index'); const bufferFrom = require('../../lib/buffer').from; const assert = helper.assert; const withPromise = helper.withPromise; describe('fs.appendFile(filename, data, [options], callback)', function() { beforeEach(function() { mock({ 'dir/file.txt': 'file content', 'link.txt': mock.symlink({path: 'dir/file.txt'}) }); }); afterEach(mock.restore); it('writes a string to a new file', function(done) { fs.appendFile('foo', 'bar', function(err) { if (err) { return done(err); } assert.equal(String(fs.readFileSync('foo')), 'bar'); done(); }); }); withPromise.it('promise writes a string to a new file', function(done) { fs.promises.appendFile('foo', 'bar').then(function() { assert.equal(String(fs.readFileSync('foo')), 'bar'); done(); }, done); }); it('appends a string to an existing file', function(done) { fs.appendFile('dir/file.txt', ' bar', function(err) { if (err) { return done(err); } assert.equal(String(fs.readFileSync('dir/file.txt')), 'file content bar'); done(); }); }); withPromise.it('promise appends a string to an existing file', function( done ) { fs.promises.appendFile('dir/file.txt', ' bar').then(function() { assert.equal(String(fs.readFileSync('dir/file.txt')), 'file content bar'); done(); }, done); }); it('appends a buffer to a file', function(done) { fs.appendFile('dir/file.txt', bufferFrom(' bar'), function(err) { if (err) { return done(err); } assert.equal(String(fs.readFileSync('dir/file.txt')), 'file content bar'); done(); }); }); withPromise.it('promise appends a buffer to a file', function(done) { fs.promises.appendFile('dir/file.txt', bufferFrom(' bar')).then(function() { assert.equal(String(fs.readFileSync('dir/file.txt')), 'file content bar'); done(); }, done); }); it('appends via a symbolic link file', function(done) { fs.appendFile('link.txt', ' bar', function(err) { if (err) { return done(err); } assert.equal(String(fs.readFileSync('dir/file.txt')), 'file content bar'); done(); }); }); withPromise.it('promise appends via a symbolic link file', function(done) { fs.promises.appendFile('link.txt', ' bar').then(function() { assert.equal(String(fs.readFileSync('dir/file.txt')), 'file content bar'); done(); }, done); }); it('fails if directory does not exist', function(done) { fs.appendFile('foo/bar', 'baz', function(err) { assert.instanceOf(err, Error); done(); }); }); withPromise.it('promise fails if directory does not exist', function(done) { fs.promises.appendFile('foo/bar', 'baz').then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'ENOENT'); done(); } ); }); }); describe('fs.appendFileSync(filename, data, [options]', function() { beforeEach(function() { mock({ 'path/to/file': 'content' }); }); afterEach(mock.restore); it('writes a string to a new file', function() { fs.appendFileSync('foo', 'bar'); assert.equal(String(fs.readFileSync('foo')), 'bar'); }); it('appends a string to an existing file', function() { fs.appendFileSync('path/to/file', ' bar'); assert.equal(String(fs.readFileSync('path/to/file')), 'content bar'); }); it('fails if directory does not exist', function() { assert.throws(function() { fs.appendFileSync('foo/bar', 'baz'); }); }); }); mock-fs-4.10.4/test/lib/fs.chmod-fchmod.spec.js000066400000000000000000000067021356713366300211340ustar00rootroot00000000000000'use strict'; const helper = require('../helper'); const fs = require('fs'); const mock = require('../../lib/index'); const assert = helper.assert; const withPromise = helper.withPromise; describe('fs.chmod(path, mode, callback)', function() { beforeEach(function() { mock({ 'file.txt': mock.file({mode: parseInt('0644', 8)}) }); }); afterEach(mock.restore); it('changes permissions of a file', function(done) { fs.chmod('file.txt', parseInt('0664', 8), function(err) { if (err) { return done(err); } const stats = fs.statSync('file.txt'); assert.equal(stats.mode & parseInt('0777', 8), parseInt('0664', 8)); done(); }); }); withPromise.it('promise changes permissions of a file', function(done) { fs.promises.chmod('file.txt', parseInt('0664', 8)).then(function() { const stats = fs.statSync('file.txt'); assert.equal(stats.mode & parseInt('0777', 8), parseInt('0664', 8)); done(); }, done); }); it('fails if file does not exist', function(done) { fs.chmod('bogus.txt', parseInt('0664', 8), function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'ENOENT'); done(); }); }); withPromise.it('promise fails if file does not exist', function(done) { fs.promises.chmod('bogus.txt', parseInt('0664', 8)).then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'ENOENT'); done(); } ); }); }); describe('fs.chmodSync(path, mode)', function() { beforeEach(function() { mock({ 'file.txt': mock.file({mode: parseInt('0666', 8)}) }); }); afterEach(mock.restore); it('changes permissions of a file', function() { fs.chmodSync('file.txt', parseInt('0644', 8)); const stats = fs.statSync('file.txt'); assert.equal(stats.mode & parseInt('0777', 8), parseInt('0644', 8)); }); it('fails if file does not exist', function() { assert.throws(function() { fs.chmodSync('bogus.txt', parseInt('0644', 8)); }); }); }); describe('fs.fchmod(fd, mode, callback)', function() { beforeEach(function() { mock({ 'file.txt': mock.file({mode: parseInt('0666', 8)}) }); }); afterEach(mock.restore); it('changes permissions of a file', function(done) { const fd = fs.openSync('file.txt', 'r'); fs.fchmod(fd, parseInt('0644', 8), function(err) { if (err) { return done(err); } const stats = fs.statSync('file.txt'); assert.equal(stats.mode & parseInt('0777', 8), parseInt('0644', 8)); done(); }); }); withPromise.it('promise changes permissions of a file', function(done) { fs.promises .open('file.txt', 'r') .then(function(fd) { return fd.chmod(parseInt('0644', 8)); }) .then(function() { const stats = fs.statSync('file.txt'); assert.equal(stats.mode & parseInt('0777', 8), parseInt('0644', 8)); done(); }, done); }); }); describe('fs.fchmodSync(fd, mode)', function() { beforeEach(function() { mock({ 'file.txt': 'content' }); }); afterEach(mock.restore); it('changes permissions of a file', function() { const fd = fs.openSync('file.txt', 'r'); fs.fchmodSync(fd, parseInt('0444', 8)); const stats = fs.statSync('file.txt'); assert.equal(stats.mode & parseInt('0777', 8), parseInt('0444', 8)); }); }); mock-fs-4.10.4/test/lib/fs.chown-fchown.spec.js000066400000000000000000000046061356713366300212050ustar00rootroot00000000000000'use strict'; const helper = require('../helper'); const fs = require('fs'); const mock = require('../../lib/index'); const assert = helper.assert; const withPromise = helper.withPromise; describe('fs.chown(path, uid, gid, callback)', function() { beforeEach(function() { mock({ 'path/empty': {}, 'file.txt': 'content' }); }); afterEach(mock.restore); it('changes ownership of a file', function(done) { fs.chown('file.txt', 42, 43, done); }); withPromise.it('promise changes ownership of a file', function(done) { fs.promises.chown('file.txt', 42, 43).then(done, done); }); it('fails if file does not exist', function(done) { fs.chown('bogus.txt', 42, 43, function(err) { assert.instanceOf(err, Error); done(); }); }); withPromise.it('promise fails if file does not exist', function(done) { fs.promises.chown('bogus.txt', 42, 43).then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'ENOENT'); done(); } ); }); }); describe('fs.chownSync(path, uid, gid)', function() { beforeEach(function() { mock({ 'path/empty': {}, 'file.txt': 'content' }); }); afterEach(mock.restore); it('changes ownership of a file', function() { fs.chownSync('file.txt', 42, 43); }); it('fails if file does not exist', function() { assert.throws(function() { fs.chownSync('bogus.txt', 42, 43); }); }); }); describe('fs.fchown(fd, uid, gid, callback)', function() { beforeEach(function() { mock({ 'path/empty': {}, 'file.txt': 'content' }); }); afterEach(mock.restore); it('changes ownership of a file', function(done) { const fd = fs.openSync('file.txt', 'r'); fs.fchown(fd, 42, 43, done); }); withPromise.it('promise changes ownership of a file', function(done) { fs.promises .open('file.txt', 'r') .then(function(fd) { return fd.chown(42, 43); }) .then(done, done); }); }); describe('fs.fchownSync(fd, uid, gid)', function() { beforeEach(function() { mock({ 'path/empty': {}, 'file.txt': 'content' }); }); afterEach(mock.restore); it('changes ownership of a file', function() { const fd = fs.openSync('file.txt', 'r'); fs.fchownSync(fd, 42, 43); }); }); mock-fs-4.10.4/test/lib/fs.copyFile.spec.js000066400000000000000000000111301356713366300203450ustar00rootroot00000000000000'use strict'; const helper = require('../helper'); const fs = require('fs'); const mock = require('../../lib/index'); const assert = helper.assert; const withPromise = helper.withPromise; if (fs.copyFile && fs.copyFileSync) { describe('fs.copyFile(src, dest[, flags], callback)', function() { beforeEach(function() { mock({ 'path/to/src.txt': 'file content', 'path/to/other.txt': 'other file content', empty: {} }); }); afterEach(mock.restore); it('copies a file to an empty directory', function(done) { fs.copyFile('path/to/src.txt', 'empty/dest.txt', function(err) { assert.isTrue(!err); assert.isTrue(fs.existsSync('empty/dest.txt')); assert.equal(String(fs.readFileSync('empty/dest.txt')), 'file content'); done(); }); }); withPromise.it('promise copies a file to an empty directory', function( done ) { fs.promises .copyFile('path/to/src.txt', 'empty/dest.txt') .then(function() { assert.isTrue(fs.existsSync('empty/dest.txt')); assert.equal( String(fs.readFileSync('empty/dest.txt')), 'file content' ); done(); }, done); }); it('truncates dest file if it exists', function(done) { fs.copyFile('path/to/src.txt', 'path/to/other.txt', function(err) { assert.isTrue(!err); assert.equal( String(fs.readFileSync('path/to/other.txt')), 'file content' ); done(); }); }); withPromise.it('promise truncates dest file if it exists', function(done) { fs.promises .copyFile('path/to/src.txt', 'path/to/other.txt') .then(function() { assert.equal( String(fs.readFileSync('path/to/other.txt')), 'file content' ); done(); }, done); }); it('throws if dest exists and exclusive', function(done) { fs.copyFile( 'path/to/src.txt', 'path/to/other.txt', fs.constants.COPYFILE_EXCL, function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'EEXIST'); done(); } ); }); withPromise.it('promise throws if dest exists and exclusive', function( done ) { fs.promises .copyFile( 'path/to/src.txt', 'path/to/other.txt', fs.constants.COPYFILE_EXCL ) .then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'EEXIST'); done(); } ); }); it('fails if src does not exist', function(done) { fs.copyFile('path/to/bogus.txt', 'empty/dest.txt', function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'ENOENT'); done(); }); }); withPromise.it('promise fails if src does not exist', function(done) { fs.promises.copyFile('path/to/bogus.txt', 'empty/dest.txt').then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'ENOENT'); done(); } ); }); it('fails if dest path does not exist', function(done) { fs.copyFile('path/to/src.txt', 'path/nope/dest.txt', function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'ENOENT'); done(); }); }); withPromise.it('promise fails if dest path does not exist', function(done) { fs.promises.copyFile('path/to/src.txt', 'path/nope/dest.txt').then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'ENOENT'); done(); } ); }); it('fails if dest is a directory', function(done) { fs.copyFile('path/to/src.txt', 'empty', function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'EISDIR'); done(); }); }); withPromise.it('promise fails if dest is a directory', function(done) { fs.promises.copyFile('path/to/src.txt', 'empty').then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'EISDIR'); done(); } ); }); }); } mock-fs-4.10.4/test/lib/fs.createReadStream.spec.js000066400000000000000000000016511356713366300220150ustar00rootroot00000000000000'use strict'; const helper = require('../helper'); const fs = require('fs'); const mock = require('../../lib/index'); const assert = helper.assert; describe('fs.createReadStream(path, [options])', function() { beforeEach(function() { mock({ 'dir/source': 'source content' }); }); afterEach(mock.restore); it('creates a readable stream', function() { const stream = fs.createReadStream('dir/source'); assert.isTrue(stream.readable); }); it('allows piping to a writable stream', function(done) { const input = fs.createReadStream('dir/source'); const output = fs.createWriteStream('dir/dest'); output.on('close', function() { fs.readFile('dir/dest', function(err, data) { if (err) { return done(err); } assert.equal(String(data), 'source content'); done(); }); }); output.on('error', done); input.pipe(output); }); }); mock-fs-4.10.4/test/lib/fs.createWriteStream.spec.js000066400000000000000000000046071356713366300222400ustar00rootroot00000000000000'use strict'; const Writable = require('stream').Writable; const helper = require('../helper'); const fs = require('fs'); const mock = require('../../lib/index'); const bufferFrom = require('../../lib/buffer').from; const assert = helper.assert; describe('fs.createWriteStream(path[, options])', function() { beforeEach(function() { mock(); }); afterEach(mock.restore); it('provides a write stream for a file in buffered mode', function(done) { const output = fs.createWriteStream('test.txt'); output.on('close', function() { fs.readFile('test.txt', function(err, data) { if (err) { return done(err); } assert.equal(String(data), 'lots of source content'); done(); }); }); output.on('error', done); // if output._writev is available, buffered multiple writes will hit _writev. // otherwise, hit multiple _write. output.write(bufferFrom('lots ')); output.write(bufferFrom('of ')); output.write(bufferFrom('source ')); output.end(bufferFrom('content')); }); it('provides a write stream for a file', function(done) { const output = fs.createWriteStream('test.txt'); output.on('close', function() { fs.readFile('test.txt', function(err, data) { if (err) { return done(err); } assert.equal(String(data), 'lots of source content'); done(); }); }); output.on('error', done); output.write(bufferFrom('lots ')); setTimeout(function() { output.write(bufferFrom('of ')); setTimeout(function() { output.write(bufferFrom('source ')); setTimeout(function() { output.end(bufferFrom('content')); }, 50); }, 50); }, 50); }); if (Writable && Writable.prototype.cork) { it('works when write stream is corked', function(done) { const output = fs.createWriteStream('test.txt'); output.on('close', function() { fs.readFile('test.txt', function(err, data) { if (err) { return done(err); } assert.equal(String(data), 'lots of source content'); done(); }); }); output.on('error', done); output.cork(); output.write(bufferFrom('lots ')); output.write(bufferFrom('of ')); output.write(bufferFrom('source ')); output.end(bufferFrom('content')); output.uncork(); }); } }); mock-fs-4.10.4/test/lib/fs.exists.spec.js000066400000000000000000000061611356713366300201220ustar00rootroot00000000000000'use strict'; const helper = require('../helper'); const fs = require('fs'); const mock = require('../../lib/index'); const path = require('path'); const bufferFrom = require('../../lib/buffer').from; const assert = helper.assert; describe('fs.exists(path, callback)', function() { beforeEach(function() { mock({ 'path/to/a.bin': bufferFrom([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': bufferFrom([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'))); }); }); mock-fs-4.10.4/test/lib/fs.link-symlink.spec.js000066400000000000000000000164521356713366300212300ustar00rootroot00000000000000'use strict'; const helper = require('../helper'); const fs = require('fs'); const mock = require('../../lib/index'); const assert = helper.assert; const withPromise = helper.withPromise; describe('fs.link(srcpath, dstpath, callback)', function() { beforeEach(function() { mock({ dir: {}, 'file.txt': 'content' }); }); afterEach(mock.restore); it('creates a link to a file', function(done) { assert.equal(fs.statSync('file.txt').nlink, 1); fs.link('file.txt', 'link.txt', function(err) { if (err) { return done(err); } assert.isTrue(fs.statSync('link.txt').isFile()); assert.equal(fs.statSync('link.txt').nlink, 2); assert.equal(fs.statSync('file.txt').nlink, 2); assert.equal(String(fs.readFileSync('link.txt')), 'content'); done(); }); }); withPromise.it('promise creates a link to a file', function(done) { assert.equal(fs.statSync('file.txt').nlink, 1); fs.promises.link('file.txt', 'link.txt').then(function() { assert.isTrue(fs.statSync('link.txt').isFile()); assert.equal(fs.statSync('link.txt').nlink, 2); assert.equal(fs.statSync('file.txt').nlink, 2); assert.equal(String(fs.readFileSync('link.txt')), 'content'); done(); }, done); }); it('works if original is renamed', function(done) { fs.link('file.txt', 'link.txt', function(err) { if (err) { return done(err); } fs.renameSync('file.txt', 'renamed.txt'); assert.isTrue(fs.statSync('link.txt').isFile()); assert.equal(String(fs.readFileSync('link.txt')), 'content'); done(); }); }); withPromise.it('promise works if original is renamed', function(done) { fs.promises.link('file.txt', 'link.txt').then(function() { fs.renameSync('file.txt', 'renamed.txt'); assert.isTrue(fs.statSync('link.txt').isFile()); assert.equal(String(fs.readFileSync('link.txt')), 'content'); done(); }, done); }); it('works if original is removed', function(done) { assert.equal(fs.statSync('file.txt').nlink, 1); fs.link('file.txt', 'link.txt', function(err) { if (err) { return done(err); } assert.equal(fs.statSync('link.txt').nlink, 2); assert.equal(fs.statSync('file.txt').nlink, 2); fs.unlinkSync('file.txt'); assert.isTrue(fs.statSync('link.txt').isFile()); assert.equal(fs.statSync('link.txt').nlink, 1); assert.equal(String(fs.readFileSync('link.txt')), 'content'); done(); }); }); withPromise.it('promise works if original is removed', function(done) { assert.equal(fs.statSync('file.txt').nlink, 1); fs.promises.link('file.txt', 'link.txt').then(function() { assert.equal(fs.statSync('link.txt').nlink, 2); assert.equal(fs.statSync('file.txt').nlink, 2); fs.unlinkSync('file.txt'); assert.isTrue(fs.statSync('link.txt').isFile()); assert.equal(fs.statSync('link.txt').nlink, 1); assert.equal(String(fs.readFileSync('link.txt')), 'content'); done(); }, done); }); it('fails if original is a directory', function(done) { fs.link('dir', 'link', function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'EPERM'); done(); }); }); withPromise.it('promise fails if original is a directory', function(done) { fs.promises.link('dir', 'link').then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'EPERM'); done(); } ); }); }); describe('fs.linkSync(srcpath, dstpath)', function() { beforeEach(function() { mock({ 'file.txt': 'content' }); }); afterEach(mock.restore); it('creates a link to a file', function() { fs.linkSync('file.txt', 'link.txt'); assert.isTrue(fs.statSync('link.txt').isFile()); assert.equal(String(fs.readFileSync('link.txt')), 'content'); }); it('works if original is renamed', function() { fs.linkSync('file.txt', 'link.txt'); fs.renameSync('file.txt', 'renamed.txt'); assert.isTrue(fs.statSync('link.txt').isFile()); assert.equal(String(fs.readFileSync('link.txt')), 'content'); }); it('works if original is removed', function() { fs.linkSync('file.txt', 'link.txt'); fs.unlinkSync('file.txt'); assert.isTrue(fs.statSync('link.txt').isFile()); assert.equal(String(fs.readFileSync('link.txt')), 'content'); }); it('fails if original is a directory', function() { assert.throws(function() { fs.linkSync('dir', 'link'); }); }); }); describe('fs.symlink(srcpath, dstpath, [type], callback)', function() { beforeEach(function() { mock({ dir: {}, 'file.txt': 'content' }); }); afterEach(mock.restore); it('creates a symbolic link to a file', function(done) { fs.symlink('../file.txt', 'dir/link.txt', function(err) { if (err) { return done(err); } assert.isTrue(fs.statSync('dir/link.txt').isFile()); assert.equal(String(fs.readFileSync('dir/link.txt')), 'content'); done(); }); }); withPromise.it('promise creates a symbolic link to a file', function(done) { fs.promises.symlink('../file.txt', 'dir/link.txt').then(function() { assert.isTrue(fs.statSync('dir/link.txt').isFile()); assert.equal(String(fs.readFileSync('dir/link.txt')), 'content'); done(); }, done); }); it('breaks if original is renamed', function(done) { fs.symlink('file.txt', 'link.txt', function(err) { if (err) { return done(err); } assert.isTrue(fs.existsSync('link.txt')); fs.renameSync('file.txt', 'renamed.txt'); assert.isFalse(fs.existsSync('link.txt')); done(); }); }); withPromise.it('promise breaks if original is renamed', function(done) { fs.promises.symlink('file.txt', 'link.txt').then(function() { assert.isTrue(fs.existsSync('link.txt')); fs.renameSync('file.txt', 'renamed.txt'); assert.isFalse(fs.existsSync('link.txt')); done(); }, done); }); it('works if original is a directory', function(done) { fs.symlink('dir', 'link', function(err) { if (err) { return done(err); } assert.isTrue(fs.statSync('link').isDirectory()); done(); }); }); withPromise.it('promise works if original is a directory', function(done) { fs.promises.symlink('dir', 'link').then(function() { assert.isTrue(fs.statSync('link').isDirectory()); done(); }, done); }); }); describe('fs.symlinkSync(srcpath, dstpath, [type])', function() { beforeEach(function() { mock({ dir: {}, 'file.txt': 'content' }); }); afterEach(mock.restore); it('creates a symbolic link to a file', function() { fs.symlinkSync('../file.txt', 'dir/link.txt'); assert.isTrue(fs.statSync('dir/link.txt').isFile()); assert.equal(String(fs.readFileSync('dir/link.txt')), 'content'); }); it('breaks if original is renamed', function() { fs.symlinkSync('file.txt', 'link.txt'); assert.isTrue(fs.existsSync('link.txt')); fs.renameSync('file.txt', 'renamed.txt'); assert.isFalse(fs.existsSync('link.txt')); }); it('works if original is a directory', function() { fs.symlinkSync('dir', 'link'); assert.isTrue(fs.statSync('link').isDirectory()); }); }); mock-fs-4.10.4/test/lib/fs.lstat.spec.js000066400000000000000000000060101356713366300177230ustar00rootroot00000000000000'use strict'; const helper = require('../helper'); const fs = require('fs'); const mock = require('../../lib/index'); const assert = helper.assert; const withPromise = helper.withPromise; describe('fs.lstat(path, callback)', function() { beforeEach(function() { mock({ 'file.txt': mock.file({ content: 'content', mtime: new Date(1) }), link: mock.symlink({ path: './file.txt', mtime: new Date(2) }) }); }); afterEach(mock.restore); it('stats a symbolic link', function(done) { fs.lstat('link', function(err, stats) { if (err) { return done(err); } assert.isTrue(stats.isSymbolicLink()); assert.isFalse(stats.isFile()); assert.equal(stats.mtime.getTime(), 2); done(); }); }); withPromise.it('promise stats a symbolic link', function(done) { fs.promises.lstat('link').then(function(stats) { assert.isTrue(stats.isSymbolicLink()); assert.isFalse(stats.isFile()); assert.equal(stats.mtime.getTime(), 2); done(); }, done); }); it('stats a regular file', function(done) { fs.lstat('file.txt', function(err, stats) { if (err) { return done(err); } assert.isTrue(stats.isFile()); assert.isFalse(stats.isSymbolicLink()); assert.equal(stats.mtime.getTime(), 1); done(); }); }); withPromise.it('promise stats a regular file', function(done) { fs.promises.lstat('file.txt').then(function(stats) { assert.isTrue(stats.isFile()); assert.isFalse(stats.isSymbolicLink()); assert.equal(stats.mtime.getTime(), 1); done(); }, done); }); it('fails on file not exist', function(done) { fs.lstat('bogus', function(err, stats) { assert.instanceOf(err, Error); assert.equal(err.code, 'ENOENT'); done(); }); }); withPromise.it('promise fails on file not exist', function(done) { fs.promises.lstat('bogus').then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'ENOENT'); done(); } ); }); }); describe('fs.lstatSync(path)', function() { beforeEach(function() { mock({ 'file.txt': mock.file({ content: 'content', mtime: new Date(1) }), link: mock.symlink({ path: './file.txt', mtime: new Date(2) }) }); }); afterEach(mock.restore); it('stats a symbolic link', function() { const stats = fs.lstatSync('link'); assert.isTrue(stats.isSymbolicLink()); assert.isFalse(stats.isFile()); assert.equal(stats.mtime.getTime(), 2); }); it('stats a regular file', function() { const stats = fs.lstatSync('file.txt'); assert.isTrue(stats.isFile()); assert.isFalse(stats.isSymbolicLink()); assert.equal(stats.mtime.getTime(), 1); }); it('fails on file not exist', function() { assert.throws(function() { fs.lstatSync('bogus'); }); }); }); mock-fs-4.10.4/test/lib/fs.mkdir.spec.js000066400000000000000000000311161356713366300177070ustar00rootroot00000000000000'use strict'; const helper = require('../helper'); const fs = require('fs'); const mock = require('../../lib/index'); const assert = helper.assert; const inVersion = helper.inVersion; const withPromise = helper.withPromise; const testParentPerms = fs.access && fs.accessSync && process.getuid && process.getgid; describe('fs.mkdir(path, [mode], callback)', function() { beforeEach(function() { mock({ parent: { 'file.md': '', child: {} }, 'file.txt': '', unwriteable: mock.directory({mode: parseInt('0555', 8)}) }); }); afterEach(mock.restore); it('creates a new directory', function(done) { fs.mkdir('parent/dir', function(err) { if (err) { return done(err); } const stats = fs.statSync('parent/dir'); assert.isTrue(stats.isDirectory()); done(); }); }); withPromise.it('promise creates a new directory', function(done) { fs.promises.mkdir('parent/dir').then(function() { const stats = fs.statSync('parent/dir'); assert.isTrue(stats.isDirectory()); done(); }, done); }); inVersion('>=10.12').it('creates a new directory recursively', function( done ) { fs.mkdir('parent/foo/bar/dir', {recursive: true}, function(err) { if (err) { return done(err); } let stats = fs.statSync('parent/foo/bar/dir'); assert.isTrue(stats.isDirectory()); stats = fs.statSync('parent/foo/bar'); assert.isTrue(stats.isDirectory()); stats = fs.statSync('parent/foo'); assert.isTrue(stats.isDirectory()); done(); }); }); withPromise.it('promise creates a new directory recursively', function(done) { fs.promises.mkdir('parent/foo/bar/dir', {recursive: true}).then(function() { let stats = fs.statSync('parent/foo/bar/dir'); assert.isTrue(stats.isDirectory()); stats = fs.statSync('parent/foo/bar'); assert.isTrue(stats.isDirectory()); stats = fs.statSync('parent/foo'); assert.isTrue(stats.isDirectory()); done(); }, done); }); it('accepts dir mode', function(done) { fs.mkdir('parent/dir', parseInt('0755', 8), function(err) { if (err) { return done(err); } const stats = fs.statSync('parent/dir'); assert.isTrue(stats.isDirectory()); assert.equal(stats.mode & parseInt('0777', 8), parseInt('0755', 8)); done(); }); }); withPromise.it('promise accepts dir mode', function(done) { fs.promises.mkdir('parent/dir', parseInt('0755', 8)).then(function() { const stats = fs.statSync('parent/dir'); assert.isTrue(stats.isDirectory()); assert.equal(stats.mode & parseInt('0777', 8), parseInt('0755', 8)); done(); }, done); }); inVersion('>=10.12').it('accepts dir mode recursively', function(done) { fs.mkdir( 'parent/foo/bar/dir', {recursive: true, mode: parseInt('0755', 8)}, function(err) { if (err) { return done(err); } let stats = fs.statSync('parent/foo/bar/dir'); assert.isTrue(stats.isDirectory()); assert.equal(stats.mode & parseInt('0777', 8), parseInt('0755', 8)); stats = fs.statSync('parent/foo/bar'); assert.isTrue(stats.isDirectory()); assert.equal(stats.mode & parseInt('0777', 8), parseInt('0755', 8)); stats = fs.statSync('parent/foo'); assert.isTrue(stats.isDirectory()); assert.equal(stats.mode & parseInt('0777', 8), parseInt('0755', 8)); done(); } ); }); withPromise.it('promise accepts dir mode recursively', function(done) { fs.promises .mkdir('parent/foo/bar/dir', {recursive: true, mode: parseInt('0755', 8)}) .then(function() { let stats = fs.statSync('parent/foo/bar/dir'); assert.isTrue(stats.isDirectory()); assert.equal(stats.mode & parseInt('0777', 8), parseInt('0755', 8)); stats = fs.statSync('parent/foo/bar'); assert.isTrue(stats.isDirectory()); assert.equal(stats.mode & parseInt('0777', 8), parseInt('0755', 8)); stats = fs.statSync('parent/foo'); assert.isTrue(stats.isDirectory()); assert.equal(stats.mode & parseInt('0777', 8), parseInt('0755', 8)); done(); }, done); }); it('fails if parent does not exist', function(done) { fs.mkdir('parent/bogus/dir', function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'ENOENT'); done(); }); }); withPromise.it('promise fails if parent does not exist', function(done) { fs.promises.mkdir('parent/bogus/dir').then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'ENOENT'); done(); } ); }); inVersion('>=10.12').it( 'fails if one parent is not a folder in recursive creation', function(done) { fs.mkdir('file.txt/bogus/dir', {recursive: true}, function(err) { assert.instanceOf(err, Error); done(); }); } ); withPromise.it( 'promise fails if one parent is not a folder in recursive creation', function(done) { fs.promises.mkdir('file.txt/bogus/dir', {recursive: true}).then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); done(); } ); } ); inVersion('>=10.12').it( 'fails if permission does not allow recursive creation', function(done) { fs.mkdir( 'parent/foo/bar/dir', {recursive: true, mode: parseInt('0400', 8)}, function(err) { assert.instanceOf(err, Error); done(); } ); } ); withPromise.it( 'promise fails if permission does not allow recursive creation', function(done) { fs.promises .mkdir('parent/foo/bar/dir', { recursive: true, mode: parseInt('0400', 8) }) .then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); done(); } ); } ); it('fails if directory already exists', function(done) { fs.mkdir('parent', function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'EEXIST'); done(); }); }); withPromise.it('promise fails if directory already exists', function(done) { fs.promises.mkdir('parent').then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'EEXIST'); done(); } ); }); it('fails if file already exists', function(done) { fs.mkdir('file.txt', function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'EEXIST'); done(); }); }); withPromise.it('promise fails if file already exists', function(done) { fs.promises.mkdir('file.txt').then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'EEXIST'); done(); } ); }); inVersion('>=10.12').it( 'fails in recursive mode if file already exists', function(done) { fs.mkdir('parent/file.md', {recursive: true}, function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'EEXIST'); done(); }); } ); withPromise.it( 'promise fails in recursive mode if file already exists', function(done) { fs.promises.mkdir('parent/file.md', {recursive: true}).then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'EEXIST'); done(); } ); } ); inVersion('>=10.12').it( 'passes in recursive mode if directory already exists', function(done) { fs.mkdir('parent/child', {recursive: true}, function(err) { assert.isNotOk(err, Error); done(); }); } ); withPromise.it( 'promise passes in recursive mode if directory already exists', function(done) { fs.promises.mkdir('parent/child', {recursive: true}).then(done, done); } ); if (testParentPerms) { it('fails if parent is not writeable', function(done) { fs.mkdir('unwriteable/child', function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'EACCES'); done(); }); }); withPromise.it('promise fails if parent is not writeable', function(done) { fs.promises.mkdir('unwriteable/child').then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'EACCES'); done(); } ); }); } it('calls callback with a single argument on success', function(done) { fs.mkdir('parent/arity', function(_) { assert.equal(arguments.length, 1); done(); }); }); it('calls callback with a single argument on failure', function(done) { fs.mkdir('parent', function(err) { assert.instanceOf(err, Error); done(); }); }); }); describe('fs.mkdirSync(path, [mode])', function() { beforeEach(function() { mock({ parent: { 'file.md': '', child: {} }, 'file.txt': 'content', unwriteable: mock.directory({mode: parseInt('0555', 8)}) }); }); afterEach(mock.restore); it('creates a new directory', function() { fs.mkdirSync('parent/dir'); const stats = fs.statSync('parent/dir'); assert.isTrue(stats.isDirectory()); }); inVersion('>=10.12').it('creates a new directory recursively', function() { fs.mkdirSync('parent/foo/bar/dir', {recursive: true}); let stats = fs.statSync('parent/foo/bar/dir'); assert.isTrue(stats.isDirectory()); stats = fs.statSync('parent/foo/bar'); assert.isTrue(stats.isDirectory()); stats = fs.statSync('parent/foo'); assert.isTrue(stats.isDirectory()); }); it('accepts dir mode', function() { fs.mkdirSync('parent/dir', parseInt('0755', 8)); const stats = fs.statSync('parent/dir'); assert.isTrue(stats.isDirectory()); assert.equal(stats.mode & parseInt('0777', 8), parseInt('0755', 8)); }); inVersion('>=10.12').it('accepts dir mode recursively', function() { fs.mkdirSync('parent/foo/bar/dir', { recursive: true, mode: parseInt('0755', 8) }); let stats = fs.statSync('parent/foo/bar/dir'); assert.isTrue(stats.isDirectory()); assert.equal(stats.mode & parseInt('0777', 8), parseInt('0755', 8)); stats = fs.statSync('parent/foo/bar'); assert.isTrue(stats.isDirectory()); assert.equal(stats.mode & parseInt('0777', 8), parseInt('0755', 8)); stats = fs.statSync('parent/foo'); assert.isTrue(stats.isDirectory()); assert.equal(stats.mode & parseInt('0777', 8), parseInt('0755', 8)); }); it('fails if parent does not exist', function() { assert.throws(function() { fs.mkdirSync('parent/bogus/dir'); }); }); inVersion('>=10.12').it( 'fails if one parent is not a folder in recursive creation', function() { assert.throws(function() { fs.mkdirSync('file.txt/bogus/dir', {recursive: true}); }); } ); inVersion('>=10.12').it( 'fails if permission does not allow recursive creation', function() { assert.throws(function() { fs.mkdirSync('parent/foo/bar/dir', { recursive: true, mode: parseInt('0400', 8) }); }); } ); it('fails if directory already exists', function() { assert.throws(function() { fs.mkdirSync('parent'); }); }); it('fails if file already exists', function() { assert.throws(function() { fs.mkdirSync('file.txt'); }); }); inVersion('>=10.12').it( 'fails in recursive mode if file already exists', function() { assert.throws(function() { fs.mkdirSync('parent/file.md', {recursive: true}); }); } ); inVersion('>=10.12').it( 'passes in recursive mode if directory already exists', function() { assert.doesNotThrow(function() { fs.mkdirSync('parent/child', {recursive: true}); }); } ); if (testParentPerms) { it('fails if parent is not writeable', function() { assert.throws(function() { fs.mkdirSync('unwriteable/child'); }); }); } }); mock-fs-4.10.4/test/lib/fs.mkdtemp.spec.js000066400000000000000000000243351356713366300202470ustar00rootroot00000000000000'use strict'; const helper = require('../helper'); const fs = require('fs'); const mock = require('../../lib/index'); const path = require('path'); const assert = helper.assert; const inVersion = helper.inVersion; const withPromise = helper.withPromise; const testParentPerms = fs.access && fs.accessSync && process.getuid && process.getgid; if (fs.mkdtemp) { describe('fs.mkdtemp(prefix[, options], callback)', function() { beforeEach(function() { mock({ parent: {}, file: 'contents', unwriteable: mock.directory({mode: parseInt('0555', 8)}) }); }); afterEach(mock.restore); it('creates a new directory', function(done) { fs.mkdtemp('parent/dir', function(err, dirPath) { if (err) { return done(err); } const parentPath = path.dirname(dirPath); assert.equal(parentPath, 'parent'); const stats = fs.statSync(dirPath); assert.isTrue(stats.isDirectory()); done(); }); }); withPromise.it('promise creates a new directory', function(done) { fs.promises.mkdtemp('parent/dir').then(function(dirPath) { const parentPath = path.dirname(dirPath); assert.equal(parentPath, 'parent'); const stats = fs.statSync(dirPath); assert.isTrue(stats.isDirectory()); done(); }, done); }); inVersion('>=6').it('accepts a "utf8" encoding argument', function(done) { fs.mkdtemp('parent/dir', 'utf8', function(err, dirPath) { if (err) { return done(err); } assert.isString(dirPath); const parentPath = path.dirname(dirPath); assert.equal(parentPath, 'parent'); const stats = fs.statSync(dirPath); assert.isTrue(stats.isDirectory()); done(); }); }); withPromise.it('promise accepts a "utf8" encoding argument', function( done ) { fs.promises.mkdtemp('parent/dir', 'utf8').then(function(dirPath) { assert.isString(dirPath); const parentPath = path.dirname(dirPath); assert.equal(parentPath, 'parent'); const stats = fs.statSync(dirPath); assert.isTrue(stats.isDirectory()); done(); }, done); }); inVersion('>=6').it('accepts a "buffer" encoding argument', function(done) { fs.mkdtemp('parent/dir', 'buffer', function(err, buffer) { if (err) { return done(err); } assert.instanceOf(buffer, Buffer); const dirPath = buffer.toString(); const parentPath = path.dirname(dirPath); assert.equal(parentPath, 'parent'); const stats = fs.statSync(dirPath); assert.isTrue(stats.isDirectory()); done(); }); }); withPromise.it('promise accepts a "buffer" encoding argument', function( done ) { fs.promises.mkdtemp('parent/dir', 'buffer').then(function(buffer) { assert.instanceOf(buffer, Buffer); const dirPath = buffer.toString(); const parentPath = path.dirname(dirPath); assert.equal(parentPath, 'parent'); const stats = fs.statSync(dirPath); assert.isTrue(stats.isDirectory()); done(); }, done); }); inVersion('>=6').it( 'accepts an options argument with "utf8" encoding', function(done) { fs.mkdtemp('parent/dir', {encoding: 'utf8'}, function(err, dirPath) { if (err) { return done(err); } assert.isString(dirPath); const parentPath = path.dirname(dirPath); assert.equal(parentPath, 'parent'); const stats = fs.statSync(dirPath); assert.isTrue(stats.isDirectory()); done(); }); } ); withPromise.it( 'promise accepts an options argument with "utf8" encoding', function(done) { fs.promises .mkdtemp('parent/dir', {encoding: 'utf8'}) .then(function(dirPath) { assert.isString(dirPath); const parentPath = path.dirname(dirPath); assert.equal(parentPath, 'parent'); const stats = fs.statSync(dirPath); assert.isTrue(stats.isDirectory()); done(); }, done); } ); inVersion('>=6').it( 'accepts an options argument with "buffer" encoding', function(done) { fs.mkdtemp('parent/dir', {encoding: 'buffer'}, function(err, buffer) { if (err) { return done(err); } assert.instanceOf(buffer, Buffer); const dirPath = buffer.toString(); const parentPath = path.dirname(dirPath); assert.equal(parentPath, 'parent'); const stats = fs.statSync(dirPath); assert.isTrue(stats.isDirectory()); done(); }); } ); withPromise.it( 'promise accepts an options argument with "buffer" encoding', function(done) { fs.promises .mkdtemp('parent/dir', {encoding: 'buffer'}) .then(function(buffer) { assert.instanceOf(buffer, Buffer); const dirPath = buffer.toString(); const parentPath = path.dirname(dirPath); assert.equal(parentPath, 'parent'); const stats = fs.statSync(dirPath); assert.isTrue(stats.isDirectory()); done(); }, done); } ); it('fails if parent does not exist', function(done) { fs.mkdtemp('unknown/child', function(err, dirPath) { if (!err || dirPath) { done(new Error('Expected failure')); } else { assert.isTrue(!dirPath); assert.instanceOf(err, Error); assert.equal(err.code, 'ENOENT'); done(); } }); }); withPromise.it('promise fails if parent does not exist', function(done) { fs.promises.mkdtemp('unknown/child').then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'ENOENT'); done(); } ); }); it('fails if parent is a file', function(done) { fs.mkdtemp('file/child', function(err, dirPath) { if (!err || dirPath) { done(new Error('Expected failure')); } else { assert.isTrue(!dirPath); assert.instanceOf(err, Error); assert.equal(err.code, 'ENOTDIR'); done(); } }); }); withPromise.it('promise fails if parent is a file', function(done) { fs.promises.mkdtemp('file/child').then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'ENOTDIR'); done(); } ); }); if (testParentPerms) { it('fails if parent is not writeable', function(done) { fs.mkdtemp('unwriteable/child', function(err, dirPath) { if (!err || dirPath) { done(new Error('Expected failure')); } else { assert.isTrue(!dirPath); assert.instanceOf(err, Error); assert.equal(err.code, 'EACCES'); done(); } }); }); withPromise.it('promise fails if parent is not writeable', function( done ) { fs.promises.mkdtemp('unwriteable/child').then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'EACCES'); done(); } ); }); } }); } if (fs.mkdtempSync) { describe('fs.mkdtempSync(prefix[, options])', function() { beforeEach(function() { mock({ parent: {}, file: 'contents', unwriteable: mock.directory({mode: parseInt('0555', 8)}) }); }); afterEach(mock.restore); it('creates a new directory', function() { const dirPath = fs.mkdtempSync('parent/dir'); const parentPath = path.dirname(dirPath); assert.equal(parentPath, 'parent'); const stats = fs.statSync(dirPath); assert.isTrue(stats.isDirectory()); }); inVersion('>=6').it('accepts a "utf8" encoding argument', function() { const dirPath = fs.mkdtempSync('parent/dir', 'utf8'); assert.isString(dirPath); const parentPath = path.dirname(dirPath); assert.equal(parentPath, 'parent'); const stats = fs.statSync(dirPath); assert.isTrue(stats.isDirectory()); }); inVersion('>=6').it('accepts a "buffer" encoding argument', function() { const buffer = fs.mkdtempSync('parent/dir', 'buffer'); assert.instanceOf(buffer, Buffer); const dirPath = buffer.toString(); const parentPath = path.dirname(dirPath); assert.equal(parentPath, 'parent'); const stats = fs.statSync(dirPath); assert.isTrue(stats.isDirectory()); }); inVersion('>=6').it( 'accepts an options argument with "utf8" encoding', function() { const dirPath = fs.mkdtempSync('parent/dir', {encoding: 'utf8'}); assert.isString(dirPath); const parentPath = path.dirname(dirPath); assert.equal(parentPath, 'parent'); const stats = fs.statSync(dirPath); assert.isTrue(stats.isDirectory()); } ); inVersion('>=6').it( 'accepts an options argument with "buffer" encoding', function() { const buffer = fs.mkdtempSync('parent/dir', {encoding: 'buffer'}); assert.instanceOf(buffer, Buffer); const dirPath = buffer.toString(); const parentPath = path.dirname(dirPath); assert.equal(parentPath, 'parent'); const stats = fs.statSync(dirPath); assert.isTrue(stats.isDirectory()); } ); it('fails if parent does not exist', function() { assert.throws(function() { fs.mkdtempSync('unknown/child'); }); }); it('fails if parent is a file', function() { assert.throws(function() { fs.mkdtempSync('file/child'); }); }); if (testParentPerms) { it('fails if parent is not writeable', function() { assert.throws(function() { fs.mkdtempSync('unwriteable/child'); }); }); } }); } mock-fs-4.10.4/test/lib/fs.open-close.spec.js000066400000000000000000000142531356713366300206500ustar00rootroot00000000000000'use strict'; const helper = require('../helper'); const fs = require('fs'); const mock = require('../../lib/index'); const assert = helper.assert; const withPromise = helper.withPromise; 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(); }); }); withPromise.it('promise opens an existing file for reading (r)', function( done ) { fs.promises.open('nested/sub/dir/one.txt', 'r').then(function(fd) { assert.isNumber(fd.fd); done(); }, done); }); it('fails if file does not exist (r)', function(done) { fs.open('bogus.txt', 'r', function(err, fd) { assert.instanceOf(err, Error); assert.equal(err.code, 'ENOENT'); done(); }); }); withPromise.it('promise fails if file does not exist (r)', function(done) { fs.promises.open('bogus.txt', 'r').then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'ENOENT'); 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(); }); }); withPromise.it('promise creates a new file for writing (w)', function(done) { fs.promises .open('path/to/new.txt', 'w', parseInt('0666', 8)) .then(function(fd) { assert.isNumber(fd.fd); assert.isTrue(fs.existsSync('path/to/new.txt')); done(); }, done); }); it('opens an existing file for writing (w)', function(done) { fs.open('path/to/file.txt', 'w', parseInt('0666', 8), function(err, fd) { if (err) { return done(err); } assert.isNumber(fd); done(); }); }); withPromise.it('promise opens an existing file for writing (w)', function( done ) { fs.promises .open('path/to/file.txt', 'w', parseInt('0666', 8)) .then(function(fd) { assert.isNumber(fd.fd); done(); }, done); }); it('fails if file exists (wx)', function(done) { fs.open('path/to/file.txt', 'wx', parseInt('0666', 8), function(err, fd) { assert.instanceOf(err, Error); assert.equal(err.code, 'EEXIST'); done(); }); }); withPromise.it('promise fails if file exists (wx)', function(done) { fs.promises.open('path/to/file.txt', 'wx', parseInt('0666', 8)).then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'EEXIST'); 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() { const 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() { const 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() { const 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) { const fd = fs.openSync('dir/file.txt', 'w'); fs.close(fd, function(err) { done(err); }); }); withPromise.it('promise closes a file descriptor', function(done) { fs.promises .open('dir/file.txt', 'w') .then(function(fd) { return fd.close(); }) .then(done, done); }); it('fails for closed file descriptors', function(done) { const fd = fs.openSync('dir/file.txt', 'w'); fs.close(fd, function(err) { if (err) { return done(err); } fs.close(fd, function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'EBADF'); done(); }); }); }); withPromise.it('promise fails for closed file descriptors', function(done) { fs.promises .open('dir/file.txt', 'w') .then(function(fd) { return fd.close().then(function() { return fd.close(); }); }) .then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'EBADF'); done(); } ); }); }); describe('fs.closeSync(fd)', function() { beforeEach(function() { mock({dir: {}}); }); afterEach(mock.restore); it('closes a file descriptor', function() { const fd = fs.openSync('dir/file.txt', 'w'); fs.closeSync(fd); }); it('fails for closed file descriptors', function() { const fd = fs.openSync('dir/file.txt', 'w'); fs.closeSync(fd); assert.throws(function() { fs.closeSync(fd); }); }); }); mock-fs-4.10.4/test/lib/fs.read.spec.js000066400000000000000000000221711356713366300175150ustar00rootroot00000000000000'use strict'; const helper = require('../helper'); const fs = require('fs'); const mock = require('../../lib/index'); const bufferAlloc = require('../../lib/buffer').alloc; const assert = helper.assert; const withPromise = helper.withPromise; 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); } const buffer = bufferAlloc(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(); }); }); }); withPromise.it('promise allows file contents to be read', function(done) { const buffer = bufferAlloc(12); fs.promises .open('path/to/file.txt', 'r') .then(function(fd) { return fd.read(buffer, 0, 12, 0); }) .then(function(result) { assert.equal(result.bytesRead, 12); assert.equal(result.buffer, buffer); assert.equal(String(buffer), 'file content'); done(); }, 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); } const buffer = bufferAlloc(12); fs.read(fd, buffer, 5, 7, 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(); }); }); }); withPromise.it('promise allows file contents to be read w/ offset', function( done ) { const buffer = bufferAlloc(12); fs.promises .open('path/to/file.txt', 'r') .then(function(fd) { return fd.read(buffer, 5, 7, 0); }) .then(function(result) { assert.equal(result.bytesRead, 7); assert.equal(result.buffer, buffer); assert.equal(String(buffer.slice(5)), 'file co'); done(); }, 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); } const buffer = bufferAlloc(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(); }); }); }); withPromise.it('promise allows file contents to be read w/ length', function( done ) { const buffer = bufferAlloc(12); fs.promises .open('path/to/file.txt', 'r') .then(function(fd) { return fd.read(buffer, 0, 4, 0); }) .then(function(result) { assert.equal(result.bytesRead, 4); assert.equal(result.buffer, buffer); assert.equal(String(buffer.slice(0, 4)), 'file'); done(); }, 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); } const buffer = bufferAlloc(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(); }); }); }); withPromise.it( 'promise allows file contents to be read w/ offset & length', function(done) { const buffer = bufferAlloc(12); fs.promises .open('path/to/file.txt', 'r') .then(function(fd) { return fd.read(buffer, 2, 4, 0); }) .then(function(result) { assert.equal(result.bytesRead, 4); assert.equal(result.buffer, buffer); assert.equal(String(buffer.slice(2, 6)), 'file'); done(); }, 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); } const buffer = bufferAlloc(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(); }); }); }); withPromise.it( 'promise allows file contents to be read w/ position', function(done) { const buffer = bufferAlloc(7); fs.promises .open('path/to/file.txt', 'r') .then(function(fd) { return fd.read(buffer, 0, 7, 5); }) .then(function(result) { assert.equal(result.bytesRead, 7); assert.equal(result.buffer, buffer); assert.equal(String(buffer), 'content'); done(); }, 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); } const buffer = bufferAlloc(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(); }); }); }); withPromise.it('promise allows read w/ offset, length, & position', function( done ) { const buffer = bufferAlloc(12); fs.promises .open('path/to/file.txt', 'r') .then(function(fd) { return fd.read(buffer, 2, 7, 5); }) .then(function(result) { assert.equal(result.bytesRead, 7); assert.equal(result.buffer, buffer); assert.equal(String(buffer.slice(2, 9)), 'content'); done(); }, done); }); it('fails for closed file descriptor', function(done) { const fd = fs.openSync('path/to/file.txt', 'r'); fs.closeSync(fd); fs.read(fd, bufferAlloc(12), 0, 12, 0, function(err, bytesRead, buf) { assert.instanceOf(err, Error); assert.equal(err.code, 'EBADF'); assert.equal(0, bytesRead); done(); }); }); withPromise.it('promise fails for closed file descriptor', function(done) { fs.promises .open('path/to/file.txt', 'r') .then(function(fd) { return fd.close().then(function() { return fd.read(bufferAlloc(12), 0, 12, 0); }); }) .then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'EBADF'); done(); } ); }); it('fails if not open for reading', function(done) { const fd = fs.openSync('path/to/file.txt', 'w'); fs.read(fd, bufferAlloc(12), 0, 12, 0, function(err, bytesRead, buf) { assert.instanceOf(err, Error); assert.equal(0, bytesRead); done(); }); }); withPromise.it('promise fails if not open for reading', function(done) { fs.promises .open('path/to/file.txt', 'w') .then(function(fd) { return fd.read(bufferAlloc(12), 0, 12, 0); }) .then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'EBADF'); 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() { const fd = fs.openSync('path/to/file.txt', 'r'); const buffer = bufferAlloc(12); const 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() { const fd = fs.openSync('path/to/file.txt', 'r'); const first = bufferAlloc(4); fs.readSync(fd, first, 0, 4, 0); assert.equal(String(first), 'file'); const second = bufferAlloc(7); fs.readSync(fd, second, 0, 7, 5); assert.equal(String(second), 'content'); }); it('treats null position as current position', function() { const fd = fs.openSync('path/to/file.txt', 'r'); const first = bufferAlloc(4); fs.readSync(fd, first, 0, 4, null); assert.equal(String(first), 'file'); // consume the space assert.equal(fs.readSync(fd, bufferAlloc(1), 0, 1, null), 1); const second = bufferAlloc(7); fs.readSync(fd, second, 0, 7, null); assert.equal(String(second), 'content'); }); }); mock-fs-4.10.4/test/lib/fs.readFile.spec.js000066400000000000000000000056601356713366300203210ustar00rootroot00000000000000'use strict'; const helper = require('../helper'); const fs = require('fs'); const mock = require('../../lib/index'); const assert = helper.assert; const withPromise = helper.withPromise; 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(); }); }); withPromise.it('promise allows a file to be read asynchronously', function( done ) { fs.promises.readFile('path/to/file.txt').then(function(data) { assert.isTrue(Buffer.isBuffer(data)); assert.equal(String(data), 'file content'); done(); }, done); }); it('fails for directory', function(done) { fs.readFile('path/to', function(err, data) { assert.instanceOf(err, Error); assert.equal(err.code, 'EBADF'); done(); }); }); withPromise.it('promise fails for directory', function(done) { fs.promises.readFile('path/to').then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'EBADF'); done(); } ); }); it('fails for bad path', function(done) { fs.readFile('path/to/bogus', function(err, data) { assert.instanceOf(err, Error); // windows has different errno for ENOENT assert.equal(err.code, 'ENOENT'); done(); }); }); withPromise.it('promise fails for bad path', function(done) { fs.promises.readFile('path/to/bogus').then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); // windows has different errno for ENOENT assert.equal(err.code, 'ENOENT'); 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() { const 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'); }); }); }); mock-fs-4.10.4/test/lib/fs.readdir.spec.js000066400000000000000000000057301356713366300202160ustar00rootroot00000000000000'use strict'; const helper = require('../helper'); const fs = require('fs'); const mock = require('../../lib/index'); const path = require('path'); const assert = helper.assert; const withPromise = helper.withPromise; 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(); }); }); withPromise.it('promise lists directory contents', function(done) { fs.promises.readdir(path.join('path', 'to')).then(function(items) { assert.isArray(items); assert.deepEqual(items, ['file.txt']); done(); }, 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(); }); }); withPromise.it('promise lists nested directory contents', function(done) { fs.promises .readdir(path.join('nested', 'sub', 'dir')) .then(function(items) { assert.isArray(items); assert.deepEqual(items, ['empty', 'one.txt', 'two.txt']); done(); }, 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(); }); }); withPromise.it('promise calls with an error for bogus path', function(done) { fs.promises.readdir('bogus').then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); 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() { const items = fs.readdirSync(path.join('path', 'to')); assert.isArray(items); assert.deepEqual(items, ['file.txt']); }); it('lists nested directory contents', function() { const 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'); }); }); }); mock-fs-4.10.4/test/lib/fs.readlink.spec.js000066400000000000000000000033021356713366300203660ustar00rootroot00000000000000'use strict'; const helper = require('../helper'); const fs = require('fs'); const mock = require('../../lib/index'); const assert = helper.assert; const withPromise = helper.withPromise; describe('fs.readlink(path, callback)', function() { beforeEach(function() { mock({ 'file.txt': 'content', link: mock.symlink({path: './file.txt'}) }); }); afterEach(mock.restore); it('reads a symbolic link', function(done) { fs.readlink('link', function(err, srcPath) { if (err) { return done(err); } assert.equal(srcPath, './file.txt'); done(); }); }); withPromise.it('promise reads a symbolic link', function(done) { fs.promises.readlink('link').then(function(srcPath) { assert.equal(srcPath, './file.txt'); done(); }, done); }); it('fails for regular files', function(done) { fs.readlink('file.txt', function(err, srcPath) { assert.instanceOf(err, Error); done(); }); }); withPromise.it('promise fails for regular files', function(done) { fs.promises.readlink('file.txt').then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); done(); } ); }); }); describe('fs.readlinkSync(path)', function() { beforeEach(function() { mock({ 'file.txt': 'content', link: mock.symlink({path: './file.txt'}) }); }); afterEach(mock.restore); it('reads a symbolic link', function() { assert.equal(fs.readlinkSync('link'), './file.txt'); }); it('fails for regular files', function() { assert.throws(function() { fs.readlinkSync('file.txt'); }); }); }); mock-fs-4.10.4/test/lib/fs.realpath.spec.js000066400000000000000000000110731356713366300204010ustar00rootroot00000000000000'use strict'; const helper = require('../helper'); const fs = require('fs'); const path = require('path'); const mock = require('../../lib/index'); const assert = helper.assert; const assertEqualPaths = helper.assertEqualPaths; const withPromise = helper.withPromise; describe('fs.realpath(path, [cache], callback)', function() { beforeEach(function() { mock({ 'dir/file.txt': 'content', link: mock.symlink({path: './dir/file.txt'}) }); }); afterEach(mock.restore); it('resolves the real path for a symbolic link', function(done) { fs.realpath('link', function(err, resolved) { if (err) { return done(err); } assertEqualPaths(resolved, path.resolve('dir/file.txt')); done(); }); }); withPromise.it('promise resolves the real path for a symbolic link', function( done ) { fs.promises.realpath('link').then(function(resolved) { assertEqualPaths(resolved, path.resolve('dir/file.txt')); done(); }, done); }); it('resolves the real path regular file', function(done) { fs.realpath('dir/file.txt', function(err, resolved) { if (err) { return done(err); } assertEqualPaths(resolved, path.resolve('dir/file.txt')); done(); }); }); withPromise.it('promise resolves the real path regular file', function(done) { fs.promises.realpath('dir/file.txt').then(function(resolved) { assertEqualPaths(resolved, path.resolve('dir/file.txt')); done(); }, done); }); it('fails on file not exist', function(done) { fs.realpath('bogus', function(err, resolved) { assert.instanceOf(err, Error); assert.equal(err.code, 'ENOENT'); done(); }); }); withPromise.it('promise fails on file not exist', function(done) { fs.promises.realpath('bogus').then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'ENOENT'); done(); } ); }); }); if (fs.realpath.native) { describe('fs.realpath.native(path, [cache], callback)', function() { beforeEach(function() { mock({ 'dir/file.txt': 'content', link: mock.symlink({path: './dir/file.txt'}) }); }); afterEach(mock.restore); it('resolves the real path for a symbolic link', function(done) { fs.realpath.native('link', function(err, resolved) { if (err) { return done(err); } assertEqualPaths(resolved, path.resolve('dir/file.txt')); done(); }); }); it('resolves the real path regular file', function(done) { fs.realpath.native('dir/file.txt', function(err, resolved) { if (err) { return done(err); } assertEqualPaths(resolved, path.resolve('dir/file.txt')); done(); }); }); it('fails on file not exist', function(done) { fs.realpath.native('bogus', function(err, resolved) { assert.instanceOf(err, Error); assert.equal(err.code, 'ENOENT'); done(); }); }); }); } describe('fs.realpathSync(path, [cache])', function() { beforeEach(function() { mock({ 'dir/file.txt': 'content', link: mock.symlink({path: './dir/file.txt'}) }); }); afterEach(mock.restore); it('resolves the real path for a symbolic link', function() { const resolved = fs.realpathSync('link'); assertEqualPaths(resolved, path.resolve('dir/file.txt')); }); it('resolves the real path regular file', function() { const resolved = fs.realpathSync('dir/file.txt'); assertEqualPaths(resolved, path.resolve('dir/file.txt')); }); it('fails on file not exist', function() { assert.throws(function() { fs.realpathSync('bogus'); }); }); }); if (fs.realpathSync.native) { describe('fs.realpathSync.native(path, [cache])', function() { beforeEach(function() { mock({ 'dir/file.txt': 'content', link: mock.symlink({path: './dir/file.txt'}) }); }); afterEach(mock.restore); it('resolves the real path for a symbolic link', function() { const resolved = fs.realpathSync.native('link'); assertEqualPaths(resolved, path.resolve('dir/file.txt')); }); it('resolves the real path regular file', function() { const resolved = fs.realpathSync.native('dir/file.txt'); assertEqualPaths(resolved, path.resolve('dir/file.txt')); }); it('fails on file not exist', function() { assert.throws(function() { fs.realpathSync.native('bogus'); }); }); }); } mock-fs-4.10.4/test/lib/fs.rename.spec.js000066400000000000000000000144401356713366300200510ustar00rootroot00000000000000'use strict'; const helper = require('../helper'); const fs = require('fs'); const mock = require('../../lib/index'); const bufferFrom = require('../../lib/buffer').from; const assert = helper.assert; const withPromise = helper.withPromise; describe('fs.rename(oldPath, newPath, callback)', function() { beforeEach(function() { mock({ 'path/to/a.bin': bufferFrom([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(); }); }); withPromise.it('promise allows files to be renamed', function(done) { fs.promises.rename('path/to/a.bin', 'path/to/b.bin').then(function() { assert.isFalse(fs.existsSync('path/to/a.bin')); assert.isTrue(fs.existsSync('path/to/b.bin')); done(); }, done); }); it('updates mtime of parent directory', function(done) { const 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')); const newTime = fs.statSync('nested/dir').mtime; assert.isTrue(newTime > oldTime); done(); }); }); withPromise.it('promise updates mtime of parent directory', function(done) { const oldTime = fs.statSync('nested/dir').mtime; fs.promises .rename('nested/dir/file.txt', 'nested/dir/renamed.txt') .then(function() { assert.isFalse(fs.existsSync('nested/dir/file.txt')); assert.isTrue(fs.existsSync('nested/dir/renamed.txt')); const newTime = fs.statSync('nested/dir').mtime; assert.isTrue(newTime > oldTime); done(); }, 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(); }); }); withPromise.it( 'promise calls callback with error if old path does not exist', function(done) { fs.promises.rename('bogus', 'empty').then( function() { assert.fail('Should not succeed.'); done(); }, 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(); }); }); withPromise.it('promise overwrites existing files', function(done) { fs.promises.rename('path/to/a.bin', 'nested/dir/file.txt').then(function() { assert.isFalse(fs.existsSync('path/to/a.bin')); assert.isTrue(fs.existsSync('nested/dir/file.txt')); done(); }, 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(); }); }); withPromise.it('promise allows directories to be renamed', function(done) { fs.promises.rename('path/to', 'path/foo').then(function() { assert.isFalse(fs.existsSync('path/to')); assert.isTrue(fs.existsSync('path/foo')); assert.deepEqual(fs.readdirSync('path/foo'), ['a.bin']); done(); }, done); }); it('calls callback with error if new directory not empty', function(done) { fs.rename('path', 'nested', function(err) { assert.instanceOf(err, Error); done(); }); }); withPromise.it( 'promise calls callback with error if new directory not empty', function(done) { fs.promises.rename('path', 'nested').then( function() { assert.fail('Should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); done(); } ); } ); }); describe('fs.renameSync(oldPath, newPath)', function() { beforeEach(function() { mock({ 'path/to/a.bin': bufferFrom([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'); }); }); }); mock-fs-4.10.4/test/lib/fs.rmdir.spec.js000066400000000000000000000064141356713366300177210ustar00rootroot00000000000000'use strict'; const helper = require('../helper'); const fs = require('fs'); const mock = require('../../lib/index'); const assert = helper.assert; const withPromise = helper.withPromise; const testParentPerms = fs.access && fs.accessSync && process.getuid && process.getgid; describe('fs.rmdir(path, callback)', function() { beforeEach(function() { mock({ 'path/to/empty': {}, unwriteable: mock.directory({ mode: parseInt('0555', 8), items: {child: {}} }) }); }); afterEach(mock.restore); it('removes an empty directory', function(done) { assert.equal(fs.statSync('path/to').nlink, 3); fs.rmdir('path/to/empty', function(err) { if (err) { return done(err); } assert.isFalse(fs.existsSync('path/to/empty')); assert.equal(fs.statSync('path/to').nlink, 2); done(); }); }); withPromise.it('promise removes an empty directory', function(done) { assert.equal(fs.statSync('path/to').nlink, 3); fs.promises.rmdir('path/to/empty').then(function() { assert.isFalse(fs.existsSync('path/to/empty')); assert.equal(fs.statSync('path/to').nlink, 2); done(); }, done); }); it('fails if not empty', function(done) { fs.rmdir('path/to', function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'ENOTEMPTY'); done(); }); }); withPromise.it('promise fails if not empty', function(done) { fs.promises.rmdir('path/to').then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'ENOTEMPTY'); done(); } ); }); if (testParentPerms) { it('fails if parent is not writeable', function(done) { fs.rmdir('unwriteable/child', function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'EACCES'); done(); }); }); withPromise.it('promise fails if parent is not writeable', function(done) { fs.promises.rmdir('unwriteable/child').then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'EACCES'); done(); } ); }); } }); describe('fs.rmdirSync(path)', function() { beforeEach(function() { mock({ 'path/empty': {}, 'file.txt': 'content', unwriteable: mock.directory({ mode: parseInt('0555', 8), items: {child: {}} }) }); }); afterEach(mock.restore); it('removes an empty directory', function() { fs.rmdirSync('path/empty'); assert.isFalse(fs.existsSync('path/empty')); }); it('fails if directory does not exist', function() { assert.throws(function() { fs.rmdirSync('path/bogus'); }); }); it('fails if not empty', function() { assert.throws(function() { fs.rmdirSync('path'); }); }); it('fails if file', function() { assert.throws(function() { fs.rmdirSync('file.txt'); }); }); if (testParentPerms) { it('fails if parent is not writeable', function() { assert.throws(function() { fs.rmdirSync('unwriteable/child'); }); }); } }); mock-fs-4.10.4/test/lib/fs.stat-fstat.spec.js000066400000000000000000000213661356713366300207010ustar00rootroot00000000000000'use strict'; const helper = require('../helper'); const fs = require('fs'); const mock = require('../../lib/index'); const semver = require('semver'); const assert = helper.assert; const withPromise = helper.withPromise; 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); xit('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(); }); }); withPromise.xit('promise creates an instance of fs.Stats', function(done) { fs.promises.stat('/path/to/file.txt').then(function(stats) { assert.instanceOf(stats, fs.Stats); done(); }, 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(); }); }); withPromise.it('promise identifies files', function(done) { fs.promises.stat('/path/to/file.txt').then(function(stats) { assert.isTrue(stats.isFile()); assert.isFalse(stats.isDirectory()); done(); }, 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(); }); }); withPromise.it('promise identifies directories', function(done) { fs.promises.stat('/empty').then(function(stats) { assert.isTrue(stats.isDirectory()); assert.isFalse(stats.isFile()); done(); }, 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.rdev); done(); }); }); withPromise.it('promise provides file stats', function(done) { fs.promises.stat('/path/to/file.txt').then(function(stats) { 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.rdev); done(); }, done); }); if ( process.platform !== 'win32' || semver.coerce(process.version).major !== 10 ) { // The fix for https://github.com/nodejs/node/issues/25913 // is not shipped in v10. But it's shipped in v12. it('includes blocks and blksize in stats', function(done) { fs.stat('/path/to/file.txt', function(err, stats) { if (err) { return done(err); } assert.isNumber(stats.blocks); assert.isNumber(stats.blksize); done(); }); }); withPromise.it('promise includes blocks and blksize in stats', function( done ) { fs.promises.stat('/path/to/file.txt').then(function(stats) { assert.isNumber(stats.blocks); assert.isNumber(stats.blksize); done(); }, 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.isNaN(stats.uid); } if (process.getgid) { assert.isNumber(stats.gid); } else { assert.isNaN(stats.gid); } assert.equal(stats.nlink, 3); assert.isNumber(stats.rdev); done(); }); }); withPromise.it('promise provides directory stats', function(done) { fs.promises.stat('/path').then(function(stats) { assert.instanceOf(stats.ctime, Date); assert.instanceOf(stats.mtime, Date); assert.instanceOf(stats.atime, Date); if (process.getuid) { assert.isNumber(stats.uid); } else { assert.isNaN(stats.uid); } if (process.getgid) { assert.isNumber(stats.gid); } else { assert.isNaN(stats.gid); } assert.equal(stats.nlink, 3); assert.isNumber(stats.rdev); done(); }, done); }); if ( process.platform !== 'win32' || semver.coerce(process.version).major !== 10 ) { // The fix for https://github.com/nodejs/node/issues/25913 // is not shipped in v10. But it's shipped in v12. it('includes blocks and blksize in directory stats', function(done) { fs.stat('/path', function(err, stats) { if (err) { return done(err); } assert.isNumber(stats.blocks); assert.isNumber(stats.blksize); done(); }); }); withPromise.it( 'promise includes blocks and blksize in directory stats', function(done) { fs.promises.stat('/path').then(function(stats) { assert.isNumber(stats.blocks); assert.isNumber(stats.blksize); done(); }, 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) { const 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(); }); }); withPromise.it('promise accepts a file descriptor for a file (r)', function( done ) { fs.promises .open('path/to/file.txt', 'r') .then(function(fd) { return fd.stat(); }) .then(function(stats) { assert.isTrue(stats.isFile()); assert.equal(stats.size, 12); done(); }, done); }); it('accepts a file descriptor for a directory (r)', function(done) { const 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(); }); }); withPromise.it( 'promise accepts a file descriptor for a directory (r)', function(done) { fs.promises .open('path/to', 'r') .then(function(fd) { return fd.stat(); }) .then(function(stats) { assert.isTrue(stats.isDirectory()); assert.isTrue(stats.size > 0); done(); }, done); } ); it('fails for bad file descriptor', function(done) { const fd = fs.openSync('path/to/file.txt', 'r'); fs.closeSync(fd); fs.fstat(fd, function(err, stats) { assert.instanceOf(err, Error); assert.equal(err.code, 'EBADF'); done(); }); }); withPromise.it('promise fails for bad file descriptor', function(done) { fs.promises .open('path/to/file.txt', 'r') .then(function(fd) { return fd.close().then(function() { return fd.stat(); }); }) .then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'EBADF'); 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() { const fd = fs.openSync('path/to/file.txt', 'r'); const stats = fs.fstatSync(fd); assert.isTrue(stats.isFile()); assert.equal(stats.size, 12); }); it('accepts a file descriptor for a directory (r)', function() { const fd = fs.openSync('path/to', 'r'); const stats = fs.fstatSync(fd); assert.isTrue(stats.isDirectory()); assert.isTrue(stats.size > 0); }); it('fails for bad file descriptor', function() { const fd = fs.openSync('path/to/file.txt', 'r'); fs.closeSync(fd); assert.throws(function() { fs.fstatSync(fd); }); }); }); mock-fs-4.10.4/test/lib/fs.unlink.spec.js000066400000000000000000000074751356713366300201140ustar00rootroot00000000000000'use strict'; const helper = require('../helper'); const fs = require('fs'); const mock = require('../../lib/index'); const bufferAlloc = require('../../lib/buffer').alloc; const assert = helper.assert; const withPromise = helper.withPromise; describe('fs.unlink(path, callback)', function() { beforeEach(function() { mock({ dir: {}, dir2: mock.directory({ mtime: new Date(1), items: {file: 'content here'} }), 'file.txt': 'content' }); }); afterEach(mock.restore); it('deletes a file', function(done) { fs.unlink('file.txt', function(err) { if (err) { return done(err); } assert.isFalse(fs.existsSync('file.txt')); done(); }); }); withPromise.it('promise deletes a file', function(done) { fs.promises.unlink('file.txt').then(function() { assert.isFalse(fs.existsSync('file.txt')); done(); }, done); }); it('updates mtime of parent', function(done) { const oldTime = fs.statSync('dir2').mtime; fs.unlink('dir2/file', function(err) { if (err) { return done(err); } assert.isFalse(fs.existsSync('dir2/file')); const newTime = fs.statSync('dir2').mtime; assert.isTrue(newTime > oldTime); done(); }); }); withPromise.it('updates mtime of parent', function(done) { const oldTime = fs.statSync('dir2').mtime; fs.promises.unlink('dir2/file').then(function() { assert.isFalse(fs.existsSync('dir2/file')); const newTime = fs.statSync('dir2').mtime; assert.isTrue(newTime > oldTime); done(); }, done); }); it('fails for a directory', function(done) { fs.unlink('dir', function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'EPERM'); assert.isTrue(fs.existsSync('dir')); done(); }); }); withPromise.it('promise fails for a directory', function(done) { fs.promises.unlink('dir').then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'EPERM'); assert.isTrue(fs.existsSync('dir')); done(); } ); }); it('respects previously opened file descriptors', function(done) { const fd = fs.openSync('file.txt', 'r'); fs.unlink('file.txt', function(err) { if (err) { return done(err); } assert.isFalse(fs.existsSync('file.txt')); // but we can still use fd to read const buffer = bufferAlloc(7); const read = fs.readSync(fd, buffer, 0, 7); assert.equal(read, 7); assert.equal(String(buffer), 'content'); done(); }); }); withPromise.it( 'promise respects previously opened file descriptors', function(done) { const fd = fs.openSync('file.txt', 'r'); fs.promises.unlink('file.txt').then(function() { assert.isFalse(fs.existsSync('file.txt')); // but we can still use fd to read const buffer = bufferAlloc(7); const read = fs.readSync(fd, buffer, 0, 7); assert.equal(read, 7); assert.equal(String(buffer), 'content'); done(); }, done); } ); }); describe('fs.unlinkSync(path)', function() { beforeEach(function() { mock({ 'file.txt': 'content' }); }); afterEach(mock.restore); it('deletes a file', function() { fs.unlinkSync('file.txt'); assert.isFalse(fs.existsSync('file.txt')); }); it('respects previously opened file descriptors', function() { const fd = fs.openSync('file.txt', 'r'); fs.unlinkSync('file.txt'); assert.isFalse(fs.existsSync('file.txt')); // but we can still use fd to read const buffer = bufferAlloc(7); const read = fs.readSync(fd, buffer, 0, 7); assert.equal(read, 7); assert.equal(String(buffer), 'content'); }); }); mock-fs-4.10.4/test/lib/fs.utimes-futimes.spec.js000066400000000000000000000116601356713366300215630ustar00rootroot00000000000000'use strict'; const helper = require('../helper'); const fs = require('fs'); const mock = require('../../lib/index'); const assert = helper.assert; const withPromise = helper.withPromise; describe('fs.utimes(path, atime, mtime, callback)', function() { beforeEach(function() { mock({ dir: {}, 'file.txt': 'content' }); }); afterEach(mock.restore); it('updates timestamps for a file', function(done) { fs.utimes('file.txt', new Date(100), new Date(200), function(err) { if (err) { return done(err); } const stats = fs.statSync('file.txt'); assert.equal(stats.atime.getTime(), 100); assert.equal(stats.mtime.getTime(), 200); done(); }); }); withPromise.it('promise updates timestamps for a file', function(done) { fs.promises .utimes('file.txt', new Date(100), new Date(200)) .then(function() { const stats = fs.statSync('file.txt'); assert.equal(stats.atime.getTime(), 100); assert.equal(stats.mtime.getTime(), 200); done(); }, done); }); it('updates timestamps for a directory', function(done) { fs.utimes('dir', new Date(300), new Date(400), function(err) { if (err) { return done(err); } const stats = fs.statSync('dir'); assert.equal(stats.atime.getTime(), 300); assert.equal(stats.mtime.getTime(), 400); done(); }); }); withPromise.it('promise updates timestamps for a directory', function(done) { fs.promises.utimes('dir', new Date(300), new Date(400)).then(function() { const stats = fs.statSync('dir'); assert.equal(stats.atime.getTime(), 300); assert.equal(stats.mtime.getTime(), 400); done(); }, done); }); it('fails for a bogus path', function(done) { fs.utimes('bogus.txt', new Date(100), new Date(200), function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'ENOENT'); done(); }); }); withPromise.it('promise fails for a bogus path', function(done) { fs.promises.utimes('bogus.txt', new Date(100), new Date(200)).then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'ENOENT'); done(); } ); }); }); describe('fs.utimesSync(path, atime, mtime)', function() { beforeEach(function() { mock({ 'file.txt': 'content' }); }); afterEach(mock.restore); it('updates timestamps for a file', function() { fs.utimesSync('file.txt', new Date(100), new Date(200)); const stats = fs.statSync('file.txt'); assert.equal(stats.atime.getTime(), 100); assert.equal(stats.mtime.getTime(), 200); }); }); describe('fs.futimes(fd, atime, mtime, callback)', function() { beforeEach(function() { mock({ dir: {}, 'file.txt': 'content' }); }); afterEach(mock.restore); it('updates timestamps for a file', function(done) { const fd = fs.openSync('file.txt', 'r'); fs.futimes(fd, new Date(100), new Date(200), function(err) { if (err) { return done(err); } const stats = fs.statSync('file.txt'); assert.equal(stats.atime.getTime(), 100); assert.equal(stats.mtime.getTime(), 200); done(); }); }); withPromise.it('promise updates timestamps for a file', function(done) { fs.promises .open('file.txt', 'r') .then(function(fd) { return fd.utimes(new Date(100), new Date(200)); }) .then(function() { const stats = fs.statSync('file.txt'); assert.equal(stats.atime.getTime(), 100); assert.equal(stats.mtime.getTime(), 200); done(); }, done); }); it('updates timestamps for a directory', function(done) { const fd = fs.openSync('dir', 'r'); fs.futimes(fd, new Date(300), new Date(400), function(err) { if (err) { return done(err); } const stats = fs.statSync('dir'); assert.equal(stats.atime.getTime(), 300); assert.equal(stats.mtime.getTime(), 400); done(); }); }); withPromise.it('promise updates timestamps for a directory', function(done) { fs.promises .open('dir', 'r') .then(function(fd) { return fd.utimes(new Date(300), new Date(400)); }) .then(function() { const stats = fs.statSync('dir'); assert.equal(stats.atime.getTime(), 300); assert.equal(stats.mtime.getTime(), 400); done(); }, done); }); }); describe('fs.futimesSync(path, atime, mtime)', function() { beforeEach(function() { mock({ 'file.txt': 'content' }); }); afterEach(mock.restore); it('updates timestamps for a file', function() { const fd = fs.openSync('file.txt', 'r'); fs.futimesSync(fd, new Date(100), new Date(200)); const stats = fs.statSync('file.txt'); assert.equal(stats.atime.getTime(), 100); assert.equal(stats.mtime.getTime(), 200); }); }); mock-fs-4.10.4/test/lib/fs.write.spec.js000066400000000000000000000377161356713366300177470ustar00rootroot00000000000000'use strict'; const helper = require('../helper'); const fs = require('fs'); const mock = require('../../lib/index'); const bufferFrom = require('../../lib/buffer').from; const assert = helper.assert; const withPromise = helper.withPromise; 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) { const fd = fs.openSync('path/new-file.txt', 'w'); const buffer = bufferFrom('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(); }); }); withPromise.it('promise writes a buffer to a file', function(done) { const buffer = bufferFrom('new file'); fs.promises .open('path/new-file.txt', 'w') .then(function(fd) { return fd.write(buffer, 0, buffer.length); }) .then(function(result) { assert.equal(result.bytesWritten, 8); assert.equal(result.buffer, buffer); assert.equal(String(fs.readFileSync('path/new-file.txt')), 'new file'); done(); }, done); }); it('writes a buffer to a file with implicit offset, length, position', function(done) { const fd = fs.openSync('path/new-file.txt', 'w'); const buffer = bufferFrom('new file'); fs.write(fd, buffer, 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(); }); }); withPromise.it( 'promise writes a buffer to a file with implicit offset, length, position', function(done) { const buffer = bufferFrom('new file'); fs.promises .open('path/new-file.txt', 'w') .then(function(fd) { return fd.write(buffer); }) .then(function(result) { assert.equal(result.bytesWritten, 8); assert.equal(result.buffer, buffer); assert.equal( String(fs.readFileSync('path/new-file.txt')), 'new file' ); done(); }, 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); } const buffer = bufferFrom('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(); }); }); }); withPromise.it('promise can write a portion of a buffer to a file', function( done ) { const buffer = bufferFrom('new file'); fs.promises .open('path/new-file.txt', 'w') .then(function(fd) { return fd.write(buffer, 1, 5); }) .then(function(result) { assert.equal(result.bytesWritten, 5); assert.equal(result.buffer, buffer); assert.equal(String(fs.readFileSync('path/new-file.txt')), 'ew fi'); done(); }, done); }); it('can write a portion of a buffer to a file position', function(done) { fs.open('path/to/file.txt', 'a', function(err, fd) { if (err) { return done(err); } const buffer = bufferFrom('new file'); fs.write(fd, buffer, 1, 5, 2, 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')), 'fiew fintent' ); done(); }); }); }); withPromise.it( 'promise can write a portion of a buffer to a file position', function(done) { const buffer = bufferFrom('new file'); fs.promises .open('path/to/file.txt', 'a') .then(function(fd) { return fd.write(buffer, 1, 5, 2); }) .then(function(result) { assert.equal(result.bytesWritten, 5); assert.equal(result.buffer, buffer); assert.equal( String(fs.readFileSync('path/to/file.txt')), 'fiew fintent' ); done(); }, done); } ); it('can write a portion of a buffer to a file position and enlarge the file', function(done) { fs.open('path/to/file.txt', 'a', function(err, fd) { if (err) { return done(err); } const buffer = bufferFrom('new file'); fs.write(fd, buffer, 1, 5, 8, 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 conew fi' ); done(); }); }); }); withPromise.it( 'promise can write a portion of a buffer to a file position and enlarge the file', function(done) { const buffer = bufferFrom('new file'); fs.promises .open('path/to/file.txt', 'a') .then(function(fd) { return fd.write(buffer, 1, 5, 8); }) .then(function(result) { assert.equal(result.bytesWritten, 5); assert.equal(result.buffer, buffer); assert.equal( String(fs.readFileSync('path/to/file.txt')), 'file conew fi' ); done(); }, done); } ); it('can append to a file', function(done) { fs.open('path/to/file.txt', 'a', function(err, fd) { if (err) { return done(err); } const buffer = bufferFrom(' 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(); }); }); }); withPromise.it('promise can append to a file', function(done) { const buffer = bufferFrom(' more'); fs.promises .open('path/to/file.txt', 'a') .then(function(fd) { return fd.write(buffer, 0, 5); }) .then(function(result) { assert.equal(result.bytesWritten, 5); assert.equal(result.buffer, buffer); assert.equal( String(fs.readFileSync('path/to/file.txt')), 'file content more' ); done(); }, 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, bufferFrom('oops'), 0, 4, null, function(err2) { assert.instanceOf(err2, Error); assert.equal(err2.code, 'EBADF'); done(); }); }); }); withPromise.it('fails if file not open for writing', function(done) { fs.promises .open('path/to/file.txt', 'r') .then(function(fd) { return fd.write(bufferFrom('oops'), 0, 4); }) .then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'EBADF'); 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() { const buffer = bufferFrom('new file'); const fd = fs.openSync('path/new-file.txt', 'w'); const 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() { const buffer = bufferFrom('new file'); const fd = fs.openSync('path/new-file.txt', 'w'); const 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() { const buffer = bufferFrom(' more'); const fd = fs.openSync('path/to/file.txt', 'a'); const 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() { const fd = fs.openSync('path/to/file.txt', 'r'); assert.throws(function() { fs.writeSync(fd, bufferFrom('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); } const string = 'new file'; fs.write(fd, string, null, 'utf-8', function(err2, written, str) { if (err2) { return done(err2); } assert.equal(written, 8); assert.equal(str, string); assert.equal(fs.readFileSync('path/new-file.txt'), 'new file'); done(); }); }); }); withPromise.it('promise writes a string to a file', function(done) { const string = 'new file'; fs.promises .open('path/new-file.txt', 'w') .then(function(fd) { return fd.write(string, null, 'utf-8'); }) .then(function(result) { assert.equal(result.bytesWritten, 8); assert.equal(String(result.buffer), string); assert.equal(String(fs.readFileSync('path/new-file.txt')), 'new file'); done(); }, done); }); it('writes a string to a file with implicit position and encoding', function(done) { fs.open('path/new-file.txt', 'w', function(err, fd) { if (err) { return done(err); } const string = 'new file'; fs.write(fd, string, function(err2, written, str) { if (err2) { return done(err2); } assert.equal(written, 8); assert.equal(str, string); assert.equal(fs.readFileSync('path/new-file.txt'), 'new file'); done(); }); }); }); withPromise.it( 'promise writes a string to a file with implicit position and encoding', function(done) { const string = 'new file'; fs.promises .open('path/new-file.txt', 'w') .then(function(fd) { return fd.write(string); }) .then(function(result) { assert.equal(result.bytesWritten, 8); assert.equal(String(result.buffer), string); assert.equal( String(fs.readFileSync('path/new-file.txt')), 'new file' ); done(); }, done); } ); it('can append to a file', function(done) { fs.open('path/to/file.txt', 'a', function(err, fd) { if (err) { return done(err); } const string = ' more'; fs.write(fd, string, null, 'utf-8', function(err2, written, str) { if (err2) { return done(err2); } assert.equal(written, 5); assert.equal(str, string); assert.equal(fs.readFileSync('path/to/file.txt'), 'file content more'); done(); }); }); }); withPromise.it('promise can append to a file', function(done) { const string = ' more'; fs.promises .open('path/to/file.txt', 'a') .then(function(fd) { return fd.write(string); }) .then(function(result) { assert.equal(result.bytesWritten, 5); assert.equal(String(result.buffer), string); assert.equal( String(fs.readFileSync('path/to/file.txt')), 'file content more' ); done(); }, done); }); it('can write to a position of a file', function(done) { fs.open('path/to/file.txt', 'a', function(err, fd) { if (err) { return done(err); } const string = ' more'; fs.write(fd, string, 3, function(err2, written, str) { if (err2) { return done(err2); } assert.equal(written, 5); assert.equal(str, string); assert.equal(fs.readFileSync('path/to/file.txt'), 'fil moretent'); done(); }); }); }); withPromise.it('promise can write to a position of a file', function(done) { const string = ' more'; fs.promises .open('path/to/file.txt', 'a') .then(function(fd) { return fd.write(string, 3); }) .then(function(result) { assert.equal(result.bytesWritten, 5); assert.equal(String(result.buffer), string); assert.equal( String(fs.readFileSync('path/to/file.txt')), 'fil moretent' ); done(); }, done); }); it('can write to a position of a file and enlarge it', function(done) { fs.open('path/to/file.txt', 'a', function(err, fd) { if (err) { return done(err); } const string = ' more'; fs.write(fd, string, 9, function(err2, written, str) { if (err2) { return done(err2); } assert.equal(written, 5); assert.equal(str, string); assert.equal(fs.readFileSync('path/to/file.txt'), 'file cont more'); done(); }); }); }); withPromise.it( 'promise can write to a position of a file and enlarge it', function(done) { const string = ' more'; fs.promises .open('path/to/file.txt', 'a') .then(function(fd) { return fd.write(string, 9); }) .then(function(result) { assert.equal(result.bytesWritten, 5); assert.equal(String(result.buffer), string); assert.equal( String(fs.readFileSync('path/to/file.txt')), 'file cont more' ); done(); }, 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, 'oops', null, 'utf-8', function(err2) { assert.instanceOf(err2, Error); done(); }); }); }); withPromise.it('promise fails if file not open for writing', function(done) { fs.promises .open('path/to/file.txt', 'r') .then(function(fd) { return fd.write('oops'); }) .then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'EBADF'); done(); } ); }); }); describe('fs.writeSync(fd, data[, position[, encoding]])', function() { beforeEach(function() { mock({ 'path/to/file.txt': 'file content' }); }); afterEach(mock.restore); it('writes a string to a file', function() { const fd = fs.openSync('path/new-file.txt', 'w'); const string = 'new file'; const written = fs.writeSync(fd, string, null, 'utf-8'); assert.equal(written, 8); assert.equal(fs.readFileSync('path/new-file.txt'), 'new file'); }); it('can append to a file', function() { const fd = fs.openSync('path/to/file.txt', 'a'); const string = ' more'; const written = fs.writeSync(fd, string, null, 'utf-8'); assert.equal(written, 5); assert.equal(fs.readFileSync('path/to/file.txt'), 'file content more'); }); it('fails if file not open for writing', function() { const fd = fs.openSync('path/to/file.txt', 'r'); assert.throws(function() { fs.writeSync(fd, 'oops', null, 'utf-8'); }); }); }); mock-fs-4.10.4/test/lib/fs.writeFile.spec.js000066400000000000000000000062771356713366300205450ustar00rootroot00000000000000'use strict'; const helper = require('../helper'); const fs = require('fs'); const mock = require('../../lib/index'); const bufferFrom = require('../../lib/buffer').from; const assert = helper.assert; const withPromise = helper.withPromise; describe('fs.writeFile(filename, data, [options], callback)', function() { beforeEach(function() { mock({ dir: mock.directory({ mtime: new Date(1) }) }); }); afterEach(mock.restore); it('writes a string to a file', function(done) { fs.writeFile('dir/foo', 'bar', function(err) { if (err) { return done(err); } assert.equal(String(fs.readFileSync('dir/foo')), 'bar'); done(); }); }); withPromise.it('promise writes a string to a file', function(done) { fs.promises.writeFile('dir/foo', 'bar').then(function() { assert.equal(String(fs.readFileSync('dir/foo')), 'bar'); done(); }, done); }); it('updates mtime of parent directory', function(done) { const oldTime = fs.statSync('dir').mtime; fs.writeFile('dir/foo', 'bar', function(err) { if (err) { return done(err); } const newTime = fs.statSync('dir').mtime; assert.isTrue(newTime > oldTime); done(); }); }); withPromise.it('promise updates mtime of parent directory', function(done) { const oldTime = fs.statSync('dir').mtime; fs.promises.writeFile('dir/foo', 'bar').then(function() { const newTime = fs.statSync('dir').mtime; assert.isTrue(newTime > oldTime); done(); }, done); }); it('writes a buffer to a file', function(done) { fs.writeFile('dir/foo', bufferFrom('bar'), function(err) { if (err) { return done(err); } assert.equal(String(fs.readFileSync('dir/foo')), 'bar'); done(); }); }); withPromise.it('promise writes a buffer to a file', function(done) { fs.promises.writeFile('dir/foo', bufferFrom('bar')).then(function() { assert.equal(String(fs.readFileSync('dir/foo')), 'bar'); done(); }, done); }); it('fails if directory does not exist', function(done) { fs.writeFile('foo/bar', 'baz', function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'ENOENT'); done(); }); }); withPromise.it('promise fails if directory does not exist', function(done) { fs.promises.writeFile('foo/bar', 'baz').then( function() { assert.fail('should not succeed.'); done(); }, function(err) { assert.instanceOf(err, Error); assert.equal(err.code, 'ENOENT'); done(); } ); }); }); describe('fs.writeFileSync(filename, data, [options]', function() { beforeEach(function() { mock({ '.': {} }); }); afterEach(mock.restore); it('writes a string to a file', function() { fs.writeFileSync('foo', 'bar'); assert.equal(String(fs.readFileSync('foo')), 'bar'); }); it('writes a buffer to a file', function() { fs.writeFileSync('foo', bufferFrom('bar')); assert.equal(String(fs.readFileSync('foo')), 'bar'); }); it('fails if directory does not exist', function() { assert.throws(function() { fs.writeFileSync('foo/bar', 'baz'); }); }); }); mock-fs-4.10.4/test/lib/index.spec.js000066400000000000000000000224761356713366300173120ustar00rootroot00000000000000'use strict'; const helper = require('../helper'); const fs = require('fs'); const mock = require('../../lib/index'); const os = require('os'); const path = require('path'); const assert = helper.assert; 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('provides direct access to the internal filesystem object', function() { mock(); const root = mock.getMockRoot(); assert.notDeepEqual(root, {}); mock.restore(); assert.deepEqual(mock.getMockRoot(), {}); }); it('creates process.cwd() and os.tmpdir() by default', function() { mock(); assert.isTrue(fs.statSync(process.cwd()).isDirectory()); let 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}); let tmp; if (os.tmpdir) { tmp = os.tmpdir(); } else if (os.tmpDir) { tmp = os.tmpDir(); } if (tmp) { assert.isFalse(fs.existsSync(tmp)); } mock.restore(); }); xit('uses the real fs module in require() calls', function() { mock({foo: 'bar'}); const pkg = require('../../package.json'); assert.equal(pkg.name, 'mock-fs'); mock.restore(); }); }); 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'}) }); const stats = fs.statSync('path/to/link'); assert.isTrue(stats.isFile()); assert.equal(String(fs.readFileSync('path/to/link')), 'content'); }); }); xdescribe('mock.fs()', function() { it('generates a mock fs module with a mock file system', function(done) { const 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() { const 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() { const 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('process.cwd()', function() { afterEach(mock.restore); it('maintains current working directory', function() { const originalCwd = process.cwd(); mock(); const cwd = process.cwd(); assert.equal(cwd, originalCwd); }); it('allows changing directory', function() { const originalCwd = process.cwd(); mock({ dir: {} }); process.chdir('dir'); const cwd = process.cwd(); assert.equal(cwd, path.join(originalCwd, 'dir')); }); it('prevents changing directory to non-existent path', function() { mock(); let err; try { process.chdir('dir'); } catch (e) { err = e; } assert.instanceOf(err, Error); assert.equal(err.code, 'ENOENT'); }); it('prevents changing directory to non-directory path', function() { mock({ file: '' }); let err; try { process.chdir('file'); } catch (e) { err = e; } assert.instanceOf(err, Error); assert.equal(err.code, 'ENOTDIR'); }); it('restores original methods on restore', function() { const originalCwd = process.cwd; const originalChdir = process.chdir; mock(); mock.restore(); assert.equal(process.cwd, originalCwd); assert.equal(process.chdir, originalChdir); }); it('restores original working directory on restore', function() { const originalCwd = process.cwd(); mock({ dir: {} }); process.chdir('dir'); mock.restore(); const cwd = process.cwd(); assert.equal(cwd, originalCwd); }); }); if (process.getuid && process.getgid) { describe('security', function() { afterEach(mock.restore); it('denies dir listing without execute on parent', function() { mock({ secure: mock.directory({ mode: parseInt('0666', 8), items: { insecure: { file: 'file content' } } }) }); let err; try { fs.readdirSync('secure/insecure'); } catch (e) { err = e; } assert.instanceOf(err, Error); assert.equal(err.code, 'EACCES'); }); it('denies file read without execute on parent', function() { mock({ secure: mock.directory({ mode: parseInt('0666', 8), items: { insecure: { file: 'file content' } } }) }); let err; try { fs.readFileSync('secure/insecure/file'); } catch (e) { err = e; } assert.instanceOf(err, Error); assert.equal(err.code, 'EACCES'); }); it('denies file read without read on file', function() { mock({ insecure: { 'write-only': mock.file({ mode: parseInt('0222', 8), content: 'write only' }) } }); let err; try { fs.readFileSync('insecure/write-only'); } catch (e) { err = e; } assert.instanceOf(err, Error); assert.equal(err.code, 'EACCES'); }); it('denies file write without write on file', function() { mock({ insecure: { 'read-only': mock.file({ mode: parseInt('0444', 8), content: 'read only' }) } }); let err; try { fs.writeFileSync('insecure/read-only', 'denied'); } catch (e) { err = e; } assert.instanceOf(err, Error); assert.equal(err.code, 'EACCES'); }); }); } mock-fs-4.10.4/test/lib/item.spec.js000066400000000000000000000247571356713366300171450ustar00rootroot00000000000000'use strict'; const Item = require('../../lib/item'); const assert = require('../helper').assert; describe('Item', function() { describe('constructor', function() { it('creates a new instance', function() { const item = new Item(); assert.instanceOf(item, Item); }); }); describe('#getATime()', function() { it('returns a date', function() { const item = new Item(); const date = item.getATime(); assert.instanceOf(date, Date); assert.isTrue(date <= new Date()); }); }); describe('#setATime()', function() { it('sets the atime', function() { const item = new Item(); const date = new Date(); item.setATime(date); assert.equal(item.getATime(), date); }); }); describe('#getCTime()', function() { it('returns a date', function() { const item = new Item(); const date = item.getCTime(); assert.instanceOf(date, Date); assert.isTrue(date <= new Date()); }); }); describe('#setCTime()', function() { it('sets the ctime', function() { const item = new Item(); const date = new Date(); item.setCTime(date); assert.equal(item.getCTime(), date); }); }); describe('#getBirthtime()', function() { it('returns a date', function() { const item = new Item(); const date = item.getBirthtime(); assert.instanceOf(date, Date); assert.isTrue(date <= new Date()); }); }); describe('#setBirthtime()', function() { it('sets the birthtime', function() { const item = new Item(); const date = new Date(); item.setBirthtime(date); assert.equal(item.getBirthtime(), date); }); }); describe('#getMTime()', function() { it('returns a date', function() { const item = new Item(); const date = item.getMTime(); assert.instanceOf(date, Date); assert.isTrue(date <= new Date()); }); }); describe('#setMTime()', function() { it('sets the mtime', function() { const item = new Item(); const date = new Date(); item.setMTime(date); assert.equal(item.getMTime(), date); }); }); describe('#getMode()', function() { it('returns a number', function() { const item = new Item(); assert.isNumber(item.getMode()); }); }); describe('#setMode()', function() { it('sets the mode', function() { const item = new Item(); item.setMode(parseInt('0644', 8)); assert.equal(item.getMode(), parseInt('0644', 8)); }); it('updates the ctime', function() { const item = new Item(); const original = new Date(1); item.setCTime(original); item.setMode(parseInt('0644', 8)); assert.isTrue(item.getCTime() > original); }); }); describe('#setUid()', function() { it('sets the uid', function() { const item = new Item(); item.setUid(42); assert.equal(item.getUid(), 42); }); it('updates the ctime', function() { const item = new Item(); const original = new Date(1); item.setCTime(original); item.setUid(42); assert.isTrue(item.getCTime() > original); }); }); describe('#setGid()', function() { it('sets the gid', function() { const item = new Item(); item.setGid(42); assert.equal(item.getGid(), 42); }); it('updates the ctime', function() { const item = new Item(); const original = new Date(1); item.setCTime(original); item.setGid(42); assert.isTrue(item.getCTime() > original); }); }); if (process.getgid && process.getuid) { const uid = process.getuid(); const gid = process.getgid(); let item; beforeEach(function() { item = new Item(); }); describe('#canRead()', function() { it('returns true if owner and 0700', function() { item.setMode(parseInt('0700', 8)); assert.isTrue(item.canRead()); }); it('returns true if owner and 0600', function() { item.setMode(parseInt('0600', 8)); assert.isTrue(item.canRead()); }); it('returns true if owner and 0500', function() { item.setMode(parseInt('0500', 8)); assert.isTrue(item.canRead()); }); it('returns true if owner and 0400', function() { item.setMode(parseInt('0400', 8)); assert.isTrue(item.canRead()); }); it('returns false if owner and 0300', function() { item.setMode(parseInt('0300', 8)); assert.isFalse(item.canRead()); }); it('returns false if owner and 0200', function() { item.setMode(parseInt('0200', 8)); assert.isFalse(item.canRead()); }); it('returns false if owner and 0100', function() { item.setMode(parseInt('0100', 8)); assert.isFalse(item.canRead()); }); it('returns false if not owner and 0700 (different user)', function() { item.setUid(uid + 1); item.setMode(parseInt('0700', 8)); assert.isFalse(item.canRead()); }); it('returns false if not owner and 0700 (different group)', function() { item.setUid(uid + 1); item.setGid(gid + 1); item.setMode(parseInt('0700', 8)); assert.isFalse(item.canRead()); }); it('returns false if owner and 0170', function() { item.setMode(parseInt('0170', 8)); assert.isFalse(item.canRead()); }); it('returns true if in group and 0170', function() { item.setUid(uid + 1); item.setMode(parseInt('0170', 8)); assert.isTrue(item.canRead()); }); it('returns false if not in group and 0770', function() { item.setUid(uid + 1); item.setGid(gid + 1); item.setMode(parseInt('0770', 8)); assert.isFalse(item.canRead()); }); it('returns true if not in group and 0777', function() { item.setUid(uid + 1); item.setGid(gid + 1); item.setMode(parseInt('0777', 8)); assert.isTrue(item.canRead()); }); }); describe('#canWrite()', function() { it('returns true if owner and 0700', function() { item.setMode(parseInt('0700', 8)); assert.isTrue(item.canWrite()); }); it('returns true if owner and 0600', function() { item.setMode(parseInt('0600', 8)); assert.isTrue(item.canWrite()); }); it('returns false if owner and 0500', function() { item.setMode(parseInt('0500', 8)); assert.isFalse(item.canWrite()); }); it('returns false if owner and 0400', function() { item.setMode(parseInt('0400', 8)); assert.isFalse(item.canWrite()); }); it('returns true if owner and 0300', function() { item.setMode(parseInt('0300', 8)); assert.isTrue(item.canWrite()); }); it('returns true if owner and 0200', function() { item.setMode(parseInt('0200', 8)); assert.isTrue(item.canWrite()); }); it('returns false if owner and 0100', function() { item.setMode(parseInt('0100', 8)); assert.isFalse(item.canWrite()); }); it('returns false if not owner and 0700 (different user)', function() { item.setUid(uid + 1); item.setMode(parseInt('0700', 8)); assert.isFalse(item.canWrite()); }); it('returns false if not owner and 0700 (different group)', function() { item.setUid(uid + 1); item.setGid(gid + 1); item.setMode(parseInt('0700', 8)); assert.isFalse(item.canWrite()); }); it('returns false if owner and 0170', function() { item.setMode(parseInt('0170', 8)); assert.isFalse(item.canWrite()); }); it('returns true if in group and 0170', function() { item.setUid(uid + 1); item.setMode(parseInt('0170', 8)); assert.isTrue(item.canWrite()); }); it('returns false if not in group and 0770', function() { item.setUid(uid + 1); item.setGid(gid + 1); item.setMode(parseInt('0770', 8)); assert.isFalse(item.canWrite()); }); it('returns true if not in group and 0777', function() { item.setUid(uid + 1); item.setGid(gid + 1); item.setMode(parseInt('0777', 8)); assert.isTrue(item.canWrite()); }); }); describe('#canExecute()', function() { it('returns true if owner and 0700', function() { item.setMode(parseInt('0700', 8)); assert.isTrue(item.canExecute()); }); it('returns false if owner and 0600', function() { item.setMode(parseInt('0600', 8)); assert.isFalse(item.canExecute()); }); it('returns true if owner and 0500', function() { item.setMode(parseInt('0500', 8)); assert.isTrue(item.canExecute()); }); it('returns false if owner and 0400', function() { item.setMode(parseInt('0400', 8)); assert.isFalse(item.canExecute()); }); it('returns true if owner and 0300', function() { item.setMode(parseInt('0300', 8)); assert.isTrue(item.canExecute()); }); it('returns false if owner and 0200', function() { item.setMode(parseInt('0200', 8)); assert.isFalse(item.canExecute()); }); it('returns true if owner and 0100', function() { item.setMode(parseInt('0100', 8)); assert.isTrue(item.canExecute()); }); it('returns false if not owner and 0700 (different user)', function() { item.setUid(uid + 1); item.setMode(parseInt('0700', 8)); assert.isFalse(item.canExecute()); }); it('returns false if not owner and 0700 (different group)', function() { item.setUid(uid + 1); item.setGid(gid + 1); item.setMode(parseInt('0700', 8)); assert.isFalse(item.canExecute()); }); it('returns false if owner and 0270', function() { item.setMode(parseInt('0270', 8)); assert.isFalse(item.canExecute()); }); it('returns true if in group and 0270', function() { item.setUid(uid + 1); item.setMode(parseInt('0270', 8)); assert.isTrue(item.canExecute()); }); it('returns false if not in group and 0770', function() { item.setUid(uid + 1); item.setGid(gid + 1); item.setMode(parseInt('0770', 8)); assert.isFalse(item.canExecute()); }); it('returns true if not in group and 0777', function() { item.setUid(uid + 1); item.setGid(gid + 1); item.setMode(parseInt('0777', 8)); assert.isTrue(item.canExecute()); }); }); } });