mirror of
https://github.com/nodejs/node.git
synced 2026-10-28 10:15:07 +08:00
Signed-off-by: harjoth <harjoth.khara@gmail.com> Fixes: https://github.com/nodejs/node/issues/64401 Assisted-by: Codex PR-URL: https://github.com/nodejs/node/pull/64403 Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
708 lines
19 KiB
JavaScript
708 lines
19 KiB
JavaScript
// Flags: --disable-warning=ExperimentalWarning --expose-internals
|
|
'use strict';
|
|
|
|
const common = require('../common');
|
|
const assert = require('assert');
|
|
const vfs = require('node:vfs');
|
|
|
|
// Test MemoryProvider can be instantiated directly
|
|
{
|
|
const provider = new vfs.MemoryProvider();
|
|
assert.strictEqual(provider.readonly, false);
|
|
assert.strictEqual(provider.supportsSymlinks, true);
|
|
}
|
|
|
|
// Test creating VFS with MemoryProvider (default)
|
|
{
|
|
const myVfs = vfs.create();
|
|
assert.ok(myVfs);
|
|
assert.strictEqual(myVfs.readonly, false);
|
|
assert.ok(myVfs.provider instanceof vfs.MemoryProvider);
|
|
}
|
|
|
|
// Test creating VFS with explicit MemoryProvider
|
|
{
|
|
const myVfs = vfs.create(new vfs.MemoryProvider());
|
|
assert.ok(myVfs);
|
|
assert.strictEqual(myVfs.readonly, false);
|
|
}
|
|
|
|
// Test reading and writing files
|
|
{
|
|
const myVfs = vfs.create();
|
|
|
|
// Write a file
|
|
myVfs.writeFileSync('/hello.txt', 'Hello from VFS!');
|
|
|
|
// Read it back
|
|
assert.strictEqual(myVfs.readFileSync('/hello.txt', 'utf8'), 'Hello from VFS!');
|
|
|
|
// Read as Buffer
|
|
const buf = myVfs.readFileSync('/hello.txt');
|
|
assert.ok(Buffer.isBuffer(buf));
|
|
assert.strictEqual(buf.toString(), 'Hello from VFS!');
|
|
|
|
// Overwrite
|
|
myVfs.writeFileSync('/hello.txt', 'Overwritten');
|
|
assert.strictEqual(myVfs.readFileSync('/hello.txt', 'utf8'), 'Overwritten');
|
|
}
|
|
|
|
// Test appendFile
|
|
{
|
|
const myVfs = vfs.create();
|
|
|
|
myVfs.writeFileSync('/append.txt', 'start');
|
|
myVfs.appendFileSync('/append.txt', '-end');
|
|
assert.strictEqual(myVfs.readFileSync('/append.txt', 'utf8'), 'start-end');
|
|
|
|
// Append to non-existent file creates it
|
|
myVfs.appendFileSync('/new-append.txt', 'new content');
|
|
assert.strictEqual(myVfs.readFileSync('/new-append.txt', 'utf8'), 'new content');
|
|
}
|
|
|
|
// Test stat operations
|
|
{
|
|
const myVfs = vfs.create();
|
|
|
|
myVfs.writeFileSync('/stat-test.txt', 'content');
|
|
myVfs.mkdirSync('/stat-dir', { recursive: true });
|
|
|
|
const fileStat = myVfs.statSync('/stat-test.txt');
|
|
assert.strictEqual(fileStat.isFile(), true);
|
|
assert.strictEqual(fileStat.isDirectory(), false);
|
|
assert.strictEqual(fileStat.size, 7);
|
|
|
|
const dirStat = myVfs.statSync('/stat-dir');
|
|
assert.strictEqual(dirStat.isFile(), false);
|
|
assert.strictEqual(dirStat.isDirectory(), true);
|
|
|
|
// Test ENOENT
|
|
assert.throws(() => {
|
|
myVfs.statSync('/nonexistent');
|
|
}, { code: 'ENOENT' });
|
|
}
|
|
|
|
// Test lstatSync (same as statSync for memory provider since no real symlink following)
|
|
{
|
|
const myVfs = vfs.create();
|
|
|
|
myVfs.writeFileSync('/lstat.txt', 'lstat test');
|
|
|
|
const stat = myVfs.lstatSync('/lstat.txt');
|
|
assert.strictEqual(stat.isFile(), true);
|
|
}
|
|
|
|
// Test readdirSync
|
|
{
|
|
const myVfs = vfs.create();
|
|
|
|
myVfs.mkdirSync('/readdir-test/subdir', { recursive: true });
|
|
myVfs.writeFileSync('/readdir-test/a.txt', 'a');
|
|
myVfs.writeFileSync('/readdir-test/b.txt', 'b');
|
|
|
|
const entries = myVfs.readdirSync('/readdir-test');
|
|
assert.deepStrictEqual(entries.sort(), ['a.txt', 'b.txt', 'subdir']);
|
|
|
|
// With file types
|
|
const dirents = myVfs.readdirSync('/readdir-test', { withFileTypes: true });
|
|
assert.strictEqual(dirents.length, 3);
|
|
|
|
const fileEntry = dirents.find((d) => d.name === 'a.txt');
|
|
assert.ok(fileEntry);
|
|
assert.strictEqual(fileEntry.isFile(), true);
|
|
|
|
const dirEntry = dirents.find((d) => d.name === 'subdir');
|
|
assert.ok(dirEntry);
|
|
assert.strictEqual(dirEntry.isDirectory(), true);
|
|
|
|
// ENOENT for non-existent directory
|
|
assert.throws(() => {
|
|
myVfs.readdirSync('/nonexistent');
|
|
}, { code: 'ENOENT' });
|
|
|
|
// ENOTDIR for file
|
|
assert.throws(() => {
|
|
myVfs.readdirSync('/readdir-test/a.txt');
|
|
}, { code: 'ENOTDIR' });
|
|
}
|
|
|
|
// Test mkdir and rmdir
|
|
{
|
|
const myVfs = vfs.create();
|
|
|
|
myVfs.mkdirSync('/new-dir');
|
|
assert.strictEqual(myVfs.existsSync('/new-dir'), true);
|
|
assert.strictEqual(myVfs.statSync('/new-dir').isDirectory(), true);
|
|
|
|
myVfs.rmdirSync('/new-dir');
|
|
assert.strictEqual(myVfs.existsSync('/new-dir'), false);
|
|
|
|
// EEXIST for existing directory
|
|
myVfs.mkdirSync('/exists');
|
|
assert.throws(() => {
|
|
myVfs.mkdirSync('/exists');
|
|
}, { code: 'EEXIST' });
|
|
|
|
// ENOTEMPTY for non-empty directory
|
|
myVfs.mkdirSync('/nonempty');
|
|
myVfs.writeFileSync('/nonempty/file.txt', 'content');
|
|
assert.throws(() => {
|
|
myVfs.rmdirSync('/nonempty');
|
|
}, { code: 'ENOTEMPTY' });
|
|
}
|
|
|
|
// Test recursive mkdir
|
|
{
|
|
const myVfs = vfs.create();
|
|
|
|
myVfs.mkdirSync('/deep/nested/dir', { recursive: true });
|
|
assert.strictEqual(myVfs.existsSync('/deep/nested/dir'), true);
|
|
assert.strictEqual(myVfs.statSync('/deep/nested/dir').isDirectory(), true);
|
|
|
|
// Recursive on existing is OK
|
|
myVfs.mkdirSync('/deep/nested/dir', { recursive: true });
|
|
assert.strictEqual(myVfs.existsSync('/deep/nested/dir'), true);
|
|
}
|
|
|
|
// Test unlink
|
|
{
|
|
const myVfs = vfs.create();
|
|
|
|
myVfs.writeFileSync('/to-delete.txt', 'delete me');
|
|
assert.strictEqual(myVfs.existsSync('/to-delete.txt'), true);
|
|
|
|
myVfs.unlinkSync('/to-delete.txt');
|
|
assert.strictEqual(myVfs.existsSync('/to-delete.txt'), false);
|
|
|
|
// ENOENT for non-existent file
|
|
assert.throws(() => {
|
|
myVfs.unlinkSync('/nonexistent.txt');
|
|
}, { code: 'ENOENT' });
|
|
|
|
// EISDIR for directory
|
|
myVfs.mkdirSync('/dir-to-unlink');
|
|
assert.throws(() => {
|
|
myVfs.unlinkSync('/dir-to-unlink');
|
|
}, { code: 'EISDIR' });
|
|
}
|
|
|
|
// Test rename
|
|
{
|
|
const myVfs = vfs.create();
|
|
|
|
myVfs.writeFileSync('/old-name.txt', 'rename me');
|
|
myVfs.renameSync('/old-name.txt', '/new-name.txt');
|
|
|
|
assert.strictEqual(myVfs.existsSync('/old-name.txt'), false);
|
|
assert.strictEqual(myVfs.existsSync('/new-name.txt'), true);
|
|
assert.strictEqual(myVfs.readFileSync('/new-name.txt', 'utf8'), 'rename me');
|
|
|
|
// ENOENT for non-existent source
|
|
assert.throws(() => {
|
|
myVfs.renameSync('/nonexistent.txt', '/dest.txt');
|
|
}, { code: 'ENOENT' });
|
|
}
|
|
|
|
// Test copyFile
|
|
{
|
|
const myVfs = vfs.create();
|
|
|
|
myVfs.writeFileSync('/source.txt', 'copy me');
|
|
myVfs.copyFileSync('/source.txt', '/dest.txt');
|
|
|
|
assert.strictEqual(myVfs.existsSync('/source.txt'), true);
|
|
assert.strictEqual(myVfs.existsSync('/dest.txt'), true);
|
|
assert.strictEqual(myVfs.readFileSync('/dest.txt', 'utf8'), 'copy me');
|
|
|
|
// ENOENT for non-existent source
|
|
assert.throws(() => {
|
|
myVfs.copyFileSync('/nonexistent.txt', '/fail.txt');
|
|
}, { code: 'ENOENT' });
|
|
}
|
|
|
|
// Test realpathSync
|
|
{
|
|
const myVfs = vfs.create();
|
|
|
|
myVfs.mkdirSync('/path/to', { recursive: true });
|
|
myVfs.writeFileSync('/path/to/real.txt', 'content');
|
|
|
|
const resolved = myVfs.realpathSync('/path/to/real.txt');
|
|
assert.strictEqual(resolved, '/path/to/real.txt');
|
|
|
|
// With .. components
|
|
const normalized = myVfs.realpathSync('/path/to/../to/real.txt');
|
|
assert.strictEqual(normalized, '/path/to/real.txt');
|
|
|
|
// ENOENT for non-existent
|
|
assert.throws(() => {
|
|
myVfs.realpathSync('/nonexistent');
|
|
}, { code: 'ENOENT' });
|
|
}
|
|
|
|
// Test existsSync
|
|
{
|
|
const myVfs = vfs.create();
|
|
|
|
myVfs.writeFileSync('/exists.txt', 'content');
|
|
assert.strictEqual(myVfs.existsSync('/exists.txt'), true);
|
|
assert.strictEqual(myVfs.existsSync('/not-exists.txt'), false);
|
|
}
|
|
|
|
// Test accessSync
|
|
{
|
|
const myVfs = vfs.create();
|
|
|
|
myVfs.writeFileSync('/accessible.txt', 'content');
|
|
|
|
// Should not throw for existing file
|
|
myVfs.accessSync('/accessible.txt');
|
|
|
|
// Should throw ENOENT for non-existent
|
|
assert.throws(() => {
|
|
myVfs.accessSync('/nonexistent.txt');
|
|
}, { code: 'ENOENT' });
|
|
}
|
|
|
|
// Test file handle operations via openSync
|
|
{
|
|
const myVfs = vfs.create();
|
|
|
|
myVfs.writeFileSync('/handle-test.txt', 'hello world');
|
|
|
|
const fd = myVfs.openSync('/handle-test.txt', 'r');
|
|
assert.ok((fd & 0x40000000) !== 0);
|
|
const handle = require('internal/vfs/fd').getVirtualFd(fd);
|
|
|
|
// Read via file handle
|
|
const buffer = Buffer.alloc(5);
|
|
const bytesRead = handle.entry.readSync(buffer, 0, 5, 0);
|
|
assert.strictEqual(bytesRead, 5);
|
|
assert.strictEqual(buffer.toString(), 'hello');
|
|
|
|
myVfs.closeSync(fd);
|
|
}
|
|
|
|
// Test file handle write operations
|
|
{
|
|
const myVfs = vfs.create();
|
|
|
|
const fd = myVfs.openSync('/write-handle.txt', 'w');
|
|
const handle = require('internal/vfs/fd').getVirtualFd(fd);
|
|
|
|
const buffer = Buffer.from('written via handle');
|
|
const bytesWritten = handle.entry.writeSync(buffer, 0, buffer.length, 0);
|
|
assert.strictEqual(bytesWritten, buffer.length);
|
|
|
|
myVfs.closeSync(fd);
|
|
|
|
// Verify content
|
|
assert.strictEqual(myVfs.readFileSync('/write-handle.txt', 'utf8'), 'written via handle');
|
|
}
|
|
|
|
// Test file handle readFile and writeFile
|
|
{
|
|
const myVfs = vfs.create();
|
|
|
|
myVfs.writeFileSync('/handle-rw.txt', 'original');
|
|
|
|
const fd = myVfs.openSync('/handle-rw.txt', 'r+');
|
|
const handle = require('internal/vfs/fd').getVirtualFd(fd);
|
|
|
|
// Read via readFile
|
|
const content = handle.entry.readFileSync('utf8');
|
|
assert.strictEqual(content, 'original');
|
|
|
|
// Write via writeFile
|
|
handle.entry.writeFileSync('replaced');
|
|
myVfs.closeSync(fd);
|
|
|
|
assert.strictEqual(myVfs.readFileSync('/handle-rw.txt', 'utf8'), 'replaced');
|
|
}
|
|
|
|
// Test symlink operations
|
|
{
|
|
const myVfs = vfs.create();
|
|
|
|
myVfs.writeFileSync('/target.txt', 'target content');
|
|
myVfs.symlinkSync('/target.txt', '/link.txt');
|
|
|
|
// Reading through symlink should work
|
|
assert.strictEqual(myVfs.readFileSync('/link.txt', 'utf8'), 'target content');
|
|
|
|
// ReadlinkSync should return target
|
|
assert.strictEqual(myVfs.readlinkSync('/link.txt'), '/target.txt');
|
|
|
|
// Lstat on symlink should show it's a symlink
|
|
const lstat = myVfs.lstatSync('/link.txt');
|
|
assert.strictEqual(lstat.isSymbolicLink(), true);
|
|
}
|
|
|
|
// Test reading directory as file should fail
|
|
{
|
|
const myVfs = vfs.create();
|
|
|
|
myVfs.mkdirSync('/mydir', { recursive: true });
|
|
assert.throws(() => {
|
|
myVfs.readFileSync('/mydir');
|
|
}, { code: 'EISDIR' });
|
|
}
|
|
|
|
// Test that readFileSync returns independent buffer copies
|
|
{
|
|
const myVfs = vfs.create();
|
|
|
|
myVfs.writeFileSync('/independent.txt', 'original content');
|
|
|
|
const buf1 = myVfs.readFileSync('/independent.txt');
|
|
const buf2 = myVfs.readFileSync('/independent.txt');
|
|
|
|
// Both should have the same content
|
|
assert.deepStrictEqual(buf1, buf2);
|
|
|
|
// Mutating one should not affect the other
|
|
buf1[0] = 0xFF;
|
|
assert.notDeepStrictEqual(buf1, buf2);
|
|
assert.strictEqual(buf2.toString(), 'original content');
|
|
|
|
// A third read should still return the original content
|
|
const buf3 = myVfs.readFileSync('/independent.txt');
|
|
assert.strictEqual(buf3.toString(), 'original content');
|
|
}
|
|
|
|
// ==================== Async Operations ====================
|
|
|
|
// Test async read and write operations
|
|
(async () => {
|
|
const myVfs = vfs.create();
|
|
|
|
await myVfs.promises.writeFile('/async-test.txt', 'async content');
|
|
const content = await myVfs.promises.readFile('/async-test.txt', 'utf8');
|
|
assert.strictEqual(content, 'async content');
|
|
|
|
const stat = await myVfs.promises.stat('/async-test.txt');
|
|
assert.strictEqual(stat.isFile(), true);
|
|
|
|
await myVfs.promises.unlink('/async-test.txt');
|
|
assert.strictEqual(myVfs.existsSync('/async-test.txt'), false);
|
|
})().then(common.mustCall());
|
|
|
|
// Test async lstat
|
|
(async () => {
|
|
const myVfs = vfs.create();
|
|
|
|
myVfs.writeFileSync('/async-lstat.txt', 'async lstat');
|
|
|
|
const stat = await myVfs.promises.lstat('/async-lstat.txt');
|
|
assert.strictEqual(stat.isFile(), true);
|
|
})().then(common.mustCall());
|
|
|
|
// Test async copyFile
|
|
(async () => {
|
|
const myVfs = vfs.create();
|
|
|
|
myVfs.writeFileSync('/async-src.txt', 'async copy');
|
|
|
|
await myVfs.promises.copyFile('/async-src.txt', '/async-dest.txt');
|
|
|
|
assert.strictEqual(myVfs.existsSync('/async-dest.txt'), true);
|
|
assert.strictEqual(myVfs.readFileSync('/async-dest.txt', 'utf8'), 'async copy');
|
|
})().then(common.mustCall());
|
|
|
|
// Test async mkdir and rmdir
|
|
(async () => {
|
|
const myVfs = vfs.create();
|
|
|
|
await myVfs.promises.mkdir('/async-dir');
|
|
assert.strictEqual(myVfs.existsSync('/async-dir'), true);
|
|
|
|
await myVfs.promises.rmdir('/async-dir');
|
|
assert.strictEqual(myVfs.existsSync('/async-dir'), false);
|
|
})().then(common.mustCall());
|
|
|
|
// Test async rename
|
|
(async () => {
|
|
const myVfs = vfs.create();
|
|
|
|
myVfs.writeFileSync('/async-old.txt', 'async rename');
|
|
|
|
await myVfs.promises.rename('/async-old.txt', '/async-new.txt');
|
|
|
|
assert.strictEqual(myVfs.existsSync('/async-old.txt'), false);
|
|
assert.strictEqual(myVfs.existsSync('/async-new.txt'), true);
|
|
})().then(common.mustCall());
|
|
|
|
// Test async readdir
|
|
(async () => {
|
|
const myVfs = vfs.create();
|
|
|
|
myVfs.mkdirSync('/async-readdir', { recursive: true });
|
|
myVfs.writeFileSync('/async-readdir/file.txt', 'content');
|
|
|
|
const entries = await myVfs.promises.readdir('/async-readdir');
|
|
assert.deepStrictEqual(entries, ['file.txt']);
|
|
})().then(common.mustCall());
|
|
|
|
// Test async appendFile
|
|
(async () => {
|
|
const myVfs = vfs.create();
|
|
|
|
myVfs.writeFileSync('/async-append.txt', 'start');
|
|
|
|
await myVfs.promises.appendFile('/async-append.txt', '-end');
|
|
assert.strictEqual(myVfs.readFileSync('/async-append.txt', 'utf8'), 'start-end');
|
|
})().then(common.mustCall());
|
|
|
|
// Test async access
|
|
(async () => {
|
|
const myVfs = vfs.create();
|
|
|
|
myVfs.writeFileSync('/async-access.txt', 'content');
|
|
|
|
await myVfs.promises.access('/async-access.txt');
|
|
|
|
await assert.rejects(
|
|
myVfs.promises.access('/nonexistent.txt'),
|
|
{ code: 'ENOENT' }
|
|
);
|
|
})().then(common.mustCall());
|
|
|
|
// Test async realpath
|
|
(async () => {
|
|
const myVfs = vfs.create();
|
|
|
|
myVfs.mkdirSync('/async-real/path', { recursive: true });
|
|
myVfs.writeFileSync('/async-real/path/file.txt', 'content');
|
|
|
|
const resolved = await myVfs.promises.realpath('/async-real/path/file.txt');
|
|
assert.strictEqual(resolved, '/async-real/path/file.txt');
|
|
})().then(common.mustCall());
|
|
|
|
// Test async file handle read
|
|
(async () => {
|
|
const myVfs = vfs.create();
|
|
|
|
myVfs.writeFileSync('/async-handle.txt', 'async read test');
|
|
|
|
const fd = myVfs.openSync('/async-handle.txt', 'r');
|
|
const handle = require('internal/vfs/fd').getVirtualFd(fd);
|
|
|
|
const buffer = Buffer.alloc(10);
|
|
const result = await handle.entry.read(buffer, 0, 10, 0);
|
|
assert.strictEqual(result.bytesRead, 10);
|
|
assert.strictEqual(buffer.toString(), 'async read');
|
|
|
|
myVfs.closeSync(fd);
|
|
})().then(common.mustCall());
|
|
|
|
// Test async file handle write
|
|
(async () => {
|
|
const myVfs = vfs.create();
|
|
|
|
const fd = myVfs.openSync('/async-write.txt', 'w');
|
|
const handle = require('internal/vfs/fd').getVirtualFd(fd);
|
|
|
|
const buffer = Buffer.from('async write');
|
|
const result = await handle.entry.write(buffer, 0, buffer.length, 0);
|
|
assert.strictEqual(result.bytesWritten, buffer.length);
|
|
|
|
myVfs.closeSync(fd);
|
|
|
|
// Verify content
|
|
assert.strictEqual(myVfs.readFileSync('/async-write.txt', 'utf8'), 'async write');
|
|
})().then(common.mustCall());
|
|
|
|
// Test async file handle stat
|
|
(async () => {
|
|
const myVfs = vfs.create();
|
|
|
|
myVfs.writeFileSync('/stat-handle.txt', 'stat test');
|
|
|
|
const fd = myVfs.openSync('/stat-handle.txt', 'r');
|
|
const handle = require('internal/vfs/fd').getVirtualFd(fd);
|
|
|
|
const stat = await handle.entry.stat();
|
|
assert.strictEqual(stat.isFile(), true);
|
|
|
|
myVfs.closeSync(fd);
|
|
})().then(common.mustCall());
|
|
|
|
// Test async file handle truncate
|
|
(async () => {
|
|
const myVfs = vfs.create();
|
|
|
|
myVfs.writeFileSync('/truncate-handle.txt', 'truncate this');
|
|
|
|
const fd = myVfs.openSync('/truncate-handle.txt', 'r+');
|
|
const handle = require('internal/vfs/fd').getVirtualFd(fd);
|
|
|
|
await handle.entry.truncate(8);
|
|
myVfs.closeSync(fd);
|
|
|
|
// Verify content was truncated
|
|
assert.strictEqual(myVfs.readFileSync('/truncate-handle.txt', 'utf8'), 'truncate');
|
|
})().then(common.mustCall());
|
|
|
|
// Test async file handle close
|
|
(async () => {
|
|
const myVfs = vfs.create();
|
|
|
|
myVfs.writeFileSync('/close-handle.txt', 'close test');
|
|
|
|
const fd = myVfs.openSync('/close-handle.txt', 'r');
|
|
const handle = require('internal/vfs/fd').getVirtualFd(fd);
|
|
|
|
await handle.entry.close();
|
|
assert.strictEqual(handle.entry.closed, true);
|
|
})().then(common.mustCall());
|
|
|
|
// Test async readFile and writeFile on handle
|
|
(async () => {
|
|
const myVfs = vfs.create();
|
|
|
|
myVfs.writeFileSync('/async-rw.txt', 'async original');
|
|
|
|
const fd = myVfs.openSync('/async-rw.txt', 'r+');
|
|
const handle = require('internal/vfs/fd').getVirtualFd(fd);
|
|
|
|
// Async read
|
|
const content = await handle.entry.readFile('utf8');
|
|
assert.strictEqual(content, 'async original');
|
|
|
|
// Async write
|
|
await handle.entry.writeFile('async replaced');
|
|
myVfs.closeSync(fd);
|
|
|
|
assert.strictEqual(myVfs.readFileSync('/async-rw.txt', 'utf8'), 'async replaced');
|
|
})().then(common.mustCall());
|
|
|
|
// ==================== Readonly Mode ====================
|
|
|
|
// Test MemoryProvider readonly mode
|
|
{
|
|
const myVfs = vfs.create();
|
|
myVfs.writeFileSync('/file.txt', 'content');
|
|
myVfs.mkdirSync('/dir', { recursive: true });
|
|
const fd = myVfs.openSync('/file.txt', 'r+');
|
|
const appendFd = myVfs.openSync('/file.txt', 'a');
|
|
|
|
// Set to readonly
|
|
myVfs.provider.setReadOnly();
|
|
assert.strictEqual(myVfs.provider.readonly, true);
|
|
|
|
// Read operations should still work
|
|
assert.strictEqual(myVfs.readFileSync('/file.txt', 'utf8'), 'content');
|
|
assert.strictEqual(myVfs.existsSync('/file.txt'), true);
|
|
assert.ok(myVfs.statSync('/file.txt'));
|
|
|
|
// Write operations should throw EROFS
|
|
assert.throws(() => {
|
|
myVfs.writeFileSync('/file.txt', 'new content');
|
|
}, { code: 'EROFS' });
|
|
|
|
assert.throws(() => {
|
|
myVfs.writeFileSync('/new.txt', 'content');
|
|
}, { code: 'EROFS' });
|
|
|
|
assert.throws(() => {
|
|
myVfs.appendFileSync('/file.txt', 'more');
|
|
}, { code: 'EROFS' });
|
|
|
|
assert.throws(() => {
|
|
myVfs.mkdirSync('/newdir');
|
|
}, { code: 'EROFS' });
|
|
|
|
assert.throws(() => {
|
|
myVfs.unlinkSync('/file.txt');
|
|
}, { code: 'EROFS' });
|
|
|
|
assert.throws(() => {
|
|
myVfs.rmdirSync('/dir');
|
|
}, { code: 'EROFS' });
|
|
|
|
assert.throws(() => {
|
|
myVfs.renameSync('/file.txt', '/renamed.txt');
|
|
}, { code: 'EROFS' });
|
|
|
|
assert.throws(() => {
|
|
myVfs.copyFileSync('/file.txt', '/copy.txt');
|
|
}, { code: 'EROFS' });
|
|
|
|
assert.throws(() => {
|
|
myVfs.symlinkSync('/file.txt', '/link');
|
|
}, { code: 'EROFS' });
|
|
|
|
// File descriptors opened before setReadOnly() must not bypass it.
|
|
assert.throws(() => {
|
|
myVfs.writeSync(fd, Buffer.from('new'), 0, 3, 0);
|
|
}, { code: 'EROFS' });
|
|
|
|
assert.throws(() => {
|
|
myVfs.ftruncateSync(fd, 0);
|
|
}, { code: 'EROFS' });
|
|
|
|
assert.throws(() => {
|
|
myVfs.writeSync(appendFd, Buffer.from('new'), 0, 3, null);
|
|
}, { code: 'EROFS' });
|
|
|
|
assert.strictEqual(myVfs.readFileSync('/file.txt', 'utf8'), 'content');
|
|
myVfs.closeSync(fd);
|
|
myVfs.closeSync(appendFd);
|
|
}
|
|
|
|
// Test async operations on readonly MemoryProvider
|
|
(async () => {
|
|
const myVfs = vfs.create();
|
|
myVfs.writeFileSync('/readonly.txt', 'content');
|
|
const handle = await myVfs.provider.open('/readonly.txt', 'r+');
|
|
myVfs.provider.setReadOnly();
|
|
|
|
await assert.rejects(
|
|
myVfs.promises.writeFile('/readonly.txt', 'new'),
|
|
{ code: 'EROFS' }
|
|
);
|
|
|
|
await assert.rejects(
|
|
myVfs.promises.appendFile('/readonly.txt', 'more'),
|
|
{ code: 'EROFS' }
|
|
);
|
|
|
|
await assert.rejects(
|
|
myVfs.promises.mkdir('/newdir'),
|
|
{ code: 'EROFS' }
|
|
);
|
|
|
|
await assert.rejects(
|
|
myVfs.promises.unlink('/readonly.txt'),
|
|
{ code: 'EROFS' }
|
|
);
|
|
|
|
await assert.rejects(
|
|
myVfs.promises.copyFile('/readonly.txt', '/copy.txt'),
|
|
{ code: 'EROFS' }
|
|
);
|
|
|
|
await assert.rejects(
|
|
handle.write(Buffer.from('new'), 0, 3, 0),
|
|
{ code: 'EROFS' }
|
|
);
|
|
|
|
await assert.rejects(
|
|
handle.writeFile('new'),
|
|
{ code: 'EROFS' }
|
|
);
|
|
|
|
await assert.rejects(
|
|
handle.truncate(0),
|
|
{ code: 'EROFS' }
|
|
);
|
|
|
|
await assert.rejects(
|
|
handle.writev([Buffer.from('n'), Buffer.from('ew')], 0),
|
|
{ code: 'EROFS' }
|
|
);
|
|
|
|
assert.strictEqual(await handle.readFile('utf8'), 'content');
|
|
await handle.close();
|
|
})().then(common.mustCall());
|