Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[v12.x] multiple util and assert backports #31431

Closed
wants to merge 15 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions benchmark/util/format.js
Expand Up @@ -13,6 +13,8 @@ const inputs = {
'no-replace-2': ['foobar', 'yeah', 'mensch', 5],
'only-objects': [{ msg: 'This is an error' }, { msg: 'This is an error' }],
'many-%': ['replace%%%%s%%%%many%s%s%s', 'percent'],
'object-to-string': ['foo %s bar', { toString() { return 'bla'; } }],
'object-%s': ['foo %s bar', { a: true, b: false }],
};

const bench = common.createBenchmark(main, {
Expand Down
18 changes: 13 additions & 5 deletions benchmark/util/inspect-proxy.js
Expand Up @@ -3,13 +3,21 @@
const util = require('util');
const common = require('../common.js');

const bench = common.createBenchmark(main, { n: [2e4] });
const bench = common.createBenchmark(main, {
n: [1e5],
showProxy: [0, 1],
isProxy: [0, 1]
});

function main({ n }) {
const proxyA = new Proxy({}, { get: () => {} });
const proxyB = new Proxy(() => {}, {});
function main({ n, showProxy, isProxy }) {
let proxyA = {};
let proxyB = () => {};
if (isProxy) {
proxyA = new Proxy(proxyA, { get: () => {} });
proxyB = new Proxy(proxyB, {});
}
bench.start();
for (let i = 0; i < n; i += 1)
util.inspect({ a: proxyA, b: proxyB }, { showProxy: true });
util.inspect({ a: proxyA, b: proxyB }, { showProxy });
bench.end(n);
}
172 changes: 126 additions & 46 deletions doc/api/assert.md
Expand Up @@ -218,8 +218,9 @@ are also recursively evaluated by the following rules.
* [`Symbol`][] properties are not compared.
* [`WeakMap`][] and [`WeakSet`][] comparison does not rely on their values.

The following example does not throw an `AssertionError` because the primitives
are considered equal by the [Abstract Equality Comparison][] ( `==` ).
The following example does not throw an [`AssertionError`][] because the
primitives are considered equal by the [Abstract Equality Comparison][]
( `==` ).

```js
// WARNING: This does not throw an AssertionError!
Expand Down Expand Up @@ -264,11 +265,11 @@ assert.deepEqual(obj1, obj4);
// AssertionError: { a: { b: 1 } } deepEqual {}
```

If the values are not equal, an `AssertionError` is thrown with a `message`
If the values are not equal, an [`AssertionError`][] is thrown with a `message`
property set equal to the value of the `message` parameter. If the `message`
parameter is undefined, a default error message is assigned. If the `message`
parameter is an instance of an [`Error`][] then it will be thrown instead of the
`AssertionError`.
[`AssertionError`][].

## `assert.deepStrictEqual(actual, expected[, message])`
<!-- YAML
Expand Down Expand Up @@ -418,12 +419,48 @@ assert.deepStrictEqual(weakMap1, weakMap3);
// }
```

If the values are not equal, an `AssertionError` is thrown with a `message`
If the values are not equal, an [`AssertionError`][] is thrown with a `message`
property set equal to the value of the `message` parameter. If the `message`
parameter is undefined, a default error message is assigned. If the `message`
parameter is an instance of an [`Error`][] then it will be thrown instead of the
`AssertionError`.

## `assert.doesNotMatch(string, regexp[, message])`
<!-- YAML
added: REPLACEME
-->

* `string` {string}
* `regexp` {RegExp}
* `message` {string|Error}

> Stability: 1 - Experimental

Expects the `string` input not to match the regular expression.

This feature is currently experimental and the name might change or it might be
completely removed again.

```js
const assert = require('assert').strict;

assert.doesNotMatch('I will fail', /fail/);
// AssertionError [ERR_ASSERTION]: The input was expected to not match the ...

assert.doesNotMatch(123, /pass/);
// AssertionError [ERR_ASSERTION]: The "string" argument must be of type string.

assert.doesNotMatch('I will pass', /different/);
// OK
```

If the values do match, or if the `string` argument is of another type than
`string`, an [`AssertionError`][] is thrown with a `message` property set equal
to the value of the `message` parameter. If the `message` parameter is
undefined, a default error message is assigned. If the `message` parameter is an
instance of an [`Error`][] then it will be thrown instead of the
[`AssertionError`][].

## `assert.doesNotReject(asyncFn[, error][, message])`
<!-- YAML
added: v10.0.0
Expand Down Expand Up @@ -501,9 +538,9 @@ When `assert.doesNotThrow()` is called, it will immediately call the `fn`
function.

If an error is thrown and it is the same type as that specified by the `error`
parameter, then an `AssertionError` is thrown. If the error is of a different
type, or if the `error` parameter is undefined, the error is propagated back
to the caller.
parameter, then an [`AssertionError`][] is thrown. If the error is of a
different type, or if the `error` parameter is undefined, the error is
propagated back to the caller.

If specified, `error` can be a [`Class`][], [`RegExp`][] or a validation
function. See [`assert.throws()`][] for more details.
Expand All @@ -521,7 +558,7 @@ assert.doesNotThrow(
);
```

However, the following will result in an `AssertionError` with the message
However, the following will result in an [`AssertionError`][] with the message
'Got unwanted exception...':

<!-- eslint-disable no-restricted-syntax -->
Expand All @@ -534,8 +571,8 @@ assert.doesNotThrow(
);
```

If an `AssertionError` is thrown and a value is provided for the `message`
parameter, the value of `message` will be appended to the `AssertionError`
If an [`AssertionError`][] is thrown and a value is provided for the `message`
parameter, the value of `message` will be appended to the [`AssertionError`][]
message:

<!-- eslint-disable no-restricted-syntax -->
Expand Down Expand Up @@ -584,7 +621,7 @@ assert.equal({ a: { b: 1 } }, { a: { b: 1 } });
// AssertionError: { a: { b: 1 } } == { a: { b: 1 } }
```

If the values are not equal, an `AssertionError` is thrown with a `message`
If the values are not equal, an [`AssertionError`][] is thrown with a `message`
property set equal to the value of the `message` parameter. If the `message`
parameter is undefined, a default error message is assigned. If the `message`
parameter is an instance of an [`Error`][] then it will be thrown instead of the
Expand All @@ -597,9 +634,9 @@ added: v0.1.21

* `message` {string|Error} **Default:** `'Failed'`

Throws an `AssertionError` with the provided error message or a default error
message. If the `message` parameter is an instance of an [`Error`][] then it
will be thrown instead of the `AssertionError`.
Throws an [`AssertionError`][] with the provided error message or a default
error message. If the `message` parameter is an instance of an [`Error`][] then
it will be thrown instead of the [`AssertionError`][].

```js
const assert = require('assert').strict;
Expand Down Expand Up @@ -687,7 +724,7 @@ changes:
- version: v10.0.0
pr-url: https://github.com/nodejs/node/pull/18247
description: Instead of throwing the original error it is now wrapped into
an `AssertionError` that contains the full stack trace.
an [`AssertionError`][] that contains the full stack trace.
- version: v10.0.0
pr-url: https://github.com/nodejs/node/pull/18247
description: Value may now only be `undefined` or `null`. Before all falsy
Expand Down Expand Up @@ -727,6 +764,42 @@ let err;
// at errorFrame
```

## `assert.match(string, regexp[, message])`
<!-- YAML
added: REPLACEME
-->

* `string` {string}
* `regexp` {RegExp}
* `message` {string|Error}

> Stability: 1 - Experimental

Expects the `string` input to match the regular expression.

This feature is currently experimental and the name might change or it might be
completely removed again.

```js
const assert = require('assert').strict;

assert.match('I will fail', /pass/);
// AssertionError [ERR_ASSERTION]: The input did not match the regular ...

assert.match(123, /pass/);
// AssertionError [ERR_ASSERTION]: The "string" argument must be of type string.

assert.match('I will pass', /pass/);
// OK
```

If the values do not match, or if the `string` argument is of another type than
`string`, an [`AssertionError`][] is thrown with a `message` property set equal
to the value of the `message` parameter. If the `message` parameter is
undefined, a default error message is assigned. If the `message` parameter is an
instance of an [`Error`][] then it will be thrown instead of the
[`AssertionError`][].

## `assert.notDeepEqual(actual, expected[, message])`
<!-- YAML
added: v0.1.21
Expand Down Expand Up @@ -795,11 +868,11 @@ assert.notDeepEqual(obj1, obj4);
// OK
```

If the values are deeply equal, an `AssertionError` is thrown with a `message`
property set equal to the value of the `message` parameter. If the `message`
parameter is undefined, a default error message is assigned. If the `message`
parameter is an instance of an [`Error`][] then it will be thrown instead of the
`AssertionError`.
If the values are deeply equal, an [`AssertionError`][] is thrown with a
`message` property set equal to the value of the `message` parameter. If the
`message` parameter is undefined, a default error message is assigned. If the
`message` parameter is an instance of an [`Error`][] then it will be thrown
instead of the `AssertionError`.

## `assert.notDeepStrictEqual(actual, expected[, message])`
<!-- YAML
Expand Down Expand Up @@ -843,11 +916,11 @@ assert.notDeepStrictEqual({ a: 1 }, { a: '1' });
// OK
```

If the values are deeply and strictly equal, an `AssertionError` is thrown with
a `message` property set equal to the value of the `message` parameter. If the
`message` parameter is undefined, a default error message is assigned. If the
`message` parameter is an instance of an [`Error`][] then it will be thrown
instead of the `AssertionError`.
If the values are deeply and strictly equal, an [`AssertionError`][] is thrown
with a `message` property set equal to the value of the `message` parameter. If
the `message` parameter is undefined, a default error message is assigned. If
the `message` parameter is an instance of an [`Error`][] then it will be thrown
instead of the [`AssertionError`][].

## `assert.notEqual(actual, expected[, message])`
<!-- YAML
Expand Down Expand Up @@ -882,10 +955,10 @@ assert.notEqual(1, '1');
// AssertionError: 1 != '1'
```

If the values are equal, an `AssertionError` is thrown with a `message` property
set equal to the value of the `message` parameter. If the `message` parameter is
undefined, a default error message is assigned. If the `message` parameter is an
instance of an [`Error`][] then it will be thrown instead of the
If the values are equal, an [`AssertionError`][] is thrown with a `message`
property set equal to the value of the `message` parameter. If the `message`
parameter is undefined, a default error message is assigned. If the `message`
parameter is an instance of an [`Error`][] then it will be thrown instead of the
`AssertionError`.

## `assert.notStrictEqual(actual, expected[, message])`
Expand Down Expand Up @@ -919,11 +992,11 @@ assert.notStrictEqual(1, '1');
// OK
```

If the values are strictly equal, an `AssertionError` is thrown with a `message`
property set equal to the value of the `message` parameter. If the `message`
parameter is undefined, a default error message is assigned. If the `message`
parameter is an instance of an [`Error`][] then it will be thrown instead of the
`AssertionError`.
If the values are strictly equal, an [`AssertionError`][] is thrown with a
`message` property set equal to the value of the `message` parameter. If the
`message` parameter is undefined, a default error message is assigned. If the
`message` parameter is an instance of an [`Error`][] then it will be thrown
instead of the `AssertionError`.

## `assert.ok(value[, message])`
<!-- YAML
Expand All @@ -941,7 +1014,7 @@ changes:
Tests if `value` is truthy. It is equivalent to
`assert.equal(!!value, true, message)`.

If `value` is not truthy, an `AssertionError` is thrown with a `message`
If `value` is not truthy, an [`AssertionError`][] is thrown with a `message`
property set equal to the value of the `message` parameter. If the `message`
parameter is `undefined`, a default error message is assigned. If the `message`
parameter is an instance of an [`Error`][] then it will be thrown instead of the
Expand Down Expand Up @@ -1020,8 +1093,8 @@ an object where each property will be tested for, or an instance of error where
each property will be tested for including the non-enumerable `message` and
`name` properties.

If specified, `message` will be the message provided by the `AssertionError` if
the `asyncFn` fails to reject.
If specified, `message` will be the message provided by the [`AssertionError`][]
if the `asyncFn` fails to reject.

```js
(async () => {
Expand Down Expand Up @@ -1096,11 +1169,11 @@ assert.strictEqual(1, '1', new TypeError('Inputs are not identical'));
// TypeError: Inputs are not identical
```

If the values are not strictly equal, an `AssertionError` is thrown with a
If the values are not strictly equal, an [`AssertionError`][] is thrown with a
`message` property set equal to the value of the `message` parameter. If the
`message` parameter is undefined, a default error message is assigned. If the
`message` parameter is an instance of an [`Error`][] then it will be thrown
instead of the `AssertionError`.
instead of the [`AssertionError`][].

## `assert.throws(fn[, error][, message])`
<!-- YAML
Expand Down Expand Up @@ -1192,10 +1265,15 @@ assert.throws(
assert.throws(
() => {
const otherErr = new Error('Not found');
otherErr.code = 404;
// Copy all enumerable properties from `err` to `otherErr`.
for (const [key, value] of Object.entries(err)) {
otherErr[key] = value;
}
throw otherErr;
},
err // This tests for `message`, `name` and `code`.
// The error's `message` and `name` properties will also be checked when using
// an error as validation object.
err
);
```

Expand Down Expand Up @@ -1226,6 +1304,9 @@ assert.throws(

Custom error validation:

The function must return `true` to indicate all internal validations passed.
It will otherwise fail with an [`AssertionError`][].

```js
assert.throws(
() => {
Expand Down Expand Up @@ -1282,16 +1363,15 @@ assert.throws(notThrowing, 'Second');
// It does not throw because the error messages match.
assert.throws(throwingSecond, /Second$/);

// If the error message does not match, the error from within the function is
// not caught.
// If the error message does not match, an AssertionError is thrown.
assert.throws(throwingFirst, /Second$/);
// Error: First
// at throwingFirst (repl:2:9)
// AssertionError [ERR_ASSERTION]
```

Due to the confusing error-prone notation, avoid a string as the second
argument.

[`AssertionError`]: #assert_class_assert_assertionerror
[`Class`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
[`ERR_INVALID_RETURN_VALUE`]: errors.html#errors_err_invalid_return_value
[`Error.captureStackTrace`]: errors.html#errors_error_capturestacktrace_targetobject_constructoropt
Expand Down
7 changes: 6 additions & 1 deletion doc/api/util.md
Expand Up @@ -398,6 +398,10 @@ stream.write('With ES6');
<!-- YAML
added: v0.3.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/30768
description: User defined prototype properties are inspected in case
`showHidden` is `true`.
- version: v12.0.0
pr-url: https://github.com/nodejs/node/pull/27109
description: The `compact` options default is changed to `3` and the
Expand Down Expand Up @@ -458,7 +462,8 @@ changes:
* `options` {Object}
* `showHidden` {boolean} If `true`, `object`'s non-enumerable symbols and
properties are included in the formatted result. [`WeakMap`][] and
[`WeakSet`][] entries are also included. **Default:** `false`.
[`WeakSet`][] entries are also included as well as user defined prototype
properties (excluding method properties). **Default:** `false`.
* `depth` {number} Specifies the number of times to recurse while formatting
`object`. This is useful for inspecting large objects. To recurse up to
the maximum call stack size pass `Infinity` or `null`.
Expand Down