diff --git a/.github/workflows/ci-module.yml b/.github/workflows/ci-module.yml
index 54426ca2..49bcabb9 100644
--- a/.github/workflows/ci-module.yml
+++ b/.github/workflows/ci-module.yml
@@ -1,14 +1,13 @@
name: ci
on:
- push:
- branches:
- - master
- pull_request:
- workflow_dispatch:
+ push:
+ branches:
+ - master
+ - next
+ pull_request:
+ workflow_dispatch:
jobs:
- test:
- uses: hapijs/.github/.github/workflows/ci-module.yml@master
- with:
- min-node-version: 14
+ test:
+ uses: hapijs/.github/.github/workflows/ci-module.yml@min-node-22-hapi-21
diff --git a/.gitignore b/.gitignore
index 8f679c9d..e0b41f66 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,7 @@
**/node_modules
**/package-lock.json
-coverage.*
+coverage
**/.DS_Store
**/._*
@@ -11,3 +11,4 @@ coverage.*
**/.vs
**/.vscode
**/.idea
+dist
diff --git a/API.md b/API.md
index ae0a7c68..4f9b16ea 100755
--- a/API.md
+++ b/API.md
@@ -1,12 +1,12 @@
-
### Object
**hoek** provides several helpful methods for objects and arrays.
#### clone(obj, [options])
-Clones an object or an array. A *deep copy* is made (duplicates everything, including values that are
+Clones an object or an array. A _deep copy_ is made (duplicates everything, including values that are
objects, as well as non-enumerable properties) where:
+
- `obj` - the object to be cloned.
- `options` - optional settings:
- `symbols` - clone symbol properties. Defaults to `true`.
@@ -15,54 +15,53 @@ objects, as well as non-enumerable properties) where:
- `true` to shallow copy all object properties. Used to shallow copy an object with non-enumerable properties and prototype;
```javascript
-
const nestedObj = {
- w: /^something$/ig,
- x: {
- a: [1, 2, 3],
- b: 123456,
- c: new Date()
- },
- y: 'y',
- z: new Date()
- };
+ w: /^something$/gi,
+ x: {
+ a: [1, 2, 3],
+ b: 123456,
+ c: new Date(),
+ },
+ y: 'y',
+ z: new Date(),
+};
const copy = Hoek.clone(nestedObj);
copy.x.b = 100;
-console.log(copy.y); // results in 'y'
+console.log(copy.y); // results in 'y'
console.log(nestedObj.x.b); // results in 123456
-console.log(copy.x.b); // results in 100
+console.log(copy.x.b); // results in 100
```
Clones an object or array excluding some keys which are shallow copied:
```javascript
-
const nestedObj = {
- w: /^something$/ig,
- x: {
- a: [1, 2, 3],
- b: 123456,
- c: new Date()
- },
- y: 'y',
- z: new Date()
- };
+ w: /^something$/gi,
+ x: {
+ a: [1, 2, 3],
+ b: 123456,
+ c: new Date(),
+ },
+ y: 'y',
+ z: new Date(),
+};
const copy = Hoek.clone(nestedObj, { shallow: ['x'] });
copy.x.b = 100;
-console.log(copy.y); // results in 'y'
+console.log(copy.y); // results in 'y'
console.log(nestedObj.x.b); // results in 100
-console.log(copy.x.b); // results in 100
+console.log(copy.x.b); // results in 100
```
#### merge(target, source, [options])
Merge all the properties of source into target where:
+
- `target` - the object onto which the properties of `source` are copied to.
- `source` - the object copied onto `target`.
- `options` - optional settings:
@@ -75,27 +74,26 @@ Merge all the properties of source into target where:
Note that source wins in conflict, and by default null and undefined from source are applied.
Merge is destructive where the target is modified. For non destructive merge, use `applyToDefaults`.
-
```javascript
+const target = { a: 1, b: 2 };
+const source = { a: 0, c: 5 };
+const source2 = { a: null, c: 5 };
-const target = {a: 1, b : 2};
-const source = {a: 0, c: 5};
-const source2 = {a: null, c: 5};
-
-Hoek.merge(target, source); // results in {a: 0, b: 2, c: 5}
-Hoek.merge(target, source2); // results in {a: null, b: 2, c: 5}
-Hoek.merge(target, source2, { nullOverride: false} ); // results in {a: 1, b: 2, c: 5}
+Hoek.merge(target, source); // results in {a: 0, b: 2, c: 5}
+Hoek.merge(target, source2); // results in {a: null, b: 2, c: 5}
+Hoek.merge(target, source2, { nullOverride: false }); // results in {a: 1, b: 2, c: 5}
const targetArray = [1, 2, 3];
const sourceArray = [4, 5];
-Hoek.merge(targetArray, sourceArray); // results in [1, 2, 3, 4, 5]
+Hoek.merge(targetArray, sourceArray); // results in [1, 2, 3, 4, 5]
Hoek.merge(targetArray, sourceArray, { mergeArrays: false }); // results in [4, 5]
```
#### applyToDefaults(defaults, source, [options])
Apply source to a copy of the defaults where:
+
- `defaults` - the default object to clone and then apply `source` onto.
- `source` - the object applied to the `defaults`.
- `options` - optional settings:
@@ -104,8 +102,7 @@ Apply source to a copy of the defaults where:
- `shallow` - an array of dot-separated or array-based key paths to shallow copy values in `source`.
```javascript
-
-const defaults = { host: "localhost", port: 8000 };
+const defaults = { host: 'localhost', port: 8000 };
const source = { port: 8080 };
const config = Hoek.applyToDefaults(defaults, source); // results in { host: "localhost", port: 8080 }
@@ -114,8 +111,7 @@ const config = Hoek.applyToDefaults(defaults, source); // results in { host: "lo
Apply source with a null value to a copy of the defaults
```javascript
-
-const defaults = { host: "localhost", port: 8000 };
+const defaults = { host: 'localhost', port: 8000 };
const source = { host: null, port: 8080 };
const config = Hoek.applyToDefaults(defaults, source, { nullOverride: true }); // results in { host: null, port: 8080 }
@@ -124,27 +120,27 @@ const config = Hoek.applyToDefaults(defaults, source, { nullOverride: true }); /
Apply source to a copy of the defaults where the shallow keys specified in the last parameter are shallow copied from source instead of merged
```javascript
-
const defaults = {
db: {
server: {
- host: "localhost",
- port: 8000
+ host: 'localhost',
+ port: 8000,
},
- name: 'example'
- }
+ name: 'example',
+ },
};
const source = { db: { server: { port: 8080 } } };
-const config = Hoek.applyToDefaults(defaults, source, { shallow: ['db.server'] }); // results in { db: { server: { port: 8080 }, name: 'example' } }
-const config = Hoek.applyToDefaults(defaults, source, { shallow: [['db', 'server']] }); // results in { db: { server: { port: 8080 }, name: 'example' } }
+const config = Hoek.applyToDefaults(defaults, source, { shallow: ['db.server'] }); // results in { db: { server: { port: 8080 }, name: 'example' } }
+const config = Hoek.applyToDefaults(defaults, source, { shallow: [['db', 'server']] }); // results in { db: { server: { port: 8080 }, name: 'example' } }
```
#### deepEqual(a, b, [options])
Performs a deep comparison of the two values including support for circular dependencies,
prototype, and enumerable properties, where:
+
- `a` - the first value.
- `b` - the second value.
- `options` - optional settings:
@@ -168,13 +164,13 @@ Hoek.deepEqual(Object.create(null), {}); //results in false
#### intersect(array1, array2, [options])
Find the common unique items betwee two arrays where:
+
- `array1` - the first array.
- `array2` - the second array.
- `options` - optional settings:
- `first` - if `true`, return only the first intersecting item. Defaults to `false`.
```javascript
-
const array1 = [1, 2, 3];
const array2 = [1, 4, 5];
@@ -184,6 +180,7 @@ const newArray = Hoek.intersect(array1, array2); // results in [1]
#### contain(ref, values, [options])
Tests if the reference value contains the provided values where:
+
- `ref` - the reference string, array, or object.
- `values` - a single or array of values to find within the `ref` value. If `ref` is an object, `values` can be a key name,
an array of key names, or an object with key-value pairs to compare.
@@ -198,9 +195,9 @@ Note: comparing a string to overlapping values will result in failed comparison
Also, if an object key's value does not match the provided value, `false` is returned even when `part` is specified.
```javascript
-Hoek.contain('aaa', 'a', { only: true }); // true
-Hoek.contain([{ a: 1 }], [{ a: 1 }], { deep: true }); // true
-Hoek.contain([1, 2, 2], [1, 2], { once: true }); // false
+Hoek.contain('aaa', 'a', { only: true }); // true
+Hoek.contain([{ a: 1 }], [{ a: 1 }], { deep: true }); // true
+Hoek.contain([1, 2, 2], [1, 2], { once: true }); // false
Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 1, d: 4 }, { part: true }); // true
```
@@ -209,7 +206,6 @@ Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 1, d: 4 }, { part: true }); // true
Flatten an array
```javascript
-
const array = [1, [2, 3]];
const flattenedArray = Hoek.flatten(array); // results in [1, 2, 3]
@@ -243,14 +239,13 @@ A chain including negative numbers will work like negative indices on an array.
If chain is `null`, `undefined` or `false`, the object itself will be returned.
```javascript
-
const chain = 'a.b.c';
-const obj = {a : {b : { c : 1}}};
+const obj = { a: { b: { c: 1 } } };
Hoek.reach(obj, chain); // returns 1
const chain = ['a', 'b', -1];
-const obj = {a : {b : [2,3,6]}};
+const obj = { a: { b: [2, 3, 6] } };
Hoek.reach(obj, chain); // returns 6
```
@@ -280,7 +275,7 @@ error message) without the need to worry about invalid conversion.
```javascript
const a = {};
a.b = a;
-Hoek.stringify(a); // Returns '[Cannot display object: Converting circular structure to JSON]'
+Hoek.stringify(a); // Returns '[Cannot display object: Converting circular structure to JSON]'
```
### Bench
@@ -293,21 +288,19 @@ human-readable timestamps. More accurate for benchmarking or internal timers.
**hoek** provides convenient methods for escaping html characters. The escaped characters are as followed:
```javascript
-
internals.htmlEscaped = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": ''',
- '`': '`'
+ '`': '`',
};
```
#### escapeHtml(string)
```javascript
-
const string = ' hey ';
const escapedString = Hoek.escapeHtml(string); // returns <html> hey </html>
```
@@ -317,8 +310,7 @@ const escapedString = Hoek.escapeHtml(string); // returns <html> hey </
Escape attribute value for use in HTTP header
```javascript
-
-const a = Hoek.escapeHeaderAttribute('I said "go w\\o me"'); //returns I said \"go w\\o me\"
+const a = Hoek.escapeHeaderAttribute('I said "go w\\o me"'); //returns I said \"go w\\o me\"
```
#### escapeJson(string)
@@ -326,9 +318,8 @@ const a = Hoek.escapeHeaderAttribute('I said "go w\\o me"'); //returns I said \
Unicode escapes the characters `<`, `>`, and `&` to prevent mime-sniffing older browsers mistaking JSON as HTML, and escapes line and paragraph separators for JSONP and script contexts.
```javascript
-
const lineSeparator = String.fromCharCode(0x2028);
-const a = Hoek.escapeJson('I said ');
- expect(encoded).to.equal('<script>alert(1)</script>');
+ expect(encoded).toEqual('<script>alert(1)</script>');
});
it('encodes < and > as named characters', () => {
-
const encoded = Hoek.escapeHtml('');
- expect(encoded).to.equal('\\u003cscript\\u003ealert(1)\\u003c/script\\u003e');
+ expect(encoded).toEqual('\\u003cscript\\u003ealert(1)\\u003c/script\\u003e');
});
});
diff --git a/test/exports.js b/test/exports.js
deleted file mode 100644
index 4cdf1f9f..00000000
--- a/test/exports.js
+++ /dev/null
@@ -1,88 +0,0 @@
-'use strict';
-
-const Code = require('@hapi/code');
-const Lab = require('@hapi/lab');
-const Hoek = require('..');
-
-
-const internals = {};
-
-
-const { before, describe, it } = exports.lab = Lab.script();
-const expect = Code.expect;
-
-
-internals.uncapitalize = (str) => {
-
- // Used capitalized classes like "Bench" and "Error"
-
- return str[0].toLowerCase() + str.slice(1);
-};
-
-
-describe('ESM', () => {
-
- let esmHoek;
-
- before(async () => {
-
- esmHoek = await import('@hapi/hoek');
- });
-
- it('exposes all methods and classes as named imports', () => {
-
- const rlist = Object.keys(Hoek).sort();
- const mlist = Object.keys(esmHoek).sort();
-
- expect(mlist).to.equal(rlist);
- expect(esmHoek).to.equal(Hoek);
- expect(esmHoek).to.not.shallow.equal(Hoek);
- });
-
- it('exposes all methods and classes as direct imports', async () => {
-
- const exported = await Promise.all(Object.keys(Hoek).map((item) => import(`@hapi/hoek/${internals.uncapitalize(item)}`)));
- const defaulted = exported.map((item) => item.default);
-
- expect(defaulted).to.equal(Object.values(Hoek));
- });
-
- it('can call an exported destructured method', () => {
-
- const { assert } = esmHoek;
-
- expect(() => assert(false, 'oops')).to.throw('oops');
- });
-
- it('exports identical classes as CJS', async () => {
-
- const error = (await import(`@hapi/hoek/assertError`)).default;
-
- expect(error).to.shallow.equal(Hoek.AssertError);
- expect(error).to.shallow.equal(esmHoek.AssertError);
- });
-});
-
-
-describe('package', () => {
-
- it('exports all methods and classes', () => {
-
- const exported = Object.keys(Hoek).map((item) => require(`@hapi/hoek/${internals.uncapitalize(item)}`));
-
- expect(exported).to.equal(Object.values(Hoek));
- });
-
- it('can call an exported method', () => {
-
- const assert = require(`@hapi/hoek/assert`);
-
- expect(() => assert(false, 'oops')).to.throw('oops');
- });
-
- it('does not export unlisted modules', () => {
-
- expect(() => require('@hapi/hoek/types')).to.throw();
- expect(() => require('@hapi/hoek/utils')).to.throw();
- });
-});
diff --git a/test/index.js b/test/index.js
deleted file mode 100755
index 4b45b842..00000000
--- a/test/index.js
+++ /dev/null
@@ -1,2523 +0,0 @@
-'use strict';
-
-const Util = require('util');
-
-const Code = require('@hapi/code');
-const Hoek = require('..');
-const Lab = require('@hapi/lab');
-
-
-const internals = {};
-
-
-const { describe, it } = exports.lab = Lab.script();
-const expect = Code.expect;
-
-
-const nestedObj = {
- v: [7, 8, 9],
- w: /^something$/igm,
- x: {
- a: [1, 2, 3],
- b: 123456,
- c: new Date(),
- d: /hi/igm,
- e: /hello/
- },
- y: 'y',
- z: new Date(1378775452757)
-};
-
-
-describe('merge()', () => {
-
- it('deep copies source items', () => {
-
- const sym1 = Symbol('1');
- const sym2 = Symbol('2');
- const sym3 = Symbol('3');
-
- const target = {
- b: 3,
- d: [],
- [sym1]: true,
- [sym3]: true
- };
-
- const source = {
- c: {
- d: 1
- },
- d: [{ e: 1 }],
- [sym2]: true,
- [sym3]: false
- };
-
- Hoek.merge(target, source);
- expect(target.c).to.not.shallow.equal(source.c);
- expect(target.c).to.equal(source.c);
- expect(target.d).to.not.shallow.equal(source.d);
- expect(target.d[0]).to.not.shallow.equal(source.d[0]);
- expect(target.d).to.equal(source.d);
-
- expect(target[sym1]).to.be.true();
- expect(target[sym2]).to.be.true();
- expect(target[sym3]).to.be.false();
- });
-
- it('deep copies source items without symbols', () => {
-
- const sym1 = Symbol('1');
- const sym2 = Symbol('2');
- const sym3 = Symbol('3');
-
- const target = {
- b: 3,
- d: [],
- [sym1]: true,
- [sym3]: true
- };
-
- const source = {
- c: {
- d: 1
- },
- d: [{ e: 1 }],
- [sym2]: true,
- [sym3]: false
- };
-
- Hoek.merge(target, source, { symbols: false });
- expect(target.c).to.not.shallow.equal(source.c);
- expect(target.c).to.equal(source.c);
- expect(target.d).to.not.shallow.equal(source.d);
- expect(target.d[0]).to.not.shallow.equal(source.d[0]);
- expect(target.d).to.equal(source.d);
-
- expect(target[sym1]).to.be.true();
- expect(target[sym2]).to.not.exist();
- expect(target[sym3]).to.be.true();
- });
-
- it('merges array over an object', () => {
-
- const a = {
- x: ['n', 'm']
- };
-
- const b = {
- x: {
- n: '1',
- m: '2'
- }
- };
-
- Hoek.merge(b, a);
- expect(a.x[0]).to.equal('n');
- expect(a.x.n).to.not.exist();
- });
-
- it('merges object over an array', () => {
-
- const a = {
- x: ['n', 'm']
- };
-
- const b = {
- x: {
- n: '1',
- m: '2'
- }
- };
-
- Hoek.merge(a, b);
- expect(a.x.n).to.equal('1');
- expect(a.x[0]).to.not.exist();
- });
-
- it('merges from null prototype objects', () => {
-
- const a = {};
-
- const b = Object.create(null);
- b.x = true;
-
- Hoek.merge(a, b);
- expect(a.x).to.be.true();
- });
-
- it('skips non-enumerable properties', () => {
-
- const a = { x: 0 };
-
- const b = {};
- Object.defineProperty(b, 'x', {
- enumerable: false,
- value: 1
- });
-
- Hoek.merge(a, b);
- expect(a.x).to.equal(0);
- });
-
- it('does not throw if source is null', () => {
-
- const a = {};
- const b = null;
- let c = null;
-
- expect(() => {
-
- c = Hoek.merge(a, b);
- }).to.not.throw();
-
- expect(c).to.equal(a);
- });
-
- it('does not throw if source is undefined', () => {
-
- const a = {};
- const b = undefined;
- let c = null;
-
- expect(() => {
-
- c = Hoek.merge(a, b);
- }).to.not.throw();
-
- expect(c).to.equal(a);
- });
-
- it('throws if source is not an object', () => {
-
- expect(() => {
-
- const a = {};
- const b = 0;
-
- Hoek.merge(a, b);
- }).to.throw('Invalid source value: must be null, undefined, or an object');
- });
-
- it('throws if target is not an object', () => {
-
- expect(() => {
-
- const a = 0;
- const b = {};
-
- Hoek.merge(a, b);
- }).to.throw('Invalid target value: must be an object');
- });
-
- it('throws if target is not an array and source is', () => {
-
- expect(() => {
-
- const a = {};
- const b = [1, 2];
-
- Hoek.merge(a, b);
- }).to.throw('Cannot merge array onto an object');
- });
-
- it('returns the same object when merging arrays', () => {
-
- const a = [];
- const b = [1, 2];
-
- expect(Hoek.merge(a, b)).to.equal(a);
- });
-
- it('combines an empty object with a non-empty object', () => {
-
- const a = {};
- const b = nestedObj;
-
- const c = Hoek.merge(a, b);
- expect(a).to.equal(b);
- expect(c).to.equal(b);
- });
-
- it('overrides values in target', () => {
-
- const a = { x: 1, y: 2, z: 3, v: 5, t: 'test', s: 1, m: 'abc' };
- const b = { x: null, z: 4, v: 0, t: { u: 6 }, s: undefined, m: '123' };
-
- const c = Hoek.merge(a, b);
- expect(c.x).to.equal(null);
- expect(c.y).to.equal(2);
- expect(c.z).to.equal(4);
- expect(c.v).to.equal(0);
- expect(c.m).to.equal('123');
- expect(c.t).to.equal({ u: 6 });
- expect(c.s).to.equal(undefined);
- });
-
- it('overrides values in target (flip)', () => {
-
- const a = { x: 1, y: 2, z: 3, v: 5, t: 'test', s: 1, m: 'abc' };
- const b = { x: null, z: 4, v: 0, t: { u: 6 }, s: undefined, m: '123' };
-
- const d = Hoek.merge(b, a);
- expect(d.x).to.equal(1);
- expect(d.y).to.equal(2);
- expect(d.z).to.equal(3);
- expect(d.v).to.equal(5);
- expect(d.m).to.equal('abc');
- expect(d.t).to.equal('test');
- expect(d.s).to.equal(1);
- });
-
- it('retains Date properties', () => {
-
- const a = { x: new Date(1378776452757) };
-
- const b = Hoek.merge({}, a);
- expect(a.x.getTime()).to.equal(b.x.getTime());
- });
-
- it('retains Date properties when merging keys', () => {
-
- const a = { x: new Date(1378776452757) };
-
- const b = Hoek.merge({ x: {} }, a);
- expect(a.x.getTime()).to.equal(b.x.getTime());
- });
-
- it('overrides Buffer', () => {
-
- const a = { x: Buffer.from('abc') };
-
- Hoek.merge({ x: {} }, a);
- expect(a.x.toString()).to.equal('abc');
- });
-
- it('overrides RegExp', () => {
-
- const a = { x: /test/ };
-
- Hoek.merge({ x: {} }, a);
- expect(a.x).to.equal(/test/);
- });
-
- it('overrides Symbol properties', () => {
-
- const sym = Symbol();
- const a = { [sym]: 1 };
-
- Hoek.merge({ [sym]: {} }, a);
- expect(a[sym]).to.equal(1);
- });
-
- it('skips __proto__', () => {
-
- const a = '{ "ok": "value", "__proto__": { "test": "value" } }';
-
- const b = Hoek.merge({}, JSON.parse(a));
- expect(b).to.equal({ ok: 'value' });
- expect(b.test).to.equal(undefined);
- });
-});
-
-describe('applyToDefaults()', () => {
-
- it('throws when target is null', () => {
-
- expect(() => {
-
- Hoek.applyToDefaults(null, {});
- }).to.throw('Invalid defaults value: must be an object');
- });
-
- it('throws when options are invalid', () => {
-
- expect(() => {
-
- Hoek.applyToDefaults({}, {}, false);
- }).to.throw('Invalid options: must be an object');
-
- expect(() => {
-
- Hoek.applyToDefaults({}, {}, 123);
- }).to.throw('Invalid options: must be an object');
- });
-
- it('returns null if source is false', () => {
-
- const defaults = {
- a: 1,
- b: 2,
- c: {
- d: 3,
- e: [5, 6]
- },
- f: 6,
- g: 'test'
- };
-
- const result = Hoek.applyToDefaults(defaults, false);
- expect(result).to.equal(null);
- });
-
- it('returns null if source is null', () => {
-
- const defaults = {
- a: 1,
- b: 2,
- c: {
- d: 3,
- e: [5, 6]
- },
- f: 6,
- g: 'test'
- };
-
- const result = Hoek.applyToDefaults(defaults, null);
- expect(result).to.equal(null);
- });
-
- it('returns null if source is undefined', () => {
-
- const defaults = {
- a: 1,
- b: 2,
- c: {
- d: 3,
- e: [5, 6]
- },
- f: 6,
- g: 'test'
- };
-
- const result = Hoek.applyToDefaults(defaults, undefined);
- expect(result).to.equal(null);
- });
-
- it('returns a copy of defaults if source is true', () => {
-
- const defaults = {
- a: 1,
- b: 2,
- c: {
- d: 3,
- e: [5, 6]
- },
- f: 6,
- g: 'test'
- };
-
- const result = Hoek.applyToDefaults(defaults, true);
- expect(result).to.equal(defaults);
- });
-
- it('applies object to defaults', () => {
-
- const defaults = {
- a: 1,
- b: 2,
- c: {
- d: 3,
- e: [5, 6]
- },
- f: 6,
- g: 'test'
- };
-
- const obj = {
- a: null,
- c: {
- e: [4]
- },
- f: 0,
- g: {
- h: 5
- }
- };
-
- const result = Hoek.applyToDefaults(defaults, obj);
- expect(result.c.e).to.equal([4]);
- expect(result.a).to.equal(1);
- expect(result.b).to.equal(2);
- expect(result.f).to.equal(0);
- expect(result.g).to.equal({ h: 5 });
- });
-
- it('applies object to defaults with null', () => {
-
- const defaults = {
- a: 1,
- b: 2,
- c: {
- d: 3,
- e: [5, 6]
- },
- f: 6,
- g: 'test'
- };
-
- const obj = {
- a: null,
- c: {
- e: [4]
- },
- f: 0,
- g: {
- h: 5
- }
- };
-
- const result = Hoek.applyToDefaults(defaults, obj, { nullOverride: true });
- expect(result.c.e).to.equal([4]);
- expect(result.a).to.equal(null);
- expect(result.b).to.equal(2);
- expect(result.f).to.equal(0);
- expect(result.g).to.equal({ h: 5 });
- });
-
- it('shallow copies the listed keys from source without merging', () => {
-
- const defaults = {
- a: {
- b: 5,
- e: 3
- },
- c: {
- d: 7,
- g: 1
- }
- };
-
- const source = {
- a: {
- b: 4
- },
- c: {
- d: 6,
- f: 7
- }
- };
-
- const merged = Hoek.applyToDefaults(defaults, source, { shallow: ['a'] });
- expect(merged).to.equal({ a: { b: 4 }, c: { d: 6, g: 1, f: 7 } });
- expect(merged.a).to.shallow.equal(source.a);
- expect(merged.a).to.not.equal(defaults.a);
- expect(merged.c).to.not.equal(source.c);
- expect(merged.c).to.not.equal(defaults.c);
- });
-
- it('shallow copies the nested keys (override)', () => {
-
- const defaults = {
- a: {
- b: 5
- },
- c: {
- d: 7,
- g: 1
- }
- };
-
- const source = {
- a: {
- b: 4
- },
- c: {
- d: 6,
- g: {
- h: 8
- }
- }
- };
-
- const merged = Hoek.applyToDefaults(defaults, source, { shallow: ['c.g'] });
- expect(merged).to.equal({ a: { b: 4 }, c: { d: 6, g: { h: 8 } } });
- expect(merged.c.g).to.shallow.equal(source.c.g);
- });
-
- it('shallow copies the nested keys (missing)', () => {
-
- const defaults = {
- a: {
- b: 5
- }
- };
-
- const source = {
- a: {
- b: 4
- },
- c: {
- g: {
- h: 8
- }
- }
- };
-
- const merged = Hoek.applyToDefaults(defaults, source, { shallow: ['c.g'] });
- expect(merged).to.equal({ a: { b: 4 }, c: { g: { h: 8 } } });
- expect(merged.c.g).to.shallow.equal(source.c.g);
- });
-
- it('shallow copies the nested keys (override)', () => {
-
- const defaults = {
- a: {
- b: 5
- },
- c: {
- g: {
- d: 7
- }
- }
- };
-
- const source = {
- a: {
- b: 4
- },
- c: {
- g: {
- h: 8
- }
- }
- };
-
- const merged = Hoek.applyToDefaults(defaults, source, { shallow: ['c.g'] });
- expect(merged).to.equal({ a: { b: 4 }, c: { g: { h: 8 } } });
- expect(merged.c.g).to.shallow.equal(source.c.g);
- });
-
- it('shallow copies the nested keys (deeper)', () => {
-
- const defaults = {
- a: {
- b: 5
- }
- };
-
- const source = {
- a: {
- b: 4
- },
- c: {
- g: {
- r: {
- h: 8
- }
- }
- }
- };
-
- const merged = Hoek.applyToDefaults(defaults, source, { shallow: ['c.g.r'] });
- expect(merged).to.equal({ a: { b: 4 }, c: { g: { r: { h: 8 } } } });
- expect(merged.c.g.r).to.shallow.equal(source.c.g.r);
- });
-
- it('shallow copies the nested keys (not present)', () => {
-
- const defaults = {
- a: {
- b: 5
- }
- };
-
- const source = {
- a: {
- b: 4
- },
- c: {
- g: {
- r: {
- h: 8
- }
- }
- }
- };
-
- const merged = Hoek.applyToDefaults(defaults, source, { shallow: ['x.y'] });
- expect(merged).to.equal({ a: { b: 4 }, c: { g: { r: { h: 8 } } } });
- });
-
- it('shallow copies the nested keys (non-object)', () => {
-
- const defaults = {
- // All falsy values:
- _undefined: {
- a: 1
- },
- _null: {
- a: 2
- },
- _false: {
- a: 3
- },
- _emptyString: {
- a: 4
- },
- _zero: {
- a: 5
- },
- _NaN: {
- a: 6
- },
- // Other non-object values:
- _string: {
- a: 7
- },
- _number: {
- a: 8
- },
- _true: {
- a: 9
- },
- _function: {
- a: 10
- }
- };
-
- const source = {
- _undefined: undefined,
- _null: null,
- _false: false,
- _emptyString: '',
- _zero: 0,
- _NaN: NaN,
- _string: 'foo',
- _number: 42,
- _true: true,
- _function: () => {}
- };
-
- const merged = Hoek.applyToDefaults(defaults, source, { shallow: [
- '_undefined.a',
- '_null.a',
- '_false.a',
- '_emptyString.a',
- '_zero.a',
- '_NaN.a',
- '_string.a',
- '_number.a',
- '_true.a',
- '_function.a'
- ] });
- expect(merged).to.equal({
- _undefined: { a: 1 },
- _null: { a: 2 },
- _false: false,
- _emptyString: '',
- _zero: 0,
- _NaN: NaN,
- _string: 'foo',
- _number: 42,
- _true: true,
- _function: source._function
- });
- });
-
- it('shallow copies the listed keys in the defaults', () => {
-
- const defaults = {
- a: {
- b: 1
- }
- };
-
- const merged = Hoek.applyToDefaults(defaults, {}, { shallow: ['a'] });
- expect(merged.a).to.shallow.equal(defaults.a);
- });
-
- it('shallow copies the listed keys in the defaults (true)', () => {
-
- const defaults = {
- a: {
- b: 1
- }
- };
-
- const merged = Hoek.applyToDefaults(defaults, true, { shallow: ['a'] });
- expect(merged.a).to.shallow.equal(defaults.a);
- });
-
- it('returns null on false', () => {
-
- const defaults = {
- a: {
- b: 1
- }
- };
-
- const merged = Hoek.applyToDefaults(defaults, false, { shallow: ['a'] });
- expect(merged).to.equal(null);
- });
-
- it('handles missing shallow key in defaults', () => {
-
- const defaults = {
- a: {
- b: 1
- }
- };
-
- const options = {
- a: {
- b: 4
- },
- c: {
- d: 2
- }
- };
-
- const merged = Hoek.applyToDefaults(defaults, options, { shallow: ['c'] });
- expect(merged).to.equal({ a: { b: 4 }, c: { d: 2 } });
- expect(merged.c).to.shallow.equal(options.c);
-
- expect(Hoek.applyToDefaults(defaults, true, { shallow: ['c'] })).to.equal({ a: { b: 1 } });
- });
-
- it('throws on missing defaults', () => {
-
- expect(() => Hoek.applyToDefaults(null, {}, { shallow: ['a'] })).to.throw('Invalid defaults value: must be an object');
- });
-
- it('throws on invalid defaults', () => {
-
- expect(() => Hoek.applyToDefaults('abc', {}, { shallow: ['a'] })).to.throw('Invalid defaults value: must be an object');
- });
-
- it('throws on invalid source', () => {
-
- expect(() => Hoek.applyToDefaults({}, 'abc', { shallow: ['a'] })).to.throw('Invalid source value: must be true, falsy or an object');
- });
-
- it('throws on missing keys', () => {
-
- expect(() => Hoek.applyToDefaults({}, true, { shallow: 123 })).to.throw('Invalid keys');
- });
-
- it('handles array keys', () => {
-
- const sym = Symbol();
-
- const defaults = {
- a: {
- b: 5,
- e: 3
- },
- c: {
- d: 7,
- [sym]: {
- f: 9
- }
- }
- };
-
- const options = {
- a: {
- b: 4
- },
- c: {
- d: 6,
- [sym]: {
- g: 1
- }
- }
- };
-
- const merged = Hoek.applyToDefaults(defaults, options, { shallow: [['c', sym]] });
- expect(merged).to.equal({ a: { b: 4, e: 3 }, c: { d: 6, [sym]: { g: 1 } } });
- expect(merged.c[sym]).to.shallow.equal(options.c[sym]);
- });
-
- it('does not modify shallow entries in source', () => {
-
- const defaults = {
- a: {
- b: 5
- }
- };
-
- const source = {};
-
- Object.defineProperty(source, 'a', { value: { b: 4 } });
-
- const merged = Hoek.applyToDefaults(defaults, source, { shallow: ['a'] });
- expect(merged).to.equal({ a: { b: 4 } });
- expect(merged.a).to.shallow.equal(source.a);
- expect(merged.a).to.not.equal(defaults.a);
- });
-
- it('should respect nullOverride when shallow is used', () => {
-
- const defaults = { host: 'localhost', port: 8000 };
- const source = { host: null, port: 8080 };
-
- const result = Hoek.applyToDefaults(defaults, source, { nullOverride: true, shallow: [] });
- expect(result.host).to.equal(null);
- expect(result.port).to.equal(8080);
- });
-});
-
-describe('deepEqual()', () => {
-
- it('compares identical references', () => {
-
- const x = {};
- expect(Hoek.deepEqual(x, x)).to.be.true();
- });
-
- it('compares simple values', () => {
-
- expect(Hoek.deepEqual('x', 'x')).to.be.true();
- expect(Hoek.deepEqual('x', 'y')).to.be.false();
- expect(Hoek.deepEqual('x1', 'x')).to.be.false();
- expect(Hoek.deepEqual(-0, +0)).to.be.false();
- expect(Hoek.deepEqual(-0, -0)).to.be.true();
- expect(Hoek.deepEqual(+0, +0)).to.be.true();
- expect(Hoek.deepEqual(+0, -0)).to.be.false();
- expect(Hoek.deepEqual(1, 1)).to.be.true();
- expect(Hoek.deepEqual(0, 0)).to.be.true();
- expect(Hoek.deepEqual(-1, 1)).to.be.false();
- expect(Hoek.deepEqual(NaN, 0)).to.be.false();
- expect(Hoek.deepEqual(NaN, NaN)).to.be.true();
- });
-
- it('compares different types', () => {
-
- expect(Hoek.deepEqual([], 5, { prototype: false })).to.be.false();
- expect(Hoek.deepEqual(5, [], { prototype: false })).to.be.false();
- expect(Hoek.deepEqual({}, null, { prototype: false })).to.be.false();
- expect(Hoek.deepEqual(null, {}, { prototype: false })).to.be.false();
- expect(Hoek.deepEqual('abc', {}, { prototype: false })).to.be.false();
- expect(Hoek.deepEqual({}, 'abc', { prototype: false })).to.be.false();
- });
-
- it('compares empty structures', () => {
-
- expect(Hoek.deepEqual([], [])).to.be.true();
- expect(Hoek.deepEqual({}, {})).to.be.true();
- expect(Hoek.deepEqual([], {})).to.be.false();
- expect(Hoek.deepEqual([], {}, { prototype: false })).to.be.false();
- expect(Hoek.deepEqual({}, [], { prototype: false })).to.be.false();
- });
-
- it('compares empty arguments object', () => {
-
- const compare = function () {
-
- expect(Hoek.deepEqual([], arguments)).to.be.false(); // eslint-disable-line prefer-rest-params
- };
-
- compare();
- });
-
- it('compares empty arguments objects', () => {
-
- const compare = function () {
-
- const arg1 = arguments; // eslint-disable-line prefer-rest-params
-
- const inner = function () {
-
- // callee is not supported in strict mode, was previously false becuse callee was different
- expect(Hoek.deepEqual(arg1, arguments)).to.be.true(); // eslint-disable-line prefer-rest-params
- };
-
- inner();
- };
-
- compare();
- });
-
- it('compares symbol object properties', () => {
-
- const sym = Symbol();
-
- const ne = {};
- Object.defineProperty(ne, sym, { value: true });
-
- expect(Hoek.deepEqual({ [sym]: { c: true } }, { [sym]: { c: true } })).to.be.true();
- expect(Hoek.deepEqual({ [sym]: { c: true } }, { [sym]: { c: false } })).to.be.false();
- expect(Hoek.deepEqual({ [sym]: { c: true } }, { [sym]: true })).to.be.false();
- expect(Hoek.deepEqual({ [sym]: undefined }, { [sym]: undefined })).to.be.true();
- expect(Hoek.deepEqual({ [sym]: undefined }, {})).to.be.false();
- expect(Hoek.deepEqual({}, { [sym]: undefined })).to.be.false();
-
- expect(Hoek.deepEqual({}, ne)).to.be.true();
- expect(Hoek.deepEqual(ne, {})).to.be.true();
- expect(Hoek.deepEqual({ [sym]: true }, ne)).to.be.false();
- expect(Hoek.deepEqual(ne, { [sym]: true })).to.be.false();
- expect(Hoek.deepEqual(ne, { [Symbol()]: undefined })).to.be.false();
-
- expect(Hoek.deepEqual({ [sym]: true }, { [sym]: true })).to.be.true();
- expect(Hoek.deepEqual({ [sym]: true }, {})).to.be.false();
- expect(Hoek.deepEqual({ [sym]: true }, {}, { symbols: false })).to.be.true();
- });
-
- it('compares dates', () => {
-
- expect(Hoek.deepEqual(new Date(2015, 1, 1), new Date('2015/02/01'))).to.be.true();
- expect(Hoek.deepEqual(new Date(100), new Date(101))).to.be.false();
- expect(Hoek.deepEqual(new Date(), {})).to.be.false();
- expect(Hoek.deepEqual(new Date(2015, 1, 1), new Date('2015/02/01'), { prototype: false })).to.be.true();
- expect(Hoek.deepEqual(new Date(), {}, { prototype: false })).to.be.false();
- expect(Hoek.deepEqual({}, new Date(), { prototype: false })).to.be.false();
- });
-
- it('compares regular expressions', () => {
-
- expect(Hoek.deepEqual(/\s/, new RegExp('\\\s'))).to.be.true();
- expect(Hoek.deepEqual(/\s/g, /\s/g)).to.be.true();
- expect(Hoek.deepEqual(/a/, {}, { prototype: false })).to.be.false();
- expect(Hoek.deepEqual(/\s/g, /\s/i)).to.be.false();
- expect(Hoek.deepEqual(/a/g, /b/g)).to.be.false();
- });
-
- it('compares errors', () => {
-
- expect(Hoek.deepEqual(new Error('a'), new Error('a'))).to.be.true();
- expect(Hoek.deepEqual(new Error('a'), new Error('b'))).to.be.false();
-
- expect(Hoek.deepEqual(new Error('a'), new TypeError('a'))).to.be.false();
- expect(Hoek.deepEqual(new Error('a'), new TypeError('a'), { prototype: false })).to.be.false();
-
- expect(Hoek.deepEqual(new Error(), {})).to.be.false();
- expect(Hoek.deepEqual(new Error(), {}, { prototype: false })).to.be.false();
-
- expect(Hoek.deepEqual({}, new Error())).to.be.false();
- expect(Hoek.deepEqual({}, new Error(), { prototype: false })).to.be.false();
-
- const error = new Error('a');
- expect(Hoek.deepEqual(Hoek.clone(error), error)).to.be.true();
- expect(Hoek.deepEqual(Hoek.clone(error), error, { prototype: false })).to.be.true();
- });
-
- it('compares arrays', () => {
-
- expect(Hoek.deepEqual([[1]], [[1]])).to.be.true();
- expect(Hoek.deepEqual([1, 2, 3], [1, 2, 3])).to.be.true();
- expect(Hoek.deepEqual([1, 2, 3], [1, 3, 2])).to.be.false();
- expect(Hoek.deepEqual([1, 2, 3], [1, 2])).to.be.false();
- expect(Hoek.deepEqual([1], [1])).to.be.true();
- const item1 = { key: 'value1' };
- const item2 = { key: 'value2' };
- expect(Hoek.deepEqual([item1, item1], [item1, item2])).to.be.false();
- });
-
- it('compares sets', () => {
-
- expect(Hoek.deepEqual(new Set(), new Set())).to.be.true();
- expect(Hoek.deepEqual(new Set([1]), new Set([1]))).to.be.true();
- expect(Hoek.deepEqual(new Set([]), new Set([]))).to.be.true();
- expect(Hoek.deepEqual(new Set([1, 2, 3]), new Set([1, 2, 3]))).to.be.true();
- expect(Hoek.deepEqual(new Set([1, 2, 3]), new Set([3, 2, 1]))).to.be.true();
- expect(Hoek.deepEqual(new Set([1, 2, 3]), new Set([1, 2, 4]))).to.be.false();
- expect(Hoek.deepEqual(new Set([1, 2, 3]), new Set([1, 2]))).to.be.false();
- expect(Hoek.deepEqual(new Set([1, 2, 1]), new Set([1, 2]))).to.be.true();
- expect(Hoek.deepEqual(new Set([+0]), new Set([-0]))).to.be.true();
- expect(Hoek.deepEqual(new Set([NaN]), new Set([NaN]))).to.be.true();
- expect(Hoek.deepEqual(new Set([1, {}]), new Set([1, {}]))).to.be.true();
- expect(Hoek.deepEqual(new Set([1, {}]), new Set([{}, 1]))).to.be.true();
- expect(Hoek.deepEqual(new Set([1, {}, {}]), new Set([{}, 1, {}]))).to.be.true();
- expect(Hoek.deepEqual(new Set([1, { a: 1 }]), new Set([{ a: 0 }, 1]))).to.be.false();
- expect(Hoek.deepEqual(new WeakSet(), new WeakSet())).to.be.true();
- const obj = {};
- expect(Hoek.deepEqual(new WeakSet([obj]), new WeakSet())).to.be.true();
- expect(Hoek.deepEqual(new WeakSet(), new Set()), { prototype: false }).to.be.false();
-
- const sets = [new Set(), new Set()].map((set) => {
-
- set.modified = true;
- return set;
- });
- expect(Hoek.deepEqual(sets[0], sets[1])).to.be.true();
- expect(Hoek.deepEqual(sets[0], new Set())).to.be.false();
- });
-
- it('compares extended sets', () => {
-
- class PrivateSet extends Set {
-
- has() {
-
- throw new Error('not allowed');
- }
- }
-
- const entries = ['a', undefined];
- expect(Hoek.deepEqual(new PrivateSet(), new PrivateSet())).to.be.true();
- expect(Hoek.deepEqual(new PrivateSet(entries), new PrivateSet(entries))).to.be.true();
- expect(Hoek.deepEqual(new PrivateSet(entries), new Set(entries), { prototype: false })).to.be.true();
- expect(Hoek.deepEqual(new PrivateSet(entries), new Set(entries), { prototype: true })).to.be.false();
- expect(Hoek.deepEqual(new PrivateSet(), new PrivateSet(entries))).to.be.false();
- expect(Hoek.deepEqual(new PrivateSet(entries), new PrivateSet())).to.be.false();
-
- class LockableSet extends Set {
-
- constructor(values, locked = true) {
-
- super(values);
- this.locked = locked;
- }
-
- has() {
-
- if (this.locked) {
- throw new Error('not allowed');
- }
- }
- }
-
- expect(Hoek.deepEqual(new LockableSet(), new LockableSet())).to.be.true();
- expect(Hoek.deepEqual(new LockableSet(entries), new LockableSet(entries))).to.be.true();
- expect(Hoek.deepEqual(new LockableSet(entries, false), new LockableSet(entries, false))).to.be.true();
- expect(Hoek.deepEqual(new LockableSet(entries, true), new LockableSet(entries, false))).to.be.false();
- expect(Hoek.deepEqual(new LockableSet(entries, false), new LockableSet(entries, true))).to.be.false();
- expect(Hoek.deepEqual(new LockableSet(entries), new Set(entries), { prototype: false })).to.be.false();
- expect(Hoek.deepEqual(new LockableSet(entries), new PrivateSet(entries), { prototype: false })).to.be.false();
- });
-
- it('compares maps', () => {
-
- const item1 = { key: 'value1' };
- const item2 = { key: 'value2' };
- expect(Hoek.deepEqual(new Map(), new Map())).to.be.true();
- expect(Hoek.deepEqual(new Map([[1, {}]]), new Map([[1, {}]]))).to.be.true();
- expect(Hoek.deepEqual(new Map([[1, item1]]), new Map([[1, item1]]))).to.be.true();
- expect(Hoek.deepEqual(new Map([[1, item1]]), new Map([[1, item2]]))).to.be.false();
- expect(Hoek.deepEqual(new Map([[1, undefined]]), new Map([[1, undefined]]))).to.be.true();
- expect(Hoek.deepEqual(new Map([[1, undefined]]), new Map([[2, undefined]]))).to.be.false();
- expect(Hoek.deepEqual(new Map([[1, {}]]), new Map([[1, {}], [2, {}]]))).to.be.false();
- expect(Hoek.deepEqual(new Map([[item1, 1]]), new Map([[item1, 1]]))).to.be.true();
- expect(Hoek.deepEqual(new Map([[{}, 1]]), new Map([[{}, 1]]))).to.be.false();
- expect(Hoek.deepEqual(new WeakMap(), new WeakMap())).to.be.true();
- expect(Hoek.deepEqual(new WeakMap([[item1, 1]]), new WeakMap())).to.be.true();
- expect(Hoek.deepEqual(new WeakMap(), new Map()), { prototype: false }).to.be.false();
-
- const maps = [new Map(), new Map()].map((map) => {
-
- map.modified = true;
- return map;
- });
- expect(Hoek.deepEqual(maps[0], maps[1])).to.be.true();
- expect(Hoek.deepEqual(maps[0], new Map())).to.be.false();
- });
-
- it('compares extended maps', () => {
-
- class PrivateMap extends Map {
-
- get() {
-
- throw new Error('not allowed');
- }
- }
-
- const entries = [['a', 1], ['b', undefined]];
- expect(Hoek.deepEqual(new PrivateMap(), new PrivateMap())).to.be.true();
- expect(Hoek.deepEqual(new PrivateMap(entries), new PrivateMap(entries))).to.be.true();
- expect(Hoek.deepEqual(new PrivateMap(entries), new Map(entries), { prototype: false })).to.be.true();
- expect(Hoek.deepEqual(new PrivateMap(entries), new Map(entries), { prototype: true })).to.be.false();
- expect(Hoek.deepEqual(new PrivateMap(), new PrivateMap(entries))).to.be.false();
- expect(Hoek.deepEqual(new PrivateMap(entries), new PrivateMap())).to.be.false();
-
- class LockableMap extends Map {
-
- constructor(kvs, locked = true) {
-
- super(kvs);
- this.locked = locked;
- }
-
- get() {
-
- if (this.locked) {
- throw new Error('not allowed');
- }
- }
- }
-
- expect(Hoek.deepEqual(new LockableMap(), new LockableMap())).to.be.true();
- expect(Hoek.deepEqual(new LockableMap(entries), new LockableMap(entries))).to.be.true();
- expect(Hoek.deepEqual(new LockableMap(entries, false), new LockableMap(entries, false))).to.be.true();
- expect(Hoek.deepEqual(new LockableMap(entries, true), new LockableMap(entries, false))).to.be.false();
- expect(Hoek.deepEqual(new LockableMap(entries, false), new LockableMap(entries, true))).to.be.false();
- expect(Hoek.deepEqual(new LockableMap(entries), new Map(entries), { prototype: false })).to.be.false();
- expect(Hoek.deepEqual(new LockableMap(entries), new PrivateMap(entries), { prototype: false })).to.be.false();
- });
-
- it('compares promises', () => {
-
- const a = new Promise(() => { });
-
- expect(Hoek.deepEqual(a, a)).to.be.true();
- expect(Hoek.deepEqual(a, new Promise(() => { }))).to.be.false();
- });
-
- it('compares urls', () => {
-
- const a = new URL('https://hapi.dev/');
-
- expect(Hoek.deepEqual(a, a)).to.be.true();
- expect(Hoek.deepEqual(a, new URL('https://hapi.dev/?new'))).to.be.false();
- expect(Hoek.deepEqual(a, {}, { prototype: false })).to.be.false();
- });
-
- it('compares buffers', () => {
-
- expect(Hoek.deepEqual(Buffer.from([1, 2, 3]), Buffer.from([1, 2, 3]))).to.be.true();
- expect(Hoek.deepEqual(Buffer.from([1, 2, 3]), Buffer.from([1, 3, 2]))).to.be.false();
- expect(Hoek.deepEqual(Buffer.from([1, 2, 3]), Buffer.from([1, 2]))).to.be.false();
- expect(Hoek.deepEqual(Buffer.from([1, 2, 3]), {})).to.be.false();
- expect(Hoek.deepEqual(Buffer.from([1, 2, 3]), [1, 2, 3])).to.be.false();
- });
-
- it('compares string objects', () => {
-
- /* eslint-disable no-new-wrappers */
- expect(Hoek.deepEqual(new String('a'), new String('a'))).to.be.true();
- expect(Hoek.deepEqual(new String('a'), new String('b'))).to.be.false();
- expect(Hoek.deepEqual(new String(''), {}, { prototype: false })).to.be.false();
- expect(Hoek.deepEqual({}, new String(''), { prototype: false })).to.be.false();
- expect(Hoek.deepEqual(new String('a'), 'a', { prototype: false })).to.be.false();
- expect(Hoek.deepEqual('a', new String('a'), { prototype: false })).to.be.false();
- /* eslint-enable no-new-wrappers */
- });
-
- it('compares number objects', () => {
-
- /* eslint-disable no-new-wrappers */
- expect(Hoek.deepEqual(new Number(1), new Number(1))).to.be.true();
- expect(Hoek.deepEqual(new Number(1), new Number(2))).to.be.false();
- expect(Hoek.deepEqual(new Number(+0), new Number(-0))).to.be.false();
- expect(Hoek.deepEqual(new Number(NaN), new Number(NaN))).to.be.true();
- expect(Hoek.deepEqual(new Number(0), {}, { prototype: false })).to.be.false();
- expect(Hoek.deepEqual({}, new Number(0), { prototype: false })).to.be.false();
- expect(Hoek.deepEqual(new Number(1), 1, { prototype: false })).to.be.false();
- expect(Hoek.deepEqual(1, new Number(1), { prototype: false })).to.be.false();
- /* eslint-enable no-new-wrappers */
- });
-
- it('compares boolean objects', () => {
-
- /* eslint-disable no-new-wrappers */
- expect(Hoek.deepEqual(new Boolean(true), new Boolean(true))).to.be.true();
- expect(Hoek.deepEqual(new Boolean(true), new Boolean(false))).to.be.false();
- expect(Hoek.deepEqual(new Boolean(false), {}, { prototype: false })).to.be.false();
- expect(Hoek.deepEqual({}, new Boolean(false), { prototype: false })).to.be.false();
- expect(Hoek.deepEqual(new Boolean(true), true, { prototype: false })).to.be.false();
- expect(Hoek.deepEqual(true, new Boolean(true), { prototype: false })).to.be.false();
- /* eslint-enable no-new-wrappers */
- });
-
- it('compares objects', () => {
-
- expect(Hoek.deepEqual({ a: 1, b: 2, c: 3 }, { a: 1, b: 2, c: 3 })).to.be.true();
- expect(Hoek.deepEqual({ foo: 'bar' }, { foo: 'baz' })).to.be.false();
- expect(Hoek.deepEqual({ foo: { bar: 'foo' } }, { foo: { bar: 'baz' } })).to.be.false();
- expect(Hoek.deepEqual({ foo: undefined }, {})).to.be.false();
- expect(Hoek.deepEqual({}, { foo: undefined })).to.be.false();
- expect(Hoek.deepEqual({ foo: undefined }, { bar: undefined })).to.be.false();
- });
-
- it('compares functions', () => {
-
- const f1 = () => 1;
- const f2 = () => 2;
- const f2a = () => 2;
-
- expect(Hoek.deepEqual({ f1 }, { f1 })).to.be.true();
- expect(Hoek.deepEqual({ f1 }, { f1: f2 })).to.be.false();
- expect(Hoek.deepEqual({ f2 }, { f2: f2a })).to.be.false();
- expect(Hoek.deepEqual({ f2 }, { f2: f2a }, { deepFunction: true })).to.be.true();
- expect(Hoek.deepEqual({ f2 }, { f2: f1 }, { deepFunction: true })).to.be.false();
-
- const f3 = () => 3;
- f3.x = 1;
-
- const f3a = () => 3;
- f3a.x = 1;
-
- const f3b = () => 3;
- f3b.x = 2;
-
- expect(Hoek.deepEqual({ f3 }, { f3: f3a }, { deepFunction: true })).to.be.true();
- expect(Hoek.deepEqual({ f3 }, { f3: f3b }, { deepFunction: true })).to.be.false();
- });
-
- it('skips keys', () => {
-
- expect(Hoek.deepEqual({ a: 1, b: 2, c: 3 }, { a: 1, b: 2, c: 4 })).to.be.false();
- expect(Hoek.deepEqual({ a: 1, b: 2, c: 3 }, { a: 1, b: 2, c: 4 }, { skip: ['c'] })).to.be.true();
-
- expect(Hoek.deepEqual({ a: 1, b: 2, c: 3 }, { a: 1, b: 2 })).to.be.false();
- expect(Hoek.deepEqual({ a: 1, b: 2, c: 3 }, { a: 1, b: 2 }, { skip: ['c'] })).to.be.true();
-
- const sym = Symbol('test');
- expect(Hoek.deepEqual({ a: 1, b: 2, [sym]: 3 }, { a: 1, b: 2, [sym]: 4 })).to.be.false();
- expect(Hoek.deepEqual({ a: 1, b: 2, [sym]: 3 }, { a: 1, b: 2, [sym]: 4 }, { skip: [sym] })).to.be.true();
-
- expect(Hoek.deepEqual({ a: 1, b: 2, [sym]: 3 }, { a: 1, b: 2 })).to.be.false();
- expect(Hoek.deepEqual({ a: 1, b: 2, [sym]: 3 }, { a: 1, b: 2 }, { skip: [sym] })).to.be.true();
- expect(Hoek.deepEqual({ a: 1, b: 2, [sym]: 3, [Symbol('other')]: true }, { a: 1, b: 2 }, { skip: [sym] })).to.be.false();
-
- expect(Hoek.deepEqual({ a: 1, b: 2 }, { a: 1 }, { skip: ['a'] })).to.be.false();
- expect(Hoek.deepEqual({ a: 1 }, { a: 1, b: 2 }, { skip: ['a'] })).to.be.false();
- });
-
- it('handles circular dependency', () => {
-
- const a = {};
- a.x = a;
-
- const b = Hoek.clone(a);
- expect(Hoek.deepEqual(a, b)).to.be.true();
- });
-
- it('handles obj only circular dependency', () => {
-
- const a = {};
- a.x = a;
-
- const b = { x: {} };
- expect(Hoek.deepEqual(a, b)).to.be.false();
- expect(Hoek.deepEqual(b, a)).to.be.false();
- });
-
- it('handles irregular circular dependency', () => {
-
- const a = {};
- a.x = a;
-
- const b = { x: {} };
- b.x.x = b;
-
- const c = { x: { x: {} } };
- c.x.x.x = c;
- expect(Hoek.deepEqual(a, b)).to.be.true();
- expect(Hoek.deepEqual(b, a)).to.be.true();
- expect(Hoek.deepEqual(a, c)).to.be.true();
- expect(Hoek.deepEqual(b, c)).to.be.true();
- expect(Hoek.deepEqual(c, a)).to.be.true();
- expect(Hoek.deepEqual(c, b)).to.be.true();
- b.x.y = 1;
- expect(Hoek.deepEqual(a, b)).to.be.false();
- expect(Hoek.deepEqual(b, a)).to.be.false();
- });
-
- it('handles cross circular dependency', () => {
-
- const a = {};
- const b = { x: {}, y: a };
- b.x.x = b;
- b.x.y = b.x;
- a.x = b;
- a.y = a;
- expect(Hoek.deepEqual(b, a)).to.be.true();
- expect(Hoek.deepEqual(a, b)).to.be.true();
- b.x.y = 1;
- expect(Hoek.deepEqual(b, a)).to.be.false();
- expect(Hoek.deepEqual(a, b)).to.be.false();
- });
-
- it('handles reuse of objects', () => {
-
- const date1 = { year: 2018, month: 1, day: 1 };
- const date2 = { year: 2000, month: 1, day: 1 };
-
- expect(Hoek.deepEqual({ start: date1, end: date1 }, { start: date1, end: date2 })).to.be.false();
- });
-
- it('handles valueOf() that throws', () => {
-
- const throwing = class {
-
- constructor(value) {
-
- this.value = value;
- }
-
- valueOf() {
-
- throw new Error('failed');
- }
- };
-
- expect(Hoek.deepEqual(new throwing('a'), new throwing('a'))).to.be.true();
- expect(Hoek.deepEqual(new throwing('a'), new throwing('b'))).to.be.false();
- expect(Hoek.deepEqual(new throwing('a'), { value: 'a' }, { prototype: false })).to.be.false();
- expect(Hoek.deepEqual({ value: 'a' }, new throwing('a'), { prototype: false })).to.be.false();
- });
-
- it('handles valueOf() that returns similar value', () => {
-
- const identity = class {
-
- constructor(value) {
-
- this.value = value;
- }
-
- valueOf() {
-
- return { value: this.value };
- }
- };
-
- expect(Hoek.deepEqual(new identity('a'), new identity('a'))).to.be.true();
- expect(Hoek.deepEqual(new identity('a'), new identity('b'))).to.be.false();
- expect(Hoek.deepEqual(new identity('a'), { value: 'a' }, { prototype: true })).to.be.false();
- expect(Hoek.deepEqual(new identity('a'), { value: 'a' }, { prototype: false })).to.be.true();
- expect(Hoek.deepEqual({ value: 'a' }, new identity('a'), { prototype: true })).to.be.false();
- expect(Hoek.deepEqual({ value: 'a' }, new identity('a'), { prototype: false })).to.be.true();
- });
-
- it('skips enumerable properties on prototype chain', () => {
-
- const base = function (value, surprice) {
-
- this.value = value;
- if (surprice) {
- this.surprice = surprice;
- }
- };
-
- Object.defineProperty(base.prototype, 'enum', {
- enumerable: true,
- configurable: true,
- value: true
- });
-
- expect('enum' in new base('a')).to.be.true();
- expect(Hoek.deepEqual(new base('a'), new base('a'))).to.be.true();
- expect(Hoek.deepEqual(new base('a'), new base('b'))).to.be.false();
- expect(Hoek.deepEqual(new base('a'), { value: 'a' }, { prototype: false })).to.be.true();
- expect(Hoek.deepEqual({ value: 'a' }, new base('a'), { prototype: false })).to.be.true();
- expect(Hoek.deepEqual(new base('a', 1), { value: 'a', enum: true }, { prototype: false })).to.be.false();
- expect(Hoek.deepEqual({ value: 'a', enum: true }, new base('a', 1), { prototype: false })).to.be.false();
- });
-
- it('skips non-enumerable properties', () => {
-
- const base = function Base(value, surprice) {
-
- this.value = value;
- if (surprice) {
- this.surprice = surprice;
- }
- };
-
- const createObj = (...args) => {
-
- const obj = new base(...args);
-
- Object.defineProperty(obj, 'hidden', {
- enumerable: false,
- configurable: true,
- value: true
- });
-
- return obj;
- };
-
- expect(Hoek.deepEqual(createObj('a'), createObj('a'))).to.be.true();
- expect(Hoek.deepEqual(createObj('a'), createObj('b'))).to.be.false();
- expect(Hoek.deepEqual(createObj('a'), { value: 'a' }, { prototype: false })).to.be.true();
- expect(Hoek.deepEqual({ value: 'a' }, createObj('a'), { prototype: false })).to.be.true();
- expect(Hoek.deepEqual(createObj('a', 1), { value: 'a', hidden: true }, { prototype: false })).to.be.false();
- expect(Hoek.deepEqual({ value: 'a', hidden: true }, createObj('a', 1), { prototype: false })).to.be.false();
- });
-
- it('compares an object with property getter while executing it', () => {
-
- const obj = {};
- const value = 1;
- let execCount = 0;
-
- Object.defineProperty(obj, 'test', {
- enumerable: true,
- configurable: true,
- get: function () {
-
- ++execCount;
- return value;
- }
- });
-
- const copy = Hoek.clone(obj);
- expect(Hoek.deepEqual(obj, copy)).to.be.true();
- expect(execCount).to.equal(2);
- expect(copy.test).to.equal(1);
- expect(execCount).to.equal(3);
- });
-
- it('compares objects with property getters', () => {
-
- const obj = {};
- Object.defineProperty(obj, 'test', {
- enumerable: true,
- configurable: true,
- get: function () {
-
- return 1;
- }
- });
-
- const ref = {};
- Object.defineProperty(ref, 'test', {
- enumerable: true,
- configurable: true,
- get: function () {
-
- return 2;
- }
- });
-
- expect(Hoek.deepEqual(obj, ref)).to.be.false();
- });
-
- it('compares object prototypes', () => {
-
- const Obj = function () {
-
- this.a = 5;
- };
-
- Obj.prototype.b = function () {
-
- return this.a;
- };
-
- const Ref = function () {
-
- this.a = 5;
- };
-
- Ref.prototype.b = function () {
-
- return this.a;
- };
-
- expect(Hoek.deepEqual(new Obj(), new Ref())).to.be.false();
- expect(Hoek.deepEqual(new Obj(), new Obj())).to.be.true();
- expect(Hoek.deepEqual(new Ref(), new Ref())).to.be.true();
- });
-
- it('compares plain objects', () => {
-
- const a = Object.create(null);
- const b = Object.create(null);
-
- a.b = 'c';
- b.b = 'c';
-
- expect(Hoek.deepEqual(a, b)).to.be.true();
- expect(Hoek.deepEqual(a, { b: 'c' })).to.be.false();
- });
-
- it('compares an object with an empty object', () => {
-
- const a = { a: 1, b: 2 };
-
- expect(Hoek.deepEqual({}, a)).to.be.false();
- expect(Hoek.deepEqual(a, {})).to.be.false();
- });
-
- it('compares an object ignoring the prototype', () => {
-
- const a = Object.create(null);
- const b = {};
-
- expect(Hoek.deepEqual(a, b, { prototype: false })).to.be.true();
- });
-
- it('compares an object ignoring the prototype recursively', () => {
-
- const a = [Object.create(null)];
- const b = [{}];
-
- expect(Hoek.deepEqual(a, b, { prototype: false })).to.be.true();
- });
-});
-
-describe('intersect()', () => {
-
- it('returns the common objects of two arrays', () => {
-
- const array1 = [1, 2, 3, 4, 4, 5, 5];
- const array2 = [5, 4, 5, 6, 7];
- const common = Hoek.intersect(array1, array2);
- expect(common).to.equal([5, 4]);
- });
-
- it('returns the common objects of array and set', () => {
-
- const array1 = new Set([1, 2, 3, 4, 4, 5, 5]);
- const array2 = [5, 4, 5, 6, 7];
- const common = Hoek.intersect(array1, array2);
- expect(common).to.equal([5, 4]);
- });
-
- it('returns the common objects of set and array', () => {
-
- const array1 = [1, 2, 3, 4, 4, 5, 5];
- const array2 = new Set([5, 4, 5, 6, 7]);
- const common = Hoek.intersect(array1, array2);
- expect(common).to.equal([5, 4]);
- });
-
- it('returns the common objects of two sets', () => {
-
- const array1 = new Set([1, 2, 3, 4, 4, 5, 5]);
- const array2 = new Set([5, 4, 5, 6, 7]);
- const common = Hoek.intersect(array1, array2);
- expect(common).to.equal([5, 4]);
- });
-
- it('returns just the first common object of two arrays', () => {
-
- const array1 = [1, 2, 3, 4, 4, 5, 5];
- const array2 = [5, 4, 5, 6, 7];
- const common = Hoek.intersect(array1, array2, { first: true });
- expect(common).to.equal(5);
- });
-
- it('returns null when no common and returning just the first common object of two arrays', () => {
-
- const array1 = [1, 2, 3, 4, 4, 5, 5];
- const array2 = [6, 7];
- const common = Hoek.intersect(array1, array2, { first: true });
- expect(common).to.equal(null);
- });
-
- it('returns an empty array if either input is null', () => {
-
- expect(Hoek.intersect([1], null).length).to.equal(0);
- expect(Hoek.intersect(null, [1]).length).to.equal(0);
- expect(Hoek.intersect(null, [1], { first: true })).to.be.null();
- });
-
- it('returns the common objects of object and array', () => {
-
- const array1 = { 1: true, 2: true, 3: true, 4: true, 5: true };
- const array2 = [5, 4, 5, 6, 7];
- const common = Hoek.intersect(array1, array2);
- expect(common.length).to.equal(2);
- });
-});
-
-describe('contain()', () => {
-
- it('tests strings', () => {
-
- expect(Hoek.contain('abc', 'ab')).to.be.true();
- expect(Hoek.contain('abc', 'abc', { only: true })).to.be.true();
- expect(Hoek.contain('aaa', 'a', { only: true })).to.be.true();
- expect(Hoek.contain('aaa', 'a', { only: true, once: true })).to.be.false();
- expect(Hoek.contain('abc', 'b', { once: true })).to.be.true();
- expect(Hoek.contain('abc', ['a', 'c'])).to.be.true();
- expect(Hoek.contain('abc', ['a', 'd'], { part: true })).to.be.true();
- expect(Hoek.contain('aaa', ['a', 'a'], { only: true, once: true })).to.be.false();
- expect(Hoek.contain('aaa', ['a', 'a'], { only: true })).to.be.true();
- expect(Hoek.contain('aaa', ['a', 'a', 'a'], { only: true, once: true })).to.be.true();
-
- expect(Hoek.contain('abc', 'ac')).to.be.false();
- expect(Hoek.contain('abcd', 'abc', { only: true })).to.be.false();
- expect(Hoek.contain('aab', 'a', { only: true })).to.be.false();
- expect(Hoek.contain('abb', 'b', { once: true })).to.be.false();
- expect(Hoek.contain('abc', ['a', 'd'])).to.be.false();
- expect(Hoek.contain('abc', ['ab', 'bc'])).to.be.false(); // Overlapping values not supported
-
- expect(Hoek.contain('', 'a')).to.be.false();
- expect(Hoek.contain('', 'a', { only: true })).to.be.false();
-
- expect(Hoek.contain('', '')).to.be.true();
- expect(Hoek.contain('', ''), { only: true }).to.be.true();
- expect(Hoek.contain('', ''), { once: true }).to.be.true();
- expect(Hoek.contain('', ['', ''])).to.be.true();
- expect(Hoek.contain('', ['', ''], { only: true })).to.be.true();
- expect(Hoek.contain('', ['', ''], { once: true })).to.be.false();
-
- expect(Hoek.contain('a', '')).to.be.true();
- expect(Hoek.contain('a', '', { only: true })).to.be.false();
- expect(Hoek.contain('a', '', { once: true })).to.be.false();
- expect(Hoek.contain('a', ['', ''])).to.be.true();
- expect(Hoek.contain('a', ['', ''], { only: true })).to.be.false();
- expect(Hoek.contain('a', ['', ''], { once: true })).to.be.false();
-
- expect(Hoek.contain('ab', ['a', 'b', 'c'])).to.be.false();
- expect(Hoek.contain('ab', ['a', 'b', 'c'], { only: true })).to.be.false();
- expect(Hoek.contain('ab', ['a', 'b', 'c'], { only: true, once: true })).to.be.false();
-
- expect(Hoek.contain('ab', ['c'], { part: true })).to.be.false();
- expect(Hoek.contain('ab', ['b'], { part: true })).to.be.true();
- });
-
- it('tests arrays', () => {
-
- expect(Hoek.contain([1, 2, 3], 1)).to.be.true();
- expect(Hoek.contain([{ a: 1 }], { a: 1 }, { deep: true })).to.be.true();
- expect(Hoek.contain([1, 2, 3], [1, 2])).to.be.true();
- expect(Hoek.contain([{ a: 1 }], [{ a: 1 }], { deep: true })).to.be.true();
- expect(Hoek.contain([1, 1, 2], [1, 2], { only: true })).to.be.true();
- expect(Hoek.contain([1, 2], [1, 2], { once: true })).to.be.true();
- expect(Hoek.contain([1, 2, 3], [1, 4], { part: true })).to.be.true();
- expect(Hoek.contain([null, 2, 3], [null, 4], { part: true })).to.be.true();
- expect(Hoek.contain([null], null, { deep: true })).to.be.true();
- expect(Hoek.contain([[1], [2]], [[1]], { deep: true })).to.be.true();
- expect(Hoek.contain([[1], [2], 3], [[1]], { deep: true })).to.be.true();
- expect(Hoek.contain([[1, 2]], [[1]], { deep: true, part: true })).to.be.true();
- expect(Hoek.contain([[1, 2]], [[1], 2], { deep: true, part: true })).to.be.true();
- expect(Hoek.contain([1, 2, 1], [1, 1, 2], { only: true })).to.be.true();
- expect(Hoek.contain([1, 2, 1], [1, 1, 2], { only: true, once: true })).to.be.true();
- expect(Hoek.contain([1, 2, 1], [1, 2, 2], { only: true })).to.be.false();
- expect(Hoek.contain([1, 2, 1], [1, 2, 2], { only: true, part: true })).to.be.true();
- expect(Hoek.contain([1, 1, 1], [1, 1, 1, 1])).to.be.false();
- expect(Hoek.contain([1, 1, 1], [1, 1, 1, 1], { part: true })).to.be.true();
-
- expect(Hoek.contain([1, 2, 3], 4)).to.be.false();
- expect(Hoek.contain([{ a: 1 }], { a: 2 }, { deep: true })).to.be.false();
- expect(Hoek.contain([{ a: 1 }, { a: 1 }], [{ a: 1 }, { a: 1 }], { deep: true, once: true, only: true })).to.be.true();
- expect(Hoek.contain([{ a: 1 }, { a: 1 }], [{ a: 1 }, { a: 2 }], { deep: true, once: true, only: true })).to.be.false();
- expect(Hoek.contain([{ a: 1 }], { a: 1 })).to.be.false();
- expect(Hoek.contain([1, 2, 3], [4, 5])).to.be.false();
- expect(Hoek.contain([[3], [2]], [[1]])).to.be.false();
- expect(Hoek.contain([[1], [2]], [[1]])).to.be.false();
- expect(Hoek.contain([[1, 2]], [[1]], { deep: true })).to.be.false();
- expect(Hoek.contain([{ a: 1 }], [{ a: 2 }], { deep: true })).to.be.false();
- expect(Hoek.contain([1, 3, 2], [1, 2], { only: true })).to.be.false();
- expect(Hoek.contain([1, 2, 2], [1, 2], { once: true })).to.be.false();
- expect(Hoek.contain([0, 2, 3], [1, 4], { part: true })).to.be.false();
- expect(Hoek.contain([1, 2, 1], [1, 2, 2], { only: true, once: true })).to.be.false();
- expect(Hoek.contain([1, 2, 1], [1, 2], { only: true, once: true })).to.be.false();
-
- expect(Hoek.contain([], 1)).to.be.false();
- expect(Hoek.contain([], 1, { only: true })).to.be.false();
-
- expect(Hoek.contain(['a', 'b'], ['a', 'b', 'c'])).to.be.false();
- expect(Hoek.contain(['a', 'b'], ['a', 'b', 'c'], { only: true })).to.be.false();
- expect(Hoek.contain(['a', 'b'], ['a', 'b', 'c'], { only: true, once: true })).to.be.false();
-
- expect(Hoek.contain(['a', 'b'], ['c'], { part: true })).to.be.false();
- expect(Hoek.contain(['a', 'b'], ['b'], { part: true })).to.be.true();
-
- expect(Hoek.contain([{ a: 1 }], [1], { deep: true })).to.be.false();
- });
-
- it('tests objects', () => {
-
- expect(Hoek.contain({ a: 1, b: 2, c: 3 }, 'a')).to.be.true();
- expect(Hoek.contain({ a: 1, b: 2, c: 3 }, ['a', 'c'])).to.be.true();
- expect(Hoek.contain({ a: 1, b: 2, c: 3 }, ['a', 'b', 'c'], { only: true })).to.be.true();
- expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 1 })).to.be.true();
- expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 1, c: 3 })).to.be.true();
- expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 1, d: 4 }, { part: true })).to.be.true();
- expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 1, b: 2, c: 3 }, { only: true })).to.be.true();
- expect(Hoek.contain({ a: [1], b: [2], c: [3] }, { a: [1], c: [3] }, { deep: true })).to.be.true();
- expect(Hoek.contain({ a: [{ b: 1 }, { c: 2 }, { d: 3, e: 4 }] }, { a: [{ b: 1 }, { d: 3 }] }, { deep: true })).to.be.false();
- expect(Hoek.contain({ a: [{ b: 1 }, { c: 2 }, { d: 3, e: 4 }] }, { a: [{ b: 1 }, { d: 3 }] }, { deep: true, part: true })).to.be.true();
- expect(Hoek.contain({ a: [{ b: 1 }, { c: 2 }, { d: 3, e: 4 }] }, { a: [{ b: 1 }, { d: 3 }] }, { deep: true, part: false })).to.be.false();
- expect(Hoek.contain({ a: [{ b: 1 }, { c: 2 }, { d: 3, e: 4 }] }, { a: [{ b: 1 }, { d: 3 }] }, { deep: true, only: true })).to.be.false();
- expect(Hoek.contain({ a: [{ b: 1 }, { c: 2 }, { d: 3, e: 4 }] }, { a: [{ b: 1 }, { d: 3 }] }, { deep: true, only: false })).to.be.true();
- expect(Hoek.contain({ a: [1, 2, 3] }, { a: [2, 4, 6] }, { deep: true, part: true })).to.be.true();
-
- expect(Hoek.contain({ a: 1, b: 2, c: 3 }, 'd')).to.be.false();
- expect(Hoek.contain({ a: 1, b: 2, c: 3 }, ['a', 'd'])).to.be.false();
- expect(Hoek.contain({ a: 1, b: 2, c: 3, d: 4 }, ['a', 'b', 'c'], { only: true })).to.be.false();
- expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 2 })).to.be.false();
- expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 2, b: 2 }, { part: true })).to.be.false(); // part does not ignore bad value
- expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 1, d: 3 })).to.be.false();
- expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 1, d: 4 })).to.be.false();
- expect(Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 1, b: 2 }, { only: true })).to.be.false();
- expect(Hoek.contain({ a: [1], b: [2], c: [3] }, { a: [1], c: [3] })).to.be.false();
- expect(Hoek.contain({ a: { b: { c: 1, d: 2 } } }, { a: { b: { c: 1 } } })).to.be.false();
- expect(Hoek.contain({ a: { b: { c: 1, d: 2 } } }, { a: { b: { c: 1 } } }, { deep: true })).to.be.false();
- expect(Hoek.contain({ a: { b: { c: 1, d: 2 } } }, { a: { b: { c: 1 } } }, { deep: true, only: true })).to.be.false();
- expect(Hoek.contain({ a: { b: { c: 1, d: 2 } } }, { a: { b: { c: 1 } } }, { deep: true, only: false })).to.be.true();
- expect(Hoek.contain({ a: { b: { c: 1, d: 2 } } }, { a: { b: { c: 1 } } }, { deep: true, part: true })).to.be.true();
- expect(Hoek.contain({ a: { b: { c: 1, d: 2 } } }, { a: { b: { c: 1 } } }, { deep: true, part: false })).to.be.false();
- expect(Hoek.contain({ a: [1, 2, 3] }, { a: [4, 5, 6] }, { deep: true, part: true })).to.be.false();
-
- expect(Hoek.contain({}, 'a')).to.be.false();
- expect(Hoek.contain({}, 'a', { only: true })).to.be.false();
-
- expect(Hoek.contain({ a: 'foo', b: 'bar' }, ['a', 'b', 'c'])).to.be.false();
- expect(Hoek.contain({ a: 'foo', b: 'bar' }, ['a', 'b', 'c'], { only: true })).to.be.false();
- expect(Hoek.contain({ a: 'foo', b: 'bar' }, { a: 'foo', b: 'bar', c: 'x' })).to.be.false();
- expect(Hoek.contain({ a: 'foo', b: 'bar' }, { a: 'foo', b: 'bar', c: 'x' }, { only: true })).to.be.false();
-
- expect(Hoek.contain({ a: 1, b: 2 }, ['c'], { part: true })).to.be.false();
- expect(Hoek.contain({ a: 1, b: 2 }, ['b'], { part: true })).to.be.true();
-
- // Getter check
-
- {
- const Foo = function (bar) {
-
- this.bar = bar;
- };
-
- const getBar = function () {
-
- return this.bar;
- };
-
- const createFoo = (value) => {
-
- const foo = new Foo(value);
- Object.defineProperty(foo, 'baz', {
- enumerable: true,
- get: getBar
- });
-
- return foo;
- };
-
- expect(Hoek.contain({ a: createFoo('b') }, { a: createFoo('b') }, { deep: true })).to.be.true();
- expect(Hoek.contain({ a: createFoo('b') }, { a: createFoo('b') }, { deep: true, part: true })).to.be.true();
- expect(Hoek.contain({ a: createFoo('b') }, { a: { bar: 'b', baz: 'b' } }, { deep: true })).to.be.true();
- expect(Hoek.contain({ a: createFoo('b') }, { a: { bar: 'b', baz: 'b' } }, { deep: true, only: true })).to.be.false();
- expect(Hoek.contain({ a: createFoo('b') }, { a: { baz: 'b' } }, { deep: true, part: false })).to.be.false();
- expect(Hoek.contain({ a: createFoo('b') }, { a: { baz: 'b' } }, { deep: true, part: true })).to.be.true();
- expect(Hoek.contain({ a: createFoo('b') }, { a: createFoo('b') }, { deep: true })).to.be.true();
- }
-
- // Properties on prototype not visible
-
- {
- const Foo = function () {
-
- this.a = 1;
- };
-
- Object.defineProperty(Foo.prototype, 'b', {
- enumerable: true,
- value: 2
- });
-
- const Bar = function () {
-
- Foo.call(this);
- this.c = 3;
- };
-
- Util.inherits(Bar, Foo);
-
- expect((new Bar()).a).to.equal(1);
- expect((new Bar()).b).to.equal(2);
- expect((new Bar()).c).to.equal(3);
- expect(Hoek.contain(new Bar(), { 'a': 1, 'c': 3 }, { only: true })).to.be.true();
- expect(Hoek.contain(new Bar(), 'b')).to.be.false();
- }
-
- // Non-Enumerable properties
-
- {
- const foo = { a: 1, b: 2 };
-
- Object.defineProperty(foo, 'c', {
- enumerable: false,
- value: 3
- });
-
- expect(Hoek.contain(foo, 'c')).to.be.true();
- expect(Hoek.contain(foo, { 'c': 3 })).to.be.true();
- expect(Hoek.contain(foo, { 'a': 1, 'b': 2, 'c': 3 }, { only: true })).to.be.true();
- }
- });
-
- it('supports symbols', () => {
-
- const sym = Symbol();
-
- expect(Hoek.contain([sym], sym)).to.be.true();
- expect(Hoek.contain({ [sym]: 1 }, sym)).to.be.true();
- expect(Hoek.contain({ [sym]: 1, a: 2 }, { [sym]: 1 })).to.be.true();
-
- expect(Hoek.contain([sym], Symbol())).to.be.false();
- expect(Hoek.contain({ [sym]: 1 }, Symbol())).to.be.false();
- });
-
- it('compares error keys', () => {
-
- const error = new Error('test');
- expect(Hoek.contain(error, { x: 1 })).to.be.false();
- expect(Hoek.contain(error, { x: 1 }, { part: true })).to.be.false();
-
- error.x = 1;
-
- expect(Hoek.contain(error, { x: 1 })).to.be.true();
- expect(Hoek.contain(error, { x: 1 }, { part: true })).to.be.true();
-
- expect(Hoek.contain(error, { x: 1, y: 2 })).to.be.false();
- expect(Hoek.contain(error, { x: 1, y: 2 }, { part: true })).to.be.true();
- });
-});
-
-describe('flatten()', () => {
-
- it('returns a flat array', () => {
-
- const result = Hoek.flatten([1, 2, [3, 4, [5, 6], [7], 8], [9], [10, [11, 12]], 13]);
- expect(result.length).to.equal(13);
- expect(result).to.equal([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]);
- });
-});
-
-describe('reach()', () => {
-
- const sym = Symbol();
- const obj = {
- a: {
- b: {
- c: {
- d: 1,
- e: 2
- },
- f: 'hello'
- },
- g: {
- h: 3
- },
- '-2': true,
- [sym]: {
- v: true
- }
- },
- i: function () { },
- j: null,
- k: [4, 8, 9, 1]
- };
-
- obj.i.x = 5;
-
- it('returns object itself', () => {
-
- expect(Hoek.reach(obj, null)).to.equal(obj);
- expect(Hoek.reach(obj, false)).to.equal(obj);
- expect(Hoek.reach(obj)).to.equal(obj);
- expect(Hoek.reach(obj, [])).to.equal(obj);
- });
-
- it('returns values of array', () => {
-
- expect(Hoek.reach(obj, 'k.0')).to.equal(4);
- expect(Hoek.reach(obj, 'k.1')).to.equal(8);
- });
-
- it('returns last value of array using negative index', () => {
-
- expect(Hoek.reach(obj, 'k.-1')).to.equal(1);
- expect(Hoek.reach(obj, 'k.-2')).to.equal(9);
- });
-
- it('returns object property with negative index for non-array', () => {
-
- expect(Hoek.reach(obj, 'a.-2')).to.be.equal(true);
- });
-
- it('returns a valid member', () => {
-
- expect(Hoek.reach(obj, 'a.b.c.d')).to.equal(1);
- });
-
- it('returns a valid member with separator override', () => {
-
- expect(Hoek.reach(obj, 'a/b/c/d', '/')).to.equal(1);
- });
-
- it('returns undefined on null object', () => {
-
- expect(Hoek.reach(null, 'a.b.c.d')).to.equal(undefined);
- });
-
- it('returns undefined on missing object member', () => {
-
- expect(Hoek.reach(obj, 'a.b.c.d.x')).to.equal(undefined);
- });
-
- it('returns undefined on missing function member', () => {
-
- expect(Hoek.reach(obj, 'i.y', { functions: true })).to.equal(undefined);
- });
-
- it('throws on missing member in strict mode', () => {
-
- expect(() => {
-
- Hoek.reach(obj, 'a.b.c.o.x', { strict: true });
- }).to.throw('Missing segment o in reach path a.b.c.o.x');
-
- });
-
- it('returns undefined on invalid member', () => {
-
- expect(Hoek.reach(obj, 'a.b.c.d-.x')).to.equal(undefined);
- expect(Hoek.reach(obj, 'k.x')).to.equal(undefined);
- expect(Hoek.reach(obj, 'k.1000')).to.equal(undefined);
- expect(Hoek.reach(obj, 'k/0.5', '/')).to.equal(undefined);
- });
-
- it('returns function member', () => {
-
- expect(typeof Hoek.reach(obj, 'i')).to.equal('function');
- });
-
- it('returns function property', () => {
-
- expect(Hoek.reach(obj, 'i.x')).to.equal(5);
- });
-
- it('returns null', () => {
-
- expect(Hoek.reach(obj, 'j')).to.equal(null);
- });
-
- it('throws on function property when functions not allowed', () => {
-
- expect(() => {
-
- Hoek.reach(obj, 'i.x', { functions: false });
- }).to.throw('Invalid segment x in reach path i.x');
- });
-
- it('will return a default value if property is not found', () => {
-
- expect(Hoek.reach(obj, 'a.b.q', { default: 'defaultValue' })).to.equal('defaultValue');
- });
-
- it('will return a default value if path is not found', () => {
-
- expect(Hoek.reach(obj, 'q', { default: 'defaultValue' })).to.equal('defaultValue');
- });
-
- it('allows a falsey value to be used as the default value', () => {
-
- expect(Hoek.reach(obj, 'q', { default: '' })).to.equal('');
- });
-
- it('allows array-based lookup', () => {
-
- expect(Hoek.reach(obj, ['a', 'b', 'c', 'd'])).to.equal(1);
- expect(Hoek.reach(obj, ['k', '1'])).to.equal(8);
- expect(Hoek.reach(obj, ['k', 1])).to.equal(8);
- expect(Hoek.reach(obj, ['k', '-2'])).to.equal(9);
- expect(Hoek.reach(obj, ['k', -2])).to.equal(9);
- });
-
- it('allows array-based lookup with symbols', () => {
-
- expect(Hoek.reach(obj, ['a', sym, 'v'])).to.equal(true);
- expect(Hoek.reach(obj, ['a', Symbol(), 'v'])).to.equal(undefined);
- });
-
- it('returns character in string', () => {
-
- expect(Hoek.reach(['abc'], [0])).to.equal('abc');
- expect(Hoek.reach(['abc'], ['0'])).to.equal('abc');
- });
-
- it('reaches sets and maps', () => {
-
- const value = {
- a: {
- b: new Set([
- { x: 1 },
- { x: 2 },
- {
- y: new Map([
- ['v', 4],
- ['w', 5]
- ])
- }
- ])
- }
- };
-
- expect(Hoek.reach(value, 'a.b.2.y.w')).to.not.exist();
- expect(Hoek.reach(value, 'a.b.2.y.w', { iterables: true })).to.equal(5);
- });
-});
-
-describe('reachTemplate()', () => {
-
- it('applies object to template', () => {
-
- const obj = {
- a: {
- b: {
- c: {
- d: 1
- }
- }
- },
- j: null,
- k: [4, 8, 9, 1]
- };
-
- const template = '{k.0}:{k.-2}:{a.b.c.d}:{x.y}:{j}';
-
- expect(Hoek.reachTemplate(obj, template)).to.equal('4:9:1::');
- });
-
- it('applies object to template (options)', () => {
-
- const obj = {
- a: {
- b: {
- c: {
- d: 1
- }
- }
- },
- j: null,
- k: [4, 8, 9, 1]
- };
-
- const template = '{k/0}:{k/-2}:{a/b/c/d}:{x/y}:{j}';
-
- expect(Hoek.reachTemplate(obj, template, '/')).to.equal('4:9:1::');
- });
-
- it('isn\'t prone to ReDoS given an adversarial template', () => {
-
- const sizes = [0, 1, 2, 3, 4]; // Should be evenly-spaced
- const times = [];
- const diffs = [];
-
- for (const size of sizes) {
- const start = Date.now();
- Hoek.reachTemplate({}, '{'.repeat(size * 10000));
- times.push(Date.now() - start);
- }
-
- for (let i = 1; i < times.length; ++i) {
- diffs.push(times[i] - times[i - 1]);
- }
-
- // Under ReDoS, as the size of the input increases the timing accelerates upwards,
- // i.e. each timing diff would be greater than the last.
-
- const diffsMonotonic = diffs[0] < diffs[1] && diffs[1] < diffs[2] && diffs[2] < diffs[3];
-
- expect(diffsMonotonic, 'Timing diffs monotonic').to.be.false();
- });
-});
-
-describe('assert()', () => {
-
- it('throws an Error when using assert in a test', () => {
-
- expect(() => {
-
- Hoek.assert(false, 'my error message');
- }).to.throw(Hoek.AssertError, 'my error message');
- });
-
- it('throws an Error when using assert in a test with no message', () => {
-
- expect(() => {
-
- Hoek.assert(false);
- }).to.throw(Hoek.AssertError, 'Unknown error');
- });
-
- it('throws an Error when using assert in a test with multipart message', () => {
-
- expect(() => {
-
- Hoek.assert(false, 'This', 'is', 'my message');
- }).to.throw(Hoek.AssertError, 'This is my message');
- });
-
- it('throws an Error when using assert in a test with multipart message (empty)', () => {
-
- expect(() => {
-
- Hoek.assert(false, 'This', 'is', '', 'my message');
- }).to.throw(Hoek.AssertError, 'This is my message');
- });
-
- it('throws an Error when using assert in a test with object message', () => {
-
- expect(() => {
-
- Hoek.assert(false, 'This', 'is', { spinal: 'tap' });
- }).to.throw(Hoek.AssertError, 'This is {"spinal":"tap"}');
- });
-
- it('throws an Error when using assert in a test with multipart string and error messages', () => {
-
- expect(() => {
-
- Hoek.assert(false, new Error('This'), 'is', 'spinal', new Error('tap'));
- }).to.throw(Hoek.AssertError, 'This is spinal tap');
- });
-
- it('throws an Error when using assert in a test with error object message', () => {
-
- const err = new TypeError('This is spinal tap');
- const got = expect(() => Hoek.assert(false, err)).to.throw(TypeError, 'This is spinal tap');
- expect(got).to.shallow.equal(err);
- });
-
- it('throws the same Error that is passed to it if there is only one error passed', () => {
-
- const error = new Error('ruh roh');
- const error2 = new Error('ruh roh');
-
- const fn = function () {
-
- Hoek.assert(false, error);
- };
-
- try {
- fn();
- }
- catch (err) {
- expect(err).to.equal(error); // should be the same reference
- expect(err).to.not.shallow.equal(error2); // error with the same message should not match
- }
- });
-});
-
-describe('AssertError', () => {
-
- it('takes an optional message', () => {
-
- expect(new Hoek.AssertError().message).to.equal('Unknown error');
- expect(new Hoek.AssertError(null).message).to.equal('Unknown error');
- expect(new Hoek.AssertError('msg').message).to.equal('msg');
- });
-
- it('has AssertError name property', () => {
-
- expect(new Hoek.AssertError().name).to.equal('AssertError');
- expect(new Hoek.AssertError('msg').name).to.equal('AssertError');
- });
-
- it('uses ctor argument to hide stack', { skip: typeof Error.captureStackTrace !== 'function' }, () => {
-
- const parentFn = () => {
-
- throw new Hoek.AssertError('msg', parentFn);
- };
-
- const err = expect(parentFn).to.throw(Hoek.AssertError);
-
- expect(err.stack).to.not.contain('parentFn');
- });
-});
-
-describe('Bench', () => {
-
- it('returns time elapsed', async () => {
-
- const timer = new Hoek.Bench();
- await Hoek.wait(12);
- expect(timer.elapsed()).to.be.above(9);
- });
-});
-
-describe('escapeRegex()', () => {
-
- it('escapes all special regular expression characters', () => {
-
- const a = Hoek.escapeRegex('4^f$s.4*5+-_?%=#!:@|~\\/`"(>)[<]d{}s,');
- expect(a).to.equal('4\\^f\\$s\\.4\\*5\\+\\-_\\?%\\=#\\!\\:@\\|~\\\\\\/`"\\(>\\)\\[<\\]d\\{\\}s\\,');
- });
-});
-
-describe('escapeHeaderAttribute()', () => {
-
- it('should not alter ascii values', () => {
-
- const a = Hoek.escapeHeaderAttribute('My Value');
- expect(a).to.equal('My Value');
- });
-
- it('escapes all special HTTP header attribute characters', () => {
-
- const a = Hoek.escapeHeaderAttribute('I said go!!!#"' + String.fromCharCode(92));
- expect(a).to.equal('I said go!!!#\\"\\\\');
- });
-
- it('throws on large unicode characters', () => {
-
- expect(() => {
-
- Hoek.escapeHeaderAttribute('this is a test' + String.fromCharCode(500) + String.fromCharCode(300));
- }).to.throw(Error);
- });
-
- it('throws on CRLF to prevent response splitting', () => {
-
- expect(() => {
-
- Hoek.escapeHeaderAttribute('this is a test\r\n');
- }).to.throw(Error);
- });
-});
-
-describe('escapeHtml()', () => {
-
- it('escapes all special HTML characters', () => {
-
- const a = Hoek.escapeHtml('&<>"\'`');
- expect(a).to.equal('&<>"'`');
- });
-
- it('returns empty string on falsy input', () => {
-
- const a = Hoek.escapeHtml('');
- expect(a).to.equal('');
- });
-
- it('returns unchanged string on no reserved input', () => {
-
- const a = Hoek.escapeHtml('abc');
- expect(a).to.equal('abc');
- });
-});
-
-describe('once()', () => {
-
- it('allows function to only execute once', () => {
-
- let gen = 0;
- let add = function (x) {
-
- gen += x;
- };
-
- add(5);
- expect(gen).to.equal(5);
- add = Hoek.once(add);
- add(5);
- expect(gen).to.equal(10);
- add(5);
- expect(gen).to.equal(10);
- });
-
- it('double once wraps one time', () => {
-
- let method = function () { };
- method = Hoek.once(method);
- method.x = 1;
- method = Hoek.once(method);
- expect(method.x).to.equal(1);
- });
-});
-
-describe('ignore()', () => {
-
- it('exists', () => {
-
- expect(Hoek.ignore).to.exist();
- expect(typeof Hoek.ignore).to.equal('function');
- });
-});
-
-describe('stringify()', () => {
-
- it('converts object to string', () => {
-
- const obj = { a: 1 };
- expect(Hoek.stringify(obj)).to.equal('{"a":1}');
- });
-
- it('returns error in result string', () => {
-
- const obj = { a: 1 };
- obj.b = obj;
- expect(Hoek.stringify(obj)).to.contain('Cannot display object');
- });
-});
-
-describe('isPromise()', () => {
-
- it('determines if an object is a promise', async () => {
-
- expect(Hoek.isPromise({})).to.be.false();
- expect(Hoek.isPromise(null)).to.be.false();
- expect(Hoek.isPromise(false)).to.be.false();
- expect(Hoek.isPromise(0)).to.be.false();
- expect(Hoek.isPromise('')).to.be.false();
- expect(Hoek.isPromise({ then: 1 })).to.be.false();
- expect(Hoek.isPromise([])).to.be.false();
-
- const items = [
- Promise.resolve(),
- Promise.reject()
- ];
-
- expect(Hoek.isPromise(items[0])).to.be.true();
- expect(Hoek.isPromise(items[1])).to.be.true();
- expect(Hoek.isPromise(new Promise(Hoek.ignore))).to.be.true();
- expect(Hoek.isPromise({ then: Hoek.ignore })).to.be.true();
-
- try {
- await Promise.all(items);
- }
- catch (err) { }
- });
-});
-
-describe('wait()', () => {
-
- it('delays for timeout ms', async () => {
-
- const timeout = {};
- setTimeout(() => (timeout.before = true), 10);
- const wait = Hoek.wait(10);
- setTimeout(() => (timeout.after = true), 10);
-
- await wait;
-
- expect(timeout.before).to.be.true();
- expect(timeout.after).to.be.undefined();
- });
-
- it('delays for timeout ms as bigint', async () => {
-
- const timeout = {};
- setTimeout(() => (timeout.before = true), 10);
- const wait = Hoek.wait(10n);
- setTimeout(() => (timeout.after = true), 10);
-
- await wait;
-
- expect(timeout.before).to.be.true();
- expect(timeout.after).to.be.undefined();
- });
-
- it('handles timeouts >= 2^31', async () => {
-
- const flow = [];
- let no = 0;
-
- const fakeTimeout = function (cb, time) {
-
- const timer = ++no;
-
- flow.push(`CALL(${timer}): ${time}`);
- setImmediate(() => {
-
- flow.push(`PRE(${timer})`);
- cb();
- flow.push(`POST(${timer})`);
- });
- };
-
- await Hoek.wait(2 ** 31, null, { setTimeout: fakeTimeout });
- flow.push('DONE1');
- await Hoek.wait(2 ** 32 + 2 ** 30, null, { setTimeout: fakeTimeout });
- flow.push('DONE2');
-
- expect(flow).to.equal([
- 'CALL(1): 2147483647',
- 'PRE(1)',
- 'CALL(2): 1',
- 'POST(1)',
- 'PRE(2)',
- 'POST(2)',
- 'DONE1',
- 'CALL(3): 2147483647',
- 'PRE(3)',
- 'CALL(4): 2147483647',
- 'POST(3)',
- 'PRE(4)',
- 'CALL(5): 1073741826',
- 'POST(4)',
- 'PRE(5)',
- 'POST(5)',
- 'DONE2'
- ]);
- });
-
- it('returns never resolving promise when timeout >= Number.MAX_SAFE_INTEGER', async () => {
-
- let calls = 0;
- const fakeTimeout = function (cb) {
-
- ++calls;
- process.nextTick(cb);
- };
-
- await Hoek.wait(2 ** 31 - 1, null, { setTimeout: fakeTimeout });
- expect(calls).to.equal(1);
-
- const waited = Symbol('waited');
-
- const result = await Promise.race([
- Hoek.wait(1, waited),
- Hoek.wait(Number.MAX_SAFE_INTEGER, null, { setTimeout: fakeTimeout }),
- Hoek.wait(Infinity, null, { setTimeout: fakeTimeout })
- ]);
-
- expect(result).to.be.equal(waited);
- expect(calls).to.equal(1);
- });
-
- it('handles a return value', async () => {
-
- const uniqueValue = {};
- const timeout = {};
- setTimeout(() => (timeout.before = true), 10);
- const wait = Hoek.wait(10, uniqueValue);
- setTimeout(() => (timeout.after = true), 10);
-
- expect(await wait).to.shallow.equal(uniqueValue);
- expect(timeout.before).to.be.true();
- expect(timeout.after).to.be.undefined();
- });
-
- it('undefined timeout resolves immediately', async () => {
-
- const waited = Symbol('waited');
- const result = await Promise.race([
- Hoek.wait(undefined, waited),
- Hoek.wait(0)
- ]);
-
- expect(result).to.equal(waited);
- });
-
- it('NaN timeout resolves immediately', async () => {
-
- const waited = Symbol('waited');
- const result = await Promise.race([
- Hoek.wait(Number.NaN, waited),
- Hoek.wait(0)
- ]);
-
- expect(result).to.equal(waited);
- });
-
- it('rejects on weird timeout values', async () => {
-
- await expect(() => Hoek.wait({})).to.throw();
- await expect(() => Hoek.wait(Symbol('hi'))).to.throw();
- });
-});
-
-describe('block()', () => {
-
- it('returns a promise', () => {
-
- expect(Hoek.block()).to.be.instanceOf(Promise);
- });
-
- it('does not immediately reject or resolve', async () => {
-
- const promise = Hoek.block();
- const waited = Symbol('waited');
-
- const result = await Promise.race([
- Hoek.wait(1, waited),
- promise
- ]);
-
- expect(result).to.be.equal(waited);
- });
-});
diff --git a/test/index.ts b/test/index.ts
index 322cc7da..d4310a1c 100755
--- a/test/index.ts
+++ b/test/index.ts
@@ -1,364 +1,2481 @@
-import * as Hoek from '..';
-import * as Lab from '@hapi/lab';
-import deepEqual = require('../lib/deepEqual');
-
-
-const { expect } = Lab.types;
-
-// Direct module import
-expect.type(deepEqual);
-expect.type(deepEqual(1, 2));
-
-interface Foo {
- a?: number;
- b?: string;
+// oxlint-disable unicorn/no-thenable
+
+import Util from 'util';
+
+import { describe, it, expect } from 'vitest';
+
+import * as Hoek from '../src/index.js';
+import { type MergeTypes } from '../src/merge.js';
+
+const nestedObj = {
+ v: [7, 8, 9],
+ w: /^something$/gim,
+ x: {
+ a: [1, 2, 3],
+ b: 123456,
+ c: new Date(),
+ d: /hi/gim,
+ e: /hello/,
+ },
+ y: 'y',
+ z: new Date(1378775452757),
};
-interface Bar {
- b?: string;
- c?: boolean;
-};
-
-
-// deepEqual()
-
-Hoek.deepEqual('some', 'some');
-Hoek.deepEqual('some', 3);
-Hoek.deepEqual({}, {});
-Hoek.deepEqual({}, {}, { prototype: false, symbols: true, part: false, deepFunction: true });
-Hoek.deepEqual({}, {}, { skip: ['a', 'b', Symbol('test')] });
-
-expect.type(Hoek.deepEqual(1, 2));
-
-expect.error(Hoek.deepEqual());
-expect.error(Hoek.deepEqual(1, 2, {}, 'x'));
-expect.error(Hoek.deepEqual({}, {}, { unknown: true }));
-expect.error(Hoek.deepEqual({}, {}, { skip: [1] }))
-
-
-// clone()
-
-Hoek.clone('string');
-Hoek.clone(123);
-Hoek.clone({ a: 1 });
-Hoek.clone({ a: 1 }, { prototype: true, symbols: true });
-Hoek.clone({}, { shallow: [] });
-Hoek.clone(1, { shallow: [] });
-Hoek.clone(null, { shallow: [] });
-Hoek.clone({ a: 1, b: { c: [2] } }, { shallow: true });
-Hoek.clone({ a: 1, b: { c: [2] } }, { shallow: ['b'] });
-Hoek.clone({ a: 1, b: { c: [2] } }, { shallow: [['b']] });
-Hoek.clone({ a: 1, b: { c: [2] } }, { shallow: ['b'], prototype: true, symbols: true });
-
-expect.type(Hoek.clone('string'));
-expect.type