mirror of
https://github.com/nodejs/node.git
synced 2025-05-07 15:35:41 +00:00

This commit adds a recursive option to fs.rmdir(), fs.rmdirSync(), and fs.promises.rmdir(). The implementation is a port of the npm module rimraf. PR-URL: https://github.com/nodejs/node/pull/29168 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Roman Reiss <me@silverwind.io> Reviewed-By: Ben Coe <bencoe@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Jiawen Geng <technicalcute@gmail.com>
153 lines
4.3 KiB
JavaScript
153 lines
4.3 KiB
JavaScript
// Flags: --expose-internals
|
|
'use strict';
|
|
const common = require('../common');
|
|
const tmpdir = require('../common/tmpdir');
|
|
const assert = require('assert');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const { validateRmdirOptions } = require('internal/fs/utils');
|
|
let count = 0;
|
|
|
|
tmpdir.refresh();
|
|
|
|
function makeNonEmptyDirectory() {
|
|
const dirname = `rmdir-recursive-${count}`;
|
|
fs.mkdirSync(path.join(dirname, 'foo', 'bar', 'baz'), { recursive: true });
|
|
fs.writeFileSync(path.join(dirname, 'text.txt'), 'hello', 'utf8');
|
|
count++;
|
|
return dirname;
|
|
}
|
|
|
|
// Test the asynchronous version.
|
|
{
|
|
const dir = makeNonEmptyDirectory();
|
|
|
|
// Removal should fail without the recursive option.
|
|
fs.rmdir(dir, common.mustCall((err) => {
|
|
assert.strictEqual(err.syscall, 'rmdir');
|
|
|
|
// Removal should fail without the recursive option set to true.
|
|
fs.rmdir(dir, { recursive: false }, common.mustCall((err) => {
|
|
assert.strictEqual(err.syscall, 'rmdir');
|
|
|
|
// Recursive removal should succeed.
|
|
fs.rmdir(dir, { recursive: true }, common.mustCall((err) => {
|
|
assert.ifError(err);
|
|
|
|
// No error should occur if recursive and the directory does not exist.
|
|
fs.rmdir(dir, { recursive: true }, common.mustCall((err) => {
|
|
assert.ifError(err);
|
|
|
|
// Attempted removal should fail now because the directory is gone.
|
|
fs.rmdir(dir, common.mustCall((err) => {
|
|
assert.strictEqual(err.syscall, 'rmdir');
|
|
}));
|
|
}));
|
|
}));
|
|
}));
|
|
}));
|
|
}
|
|
|
|
// Test the synchronous version.
|
|
{
|
|
const dir = makeNonEmptyDirectory();
|
|
|
|
// Removal should fail without the recursive option set to true.
|
|
common.expectsError(() => {
|
|
fs.rmdirSync(dir);
|
|
}, { syscall: 'rmdir' });
|
|
common.expectsError(() => {
|
|
fs.rmdirSync(dir, { recursive: false });
|
|
}, { syscall: 'rmdir' });
|
|
|
|
// Recursive removal should succeed.
|
|
fs.rmdirSync(dir, { recursive: true });
|
|
|
|
// No error should occur if recursive and the directory does not exist.
|
|
fs.rmdirSync(dir, { recursive: true });
|
|
|
|
// Attempted removal should fail now because the directory is gone.
|
|
common.expectsError(() => fs.rmdirSync(dir), { syscall: 'rmdir' });
|
|
}
|
|
|
|
// Test the Promises based version.
|
|
(async () => {
|
|
const dir = makeNonEmptyDirectory();
|
|
|
|
// Removal should fail without the recursive option set to true.
|
|
assert.rejects(fs.promises.rmdir(dir), { syscall: 'rmdir' });
|
|
assert.rejects(fs.promises.rmdir(dir, { recursive: false }), {
|
|
syscall: 'rmdir'
|
|
});
|
|
|
|
// Recursive removal should succeed.
|
|
await fs.promises.rmdir(dir, { recursive: true });
|
|
|
|
// No error should occur if recursive and the directory does not exist.
|
|
await fs.promises.rmdir(dir, { recursive: true });
|
|
|
|
// Attempted removal should fail now because the directory is gone.
|
|
assert.rejects(fs.promises.rmdir(dir), { syscall: 'rmdir' });
|
|
})();
|
|
|
|
// Test input validation.
|
|
{
|
|
const defaults = {
|
|
emfileWait: 1000,
|
|
maxBusyTries: 3,
|
|
recursive: false
|
|
};
|
|
const modified = {
|
|
emfileWait: 953,
|
|
maxBusyTries: 5,
|
|
recursive: true
|
|
};
|
|
|
|
assert.deepStrictEqual(validateRmdirOptions(), defaults);
|
|
assert.deepStrictEqual(validateRmdirOptions({}), defaults);
|
|
assert.deepStrictEqual(validateRmdirOptions(modified), modified);
|
|
assert.deepStrictEqual(validateRmdirOptions({
|
|
maxBusyTries: 99
|
|
}), {
|
|
emfileWait: 1000,
|
|
maxBusyTries: 99,
|
|
recursive: false
|
|
});
|
|
|
|
[null, 'foo', 5, NaN].forEach((bad) => {
|
|
common.expectsError(() => {
|
|
validateRmdirOptions(bad);
|
|
}, {
|
|
code: 'ERR_INVALID_ARG_TYPE',
|
|
type: TypeError,
|
|
message: /^The "options" argument must be of type object\./
|
|
});
|
|
});
|
|
|
|
[undefined, null, 'foo', Infinity, function() {}].forEach((bad) => {
|
|
common.expectsError(() => {
|
|
validateRmdirOptions({ recursive: bad });
|
|
}, {
|
|
code: 'ERR_INVALID_ARG_TYPE',
|
|
type: TypeError,
|
|
message: /^The "recursive" argument must be of type boolean\./
|
|
});
|
|
});
|
|
|
|
common.expectsError(() => {
|
|
validateRmdirOptions({ emfileWait: -1 });
|
|
}, {
|
|
code: 'ERR_OUT_OF_RANGE',
|
|
type: RangeError,
|
|
message: /^The value of "emfileWait" is out of range\./
|
|
});
|
|
|
|
common.expectsError(() => {
|
|
validateRmdirOptions({ maxBusyTries: -1 });
|
|
}, {
|
|
code: 'ERR_OUT_OF_RANGE',
|
|
type: RangeError,
|
|
message: /^The value of "maxBusyTries" is out of range\./
|
|
});
|
|
}
|