diff --git a/lib/internal/vfs/providers/memory.js b/lib/internal/vfs/providers/memory.js index acec5b4166b2..dcdae87255d0 100644 --- a/lib/internal/vfs/providers/memory.js +++ b/lib/internal/vfs/providers/memory.js @@ -849,6 +849,10 @@ class MemoryProvider extends VirtualProvider { if (!existingDest.isDirectory() && entry.isDirectory()) { throw createENOTDIR('rename', newPath); } + // Cannot overwrite a non-empty directory + if (existingDest.isDirectory() && existingDest.children.size > 0) { + throw createENOTEMPTY('rename', newPath); + } } // Remove from old location (after destination validation) diff --git a/test/parallel/test-vfs-rename.js b/test/parallel/test-vfs-rename.js index 69daba43c11d..009494495794 100644 --- a/test/parallel/test-vfs-rename.js +++ b/test/parallel/test-vfs-rename.js @@ -58,3 +58,28 @@ const vfs = require('node:vfs'); assert.strictEqual(myVfs.existsSync('/a/b/c'), false); assert.strictEqual(myVfs.readFileSync('/a/file.txt', 'utf8'), 'data'); } + +// Renaming a directory onto a non-empty directory throws ENOTEMPTY +{ + const myVfs = vfs.create(); + myVfs.mkdirSync('/src'); + myVfs.writeFileSync('/src/a.txt', 'a'); + myVfs.mkdirSync('/dst'); + myVfs.writeFileSync('/dst/keep.txt', 'keep'); + + assert.throws(() => myVfs.renameSync('/src', '/dst'), { code: 'ENOTEMPTY' }); + assert.strictEqual(myVfs.readFileSync('/dst/keep.txt', 'utf8'), 'keep'); + assert.strictEqual(myVfs.readFileSync('/src/a.txt', 'utf8'), 'a'); +} + +// Renaming a directory onto an empty directory succeeds +{ + const myVfs = vfs.create(); + myVfs.mkdirSync('/src'); + myVfs.writeFileSync('/src/a.txt', 'a'); + myVfs.mkdirSync('/dst'); + + myVfs.renameSync('/src', '/dst'); + assert.strictEqual(myVfs.existsSync('/src'), false); + assert.strictEqual(myVfs.readFileSync('/dst/a.txt', 'utf8'), 'a'); +}