Skip to content

Commit 9a1ca04

Browse files
committed
test: rename and split VFS test files into topic-based names
Replaces the -coverage / -branches / -misc suffixes with focused files named after the API or behaviour they exercise. Splits the larger multi-topic files into one-topic-per-file. Renames: - callbacks.js → callback-api.js - stats-defaults.js → stats-helpers.js - file-handle-base.js → virtual-file-handle.js - provider-base.js → virtual-provider.js - provider-memory.js → memory-provider.js - real-provider-async.js → real-provider-promises.js - mkdir-recursive-return.js → mkdir.js New files (split out of -coverage/-branches/-misc): - access-modes, create, link, mkdtemp, rename, symlinks, utimes, write-options - memory-file-handle, memory-provider-dynamic, memory-provider-flags - real-provider-handle, real-provider-symlinks, real-provider-watch - stream-errors, stream-explicit-fd - watch, watch-abort-signal, watch-encoding, watch-promises, watch-recursive Coverage maintained at 97.6% line / 95.2% branch / 95.3% function. Assisted-by: Claude-Opus4.7
1 parent a4a85f2 commit 9a1ca04

49 files changed

Lines changed: 1669 additions & 2208 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
'use strict';
2+
3+
// access / accessSync honour the R_OK / W_OK / X_OK / F_OK mode bits and
4+
// throw EACCES when the file's permission bits don't allow the request.
5+
6+
const common = require('../common');
7+
const assert = require('assert');
8+
const fs = require('fs');
9+
const vfs = require('node:vfs');
10+
11+
const { R_OK, W_OK, X_OK } = fs.constants;
12+
13+
const myVfs = vfs.create();
14+
15+
// No read permission (mode 0o222 → owner has W only)
16+
myVfs.writeFileSync('/no-r.txt', 'x');
17+
myVfs.chmodSync('/no-r.txt', 0o222);
18+
assert.throws(() => myVfs.accessSync('/no-r.txt', R_OK), { code: 'EACCES' });
19+
assert.rejects(myVfs.promises.access('/no-r.txt', R_OK),
20+
{ code: 'EACCES' }).then(common.mustCall());
21+
22+
// No write permission (mode 0o444 → owner has R only)
23+
myVfs.writeFileSync('/no-w.txt', 'x');
24+
myVfs.chmodSync('/no-w.txt', 0o444);
25+
assert.throws(() => myVfs.accessSync('/no-w.txt', W_OK), { code: 'EACCES' });
26+
assert.rejects(myVfs.promises.access('/no-w.txt', W_OK),
27+
{ code: 'EACCES' }).then(common.mustCall());
28+
29+
// No execute permission (mode 0o644)
30+
myVfs.writeFileSync('/no-x.txt', 'x');
31+
myVfs.chmodSync('/no-x.txt', 0o644);
32+
assert.throws(() => myVfs.accessSync('/no-x.txt', X_OK), { code: 'EACCES' });
33+
assert.rejects(myVfs.promises.access('/no-x.txt', X_OK),
34+
{ code: 'EACCES' }).then(common.mustCall());
35+
36+
// F_OK (mode 0) is an existence-only check and does not require permission
37+
myVfs.accessSync('/no-r.txt', 0);
38+
39+
// mode passed as null also exits early (existence-only)
40+
myVfs.accessSync('/no-r.txt', null);

