src: add CollectExceptionInfo & errors.SystemError

Preparing for the migration of existing UVException and ErrnoExceptions
from the native layer, add new `errors.SystemError` to internal/errors
and new `env->CollectExceptionInfo()` / `env->CollectUVExceptionInfo()`
methods.

PR-URL: https://github.com/nodejs/node/pull/16567
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
This commit is contained in:
James M Snell 2017-10-27 16:25:14 -07:00
parent f1f0eb2595
commit c3dc0e0d75
7 changed files with 720 additions and 329 deletions

View File

@ -458,7 +458,7 @@ checks or `abort()` calls in the C++ layer.
## System Errors
System errors are generated when exceptions occur within the program's
System errors are generated when exceptions occur within the Node.js
runtime environment. Typically, these are operational errors that occur
when an application violates an operating system constraint such as attempting
to read a file that does not exist or when the user does not have sufficient
@ -471,7 +471,24 @@ of error codes and their meanings is available by running `man 2 intro` or
In Node.js, system errors are represented as augmented `Error` objects with
added properties.
### Class: System Error
### Class: SystemError
### error.info
`SystemError` instances may have an additional `info` property whose
value is an object with additional details about the error conditions.
The following properties are provided:
* `code` {string} The string error code
* `errno` {number} The system-provided error number
* `message` {string} A system-provided human readable description of the error
* `syscall` {string} The name of the system call that triggered the error
* `path` {Buffer} When reporting a file system error, the `path` will identify
the file path.
* `dest` {Buffer} When reporting a file system error, the `dest` will identify
the file path destination (if any).
#### error.code
@ -1379,6 +1396,13 @@ instance.setEncoding('utf8');
Used when an attempt is made to call [`stream.write()`][] after
`stream.end()` has been called.
<a id="ERR_SYSTEM_ERROR"></a>
### ERR_SYSTEM_ERROR
The `ERR_SYSTEM_ERROR` code is used when an unspecified or non-specific system
error has occurred within the Node.js process. The error object will have an
`err.info` object property with additional details.
<a id="ERR_TLS_CERT_ALTNAME_INVALID"></a>
### ERR_TLS_CERT_ALTNAME_INVALID

View File

