1 | 'use strict';
|
2 |
|
3 | const Binding = require('./binding');
|
4 | const {FSError} = require('./error');
|
5 | const FileSystem = require('./filesystem');
|
6 | const realBinding = process.binding('fs');
|
7 | const path = require('path');
|
8 | const loader = require('./loader');
|
9 | const bypass = require('./bypass');
|
10 | const {
|
11 | getReadFileContextPrototype,
|
12 | patchReadFileContext
|
13 | } = require('./readfilecontext');
|
14 | const fs = require('fs');
|
15 |
|
16 | const toNamespacedPath = FileSystem.toNamespacedPath;
|
17 |
|
18 | const realProcessProps = {
|
19 | cwd: process.cwd,
|
20 | chdir: process.chdir
|
21 | };
|
22 | const realCreateWriteStream = fs.createWriteStream;
|
23 | const realStats = realBinding.Stats;
|
24 | const realStatWatcher = realBinding.StatWatcher;
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 | function patch(key) {
|
38 | const existingMethod = realBinding[key];
|
39 | realBinding[key] = function() {
|
40 | if (this._mockedBinding) {
|
41 | return this._mockedBinding[key].apply(this._mockedBinding, arguments);
|
42 | } else {
|
43 | return existingMethod.apply(this, arguments);
|
44 | }
|
45 | }.bind(realBinding);
|
46 | }
|
47 |
|
48 | for (const key in Binding.prototype) {
|
49 | if (typeof realBinding[key] === 'function') {
|
50 |
|
51 | if (key !== 'Stats' && key !== 'StatWatcher') {
|
52 | patch(key);
|
53 | }
|
54 | }
|
55 | }
|
56 |
|
57 | const readFileContextPrototype = getReadFileContextPrototype();
|
58 |
|
59 | patchReadFileContext(readFileContextPrototype);
|
60 |
|
61 | function overrideBinding(binding) {
|
62 | realBinding._mockedBinding = binding;
|
63 | }
|
64 |
|
65 | function overrideProcess(cwd, chdir) {
|
66 | process.cwd = cwd;
|
67 | process.chdir = chdir;
|
68 | }
|
69 |
|
70 |
|
71 |
|
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 |
|
80 |
|
81 |
|
82 |
|
83 |
|
84 |
|
85 |
|
86 |
|
87 |
|
88 |
|
89 |
|
90 |
|
91 |
|
92 |
|
93 |
|
94 | function overrideCreateWriteStream() {
|
95 | fs.createWriteStream = function(path, options) {
|
96 | const output = realCreateWriteStream(path, options);
|
97 |
|
98 | if (realBinding._mockedBinding) {
|
99 | output._writev = undefined;
|
100 | }
|
101 | return output;
|
102 | };
|
103 | }
|
104 |
|
105 | function overrideReadFileContext(binding) {
|
106 | readFileContextPrototype._mockedBinding = binding;
|
107 | }
|
108 |
|
109 | function restoreBinding() {
|
110 | delete realBinding._mockedBinding;
|
111 | realBinding.Stats = realStats;
|
112 | realBinding.StatWatcher = realStatWatcher;
|
113 | }
|
114 |
|
115 | function restoreProcess() {
|
116 | for (const key in realProcessProps) {
|
117 | process[key] = realProcessProps[key];
|
118 | }
|
119 | }
|
120 |
|
121 | function restoreCreateWriteStream() {
|
122 | fs.createWriteStream = realCreateWriteStream;
|
123 | }
|
124 |
|
125 | function restoreReadFileContext(binding) {
|
126 | delete readFileContextPrototype._mockedBinding;
|
127 | }
|
128 |
|
129 |
|
130 |
|
131 |
|
132 |
|
133 |
|
134 |
|
135 |
|
136 |
|
137 |
|
138 | exports = module.exports = function mock(config, options) {
|
139 | const system = FileSystem.create(config, options);
|
140 | const binding = new Binding(system);
|
141 |
|
142 | overrideBinding(binding);
|
143 |
|
144 | overrideReadFileContext(binding);
|
145 |
|
146 | let currentPath = process.cwd();
|
147 | overrideProcess(
|
148 | function cwd() {
|
149 | if (realBinding._mockedBinding) {
|
150 | return currentPath;
|
151 | }
|
152 | return realProcessProps.cwd();
|
153 | },
|
154 | function chdir(directory) {
|
155 | if (realBinding._mockedBinding) {
|
156 | if (!fs.statSync(toNamespacedPath(directory)).isDirectory()) {
|
157 | throw new FSError('ENOTDIR');
|
158 | }
|
159 | currentPath = path.resolve(currentPath, directory);
|
160 | } else {
|
161 | return realProcessProps.chdir(directory);
|
162 | }
|
163 | }
|
164 | );
|
165 |
|
166 | overrideCreateWriteStream();
|
167 | };
|
168 |
|
169 |
|
170 |
|
171 |
|
172 |
|
173 | exports.getMockRoot = function() {
|
174 | if (realBinding._mockedBinding) {
|
175 | return realBinding._mockedBinding.getSystem().getRoot();
|
176 | } else {
|
177 | return {};
|
178 | }
|
179 | };
|
180 |
|
181 |
|
182 |
|
183 |
|
184 | exports.restore = function() {
|
185 | restoreBinding();
|
186 | restoreProcess();
|
187 | restoreCreateWriteStream();
|
188 | restoreReadFileContext();
|
189 | };
|
190 |
|
191 |
|
192 |
|
193 |
|
194 | exports.file = FileSystem.file;
|
195 |
|
196 |
|
197 |
|
198 |
|
199 | exports.directory = FileSystem.directory;
|
200 |
|
201 |
|
202 |
|
203 |
|
204 | exports.symlink = FileSystem.symlink;
|
205 |
|
206 |
|
207 |
|
208 |
|
209 | exports.load = loader.load;
|
210 |
|
211 |
|
212 |
|
213 |
|
214 |
|
215 |
|
216 |
|
217 |
|
218 | exports.bypass = bypass;
|