process: migrate methods to throw errors with code
Migrate some methods from node.cc to JS in order to properly throw errors with codes. PR-URL: https://github.com/nodejs/node/pull/19973 Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
parent
e836128703
commit
2fd248f639
@ -1607,6 +1607,11 @@ A string that contained unescaped characters was received.
|
||||
An unhandled error occurred (for instance, when an `'error'` event is emitted
|
||||
by an [`EventEmitter`][] but an `'error'` handler is not registered).
|
||||
|
||||
<a id="ERR_UNKNOWN_CREDENTIAL"></a>
|
||||
### ERR_UNKNOWN_CREDENTIAL
|
||||
|
||||
A Unix group or user identifier that does not exist was passed.
|
||||
|
||||
<a id="ERR_UNKNOWN_ENCODING"></a>
|
||||
### ERR_UNKNOWN_ENCODING
|
||||
|
||||
|
@ -41,6 +41,7 @@
|
||||
NativeModule.require('internal/process/warning').setup();
|
||||
NativeModule.require('internal/process/next_tick').setup();
|
||||
NativeModule.require('internal/process/stdio').setup();
|
||||
NativeModule.require('internal/process/methods').setup();
|
||||
|
||||
const perf = process.binding('performance');
|
||||
const {
|
||||
|
@ -1017,6 +1017,7 @@ E('ERR_UNHANDLED_ERROR',
|
||||
if (err === undefined) return msg;
|
||||
return `${msg} (${err})`;
|
||||
}, Error);
|
||||
E('ERR_UNKNOWN_CREDENTIAL', '%s identifier does not exist: %s', Error);
|
||||
E('ERR_UNKNOWN_ENCODING', 'Unknown encoding: %s', TypeError);
|
||||
|
||||
// This should probably be a `TypeError`.
|
||||
|
137
lib/internal/process/methods.js
Normal file
137
lib/internal/process/methods.js
Normal file
@ -0,0 +1,137 @@
|
||||
'use strict';
|
||||
|
||||
const {
|
||||
ERR_INVALID_ARG_TYPE,
|
||||
ERR_INVALID_ARG_VALUE,
|
||||
ERR_UNKNOWN_CREDENTIAL
|
||||
} = require('internal/errors').codes;
|
||||
const {
|
||||
validateUint32
|
||||
} = require('internal/validators');
|
||||
|
||||
function setupProcessMethods() {
|
||||
// Non-POSIX platforms like Windows don't have certain methods.
|
||||
if (process.setgid !== undefined) {
|
||||
setupPosixMethods();
|
||||
}
|
||||
|
||||
const {
|
||||
chdir: _chdir,
|
||||
umask: _umask,
|
||||
} = process;
|
||||
|
||||
process.chdir = chdir;
|
||||
process.umask = umask;
|
||||
|
||||
function chdir(directory) {
|
||||
if (typeof directory !== 'string') {
|
||||
throw new ERR_INVALID_ARG_TYPE('directory', 'string', directory);
|
||||
}
|
||||
return _chdir(directory);
|
||||
}
|
||||
|
||||
const octalReg = /^[0-7]+$/;
|
||||
function umask(mask) {
|
||||
if (typeof mask === 'undefined') {
|
||||
return _umask(mask);
|
||||
}
|
||||
|
||||
if (typeof mask === 'number') {
|
||||
validateUint32(mask, 'mask');
|
||||
return _umask(mask);
|
||||
}
|
||||
|
||||
if (typeof mask === 'string') {
|
||||
if (!octalReg.test(mask)) {
|
||||
throw new ERR_INVALID_ARG_VALUE('mask', mask,
|
||||
'must be an octal string');
|
||||
}
|
||||
const octal = Number.parseInt(mask, 8);
|
||||
validateUint32(octal, 'mask');
|
||||
return _umask(octal);
|
||||
}
|
||||
|
||||
throw new ERR_INVALID_ARG_TYPE('mask', ['number', 'string', 'undefined'],
|
||||
mask);
|
||||
}
|
||||
}
|
||||
|
||||
function setupPosixMethods() {
|
||||
const {
|
||||
initgroups: _initgroups,
|
||||
setegid: _setegid,
|
||||
seteuid: _seteuid,
|
||||
setgid: _setgid,
|
||||
setuid: _setuid,
|
||||
setgroups: _setgroups
|
||||
} = process;
|
||||
|
||||
process.initgroups = initgroups;
|
||||
process.setegid = setegid;
|
||||
process.seteuid = seteuid;
|
||||
process.setgid = setgid;
|
||||
process.setuid = setuid;
|
||||
process.setgroups = setgroups;
|
||||
|
||||
function initgroups(user, extraGroup) {
|
||||
validateId(user, 'user');
|
||||
validateId(extraGroup, 'extraGroup');
|
||||
// Result is 0 on success, 1 if user is unknown, 2 if group is unknown.
|
||||
const result = _initgroups(user, extraGroup);
|
||||
if (result === 1) {
|
||||
throw new ERR_UNKNOWN_CREDENTIAL('User', user);
|
||||
} else if (result === 2) {
|
||||
throw new ERR_UNKNOWN_CREDENTIAL('Group', extraGroup);
|
||||
}
|
||||
}
|
||||
|
||||
function setegid(id) {
|
||||
return execId(id, 'Group', _setegid);
|
||||
}
|
||||
|
||||
function seteuid(id) {
|
||||
return execId(id, 'User', _seteuid);
|
||||
}
|
||||
|
||||
function setgid(id) {
|
||||
return execId(id, 'Group', _setgid);
|
||||
}
|
||||
|
||||
function setuid(id) {
|
||||
return execId(id, 'User', _setuid);
|
||||
}
|
||||
|
||||
function setgroups(groups) {
|
||||
if (!Array.isArray(groups)) {
|
||||
throw new ERR_INVALID_ARG_TYPE('groups', 'Array', groups);
|
||||
}
|
||||
for (var i = 0; i < groups.length; i++) {
|
||||
validateId(groups[i], `groups[${i}]`);
|
||||
}
|
||||
// Result is 0 on success. A positive integer indicates that the
|
||||
// corresponding group was not found.
|
||||
const result = _setgroups(groups);
|
||||
if (result > 0) {
|
||||
throw new ERR_UNKNOWN_CREDENTIAL('Group', groups[result - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
function execId(id, type, method) {
|
||||
validateId(id, 'id');
|
||||
// Result is 0 on success, 1 if credential is unknown.
|
||||
const result = method(id);
|
||||
if (result === 1) {
|
||||
throw new ERR_UNKNOWN_CREDENTIAL(type, id);
|
||||
}
|
||||
}
|
||||
|
||||
function validateId(id, name) {
|
||||
if (typeof id === 'number') {
|
||||
validateUint32(id, name);
|
||||
} else if (typeof id !== 'string') {
|
||||
throw new ERR_INVALID_ARG_TYPE(name, ['number', 'string'], id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exports.setup = setupProcessMethods;
|
1
node.gyp
1
node.gyp
@ -118,6 +118,7 @@
|
||||
'lib/internal/net.js',
|
||||
'lib/internal/os.js',
|
||||
'lib/internal/process/esm_loader.js',
|
||||
'lib/internal/process/methods.js',
|
||||
'lib/internal/process/next_tick.js',
|
||||
'lib/internal/process/promises.js',
|
||||
'lib/internal/process/stdio.js',
|
||||
|
126
src/node.cc
126
src/node.cc
@ -164,6 +164,7 @@ using v8::ScriptOrigin;
|
||||
using v8::SealHandleScope;
|
||||
using v8::String;
|
||||
using v8::TryCatch;
|
||||
using v8::Uint32;
|
||||
using v8::Uint32Array;
|
||||
using v8::Undefined;
|
||||
using v8::V8;
|
||||
@ -1580,10 +1581,8 @@ static void Abort(const FunctionCallbackInfo<Value>& args) {
|
||||
static void Chdir(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
|
||||
if (args.Length() != 1 || !args[0]->IsString()) {
|
||||
return env->ThrowTypeError("Bad argument.");
|
||||
}
|
||||
|
||||
CHECK_EQ(args.Length(), 1);
|
||||
CHECK(args[0]->IsString());
|
||||
node::Utf8Value path(args.GetIsolate(), args[0]);
|
||||
int err = uv_chdir(*path);
|
||||
if (err) {
|
||||
@ -1616,32 +1615,16 @@ static void Cwd(const FunctionCallbackInfo<Value>& args) {
|
||||
|
||||
|
||||
static void Umask(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
uint32_t old;
|
||||
|
||||
if (args.Length() < 1 || args[0]->IsUndefined()) {
|
||||
CHECK_EQ(args.Length(), 1);
|
||||
CHECK(args[0]->IsUndefined() || args[0]->IsUint32());
|
||||
|
||||
if (args[0]->IsUndefined()) {
|
||||
old = umask(0);
|
||||
umask(static_cast<mode_t>(old));
|
||||
} else if (!args[0]->IsInt32() && !args[0]->IsString()) {
|
||||
return env->ThrowTypeError("argument must be an integer or octal string.");
|
||||
} else {
|
||||
int oct;
|
||||
if (args[0]->IsInt32()) {
|
||||
oct = args[0]->Uint32Value();
|
||||
} else {
|
||||
oct = 0;
|
||||
node::Utf8Value str(env->isolate(), args[0]);
|
||||
|
||||
// Parse the octal string.
|
||||
for (size_t i = 0; i < str.length(); i++) {
|
||||
char c = (*str)[i];
|
||||
if (c > '7' || c < '0') {
|
||||
return env->ThrowTypeError("invalid octal string");
|
||||
}
|
||||
oct *= 8;
|
||||
oct += c - '0';
|
||||
}
|
||||
}
|
||||
int oct = args[0].As<Uint32>()->Value();
|
||||
old = umask(static_cast<mode_t>(oct));
|
||||
}
|
||||
|
||||
@ -1779,18 +1762,18 @@ static void GetEGid(const FunctionCallbackInfo<Value>& args) {
|
||||
static void SetGid(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
|
||||
if (!args[0]->IsUint32() && !args[0]->IsString()) {
|
||||
return env->ThrowTypeError("setgid argument must be a number or a string");
|
||||
}
|
||||
CHECK_EQ(args.Length(), 1);
|
||||
CHECK(args[0]->IsUint32() || args[0]->IsString());
|
||||
|
||||
gid_t gid = gid_by_name(env->isolate(), args[0]);
|
||||
|
||||
if (gid == gid_not_found) {
|
||||
return env->ThrowError("setgid group id does not exist");
|
||||
}
|
||||
|
||||
if (setgid(gid)) {
|
||||
return env->ThrowErrnoException(errno, "setgid");
|
||||
// Tells JS to throw ERR_INVALID_CREDENTIAL
|
||||
args.GetReturnValue().Set(1);
|
||||
} else if (setgid(gid)) {
|
||||
env->ThrowErrnoException(errno, "setgid");
|
||||
} else {
|
||||
args.GetReturnValue().Set(0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1798,18 +1781,18 @@ static void SetGid(const FunctionCallbackInfo<Value>& args) {
|
||||
static void SetEGid(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
|
||||
if (!args[0]->IsUint32() && !args[0]->IsString()) {
|
||||
return env->ThrowTypeError("setegid argument must be a number or string");
|
||||
}
|
||||
CHECK_EQ(args.Length(), 1);
|
||||
CHECK(args[0]->IsUint32() || args[0]->IsString());
|
||||
|
||||
gid_t gid = gid_by_name(env->isolate(), args[0]);
|
||||
|
||||
if (gid == gid_not_found) {
|
||||
return env->ThrowError("setegid group id does not exist");
|
||||
}
|
||||
|
||||
if (setegid(gid)) {
|
||||
return env->ThrowErrnoException(errno, "setegid");
|
||||
// Tells JS to throw ERR_INVALID_CREDENTIAL
|
||||
args.GetReturnValue().Set(1);
|
||||
} else if (setegid(gid)) {
|
||||
env->ThrowErrnoException(errno, "setegid");
|
||||
} else {
|
||||
args.GetReturnValue().Set(0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1817,18 +1800,18 @@ static void SetEGid(const FunctionCallbackInfo<Value>& args) {
|
||||
static void SetUid(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
|
||||
if (!args[0]->IsUint32() && !args[0]->IsString()) {
|
||||
return env->ThrowTypeError("setuid argument must be a number or a string");
|
||||
}
|
||||
CHECK_EQ(args.Length(), 1);
|
||||
CHECK(args[0]->IsUint32() || args[0]->IsString());
|
||||
|
||||
uid_t uid = uid_by_name(env->isolate(), args[0]);
|
||||
|
||||
if (uid == uid_not_found) {
|
||||
return env->ThrowError("setuid user id does not exist");
|
||||
}
|
||||
|
||||
if (setuid(uid)) {
|
||||
return env->ThrowErrnoException(errno, "setuid");
|
||||
// Tells JS to throw ERR_INVALID_CREDENTIAL
|
||||
args.GetReturnValue().Set(1);
|
||||
} else if (setuid(uid)) {
|
||||
env->ThrowErrnoException(errno, "setuid");
|
||||
} else {
|
||||
args.GetReturnValue().Set(0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1836,18 +1819,18 @@ static void SetUid(const FunctionCallbackInfo<Value>& args) {
|
||||
static void SetEUid(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
|
||||
if (!args[0]->IsUint32() && !args[0]->IsString()) {
|
||||
return env->ThrowTypeError("seteuid argument must be a number or string");
|
||||
}
|
||||
CHECK_EQ(args.Length(), 1);
|
||||
CHECK(args[0]->IsUint32() || args[0]->IsString());
|
||||
|
||||
uid_t uid = uid_by_name(env->isolate(), args[0]);
|
||||
|
||||
if (uid == uid_not_found) {
|
||||
return env->ThrowError("seteuid user id does not exist");
|
||||
}
|
||||
|
||||
if (seteuid(uid)) {
|
||||
return env->ThrowErrnoException(errno, "seteuid");
|
||||
// Tells JS to throw ERR_INVALID_CREDENTIAL
|
||||
args.GetReturnValue().Set(1);
|
||||
} else if (seteuid(uid)) {
|
||||
env->ThrowErrnoException(errno, "seteuid");
|
||||
} else {
|
||||
args.GetReturnValue().Set(0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1893,9 +1876,8 @@ static void GetGroups(const FunctionCallbackInfo<Value>& args) {
|
||||
static void SetGroups(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
|
||||
if (!args[0]->IsArray()) {
|
||||
return env->ThrowTypeError("argument 1 must be an array");
|
||||
}
|
||||
CHECK_EQ(args.Length(), 1);
|
||||
CHECK(args[0]->IsArray());
|
||||
|
||||
Local<Array> groups_list = args[0].As<Array>();
|
||||
size_t size = groups_list->Length();
|
||||
@ -1906,7 +1888,9 @@ static void SetGroups(const FunctionCallbackInfo<Value>& args) {
|
||||
|
||||
if (gid == gid_not_found) {
|
||||
delete[] groups;
|
||||
return env->ThrowError("group name not found");
|
||||
// Tells JS to throw ERR_INVALID_CREDENTIAL
|
||||
args.GetReturnValue().Set(static_cast<uint32_t>(i + 1));
|
||||
return;
|
||||
}
|
||||
|
||||
groups[i] = gid;
|
||||
@ -1918,19 +1902,17 @@ static void SetGroups(const FunctionCallbackInfo<Value>& args) {
|
||||
if (rc == -1) {
|
||||
return env->ThrowErrnoException(errno, "setgroups");
|
||||
}
|
||||
|
||||
args.GetReturnValue().Set(0);
|
||||
}
|
||||
|
||||
|
||||
static void InitGroups(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
|
||||
if (!args[0]->IsUint32() && !args[0]->IsString()) {
|
||||
return env->ThrowTypeError("argument 1 must be a number or a string");
|
||||
}
|
||||
|
||||
if (!args[1]->IsUint32() && !args[1]->IsString()) {
|
||||
return env->ThrowTypeError("argument 2 must be a number or a string");
|
||||
}
|
||||
CHECK_EQ(args.Length(), 2);
|
||||
CHECK(args[0]->IsUint32() || args[0]->IsString());
|
||||
CHECK(args[1]->IsUint32() || args[1]->IsString());
|
||||
|
||||
node::Utf8Value arg0(env->isolate(), args[0]);
|
||||
gid_t extra_group;
|
||||
@ -1946,7 +1928,8 @@ static void InitGroups(const FunctionCallbackInfo<Value>& args) {
|
||||
}
|
||||
|
||||
if (user == nullptr) {
|
||||
return env->ThrowError("initgroups user not found");
|
||||
// Tells JS to throw ERR_INVALID_CREDENTIAL
|
||||
return args.GetReturnValue().Set(1);
|
||||
}
|
||||
|
||||
extra_group = gid_by_name(env->isolate(), args[1]);
|
||||
@ -1954,7 +1937,8 @@ static void InitGroups(const FunctionCallbackInfo<Value>& args) {
|
||||
if (extra_group == gid_not_found) {
|
||||
if (must_free)
|
||||
free(user);
|
||||
return env->ThrowError("initgroups extra group not found");
|
||||
// Tells JS to throw ERR_INVALID_CREDENTIAL
|
||||
return args.GetReturnValue().Set(2);
|
||||
}
|
||||
|
||||
int rc = initgroups(user, extra_group);
|
||||
@ -1966,6 +1950,8 @@ static void InitGroups(const FunctionCallbackInfo<Value>& args) {
|
||||
if (rc) {
|
||||
return env->ThrowErrnoException(errno, "initgroups");
|
||||
}
|
||||
|
||||
args.GetReturnValue().Set(0);
|
||||
}
|
||||
|
||||
#endif // __POSIX__ && !defined(__ANDROID__) && !defined(__CloudABI__)
|
||||
|
@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
require('../common');
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
@ -33,10 +33,9 @@ process.chdir('..');
|
||||
assert.strictEqual(process.cwd().normalize(),
|
||||
path.resolve(tmpdir.path).normalize());
|
||||
|
||||
const errMessage = /^TypeError: Bad argument\.$/;
|
||||
assert.throws(function() { process.chdir({}); },
|
||||
errMessage, 'Bad argument.');
|
||||
assert.throws(function() { process.chdir(); },
|
||||
errMessage, 'Bad argument.');
|
||||
assert.throws(function() { process.chdir('x', 'y'); },
|
||||
errMessage, 'Bad argument.');
|
||||
const err = {
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
message: /The "directory" argument must be of type string/
|
||||
};
|
||||
common.expectsError(function() { process.chdir({}); }, err);
|
||||
common.expectsError(function() { process.chdir(); }, err);
|
||||
|
@ -13,11 +13,18 @@ if (common.isWindows) {
|
||||
|
||||
assert.throws(() => {
|
||||
process.seteuid({});
|
||||
}, /^TypeError: seteuid argument must be a number or string$/);
|
||||
}, {
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
message: 'The "id" argument must be one of type number or string. ' +
|
||||
'Received type object'
|
||||
});
|
||||
|
||||
assert.throws(() => {
|
||||
process.seteuid('fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf');
|
||||
}, /^Error: seteuid user id does not exist$/);
|
||||
process.seteuid('fhqwhgadshgnsdhjsdbkhsdabkfabkveyb');
|
||||
}, {
|
||||
code: 'ERR_UNKNOWN_CREDENTIAL',
|
||||
message: 'User identifier does not exist: fhqwhgadshgnsdhjsdbkhsdabkfabkveyb'
|
||||
});
|
||||
|
||||
// If we're not running as super user...
|
||||
if (process.getuid() !== 0) {
|
||||
@ -27,11 +34,11 @@ if (process.getuid() !== 0) {
|
||||
|
||||
assert.throws(() => {
|
||||
process.setegid('nobody');
|
||||
}, /^Error: (?:EPERM, .+|setegid group id does not exist)$/);
|
||||
}, /(?:EPERM, .+|Group identifier does not exist: nobody)$/);
|
||||
|
||||
assert.throws(() => {
|
||||
process.seteuid('nobody');
|
||||
}, /^Error: (?:EPERM, .+|seteuid user id does not exist)$/);
|
||||
}, /^Error: (?:EPERM, .+|User identifier does not exist: nobody)$/);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -41,7 +48,7 @@ const oldgid = process.getegid();
|
||||
try {
|
||||
process.setegid('nobody');
|
||||
} catch (err) {
|
||||
if (err.message !== 'setegid group id does not exist') {
|
||||
if (err.message !== 'Group identifier does not exist: nobody') {
|
||||
throw err;
|
||||
} else {
|
||||
process.setegid('nogroup');
|
||||
|
@ -35,11 +35,18 @@ if (common.isWindows) {
|
||||
|
||||
assert.throws(() => {
|
||||
process.setuid({});
|
||||
}, /^TypeError: setuid argument must be a number or a string$/);
|
||||
}, {
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
message: 'The "id" argument must be one of type ' +
|
||||
'number or string. Received type object'
|
||||
});
|
||||
|
||||
assert.throws(() => {
|
||||
process.setuid('fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf');
|
||||
}, /^Error: setuid user id does not exist$/);
|
||||
process.setuid('fhqwhgadshgnsdhjsdbkhsdabkfabkveyb');
|
||||
}, {
|
||||
code: 'ERR_UNKNOWN_CREDENTIAL',
|
||||
message: 'User identifier does not exist: fhqwhgadshgnsdhjsdbkhsdabkfabkveyb'
|
||||
});
|
||||
|
||||
// If we're not running as super user...
|
||||
if (process.getuid() !== 0) {
|
||||
@ -49,12 +56,12 @@ if (process.getuid() !== 0) {
|
||||
|
||||
assert.throws(
|
||||
() => { process.setgid('nobody'); },
|
||||
/^Error: (?:EPERM, .+|setgid group id does not exist)$/
|
||||
/(?:EPERM, .+|Group identifier does not exist: nobody)$/
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
() => { process.setuid('nobody'); },
|
||||
/^Error: (?:EPERM, .+|setuid user id does not exist)$/
|
||||
/(?:EPERM, .+|User identifier does not exist: nobody)$/
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
@ -43,8 +43,17 @@ assert.strictEqual(old, process.umask());
|
||||
|
||||
assert.throws(() => {
|
||||
process.umask({});
|
||||
}, /argument must be an integer or octal string/);
|
||||
}, {
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
message: 'The "mask" argument must be one of type number, string, or ' +
|
||||
'undefined. Received type object'
|
||||
});
|
||||
|
||||
assert.throws(() => {
|
||||
process.umask('123x');
|
||||
}, /invalid octal string/);
|
||||
['123x', 'abc', '999'].forEach((value) => {
|
||||
assert.throws(() => {
|
||||
process.umask(value);
|
||||
}, {
|
||||
code: 'ERR_INVALID_ARG_VALUE',
|
||||
message: `The argument 'mask' must be an octal string. Received '${value}'`
|
||||
});
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user