test/parallel/test-vfs-create.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
'use strict';
2+
3+
// Constructor variants and option validation for vfs.create() and
4+
// `new VirtualFileSystem(...)`.
5+
6+
require('../common');
7+
const assert = require('assert');
8+
const vfs = require('node:vfs');
9+
10+
// vfs.create() with no arguments uses the default MemoryProvider
11+
{
12+
const myVfs = vfs.create();
13+
assert.ok(myVfs.provider instanceof vfs.MemoryProvider);
14+
}
15+
16+
// vfs.create with first arg as options object (no provider)
17+
{
18+
const myVfs = vfs.create({ emitExperimentalWarning: false });
19+
assert.ok(myVfs);
20+
assert.ok(myVfs.provider instanceof vfs.MemoryProvider);
21+
}
22+
23+
// vfs.create with explicit provider
24+
{
25+
const provider = new vfs.MemoryProvider();
26+
const myVfs = vfs.create(provider);
27+
assert.strictEqual(myVfs.provider, provider);
28+
}
29+
30+
// new VirtualFileSystem(options) directly
31+
{
32+
const myVfs = new vfs.VirtualFileSystem({ emitExperimentalWarning: false });
33+
assert.ok(myVfs);
34+
}
35+
36+
// emitExperimentalWarning option must be a boolean
37+
{
38+
assert.throws(
39+
() => new vfs.VirtualFileSystem({ emitExperimentalWarning: 'not-bool' }),
40+
{ code: 'ERR_INVALID_ARG_TYPE' });
41+
}
42+
43+
// existsSync swallows ALL errors from the provider, not just ENOENT
44+
{
45+
class ThrowingProvider extends vfs.VirtualProvider {
46+
existsSync() { throw new Error('boom'); }
47+
}
48+
const myVfs = vfs.create(new ThrowingProvider());
49+
assert.strictEqual(myVfs.existsSync('/anything'), false);
50+
}
51+
52+
// Walking a path through a regular-file parent throws ENOTDIR
53+
{
54+
const myVfs = vfs.create();
55+
myVfs.writeFileSync('/file.txt', 'x');
56+
assert.throws(() => myVfs.writeFileSync('/file.txt/oops', 'y'),
57+
{ code: 'ENOTDIR' });
58+
}
59+
60+
// statSync('/') returns the root directory
61+
{
62+
const myVfs = vfs.create();
63+
assert.ok(myVfs.statSync('/').isDirectory());
64+
}

test/parallel/test-vfs-dir-handle.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,37 @@ myVfs.opendir('/d', common.mustCall((err, dir) => {
7171
assert.strictEqual(dir.path, '/d');
7272
dir.closeSync();
7373
}));
74+
75+
// read() callback on a closed dir delivers ERR_DIR_CLOSED
76+
{
77+
const dir = myVfs.opendirSync('/d');
78+
dir.closeSync();
79+
dir.read(common.mustCall((err) => {
80+
assert.strictEqual(err.code, 'ERR_DIR_CLOSED');
81+
}));
82+
// entries() iteration on a closed dir rejects with ERR_DIR_CLOSED
83+
(async () => {
84+
await assert.rejects(
85+
(async () => { for await (const _ of dir.entries()) {} })(), // eslint-disable-line no-unused-vars
86+
{ code: 'ERR_DIR_CLOSED' });
87+
})().then(common.mustCall());
88+
// [Symbol.dispose] is a no-op on an already-closed dir (must not throw)
89+
dir[Symbol.dispose]();
90+
}
91+
92+
// async dir.close() returns a promise when invoked without a callback
93+
(async () => {
94+
const dir = myVfs.opendirSync('/d');
95+
await dir.close();
96+
})().then(common.mustCall());
97+
98+
// opendirSync without options object
99+
{
100+
const dir = myVfs.opendirSync('/d');
101+
dir.closeSync();
102+
}
103+
104+
// opendir error path (missing directory)
105+
myVfs.opendir('/missing-dir', common.mustCall((err) => {
106+
assert.ok(err);
107+
}));

test/parallel/test-vfs-file-handle-branches.js

Lines changed: 0 additions & 98 deletions
This file was deleted.

