Skip to content

Commit

Permalink
fix: synchronize patching binding/createWriteStream/cwd/chdir
Browse files Browse the repository at this point in the history
All the patches now check same realBinding._mockedBinding. This should
fix the edge cases around the new feature bypass().

follows up #306
  • Loading branch information
3cp committed Aug 13, 2020
1 parent 47a7979 commit eb24e2f
Showing 1 changed file with 34 additions and 58 deletions.
92 changes: 34 additions & 58 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,39 @@
const Binding = require('./binding');
const FSError = require('./error');
const FileSystem = require('./filesystem');
const realBinding = process.binding('fs');
const path = require('path');
const loader = require('./loader');
const bypass = require('./bypass');
const fs = require('fs');

const realBinding = process.binding('fs');
const toNamespacedPath = FileSystem.toNamespacedPath;
const realCreateWriteStream = fs.createWriteStream;
const realCwd = process.cwd;
const realChdir = process.chdir;

const realProcessProps = {
cwd: process.cwd,
chdir: process.chdir
let mockedCwd; // To be set in mockfs()
process.cwd = function() {
if (realBinding._mockedBinding) {
return mockedCwd;
}
return realCwd();
};

process.chdir = function(directory) {
if (realBinding._mockedBinding) {
if (
!realBinding._mockedBinding
.stat(toNamespacedPath(directory))
.isDirectory()
) {
throw new FSError('ENOTDIR');
}
mockedCwd = path.resolve(mockedCwd, directory);
} else {
return realChdir();
}
};
const realCreateWriteStream = fs.createWriteStream;
const realStats = realBinding.Stats;
const realStatWatcher = realBinding.StatWatcher;

/**
* Pre-patch fs binding.
Expand Down Expand Up @@ -50,15 +68,6 @@ for (const key in Binding.prototype) {
}
}

function overrideBinding(binding) {
realBinding._mockedBinding = binding;
}

function overrideProcess(cwd, chdir) {
process.cwd = cwd;
process.chdir = chdir;
}

/**
* Have to disable write stream _writev on nodejs v10+.
*
Expand All @@ -83,30 +92,14 @@ function overrideProcess(cwd, chdir) {
* 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
fs.createWriteStream = function(path, options) {
const output = realCreateWriteStream(path, options);
// disable _writev, this will over shadow WriteStream.prototype._writev
if (realBinding._mockedBinding) {
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;
}
return output;
};

/**
* Swap out the fs bindings for a mock file system.
Expand All @@ -120,23 +113,8 @@ function restoreCreateWriteStream() {
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();
mockedCwd = realCwd();
realBinding._mockedBinding = binding;
};

/**
Expand All @@ -155,9 +133,7 @@ exports.getMockRoot = function() {
* Restore the fs bindings for the real file system.
*/
exports.restore = function() {
restoreBinding();
restoreProcess();
restoreCreateWriteStream();
delete realBinding._mockedBinding;
};

/**
Expand Down

0 comments on commit eb24e2f

Please # to comment.