react-native-github: remove old fs mock implementation
Reviewed By: rafeca Differential Revision: D7652914 fbshipit-source-id: 5494305750e7616b5120169266c519f460ae7e6d
This commit is contained in:
parent
d5e9e55fa3
commit
c6b96c0df7
|
@ -9,428 +9,35 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const asyncify = require('async/asyncify');
|
||||
const {EventEmitter} = require('events');
|
||||
const {dirname} = require.requireActual('path');
|
||||
const fs = jest.genMockFromModule('fs');
|
||||
const invariant = require('fbjs/lib/invariant');
|
||||
const path = require('path');
|
||||
const stream = require.requireActual('stream');
|
||||
const fs = new (require('metro-memory-fs'))();
|
||||
|
||||
const noop = () => {};
|
||||
|
||||
function asyncCallback(cb) {
|
||||
return function() {
|
||||
setImmediate(() => cb.apply(this, arguments));
|
||||
};
|
||||
function setMockFilesystem(object) {
|
||||
fs.reset();
|
||||
const root = process.platform === 'win32' ? 'c:\\' : '/';
|
||||
mockDir(root, {...object});
|
||||
}
|
||||
|
||||
const mtime = {
|
||||
getTime: () => Math.ceil(Math.random() * 10000000),
|
||||
};
|
||||
|
||||
fs.realpath.mockImplementation((filepath, callback) => {
|
||||
callback = asyncCallback(callback);
|
||||
let node;
|
||||
try {
|
||||
node = getToNode(filepath);
|
||||
} catch (e) {
|
||||
return callback(e);
|
||||
}
|
||||
if (node && typeof node === 'object' && node.SYMLINK != null) {
|
||||
return callback(null, node.SYMLINK);
|
||||
}
|
||||
return callback(null, filepath);
|
||||
});
|
||||
|
||||
fs.readdirSync.mockImplementation(filepath => Object.keys(getToNode(filepath)));
|
||||
|
||||
fs.readdir.mockImplementation((filepath, callback) => {
|
||||
callback = asyncCallback(callback);
|
||||
let node;
|
||||
try {
|
||||
node = getToNode(filepath);
|
||||
if (node && typeof node === 'object' && node.SYMLINK != null) {
|
||||
node = getToNode(node.SYMLINK);
|
||||
function mockDir(dirPath, desc) {
|
||||
for (const entName in desc) {
|
||||
const ent = desc[entName];
|
||||
const entPath = require('path').join(dirPath, entName);
|
||||
if (typeof ent === 'string' || ent instanceof Buffer) {
|
||||
fs.writeFileSync(entPath, ent);
|
||||
continue;
|
||||
}
|
||||
} catch (e) {
|
||||
return callback(e);
|
||||
}
|
||||
|
||||
if (!(node && typeof node === 'object' && node.SYMLINK == null)) {
|
||||
return callback(new Error(filepath + ' is not a directory.'));
|
||||
}
|
||||
|
||||
return callback(null, Object.keys(node));
|
||||
});
|
||||
|
||||
fs.readFile.mockImplementation(asyncify(fs.readFileSync));
|
||||
|
||||
fs.readFileSync.mockImplementation(function(filepath, encoding) {
|
||||
filepath = path.normalize(filepath);
|
||||
const node = getToNode(filepath);
|
||||
if (isDirNode(node)) {
|
||||
throw new Error('Error readFileSync a dir: ' + filepath);
|
||||
}
|
||||
if (Buffer.isBuffer(node) && typeof encoding !== 'undefined') {
|
||||
return node.toString();
|
||||
}
|
||||
return node;
|
||||
});
|
||||
|
||||
fs.writeFile.mockImplementation(asyncify(fs.writeFileSync));
|
||||
|
||||
fs.writeFileSync.mockImplementation((filePath, content, options) => {
|
||||
filePath = path.normalize(filePath);
|
||||
if (options == null || typeof options === 'string') {
|
||||
options = {encoding: options};
|
||||
}
|
||||
invariant(
|
||||
options.encoding == null || options.encoding === 'utf8',
|
||||
'`options` argument supports only `null` or `"utf8"`',
|
||||
);
|
||||
const dirPath = path.dirname(filePath);
|
||||
const node = getToNode(dirPath);
|
||||
if (!isDirNode(node)) {
|
||||
throw fsError('ENOTDIR', 'not a directory: ' + dirPath);
|
||||
}
|
||||
node[path.basename(filePath)] = content;
|
||||
});
|
||||
|
||||
const openFds = new Map();
|
||||
let nextFd = 3;
|
||||
|
||||
fs.openSync.mockImplementation((filePath, flags) => {
|
||||
const dirPath = path.dirname(filePath);
|
||||
const node = getToNode(dirPath);
|
||||
if (!isDirNode(node)) {
|
||||
throw fsError('ENOTDIR', 'not a directory: ' + dirPath);
|
||||
}
|
||||
node[path.basename(filePath)] = '';
|
||||
openFds.set(nextFd, {filePath, flags, node});
|
||||
return nextFd++;
|
||||
});
|
||||
|
||||
fs.writeSync.mockImplementation((fd, str) => {
|
||||
invariant(typeof str === 'string', 'only strings supported');
|
||||
const data = openFds.get(fd);
|
||||
if (data == null || data.flags !== 'w') {
|
||||
throw fsError('EBADF', 'bad file descriptor, write');
|
||||
}
|
||||
data.node[path.basename(data.filePath)] += str;
|
||||
});
|
||||
|
||||
fs.closeSync.mockImplementation(fd => {
|
||||
openFds.delete(fd);
|
||||
});
|
||||
|
||||
fs.mkdir.mockImplementation(asyncify(fs.mkdirSync));
|
||||
|
||||
fs.mkdirSync.mockImplementation((dirPath, mode) => {
|
||||
const parentPath = path.dirname(dirPath);
|
||||
const node = getToNode(parentPath);
|
||||
if (!isDirNode(node)) {
|
||||
throw fsError('ENOTDIR', 'not a directory: ' + parentPath);
|
||||
}
|
||||
if (node[path.basename(dirPath)] == null) {
|
||||
node[path.basename(dirPath)] = {};
|
||||
}
|
||||
});
|
||||
|
||||
function fsError(code, message) {
|
||||
const error = new Error(code + ': ' + message);
|
||||
error.code = code;
|
||||
return error;
|
||||
}
|
||||
|
||||
function isDirNode(node) {
|
||||
return (
|
||||
node &&
|
||||
typeof node === 'object' &&
|
||||
node.SYMLINK == null &&
|
||||
Buffer.isBuffer(node) === false
|
||||
);
|
||||
}
|
||||
|
||||
function readlinkSync(filepath) {
|
||||
const node = getToNode(filepath);
|
||||
if (node !== null && typeof node === 'object' && !!node.SYMLINK) {
|
||||
return node.SYMLINK;
|
||||
} else {
|
||||
throw new Error(`EINVAL: invalid argument, readlink '${filepath}'`);
|
||||
}
|
||||
}
|
||||
|
||||
fs.readlink.mockImplementation((filepath, callback) => {
|
||||
callback = asyncCallback(callback);
|
||||
let result;
|
||||
try {
|
||||
result = readlinkSync(filepath);
|
||||
} catch (e) {
|
||||
callback(e);
|
||||
return;
|
||||
}
|
||||
callback(null, result);
|
||||
});
|
||||
|
||||
fs.readlinkSync.mockImplementation(readlinkSync);
|
||||
|
||||
function existsSync(filepath) {
|
||||
try {
|
||||
const node = getToNode(filepath);
|
||||
return node !== null;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
fs.exists.mockImplementation((filepath, callback) => {
|
||||
callback = asyncCallback(callback);
|
||||
let result;
|
||||
try {
|
||||
result = existsSync(filepath);
|
||||
} catch (e) {
|
||||
callback(e);
|
||||
return;
|
||||
}
|
||||
callback(null, result);
|
||||
});
|
||||
|
||||
fs.existsSync.mockImplementation(existsSync);
|
||||
|
||||
function makeStatResult(node) {
|
||||
const isSymlink = node != null && node.SYMLINK != null;
|
||||
return {
|
||||
isBlockDevice: () => false,
|
||||
isCharacterDevice: () => false,
|
||||
isDirectory: () => node != null && typeof node === 'object' && !isSymlink,
|
||||
isFIFO: () => false,
|
||||
isFile: () => node != null && typeof node === 'string',
|
||||
isSocket: () => false,
|
||||
isSymbolicLink: () => isSymlink,
|
||||
mtime,
|
||||
};
|
||||
}
|
||||
|
||||
function statSync(filepath) {
|
||||
const node = getToNode(filepath);
|
||||
if (node != null && node.SYMLINK) {
|
||||
return statSync(node.SYMLINK);
|
||||
}
|
||||
return makeStatResult(node);
|
||||
}
|
||||
|
||||
fs.stat.mockImplementation((filepath, callback) => {
|
||||
callback = asyncCallback(callback);
|
||||
let result;
|
||||
try {
|
||||
result = statSync(filepath);
|
||||
} catch (e) {
|
||||
callback(e);
|
||||
return;
|
||||
}
|
||||
callback(null, result);
|
||||
});
|
||||
|
||||
fs.statSync.mockImplementation(statSync);
|
||||
|
||||
function lstatSync(filepath) {
|
||||
const node = getToNode(filepath);
|
||||
return makeStatResult(node);
|
||||
}
|
||||
|
||||
fs.lstat.mockImplementation((filepath, callback) => {
|
||||
callback = asyncCallback(callback);
|
||||
let result;
|
||||
try {
|
||||
result = lstatSync(filepath);
|
||||
} catch (e) {
|
||||
callback(e);
|
||||
return;
|
||||
}
|
||||
callback(null, result);
|
||||
});
|
||||
|
||||
fs.lstatSync.mockImplementation(lstatSync);
|
||||
|
||||
fs.open.mockImplementation(function(filepath) {
|
||||
const callback = arguments[arguments.length - 1] || noop;
|
||||
let data, error, fd;
|
||||
try {
|
||||
data = getToNode(filepath);
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
|
||||
if (error || data == null) {
|
||||
error = Error(`ENOENT: no such file or directory: \`${filepath}\``);
|
||||
}
|
||||
if (data != null) {
|
||||
/* global Buffer: true */
|
||||
fd = {buffer: new Buffer(data, 'utf8'), position: 0};
|
||||
}
|
||||
|
||||
callback(error, fd);
|
||||
});
|
||||
|
||||
fs.read.mockImplementation(
|
||||
(fd, buffer, writeOffset, length, position, callback = noop) => {
|
||||
let bytesWritten;
|
||||
try {
|
||||
if (position == null || position < 0) {
|
||||
({position} = fd);
|
||||
}
|
||||
bytesWritten = fd.buffer.copy(
|
||||
buffer,
|
||||
writeOffset,
|
||||
position,
|
||||
position + length,
|
||||
);
|
||||
fd.position = position + bytesWritten;
|
||||
} catch (e) {
|
||||
callback(Error('invalid argument'));
|
||||
return;
|
||||
if (typeof ent !== 'object') {
|
||||
throw new Error(require('util').format('invalid entity:', ent));
|
||||
}
|
||||
callback(null, bytesWritten, buffer);
|
||||
},
|
||||
);
|
||||
|
||||
fs.close.mockImplementation((fd, callback = noop) => {
|
||||
try {
|
||||
fd.buffer = fs.position = undefined;
|
||||
} catch (e) {
|
||||
callback(Error('invalid argument'));
|
||||
return;
|
||||
}
|
||||
callback(null);
|
||||
});
|
||||
|
||||
let filesystem = {};
|
||||
|
||||
fs.mock = {
|
||||
clear() {
|
||||
filesystem = {};
|
||||
},
|
||||
};
|
||||
|
||||
fs.createReadStream.mockImplementation(filepath => {
|
||||
if (!filepath.startsWith('/')) {
|
||||
throw Error('Cannot open file ' + filepath);
|
||||
}
|
||||
|
||||
const parts = filepath.split('/').slice(1);
|
||||
let file = filesystem;
|
||||
|
||||
for (const part of parts) {
|
||||
file = file[part];
|
||||
if (!file) {
|
||||
break;
|
||||
if (ent.SYMLINK != null) {
|
||||
fs.symlinkSync(ent.SYMLINK, entPath);
|
||||
continue;
|
||||
}
|
||||
fs.mkdirSync(entPath);
|
||||
mockDir(entPath, ent);
|
||||
}
|
||||
|
||||
if (typeof file !== 'string') {
|
||||
throw Error('Cannot open file ' + filepath);
|
||||
}
|
||||
|
||||
return new stream.Readable({
|
||||
read() {
|
||||
this.push(file, 'utf8');
|
||||
this.push(null);
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
fs.createWriteStream.mockImplementation(filePath => {
|
||||
let node;
|
||||
const writeStream = new stream.Writable({
|
||||
write(chunk, encoding, callback) {
|
||||
this.__chunks.push(chunk);
|
||||
node[path.basename(filePath)] = this.__chunks.join('');
|
||||
callback();
|
||||
},
|
||||
});
|
||||
writeStream.__file = filePath;
|
||||
writeStream.__chunks = [];
|
||||
writeStream.end = jest.fn(writeStream.end);
|
||||
fs.createWriteStream.mock.returned.push(writeStream);
|
||||
try {
|
||||
const dirPath = dirname(filePath);
|
||||
node = getToNode(dirPath);
|
||||
if (!isDirNode(node)) {
|
||||
throw fsError('ENOTDIR', 'not a directory: ' + dirPath);
|
||||
}
|
||||
// Truncate the file on opening.
|
||||
node[path.basename(filePath)] = '';
|
||||
} catch (error) {
|
||||
process.nextTick(() => writeStream.emit('error', error));
|
||||
}
|
||||
return writeStream;
|
||||
});
|
||||
fs.createWriteStream.mock.returned = [];
|
||||
|
||||
fs.__setMockFilesystem = object => (filesystem = object);
|
||||
|
||||
const watcherListByPath = new Map();
|
||||
|
||||
fs.watch.mockImplementation((filename, options, listener) => {
|
||||
if (options.recursive) {
|
||||
throw new Error('recursive watch not implemented');
|
||||
}
|
||||
let watcherList = watcherListByPath.get(filename);
|
||||
if (watcherList == null) {
|
||||
watcherList = [];
|
||||
watcherListByPath.set(filename, watcherList);
|
||||
}
|
||||
const fsWatcher = new EventEmitter();
|
||||
fsWatcher.on('change', listener);
|
||||
fsWatcher.close = () => {
|
||||
watcherList.splice(watcherList.indexOf(fsWatcher), 1);
|
||||
fsWatcher.close = () => {
|
||||
throw new Error('FSWatcher is already closed');
|
||||
};
|
||||
};
|
||||
watcherList.push(fsWatcher);
|
||||
});
|
||||
|
||||
fs.__triggerWatchEvent = (eventType, filename) => {
|
||||
const directWatchers = watcherListByPath.get(filename) || [];
|
||||
directWatchers.forEach(wtc => wtc.emit('change', eventType));
|
||||
const dirPath = path.dirname(filename);
|
||||
const dirWatchers = watcherListByPath.get(dirPath) || [];
|
||||
dirWatchers.forEach(wtc =>
|
||||
wtc.emit('change', eventType, path.relative(dirPath, filename)),
|
||||
);
|
||||
};
|
||||
|
||||
function getToNode(filepath) {
|
||||
// Ignore the drive for Windows paths.
|
||||
if (filepath.match(/^[a-zA-Z]:\\/)) {
|
||||
filepath = filepath.substring(2);
|
||||
}
|
||||
|
||||
if (filepath.endsWith(path.sep)) {
|
||||
filepath = filepath.slice(0, -1);
|
||||
}
|
||||
const parts = filepath.split(/[\/\\]/);
|
||||
if (parts[0] !== '') {
|
||||
throw new Error('Make sure all paths are absolute.');
|
||||
}
|
||||
let node = filesystem;
|
||||
parts.slice(1).forEach(part => {
|
||||
if (node && node.SYMLINK) {
|
||||
node = getToNode(node.SYMLINK);
|
||||
}
|
||||
node = node[part];
|
||||
if (node == null) {
|
||||
const err = new Error(
|
||||
`ENOENT: no such file or directory: \`${filepath}\``,
|
||||
);
|
||||
err.code = 'ENOENT';
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
fs.__setMockFilesystem = setMockFilesystem;
|
||||
fs.mock = {clear: () => fs.reset()};
|
||||
|
||||
module.exports = fs;
|
||||
|
|
|
@ -1,89 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @emails oncall+javascript_foundation
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
declare var jest: any;
|
||||
declare var describe: any;
|
||||
declare var beforeEach: any;
|
||||
declare var expect: any;
|
||||
declare var it: any;
|
||||
|
||||
jest.mock('fs');
|
||||
|
||||
const fs = require('fs');
|
||||
|
||||
describe('fs mock', () => {
|
||||
beforeEach(() => {
|
||||
(fs: $FlowFixMe).mock.clear();
|
||||
});
|
||||
|
||||
describe('writeFileSync()', () => {
|
||||
it('stores content correctly', () => {
|
||||
fs.writeFileSync('/test', 'foobar', 'utf8');
|
||||
const content = fs.readFileSync('/test', 'utf8');
|
||||
expect(content).toEqual('foobar');
|
||||
});
|
||||
|
||||
it('fails on missing path', () => {
|
||||
expect(() =>
|
||||
fs.writeFileSync('/dir/test', 'foobar', 'utf8'),
|
||||
).toThrowError('ENOENT: no such file or directory');
|
||||
});
|
||||
|
||||
it('properly normalizes paths', () => {
|
||||
fs.writeFileSync('/test/foo/../bar/../../tadam', 'beep', 'utf8');
|
||||
const content = fs.readFileSync('/glo/../tadam', 'utf8');
|
||||
expect(content).toEqual('beep');
|
||||
});
|
||||
});
|
||||
|
||||
describe('mkdirSync()', () => {
|
||||
it('creates folders that we can write files in', () => {
|
||||
fs.mkdirSync('/dir', 0o777);
|
||||
fs.writeFileSync('/dir/test', 'foobar', 'utf8');
|
||||
const content = fs.readFileSync('/dir/test', 'utf8');
|
||||
expect(content).toEqual('foobar');
|
||||
});
|
||||
|
||||
it('does not erase directories', () => {
|
||||
fs.mkdirSync('/dir', 0o777);
|
||||
fs.writeFileSync('/dir/test', 'foobar', 'utf8');
|
||||
fs.mkdirSync('/dir', 0o777);
|
||||
const content = fs.readFileSync('/dir/test', 'utf8');
|
||||
expect(content).toEqual('foobar');
|
||||
});
|
||||
});
|
||||
|
||||
describe('createWriteStream()', () => {
|
||||
it('writes content', done => {
|
||||
const stream = fs.createWriteStream('/test');
|
||||
stream.write('hello, ');
|
||||
stream.write('world');
|
||||
stream.end('!');
|
||||
process.nextTick(() => {
|
||||
const content = fs.readFileSync('/test', 'utf8');
|
||||
expect(content).toEqual('hello, world!');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('writeSync()', () => {
|
||||
it('writes content', () => {
|
||||
const fd = fs.openSync('/test', 'w');
|
||||
fs.writeSync(fd, 'hello, world!');
|
||||
fs.closeSync(fd);
|
||||
const content = fs.readFileSync('/test', 'utf8');
|
||||
expect(content).toEqual('hello, world!');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -26,6 +26,9 @@ const infoPlistPath = path.join(__dirname, '../../__fixtures__/Info.plist');
|
|||
|
||||
fs.readFileSync = jest.fn(() => readFileSync(projectPath).toString());
|
||||
|
||||
const {writeFileSync} = fs;
|
||||
fs.writeFileSync = jest.fn(writeFileSync);
|
||||
|
||||
const project = xcode.project('/Basic/project.pbxproj');
|
||||
|
||||
const plist = {
|
||||
|
|
|
@ -170,6 +170,7 @@
|
|||
"metro": "^0.34.0",
|
||||
"metro-babel-register": "^0.34.2",
|
||||
"metro-core": "^0.34.0",
|
||||
"metro-memory-fs": "^0.34.0",
|
||||
"mime": "^1.3.4",
|
||||
"minimist": "^1.2.0",
|
||||
"mkdirp": "^0.5.1",
|
||||
|
|
Loading…
Reference in New Issue