test/parallel/test-vfs-file-handle.js

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,3 +121,84 @@ myVfs.writeFileSync('/file.txt', 'hello world');
121121
{ code: 'EBADF' });
122122
await assert.rejects(handle.stat(), { code: 'EBADF' });
123123
})().then(common.mustCall());
124+
125+
// readv with a partial read at EOF (second buffer larger than remaining)
126+
(async () => {
127+
const handle = await myVfs.provider.open('/file.txt', 'r');
128+
const b1 = Buffer.alloc(5);
129+
const b2 = Buffer.alloc(20);
130+
const r = await handle.readv([b1, b2], 0);
131+
assert.strictEqual(b1.toString(), 'hello');
132+
assert.strictEqual(r.bytesRead, 11);
133+
await handle.close();
134+
})().then(common.mustCall());
135+
136+
// writev with explicit position 0
137+
(async () => {
138+
const wh = await myVfs.provider.open('/wv.txt', 'w+');
139+
await wh.writev([Buffer.from('AB'), Buffer.from('CD')], 0);
140+
await wh.close();
141+
assert.strictEqual(myVfs.readFileSync('/wv.txt', 'utf8'), 'ABCD');
142+
})().then(common.mustCall());
143+
144+
// appendFile with string + encoding option
145+
(async () => {
146+
const ah = await myVfs.provider.open('/ap.txt', 'a+');
147+
await ah.appendFile('hello', { encoding: 'utf8' });
148+
await ah.close();
149+
assert.strictEqual(myVfs.readFileSync('/ap.txt', 'utf8'), 'hello');
150+
})().then(common.mustCall());
151+
152+
// 'w'-mode handle rejects all read ops with EBADF
153+
(async () => {
154+
const handle = await myVfs.provider.open('/wonly.txt', 'w');
155+
assert.throws(() => handle.readSync(Buffer.alloc(1), 0, 1, 0),
156+
{ code: 'EBADF' });
157+
await assert.rejects(handle.read(Buffer.alloc(1), 0, 1, 0),
158+
{ code: 'EBADF' });
159+
assert.throws(() => handle.readFileSync(), { code: 'EBADF' });
160+
await assert.rejects(handle.readFile(), { code: 'EBADF' });
161+
await handle.close();
162+
})().then(common.mustCall());
163+
164+
// 'r'-mode handle rejects all write ops with EBADF
165+
(async () => {
166+
myVfs.writeFileSync('/ronly.txt', 'x');
167+
const handle = await myVfs.provider.open('/ronly.txt', 'r');
168+
assert.throws(() => handle.writeSync(Buffer.from('y'), 0, 1, 0),
169+
{ code: 'EBADF' });
170+
await assert.rejects(handle.write(Buffer.from('y'), 0, 1, 0),
171+
{ code: 'EBADF' });
172+
assert.throws(() => handle.writeFileSync('y'), { code: 'EBADF' });
173+
await assert.rejects(handle.writeFile('y'), { code: 'EBADF' });
174+
assert.throws(() => handle.truncateSync(0), { code: 'EBADF' });
175+
await assert.rejects(handle.truncate(0), { code: 'EBADF' });
176+
await handle.close();
177+
})().then(common.mustCall());
178+
179+
// writeFile with string + encoding
180+
(async () => {
181+
const handle = await myVfs.provider.open('/se.txt', 'w+');
182+
await handle.writeFile('héllo', { encoding: 'utf8' });
183+
assert.strictEqual(await handle.readFile('utf8'), 'héllo');
184+
await handle.close();
185+
})().then(common.mustCall());
186+
187+
// truncate extending past current size zero-fills
188+
(async () => {
189+
const handle = await myVfs.provider.open('/grow.txt', 'w+');
190+
await handle.writeFile('abc');
191+
await handle.truncate(10);
192+
assert.strictEqual((await handle.stat()).size, 10);
193+
assert.strictEqual((await handle.readFile()).length, 10);
194+
await handle.close();
195+
})().then(common.mustCall());
196+
197+
// readv / writev / appendFile on a closed handle reject with EBADF
198+
(async () => {
199+
const handle = await myVfs.provider.open('/file.txt', 'r');
200+
await handle.close();
201+
await assert.rejects(handle.readv([Buffer.alloc(1)], 0), { code: 'EBADF' });
202+
await assert.rejects(handle.writev([Buffer.alloc(1)], 0), { code: 'EBADF' });
203+
await assert.rejects(handle.appendFile('x'), { code: 'EBADF' });
204+
})().then(common.mustCall());

test/parallel/test-vfs-link.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
'use strict';
2+
3+
// Hard-link error cases: creating a link to a directory or to an
4+
// already-existing path.
5+
6+
require('../common');
7+
const assert = require('assert');
8+
const vfs = require('node:vfs');
9+
10+
// Linking to a directory throws EINVAL
11+
{
12+
const myVfs = vfs.create();
13+
myVfs.mkdirSync('/d');
14+
assert.throws(() => myVfs.linkSync('/d', '/d-link'), { code: 'EINVAL' });
15+
}
16+
17+
// Linking to an existing target throws EEXIST
18+
{
19+
const myVfs = vfs.create();
20+
myVfs.writeFileSync('/a.txt', 'x');
21+
myVfs.writeFileSync('/b.txt', 'y');
22+
assert.throws(() => myVfs.linkSync('/a.txt', '/b.txt'), { code: 'EEXIST' });
23+
}

0 commit comments

Comments
 (0)