@ -10,6 +10,7 @@
// message may change, the code should not.
const kCode = Symbol('code');
const kInfo = Symbol('info');
const messages = new Map();
const { kMaxLength } = process.binding('buffer');
@ -58,6 +59,68 @@ function makeNodeError(Base) {
};
}
// A specialized Error that includes an additional info property with
// additional information about the error condition. The code key will
// be extracted from the context object or the ERR_SYSTEM_ERROR default
// will be used.
class SystemError extends makeNodeError(Error) {
constructor(context) {
context = context || {};
let code = 'ERR_SYSTEM_ERROR';
if (messages.has(context.code))
code = context.code;
super(code,
context.code,
context.syscall,
context.path,
context.dest,
context.message);
Object.defineProperty(this, kInfo, {
configurable: false,
enumerable: false,
value: context
});
}
get info() {
return this[kInfo];
}
get errno() {
return this[kInfo].errno;
}
set errno(val) {
this[kInfo].errno = val;
}
get syscall() {
return this[kInfo].syscall;
}
set syscall(val) {
this[kInfo].syscall = val;
}
get path() {
return this[kInfo].path !== undefined ?
this[kInfo].path.toString() : undefined;
}
set path(val) {
this[kInfo].path = val ? Buffer.from(val.toString()) : undefined;
}
get dest() {
return this[kInfo].path !== undefined ?
this[kInfo].dest.toString() : undefined;
}
set dest(val) {
this[kInfo].dest = val ? Buffer.from(val.toString()) : undefined;
}
}
class AssertionError extends Error {
constructor(options) {
if (typeof options !== 'object' || options === null) {
@ -128,6 +191,7 @@ module.exports = exports = {
RangeError: makeNodeError(RangeError),
URIError: makeNodeError(URIError),
AssertionError,
SystemError,
E // This is exported only to facilitate testing.
};
@ -144,6 +208,9 @@ module.exports = exports = {
// Any error code added here should also be added to the documentation
//
// Note: Please try to keep these in alphabetical order
//
// Note: Node.js specific errors must begin with the prefix ERR_
E('ERR_ARG_NOT_ITERABLE', '%s must be iterable');
E('ERR_ASSERTION', '%s');
E('ERR_ASYNC_CALLBACK', (name) => `${name} must be a function`);
@ -334,6 +401,7 @@ E('ERR_STREAM_READ_NOT_IMPLEMENTED', '_read() is not implemented');
E('ERR_STREAM_UNSHIFT_AFTER_END_EVENT', 'stream.unshift() after end event');
E('ERR_STREAM_WRAP', 'Stream has StringDecoder set or is in objectMode');
E('ERR_STREAM_WRITE_AFTER_END', 'write after end');
E('ERR_SYSTEM_ERROR', sysError('A system error occurred'));
E('ERR_TLS_CERT_ALTNAME_INVALID',
'Hostname/IP does not match certificate\'s altnames: %s');
E('ERR_TLS_DH_PARAM_SIZE', (size) =>
@ -371,6 +439,28 @@ E('ERR_VALUE_OUT_OF_RANGE', (start, end, value) => {
E('ERR_ZLIB_BINDING_CLOSED', 'zlib binding closed');
E('ERR_ZLIB_INITIALIZATION_FAILED', 'Initialization failed');
function sysError(defaultMessage) {
return function(code,
syscall,
path,
dest,
message = defaultMessage) {
if (code !== undefined)
message += `: ${code}`;
if (syscall !== undefined) {
if (code === undefined)
message += ':';
message += ` [${syscall}]`;
}
if (path !== undefined) {
message += `: ${path}`;
if (dest !== undefined)
message += ` => ${dest}`;
}
return message;
};
}
function invalidArgType(name, expected, actual) {
internalAssert(name, 'name is required');

View File

@ -1,6 +1,7 @@
#include "node_internals.h"
#include "async-wrap.h"
#include "v8-profiler.h"
#include "node_buffer.h"
#if defined(_MSC_VER)
#define getpid GetCurrentProcessId
@ -228,4 +229,81 @@ void Environment::EnvPromiseHook(v8::PromiseHookType type,
}
}
void CollectExceptionInfo(Environment* env,
v8::Local<v8::Object> obj,
int errorno,
const char* err_string,
const char* syscall,
const char* message,
const char* path,
const char* dest) {
obj->Set(env->errno_string(), v8::Integer::New(env->isolate(), errorno));
obj->Set(env->context(), env->code_string(),
OneByteString(env->isolate(), err_string)).FromJust();
if (message != nullptr) {
obj->Set(env->context(), env->message_string(),
OneByteString(env->isolate(), message)).FromJust();
}
v8::Local<v8::Value> path_buffer;
if (path != nullptr) {
path_buffer =
Buffer::Copy(env->isolate(), path, strlen(path)).ToLocalChecked();
obj->Set(env->context(), env->path_string(), path_buffer).FromJust();
}
v8::Local<v8::Value> dest_buffer;
if (dest != nullptr) {
dest_buffer =
Buffer::Copy(env->isolate(), dest, strlen(dest)).ToLocalChecked();
obj->Set(env->context(), env->dest_string(), dest_buffer).FromJust();
}
if (syscall != nullptr) {
obj->Set(env->context(), env->syscall_string(),
OneByteString(env->isolate(), syscall));
}
}
void Environment::CollectExceptionInfo(v8::Local<v8::Value> object,
int errorno,
const char* syscall,
const char* message,
const char* path) {
if (!object->IsObject() || errorno == 0)
return;
v8::Local<v8::Object> obj = object.As<v8::Object>();
const char* err_string = node::errno_string(errorno);
if (message == nullptr || message[0] == '\0') {
message = strerror(errorno);
}
node::CollectExceptionInfo(this, obj, errorno, err_string,
syscall, message, path, nullptr);
}
void Environment::CollectUVExceptionInfo(v8::Local<v8::Value> object,
int errorno,
const char* syscall,
const char* message,
const char* path,
const char* dest) {
if (!object->IsObject() || errorno == 0)
return;
v8::Local<v8::Object> obj = object.As<v8::Object>();
const char* err_string = uv_err_name(errorno);
if (message == nullptr || message[0] == '\0') {
message = uv_strerror(errorno);
}
node::CollectExceptionInfo(this, obj, errorno, err_string,
syscall, message, path, dest);
}
} // namespace node

View File

@ -617,6 +617,19 @@ class Environment {
inline performance::performance_state* performance_state();
inline std::map<std::string, uint64_t>* performance_marks();
void CollectExceptionInfo(v8::Local<v8::Value> context,
int errorno,
const char* syscall = nullptr,
const char* message = nullptr,
const char* path = nullptr);
void CollectUVExceptionInfo(v8::Local<v8::Value> context,
int errorno,
const char* syscall = nullptr,
const char* message = nullptr,
const char* path = nullptr,
const char* dest = nullptr);
inline void ThrowError(const char* errmsg);
inline void ThrowTypeError(const char* errmsg);
inline void ThrowRangeError(const char* errmsg);

View File

@ -390,333 +390,6 @@ static void IdleImmediateDummy(uv_idle_t* handle) {
// TODO(bnoordhuis) Maybe make libuv accept nullptr idle callbacks.
}
static inline const char *errno_string(int errorno) {
#define ERRNO_CASE(e) case e: return #e;
switch (errorno) {
#ifdef EACCES
ERRNO_CASE(EACCES);
#endif
#ifdef EADDRINUSE
ERRNO_CASE(EADDRINUSE);
#endif
#ifdef EADDRNOTAVAIL
ERRNO_CASE(EADDRNOTAVAIL);
#endif
#ifdef EAFNOSUPPORT
ERRNO_CASE(EAFNOSUPPORT);
#endif
#ifdef EAGAIN
ERRNO_CASE(EAGAIN);
#endif
#ifdef EWOULDBLOCK
# if EAGAIN != EWOULDBLOCK
ERRNO_CASE(EWOULDBLOCK);
# endif
#endif
#ifdef EALREADY
ERRNO_CASE(EALREADY);
#endif
#ifdef EBADF
ERRNO_CASE(EBADF);
#endif
#ifdef EBADMSG
ERRNO_CASE(EBADMSG);
#endif
#ifdef EBUSY
ERRNO_CASE(EBUSY);
#endif
#ifdef ECANCELED
ERRNO_CASE(ECANCELED);
#endif
#ifdef ECHILD
ERRNO_CASE(ECHILD);
#endif
#ifdef ECONNABORTED
ERRNO_CASE(ECONNABORTED);
#endif
#ifdef ECONNREFUSED
ERRNO_CASE(ECONNREFUSED);
#endif
#ifdef ECONNRESET
ERRNO_CASE(ECONNRESET);
#endif
#ifdef EDEADLK
ERRNO_CASE(EDEADLK);
#endif
#ifdef EDESTADDRREQ
ERRNO_CASE(EDESTADDRREQ);
#endif
#ifdef EDOM
ERRNO_CASE(EDOM);
#endif
#ifdef EDQUOT
ERRNO_CASE(EDQUOT);
#endif
#ifdef EEXIST
ERRNO_CASE(EEXIST);
#endif
#ifdef EFAULT
ERRNO_CASE(EFAULT);
#endif
#ifdef EFBIG
ERRNO_CASE(EFBIG);
#endif
#ifdef EHOSTUNREACH
ERRNO_CASE(EHOSTUNREACH);
#endif
#ifdef EIDRM
ERRNO_CASE(EIDRM);
#endif
#ifdef EILSEQ
ERRNO_CASE(EILSEQ);
#endif
#ifdef EINPROGRESS
ERRNO_CASE(EINPROGRESS);
#endif
#ifdef EINTR
ERRNO_CASE(EINTR);
#endif
#ifdef EINVAL
ERRNO_CASE(EINVAL);
#endif
#ifdef EIO
ERRNO_CASE(EIO);
#endif
#ifdef EISCONN
ERRNO_CASE(EISCONN);
#endif
#ifdef EISDIR
ERRNO_CASE(EISDIR);
#endif
#ifdef ELOOP
ERRNO_CASE(ELOOP);
#endif
#ifdef EMFILE
ERRNO_CASE(EMFILE);
#endif
#ifdef EMLINK
ERRNO_CASE(EMLINK);
#endif
#ifdef EMSGSIZE
ERRNO_CASE(EMSGSIZE);
#endif
#ifdef EMULTIHOP
ERRNO_CASE(EMULTIHOP);
#endif
#ifdef ENAMETOOLONG
ERRNO_CASE(ENAMETOOLONG);
#endif
#ifdef ENETDOWN
ERRNO_CASE(ENETDOWN);
#endif
#ifdef ENETRESET
ERRNO_CASE(ENETRESET);
#endif
#ifdef ENETUNREACH
ERRNO_CASE(ENETUNREACH);
#endif
#ifdef ENFILE
ERRNO_CASE(ENFILE);
#endif
#ifdef ENOBUFS
ERRNO_CASE(ENOBUFS);
#endif
#ifdef ENODATA
ERRNO_CASE(ENODATA);
#endif
#ifdef ENODEV
ERRNO_CASE(ENODEV);
#endif
#ifdef ENOENT
ERRNO_CASE(ENOENT);
#endif
#ifdef ENOEXEC
ERRNO_CASE(ENOEXEC);
#endif
#ifdef ENOLINK
ERRNO_CASE(ENOLINK);
#endif
#ifdef ENOLCK
# if ENOLINK != ENOLCK
ERRNO_CASE(ENOLCK);
# endif
#endif
#ifdef ENOMEM
ERRNO_CASE(ENOMEM);
#endif
#ifdef ENOMSG
ERRNO_CASE(ENOMSG);
#endif
#ifdef ENOPROTOOPT
ERRNO_CASE(ENOPROTOOPT);
#endif
#ifdef ENOSPC
ERRNO_CASE(ENOSPC);
#endif
#ifdef ENOSR
ERRNO_CASE(ENOSR);
#endif
#ifdef ENOSTR
ERRNO_CASE(ENOSTR);
#endif
#ifdef ENOSYS
ERRNO_CASE(ENOSYS);
#endif
#ifdef ENOTCONN
ERRNO_CASE(ENOTCONN);
#endif
#ifdef ENOTDIR
ERRNO_CASE(ENOTDIR);
#endif
#ifdef ENOTEMPTY
# if ENOTEMPTY != EEXIST
ERRNO_CASE(ENOTEMPTY);
# endif
#endif
#ifdef ENOTSOCK
ERRNO_CASE(ENOTSOCK);
#endif
#ifdef ENOTSUP
ERRNO_CASE(ENOTSUP);
#else
# ifdef EOPNOTSUPP
ERRNO_CASE(EOPNOTSUPP);
# endif
#endif
#ifdef ENOTTY
ERRNO_CASE(ENOTTY);
#endif
#ifdef ENXIO
ERRNO_CASE(ENXIO);
#endif
#ifdef EOVERFLOW
ERRNO_CASE(EOVERFLOW);
#endif
#ifdef EPERM
ERRNO_CASE(EPERM);
#endif
#ifdef EPIPE
ERRNO_CASE(EPIPE);
#endif
#ifdef EPROTO
ERRNO_CASE(EPROTO);
#endif
#ifdef EPROTONOSUPPORT
ERRNO_CASE(EPROTONOSUPPORT);
#endif
#ifdef EPROTOTYPE
ERRNO_CASE(EPROTOTYPE);
#endif
#ifdef ERANGE
ERRNO_CASE(ERANGE);
#endif
#ifdef EROFS
ERRNO_CASE(EROFS);
#endif
#ifdef ESPIPE
ERRNO_CASE(ESPIPE);
#endif
#ifdef ESRCH
ERRNO_CASE(ESRCH);
#endif
#ifdef ESTALE
ERRNO_CASE(ESTALE);
#endif
#ifdef ETIME
ERRNO_CASE(ETIME);
#endif
#ifdef ETIMEDOUT
ERRNO_CASE(ETIMEDOUT);
#endif
#ifdef ETXTBSY
ERRNO_CASE(ETXTBSY);
#endif
#ifdef EXDEV
ERRNO_CASE(EXDEV);
#endif
default: return "";
}
}
const char *signo_string(int signo) {
#define SIGNO_CASE(e) case e: return #e;
switch (signo) {

View File

@ -324,6 +324,332 @@ class InternalCallbackScope {
bool closed_ = false;
};
static inline const char *errno_string(int errorno) {
#define ERRNO_CASE(e) case e: return #e;
switch (errorno) {
#ifdef EACCES
ERRNO_CASE(EACCES);
#endif
#ifdef EADDRINUSE
ERRNO_CASE(EADDRINUSE);
#endif
#ifdef EADDRNOTAVAIL
ERRNO_CASE(EADDRNOTAVAIL);
#endif
#ifdef EAFNOSUPPORT
ERRNO_CASE(EAFNOSUPPORT);
#endif
#ifdef EAGAIN
ERRNO_CASE(EAGAIN);
#endif
#ifdef EWOULDBLOCK
# if EAGAIN != EWOULDBLOCK
ERRNO_CASE(EWOULDBLOCK);
# endif
#endif
#ifdef EALREADY
ERRNO_CASE(EALREADY);
#endif
#ifdef EBADF
ERRNO_CASE(EBADF);
#endif
#ifdef EBADMSG
ERRNO_CASE(EBADMSG);
#endif
#ifdef EBUSY
ERRNO_CASE(EBUSY);
#endif
#ifdef ECANCELED
ERRNO_CASE(ECANCELED);
#endif
#ifdef ECHILD
ERRNO_CASE(ECHILD);
#endif
#ifdef ECONNABORTED
ERRNO_CASE(ECONNABORTED);
#endif
#ifdef ECONNREFUSED
ERRNO_CASE(ECONNREFUSED);
#endif
#ifdef ECONNRESET
ERRNO_CASE(ECONNRESET);
#endif
#ifdef EDEADLK
ERRNO_CASE(EDEADLK);
#endif
#ifdef EDESTADDRREQ
ERRNO_CASE(EDESTADDRREQ);
#endif
#ifdef EDOM
ERRNO_CASE(EDOM);
#endif
#ifdef EDQUOT
ERRNO_CASE(EDQUOT);
#endif
#ifdef EEXIST
ERRNO_CASE(EEXIST);
#endif
#ifdef EFAULT
ERRNO_CASE(EFAULT);
#endif
#ifdef EFBIG
ERRNO_CASE(EFBIG);
#endif
#ifdef EHOSTUNREACH
ERRNO_CASE(EHOSTUNREACH);
#endif
#ifdef EIDRM
ERRNO_CASE(EIDRM);
#endif
#ifdef EILSEQ
ERRNO_CASE(EILSEQ);
#endif
#ifdef EINPROGRESS
ERRNO_CASE(EINPROGRESS);
#endif
#ifdef EINTR
ERRNO_CASE(EINTR);
#endif
#ifdef EINVAL
ERRNO_CASE(EINVAL);
#endif
#ifdef EIO
ERRNO_CASE(EIO);
#endif
#ifdef EISCONN
ERRNO_CASE(EISCONN);
#endif
#ifdef EISDIR
ERRNO_CASE(EISDIR);
#endif
#ifdef ELOOP
ERRNO_CASE(ELOOP);
#endif
#ifdef EMFILE
ERRNO_CASE(EMFILE);
#endif
#ifdef EMLINK
ERRNO_CASE(EMLINK);
#endif
#ifdef EMSGSIZE
ERRNO_CASE(EMSGSIZE);
#endif
#ifdef EMULTIHOP
ERRNO_CASE(EMULTIHOP);
#endif
#ifdef ENAMETOOLONG
ERRNO_CASE(ENAMETOOLONG);
#endif
#ifdef ENETDOWN
ERRNO_CASE(ENETDOWN);
#endif
#ifdef ENETRESET
ERRNO_CASE(ENETRESET);
#endif
#ifdef ENETUNREACH
ERRNO_CASE(ENETUNREACH);
#endif
#ifdef ENFILE
ERRNO_CASE(ENFILE);
#endif
#ifdef ENOBUFS
ERRNO_CASE(ENOBUFS);
#endif
#ifdef ENODATA
ERRNO_CASE(ENODATA);
#endif
#ifdef ENODEV
ERRNO_CASE(ENODEV);
#endif
#ifdef ENOENT
ERRNO_CASE(ENOENT);
#endif
#ifdef ENOEXEC
ERRNO_CASE(ENOEXEC);
#endif
#ifdef ENOLINK
ERRNO_CASE(ENOLINK);
#endif
#ifdef ENOLCK
# if ENOLINK != ENOLCK
ERRNO_CASE(ENOLCK);
# endif
#endif
#ifdef ENOMEM
ERRNO_CASE(ENOMEM);
#endif
#ifdef ENOMSG
ERRNO_CASE(ENOMSG);
#endif
#ifdef ENOPROTOOPT
ERRNO_CASE(ENOPROTOOPT);
#endif
#ifdef ENOSPC
ERRNO_CASE(ENOSPC);
#endif
#ifdef ENOSR
ERRNO_CASE(ENOSR);
#endif
#ifdef ENOSTR
ERRNO_CASE(ENOSTR);
#endif
#ifdef ENOSYS
ERRNO_CASE(ENOSYS);
#endif
#ifdef ENOTCONN
ERRNO_CASE(ENOTCONN);
#endif
#ifdef ENOTDIR
ERRNO_CASE(ENOTDIR);
#endif
#ifdef ENOTEMPTY
# if ENOTEMPTY != EEXIST
ERRNO_CASE(ENOTEMPTY);
# endif
#endif
#ifdef ENOTSOCK
ERRNO_CASE(ENOTSOCK);
#endif
#ifdef ENOTSUP
ERRNO_CASE(ENOTSUP);
#else
# ifdef EOPNOTSUPP
ERRNO_CASE(EOPNOTSUPP);
# endif
#endif
#ifdef ENOTTY
ERRNO_CASE(ENOTTY);
#endif
#ifdef ENXIO
ERRNO_CASE(ENXIO);
#endif
#ifdef EOVERFLOW
ERRNO_CASE(EOVERFLOW);
#endif
#ifdef EPERM
ERRNO_CASE(EPERM);
#endif
#ifdef EPIPE
ERRNO_CASE(EPIPE);
#endif
#ifdef EPROTO
ERRNO_CASE(EPROTO);
#endif
#ifdef EPROTONOSUPPORT
ERRNO_CASE(EPROTONOSUPPORT);
#endif
#ifdef EPROTOTYPE
ERRNO_CASE(EPROTOTYPE);
#endif
#ifdef ERANGE
ERRNO_CASE(ERANGE);
#endif
#ifdef EROFS
ERRNO_CASE(EROFS);
#endif
#ifdef ESPIPE
ERRNO_CASE(ESPIPE);
#endif
#ifdef ESRCH
ERRNO_CASE(ESRCH);
#endif
#ifdef ESTALE
ERRNO_CASE(ESTALE);
#endif
#ifdef ETIME
ERRNO_CASE(ETIME);
#endif
#ifdef ETIMEDOUT
ERRNO_CASE(ETIMEDOUT);
#endif
#ifdef ETXTBSY
ERRNO_CASE(ETXTBSY);
#endif
#ifdef EXDEV
ERRNO_CASE(EXDEV);
#endif
default: return "";
}
}
#define NODE_MODULE_CONTEXT_AWARE_INTERNAL(modname, regfunc) \
NODE_MODULE_CONTEXT_AWARE_X(modname, regfunc, NULL, NM_F_INTERNAL) \

View File

@ -0,0 +1,187 @@
// Flags: --expose-internals
'use strict';
const common = require('../common');
const assert = require('assert');
const errors = require('internal/errors');
common.expectsError(
() => { throw new errors.SystemError(); },
{
code: 'ERR_SYSTEM_ERROR',
type: errors.SystemError,
message: 'A system error occurred'
}
);
common.expectsError(
() => { throw new errors.SystemError({}); },
{
code: 'ERR_SYSTEM_ERROR',
type: errors.SystemError,
message: 'A system error occurred'
}
);
common.expectsError(
() => { throw new errors.SystemError(null); },
{
code: 'ERR_SYSTEM_ERROR',
type: errors.SystemError,
message: 'A system error occurred'
}
);
common.expectsError(
() => { throw new errors.SystemError({ code: 'ERR' }); },
{
code: 'ERR_SYSTEM_ERROR',
type: errors.SystemError,
message: 'A system error occurred: ERR'
}
);
{
const ctx = {
code: 'ERR',
syscall: 'foo'
};
common.expectsError(
() => { throw new errors.SystemError(ctx); },
{
code: 'ERR_SYSTEM_ERROR',
type: errors.SystemError,
message: 'A system error occurred: ERR [foo]'
}
);
}
{
const ctx = {
code: 'ERR',
syscall: 'foo',
path: Buffer.from('a')
};
common.expectsError(
() => { throw new errors.SystemError(ctx); },
{
code: 'ERR_SYSTEM_ERROR',
type: errors.SystemError,
message: 'A system error occurred: ERR [foo]: a'
}
);
}
{
const ctx = {
code: 'ERR',
syscall: 'foo',
path: Buffer.from('a'),
dest: Buffer.from('b')
};
common.expectsError(
() => { throw new errors.SystemError(ctx); },
{
code: 'ERR_SYSTEM_ERROR',
type: errors.SystemError,
message: 'A system error occurred: ERR [foo]: a => b'
}
);
}
{
const ctx = {
syscall: 'foo',
path: Buffer.from('a'),
dest: Buffer.from('b')
};
common.expectsError(
() => { throw new errors.SystemError(ctx); },
{
code: 'ERR_SYSTEM_ERROR',
type: errors.SystemError,
message: 'A system error occurred: [foo]: a => b'
}
);
}
{
const ctx = {
path: Buffer.from('a'),
dest: Buffer.from('b')
};
common.expectsError(
() => { throw new errors.SystemError(ctx); },
{
code: 'ERR_SYSTEM_ERROR',
type: errors.SystemError,
message: 'A system error occurred: a => b'
}
);
}
{
const ctx = {
code: 'ERR',
message: 'something happened',
syscall: 'foo',
path: Buffer.from('a'),
dest: Buffer.from('b')
};
common.expectsError(
() => { throw new errors.SystemError(ctx); },
{
code: 'ERR_SYSTEM_ERROR',
type: errors.SystemError,
message: 'something happened: ERR [foo]: a => b'
}
);
}
{
const ctx = {
code: 'ERR_ASSERTION'
};
common.expectsError(
() => { throw new errors.SystemError(ctx); },
{
code: 'ERR_ASSERTION',
type: errors.SystemError
}
);
}
{
const ctx = {
code: 'ERR',
errno: 123,
message: 'something happened',
syscall: 'foo',
path: Buffer.from('a'),
dest: Buffer.from('b')
};
const err = new errors.SystemError(ctx);
assert.strictEqual(err.info, ctx);
assert.strictEqual(err.code, 'ERR_SYSTEM_ERROR');
err.code = 'test';
assert.strictEqual(err.code, 'test');
// Test legacy properties. These shouldn't be used anymore
// but let us make sure they still work
assert.strictEqual(err.errno, 123);
assert.strictEqual(err.syscall, 'foo');
assert.strictEqual(err.path, 'a');
assert.strictEqual(err.dest, 'b');
// Make sure it's mutable
err.code = 'test';
err.errno = 321;
err.syscall = 'test';
err.path = 'path';
err.dest = 'path';
assert.strictEqual(err.errno, 321);
assert.strictEqual(err.syscall, 'test');
assert.strictEqual(err.path, 'path');
assert.strictEqual(err.dest, 'path');
}