memfs 4.0.0 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -24
- package/README.md +21 -92
- package/lib/Dirent.d.ts +2 -1
- package/lib/__tests__/util.d.ts +13 -0
- package/lib/__tests__/util.js +29 -0
- package/lib/consts/AMODE.d.ts +9 -0
- package/lib/consts/FLAG.d.ts +22 -0
- package/lib/consts/FLAG.js +2 -0
- package/lib/fsa/types.d.ts +3 -3
- package/lib/fsa-to-node/FsaNodeCore.d.ts +32 -0
- package/lib/fsa-to-node/FsaNodeCore.js +168 -0
- package/lib/fsa-to-node/FsaNodeDirent.d.ts +13 -0
- package/lib/fsa-to-node/FsaNodeDirent.js +31 -0
- package/lib/fsa-to-node/FsaNodeFs.d.ts +171 -0
- package/lib/fsa-to-node/FsaNodeFs.js +842 -0
- package/lib/fsa-to-node/FsaNodeFsOpenFile.d.ts +24 -0
- package/lib/fsa-to-node/FsaNodeFsOpenFile.js +46 -0
- package/lib/fsa-to-node/FsaNodeReadStream.d.ts +24 -0
- package/lib/fsa-to-node/FsaNodeReadStream.js +100 -0
- package/lib/fsa-to-node/FsaNodeStats.d.ts +30 -0
- package/lib/fsa-to-node/FsaNodeStats.js +52 -0
- package/lib/fsa-to-node/FsaNodeWriteStream.d.ts +48 -0
- package/lib/fsa-to-node/FsaNodeWriteStream.js +162 -0
- package/lib/fsa-to-node/__tests__/FsaNodeFs.test.d.ts +1 -0
- package/lib/fsa-to-node/__tests__/FsaNodeFs.test.js +873 -0
- package/lib/fsa-to-node/__tests__/util.test.d.ts +1 -0
- package/lib/fsa-to-node/__tests__/util.test.js +28 -0
- package/lib/fsa-to-node/constants.d.ts +3 -0
- package/lib/fsa-to-node/constants.js +2 -0
- package/lib/fsa-to-node/index.d.ts +2 -0
- package/lib/fsa-to-node/index.js +7 -0
- package/lib/fsa-to-node/json.d.ts +4 -0
- package/lib/fsa-to-node/json.js +7 -0
- package/lib/fsa-to-node/types.d.ts +37 -0
- package/lib/fsa-to-node/types.js +2 -0
- package/lib/fsa-to-node/util.d.ts +4 -0
- package/lib/fsa-to-node/util.js +40 -0
- package/lib/fsa-to-node/worker/FsaNodeSyncAdapterWorker.d.ts +10 -0
- package/lib/fsa-to-node/worker/FsaNodeSyncAdapterWorker.js +72 -0
- package/lib/fsa-to-node/worker/FsaNodeSyncWorker.d.ts +20 -0
- package/lib/fsa-to-node/worker/FsaNodeSyncWorker.js +190 -0
- package/lib/fsa-to-node/worker/SyncMessenger.d.ts +24 -0
- package/lib/fsa-to-node/worker/SyncMessenger.js +80 -0
- package/lib/fsa-to-node/worker/constants.d.ts +8 -0
- package/lib/fsa-to-node/worker/constants.js +2 -0
- package/lib/fsa-to-node/worker/types.d.ts +17 -0
- package/lib/fsa-to-node/worker/types.js +2 -0
- package/lib/index.d.ts +5 -4
- package/lib/index.js +1 -1
- package/lib/node/constants.d.ts +41 -0
- package/lib/node/constants.js +56 -0
- package/lib/node/options.d.ts +23 -0
- package/lib/node/options.js +94 -0
- package/lib/node/promises.d.ts +1 -1
- package/lib/node/promises.js +1 -3
- package/lib/node/types/FsCommonObjects.d.ts +17 -0
- package/lib/node/types/FsCommonObjects.js +2 -0
- package/lib/node/types/{sync.d.ts → FsSynchronousApi.d.ts} +36 -37
- package/lib/node/types/FsSynchronousApi.js +2 -0
- package/lib/node/types/callback.d.ts +57 -58
- package/lib/node/types/index.d.ts +1 -1
- package/lib/node/types/misc.d.ts +6 -8
- package/lib/node/types/options.d.ts +20 -6
- package/lib/node/types/promises.d.ts +2 -2
- package/lib/node/util.d.ts +19 -0
- package/lib/node/util.js +265 -1
- package/lib/node-to-fsa/NodeFileSystemDirectoryHandle.d.ts +71 -0
- package/lib/node-to-fsa/NodeFileSystemDirectoryHandle.js +264 -0
- package/lib/node-to-fsa/NodeFileSystemFileHandle.d.ts +28 -0
- package/lib/node-to-fsa/NodeFileSystemFileHandle.js +73 -0
- package/lib/node-to-fsa/NodeFileSystemHandle.d.ts +33 -0
- package/lib/node-to-fsa/NodeFileSystemHandle.js +53 -0
- package/lib/node-to-fsa/NodeFileSystemSyncAccessHandle.d.ts +42 -0
- package/lib/node-to-fsa/NodeFileSystemSyncAccessHandle.js +116 -0
- package/lib/node-to-fsa/NodeFileSystemWritableFileStream.d.ts +54 -0
- package/lib/node-to-fsa/NodeFileSystemWritableFileStream.js +195 -0
- package/lib/node-to-fsa/NodePermissionStatus.d.ts +8 -0
- package/lib/node-to-fsa/NodePermissionStatus.js +13 -0
- package/lib/node-to-fsa/__tests__/NodeFileSystemDirectoryHandle.test.d.ts +1 -0
- package/lib/node-to-fsa/__tests__/NodeFileSystemDirectoryHandle.test.js +627 -0
- package/lib/node-to-fsa/__tests__/NodeFileSystemFileHandle.test.d.ts +1 -0
- package/lib/node-to-fsa/__tests__/NodeFileSystemFileHandle.test.js +191 -0
- package/lib/node-to-fsa/__tests__/NodeFileSystemHandle.test.d.ts +1 -0
- package/lib/node-to-fsa/__tests__/NodeFileSystemHandle.test.js +49 -0
- package/lib/node-to-fsa/__tests__/NodeFileSystemSyncAccessHandle.test.d.ts +1 -0
- package/lib/node-to-fsa/__tests__/NodeFileSystemSyncAccessHandle.test.js +183 -0
- package/lib/node-to-fsa/__tests__/NodeFileSystemWritableFileStream.test.d.ts +1 -0
- package/lib/node-to-fsa/__tests__/NodeFileSystemWritableFileStream.test.js +106 -0
- package/lib/node-to-fsa/__tests__/scenarios.test.d.ts +1 -0
- package/lib/node-to-fsa/__tests__/scenarios.test.js +46 -0
- package/lib/node-to-fsa/__tests__/util.test.d.ts +1 -0
- package/lib/node-to-fsa/__tests__/util.test.js +25 -0
- package/lib/node-to-fsa/index.d.ts +7 -0
- package/lib/node-to-fsa/index.js +26 -0
- package/lib/node-to-fsa/types.d.ts +12 -0
- package/lib/node-to-fsa/types.js +2 -0
- package/lib/node-to-fsa/util.d.ts +11 -0
- package/lib/node-to-fsa/util.js +33 -0
- package/lib/node.d.ts +1 -1
- package/lib/volume.d.ts +45 -126
- package/lib/volume.js +204 -562
- package/lib/webfs/index.d.ts +1 -0
- package/lib/webfs/index.js +22 -0
- package/package.json +28 -5
- /package/lib/{node/types/sync.js → consts/AMODE.js} +0 -0
|
@@ -0,0 +1,873 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const __1 = require("../..");
|
|
13
|
+
const node_to_fsa_1 = require("../../node-to-fsa");
|
|
14
|
+
const FsaNodeFs_1 = require("../FsaNodeFs");
|
|
15
|
+
const thingies_1 = require("thingies");
|
|
16
|
+
const util_1 = require("../../__tests__/util");
|
|
17
|
+
const setup = (json = null, mode = 'readwrite') => {
|
|
18
|
+
const mfs = (0, __1.memfs)({ mountpoint: json });
|
|
19
|
+
const dir = (0, node_to_fsa_1.nodeToFsa)(mfs, '/mountpoint', { mode, syncHandleAllowed: true });
|
|
20
|
+
const fs = new FsaNodeFs_1.FsaNodeFs(dir);
|
|
21
|
+
return { fs, mfs, dir };
|
|
22
|
+
};
|
|
23
|
+
(0, util_1.onlyOnNode20)('FsaNodeFs', () => {
|
|
24
|
+
describe('.mkdir()', () => {
|
|
25
|
+
test('can create a sub-folder', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
26
|
+
const { fs, mfs } = setup();
|
|
27
|
+
yield new Promise((resolve, reject) => fs.mkdir('/test', err => {
|
|
28
|
+
if (err)
|
|
29
|
+
return reject(err);
|
|
30
|
+
return resolve();
|
|
31
|
+
}));
|
|
32
|
+
expect(mfs.statSync('/mountpoint/test').isDirectory()).toBe(true);
|
|
33
|
+
}));
|
|
34
|
+
test('throws when creating sub-sub-folder', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
35
|
+
const { fs } = setup();
|
|
36
|
+
try {
|
|
37
|
+
yield new Promise((resolve, reject) => fs.mkdir('/test/subtest', err => {
|
|
38
|
+
if (err)
|
|
39
|
+
return reject(err);
|
|
40
|
+
return resolve();
|
|
41
|
+
}));
|
|
42
|
+
throw new Error('Expected error');
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
expect(error.code).toBe('ENOENT');
|
|
46
|
+
}
|
|
47
|
+
}));
|
|
48
|
+
test('can create sub-sub-folder with "recursive" flag', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
49
|
+
const { fs, mfs } = setup();
|
|
50
|
+
yield new Promise((resolve, reject) => fs.mkdir('/test/subtest', { recursive: true }, err => {
|
|
51
|
+
if (err)
|
|
52
|
+
return reject(err);
|
|
53
|
+
return resolve();
|
|
54
|
+
}));
|
|
55
|
+
expect(mfs.statSync('/mountpoint/test/subtest').isDirectory()).toBe(true);
|
|
56
|
+
}));
|
|
57
|
+
test('can create sub-sub-folder with "recursive" flag with Promises API', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
58
|
+
const { fs, mfs } = setup();
|
|
59
|
+
yield fs.promises.mkdir('/test/subtest', { recursive: true });
|
|
60
|
+
expect(mfs.statSync('/mountpoint/test/subtest').isDirectory()).toBe(true);
|
|
61
|
+
}));
|
|
62
|
+
test('cannot create a folder over a file', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
63
|
+
const { fs } = setup({ file: 'test' });
|
|
64
|
+
try {
|
|
65
|
+
yield fs.promises.mkdir('/file/folder', { recursive: true });
|
|
66
|
+
throw new Error('Expected error');
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
expect(error.code).toBe('ENOTDIR');
|
|
70
|
+
}
|
|
71
|
+
}));
|
|
72
|
+
});
|
|
73
|
+
describe('.mkdtemp()', () => {
|
|
74
|
+
test('can create a temporary folder', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
75
|
+
const { fs, mfs } = setup();
|
|
76
|
+
const dirname = (yield fs.promises.mkdtemp('prefix--'));
|
|
77
|
+
expect(dirname.startsWith('prefix--')).toBe(true);
|
|
78
|
+
expect(mfs.statSync('/mountpoint/' + dirname).isDirectory()).toBe(true);
|
|
79
|
+
}));
|
|
80
|
+
});
|
|
81
|
+
describe('.rmdir()', () => {
|
|
82
|
+
test('can remove an empty folder', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
83
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null });
|
|
84
|
+
yield fs.promises.rmdir('/empty-folder');
|
|
85
|
+
expect(mfs.__vol.toJSON()).toStrictEqual({ '/mountpoint/folder/file': 'test' });
|
|
86
|
+
}));
|
|
87
|
+
test('throws when attempts to remove non-empty folder', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
88
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null });
|
|
89
|
+
try {
|
|
90
|
+
yield fs.promises.rmdir('/folder');
|
|
91
|
+
throw new Error('Expected error');
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
expect(error.code).toBe('ENOTEMPTY');
|
|
95
|
+
expect(mfs.__vol.toJSON()).toStrictEqual({
|
|
96
|
+
'/mountpoint/folder/file': 'test',
|
|
97
|
+
'/mountpoint/empty-folder': null,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}));
|
|
101
|
+
test('can remove non-empty directory recursively', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
102
|
+
const { fs, mfs } = setup({ folder: { subfolder: { file: 'test' } }, 'empty-folder': null });
|
|
103
|
+
yield fs.promises.rmdir('/folder', { recursive: true });
|
|
104
|
+
expect(mfs.__vol.toJSON()).toStrictEqual({
|
|
105
|
+
'/mountpoint/empty-folder': null,
|
|
106
|
+
});
|
|
107
|
+
}));
|
|
108
|
+
test('can remove starting from root folder', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
109
|
+
const { fs, mfs } = setup({ folder: { subfolder: { file: 'test' } }, 'empty-folder': null });
|
|
110
|
+
yield fs.promises.rmdir('/', { recursive: true });
|
|
111
|
+
expect(mfs.__vol.toJSON()).toStrictEqual({
|
|
112
|
+
'/mountpoint': null,
|
|
113
|
+
});
|
|
114
|
+
}));
|
|
115
|
+
});
|
|
116
|
+
describe('.rm()', () => {
|
|
117
|
+
test('can remove an empty folder', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
118
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null });
|
|
119
|
+
yield fs.promises.rm('/empty-folder');
|
|
120
|
+
expect(mfs.__vol.toJSON()).toStrictEqual({ '/mountpoint/folder/file': 'test' });
|
|
121
|
+
}));
|
|
122
|
+
test('throws when attempts to remove non-empty folder', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
123
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null });
|
|
124
|
+
try {
|
|
125
|
+
yield fs.promises.rm('/folder');
|
|
126
|
+
throw new Error('Expected error');
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
expect(error.code).toBe('ENOTEMPTY');
|
|
130
|
+
expect(mfs.__vol.toJSON()).toStrictEqual({
|
|
131
|
+
'/mountpoint/folder/file': 'test',
|
|
132
|
+
'/mountpoint/empty-folder': null,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}));
|
|
136
|
+
test('can remove non-empty directory recursively', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
137
|
+
const { fs, mfs } = setup({ folder: { subfolder: { file: 'test' } }, 'empty-folder': null });
|
|
138
|
+
yield fs.promises.rm('/folder', { recursive: true });
|
|
139
|
+
expect(mfs.__vol.toJSON()).toStrictEqual({
|
|
140
|
+
'/mountpoint/empty-folder': null,
|
|
141
|
+
});
|
|
142
|
+
}));
|
|
143
|
+
test('throws if path does not exist', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
144
|
+
const { fs, mfs } = setup({ folder: { subfolder: { file: 'test' } }, 'empty-folder': null });
|
|
145
|
+
try {
|
|
146
|
+
yield fs.promises.rm('/lala/lulu', { recursive: true });
|
|
147
|
+
throw new Error('Expected error');
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
expect(error.code).toBe('ENOENT');
|
|
151
|
+
expect(mfs.__vol.toJSON()).toStrictEqual({
|
|
152
|
+
'/mountpoint/folder/subfolder/file': 'test',
|
|
153
|
+
'/mountpoint/empty-folder': null,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}));
|
|
157
|
+
test('does not throw, if path does not exist, but "force" flag set', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
158
|
+
const { fs } = setup({ folder: { subfolder: { file: 'test' } }, 'empty-folder': null });
|
|
159
|
+
yield fs.promises.rm('/lala/lulu', { recursive: true, force: true });
|
|
160
|
+
}));
|
|
161
|
+
test('can remove a file', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
162
|
+
const { fs, mfs } = setup({ folder: { subfolder: { file: 'test' } }, 'empty-folder': null });
|
|
163
|
+
yield fs.promises.rm('/folder/subfolder/file');
|
|
164
|
+
expect(mfs.__vol.toJSON()).toStrictEqual({
|
|
165
|
+
'/mountpoint/folder/subfolder': null,
|
|
166
|
+
'/mountpoint/empty-folder': null,
|
|
167
|
+
});
|
|
168
|
+
}));
|
|
169
|
+
test('can remove starting from root folder', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
170
|
+
const { fs, mfs } = setup({ folder: { subfolder: { file: 'test' } }, 'empty-folder': null });
|
|
171
|
+
yield fs.promises.rm('/', { recursive: true });
|
|
172
|
+
expect(mfs.__vol.toJSON()).toStrictEqual({
|
|
173
|
+
'/mountpoint': null,
|
|
174
|
+
});
|
|
175
|
+
}));
|
|
176
|
+
});
|
|
177
|
+
describe('.unlink()', () => {
|
|
178
|
+
test('can remove a file', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
179
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null });
|
|
180
|
+
const res = yield fs.promises.unlink('/folder/file');
|
|
181
|
+
expect(res).toBe(undefined);
|
|
182
|
+
expect(mfs.__vol.toJSON()).toStrictEqual({
|
|
183
|
+
'/mountpoint/folder': null,
|
|
184
|
+
'/mountpoint/empty-folder': null,
|
|
185
|
+
});
|
|
186
|
+
}));
|
|
187
|
+
test('cannot delete a folder', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
188
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null });
|
|
189
|
+
try {
|
|
190
|
+
yield fs.promises.unlink('/folder');
|
|
191
|
+
throw new Error('Expected error');
|
|
192
|
+
}
|
|
193
|
+
catch (error) {
|
|
194
|
+
expect(error.code).toBe('EISDIR');
|
|
195
|
+
expect(mfs.__vol.toJSON()).toStrictEqual({
|
|
196
|
+
'/mountpoint/folder/file': 'test',
|
|
197
|
+
'/mountpoint/empty-folder': null,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}));
|
|
201
|
+
test('throws when deleting non-existing file', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
202
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null });
|
|
203
|
+
try {
|
|
204
|
+
yield fs.promises.unlink('/folder/not-a-file');
|
|
205
|
+
throw new Error('Expected error');
|
|
206
|
+
}
|
|
207
|
+
catch (error) {
|
|
208
|
+
expect(error.code).toBe('ENOENT');
|
|
209
|
+
expect(mfs.__vol.toJSON()).toStrictEqual({
|
|
210
|
+
'/mountpoint/folder/file': 'test',
|
|
211
|
+
'/mountpoint/empty-folder': null,
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
}));
|
|
215
|
+
});
|
|
216
|
+
describe('.readFile()', () => {
|
|
217
|
+
test('can read file contents', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
218
|
+
const { fs } = setup({ folder: { file: 'test' }, 'empty-folder': null });
|
|
219
|
+
const data = yield fs.promises.readFile('/folder/file');
|
|
220
|
+
expect(data.toString()).toBe('test');
|
|
221
|
+
}));
|
|
222
|
+
test('can read file by file handle', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
223
|
+
const { fs } = setup({ folder: { file: 'test' }, 'empty-folder': null });
|
|
224
|
+
const handle = yield fs.promises.open('/folder/file');
|
|
225
|
+
expect(typeof handle).toBe('object');
|
|
226
|
+
const data = yield fs.promises.readFile(handle);
|
|
227
|
+
expect(data.toString()).toBe('test');
|
|
228
|
+
}));
|
|
229
|
+
test('can read file by file descriptor', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
230
|
+
const { fs } = setup({ folder: { file: 'test' }, 'empty-folder': null });
|
|
231
|
+
const fd = yield new Promise(resolve => {
|
|
232
|
+
fs.open('/folder/file', 'r', (err, fd) => resolve(fd));
|
|
233
|
+
});
|
|
234
|
+
expect(typeof fd).toBe('number');
|
|
235
|
+
const data = yield new Promise(resolve => {
|
|
236
|
+
fs.readFile(fd, { encoding: 'utf8' }, (err, data) => resolve(data));
|
|
237
|
+
});
|
|
238
|
+
expect(data).toBe('test');
|
|
239
|
+
}));
|
|
240
|
+
test('cannot read from closed file descriptor', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
241
|
+
const { fs } = setup({ folder: { file: 'test' }, 'empty-folder': null });
|
|
242
|
+
const fd = yield new Promise(resolve => {
|
|
243
|
+
fs.open('/folder/file', 'r', (err, fd) => resolve(fd));
|
|
244
|
+
});
|
|
245
|
+
expect(typeof fd).toBe('number');
|
|
246
|
+
yield new Promise(resolve => {
|
|
247
|
+
fs.close(fd, () => resolve());
|
|
248
|
+
});
|
|
249
|
+
try {
|
|
250
|
+
yield new Promise((resolve, reject) => {
|
|
251
|
+
fs.readFile(fd, { encoding: 'utf8' }, (err, data) => reject(err));
|
|
252
|
+
});
|
|
253
|
+
throw new Error('Expected error');
|
|
254
|
+
}
|
|
255
|
+
catch (error) {
|
|
256
|
+
expect(error).toBeInstanceOf(Error);
|
|
257
|
+
expect(error.code).toBe('EBADF');
|
|
258
|
+
}
|
|
259
|
+
}));
|
|
260
|
+
});
|
|
261
|
+
describe('.truncate()', () => {
|
|
262
|
+
test('can truncate a file', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
263
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null });
|
|
264
|
+
const res = yield new Promise((resolve, reject) => {
|
|
265
|
+
fs.truncate('/folder/file', 2, (err, res) => (err ? reject(err) : resolve(res)));
|
|
266
|
+
});
|
|
267
|
+
expect(res).toBe(undefined);
|
|
268
|
+
expect(mfs.readFileSync('/mountpoint/folder/file', 'utf8')).toBe('te');
|
|
269
|
+
}));
|
|
270
|
+
});
|
|
271
|
+
describe('.ftruncate()', () => {
|
|
272
|
+
test('can truncate a file', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
273
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null });
|
|
274
|
+
const handle = yield fs.promises.open('/folder/file');
|
|
275
|
+
const res = yield new Promise((resolve, reject) => {
|
|
276
|
+
fs.ftruncate(handle.fd, 3, (err, res) => (err ? reject(err) : resolve(res)));
|
|
277
|
+
});
|
|
278
|
+
expect(res).toBe(undefined);
|
|
279
|
+
expect(mfs.readFileSync('/mountpoint/folder/file', 'utf8')).toBe('tes');
|
|
280
|
+
}));
|
|
281
|
+
});
|
|
282
|
+
describe('.readdir()', () => {
|
|
283
|
+
test('can read directory contents as strings', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
284
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
285
|
+
const res = (yield fs.promises.readdir('/'));
|
|
286
|
+
expect(res.length).toBe(3);
|
|
287
|
+
expect(res.includes('folder')).toBe(true);
|
|
288
|
+
expect(res.includes('empty-folder')).toBe(true);
|
|
289
|
+
expect(res.includes('f.html')).toBe(true);
|
|
290
|
+
}));
|
|
291
|
+
test('can read directory contents with "withFileTypes" flag set', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
292
|
+
var _a, _b, _c, _d;
|
|
293
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
294
|
+
const list = (yield fs.promises.readdir('/', { withFileTypes: true }));
|
|
295
|
+
expect(list.length).toBe(3);
|
|
296
|
+
const names = list.map(item => item.name);
|
|
297
|
+
expect(names).toStrictEqual(['empty-folder', 'f.html', 'folder']);
|
|
298
|
+
expect((_a = list.find(item => item.name === 'folder')) === null || _a === void 0 ? void 0 : _a.isDirectory()).toBe(true);
|
|
299
|
+
expect((_b = list.find(item => item.name === 'empty-folder')) === null || _b === void 0 ? void 0 : _b.isDirectory()).toBe(true);
|
|
300
|
+
expect((_c = list.find(item => item.name === 'f.html')) === null || _c === void 0 ? void 0 : _c.isFile()).toBe(true);
|
|
301
|
+
expect((_d = list.find(item => item.name === 'f.html')) === null || _d === void 0 ? void 0 : _d.isDirectory()).toBe(false);
|
|
302
|
+
}));
|
|
303
|
+
});
|
|
304
|
+
describe('.appendFile()', () => {
|
|
305
|
+
test('can create a file', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
306
|
+
const { fs, mfs } = setup({});
|
|
307
|
+
yield fs.promises.appendFile('/test.txt', 'a');
|
|
308
|
+
expect(mfs.readFileSync('/mountpoint/test.txt', 'utf8')).toBe('a');
|
|
309
|
+
}));
|
|
310
|
+
test('can append to a file', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
311
|
+
const { fs, mfs } = setup({});
|
|
312
|
+
yield fs.promises.appendFile('/test.txt', 'a');
|
|
313
|
+
yield fs.promises.appendFile('/test.txt', 'b');
|
|
314
|
+
expect(mfs.readFileSync('/mountpoint/test.txt', 'utf8')).toBe('ab');
|
|
315
|
+
}));
|
|
316
|
+
test('can append to a file - 2', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
317
|
+
const { fs, mfs } = setup({ file: '123' });
|
|
318
|
+
yield fs.promises.appendFile('file', 'x');
|
|
319
|
+
expect(mfs.readFileSync('/mountpoint/file', 'utf8')).toBe('123x');
|
|
320
|
+
}));
|
|
321
|
+
test('can append to a file - 2', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
322
|
+
const { fs, mfs } = setup({ file: '123' });
|
|
323
|
+
yield fs.promises.writeFile('cool.txt', 'worlds');
|
|
324
|
+
yield fs.promises.appendFile('cool.txt', '!');
|
|
325
|
+
expect(mfs.readFileSync('/mountpoint/cool.txt', 'utf8')).toBe('worlds!');
|
|
326
|
+
}));
|
|
327
|
+
});
|
|
328
|
+
describe('.write()', () => {
|
|
329
|
+
test('can write to a file', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
330
|
+
const { fs, mfs } = setup({});
|
|
331
|
+
const fd = yield new Promise((resolve, reject) => fs.open('/test.txt', 'w', (err, fd) => {
|
|
332
|
+
if (err)
|
|
333
|
+
reject(err);
|
|
334
|
+
else
|
|
335
|
+
resolve(fd);
|
|
336
|
+
}));
|
|
337
|
+
const [bytesWritten, data] = yield new Promise((resolve, reject) => {
|
|
338
|
+
fs.write(fd, 'a', (err, bytesWritten, data) => {
|
|
339
|
+
if (err)
|
|
340
|
+
reject(err);
|
|
341
|
+
else
|
|
342
|
+
resolve([bytesWritten, data]);
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
expect(bytesWritten).toBe(1);
|
|
346
|
+
expect(data).toBe('a');
|
|
347
|
+
expect(mfs.readFileSync('/mountpoint/test.txt', 'utf8')).toBe('a');
|
|
348
|
+
}));
|
|
349
|
+
test('can write to a file twice sequentially', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
350
|
+
const { fs, mfs } = setup({});
|
|
351
|
+
const fd = yield new Promise((resolve, reject) => fs.open('/test.txt', 'w', (err, fd) => {
|
|
352
|
+
if (err)
|
|
353
|
+
reject(err);
|
|
354
|
+
else
|
|
355
|
+
resolve(fd);
|
|
356
|
+
}));
|
|
357
|
+
const res1 = yield new Promise((resolve, reject) => {
|
|
358
|
+
fs.write(fd, 'a', (err, bytesWritten, data) => {
|
|
359
|
+
if (err)
|
|
360
|
+
reject(err);
|
|
361
|
+
else
|
|
362
|
+
resolve([bytesWritten, data]);
|
|
363
|
+
});
|
|
364
|
+
});
|
|
365
|
+
expect(res1[0]).toBe(1);
|
|
366
|
+
expect(res1[1]).toBe('a');
|
|
367
|
+
const res2 = yield new Promise((resolve, reject) => {
|
|
368
|
+
fs.write(fd, 'bc', (err, bytesWritten, data) => {
|
|
369
|
+
if (err)
|
|
370
|
+
reject(err);
|
|
371
|
+
else
|
|
372
|
+
resolve([bytesWritten, data]);
|
|
373
|
+
});
|
|
374
|
+
});
|
|
375
|
+
expect(res2[0]).toBe(2);
|
|
376
|
+
expect(res2[1]).toBe('bc');
|
|
377
|
+
expect(mfs.readFileSync('/mountpoint/test.txt', 'utf8')).toBe('abc');
|
|
378
|
+
}));
|
|
379
|
+
});
|
|
380
|
+
describe('.writev()', () => {
|
|
381
|
+
test('can write to a file two buffers', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
382
|
+
const { fs, mfs } = setup({});
|
|
383
|
+
const fd = yield new Promise((resolve, reject) => fs.open('/test.txt', 'w', (err, fd) => {
|
|
384
|
+
if (err)
|
|
385
|
+
reject(err);
|
|
386
|
+
else
|
|
387
|
+
resolve(fd);
|
|
388
|
+
}));
|
|
389
|
+
const [bytesWritten, data] = yield new Promise((resolve, reject) => {
|
|
390
|
+
const buffers = [Buffer.from('a'), Buffer.from('b')];
|
|
391
|
+
fs.writev(fd, buffers, (err, bytesWritten, data) => {
|
|
392
|
+
if (err)
|
|
393
|
+
reject(err);
|
|
394
|
+
else
|
|
395
|
+
resolve([bytesWritten, data]);
|
|
396
|
+
});
|
|
397
|
+
});
|
|
398
|
+
expect(bytesWritten).toBe(2);
|
|
399
|
+
expect(mfs.readFileSync('/mountpoint/test.txt', 'utf8')).toBe('ab');
|
|
400
|
+
}));
|
|
401
|
+
});
|
|
402
|
+
describe('.exists()', () => {
|
|
403
|
+
test('can works for folders and files', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
404
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
405
|
+
const exists = (path) => __awaiter(void 0, void 0, void 0, function* () {
|
|
406
|
+
return new Promise(resolve => {
|
|
407
|
+
fs.exists(path, exists => resolve(exists));
|
|
408
|
+
});
|
|
409
|
+
});
|
|
410
|
+
expect(yield exists('/folder')).toBe(true);
|
|
411
|
+
expect(yield exists('/folder/file')).toBe(true);
|
|
412
|
+
expect(yield exists('/folder/not-a-file')).toBe(false);
|
|
413
|
+
expect(yield exists('/f.html')).toBe(true);
|
|
414
|
+
expect(yield exists('/empty-folder')).toBe(true);
|
|
415
|
+
expect(yield exists('/')).toBe(true);
|
|
416
|
+
expect(yield exists('/asdf')).toBe(false);
|
|
417
|
+
expect(yield exists('asdf')).toBe(false);
|
|
418
|
+
}));
|
|
419
|
+
});
|
|
420
|
+
describe('.access()', () => {
|
|
421
|
+
describe('files', () => {
|
|
422
|
+
test('succeeds on file existence check', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
423
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
424
|
+
yield fs.promises.access('/folder/file', 0 /* AMODE.F_OK */);
|
|
425
|
+
}));
|
|
426
|
+
test('succeeds on file "read" check', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
427
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
428
|
+
yield fs.promises.access('/folder/file', 4 /* AMODE.R_OK */);
|
|
429
|
+
}));
|
|
430
|
+
test('succeeds on file "write" check, on writable file system', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
431
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
432
|
+
yield fs.promises.access('/folder/file', 2 /* AMODE.W_OK */);
|
|
433
|
+
}));
|
|
434
|
+
test('fails on file "write" check, on read-only file system', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
435
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' }, 'read');
|
|
436
|
+
try {
|
|
437
|
+
yield fs.promises.access('/folder/file', 2 /* AMODE.W_OK */);
|
|
438
|
+
throw new Error('should not be here');
|
|
439
|
+
}
|
|
440
|
+
catch (error) {
|
|
441
|
+
expect(error.code).toBe('EACCESS');
|
|
442
|
+
}
|
|
443
|
+
}));
|
|
444
|
+
test('fails on file "execute" check', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
445
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
446
|
+
try {
|
|
447
|
+
yield fs.promises.access('/folder/file', 1 /* AMODE.X_OK */);
|
|
448
|
+
throw new Error('should not be here');
|
|
449
|
+
}
|
|
450
|
+
catch (error) {
|
|
451
|
+
expect(error.code).toBe('EACCESS');
|
|
452
|
+
}
|
|
453
|
+
}));
|
|
454
|
+
});
|
|
455
|
+
describe('directories', () => {
|
|
456
|
+
test('succeeds on folder existence check', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
457
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
458
|
+
yield fs.promises.access('/folder', 0 /* AMODE.F_OK */);
|
|
459
|
+
}));
|
|
460
|
+
test('succeeds on folder "read" check', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
461
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
462
|
+
yield fs.promises.access('/folder', 4 /* AMODE.R_OK */);
|
|
463
|
+
}));
|
|
464
|
+
test('succeeds on folder "write" check, on writable file system', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
465
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
466
|
+
yield fs.promises.access('/folder', 2 /* AMODE.W_OK */);
|
|
467
|
+
}));
|
|
468
|
+
test('fails on folder "write" check, on read-only file system', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
469
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' }, 'read');
|
|
470
|
+
try {
|
|
471
|
+
yield fs.promises.access('/folder', 2 /* AMODE.W_OK */);
|
|
472
|
+
throw new Error('should not be here');
|
|
473
|
+
}
|
|
474
|
+
catch (error) {
|
|
475
|
+
expect(error.code).toBe('EACCESS');
|
|
476
|
+
}
|
|
477
|
+
}));
|
|
478
|
+
test('fails on folder "execute" check', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
479
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
480
|
+
try {
|
|
481
|
+
yield fs.promises.access('/folder', 1 /* AMODE.X_OK */);
|
|
482
|
+
throw new Error('should not be here');
|
|
483
|
+
}
|
|
484
|
+
catch (error) {
|
|
485
|
+
expect(error.code).toBe('EACCESS');
|
|
486
|
+
}
|
|
487
|
+
}));
|
|
488
|
+
});
|
|
489
|
+
});
|
|
490
|
+
describe('.rename()', () => {
|
|
491
|
+
test('can rename a file', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
492
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
493
|
+
yield fs.promises.rename('/folder/file', '/folder/file2');
|
|
494
|
+
expect(mfs.__vol.toJSON()).toStrictEqual({
|
|
495
|
+
'/mountpoint/folder/file2': 'test',
|
|
496
|
+
'/mountpoint/empty-folder': null,
|
|
497
|
+
'/mountpoint/f.html': 'test',
|
|
498
|
+
});
|
|
499
|
+
}));
|
|
500
|
+
});
|
|
501
|
+
describe('.stat()', () => {
|
|
502
|
+
test('can stat a file', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
503
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
504
|
+
const stats = yield fs.promises.stat('/folder/file');
|
|
505
|
+
expect(stats.isFile()).toBe(true);
|
|
506
|
+
}));
|
|
507
|
+
test('throws "ENOENT" when path is not found', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
508
|
+
const { fs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
509
|
+
const [, error] = yield (0, thingies_1.of)(fs.promises.stat('/folder/repo/.git'));
|
|
510
|
+
expect(error.code).toBe('ENOENT');
|
|
511
|
+
}));
|
|
512
|
+
test('throws "ENOTDIR" when sub-folder is a file', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
513
|
+
const { fs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
514
|
+
const [, error] = yield (0, thingies_1.of)(fs.promises.stat('/folder/file/repo/.git'));
|
|
515
|
+
expect(error.code).toBe('ENOTDIR');
|
|
516
|
+
}));
|
|
517
|
+
test('can retrieve file size', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
518
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
519
|
+
const stats = yield fs.promises.stat('/folder/file');
|
|
520
|
+
expect(stats.size).toBe(4);
|
|
521
|
+
}));
|
|
522
|
+
test('can stat a folder', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
523
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
524
|
+
const stats = yield fs.promises.stat('/folder');
|
|
525
|
+
expect(stats.isFile()).toBe(false);
|
|
526
|
+
expect(stats.isDirectory()).toBe(true);
|
|
527
|
+
}));
|
|
528
|
+
test('throws on non-existing path', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
529
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
530
|
+
try {
|
|
531
|
+
const stats = yield fs.promises.stat('/folder/abc');
|
|
532
|
+
throw new Error('should not be here');
|
|
533
|
+
}
|
|
534
|
+
catch (error) {
|
|
535
|
+
expect(error.code).toBe('ENOENT');
|
|
536
|
+
}
|
|
537
|
+
}));
|
|
538
|
+
});
|
|
539
|
+
describe('.lstat()', () => {
|
|
540
|
+
test('can stat a file', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
541
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
542
|
+
const stats = yield fs.promises.lstat('/folder/file');
|
|
543
|
+
expect(stats.isFile()).toBe(true);
|
|
544
|
+
}));
|
|
545
|
+
test('can retrieve file size', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
546
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
547
|
+
const stats = yield fs.promises.lstat('/folder/file');
|
|
548
|
+
expect(stats.size).toBe(4);
|
|
549
|
+
}));
|
|
550
|
+
test('can stat a folder', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
551
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
552
|
+
const stats = yield fs.promises.lstat('/folder');
|
|
553
|
+
expect(stats.isFile()).toBe(false);
|
|
554
|
+
expect(stats.isDirectory()).toBe(true);
|
|
555
|
+
}));
|
|
556
|
+
test('throws on non-existing path', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
557
|
+
const { fs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
558
|
+
try {
|
|
559
|
+
yield fs.promises.lstat('/folder/abc');
|
|
560
|
+
throw new Error('should not be here');
|
|
561
|
+
}
|
|
562
|
+
catch (error) {
|
|
563
|
+
expect(error.code).toBe('ENOENT');
|
|
564
|
+
}
|
|
565
|
+
}));
|
|
566
|
+
});
|
|
567
|
+
describe('.fstat()', () => {
|
|
568
|
+
test('can stat a file', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
569
|
+
const { fs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
570
|
+
const handle = yield fs.promises.open('/folder/file', 'r');
|
|
571
|
+
const stats = yield new Promise((resolve, reject) => {
|
|
572
|
+
fs.fstat(handle.fd, (error, stats) => {
|
|
573
|
+
if (error)
|
|
574
|
+
reject(error);
|
|
575
|
+
else
|
|
576
|
+
resolve(stats);
|
|
577
|
+
});
|
|
578
|
+
});
|
|
579
|
+
expect(stats.isFile()).toBe(true);
|
|
580
|
+
}));
|
|
581
|
+
});
|
|
582
|
+
describe('.realpath()', () => {
|
|
583
|
+
test('returns file path', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
584
|
+
const { fs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
585
|
+
const path = yield fs.promises.realpath('folder/file');
|
|
586
|
+
expect(path).toBe('/folder/file');
|
|
587
|
+
}));
|
|
588
|
+
});
|
|
589
|
+
describe('.realpathSync()', () => {
|
|
590
|
+
test('returns file path', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
591
|
+
const { fs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
592
|
+
const path = fs.realpathSync('folder/file');
|
|
593
|
+
expect(path).toBe('/folder/file');
|
|
594
|
+
}));
|
|
595
|
+
});
|
|
596
|
+
describe('.copyFile()', () => {
|
|
597
|
+
test('can copy a file', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
598
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
599
|
+
yield fs.promises.copyFile('/folder/file', '/folder/file2');
|
|
600
|
+
expect(mfs.__vol.toJSON()).toStrictEqual({
|
|
601
|
+
'/mountpoint/folder/file': 'test',
|
|
602
|
+
'/mountpoint/folder/file2': 'test',
|
|
603
|
+
'/mountpoint/empty-folder': null,
|
|
604
|
+
'/mountpoint/f.html': 'test',
|
|
605
|
+
});
|
|
606
|
+
}));
|
|
607
|
+
});
|
|
608
|
+
describe('.writeFile()', () => {
|
|
609
|
+
test('can create a new file', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
610
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
611
|
+
const res = yield new Promise((resolve, reject) => {
|
|
612
|
+
fs.writeFile('/folder/foo', 'bar', error => {
|
|
613
|
+
if (error)
|
|
614
|
+
reject(error);
|
|
615
|
+
else
|
|
616
|
+
resolve();
|
|
617
|
+
});
|
|
618
|
+
});
|
|
619
|
+
expect(res).toBe(undefined);
|
|
620
|
+
expect(mfs.__vol.toJSON()).toStrictEqual({
|
|
621
|
+
'/mountpoint/folder/file': 'test',
|
|
622
|
+
'/mountpoint/folder/foo': 'bar',
|
|
623
|
+
'/mountpoint/empty-folder': null,
|
|
624
|
+
'/mountpoint/f.html': 'test',
|
|
625
|
+
});
|
|
626
|
+
}));
|
|
627
|
+
});
|
|
628
|
+
describe('.read()', () => {
|
|
629
|
+
test('can read from a file at offset into Buffer', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
630
|
+
const { fs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
631
|
+
const handle = yield fs.promises.open('/folder/file', 'r');
|
|
632
|
+
const [buffer, length] = yield new Promise((resolve, reject) => {
|
|
633
|
+
const buffer = Buffer.alloc(4);
|
|
634
|
+
fs.read(handle.fd, buffer, 0, 2, 1, (error, bytesRead, buffer) => {
|
|
635
|
+
if (error)
|
|
636
|
+
reject(error);
|
|
637
|
+
else
|
|
638
|
+
resolve([buffer, bytesRead]);
|
|
639
|
+
});
|
|
640
|
+
});
|
|
641
|
+
expect(length).toBe(2);
|
|
642
|
+
expect(buffer.slice(0, 2).toString()).toBe('es');
|
|
643
|
+
}));
|
|
644
|
+
test('can read from a file at offset into Uint8Array', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
645
|
+
const { fs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
646
|
+
const handle = yield fs.promises.open('/folder/file', 'r');
|
|
647
|
+
const [buffer, length] = yield new Promise((resolve, reject) => {
|
|
648
|
+
const buffer = new Uint8Array(4);
|
|
649
|
+
fs.read(handle.fd, buffer, 0, 2, 1, (error, bytesRead, buffer) => {
|
|
650
|
+
if (error)
|
|
651
|
+
reject(error);
|
|
652
|
+
else
|
|
653
|
+
resolve([buffer, bytesRead]);
|
|
654
|
+
});
|
|
655
|
+
});
|
|
656
|
+
expect(length).toBe(2);
|
|
657
|
+
expect(buffer[0]).toBe(101);
|
|
658
|
+
expect(buffer[1]).toBe(115);
|
|
659
|
+
}));
|
|
660
|
+
});
|
|
661
|
+
describe('.createWriteStream()', () => {
|
|
662
|
+
test('can use stream to write to a new file', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
663
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
664
|
+
const stream = fs.createWriteStream('/folder/file2');
|
|
665
|
+
stream.write(Buffer.from('A'));
|
|
666
|
+
stream.write(Buffer.from('BC'));
|
|
667
|
+
stream.write(Buffer.from('DEF'));
|
|
668
|
+
stream.end();
|
|
669
|
+
yield new Promise(resolve => stream.once('close', resolve));
|
|
670
|
+
expect(stream.bytesWritten).toBe(6);
|
|
671
|
+
expect(mfs.__vol.toJSON()).toStrictEqual({
|
|
672
|
+
'/mountpoint/folder/file': 'test',
|
|
673
|
+
'/mountpoint/folder/file2': 'ABCDEF',
|
|
674
|
+
'/mountpoint/empty-folder': null,
|
|
675
|
+
'/mountpoint/f.html': 'test',
|
|
676
|
+
});
|
|
677
|
+
}));
|
|
678
|
+
test('can use stream to write to a new file using strings', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
679
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
680
|
+
const stream = fs.createWriteStream('/folder/file2');
|
|
681
|
+
stream.write('A');
|
|
682
|
+
stream.write('BC');
|
|
683
|
+
stream.write('DEF');
|
|
684
|
+
stream.end();
|
|
685
|
+
yield new Promise(resolve => stream.once('close', resolve));
|
|
686
|
+
expect(stream.bytesWritten).toBe(6);
|
|
687
|
+
expect(mfs.__vol.toJSON()).toStrictEqual({
|
|
688
|
+
'/mountpoint/folder/file': 'test',
|
|
689
|
+
'/mountpoint/folder/file2': 'ABCDEF',
|
|
690
|
+
'/mountpoint/empty-folder': null,
|
|
691
|
+
'/mountpoint/f.html': 'test',
|
|
692
|
+
});
|
|
693
|
+
}));
|
|
694
|
+
test('can use stream to overwrite existing file', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
695
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
696
|
+
const stream = fs.createWriteStream('/folder/file');
|
|
697
|
+
stream.write(Buffer.from('A'));
|
|
698
|
+
stream.write(Buffer.from('BC'));
|
|
699
|
+
stream.end();
|
|
700
|
+
yield new Promise(resolve => stream.once('close', resolve));
|
|
701
|
+
expect(stream.bytesWritten).toBe(3);
|
|
702
|
+
expect(mfs.__vol.toJSON()).toStrictEqual({
|
|
703
|
+
'/mountpoint/folder/file': 'ABC',
|
|
704
|
+
'/mountpoint/empty-folder': null,
|
|
705
|
+
'/mountpoint/f.html': 'test',
|
|
706
|
+
});
|
|
707
|
+
}));
|
|
708
|
+
test('can write by file descriptor', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
709
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
710
|
+
const handle = yield fs.promises.open('/folder/file', 'a');
|
|
711
|
+
const stream = fs.createWriteStream('', { fd: handle.fd, start: 1, flags: 'a' });
|
|
712
|
+
stream.write(Buffer.from('BC'));
|
|
713
|
+
stream.end();
|
|
714
|
+
yield new Promise(resolve => stream.once('close', resolve));
|
|
715
|
+
expect(stream.bytesWritten).toBe(2);
|
|
716
|
+
expect(mfs.__vol.toJSON()).toStrictEqual({
|
|
717
|
+
'/mountpoint/folder/file': 'tBCt',
|
|
718
|
+
'/mountpoint/empty-folder': null,
|
|
719
|
+
'/mountpoint/f.html': 'test',
|
|
720
|
+
});
|
|
721
|
+
}));
|
|
722
|
+
test('closes file once stream ends', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
723
|
+
const { fs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
724
|
+
const handle = yield fs.promises.open('/folder/file', 'a');
|
|
725
|
+
const stream = fs.createWriteStream('', { fd: handle.fd, start: 1, flags: 'a' });
|
|
726
|
+
stream.write(Buffer.from('BC'));
|
|
727
|
+
const stat = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
728
|
+
return yield new Promise((resolve, reject) => fs.fstat(handle.fd, (err, stats) => {
|
|
729
|
+
if (err)
|
|
730
|
+
reject(err);
|
|
731
|
+
else
|
|
732
|
+
resolve(stats);
|
|
733
|
+
}));
|
|
734
|
+
});
|
|
735
|
+
yield stat();
|
|
736
|
+
stream.end();
|
|
737
|
+
yield (0, thingies_1.until)(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
738
|
+
const [, error] = yield (0, thingies_1.of)(stat());
|
|
739
|
+
return !!error;
|
|
740
|
+
}));
|
|
741
|
+
const [, error] = yield (0, thingies_1.of)(stat());
|
|
742
|
+
expect(error.code).toBe('EBADF');
|
|
743
|
+
}));
|
|
744
|
+
test('does not close file if "autoClose" is false', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
745
|
+
const { fs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
746
|
+
const handle = yield fs.promises.open('/folder/file', 'a');
|
|
747
|
+
const stream = fs.createWriteStream('', { fd: handle.fd, start: 1, flags: 'a', autoClose: false });
|
|
748
|
+
stream.write(Buffer.from('BC'));
|
|
749
|
+
const stat = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
750
|
+
return yield new Promise((resolve, reject) => fs.fstat(handle.fd, (err, stats) => {
|
|
751
|
+
if (err)
|
|
752
|
+
reject(err);
|
|
753
|
+
else
|
|
754
|
+
resolve(stats);
|
|
755
|
+
}));
|
|
756
|
+
});
|
|
757
|
+
yield stat();
|
|
758
|
+
stream.end();
|
|
759
|
+
yield (0, thingies_1.tick)(200);
|
|
760
|
+
yield stat();
|
|
761
|
+
}));
|
|
762
|
+
test('can use stream to add to existing file', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
763
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
764
|
+
const stream = fs.createWriteStream('/folder/file', { flags: 'a' });
|
|
765
|
+
stream.write(Buffer.from('A'));
|
|
766
|
+
stream.write(Buffer.from('BC'));
|
|
767
|
+
stream.end();
|
|
768
|
+
yield new Promise(resolve => stream.once('close', resolve));
|
|
769
|
+
expect(stream.bytesWritten).toBe(3);
|
|
770
|
+
expect(mfs.__vol.toJSON()).toStrictEqual({
|
|
771
|
+
'/mountpoint/folder/file': 'ABCt',
|
|
772
|
+
'/mountpoint/empty-folder': null,
|
|
773
|
+
'/mountpoint/f.html': 'test',
|
|
774
|
+
});
|
|
775
|
+
}));
|
|
776
|
+
test('can use stream to add to existing file at specified offset', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
777
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
778
|
+
const stream = fs.createWriteStream('/folder/file', { flags: 'a', start: 1 });
|
|
779
|
+
stream.write(Buffer.from('A'));
|
|
780
|
+
stream.write(Buffer.from('B'));
|
|
781
|
+
stream.end();
|
|
782
|
+
yield new Promise(resolve => stream.once('close', resolve));
|
|
783
|
+
expect(stream.bytesWritten).toBe(2);
|
|
784
|
+
expect(mfs.__vol.toJSON()).toStrictEqual({
|
|
785
|
+
'/mountpoint/folder/file': 'tABt',
|
|
786
|
+
'/mountpoint/empty-folder': null,
|
|
787
|
+
'/mountpoint/f.html': 'test',
|
|
788
|
+
});
|
|
789
|
+
}));
|
|
790
|
+
test('throws if "start" option is not a number', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
791
|
+
const { fs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
792
|
+
try {
|
|
793
|
+
fs.createWriteStream('/folder/file', { flags: 'a', start: '1' });
|
|
794
|
+
throw new Error('should have thrown');
|
|
795
|
+
}
|
|
796
|
+
catch (error) {
|
|
797
|
+
expect(error).toBeInstanceOf(TypeError);
|
|
798
|
+
expect(error.message).toBe('"start" option must be a Number');
|
|
799
|
+
}
|
|
800
|
+
}));
|
|
801
|
+
test('throws if "start" option is negative', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
802
|
+
const { fs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
803
|
+
try {
|
|
804
|
+
fs.createWriteStream('/folder/file', { flags: 'a', start: -1 });
|
|
805
|
+
throw new Error('should have thrown');
|
|
806
|
+
}
|
|
807
|
+
catch (error) {
|
|
808
|
+
expect(error).toBeInstanceOf(TypeError);
|
|
809
|
+
expect(error.message).toBe('"start" must be >= zero');
|
|
810
|
+
}
|
|
811
|
+
}));
|
|
812
|
+
});
|
|
813
|
+
describe('.createReadStream()', () => {
|
|
814
|
+
test('can pipe fs.ReadStream to fs.WriteStream', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
815
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
816
|
+
const readStream = fs.createReadStream('/folder/file');
|
|
817
|
+
const writeStream = fs.createWriteStream('/folder/file2');
|
|
818
|
+
readStream.pipe(writeStream);
|
|
819
|
+
yield new Promise(resolve => writeStream.once('close', resolve));
|
|
820
|
+
expect(mfs.__vol.toJSON()).toStrictEqual({
|
|
821
|
+
'/mountpoint/folder/file': 'test',
|
|
822
|
+
'/mountpoint/folder/file2': 'test',
|
|
823
|
+
'/mountpoint/empty-folder': null,
|
|
824
|
+
'/mountpoint/f.html': 'test',
|
|
825
|
+
});
|
|
826
|
+
}));
|
|
827
|
+
test('emits "open" event', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
828
|
+
const { fs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
829
|
+
const readStream = fs.createReadStream('/folder/file');
|
|
830
|
+
const fd = yield new Promise(resolve => readStream.once('open', resolve));
|
|
831
|
+
expect(typeof fd).toBe('number');
|
|
832
|
+
}));
|
|
833
|
+
test('emits "ready" event', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
834
|
+
const { fs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
835
|
+
const readStream = fs.createReadStream('/folder/file');
|
|
836
|
+
yield new Promise(resolve => readStream.once('ready', resolve));
|
|
837
|
+
}));
|
|
838
|
+
test('emits "close" event', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
839
|
+
const { fs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
840
|
+
const readStream = fs.createReadStream('/folder/file', { emitClose: true });
|
|
841
|
+
const writeStream = fs.createWriteStream('/folder/file2');
|
|
842
|
+
readStream.pipe(writeStream);
|
|
843
|
+
yield new Promise(resolve => readStream.once('close', resolve));
|
|
844
|
+
}));
|
|
845
|
+
test('can write to already open file', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
846
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
847
|
+
const handle = yield fs.promises.open('/folder/file');
|
|
848
|
+
const readStream = fs.createReadStream('xyz', { fd: handle.fd });
|
|
849
|
+
const writeStream = fs.createWriteStream('/folder/file2');
|
|
850
|
+
readStream.pipe(writeStream);
|
|
851
|
+
yield new Promise(resolve => writeStream.once('close', resolve));
|
|
852
|
+
expect(mfs.__vol.toJSON()).toStrictEqual({
|
|
853
|
+
'/mountpoint/folder/file': 'test',
|
|
854
|
+
'/mountpoint/folder/file2': 'test',
|
|
855
|
+
'/mountpoint/empty-folder': null,
|
|
856
|
+
'/mountpoint/f.html': 'test',
|
|
857
|
+
});
|
|
858
|
+
}));
|
|
859
|
+
test('can read a specified slice of a file', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
860
|
+
const { fs, mfs } = setup({ folder: { file: 'test' }, 'empty-folder': null, 'f.html': 'test' });
|
|
861
|
+
const readStream = fs.createReadStream('/folder/file', { start: 1, end: 2 });
|
|
862
|
+
const writeStream = fs.createWriteStream('/folder/file2');
|
|
863
|
+
readStream.pipe(writeStream);
|
|
864
|
+
yield new Promise(resolve => writeStream.once('close', resolve));
|
|
865
|
+
expect(mfs.__vol.toJSON()).toStrictEqual({
|
|
866
|
+
'/mountpoint/folder/file': 'test',
|
|
867
|
+
'/mountpoint/folder/file2': 'es',
|
|
868
|
+
'/mountpoint/empty-folder': null,
|
|
869
|
+
'/mountpoint/f.html': 'test',
|
|
870
|
+
});
|
|
871
|
+
}));
|
|
872
|
+
});
|
|
873
|
+
});
|