@zenfs/core 2.5.7 → 2.6.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/cow.d.ts +13 -0
- package/dist/backends/cow.js +48 -11
- package/dist/backends/single_buffer.d.ts +2 -2
- package/dist/backends/store/fs.d.ts +6 -6
- package/dist/backends/store/fs.js +14 -10
- package/dist/internal/devices.d.ts +6 -6
- package/dist/internal/filesystem.d.ts +4 -4
- package/dist/internal/index_fs.d.ts +4 -4
- package/dist/internal/index_fs.js +6 -8
- package/dist/internal/inode.js +3 -0
- package/dist/node/async.js +1 -1
- package/dist/node/dir.d.ts +3 -1
- package/dist/node/dir.js +23 -5
- package/dist/node/promises.d.ts +4 -2
- package/dist/node/promises.js +130 -89
- package/dist/node/streams.d.ts +4 -0
- package/dist/node/streams.js +9 -10
- package/dist/node/sync.js +71 -40
- package/dist/utils.d.ts +8 -1
- package/dist/utils.js +26 -7
- package/dist/vfs/async.js +224 -85
- package/dist/vfs/file.d.ts +13 -7
- package/dist/vfs/file.js +661 -357
- package/dist/vfs/shared.d.ts +1 -0
- package/dist/vfs/shared.js +19 -3
- package/dist/vfs/sync.js +214 -85
- package/dist/vfs/vcache.d.ts +66 -0
- package/dist/vfs/vcache.js +249 -0
- package/dist/vfs/vnode.d.ts +66 -0
- package/dist/vfs/vnode.js +200 -0
- package/dist/vfs/watchers.js +4 -2
- package/dist/vfs/xattr.js +2 -2
- package/eslint.shared.js +1 -1
- package/package.json +6 -3
- package/scripts/make-index.js +7 -1
- package/scripts/test.js +28 -21
- package/tests/backend/port.test.ts +3 -3
- package/tests/backend/store.test.ts +49 -0
- package/tests/common/inode.test.ts +8 -0
- package/tests/common.ts +62 -0
- package/tests/fetch/fetch.ts +6 -0
- package/tests/fetch/run.sh +2 -2
- package/tests/fetch/server.js +3 -3
- package/tests/fs/append.test.ts +5 -5
- package/tests/fs/concurrency.test.ts +52 -0
- package/tests/fs/dir.test.ts +13 -15
- package/tests/fs/directory.test.ts +32 -31
- package/tests/fs/errors.test.ts +151 -31
- package/tests/fs/exists.test.ts +4 -4
- package/tests/fs/links.test.ts +4 -11
- package/tests/fs/open.test.ts +4 -4
- package/tests/fs/permissions.test.ts +15 -15
- package/tests/fs/read.test.ts +9 -9
- package/tests/fs/readFile.test.ts +9 -9
- package/tests/fs/rename.test.ts +8 -8
- package/tests/fs/scaling.test.ts +4 -4
- package/tests/fs/stat.test.ts +20 -20
- package/tests/fs/streams.test.ts +9 -6
- package/tests/fs/tempdir.test.ts +33 -10
- package/tests/fs/times.test.ts +11 -11
- package/tests/fs/truncate.test.ts +6 -6
- package/tests/fs/watch.test.ts +107 -53
- package/tests/fs/write.test.ts +10 -10
- package/tests/fs/xattr.test.ts +3 -3
- package/tests/native/run.sh +3 -0
- package/tests/native/setup.ts +230 -0
- package/types/readable-stream.d.ts +2 -2
|
@@ -1,14 +1,14 @@
|
|
|
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.js';
|
|
4
|
+
import { config, fs } from '../common.js';
|
|
5
5
|
|
|
6
6
|
suite('Reading', () => {
|
|
7
|
-
test('Cannot read a file with an invalid encoding', () => {
|
|
7
|
+
test('Cannot read a file with an invalid encoding', config('sync'), () => {
|
|
8
8
|
assert.throws(() => fs.readFileSync('a.js', 'wrong-encoding' as BufferEncoding));
|
|
9
9
|
});
|
|
10
10
|
|
|
11
|
-
test('Reading past the end of a file should not be an error', async () => {
|
|
11
|
+
test('Reading past the end of a file should not be an error', config('async'), async () => {
|
|
12
12
|
const 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);
|
|
@@ -18,35 +18,35 @@ suite('Reading', () => {
|
|
|
18
18
|
const file = 'test-readfile-unlink/test.bin';
|
|
19
19
|
const data = new Uint8Array(512).fill(42);
|
|
20
20
|
|
|
21
|
-
test('create directory and write file', async () => {
|
|
21
|
+
test('create directory and write file', config('async', 'write', 'directories'), async () => {
|
|
22
22
|
await fs.promises.mkdir(dir);
|
|
23
23
|
await fs.promises.writeFile(file, data);
|
|
24
24
|
});
|
|
25
25
|
|
|
26
|
-
test('read file and verify its content', async () => {
|
|
26
|
+
test('read file and verify its content', config('async'), async () => {
|
|
27
27
|
const read: Uint8Array = await fs.promises.readFile(file);
|
|
28
28
|
assert.equal(read.length, data.length);
|
|
29
29
|
assert.equal(read[0], 42);
|
|
30
30
|
});
|
|
31
31
|
|
|
32
|
-
test('unlink file and remove directory', async () => {
|
|
32
|
+
test('unlink file and remove directory', config('async', 'write', 'directories'), async () => {
|
|
33
33
|
await fs.promises.unlink(file);
|
|
34
34
|
await fs.promises.rmdir(dir);
|
|
35
35
|
});
|
|
36
36
|
|
|
37
37
|
const fileName = 'empty.txt';
|
|
38
38
|
|
|
39
|
-
test('read file', async () => {
|
|
39
|
+
test('read file', config('sync', 'async'), async () => {
|
|
40
40
|
assert.equal((await fs.promises.readFile(fileName)).toString(), '');
|
|
41
41
|
assert.equal(fs.readFileSync(fileName).toString(), '');
|
|
42
42
|
});
|
|
43
43
|
|
|
44
|
-
test('read file with utf-8 encoding', async () => {
|
|
44
|
+
test('read file with utf-8 encoding', config('sync', 'async'), async () => {
|
|
45
45
|
assert.equal(await fs.promises.readFile(fileName, 'utf8'), '');
|
|
46
46
|
assert.equal(fs.readFileSync(fileName, 'utf8'), '');
|
|
47
47
|
});
|
|
48
48
|
|
|
49
|
-
test('read file synchronously and verify the content', () => {
|
|
49
|
+
test('read file synchronously and verify the content', config('sync'), () => {
|
|
50
50
|
const content = fs.readFileSync('elipses.txt', 'utf8');
|
|
51
51
|
|
|
52
52
|
assert.equal(content.length, 10000);
|
package/tests/fs/rename.test.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
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.js';
|
|
4
|
+
import { config, fs } from '../common.js';
|
|
5
5
|
|
|
6
|
-
suite('Rename', () => {
|
|
6
|
+
suite('Rename', config('rename'), () => {
|
|
7
7
|
/**
|
|
8
8
|
* Creates the following directory structure within `dir`:
|
|
9
9
|
* - _rename_me
|
|
@@ -30,7 +30,7 @@ suite('Rename', () => {
|
|
|
30
30
|
assert(await fs.promises.exists(dir + '/_rename_me/lol.txt'));
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
test('rename directory', async () => {
|
|
33
|
+
test('rename directory', config('async'), async () => {
|
|
34
34
|
const oldDir = '/rename_test';
|
|
35
35
|
const newDir = '/rename_test2';
|
|
36
36
|
|
|
@@ -53,7 +53,7 @@ suite('Rename', () => {
|
|
|
53
53
|
await fs.promises.rename(oldDir, newDir + '/newDir');
|
|
54
54
|
});
|
|
55
55
|
|
|
56
|
-
test('rename file', async () => {
|
|
56
|
+
test('rename file', config('async'), async () => {
|
|
57
57
|
const dir = '/rename_file_test';
|
|
58
58
|
const one = dir + '/fun.js';
|
|
59
59
|
const two = dir + '/fun2.js';
|
|
@@ -70,7 +70,7 @@ suite('Rename', () => {
|
|
|
70
70
|
assert(!(await fs.promises.exists(one)));
|
|
71
71
|
});
|
|
72
72
|
|
|
73
|
-
test('File to Directory and Directory to File Rename', async () => {
|
|
73
|
+
test('File to Directory and Directory to File Rename', config('sync', 'async'), async () => {
|
|
74
74
|
const dir = '/rename_file_dir_test';
|
|
75
75
|
const file = '/rename_file_dir_test.txt';
|
|
76
76
|
|
|
@@ -81,13 +81,13 @@ suite('Rename', () => {
|
|
|
81
81
|
assert.throws(() => fs.renameSync(file, dir), { code: 'EISDIR' });
|
|
82
82
|
});
|
|
83
83
|
|
|
84
|
-
test('rename directory inside itself', async () => {
|
|
84
|
+
test('rename directory inside itself', config('sync', 'async'), async () => {
|
|
85
85
|
const renDir1 = '/rename_dir_1';
|
|
86
86
|
const renDir2 = '/rename_dir_1/lol';
|
|
87
87
|
|
|
88
88
|
await fs.promises.mkdir(renDir1);
|
|
89
89
|
|
|
90
|
-
await assert.rejects(fs.promises.rename(renDir1, renDir2), { code: '
|
|
91
|
-
assert.throws(() => fs.renameSync(renDir1, renDir2), { code: '
|
|
90
|
+
await assert.rejects(fs.promises.rename(renDir1, renDir2), { code: 'EINVAL' });
|
|
91
|
+
assert.throws(() => fs.renameSync(renDir1, renDir2), { code: 'EINVAL' });
|
|
92
92
|
});
|
|
93
93
|
});
|
package/tests/fs/scaling.test.ts
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
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 { fs } from '../common.js';
|
|
5
|
+
import { config, fs } from '../common.js';
|
|
6
6
|
|
|
7
7
|
const n_files = 130;
|
|
8
8
|
const huge_size = 0x1000000;
|
|
9
9
|
|
|
10
10
|
// Tests for having a lot of various things (number of inodes/files, individual file size, etc.).
|
|
11
|
-
suite('Scaling', () => {
|
|
12
|
-
test('Lots of inodes/files', async () => {
|
|
11
|
+
suite('Scaling', config('write'), () => {
|
|
12
|
+
test('Lots of inodes/files', config('sync', 'async'), async () => {
|
|
13
13
|
fs.mkdirSync('/n');
|
|
14
14
|
|
|
15
15
|
for (let i = 0; i < n_files; i++) {
|
|
@@ -28,7 +28,7 @@ suite('Scaling', () => {
|
|
|
28
28
|
await Promise.all(results);
|
|
29
29
|
});
|
|
30
30
|
|
|
31
|
-
test('Singular file size', () => {
|
|
31
|
+
test('Singular file size', config('sync'), () => {
|
|
32
32
|
fs.writeFileSync('/huge', new Uint8Array(huge_size));
|
|
33
33
|
assert.equal(fs.statSync('/huge').size, huge_size);
|
|
34
34
|
});
|
package/tests/fs/stat.test.ts
CHANGED
|
@@ -1,41 +1,41 @@
|
|
|
1
1
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
2
|
-
import { defaultContext,
|
|
2
|
+
import { defaultContext, hasAccess } from '@zenfs/core';
|
|
3
3
|
import assert from 'node:assert/strict';
|
|
4
4
|
import { suite, test } from 'node:test';
|
|
5
|
-
import { fs } from '../common.js';
|
|
5
|
+
import { config, fs } from '../common.js';
|
|
6
6
|
|
|
7
7
|
suite('Stats', () => {
|
|
8
8
|
const existing_file = 'x.txt';
|
|
9
9
|
|
|
10
|
-
test('stat empty path', async () => {
|
|
10
|
+
test('stat empty path', config('async'), async () => {
|
|
11
11
|
await assert.rejects(fs.promises.stat(''));
|
|
12
12
|
});
|
|
13
13
|
|
|
14
|
-
test('stat directory', async () => {
|
|
14
|
+
test('stat directory', config('async'), async () => {
|
|
15
15
|
const stats = await fs.promises.stat('/');
|
|
16
|
-
assert(stats instanceof Stats);
|
|
16
|
+
assert(stats instanceof fs.Stats);
|
|
17
17
|
});
|
|
18
18
|
|
|
19
|
-
test('lstat directory', async () => {
|
|
19
|
+
test('lstat directory', config('async'), async () => {
|
|
20
20
|
const stats = await fs.promises.lstat('/');
|
|
21
|
-
assert(stats instanceof Stats);
|
|
21
|
+
assert(stats instanceof fs.Stats);
|
|
22
22
|
});
|
|
23
23
|
|
|
24
|
-
test('FileHandle.stat', async () => {
|
|
24
|
+
test('FileHandle.stat', config('async'), async () => {
|
|
25
25
|
const handle = await fs.promises.open(existing_file, 'r');
|
|
26
26
|
const stats = await handle.stat();
|
|
27
|
-
assert(stats instanceof Stats);
|
|
27
|
+
assert(stats instanceof fs.Stats);
|
|
28
28
|
await handle.close();
|
|
29
29
|
});
|
|
30
30
|
|
|
31
|
-
test('fstatSync file', () => {
|
|
31
|
+
test('fstatSync file', config('sync'), () => {
|
|
32
32
|
const fd = fs.openSync(existing_file, 'r');
|
|
33
33
|
const stats = fs.fstatSync(fd);
|
|
34
|
-
assert(stats instanceof Stats);
|
|
34
|
+
assert(stats instanceof fs.Stats);
|
|
35
35
|
fs.close(fd);
|
|
36
36
|
});
|
|
37
37
|
|
|
38
|
-
test('hasAccess for non-root access', () => {
|
|
38
|
+
test('hasAccess for non-root access', config('sync', 'permissions'), () => {
|
|
39
39
|
const newFile = 'new.txt';
|
|
40
40
|
|
|
41
41
|
fs.writeFileSync(newFile, 'hello', { mode: 0o640 });
|
|
@@ -58,21 +58,21 @@ suite('Stats', () => {
|
|
|
58
58
|
|
|
59
59
|
assert.equal(stat.gid, nonRootCredentials.gid);
|
|
60
60
|
assert.equal(stat.uid, 0);
|
|
61
|
-
assert.equal(
|
|
62
|
-
assert.equal(
|
|
63
|
-
assert.equal(
|
|
61
|
+
assert.equal(hasAccess(defaultContext, stat, fs.constants.R_OK), true);
|
|
62
|
+
assert.equal(hasAccess(defaultContext, stat, fs.constants.W_OK), false);
|
|
63
|
+
assert.equal(hasAccess(defaultContext, stat, fs.constants.X_OK), false);
|
|
64
64
|
// changing group
|
|
65
65
|
|
|
66
66
|
Object.assign(defaultContext.credentials, { ...nonRootCredentials, gid: 44 });
|
|
67
67
|
|
|
68
|
-
assert.equal(
|
|
69
|
-
assert.equal(
|
|
70
|
-
assert.equal(
|
|
68
|
+
assert.equal(hasAccess(defaultContext, stat, fs.constants.R_OK), false);
|
|
69
|
+
assert.equal(hasAccess(defaultContext, stat, fs.constants.W_OK), false);
|
|
70
|
+
assert.equal(hasAccess(defaultContext, stat, fs.constants.X_OK), false);
|
|
71
71
|
|
|
72
72
|
Object.assign(defaultContext.credentials, prevCredentials);
|
|
73
73
|
});
|
|
74
74
|
|
|
75
|
-
test('stat file', async () => {
|
|
75
|
+
test('stat file', config('async'), async () => {
|
|
76
76
|
const stats = await fs.promises.stat(existing_file);
|
|
77
77
|
assert(!stats.isDirectory());
|
|
78
78
|
assert(stats.isFile());
|
|
@@ -81,6 +81,6 @@ suite('Stats', () => {
|
|
|
81
81
|
assert(!stats.isCharacterDevice());
|
|
82
82
|
assert(!stats.isFIFO());
|
|
83
83
|
assert(!stats.isSymbolicLink());
|
|
84
|
-
assert(stats instanceof Stats);
|
|
84
|
+
assert(stats instanceof fs.Stats);
|
|
85
85
|
});
|
|
86
86
|
});
|
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 { fs } from '../common.js';
|
|
4
|
+
import { config, fs } from '../common.js';
|
|
5
5
|
|
|
6
6
|
// Top-level initialization
|
|
7
7
|
const testFilePath = 'test-file.txt';
|
|
@@ -11,7 +11,7 @@ await fs.promises.writeFile(testFilePath, testData);
|
|
|
11
11
|
const testFilePathWrite = 'test-file-write.txt';
|
|
12
12
|
await fs.promises.writeFile(testFilePathWrite, ''); // Ensure the file exists
|
|
13
13
|
|
|
14
|
-
suite('Streams', () => {
|
|
14
|
+
suite('Streams', config('streams'), () => {
|
|
15
15
|
test('ReadStream reads data correctly', (_, done) => {
|
|
16
16
|
const readStream = fs.createReadStream(testFilePath);
|
|
17
17
|
|
|
@@ -36,8 +36,9 @@ suite('Streams', () => {
|
|
|
36
36
|
closed = true;
|
|
37
37
|
});
|
|
38
38
|
|
|
39
|
+
// Closing before the stream has finished reading is a premature close
|
|
39
40
|
readStream.close(err => {
|
|
40
|
-
assert.
|
|
41
|
+
assert.equal((err as NodeJS.ErrnoException | null)?.code, 'ERR_STREAM_PREMATURE_CLOSE');
|
|
41
42
|
assert(closed);
|
|
42
43
|
done();
|
|
43
44
|
});
|
|
@@ -81,7 +82,7 @@ suite('Streams', () => {
|
|
|
81
82
|
test('createReadStream with end', async () => {
|
|
82
83
|
await fs.promises.writeFile('hello.txt', 'Hello world');
|
|
83
84
|
|
|
84
|
-
const stream = fs.createReadStream('hello.txt', { end:
|
|
85
|
+
const stream = fs.createReadStream('hello.txt', { end: 4, encoding: 'utf-8' });
|
|
85
86
|
|
|
86
87
|
const data = (await stream.toArray()).join('');
|
|
87
88
|
|
|
@@ -130,12 +131,14 @@ suite('Streams', () => {
|
|
|
130
131
|
test('FileHandle.createReadStream after close should give an error', async () => {
|
|
131
132
|
const fileHandle = await fs.promises.open(testFilePath, 'r');
|
|
132
133
|
await fileHandle.close();
|
|
133
|
-
|
|
134
|
+
// Closing invalidates the descriptor, so it fails range validation
|
|
135
|
+
assert.throws(() => fileHandle.createReadStream(), { code: 'ERR_OUT_OF_RANGE' });
|
|
134
136
|
});
|
|
135
137
|
|
|
136
138
|
test('FileHandle.createWriteStream after close should give an error', async () => {
|
|
137
139
|
const fileHandle = await fs.promises.open(testFilePathWrite, 'w');
|
|
138
140
|
await fileHandle.close();
|
|
139
|
-
|
|
141
|
+
// Closing invalidates the descriptor, so it fails range validation
|
|
142
|
+
assert.throws(() => fileHandle.createWriteStream(), { code: 'ERR_OUT_OF_RANGE' });
|
|
140
143
|
});
|
|
141
144
|
});
|
package/tests/fs/tempdir.test.ts
CHANGED
|
@@ -1,41 +1,64 @@
|
|
|
1
1
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
2
2
|
import { test, suite } from 'node:test';
|
|
3
|
-
import { fs } from '../common.js';
|
|
3
|
+
import { config, fs } from '../common.js';
|
|
4
4
|
import assert from 'node:assert/strict';
|
|
5
5
|
import { basename } from 'node:path/posix';
|
|
6
6
|
|
|
7
7
|
await fs.promises.mkdir('/tmp');
|
|
8
8
|
|
|
9
|
-
suite('Temporary Directories', () => {
|
|
10
|
-
test('mkdtempSync', () => {
|
|
11
|
-
const path = fs.mkdtempSync('test-', { encoding: 'utf8' });
|
|
9
|
+
suite('Temporary Directories', config('tempdir'), () => {
|
|
10
|
+
test('mkdtempSync', config('sync'), () => {
|
|
11
|
+
const path = fs.mkdtempSync('/tmp/test-', { encoding: 'utf8' });
|
|
12
12
|
|
|
13
13
|
assert.deepEqual(fs.readdirSync('/tmp'), [basename(path)]);
|
|
14
14
|
|
|
15
15
|
fs.rmdirSync(path);
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
-
test('mkdtemp', async () => {
|
|
19
|
-
const path = await fs.promises.mkdtemp('test-', { encoding: 'utf8' });
|
|
18
|
+
test('mkdtemp', config('async'), async () => {
|
|
19
|
+
const path = await fs.promises.mkdtemp('/tmp/test-', { encoding: 'utf8' });
|
|
20
20
|
|
|
21
21
|
assert.deepEqual(await fs.promises.readdir('/tmp'), [basename(path)]);
|
|
22
22
|
|
|
23
23
|
await fs.promises.rmdir(path);
|
|
24
24
|
});
|
|
25
25
|
|
|
26
|
-
test('mkdtempDisposableSync', () => {
|
|
27
|
-
using result = fs.mkdtempDisposableSync('test-', { encoding: 'utf8' });
|
|
26
|
+
test('mkdtempDisposableSync', config('sync'), () => {
|
|
27
|
+
using result = fs.mkdtempDisposableSync('/tmp/test-', { encoding: 'utf8' });
|
|
28
28
|
|
|
29
29
|
assert.deepEqual(fs.readdirSync('/tmp'), [basename(result.path)]);
|
|
30
30
|
|
|
31
31
|
fs.rmdirSync(result.path);
|
|
32
32
|
});
|
|
33
33
|
|
|
34
|
-
test('mkdtempDisposable', async () => {
|
|
35
|
-
await using result = await fs.promises.mkdtempDisposable('test-', { encoding: 'utf8' });
|
|
34
|
+
test('mkdtempDisposable', config('async'), async () => {
|
|
35
|
+
await using result = await fs.promises.mkdtempDisposable('/tmp/test-', { encoding: 'utf8' });
|
|
36
36
|
|
|
37
37
|
assert.deepEqual(await fs.promises.readdir('/tmp'), [basename(result.path)]);
|
|
38
38
|
|
|
39
39
|
await fs.promises.rmdir(result.path);
|
|
40
40
|
});
|
|
41
|
+
|
|
42
|
+
/* A relative prefix is resolved against the working directory, rather than always being placed in `/tmp`.
|
|
43
|
+
Note the returned path keeps the prefix it was given, so it is only compared by basename here. */
|
|
44
|
+
|
|
45
|
+
test('mkdtempSync with a relative prefix', config('sync'), () => {
|
|
46
|
+
const path = fs.mkdtempSync('tmp/relative-', { encoding: 'utf8' });
|
|
47
|
+
|
|
48
|
+
assert(basename(path).startsWith('relative-'));
|
|
49
|
+
assert(fs.statSync(path).isDirectory());
|
|
50
|
+
assert(fs.readdirSync('/tmp').includes(basename(path)));
|
|
51
|
+
|
|
52
|
+
fs.rmdirSync(path);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test('mkdtemp with a relative prefix', config('async'), async () => {
|
|
56
|
+
const path = await fs.promises.mkdtemp('tmp/relative-', { encoding: 'utf8' });
|
|
57
|
+
|
|
58
|
+
assert(basename(path).startsWith('relative-'));
|
|
59
|
+
assert((await fs.promises.stat(path)).isDirectory());
|
|
60
|
+
assert((await fs.promises.readdir('/tmp')).includes(basename(path)));
|
|
61
|
+
|
|
62
|
+
await fs.promises.rmdir(path);
|
|
63
|
+
});
|
|
41
64
|
});
|
package/tests/fs/times.test.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
2
2
|
import type { StatsLike } from '@zenfs/core';
|
|
3
|
-
import { Exception } from 'kerium';
|
|
3
|
+
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 { fs } from '../common.js';
|
|
7
|
+
import { config, fs } from '../common.js';
|
|
8
8
|
|
|
9
9
|
const path = 'x.txt';
|
|
10
10
|
|
|
@@ -20,11 +20,12 @@ export function unixTimestamps(stats: StatsLike<number>): Record<'atime' | 'mtim
|
|
|
20
20
|
};
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
suite('Times', () => {
|
|
23
|
+
suite('Times', config('times'), () => {
|
|
24
24
|
async function runTest(atime: Date | number, mtime: Date | number): Promise<void> {
|
|
25
|
+
// Numbers are seconds since the epoch, while `Date`s and stats are in milliseconds
|
|
25
26
|
const times = {
|
|
26
|
-
atime: typeof atime == 'number' ? Math.floor(atime) : atime.getTime(),
|
|
27
|
-
mtime: typeof mtime == 'number' ? Math.floor(mtime) : mtime.getTime(),
|
|
27
|
+
atime: typeof atime == 'number' ? Math.floor(atime * 1000) : atime.getTime(),
|
|
28
|
+
mtime: typeof mtime == 'number' ? Math.floor(mtime * 1000) : mtime.getTime(),
|
|
28
29
|
};
|
|
29
30
|
|
|
30
31
|
await fs.promises.utimes(path, atime, mtime);
|
|
@@ -32,7 +33,7 @@ suite('Times', () => {
|
|
|
32
33
|
assert.deepEqual(unixTimestamps(await fs.promises.stat(path)), times);
|
|
33
34
|
|
|
34
35
|
await fs.promises.utimes('foobarbaz', atime, mtime).catch((error: Exception) => {
|
|
35
|
-
assert(error instanceof
|
|
36
|
+
assert(error instanceof Error);
|
|
36
37
|
assert.equal(error.code, 'ENOENT');
|
|
37
38
|
});
|
|
38
39
|
|
|
@@ -47,15 +48,14 @@ suite('Times', () => {
|
|
|
47
48
|
try {
|
|
48
49
|
fs.utimesSync('foobarbaz', atime, mtime);
|
|
49
50
|
} catch (error: any) {
|
|
50
|
-
assert(error instanceof Exception);
|
|
51
51
|
assert.equal(error.code, 'ENOENT');
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
try {
|
|
55
55
|
fs.futimesSync(-1, atime, mtime);
|
|
56
56
|
} catch (error: any) {
|
|
57
|
-
|
|
58
|
-
assert.equal(error.code, '
|
|
57
|
+
// A negative descriptor fails range validation before it is looked up
|
|
58
|
+
assert.equal(error.code, 'ERR_OUT_OF_RANGE');
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
|
|
@@ -67,7 +67,7 @@ suite('Times', () => {
|
|
|
67
67
|
await test('from stats', () => runTest(stats.atime, stats.mtime));
|
|
68
68
|
});
|
|
69
69
|
|
|
70
|
-
test('read changes atime', async () => {
|
|
70
|
+
test('read changes atime', config('sync'), async () => {
|
|
71
71
|
const before = fs.statSync(path).atimeMs;
|
|
72
72
|
fs.readFileSync(path);
|
|
73
73
|
await wait(25);
|
|
@@ -75,7 +75,7 @@ suite('Times', () => {
|
|
|
75
75
|
assert(before < after);
|
|
76
76
|
});
|
|
77
77
|
|
|
78
|
-
test('write changes mtime', async () => {
|
|
78
|
+
test('write changes mtime', config('sync', 'write'), async () => {
|
|
79
79
|
const before = fs.statSync(path).mtimeMs;
|
|
80
80
|
fs.writeFileSync(path, 'cool');
|
|
81
81
|
await wait(25);
|
|
@@ -1,14 +1,14 @@
|
|
|
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.js';
|
|
4
|
+
import { config, fs } from '../common.js';
|
|
5
5
|
|
|
6
6
|
const path: string = 'truncate-file.txt',
|
|
7
7
|
size = 1024 * 16,
|
|
8
8
|
data = new Uint8Array(size).fill('x'.charCodeAt(0));
|
|
9
9
|
|
|
10
|
-
suite('Truncating', () => {
|
|
11
|
-
test('Sync path functions', () => {
|
|
10
|
+
suite('Truncating', config('truncate'), () => {
|
|
11
|
+
test('Sync path functions', config('sync'), () => {
|
|
12
12
|
fs.writeFileSync(path, data);
|
|
13
13
|
assert.equal(fs.statSync(path).size, size);
|
|
14
14
|
|
|
@@ -22,7 +22,7 @@ suite('Truncating', () => {
|
|
|
22
22
|
assert.equal(fs.statSync(path).size, size);
|
|
23
23
|
});
|
|
24
24
|
|
|
25
|
-
test('FD functions', () => {
|
|
25
|
+
test('FD functions', config('sync'), () => {
|
|
26
26
|
const fd = fs.openSync(path, 'r+');
|
|
27
27
|
|
|
28
28
|
fs.ftruncateSync(fd, 1024);
|
|
@@ -36,7 +36,7 @@ suite('Truncating', () => {
|
|
|
36
36
|
|
|
37
37
|
const statSize = async (path: string) => (await fs.promises.stat(path)).size;
|
|
38
38
|
|
|
39
|
-
test('Async path functions', async () => {
|
|
39
|
+
test('Async path functions', config('async'), async () => {
|
|
40
40
|
await fs.promises.writeFile(path, data);
|
|
41
41
|
|
|
42
42
|
assert.equal(await statSize(path), 1024 * 16);
|
|
@@ -51,7 +51,7 @@ suite('Truncating', () => {
|
|
|
51
51
|
assert.equal(await statSize(path), size);
|
|
52
52
|
});
|
|
53
53
|
|
|
54
|
-
test('FileHandle', async () => {
|
|
54
|
+
test('FileHandle', config('async'), async () => {
|
|
55
55
|
const handle = await fs.promises.open(path, 'w');
|
|
56
56
|
|
|
57
57
|
await handle.truncate(1024);
|