@zenfs/core 1.11.4 → 2.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/dist/backends/backend.d.ts +19 -15
- package/dist/backends/backend.js +36 -19
- package/dist/backends/cow.d.ts +20 -30
- package/dist/backends/cow.js +83 -192
- package/dist/backends/fetch.d.ts +1 -0
- package/dist/backends/fetch.js +30 -30
- package/dist/backends/index.d.ts +1 -1
- package/dist/backends/index.js +1 -1
- package/dist/backends/memory.d.ts +5 -7
- package/dist/backends/memory.js +2 -3
- package/dist/backends/passthrough.d.ts +19 -23
- package/dist/backends/passthrough.js +98 -288
- package/dist/backends/port.d.ts +220 -0
- package/dist/backends/port.js +328 -0
- package/dist/backends/single_buffer.d.ts +59 -47
- package/dist/backends/single_buffer.js +468 -219
- package/dist/backends/store/fs.d.ts +25 -35
- package/dist/backends/store/fs.js +276 -315
- package/dist/backends/store/store.d.ts +10 -15
- package/dist/backends/store/store.js +11 -10
- package/dist/config.d.ts +3 -12
- package/dist/config.js +17 -19
- package/dist/context.d.ts +8 -21
- package/dist/context.js +33 -10
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/internal/contexts.d.ts +63 -0
- package/dist/internal/contexts.js +15 -0
- package/dist/internal/credentials.d.ts +2 -11
- package/dist/internal/credentials.js +0 -19
- package/dist/internal/devices.d.ts +18 -80
- package/dist/internal/devices.js +103 -316
- package/dist/internal/error.d.ts +9 -204
- package/dist/internal/error.js +19 -288
- package/dist/internal/file_index.d.ts +1 -1
- package/dist/internal/file_index.js +11 -11
- package/dist/internal/filesystem.d.ts +51 -94
- package/dist/internal/filesystem.js +21 -20
- package/dist/internal/index.d.ts +1 -2
- package/dist/internal/index.js +1 -2
- package/dist/internal/index_fs.d.ts +12 -30
- package/dist/internal/index_fs.js +37 -69
- package/dist/internal/inode.d.ts +140 -24
- package/dist/internal/inode.js +515 -66
- package/dist/mixins/async.js +52 -112
- package/dist/mixins/mutexed.d.ts +19 -18
- package/dist/mixins/mutexed.js +62 -64
- package/dist/mixins/readonly.d.ts +7 -6
- package/dist/mixins/readonly.js +24 -18
- package/dist/mixins/sync.js +8 -8
- package/dist/{vfs/path.d.ts → path.d.ts} +3 -4
- package/dist/{vfs/path.js → path.js} +6 -9
- package/dist/polyfills.js +1 -1
- package/dist/readline.d.ts +134 -0
- package/dist/readline.js +623 -0
- package/dist/utils.d.ts +9 -37
- package/dist/utils.js +17 -85
- package/dist/vfs/acl.d.ts +42 -0
- package/dist/vfs/acl.js +268 -0
- package/dist/vfs/async.d.ts +9 -23
- package/dist/vfs/async.js +25 -27
- package/dist/vfs/config.d.ts +6 -18
- package/dist/vfs/config.js +8 -18
- package/dist/vfs/dir.d.ts +3 -3
- package/dist/vfs/dir.js +12 -12
- package/dist/vfs/file.d.ts +106 -0
- package/dist/vfs/file.js +244 -0
- package/dist/vfs/flags.d.ts +19 -0
- package/dist/vfs/flags.js +62 -0
- package/dist/vfs/index.d.ts +4 -10
- package/dist/vfs/index.js +4 -13
- package/dist/vfs/ioctl.d.ts +88 -0
- package/dist/vfs/ioctl.js +409 -0
- package/dist/vfs/promises.d.ts +81 -19
- package/dist/vfs/promises.js +404 -288
- package/dist/vfs/shared.d.ts +7 -37
- package/dist/vfs/shared.js +29 -85
- package/dist/{stats.d.ts → vfs/stats.d.ts} +14 -28
- package/dist/{stats.js → vfs/stats.js} +11 -66
- package/dist/vfs/streams.d.ts +1 -0
- package/dist/vfs/streams.js +32 -27
- package/dist/vfs/sync.d.ts +3 -3
- package/dist/vfs/sync.js +263 -260
- package/dist/vfs/watchers.d.ts +2 -2
- package/dist/vfs/watchers.js +12 -12
- package/dist/vfs/xattr.d.ts +116 -0
- package/dist/vfs/xattr.js +201 -0
- package/package.json +5 -3
- package/readme.md +1 -1
- package/scripts/test.js +2 -2
- package/tests/assignment.ts +1 -1
- package/tests/backend/config.worker.js +4 -1
- package/tests/backend/fetch.test.ts +3 -0
- package/tests/backend/port.test.ts +19 -33
- package/tests/backend/remote.worker.js +4 -1
- package/tests/backend/single-buffer.test.ts +53 -0
- package/tests/backend/single-buffer.worker.js +30 -0
- package/tests/common/context.test.ts +3 -3
- package/tests/common/handle.test.ts +17 -12
- package/tests/common/mutex.test.ts +9 -9
- package/tests/common/path.test.ts +1 -1
- package/tests/common/readline.test.ts +104 -0
- package/tests/common.ts +4 -19
- package/tests/fetch/fetch.ts +2 -2
- package/tests/fs/append.test.ts +4 -4
- package/tests/fs/directory.test.ts +25 -25
- package/tests/fs/errors.test.ts +15 -19
- package/tests/fs/links.test.ts +4 -3
- package/tests/fs/open.test.ts +4 -21
- package/tests/fs/permissions.test.ts +14 -18
- package/tests/fs/read.test.ts +10 -9
- package/tests/fs/readFile.test.ts +10 -26
- package/tests/fs/rename.test.ts +4 -9
- package/tests/fs/stat.test.ts +8 -8
- package/tests/fs/streams.test.ts +2 -11
- package/tests/fs/times.test.ts +7 -7
- package/tests/fs/truncate.test.ts +8 -36
- package/tests/fs/watch.test.ts +10 -10
- package/tests/fs/write.test.ts +77 -13
- package/tests/fs/xattr.test.ts +85 -0
- package/tests/logs.js +22 -0
- package/tests/setup/context.ts +1 -1
- package/tests/setup/index.ts +3 -3
- package/tests/setup/port.ts +7 -1
- package/dist/backends/port/fs.d.ts +0 -84
- package/dist/backends/port/fs.js +0 -151
- package/dist/backends/port/rpc.d.ts +0 -77
- package/dist/backends/port/rpc.js +0 -100
- package/dist/backends/store/simple.d.ts +0 -20
- package/dist/backends/store/simple.js +0 -13
- package/dist/internal/file.d.ts +0 -359
- package/dist/internal/file.js +0 -751
- package/dist/internal/log.d.ts +0 -133
- package/dist/internal/log.js +0 -218
- package/tests/fs/writeFile.test.ts +0 -70
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { suite, test } from 'node:test';
|
|
2
1
|
import assert from 'node:assert/strict';
|
|
2
|
+
import { suite, test } from 'node:test';
|
|
3
|
+
import { canary } from 'utilium';
|
|
3
4
|
import { bindContext } from '../../dist/context.js';
|
|
4
5
|
import * as fs from '../../dist/vfs/index.js';
|
|
5
|
-
import { canary } from 'utilium';
|
|
6
6
|
|
|
7
7
|
fs.mkdirSync('/ctx');
|
|
8
|
-
const { fs: ctx } = bindContext('/ctx');
|
|
8
|
+
const { fs: ctx } = bindContext({ root: '/ctx' });
|
|
9
9
|
|
|
10
10
|
suite('Context', () => {
|
|
11
11
|
test('create a file', () => {
|
|
@@ -1,25 +1,21 @@
|
|
|
1
1
|
import assert from 'node:assert/strict';
|
|
2
2
|
import { suite, test } from 'node:test';
|
|
3
|
+
import { wait } from 'utilium';
|
|
3
4
|
import { constants, type FileHandle, open } from '../../dist/vfs/promises.js';
|
|
4
5
|
|
|
5
6
|
const content = 'The cake is a lie',
|
|
6
7
|
appended = '\nAnother lie';
|
|
7
8
|
|
|
8
|
-
await
|
|
9
|
-
let handle: FileHandle;
|
|
10
|
-
const filePath = './test.txt';
|
|
11
|
-
|
|
12
|
-
test('open', async () => {
|
|
13
|
-
handle = await open(filePath, 'w+');
|
|
14
|
-
});
|
|
9
|
+
await using handle: FileHandle = await open('./test.txt', 'ws+');
|
|
15
10
|
|
|
11
|
+
await suite('FileHandle', () => {
|
|
16
12
|
test('writeFile', async () => {
|
|
17
13
|
await handle.writeFile(content);
|
|
18
14
|
await handle.sync();
|
|
19
15
|
});
|
|
20
16
|
|
|
21
17
|
test('readFile', async () => {
|
|
22
|
-
assert(
|
|
18
|
+
assert.equal(await handle.readFile('utf8'), content);
|
|
23
19
|
});
|
|
24
20
|
|
|
25
21
|
test('appendFile', async () => {
|
|
@@ -27,12 +23,12 @@ await suite('FileHandle', () => {
|
|
|
27
23
|
});
|
|
28
24
|
|
|
29
25
|
test('readFile after appendFile', async () => {
|
|
30
|
-
assert(
|
|
26
|
+
assert.equal(await handle.readFile({ encoding: 'utf8' }), content + appended);
|
|
31
27
|
});
|
|
32
28
|
|
|
33
29
|
test('truncate', async () => {
|
|
34
30
|
await handle.truncate(5);
|
|
35
|
-
assert(
|
|
31
|
+
assert.equal(await handle.readFile({ encoding: 'utf8' }), content.slice(0, 5));
|
|
36
32
|
});
|
|
37
33
|
|
|
38
34
|
test('stat', async () => {
|
|
@@ -54,7 +50,16 @@ await suite('FileHandle', () => {
|
|
|
54
50
|
assert.equal(stats.gid, 5678);
|
|
55
51
|
});
|
|
56
52
|
|
|
57
|
-
test('
|
|
58
|
-
await handle.
|
|
53
|
+
test('readLines', async () => {
|
|
54
|
+
await handle.writeFile('first line\nsecond line\nthird line');
|
|
55
|
+
|
|
56
|
+
await using rl = handle.readLines();
|
|
57
|
+
|
|
58
|
+
const lines: string[] = [];
|
|
59
|
+
rl.on('line', (line: string) => lines.push(line));
|
|
60
|
+
|
|
61
|
+
await wait(50);
|
|
62
|
+
|
|
63
|
+
assert.deepEqual(lines, ['first line', 'second line', 'third line']);
|
|
59
64
|
});
|
|
60
65
|
});
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { suite, test } from 'node:test';
|
|
1
3
|
import { wait } from 'utilium';
|
|
2
|
-
import { Mutexed } from '../../dist/mixins/mutexed.js';
|
|
3
|
-
import { StoreFS } from '../../dist/backends/store/fs.js';
|
|
4
4
|
import { InMemoryStore } from '../../dist/backends/memory.js';
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
5
|
+
import { StoreFS } from '../../dist/backends/store/fs.js';
|
|
6
|
+
import { Mutexed } from '../../dist/mixins/mutexed.js';
|
|
7
7
|
|
|
8
|
-
suite('
|
|
8
|
+
suite('Mutexed FS', () => {
|
|
9
9
|
const fs = new (Mutexed(StoreFS))(new InMemoryStore(0x10000, 'test'));
|
|
10
10
|
fs._fs.checkRootSync();
|
|
11
11
|
|
|
12
12
|
test('lock/unlock', () => {
|
|
13
|
-
const lock = fs.lockSync(
|
|
13
|
+
const lock = fs.lockSync();
|
|
14
14
|
assert(fs.isLocked);
|
|
15
15
|
lock.unlock();
|
|
16
16
|
assert(!fs.isLocked);
|
|
@@ -20,11 +20,11 @@ suite('LockFS mutex', () => {
|
|
|
20
20
|
let lock1Resolved = false;
|
|
21
21
|
let lock2Resolved = false;
|
|
22
22
|
|
|
23
|
-
const lock1 = fs.lock(
|
|
23
|
+
const lock1 = fs.lock().then(lock => {
|
|
24
24
|
lock1Resolved = true;
|
|
25
25
|
lock.unlock();
|
|
26
26
|
});
|
|
27
|
-
const lock2 = fs.lock(
|
|
27
|
+
const lock2 = fs.lock().then(lock => {
|
|
28
28
|
lock2Resolved = true;
|
|
29
29
|
lock.unlock();
|
|
30
30
|
});
|
|
@@ -50,7 +50,7 @@ suite('LockFS mutex', () => {
|
|
|
50
50
|
let x = 1;
|
|
51
51
|
|
|
52
52
|
async function foo() {
|
|
53
|
-
const lock = await fs.lock(
|
|
53
|
+
const lock = await fs.lock();
|
|
54
54
|
await wait(25);
|
|
55
55
|
x++;
|
|
56
56
|
lock.unlock();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import assert from 'node:assert/strict';
|
|
2
2
|
import { suite, test } from 'node:test';
|
|
3
|
-
import { basename, dirname, extname, join, normalize, resolve } from '../../dist/
|
|
3
|
+
import { basename, dirname, extname, join, normalize, resolve } from '../../dist/path.js';
|
|
4
4
|
import * as fs from '../../dist/vfs/index.js';
|
|
5
5
|
|
|
6
6
|
suite('Path emulation', () => {
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { PassThrough } from 'node:stream';
|
|
3
|
+
import { suite, test } from 'node:test';
|
|
4
|
+
import { wait } from 'utilium';
|
|
5
|
+
import { createInterface, Interface } from '../../dist/readline.js';
|
|
6
|
+
|
|
7
|
+
suite('Readline interface', { skip: true }, () => {
|
|
8
|
+
test('creates interface with readable stream', async () => {
|
|
9
|
+
const input = new PassThrough();
|
|
10
|
+
await using rl = createInterface({ input });
|
|
11
|
+
|
|
12
|
+
assert.ok(rl instanceof Interface);
|
|
13
|
+
assert.equal(rl.input, input);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test('emits line events when receiving data', async () => {
|
|
17
|
+
const input = new PassThrough();
|
|
18
|
+
await using rl = createInterface({ input });
|
|
19
|
+
|
|
20
|
+
const lines: string[] = [];
|
|
21
|
+
rl.on('line', (line: string) => lines.push(line));
|
|
22
|
+
|
|
23
|
+
input.write('first line\n');
|
|
24
|
+
input.write('second line\r\n');
|
|
25
|
+
input.write('third line\n');
|
|
26
|
+
|
|
27
|
+
await wait(10);
|
|
28
|
+
|
|
29
|
+
assert.deepEqual(lines, ['first line', 'second line', 'third line']);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('handles partial lines correctly', async () => {
|
|
33
|
+
const input = new PassThrough();
|
|
34
|
+
await using rl = createInterface({ input });
|
|
35
|
+
|
|
36
|
+
const lines: string[] = [];
|
|
37
|
+
rl.on('line', (line: string) => lines.push(line));
|
|
38
|
+
|
|
39
|
+
input.write('partial ');
|
|
40
|
+
input.write('line\n');
|
|
41
|
+
input.write('another ');
|
|
42
|
+
input.write('partial line\n');
|
|
43
|
+
|
|
44
|
+
await wait(10);
|
|
45
|
+
|
|
46
|
+
assert.deepEqual(lines, ['partial line', 'another partial line']);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('emits remaining buffer on close', async () => {
|
|
50
|
+
const input = new PassThrough();
|
|
51
|
+
await using rl = createInterface({ input });
|
|
52
|
+
|
|
53
|
+
const lines: string[] = [];
|
|
54
|
+
rl.on('line', (line: string) => lines.push(line));
|
|
55
|
+
|
|
56
|
+
input.write('line with newline\n');
|
|
57
|
+
input.write('line without newline');
|
|
58
|
+
|
|
59
|
+
await wait(10);
|
|
60
|
+
|
|
61
|
+
assert.deepEqual(lines, ['line with newline']);
|
|
62
|
+
|
|
63
|
+
await wait(10);
|
|
64
|
+
|
|
65
|
+
assert.deepEqual(lines, ['line with newline', 'line without newline']);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test('tracks history correctly', async () => {
|
|
69
|
+
const input = new PassThrough();
|
|
70
|
+
await using rl = createInterface({ input });
|
|
71
|
+
|
|
72
|
+
let history: string[] = [];
|
|
73
|
+
rl.on('history', (h: string[]) => (history = h));
|
|
74
|
+
|
|
75
|
+
input.write('first command\n');
|
|
76
|
+
input.write('second command\n');
|
|
77
|
+
|
|
78
|
+
await wait(10);
|
|
79
|
+
|
|
80
|
+
assert.deepEqual(history, ['first command', 'second command']);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test('pause and resume functionality', async () => {
|
|
84
|
+
const input = new PassThrough();
|
|
85
|
+
await using rl = createInterface({ input });
|
|
86
|
+
|
|
87
|
+
const lines: string[] = [];
|
|
88
|
+
rl.on('line', (line: string) => lines.push(line));
|
|
89
|
+
|
|
90
|
+
rl.pause();
|
|
91
|
+
input.write('should not be processed\n');
|
|
92
|
+
|
|
93
|
+
await wait(10);
|
|
94
|
+
|
|
95
|
+
assert.deepEqual(lines, []);
|
|
96
|
+
|
|
97
|
+
rl.resume();
|
|
98
|
+
input.write('should be processed\n');
|
|
99
|
+
|
|
100
|
+
await wait(10);
|
|
101
|
+
|
|
102
|
+
assert.deepEqual(lines, ['should be processed']);
|
|
103
|
+
});
|
|
104
|
+
});
|
package/tests/common.ts
CHANGED
|
@@ -1,26 +1,11 @@
|
|
|
1
1
|
import { join, resolve } from 'node:path';
|
|
2
|
-
import { fs as defaultFS
|
|
2
|
+
import { fs as defaultFS } from '../dist/index.js';
|
|
3
|
+
import { setupLogs } from './logs.js';
|
|
3
4
|
export type * from '../dist/index.js';
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
setupLogs();
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
if (ZENFS_LOG_LEVEL) {
|
|
10
|
-
const tmp = parseInt(ZENFS_LOG_LEVEL);
|
|
11
|
-
if (Number.isSafeInteger(tmp)) level = tmp;
|
|
12
|
-
else level = ZENFS_LOG_LEVEL as (typeof log.levels)[log.Level];
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
log.configure({
|
|
16
|
-
enabled: true,
|
|
17
|
-
format: log.formats.ansi_message,
|
|
18
|
-
dumpBacklog: true,
|
|
19
|
-
level,
|
|
20
|
-
output: console.error,
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
const setupPath = resolve(SETUP || join(import.meta.dirname, 'setup/memory.ts'));
|
|
8
|
+
const setupPath = resolve(process.env.SETUP || join(import.meta.dirname, 'setup/memory.ts'));
|
|
24
9
|
|
|
25
10
|
const setup = await import(setupPath).catch(error => {
|
|
26
11
|
console.log('Failed to import test setup:');
|
package/tests/fetch/fetch.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { log } from 'kerium';
|
|
1
2
|
import { configure, Fetch } from '../../dist/index.js';
|
|
2
3
|
import { baseUrl } from './config.js';
|
|
3
|
-
import * as log from '../../dist/internal/log.js';
|
|
4
4
|
|
|
5
5
|
await configure({
|
|
6
6
|
mounts: {
|
|
@@ -13,7 +13,7 @@ await configure({
|
|
|
13
13
|
log: {
|
|
14
14
|
enabled: true,
|
|
15
15
|
output: console.error,
|
|
16
|
-
format: log.
|
|
16
|
+
format: log.fancy({ style: 'ansi', colorize: 'message' }),
|
|
17
17
|
level: log.Level.INFO,
|
|
18
18
|
dumpBacklog: true,
|
|
19
19
|
},
|
package/tests/fs/append.test.ts
CHANGED
|
@@ -5,15 +5,15 @@ import { fs } from '../common.js';
|
|
|
5
5
|
const content = 'Sample content',
|
|
6
6
|
original = 'ABCD';
|
|
7
7
|
|
|
8
|
-
suite('
|
|
9
|
-
test('
|
|
8
|
+
suite('Appends', () => {
|
|
9
|
+
test('Create an empty file and add content', async () => {
|
|
10
10
|
const filename = 'append.txt';
|
|
11
11
|
await fs.promises.appendFile(filename, content);
|
|
12
12
|
const data = await fs.promises.readFile(filename, 'utf8');
|
|
13
13
|
assert.equal(data, content);
|
|
14
14
|
});
|
|
15
15
|
|
|
16
|
-
test('
|
|
16
|
+
test('Append data to a non-empty file', async () => {
|
|
17
17
|
const filename = 'append2.txt';
|
|
18
18
|
|
|
19
19
|
await fs.promises.writeFile(filename, original);
|
|
@@ -22,7 +22,7 @@ suite('appendFile', () => {
|
|
|
22
22
|
assert.equal(data, original + content);
|
|
23
23
|
});
|
|
24
24
|
|
|
25
|
-
test('
|
|
25
|
+
test('Append a buffer to the file', async () => {
|
|
26
26
|
const filename = 'append3.txt';
|
|
27
27
|
|
|
28
28
|
await fs.promises.writeFile(filename, original);
|
|
@@ -27,7 +27,7 @@ suite('Directories', () => {
|
|
|
27
27
|
test('mkdirSync', async () => await fs.promises.mkdir('/two', 0o000));
|
|
28
28
|
|
|
29
29
|
test('mkdir, nested', async () => {
|
|
30
|
-
assert.rejects(fs.promises.mkdir('/nested/dir'), { code: 'ENOENT', path: '/nested' });
|
|
30
|
+
await assert.rejects(fs.promises.mkdir('/nested/dir'), { code: 'ENOENT', path: '/nested' });
|
|
31
31
|
assert(!(await fs.promises.exists('/nested/dir')));
|
|
32
32
|
});
|
|
33
33
|
|
|
@@ -59,39 +59,39 @@ suite('Directories', () => {
|
|
|
59
59
|
await fs.promises.mkdir('/rmdirTest');
|
|
60
60
|
await fs.promises.mkdir('/rmdirTest/rmdirTest2');
|
|
61
61
|
|
|
62
|
-
assert.rejects(fs.promises.rmdir('/rmdirTest'), { code: 'ENOTEMPTY' });
|
|
62
|
+
await assert.rejects(fs.promises.rmdir('/rmdirTest'), { code: 'ENOTEMPTY' });
|
|
63
63
|
});
|
|
64
64
|
|
|
65
65
|
test('readdirSync on file', () => {
|
|
66
66
|
assert.throws(() => fs.readdirSync('a.js'), { code: 'ENOTDIR' });
|
|
67
67
|
});
|
|
68
68
|
|
|
69
|
-
test('readdir on file', () => {
|
|
70
|
-
assert.rejects(fs.promises.readdir('a.js'), { code: 'ENOTDIR' });
|
|
69
|
+
test('readdir on file', async () => {
|
|
70
|
+
await assert.rejects(fs.promises.readdir('a.js'), { code: 'ENOTDIR' });
|
|
71
71
|
});
|
|
72
72
|
|
|
73
|
-
test('readdirSync on non-
|
|
73
|
+
test('readdirSync on non-existent directory', () => {
|
|
74
74
|
assert.throws(() => fs.readdirSync('/does/not/exist'), { code: 'ENOENT' });
|
|
75
75
|
});
|
|
76
76
|
|
|
77
|
-
test('readdir on non-
|
|
78
|
-
assert.rejects(fs.promises.readdir('/does/not/exist'), { code: 'ENOENT' });
|
|
77
|
+
test('readdir on non-existent directory', async () => {
|
|
78
|
+
await assert.rejects(fs.promises.readdir('/does/not/exist'), { code: 'ENOENT' });
|
|
79
79
|
});
|
|
80
80
|
|
|
81
|
-
test('rm recursively
|
|
82
|
-
await fs.promises.mkdir('/
|
|
83
|
-
await fs.promises.mkdir('/
|
|
84
|
-
await fs.promises.writeFile('/
|
|
81
|
+
test('rm recursively', async () => {
|
|
82
|
+
await fs.promises.mkdir('/rmDirRecursively');
|
|
83
|
+
await fs.promises.mkdir('/rmDirRecursively/rmDirNested');
|
|
84
|
+
await fs.promises.writeFile('/rmDirRecursively/rmDirNested/test.txt', 'hello world!');
|
|
85
85
|
|
|
86
|
-
await fs.promises.rm('/
|
|
86
|
+
await fs.promises.rm('/rmDirRecursively', { recursive: true });
|
|
87
87
|
});
|
|
88
88
|
|
|
89
|
-
test('
|
|
90
|
-
fs.mkdirSync('/
|
|
91
|
-
fs.mkdirSync('/
|
|
92
|
-
fs.writeFileSync('/
|
|
89
|
+
test('rmSync recursively', () => {
|
|
90
|
+
fs.mkdirSync('/rmDirRecursively');
|
|
91
|
+
fs.mkdirSync('/rmDirRecursively/rmDirNested');
|
|
92
|
+
fs.writeFileSync('/rmDirRecursively/rmDirNested/test.txt', 'hello world!');
|
|
93
93
|
|
|
94
|
-
fs.rmSync('/
|
|
94
|
+
fs.rmSync('/rmDirRecursively', { recursive: true });
|
|
95
95
|
});
|
|
96
96
|
|
|
97
97
|
test('readdir returns files and directories', async () => {
|
|
@@ -143,17 +143,17 @@ suite('Directories', () => {
|
|
|
143
143
|
|
|
144
144
|
test('readdir returns Dirent recursively', async () => {
|
|
145
145
|
const entries = await fs.promises.readdir(testDir, { recursive: true, withFileTypes: true });
|
|
146
|
-
|
|
147
|
-
assert
|
|
148
|
-
assert
|
|
146
|
+
const paths = entries.map(entry => entry.path).sort();
|
|
147
|
+
assert.equal(paths[0], 'file1.txt');
|
|
148
|
+
assert.equal(paths[4], 'subdir1/file4.txt');
|
|
149
|
+
assert.equal(paths[8], 'subdir2/file5.txt');
|
|
149
150
|
});
|
|
150
151
|
|
|
151
|
-
// New test for readdirSync with recursive: true
|
|
152
152
|
test('readdirSync returns files recursively', () => {
|
|
153
|
-
const entries = fs.readdirSync(testDir, { recursive: true });
|
|
154
|
-
assert(entries
|
|
155
|
-
assert(entries
|
|
156
|
-
assert(entries
|
|
153
|
+
const entries = fs.readdirSync(testDir, { recursive: true }).sort();
|
|
154
|
+
assert.equal(entries[0], 'file1.txt');
|
|
155
|
+
assert.equal(entries[4], 'subdir1/file4.txt');
|
|
156
|
+
assert.equal(entries[8], 'subdir2/file5.txt');
|
|
157
157
|
});
|
|
158
158
|
|
|
159
159
|
test('Cyrillic file names', () => {
|
package/tests/fs/errors.test.ts
CHANGED
|
@@ -1,36 +1,32 @@
|
|
|
1
1
|
import assert from 'node:assert/strict';
|
|
2
2
|
import test, { suite } from 'node:test';
|
|
3
3
|
import { fs } from '../common.js';
|
|
4
|
-
import type { ErrnoError } from '../../dist/index.js';
|
|
5
4
|
|
|
6
5
|
const existingFile = '/exit.js';
|
|
7
6
|
|
|
8
7
|
suite('Error messages', () => {
|
|
9
8
|
const path = '/non-existent';
|
|
10
9
|
|
|
11
|
-
fs.promises.stat(path).catch((error: ErrnoError) => {
|
|
12
|
-
assert.equal(error.bufferSize(), 4 + JSON.stringify(error.toJSON()).length);
|
|
13
|
-
});
|
|
14
|
-
|
|
15
10
|
const missing = { path, code: 'ENOENT' };
|
|
16
|
-
const existing = { path: existingFile };
|
|
11
|
+
const existing = { path: existingFile, code: 'EEXIST' };
|
|
12
|
+
const notDir = { path: existingFile, code: 'ENOTDIR' };
|
|
17
13
|
|
|
18
|
-
test('stat', () => assert.rejects(() => fs.promises.stat(path), missing));
|
|
19
|
-
test('mkdir', () => assert.rejects(() => fs.promises.mkdir(existingFile, 0o666), existing));
|
|
20
|
-
test('rmdir', () => assert.rejects(() => fs.promises.rmdir(path), missing));
|
|
21
|
-
test('rmdir', () => assert.rejects(() => fs.promises.rmdir(existingFile),
|
|
22
|
-
test('rename', () => assert.rejects(() => fs.promises.rename(path, 'foo'), missing));
|
|
23
|
-
test('open', () => assert.rejects(() => fs.promises.open(path, 'r'), missing));
|
|
24
|
-
test('readdir', () => assert.rejects(() => fs.promises.readdir(path), missing));
|
|
25
|
-
test('unlink', () => assert.rejects(() => fs.promises.unlink(path), missing));
|
|
26
|
-
test('link', () => assert.rejects(() => fs.promises.link(path, 'foo'), missing));
|
|
27
|
-
test('chmod', () => assert.rejects(() => fs.promises.chmod(path, 0o666), missing));
|
|
28
|
-
test('lstat', () => assert.rejects(() => fs.promises.lstat(path), missing));
|
|
29
|
-
test('readlink', () => assert.rejects(() => fs.promises.readlink(path), missing));
|
|
14
|
+
test('stat', async () => await assert.rejects(() => fs.promises.stat(path), missing));
|
|
15
|
+
test('mkdir', async () => await assert.rejects(() => fs.promises.mkdir(existingFile, 0o666), existing));
|
|
16
|
+
test('rmdir (missing)', async () => await assert.rejects(() => fs.promises.rmdir(path), missing));
|
|
17
|
+
test('rmdir (existing)', async () => await assert.rejects(() => fs.promises.rmdir(existingFile), notDir));
|
|
18
|
+
test('rename', async () => await assert.rejects(() => fs.promises.rename(path, 'foo'), missing));
|
|
19
|
+
test('open', async () => await assert.rejects(() => fs.promises.open(path, 'r'), missing));
|
|
20
|
+
test('readdir', async () => await assert.rejects(() => fs.promises.readdir(path), missing));
|
|
21
|
+
test('unlink', async () => await assert.rejects(() => fs.promises.unlink(path), missing));
|
|
22
|
+
test('link', async () => await assert.rejects(() => fs.promises.link(path, 'foo'), missing));
|
|
23
|
+
test('chmod', async () => await assert.rejects(() => fs.promises.chmod(path, 0o666), missing));
|
|
24
|
+
test('lstat', async () => await assert.rejects(() => fs.promises.lstat(path), missing));
|
|
25
|
+
test('readlink', async () => await assert.rejects(() => fs.promises.readlink(path), missing));
|
|
30
26
|
test('statSync', () => assert.throws(() => fs.statSync(path), missing));
|
|
31
27
|
test('mkdirSync', () => assert.throws(() => fs.mkdirSync(existingFile, 0o666), existing));
|
|
32
28
|
test('rmdirSync', () => assert.throws(() => fs.rmdirSync(path), missing));
|
|
33
|
-
test('rmdirSync', () => assert.throws(() => fs.rmdirSync(existingFile),
|
|
29
|
+
test('rmdirSync', () => assert.throws(() => fs.rmdirSync(existingFile), notDir));
|
|
34
30
|
test('renameSync', () => assert.throws(() => fs.renameSync(path, 'foo'), missing));
|
|
35
31
|
test('openSync', () => assert.throws(() => fs.openSync(path, 'r'), missing));
|
|
36
32
|
test('readdirSync', () => assert.throws(() => fs.readdirSync(path), missing));
|
package/tests/fs/links.test.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import type { Exception } from 'kerium';
|
|
1
2
|
import assert from 'node:assert/strict';
|
|
2
3
|
import { suite, test } from 'node:test';
|
|
3
|
-
import { join } from '../../dist/
|
|
4
|
+
import { join } from '../../dist/path.js';
|
|
4
5
|
import { fs } from '../common.js';
|
|
5
|
-
import type { ErrnoError } from '../../dist/index.js';
|
|
6
6
|
|
|
7
7
|
suite('Links', () => {
|
|
8
8
|
const target = '/a1.js',
|
|
@@ -21,6 +21,7 @@ suite('Links', () => {
|
|
|
21
21
|
test('readlink', async () => {
|
|
22
22
|
const destination = await fs.promises.readlink(symlink);
|
|
23
23
|
assert.equal(destination, target);
|
|
24
|
+
assert.throws(() => fs.readlinkSync(destination));
|
|
24
25
|
});
|
|
25
26
|
|
|
26
27
|
test('read target contents', async () => {
|
|
@@ -59,7 +60,7 @@ suite('Links', () => {
|
|
|
59
60
|
});
|
|
60
61
|
|
|
61
62
|
test('link', async t => {
|
|
62
|
-
const _ = await fs.promises.link(target, hardlink).catch((e:
|
|
63
|
+
const _ = await fs.promises.link(target, hardlink).catch((e: Exception) => {
|
|
63
64
|
if (e.code == 'ENOSYS') return e;
|
|
64
65
|
throw e;
|
|
65
66
|
});
|
package/tests/fs/open.test.ts
CHANGED
|
@@ -1,30 +1,13 @@
|
|
|
1
1
|
import assert from 'node:assert/strict';
|
|
2
2
|
import { suite, test } from 'node:test';
|
|
3
|
-
import { ErrnoError } from '../../dist/index.js';
|
|
4
3
|
import { fs } from '../common.js';
|
|
5
4
|
|
|
6
|
-
suite('
|
|
5
|
+
suite('Opening files', () => {
|
|
7
6
|
const filename = 'a.js';
|
|
8
7
|
|
|
9
|
-
test('throw ENOENT when opening non-existent file
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
fs.openSync('/path/to/file/that/does/not/exist', 'r');
|
|
13
|
-
} catch (error: any) {
|
|
14
|
-
assert(error instanceof ErrnoError);
|
|
15
|
-
assert.equal(error?.code, 'ENOENT');
|
|
16
|
-
caughtException = true;
|
|
17
|
-
}
|
|
18
|
-
assert(caughtException);
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
test('throw ENOENT when opening non-existent file (async)', async () => {
|
|
22
|
-
try {
|
|
23
|
-
await fs.promises.open('/path/to/file/that/does/not/exist', 'r');
|
|
24
|
-
} catch (error: any) {
|
|
25
|
-
assert(error instanceof ErrnoError);
|
|
26
|
-
assert.equal(error?.code, 'ENOENT');
|
|
27
|
-
}
|
|
8
|
+
test('throw ENOENT when opening non-existent file', async () => {
|
|
9
|
+
assert.throws(() => fs.openSync('/path/to/file/that/does/not/exist', 'r'), { code: 'ENOENT' });
|
|
10
|
+
await assert.rejects(fs.promises.open('/path/to/file/that/does/not/exist', 'r'), { code: 'ENOENT' });
|
|
28
11
|
});
|
|
29
12
|
|
|
30
13
|
test('open file with mode "r"', async () => {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { Exception } from 'kerium';
|
|
1
2
|
import assert from 'node:assert/strict';
|
|
2
3
|
import { suite, test } from 'node:test';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
4
|
+
import { encodeUTF8 } from 'utilium';
|
|
5
|
+
import { defaultContext } from '../../dist/internal/contexts.js';
|
|
6
|
+
import { join } from '../../dist/path.js';
|
|
5
7
|
import { R_OK, W_OK, X_OK } from '../../dist/vfs/constants.js';
|
|
6
|
-
import { join } from '../../dist/vfs/path.js';
|
|
7
8
|
import { fs } from '../common.js';
|
|
8
9
|
|
|
9
10
|
const asyncMode = 0o777;
|
|
@@ -47,19 +48,16 @@ suite('Permissions', () => {
|
|
|
47
48
|
});
|
|
48
49
|
|
|
49
50
|
async function test_item(path: string): Promise<void> {
|
|
50
|
-
const stats = await fs.promises.stat(path).catch((error:
|
|
51
|
-
assert(error instanceof
|
|
51
|
+
const stats = await fs.promises.stat(path).catch((error: Exception) => {
|
|
52
|
+
assert(error instanceof Exception);
|
|
52
53
|
assert.equal(error.code, 'EACCES');
|
|
53
54
|
});
|
|
54
|
-
if (!stats)
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
55
|
+
if (!stats) return;
|
|
57
56
|
assert(stats.hasAccess(X_OK));
|
|
58
57
|
|
|
59
58
|
function checkError(access: number) {
|
|
60
|
-
return function (error:
|
|
61
|
-
assert(error instanceof
|
|
62
|
-
assert(error);
|
|
59
|
+
return function (error: Exception) {
|
|
60
|
+
assert(error instanceof Exception);
|
|
63
61
|
assert(!stats!.hasAccess(access));
|
|
64
62
|
};
|
|
65
63
|
}
|
|
@@ -79,16 +77,14 @@ suite('Permissions', () => {
|
|
|
79
77
|
await fs.promises.unlink(testFile).catch(checkError(W_OK));
|
|
80
78
|
} else {
|
|
81
79
|
const handle = await fs.promises.open(path, 'a').catch(checkError(W_OK));
|
|
82
|
-
if (!handle)
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
80
|
+
if (!handle) return;
|
|
85
81
|
await handle.close();
|
|
86
82
|
}
|
|
87
|
-
assert(stats.hasAccess(
|
|
83
|
+
assert(stats.hasAccess(W_OK));
|
|
88
84
|
}
|
|
89
85
|
|
|
90
|
-
const copy = { ...credentials };
|
|
91
|
-
Object.assign(credentials, { uid: 1000, gid: 1000, euid: 1000, egid: 1000 });
|
|
86
|
+
const copy = { ...defaultContext.credentials };
|
|
87
|
+
Object.assign(defaultContext.credentials, { uid: 1000, gid: 1000, euid: 1000, egid: 1000 });
|
|
92
88
|
test('Access controls: /', () => test_item('/'));
|
|
93
|
-
Object.assign(credentials, copy);
|
|
89
|
+
Object.assign(defaultContext.credentials, copy);
|
|
94
90
|
});
|
package/tests/fs/read.test.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { Buffer } from 'buffer';
|
|
1
2
|
import assert from 'node:assert/strict';
|
|
2
3
|
import { suite, test } from 'node:test';
|
|
3
4
|
import { fs } from '../common.js';
|
|
4
|
-
import { Buffer } from 'buffer';
|
|
5
5
|
|
|
6
6
|
const filepath = 'x.txt';
|
|
7
7
|
const expected = 'xyz\n';
|
|
8
|
+
const ellipses = '…'.repeat(10_000);
|
|
8
9
|
|
|
9
10
|
suite('read', () => {
|
|
10
11
|
test('read file asynchronously', async () => {
|
|
@@ -22,25 +23,25 @@ suite('read', () => {
|
|
|
22
23
|
assert.equal(bytesRead, expected.length);
|
|
23
24
|
assert.equal(buffer.toString(), expected);
|
|
24
25
|
});
|
|
25
|
-
});
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
test('Read a file and check its binary bytes (asynchronous)', async () => {
|
|
27
|
+
test('Read a file and check its binary bytes asynchronously', async () => {
|
|
29
28
|
const buff = await fs.promises.readFile('elipses.txt');
|
|
29
|
+
assert.equal(buff.length, 30_000);
|
|
30
|
+
assert.equal(buff.toString(), ellipses);
|
|
30
31
|
assert.equal((buff[1] << 8) | buff[0], 32994);
|
|
31
32
|
});
|
|
32
33
|
|
|
33
|
-
test('Read a file and check its binary bytes
|
|
34
|
+
test('Read a file and check its binary bytes synchronously', () => {
|
|
34
35
|
const buff = fs.readFileSync('elipses.txt');
|
|
36
|
+
assert.equal(buff.length, 30_000);
|
|
37
|
+
assert.equal(buff.toString(), ellipses);
|
|
35
38
|
assert.equal((buff[1] << 8) | buff[0], 32994);
|
|
36
39
|
});
|
|
37
|
-
});
|
|
38
40
|
|
|
39
|
-
suite('read buffer', () => {
|
|
40
41
|
const bufferAsync = Buffer.alloc(expected.length);
|
|
41
42
|
const bufferSync = Buffer.alloc(expected.length);
|
|
42
43
|
|
|
43
|
-
test('read file asynchronously', async () => {
|
|
44
|
+
test('read file from handle asynchronously', async () => {
|
|
44
45
|
const handle = await fs.promises.open(filepath, 'r');
|
|
45
46
|
const { bytesRead } = await handle.read(bufferAsync, 0, expected.length, 0);
|
|
46
47
|
|
|
@@ -48,7 +49,7 @@ suite('read buffer', () => {
|
|
|
48
49
|
assert.equal(bufferAsync.toString(), expected);
|
|
49
50
|
});
|
|
50
51
|
|
|
51
|
-
test('read file synchronously', () => {
|
|
52
|
+
test('read file from handle synchronously', () => {
|
|
52
53
|
const fd = fs.openSync(filepath, 'r');
|
|
53
54
|
const bytesRead = fs.readSync(fd, bufferSync, 0, expected.length, 0);
|
|
54
55
|
|