@zenfs/core 2.6.3 → 2.6.5
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/README.md +1 -1
- package/dist/backends/cow.js +11 -3
- package/dist/internal/file_index.d.ts +2 -0
- package/dist/internal/file_index.js +10 -2
- package/dist/polyfills.js +4 -1
- package/package.json +11 -11
- package/scripts/test.js +15 -8
- package/tests/backend/single-buffer.test.ts +2 -2
- package/tests/backend/single-buffer.worker.js +1 -1
- package/tests/common/file_index.test.ts +51 -0
- package/tests/common/glob.test.ts +1 -1
- package/tests/common/inode.test.ts +1 -1
- package/tests/common/utf8stream.test.ts +1 -1
- package/tests/common.ts +4 -2
- package/tests/fetch/fetch.ts +1 -1
- package/tests/fetch/run.sh +1 -1
- package/tests/fs/append.test.ts +1 -1
- package/tests/fs/concurrency.test.ts +1 -1
- package/tests/fs/dir.test.ts +1 -1
- package/tests/fs/directory.test.ts +3 -3
- package/tests/fs/errors.test.ts +1 -1
- package/tests/fs/exists.test.ts +3 -3
- package/tests/fs/links.test.ts +5 -5
- package/tests/fs/open.test.ts +5 -5
- package/tests/fs/permissions.test.ts +5 -5
- package/tests/fs/read.test.ts +3 -3
- package/tests/fs/readFile.test.ts +2 -2
- package/tests/fs/rename.test.ts +5 -5
- package/tests/fs/scaling.test.ts +1 -1
- package/tests/fs/stat.test.ts +2 -2
- package/tests/fs/streams.test.ts +1 -1
- package/tests/fs/tempdir.test.ts +1 -1
- package/tests/fs/times.test.ts +2 -2
- package/tests/fs/truncate.test.ts +1 -1
- package/tests/fs/watch.test.ts +1 -1
- package/tests/fs/write.test.ts +2 -2
- package/tests/fs/xattr.test.ts +1 -1
- package/tests/{native/setup.ts → native-setup.ts} +5 -5
- package/tests/setup/context.ts +1 -1
- package/tests/setup/cow.ts +1 -1
- package/tests/setup/index.ts +1 -1
- package/tests/setup/memory.ts +1 -1
- package/tests/setup/port.ts +1 -1
- package/tests/setup/single-buffer.ts +1 -1
- package/tests/setup.ts +1 -1
- package/tests/tsconfig.json +2 -1
- package/tests/native/run.sh +0 -3
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
ZenFS is a cross-platform library that emulates the [Node.js filesystem API](http://nodejs.org/api/fs.html).
|
|
4
4
|
It works using a system of backends, which are used by ZenFS to store and retrieve data.
|
|
5
|
-
ZenFS
|
|
5
|
+
ZenFS should cover the full API surface of the latest Node.js version, though complex changes may lag a little bit.
|
|
6
6
|
|
|
7
7
|
## Backends
|
|
8
8
|
|
package/dist/backends/cow.js
CHANGED
|
@@ -116,11 +116,19 @@ export class CopyOnWriteFS extends FileSystem {
|
|
|
116
116
|
_nextIno = 1;
|
|
117
117
|
/** Moves the public inode numbers for a rename, including a directory's descendants */
|
|
118
118
|
renameInos(oldPath, newPath) {
|
|
119
|
-
|
|
119
|
+
const changes = [];
|
|
120
|
+
for (const [path, ino] of this.inos) {
|
|
120
121
|
if (path != oldPath && !path.startsWith(oldPath + '/'))
|
|
121
122
|
continue;
|
|
122
|
-
|
|
123
|
-
|
|
123
|
+
changes.push({
|
|
124
|
+
path,
|
|
125
|
+
add: newPath + path.slice(oldPath.length),
|
|
126
|
+
ino,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
for (const change of changes) {
|
|
130
|
+
this.inos.delete(change.path);
|
|
131
|
+
this.inos.set(change.add, change.ino);
|
|
124
132
|
}
|
|
125
133
|
}
|
|
126
134
|
/** Replaces the layer's inode number with the public one for `path` */
|
|
@@ -17,6 +17,7 @@ export declare const version = 1;
|
|
|
17
17
|
* @internal
|
|
18
18
|
*/
|
|
19
19
|
export declare class Index extends Map<string, Inode> {
|
|
20
|
+
#private;
|
|
20
21
|
maxSize: number;
|
|
21
22
|
/**
|
|
22
23
|
* Converts the index to JSON
|
|
@@ -26,6 +27,7 @@ export declare class Index extends Map<string, Inode> {
|
|
|
26
27
|
* Converts the index to a string
|
|
27
28
|
*/
|
|
28
29
|
toString(): string;
|
|
30
|
+
clear(): void;
|
|
29
31
|
/**
|
|
30
32
|
* Get the size in bytes of the index (including the size reported for each entry)
|
|
31
33
|
*/
|
|
@@ -21,7 +21,8 @@ export class Index extends Map {
|
|
|
21
21
|
return {
|
|
22
22
|
version,
|
|
23
23
|
maxSize: this.maxSize,
|
|
24
|
-
|
|
24
|
+
// @todo use `Iterator.map` #296
|
|
25
|
+
entries: Object.fromEntries(Array.from(this).map(([k, v]) => [k, v.toJSON()])),
|
|
25
26
|
};
|
|
26
27
|
}
|
|
27
28
|
/**
|
|
@@ -30,6 +31,10 @@ export class Index extends Map {
|
|
|
30
31
|
toString() {
|
|
31
32
|
return JSON.stringify(this.toJSON());
|
|
32
33
|
}
|
|
34
|
+
clear() {
|
|
35
|
+
super.clear();
|
|
36
|
+
this.#lastAlloc = 0;
|
|
37
|
+
}
|
|
33
38
|
/**
|
|
34
39
|
* Get the size in bytes of the index (including the size reported for each entry)
|
|
35
40
|
*/
|
|
@@ -74,12 +79,15 @@ export class Index extends Map {
|
|
|
74
79
|
}
|
|
75
80
|
return entries;
|
|
76
81
|
}
|
|
82
|
+
#lastAlloc = 0;
|
|
77
83
|
/**
|
|
78
84
|
* Get the next available ID in the index
|
|
79
85
|
* @internal
|
|
80
86
|
*/
|
|
81
87
|
_alloc() {
|
|
82
|
-
|
|
88
|
+
// @todo use `Iterator.flatMap` #296
|
|
89
|
+
this.#lastAlloc ||= Array.from(this.values()).reduce((max, inode) => Math.max(max, inode.ino, inode.data), 0);
|
|
90
|
+
return ++this.#lastAlloc;
|
|
83
91
|
}
|
|
84
92
|
/**
|
|
85
93
|
* Gets a list of entries for each directory in the index.
|
package/dist/polyfills.js
CHANGED
|
@@ -43,7 +43,10 @@ Uint8Array.fromBase64 ??=
|
|
|
43
43
|
Uint8Array.prototype.toHex ??=
|
|
44
44
|
(warn('Using a polyfill of Uint8Array.prototype.toHex'),
|
|
45
45
|
function toHex() {
|
|
46
|
-
|
|
46
|
+
// @todo use `Iterator.map` #296
|
|
47
|
+
return Array.from(this)
|
|
48
|
+
.map(b => b.toString(16).padStart(2, '0'))
|
|
49
|
+
.join('');
|
|
47
50
|
});
|
|
48
51
|
Uint8Array.fromHex ??=
|
|
49
52
|
(warn('Using a polyfill of Uint8Array.fromHex'),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zenfs/core",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.5",
|
|
4
4
|
"description": "A filesystem, anywhere",
|
|
5
5
|
"funding": {
|
|
6
6
|
"type": "individual",
|
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
"keywords": [
|
|
12
12
|
"filesystem",
|
|
13
13
|
"node",
|
|
14
|
-
"storage"
|
|
14
|
+
"storage",
|
|
15
|
+
"fs",
|
|
16
|
+
"browser"
|
|
15
17
|
],
|
|
16
18
|
"bin": {
|
|
17
19
|
"make-index": "scripts/make-index.js",
|
|
@@ -44,14 +46,15 @@
|
|
|
44
46
|
},
|
|
45
47
|
"exports": {
|
|
46
48
|
".": "./dist/index.js",
|
|
47
|
-
"
|
|
49
|
+
"./*.js": "./dist/*.js",
|
|
50
|
+
"./*": "./dist/*.js",
|
|
48
51
|
"./emulation/*": "./dist/node/*",
|
|
49
52
|
"./promises": "./dist/node/promises.js",
|
|
50
53
|
"./readline": "./dist/node/readline.js",
|
|
51
|
-
"./constants": "./dist/constants.js",
|
|
52
|
-
"./path": "./dist/path.js",
|
|
53
54
|
"./eslint": "./eslint.shared.js",
|
|
54
|
-
"./tests
|
|
55
|
+
"./tests/*.ts": "./tests/*.ts",
|
|
56
|
+
"./tests/*.js": "./tests/*.js",
|
|
57
|
+
"./tests/*": "./tests/*.js",
|
|
55
58
|
"./types/*": "./types/*"
|
|
56
59
|
},
|
|
57
60
|
"publishConfig": {
|
|
@@ -64,7 +67,8 @@
|
|
|
64
67
|
"spdx:check": "npx lice -a src tests/*.ts tests/**/*.test.ts",
|
|
65
68
|
"spdx:fix": "npx lice -aw src tests/*.ts tests/**/*.test.ts",
|
|
66
69
|
"lint": "eslint src tests",
|
|
67
|
-
"test": "npx
|
|
70
|
+
"test": "npx -s zenfs-test --clean; npx -s zenfs-test -abcpn; tests/fetch/run.sh; npx -s zenfs-test --report-only",
|
|
71
|
+
"test:native": "npx -s zenfs-test tests/native-setup.ts --verbose",
|
|
68
72
|
"build": "tsc -p tsconfig.json",
|
|
69
73
|
"build:docs": "typedoc",
|
|
70
74
|
"dev": "tsc -p tsconfig.json --watch",
|
|
@@ -86,12 +90,8 @@
|
|
|
86
90
|
"eslint": "^10.1.0",
|
|
87
91
|
"globals": "^17.3.0",
|
|
88
92
|
"prettier": "^3.2.5",
|
|
89
|
-
"tsx": "^4.19.1",
|
|
90
93
|
"typedoc": "^0.28.18",
|
|
91
94
|
"typescript": "^6.0.0",
|
|
92
95
|
"typescript-eslint": "^8.58.0"
|
|
93
|
-
},
|
|
94
|
-
"allowScripts": {
|
|
95
|
-
"esbuild": true
|
|
96
96
|
}
|
|
97
97
|
}
|
package/scripts/test.js
CHANGED
|
@@ -26,11 +26,14 @@ const { values: options, positionals } = parseArgs({
|
|
|
26
26
|
skip: { short: 's', type: 'string', multiple: true, default: [] },
|
|
27
27
|
'exit-on-fail': { short: 'e', type: 'boolean' },
|
|
28
28
|
runs: { short: 'r', type: 'string', default: '1' },
|
|
29
|
+
// @todo [breaking] make using node the default and remove tsx completely
|
|
30
|
+
node: { short: 'n', type: 'boolean', default: false },
|
|
29
31
|
|
|
30
32
|
// Coverage and performance
|
|
31
33
|
coverage: { type: 'string', default: 'tests/.coverage' },
|
|
32
34
|
preserve: { short: 'p', type: 'boolean' },
|
|
33
35
|
report: { type: 'boolean', default: false },
|
|
36
|
+
'report-only': { type: 'boolean', default: false },
|
|
34
37
|
clean: { type: 'boolean', default: false },
|
|
35
38
|
profile: { type: 'boolean', default: false },
|
|
36
39
|
},
|
|
@@ -42,7 +45,8 @@ const { values: options, positionals } = parseArgs({
|
|
|
42
45
|
* @param {...any} args
|
|
43
46
|
*/
|
|
44
47
|
function debug(...args) {
|
|
45
|
-
if (options.debug
|
|
48
|
+
if (options.debug || process.env.DEBUG)
|
|
49
|
+
console.debug(styleText('dim', '[debug]'), ...args.map(a => (typeof a === 'string' ? styleText('dim', a) : a)));
|
|
46
50
|
}
|
|
47
51
|
|
|
48
52
|
if (options.help) {
|
|
@@ -61,6 +65,7 @@ Behavior:
|
|
|
61
65
|
-I, --inspect Use the inspector for debugging
|
|
62
66
|
-s, --skip <pattern> Skip tests with names matching the given pattern. Can be specified multiple times.
|
|
63
67
|
-d, --debug Output debug messages from the test runner
|
|
68
|
+
-n, --node Use plain node instead of tsx. Requires use of erasable TS syntax only
|
|
64
69
|
|
|
65
70
|
Output:
|
|
66
71
|
-h, --help Outputs this help message
|
|
@@ -74,9 +79,10 @@ Output:
|
|
|
74
79
|
Coverage:
|
|
75
80
|
--coverage <dir> Override the default coverage data directory
|
|
76
81
|
-p, --preserve Do not delete or report coverage data
|
|
77
|
-
--report
|
|
82
|
+
--report Report coverage along with test results
|
|
83
|
+
--report-only ONLY report coverage
|
|
78
84
|
--clean ONLY clean up coverage directory
|
|
79
|
-
|
|
85
|
+
--profile Record performance profiles`);
|
|
80
86
|
process.exit();
|
|
81
87
|
}
|
|
82
88
|
|
|
@@ -105,12 +111,13 @@ function report() {
|
|
|
105
111
|
}
|
|
106
112
|
}
|
|
107
113
|
|
|
108
|
-
if (options
|
|
114
|
+
if (options['report-only']) {
|
|
109
115
|
report();
|
|
110
116
|
process.exit();
|
|
111
117
|
}
|
|
112
118
|
|
|
113
|
-
const nRuns = Number.isSafeInteger(parseInt(options.runs)) ? parseInt(options.runs) : 1
|
|
119
|
+
const nRuns = Number.isSafeInteger(parseInt(options.runs)) ? parseInt(options.runs) : 1,
|
|
120
|
+
nodeCommand = options.node ? 'node' : 'tsx';
|
|
114
121
|
|
|
115
122
|
/** @type {typeof import('./ci.js')} */
|
|
116
123
|
let ci;
|
|
@@ -175,7 +182,7 @@ function makeCommand(profileName, ...rest) {
|
|
|
175
182
|
]
|
|
176
183
|
.filter(v => v)
|
|
177
184
|
.filter(v => typeof v == 'string');
|
|
178
|
-
if (!options.quiet) debug('command:
|
|
185
|
+
if (!options.quiet) debug('command: ' + nodeCommand, command.join(' '));
|
|
179
186
|
|
|
180
187
|
return command;
|
|
181
188
|
}
|
|
@@ -235,7 +242,7 @@ async function runTests(config) {
|
|
|
235
242
|
}
|
|
236
243
|
|
|
237
244
|
try {
|
|
238
|
-
execFileSync(
|
|
245
|
+
execFileSync(nodeCommand, command, {
|
|
239
246
|
stdio: ['ignore', options.verbose ? 'inherit' : 'ignore', 'inherit'],
|
|
240
247
|
});
|
|
241
248
|
if (!options.quiet) console.log(`${styleText('green', 'passed')}${identText} ${time()}`);
|
|
@@ -283,4 +290,4 @@ for (const setupFile of positionals) {
|
|
|
283
290
|
});
|
|
284
291
|
}
|
|
285
292
|
|
|
286
|
-
if (!options.preserve) report();
|
|
293
|
+
if (!options.preserve && options.report) report();
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
2
|
-
import assert from 'node:assert';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
3
|
import { randomBytes } from 'node:crypto';
|
|
4
4
|
import { suite, test } from 'node:test';
|
|
5
5
|
import { Worker } from 'worker_threads';
|
|
6
6
|
import { sizeof } from 'memium';
|
|
7
7
|
import { fs, mount, resolveMountConfig, SingleBuffer, vfs } from '@zenfs/core';
|
|
8
|
-
import { MetadataBlock, SuperBlock } from '@zenfs/core/backends/single_buffer
|
|
8
|
+
import { MetadataBlock, SuperBlock } from '@zenfs/core/backends/single_buffer';
|
|
9
9
|
import { setupLogs } from '../logs.js';
|
|
10
10
|
|
|
11
11
|
setupLogs();
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
2
|
+
import { Index, Inode } from '@zenfs/core';
|
|
3
|
+
import assert from 'node:assert/strict';
|
|
4
|
+
import { suite, test } from 'node:test';
|
|
5
|
+
|
|
6
|
+
/** Build an index with `n` file entries, using IDs 2..2n+1 */
|
|
7
|
+
function buildIndex(n: number): Index {
|
|
8
|
+
const index = new Index();
|
|
9
|
+
index.set('/', new Inode({ ino: 0, data: 1, mode: 0o40755, nlink: 1 }));
|
|
10
|
+
for (let i = 0; i < n; i++) {
|
|
11
|
+
index.set(`/f${i}`, new Inode({ ino: 2 * i + 2, data: 2 * i + 3, mode: 0o100644, nlink: 1 }));
|
|
12
|
+
}
|
|
13
|
+
return index;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Calls `fn` with `depth` extra frames on the stack */
|
|
17
|
+
function atDepth<T>(depth: number, fn: () => T): T {
|
|
18
|
+
return depth > 0 ? atDepth(depth - 1, fn) : fn();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
suite('Index', () => {
|
|
22
|
+
test('_alloc returns an unused ID', () => {
|
|
23
|
+
const index = buildIndex(10);
|
|
24
|
+
assert.equal(index._alloc(), 22);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test('_alloc does not re-use IDs', () => {
|
|
28
|
+
const index = buildIndex(10);
|
|
29
|
+
const ids = new Set<number>();
|
|
30
|
+
|
|
31
|
+
for (let i = 0; i < 100; i++) {
|
|
32
|
+
const id = index._alloc();
|
|
33
|
+
assert.equal(index.getByID(id), undefined, `\`_alloc\` returned in-use ID ${id}`);
|
|
34
|
+
assert(!ids.has(id), `\`_alloc\` returned duplicate ID ${id}`);
|
|
35
|
+
ids.add(id);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('_alloc works with a large index #312', () => {
|
|
40
|
+
const index = buildIndex(100_000);
|
|
41
|
+
assert.equal(index._alloc(), 200_002);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('_alloc works with a large index and a deep stack #312', () => {
|
|
45
|
+
const index = buildIndex(60_000);
|
|
46
|
+
assert.equal(
|
|
47
|
+
atDepth(1000, () => index._alloc()),
|
|
48
|
+
120_002
|
|
49
|
+
);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
3
|
import { suite, test } from 'node:test';
|
|
4
|
-
import { fs } from '../common.
|
|
4
|
+
import { fs } from '../common.ts';
|
|
5
5
|
|
|
6
6
|
// Set up a directory structure for glob tests
|
|
7
7
|
fs.mkdirSync('/glob');
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { Buffer } from 'buffer';
|
|
3
3
|
import assert from 'node:assert/strict';
|
|
4
4
|
import { suite, test } from 'node:test';
|
|
5
|
-
import { config, fs } from '../common.
|
|
5
|
+
import { config, fs } from '../common.ts';
|
|
6
6
|
|
|
7
7
|
suite('Utf8Stream', config('write'), () => {
|
|
8
8
|
test('writes synchronously', config('sync'), () => {
|
package/tests/common.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
2
2
|
import { fs as defaultFS } from '@zenfs/core';
|
|
3
|
-
import type { NodeFS } from '@zenfs/core/node/types
|
|
3
|
+
import type { NodeFS } from '@zenfs/core/node/types';
|
|
4
4
|
import { join, resolve } from 'node:path';
|
|
5
5
|
import { styleText } from 'node:util';
|
|
6
6
|
import { setupLogs } from './logs.js';
|
|
@@ -41,7 +41,9 @@ export type TestFlag =
|
|
|
41
41
|
| 'xattr'
|
|
42
42
|
| 'times'
|
|
43
43
|
| 'tempdir'
|
|
44
|
-
| 'lchmod'
|
|
44
|
+
| 'lchmod'
|
|
45
|
+
| 'promises.exists'
|
|
46
|
+
| 'root';
|
|
45
47
|
|
|
46
48
|
/**
|
|
47
49
|
* Whether a backend supports a flag.
|
package/tests/fetch/fetch.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { configure, Fetch } from '@zenfs/core';
|
|
2
2
|
import { log } from 'kerium';
|
|
3
|
-
import type { TestFlag, TestFlagState } from '../common.
|
|
3
|
+
import type { TestFlag, TestFlagState } from '../common.ts';
|
|
4
4
|
import { baseUrl } from './config.js';
|
|
5
5
|
|
|
6
6
|
await configure({
|
package/tests/fetch/run.sh
CHANGED
package/tests/fs/append.test.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
3
|
import { suite, test } from 'node:test';
|
|
4
|
-
import { fs, config } from '../common.
|
|
4
|
+
import { fs, config } from '../common.ts';
|
|
5
5
|
|
|
6
6
|
const content = 'Sample content',
|
|
7
7
|
original = 'ABCD';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
3
|
import { suite, test } from 'node:test';
|
|
4
|
-
import { config, fs } from '../common.
|
|
4
|
+
import { config, fs } from '../common.ts';
|
|
5
5
|
|
|
6
6
|
suite('Concurrency', config('write', 'async'), () => {
|
|
7
7
|
test('parallel writeFile in the same directory does not lose entries #256', async () => {
|
package/tests/fs/dir.test.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { sync, type Dirent } from '@zenfs/core';
|
|
3
3
|
import assert, { rejects } from 'node:assert/strict';
|
|
4
4
|
import { suite, test } from 'node:test';
|
|
5
|
-
import { config, fs } from '../common.
|
|
5
|
+
import { config, fs } from '../common.ts';
|
|
6
6
|
|
|
7
7
|
const testFile = 'test-file.txt';
|
|
8
8
|
fs.writeFileSync(testFile, 'Sample content');
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
3
|
import { join } from 'node:path/posix';
|
|
4
4
|
import { suite, test } from 'node:test';
|
|
5
|
-
import { config, fs } from '../common.
|
|
5
|
+
import { config, fs } from '../common.ts';
|
|
6
6
|
|
|
7
7
|
const testDir = 'test-dir';
|
|
8
8
|
const testFiles = ['file1.txt', 'file2.txt', 'file3.txt'];
|
|
@@ -22,7 +22,7 @@ for (const dir of testDirectories) {
|
|
|
22
22
|
suite('Directories', config('directories'), () => {
|
|
23
23
|
test('mkdir', config('async'), async () => {
|
|
24
24
|
await fs.promises.mkdir('/one', 0o755);
|
|
25
|
-
assert(await fs.promises.
|
|
25
|
+
assert(await fs.promises.stat('/one', { throwIfNoEntry: false }));
|
|
26
26
|
await assert.rejects(fs.promises.mkdir('/one', 0o755), { code: 'EEXIST' });
|
|
27
27
|
});
|
|
28
28
|
|
|
@@ -30,7 +30,7 @@ suite('Directories', config('directories'), () => {
|
|
|
30
30
|
|
|
31
31
|
test('mkdir, nested', config('async'), async () => {
|
|
32
32
|
await assert.rejects(fs.promises.mkdir('/nested/dir'), { code: 'ENOENT', path: '/nested/dir' });
|
|
33
|
-
assert(!(await fs.promises.
|
|
33
|
+
assert(!(await fs.promises.stat('/nested/dir', { throwIfNoEntry: false })));
|
|
34
34
|
});
|
|
35
35
|
|
|
36
36
|
test('mkdir, recursive', config('async'), async () => {
|
package/tests/fs/errors.test.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
3
|
import test, { suite } from 'node:test';
|
|
4
|
-
import { config, fs } from '../common.
|
|
4
|
+
import { config, fs } from '../common.ts';
|
|
5
5
|
|
|
6
6
|
const existingFile = '/exit.js';
|
|
7
7
|
const path = '/non-existent';
|
package/tests/fs/exists.test.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
3
|
import { suite, test } from 'node:test';
|
|
4
|
-
import { config, fs } from '../common.
|
|
4
|
+
import { config, fs } from '../common.ts';
|
|
5
5
|
|
|
6
6
|
suite('exists', () => {
|
|
7
7
|
const f = 'x.txt';
|
|
8
8
|
|
|
9
|
-
test('return true for an existing file', config('async'), async () => {
|
|
9
|
+
test('return true for an existing file', config('async', 'promises.exists'), async () => {
|
|
10
10
|
const exists = await fs.promises.exists(f);
|
|
11
11
|
assert(exists);
|
|
12
12
|
});
|
|
13
13
|
|
|
14
|
-
test('return false for a non-existent file', config('async'), async () => {
|
|
14
|
+
test('return false for a non-existent file', config('async', 'promises.exists'), async () => {
|
|
15
15
|
const exists = await fs.promises.exists(f + '-NO');
|
|
16
16
|
assert(!exists);
|
|
17
17
|
});
|
package/tests/fs/links.test.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { join } from '@zenfs/core/path';
|
|
3
3
|
import assert from 'node:assert/strict';
|
|
4
4
|
import { suite, test } from 'node:test';
|
|
5
|
-
import { config, fs } from '../common.
|
|
5
|
+
import { config, fs } from '../common.ts';
|
|
6
6
|
|
|
7
7
|
suite('Links', config('symlinks'), () => {
|
|
8
8
|
const target = '/a1.js',
|
|
@@ -64,8 +64,8 @@ suite('Links', config('symlinks'), () => {
|
|
|
64
64
|
|
|
65
65
|
test('unlink', async () => {
|
|
66
66
|
await fs.promises.unlink(symlink);
|
|
67
|
-
assert(!(await fs.promises.
|
|
68
|
-
assert(await fs.promises.
|
|
67
|
+
assert(!(await fs.promises.stat(symlink, { throwIfNoEntry: false })));
|
|
68
|
+
assert(await fs.promises.stat(target, { throwIfNoEntry: false }));
|
|
69
69
|
});
|
|
70
70
|
|
|
71
71
|
test('link', config('links'), async () => {
|
|
@@ -99,7 +99,7 @@ suite('Links', config('symlinks'), () => {
|
|
|
99
99
|
// A link pointing at a directory satisfies a recursive mkdir and is left as a link
|
|
100
100
|
assert.equal(await fs.promises.mkdir('/mkdir-link', { recursive: true }), undefined);
|
|
101
101
|
assert((await fs.promises.lstat('/mkdir-link')).isSymbolicLink());
|
|
102
|
-
assert(!(await fs.promises.
|
|
102
|
+
assert(!(await fs.promises.stat('/mkdir-missing', { throwIfNoEntry: false })));
|
|
103
103
|
});
|
|
104
104
|
|
|
105
105
|
test('mkdir follows symlinks for intermediate components', config('async'), async () => {
|
|
@@ -113,7 +113,7 @@ suite('Links', config('symlinks'), () => {
|
|
|
113
113
|
|
|
114
114
|
// Node reports the link itself here, unlike `mkdirSync` which reports the requested path with ENOENT
|
|
115
115
|
await assert.rejects(fs.promises.mkdir('/mkdir-dangling/x', { recursive: true }), { code: 'ENOTDIR', path: '/mkdir-dangling' });
|
|
116
|
-
assert(!(await fs.promises.
|
|
116
|
+
assert(!(await fs.promises.stat('/mkdir-missing', { throwIfNoEntry: false })));
|
|
117
117
|
});
|
|
118
118
|
|
|
119
119
|
test('mkdirSync does not follow a symlink at the final component', config('sync'), () => {
|
package/tests/fs/open.test.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
3
|
import { suite, test } from 'node:test';
|
|
4
|
-
import { config, fs } from '../common.
|
|
4
|
+
import { config, fs } from '../common.ts';
|
|
5
5
|
|
|
6
6
|
suite('Opening files', () => {
|
|
7
7
|
const filename = 'a.js';
|
|
@@ -12,12 +12,12 @@ suite('Opening files', () => {
|
|
|
12
12
|
});
|
|
13
13
|
|
|
14
14
|
test('open file with mode "r"', config('async'), async () => {
|
|
15
|
-
|
|
16
|
-
assert(fd >= -Infinity);
|
|
15
|
+
await using handle = await fs.promises.open(filename, 'r');
|
|
16
|
+
assert(handle.fd >= -Infinity);
|
|
17
17
|
});
|
|
18
18
|
|
|
19
19
|
test('open file with mode "rs"', config('async'), async () => {
|
|
20
|
-
|
|
21
|
-
assert(fd >= -Infinity);
|
|
20
|
+
await using handle = await fs.promises.open(filename, 'rs');
|
|
21
|
+
assert(handle.fd >= -Infinity);
|
|
22
22
|
});
|
|
23
23
|
});
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
2
2
|
import { R_OK, W_OK, X_OK } from '@zenfs/core/constants';
|
|
3
|
-
import { defaultContext } from '@zenfs/core/internal/contexts
|
|
4
|
-
import { hasAccess } from '@zenfs/core/internal/inode
|
|
3
|
+
import { defaultContext } from '@zenfs/core/internal/contexts';
|
|
4
|
+
import { hasAccess } from '@zenfs/core/internal/inode';
|
|
5
5
|
import { join } from '@zenfs/core/path';
|
|
6
6
|
import type { Exception } from 'kerium';
|
|
7
7
|
import assert from 'node:assert/strict';
|
|
8
8
|
import { suite, test } from 'node:test';
|
|
9
9
|
import { encodeUTF8 } from 'utilium';
|
|
10
|
-
import { config, fs } from '../common.
|
|
10
|
+
import { config, fs } from '../common.ts';
|
|
11
11
|
|
|
12
12
|
const asyncMode = 0o777;
|
|
13
13
|
const syncMode = 0o644;
|
|
@@ -25,7 +25,7 @@ suite('Permissions', config('permissions'), () => {
|
|
|
25
25
|
});
|
|
26
26
|
|
|
27
27
|
test('fchmod', config('sync', 'async'), async () => {
|
|
28
|
-
|
|
28
|
+
await using handle = await fs.promises.open(file, 'a', 0o644);
|
|
29
29
|
|
|
30
30
|
await handle.chmod(asyncMode);
|
|
31
31
|
const stats = await handle.stat();
|
|
@@ -58,7 +58,7 @@ suite('Permissions', config('permissions'), () => {
|
|
|
58
58
|
|
|
59
59
|
function checkError(access: number) {
|
|
60
60
|
return function (error: Exception) {
|
|
61
|
-
assert(error
|
|
61
|
+
assert(Error.isError(error));
|
|
62
62
|
assert(!hasAccess(defaultContext, stats!, access));
|
|
63
63
|
};
|
|
64
64
|
}
|
package/tests/fs/read.test.ts
CHANGED
|
@@ -5,7 +5,7 @@ import assert from 'node:assert/strict';
|
|
|
5
5
|
import type { OpenMode, PathLike } from 'node:fs';
|
|
6
6
|
import { suite, test } from 'node:test';
|
|
7
7
|
import { promisify } from 'node:util';
|
|
8
|
-
import { config, fs } from '../common.
|
|
8
|
+
import { config, fs } from '../common.ts';
|
|
9
9
|
|
|
10
10
|
const filepath = 'x.txt';
|
|
11
11
|
const expected = 'xyz\n';
|
|
@@ -13,7 +13,7 @@ const ellipses = '…'.repeat(10_000);
|
|
|
13
13
|
|
|
14
14
|
suite('read', () => {
|
|
15
15
|
test('read file asynchronously', config('async'), async () => {
|
|
16
|
-
|
|
16
|
+
await using handle = await fs.promises.open(filepath, 'r');
|
|
17
17
|
const { bytesRead, buffer } = await handle.read(Buffer.alloc(expected.length), 0, expected.length, 0);
|
|
18
18
|
assert.equal(bytesRead, expected.length);
|
|
19
19
|
assert.equal(buffer.toString(), expected);
|
|
@@ -46,7 +46,7 @@ suite('read', () => {
|
|
|
46
46
|
const bufferSync = Buffer.alloc(expected.length);
|
|
47
47
|
|
|
48
48
|
test('read file from handle asynchronously', config('async'), async () => {
|
|
49
|
-
|
|
49
|
+
await using handle = await fs.promises.open(filepath, 'r');
|
|
50
50
|
const { bytesRead } = await handle.read(bufferAsync, 0, expected.length, 0);
|
|
51
51
|
|
|
52
52
|
assert.equal(bytesRead, expected.length);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
3
|
import { suite, test } from 'node:test';
|
|
4
|
-
import { config, fs } from '../common.
|
|
4
|
+
import { config, fs } from '../common.ts';
|
|
5
5
|
|
|
6
6
|
suite('Reading', () => {
|
|
7
7
|
test('Cannot read a file with an invalid encoding', config('sync'), () => {
|
|
@@ -9,7 +9,7 @@ suite('Reading', () => {
|
|
|
9
9
|
});
|
|
10
10
|
|
|
11
11
|
test('Reading past the end of a file should not be an error', config('async'), async () => {
|
|
12
|
-
|
|
12
|
+
await using handle = await fs.promises.open('a.js', 'r');
|
|
13
13
|
const { bytesRead } = await handle.read(new Uint8Array(10), 0, 10, 10000);
|
|
14
14
|
assert.equal(bytesRead, 0);
|
|
15
15
|
});
|
package/tests/fs/rename.test.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
3
|
import { suite, test } from 'node:test';
|
|
4
|
-
import { config, fs } from '../common.
|
|
4
|
+
import { config, fs } from '../common.ts';
|
|
5
5
|
|
|
6
6
|
suite('Rename', config('rename'), () => {
|
|
7
7
|
/**
|
|
@@ -26,8 +26,8 @@ suite('Rename', config('rename'), () => {
|
|
|
26
26
|
const subContents = await fs.promises.readdir(dir + '/_rename_me');
|
|
27
27
|
assert.equal(subContents.length, 1);
|
|
28
28
|
|
|
29
|
-
assert(await fs.promises.
|
|
30
|
-
assert(await fs.promises.
|
|
29
|
+
assert(await fs.promises.stat(dir + '/file.dat', { throwIfNoEntry: false }));
|
|
30
|
+
assert(await fs.promises.stat(dir + '/_rename_me/lol.txt', { throwIfNoEntry: false }));
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
test('rename directory', config('async'), async () => {
|
|
@@ -46,7 +46,7 @@ suite('Rename', config('rename'), () => {
|
|
|
46
46
|
|
|
47
47
|
await check_directory(newDir);
|
|
48
48
|
|
|
49
|
-
assert(!(await fs.promises.
|
|
49
|
+
assert(!(await fs.promises.stat(oldDir, { throwIfNoEntry: false })));
|
|
50
50
|
|
|
51
51
|
await fs.promises.mkdir(oldDir);
|
|
52
52
|
await populate(oldDir);
|
|
@@ -67,7 +67,7 @@ suite('Rename', config('rename'), () => {
|
|
|
67
67
|
await fs.promises.rename(one, two);
|
|
68
68
|
|
|
69
69
|
assert.equal(await fs.promises.readFile(two, 'utf8'), 'hey');
|
|
70
|
-
assert(!(await fs.promises.
|
|
70
|
+
assert(!(await fs.promises.stat(one, { throwIfNoEntry: false })));
|
|
71
71
|
});
|
|
72
72
|
|
|
73
73
|
test('File to Directory and Directory to File Rename', config('sync', 'async'), async () => {
|
package/tests/fs/scaling.test.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { sync } from '@zenfs/core';
|
|
3
3
|
import assert from 'node:assert/strict';
|
|
4
4
|
import { suite, test } from 'node:test';
|
|
5
|
-
import { config, fs } from '../common.
|
|
5
|
+
import { config, fs } from '../common.ts';
|
|
6
6
|
|
|
7
7
|
const n_files = 130;
|
|
8
8
|
const huge_size = 0x1000000;
|
package/tests/fs/stat.test.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { defaultContext, hasAccess, type Stats } from '@zenfs/core';
|
|
3
3
|
import assert from 'node:assert/strict';
|
|
4
4
|
import { suite, test } from 'node:test';
|
|
5
|
-
import { config, fs } from '../common.
|
|
5
|
+
import { config, fs } from '../common.ts';
|
|
6
6
|
|
|
7
7
|
suite('Stats', () => {
|
|
8
8
|
const existing_file = 'x.txt';
|
|
@@ -35,7 +35,7 @@ suite('Stats', () => {
|
|
|
35
35
|
fs.close(fd);
|
|
36
36
|
});
|
|
37
37
|
|
|
38
|
-
test('hasAccess for non-root access', config('sync', 'permissions'), () => {
|
|
38
|
+
test('hasAccess for non-root access', config('sync', 'permissions', 'root'), () => {
|
|
39
39
|
const newFile = 'new.txt';
|
|
40
40
|
|
|
41
41
|
fs.writeFileSync(newFile, 'hello', { mode: 0o640 });
|
package/tests/fs/streams.test.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
3
|
import { suite, test } from 'node:test';
|
|
4
|
-
import { config, fs } from '../common.
|
|
4
|
+
import { config, fs } from '../common.ts';
|
|
5
5
|
|
|
6
6
|
// Top-level initialization
|
|
7
7
|
const testFilePath = 'test-file.txt';
|
package/tests/fs/tempdir.test.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
2
2
|
import { test, suite } from 'node:test';
|
|
3
|
-
import { config, fs } from '../common.
|
|
3
|
+
import { config, fs } from '../common.ts';
|
|
4
4
|
import assert from 'node:assert/strict';
|
|
5
5
|
import { basename } from 'node:path/posix';
|
|
6
6
|
|
package/tests/fs/times.test.ts
CHANGED
|
@@ -4,7 +4,7 @@ import type { Exception } from 'kerium';
|
|
|
4
4
|
import assert from 'node:assert/strict';
|
|
5
5
|
import { suite, test } from 'node:test';
|
|
6
6
|
import { wait } from 'utilium';
|
|
7
|
-
import { config, fs } from '../common.
|
|
7
|
+
import { config, fs } from '../common.ts';
|
|
8
8
|
|
|
9
9
|
const path = 'x.txt';
|
|
10
10
|
|
|
@@ -33,7 +33,7 @@ suite('Times', config('times'), () => {
|
|
|
33
33
|
assert.deepEqual(unixTimestamps(await fs.promises.stat(path)), times);
|
|
34
34
|
|
|
35
35
|
await fs.promises.utimes('foobarbaz', atime, mtime).catch((error: Exception) => {
|
|
36
|
-
assert(error
|
|
36
|
+
assert(Error.isError(error));
|
|
37
37
|
assert.equal(error.code, 'ENOENT');
|
|
38
38
|
});
|
|
39
39
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
3
|
import { suite, test } from 'node:test';
|
|
4
|
-
import { config, fs } from '../common.
|
|
4
|
+
import { config, fs } from '../common.ts';
|
|
5
5
|
|
|
6
6
|
const path: string = 'truncate-file.txt',
|
|
7
7
|
size = 1024 * 16,
|
package/tests/fs/watch.test.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import type { Stats } from '@zenfs/core';
|
|
3
3
|
import assert from 'node:assert/strict';
|
|
4
4
|
import { suite, test } from 'node:test';
|
|
5
|
-
import { config, fs } from '../common.
|
|
5
|
+
import { config, fs } from '../common.ts';
|
|
6
6
|
|
|
7
7
|
const testDir = '/test-watch-dir';
|
|
8
8
|
const testFile = testDir + '/test.txt';
|
package/tests/fs/write.test.ts
CHANGED
|
@@ -3,8 +3,8 @@ import assert from 'node:assert/strict';
|
|
|
3
3
|
import { readFileSync } from 'node:fs';
|
|
4
4
|
import { join } from 'node:path/posix';
|
|
5
5
|
import { suite, test } from 'node:test';
|
|
6
|
-
import { config, fs } from '../common.
|
|
7
|
-
import { data as dataPath } from '../setup.
|
|
6
|
+
import { config, fs } from '../common.ts';
|
|
7
|
+
import { data as dataPath } from '../setup.ts';
|
|
8
8
|
|
|
9
9
|
const fileName = 'write.txt';
|
|
10
10
|
const utf8example = readFileSync(join(dataPath, 'utf8.txt'), 'utf8');
|
package/tests/fs/xattr.test.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { Buffer } from 'buffer';
|
|
3
3
|
import assert from 'node:assert/strict';
|
|
4
4
|
import { suite, test } from 'node:test';
|
|
5
|
-
import { config, fs } from '../common.
|
|
5
|
+
import { config, fs } from '../common.ts';
|
|
6
6
|
|
|
7
7
|
suite('Extended Attributes', config('xattr'), () => {
|
|
8
8
|
const testFile = 'xattr-test.txt';
|
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
/* Run the FS test suite against native node:fs.
|
|
3
3
|
Since the tests use absolute paths, everything is contained to a scratch directory using chroot-style path mapping. */
|
|
4
4
|
import * as native from 'node:fs';
|
|
5
|
-
import type { TestFlag, TestFlagState } from '
|
|
5
|
+
import type { TestFlag, TestFlagState } from './common.ts';
|
|
6
6
|
import { isAbsolute, join, relative, resolve } from 'node:path';
|
|
7
7
|
import { fileURLToPath } from 'node:url';
|
|
8
|
-
import { copySync, data, tmp } from '
|
|
8
|
+
import { copySync, data, tmp } from './setup.ts';
|
|
9
9
|
import { styleText } from 'node:util';
|
|
10
|
+
import { isRoot } from 'utilium/node';
|
|
10
11
|
|
|
11
12
|
// The tests assume modes are used as-is, but native fs applies the process umask
|
|
12
13
|
process.umask(0);
|
|
@@ -205,9 +206,6 @@ for (const [key, value] of Object.entries(native.promises)) {
|
|
|
205
206
|
promises.watch = (...args: Parameters<typeof native.promises.watch>) =>
|
|
206
207
|
native.promises.watch(...(mapArgs('watch', args) as Parameters<typeof native.promises.watch>));
|
|
207
208
|
|
|
208
|
-
// ZenFS API extension
|
|
209
|
-
promises.exists = (path: PathLike) => Promise.resolve(native.existsSync(toNative(path)));
|
|
210
|
-
|
|
211
209
|
wrapped.promises = promises;
|
|
212
210
|
|
|
213
211
|
export const fs = wrapped as unknown as typeof native;
|
|
@@ -220,6 +218,8 @@ export const flags: Partial<Record<TestFlag, TestFlagState>> = {
|
|
|
220
218
|
lchmod: process.platform == 'darwin',
|
|
221
219
|
// The suite uses ZenFS' own extended attribute API, which `node:fs` does not have
|
|
222
220
|
xattr: false,
|
|
221
|
+
'promises.exists': false,
|
|
222
|
+
root: isRoot || 'skip',
|
|
223
223
|
};
|
|
224
224
|
|
|
225
225
|
copySync(data, fs);
|
package/tests/setup/context.ts
CHANGED
package/tests/setup/cow.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { configureSingle, CopyOnWrite, fs, InMemory, resolveMountConfig } from '@zenfs/core';
|
|
2
|
-
import { copySync, data } from '../setup.
|
|
2
|
+
import { copySync, data } from '../setup.ts';
|
|
3
3
|
|
|
4
4
|
fs.umount('/');
|
|
5
5
|
const readable = await resolveMountConfig({ backend: InMemory, label: 'ro' });
|
package/tests/setup/index.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { readFileSync } from 'node:fs';
|
|
|
2
2
|
import { join } from 'node:path/posix';
|
|
3
3
|
import { configureSingle, CopyOnWrite, InMemory, InMemoryStore, mounts, Readonly, StoreFS } from '@zenfs/core';
|
|
4
4
|
import { S_IFDIR } from '@zenfs/core/constants';
|
|
5
|
-
import { copySync, data } from '../setup.
|
|
5
|
+
import { copySync, data } from '../setup.ts';
|
|
6
6
|
|
|
7
7
|
copySync(data);
|
|
8
8
|
|
package/tests/setup/memory.ts
CHANGED
package/tests/setup/port.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { InMemory, Port, configureSingle, fs, resolveMountConfig, resolveRemoteMount, sync } from '@zenfs/core';
|
|
2
2
|
import { after, afterEach } from 'node:test';
|
|
3
3
|
import { MessageChannel } from 'node:worker_threads';
|
|
4
|
-
import { copySync, data } from '../setup.
|
|
4
|
+
import { copySync, data } from '../setup.ts';
|
|
5
5
|
|
|
6
6
|
const { port1: localPort, port2: remotePort } = new MessageChannel();
|
|
7
7
|
|
package/tests/setup.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
2
2
|
import { fs as _fs } from '@zenfs/core';
|
|
3
|
+
import type { NodeFS } from '@zenfs/core/node/types';
|
|
3
4
|
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync } from 'node:fs';
|
|
4
5
|
import { join, relative } from 'node:path';
|
|
5
|
-
import type { NodeFS } from '@zenfs/core/node/types.js';
|
|
6
6
|
|
|
7
7
|
export const data = join(import.meta.dirname, 'data');
|
|
8
8
|
|
package/tests/tsconfig.json
CHANGED
package/tests/native/run.sh
DELETED