UNPKG

3.19 kBJavaScriptView Raw
1'use strict';
2
3var realFs = require('fs');
4var path = require('path');
5
6var rewire = require('rewire');
7var semver = require('semver');
8
9var Binding = require('./binding');
10var FileSystem = require('./filesystem');
11var FSError = require('./error');
12
13var versions = {
14 '0.8.x': 'fs-0.8.26.js',
15 '0.9.x': 'fs-0.9.12.js',
16 '0.10.x': 'fs-0.10.28.js',
17 '0.11 - 0.11.14': 'fs-0.11.13.js',
18 '0.11.15 - 0.12.x': 'fs-0.12.0.js',
19 '1.x.x': 'fs-1.1.0.js',
20 '2.x.x': 'fs-2.0.0.js',
21 '3.x.x': 'fs-3.0.0.js'
22};
23var nodeVersion = process.versions.node;
24var fsName;
25
26Object.keys(versions).forEach(function (version) {
27 if (semver.satisfies(nodeVersion, version)) {
28 fsName = versions[version];
29 return false;
30 }
31});
32
33if (!fsName) {
34 throw new Error('Unsupported Node version: ' + nodeVersion);
35}
36
37
38/**
39 * Hijack the real fs module immediately so the binding can be swapped at will.
40 * This works as expected in cases where mock-fs is required before any other
41 * module that wraps fs exports.
42 */
43var mockFs = rewire(path.join(__dirname, '..', 'node', fsName));
44var originalBinding = mockFs.__get__('binding');
45var originalStats = mockFs.Stats;
46for (var name in mockFs) {
47 var descriptor = Object.getOwnPropertyDescriptor(realFs, name);
48
49 if (!descriptor || descriptor && descriptor.writable) {
50 realFs[name] = mockFs[name];
51 }
52}
53var originalProcess = {
54 cwd: process.cwd,
55 chdir: process.chdir
56};
57
58function setBinding(binding, Stats) {
59 mockFs.__set__('binding', binding);
60 mockFs.Stats = realFs.Stats = Stats;
61}
62
63function setProcess(cwd, chdir) {
64 process.cwd = cwd;
65 process.chdir = chdir;
66}
67
68
69/**
70 * Swap out the fs bindings for a mock file system.
71 * @param {Object} config Mock file system configuration.
72 */
73var exports = module.exports = function mock(config) {
74 var system = FileSystem.create(config);
75 var binding = new Binding(system);
76 setBinding(binding, binding.Stats);
77
78 var currentPath = process.cwd();
79 setProcess(
80 function cwd() {
81 return currentPath;
82 },
83 function chdir(directory) {
84 if (!mockFs.statSync(directory).isDirectory()) {
85 throw new FSError('ENOTDIR');
86 }
87 currentPath = path.resolve(currentPath, directory);
88 }
89 );
90};
91
92
93/**
94 * Restore the fs bindings for the real file system.
95 */
96exports.restore = function() {
97 setBinding(originalBinding, originalStats);
98 setProcess(originalProcess.cwd, originalProcess.chdir);
99};
100
101
102/**
103 * Create a mock fs module based on the given file system configuration.
104 * @param {Object} config File system configuration.
105 * @return {Object} A fs module with a mock file system.
106 */
107exports.fs = function(config) {
108 var system = FileSystem.create(config);
109 var binding = new Binding(system);
110
111 // inject the mock binding
112 var newMockFs = rewire(path.join(__dirname, '..', 'node', fsName));
113 newMockFs.__set__('binding', binding);
114
115 // overwrite fs.Stats from original binding
116 newMockFs.Stats = binding.Stats;
117
118 return newMockFs;
119};
120
121
122/**
123 * Create a file factory.
124 */
125exports.file = FileSystem.file;
126
127
128/**
129 * Create a directory factory.
130 */
131exports.directory = FileSystem.directory;
132
133
134/**
135 * Create a symbolic link factory.
136 */
137exports.symlink = FileSystem.symlink;