diff --git a/features.txt b/features.txt index bd50c2957f2..a3304a46585 100644 --- a/features.txt +++ b/features.txt @@ -141,6 +141,10 @@ optional-chaining # https://github.com/tc39/proposal-top-level-await top-level-await +# RegExp Match Array Indices +# https://github.com/tc39/proposal-regexp-match-indices +regexp-match-indices + ## Standard language features # # Language features that have been included in a published version of the diff --git a/harness/assert.js b/harness/assert.js index cd548d895af..c777a4c2f63 100644 --- a/harness/assert.js +++ b/harness/assert.js @@ -5,6 +5,9 @@ description: | Collection of assertion functions used throughout test262 ---*/ +/// +/// + function assert(mustBeTrue, message) { if (mustBeTrue === true) { return; @@ -92,6 +95,58 @@ assert.throws = function (expectedErrorConstructor, func, message) { $ERROR(message); }; +assert._formatValue = function(value, seen) { + switch (typeof value) { + case 'string': + return typeof JSON !== "undefined" ? JSON.stringify(value) : '"' + value + '"'; + case 'number': + case 'boolean': + case 'symbol': + case 'bigint': + return value.toString(); + case 'undefined': + return 'undefined'; + case 'function': + return '[Function' + (value.name ? ': ' + value.name : '') + ']'; + case 'object': + if (value === null) return 'null'; + if (value instanceof Date) return 'Date "' + value.toISOString() + '"'; + if (value instanceof RegExp) return value.toString(); + if (!seen) { + seen = { + counter: 0, + map: new Map() + }; + } + + var usage = seen.map.get(value); + if (usage) { + usage.used = true; + return '[Ref: #' + usage.id + ']'; + } + + usage = { id: ++seen.counter, used: false }; + seen.map.set(value, usage); + + if (typeof Set !== "undefined" && value instanceof Set) { + return 'Set {' + Array.from(value).map(function (value) { return assert._formatValue(value, seen); }).join(', ') + '}' + (usage.used ? ' as #' + usage.id : ''); + } + if (typeof Map !== "undefined" && value instanceof Map) { + return 'Map {' + Array.from(value).map(function (pair) { return assert._formatValue(pair[0], seen) + ' => ' + assert._formatValue(pair[1], seen) + '}'; }).join(', ') + '}' + (usage.used ? ' as #' + usage.id : ''); + } + if (Array.isArray ? Array.isArray(value) : value instanceof Array) { + return '[' + value.map(function (value) { return assert._formatValue(value, seen); }).join(', ') + ']' + (usage.used ? ' as #' + usage.id : ''); + } + var tag = Symbol.toStringTag in value ? value[Symbol.toStringTag] : 'Object'; + if (tag === 'Object' && Object.getPrototypeOf(value) === null) { + tag = '[Object: null prototype]'; + } + return (tag ? tag + ' ' : '') + '{ ' + Object.keys(value).map(function (key) { return key.toString() + ': ' + assert._formatValue(value[key], seen); }).join(', ') + ' }' + (usage.used ? ' as #' + usage.id : ''); + default: + return typeof value; + } +}; + assert._toString = function (value) { try { return String(value); diff --git a/harness/compareArray.js b/harness/compareArray.js index 38a5d9a5a69..a95c7533d2b 100644 --- a/harness/compareArray.js +++ b/harness/compareArray.js @@ -5,6 +5,9 @@ description: | Compare the contents of two arrays ---*/ +// @ts-check +/// + function isSameValue(a, b) { if (a === 0 && b === 0) return 1 / a === 1 / b; if (a !== a && b !== b) return true; @@ -12,6 +15,11 @@ function isSameValue(a, b) { return a === b; } +/** + * @template T + * @param {T[]} a + * @param {T[]} b + */ function compareArray(a, b) { if (b.length !== a.length) { return false; @@ -25,11 +33,13 @@ function compareArray(a, b) { return true; } +/** + * @template T + * @param {T[]} actual + * @param {T[]} expected + * @param {string} [message] + */ assert.compareArray = function(actual, expected, message) { - function formatArray(array) { - return '[' + array.map(String).join(', ') + ']'; - } - assert(compareArray(actual, expected), - 'Expected ' + formatArray(actual) + ' and ' + formatArray(expected) + ' to have the same contents. ' + message); + 'Expected ' + assert._formatValue(actual) + ' and ' + assert._formatValue(expected) + ' to have the same contents. ' + message); }; diff --git a/harness/deepEqual.js b/harness/deepEqual.js new file mode 100644 index 00000000000..5266035fd37 --- /dev/null +++ b/harness/deepEqual.js @@ -0,0 +1,415 @@ +// Copyright 2019 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. +/*--- +description: | + Compare two values structurally +---*/ + +// @ts-check +/// + +var deepEqual = (function () { + /** + * @typedef {0} UNKNOWN + * @typedef {1} EQUAL + * @typedef {-1} NOT_EQUAL + * @typedef {Map>} ComparisonCache + */ + + /** @type {EQUAL} */ + var EQUAL = 1; + + /** @type {NOT_EQUAL} */ + var NOT_EQUAL = -1; + + /** @type {UNKNOWN} */ + var UNKNOWN = 0; + + /** + * @template T + * @param {T} a + * @param {T} b + * @returns {boolean} + */ + function deepEqual(a, b) { + return compareEquality(a, b) === EQUAL; + } + + /** + * @param {unknown} a + * @param {unknown} b + * @param {ComparisonCache} [cache] + * @returns {EQUAL | NOT_EQUAL} + */ + function compareEquality(a, b, cache) { + return compareIf(a, b, isOptional, compareOptionality) + || compareIf(a, b, isPrimitiveEquatable, comparePrimitiveEquality) + || compareIf(a, b, isObjectEquatable, compareObjectEquality, cache) + || NOT_EQUAL; + } + + /** + * @template T + * @param {unknown} a + * @param {unknown} b + * @param {(value: unknown) => value is T} test + * @param {(a: T, b: T, cache?: ComparisonCache) => EQUAL | NOT_EQUAL} compare + * @param {ComparisonCache} [cache] + * @returns {EQUAL | NOT_EQUAL | UNKNOWN} + */ + function compareIf(a, b, test, compare, cache) { + return !test(a) + ? !test(b) ? UNKNOWN : NOT_EQUAL + : !test(b) ? NOT_EQUAL : cacheComparison(a, b, compare, cache); + } + + /** + * @returns {EQUAL | UNKNOWN} + */ + function tryCompareStrictEquality(a, b) { + return a === b ? EQUAL : UNKNOWN; + } + + /** + * @returns {NOT_EQUAL | UNKNOWN} + */ + function tryCompareTypeOfEquality(a, b) { + return typeof a !== typeof b ? NOT_EQUAL : UNKNOWN; + } + + /** + * @returns {NOT_EQUAL | UNKNOWN} + */ + function tryCompareToStringTagEquality(a, b) { + var aTag = Symbol.toStringTag in a ? a[Symbol.toStringTag] : undefined; + var bTag = Symbol.toStringTag in b ? b[Symbol.toStringTag] : undefined; + return aTag !== bTag ? NOT_EQUAL : UNKNOWN; + } + + /** + * @returns {value is null | undefined} + */ + function isOptional(value) { + return value === undefined + || value === null; + } + + /** + * @returns {EQUAL | NOT_EQUAL} + */ + function compareOptionality(a, b) { + return tryCompareStrictEquality(a, b) + || NOT_EQUAL; + } + + /** + * @returns {value is number | bigint | string | symbol | boolean | undefined} + */ + function isPrimitiveEquatable(value) { + switch (typeof value) { + case 'string': + case 'number': + case 'bigint': + case 'boolean': + case 'symbol': + return true; + default: + return isBoxed(value); + } + } + + /** + * @returns {EQUAL | NOT_EQUAL} + */ + function comparePrimitiveEquality(a, b) { + if (isBoxed(a)) a = a.valueOf(); + if (isBoxed(b)) b = b.valueOf(); + return tryCompareStrictEquality(a, b) + || tryCompareTypeOfEquality(a, b) + || compareIf(a, b, isNaNEquatable, compareNaNEquality) + || NOT_EQUAL; + } + + /** + * @returns {value is number} + */ + function isNaNEquatable(value) { + return typeof value === 'number'; + } + + /** + * @param {number} a + * @param {number} b + * @returns {EQUAL | NOT_EQUAL} + */ + function compareNaNEquality(a, b) { + return isNaN(a) && isNaN(b) ? EQUAL : NOT_EQUAL; + } + + /** + * @returns {value is object} + */ + function isObjectEquatable(value) { + return typeof value === 'object'; + } + + /** + * @param {ComparisonCache} cache + * @returns {EQUAL | NOT_EQUAL} + */ + function compareObjectEquality(a, b, cache) { + if (!cache) cache = new Map(); + return getCache(cache, a, b) + || setCache(cache, a, b, EQUAL) // consider equal for now + || cacheComparison(a, b, tryCompareStrictEquality, cache) + || cacheComparison(a, b, tryCompareToStringTagEquality, cache) + || compareIf(a, b, isValueOfEquatable, compareValueOfEquality) + || compareIf(a, b, isToStringEquatable, compareToStringEquality) + || compareIf(a, b, isArrayLikeEquatable, compareArrayLikeEquality, cache) + || compareIf(a, b, isStructurallyEquatable, compareStructuralEquality, cache) + || compareIf(a, b, isIterableEquatable, compareIterableEquality, cache) + || cacheComparison(a, b, fail, cache); + } + + function isBoxed(value) { + return value instanceof String + || value instanceof Number + || value instanceof Boolean + || typeof Symbol === 'function' && value instanceof Symbol + || typeof BigInt === 'function' && value instanceof BigInt; + } + + /** + * @returns {value is { valueOf(): any }} + */ + function isValueOfEquatable(value) { + return value instanceof Date; + } + + /** + * @param {{ valueOf(): any }} a + * @param {{ valueOf(): any }} b + * @returns {EQUAL | NOT_EQUAL} + */ + function compareValueOfEquality(a, b) { + return compareIf(a.valueOf(), b.valueOf(), isPrimitiveEquatable, comparePrimitiveEquality) + || NOT_EQUAL; + } + + /** + * @returns {value is { toString(): string }} + */ + function isToStringEquatable(value) { + return value instanceof RegExp; + } + + /** + * @param {{ toString(): string }} a + * @param {{ toString(): string }} b + * @returns {EQUAL | NOT_EQUAL} + */ + function compareToStringEquality(a, b) { + return compareIf(a.toString(), b.toString(), isPrimitiveEquatable, comparePrimitiveEquality) + || NOT_EQUAL; + } + + /** + * @returns {value is ArrayLike} + */ + function isArrayLikeEquatable(value) { + return (Array.isArray ? Array.isArray(value) : value instanceof Array) + || (typeof Uint8Array === 'function' && value instanceof Uint8Array) + || (typeof Uint8ClampedArray === 'function' && value instanceof Uint8ClampedArray) + || (typeof Uint16Array === 'function' && value instanceof Uint16Array) + || (typeof Uint32Array === 'function' && value instanceof Uint32Array) + || (typeof Int8Array === 'function' && value instanceof Int8Array) + || (typeof Int16Array === 'function' && value instanceof Int16Array) + || (typeof Int32Array === 'function' && value instanceof Int32Array) + || (typeof Float32Array === 'function' && value instanceof Float32Array) + || (typeof Float64Array === 'function' && value instanceof Float64Array) + || (typeof BigUint64Array === 'function' && value instanceof BigUint64Array) + || (typeof BigInt64Array === 'function' && value instanceof BigInt64Array); + } + + /** + * @template T + * @param {ArrayLike} a + * @param {ArrayLike} b + * @param {ComparisonCache} cache + * @returns {EQUAL | NOT_EQUAL} + */ + function compareArrayLikeEquality(a, b, cache) { + if (a.length !== b.length) return NOT_EQUAL; + for (var i = 0; i < a.length; i++) { + if (compareEquality(a[i], b[i], cache) === NOT_EQUAL) { + return NOT_EQUAL; + } + } + return EQUAL; + } + + /** + * @template T + * @param {T} value + * @returns {value is Exclude} + */ + function isStructurallyEquatable(value) { + return !(typeof Promise === 'function' && value instanceof Promise // only comparable by reference + || typeof WeakMap === 'function' && value instanceof WeakMap // only comparable by reference + || typeof WeakSet === 'function' && value instanceof WeakSet // only comparable by reference + || typeof Map === 'function' && value instanceof Map // comparable via @@iterator + || typeof Set === 'function' && value instanceof Set); // comparable via @@iterator + } + + /** + * @param {ComparisonCache} cache + * @returns {EQUAL | NOT_EQUAL} + */ + function compareStructuralEquality(a, b, cache) { + var aKeys = []; + for (var key in a) aKeys.push(key); + + var bKeys = []; + for (var key in b) bKeys.push(key); + + if (aKeys.length !== bKeys.length) { + return NOT_EQUAL; + } + + aKeys.sort(); + bKeys.sort(); + + for (var i = 0; i < aKeys.length; i++) { + var aKey = aKeys[i]; + var bKey = bKeys[i]; + if (compareEquality(aKey, bKey, cache) === NOT_EQUAL) { + return NOT_EQUAL; + } + if (compareEquality(a[aKey], b[bKey], cache) === NOT_EQUAL) { + return NOT_EQUAL; + } + } + + return compareIf(a, b, isIterableEquatable, compareIterableEquality, cache) + || EQUAL; + } + + /** + * @returns {value is Iterable} + */ + function isIterableEquatable(value) { + return typeof Symbol === 'function' + && typeof value[Symbol.iterator] === 'function'; + } + + /** + * @template T + * @param {Iterator} a + * @param {Iterator} b + * @param {ComparisonCache} cache + * @returns {EQUAL | NOT_EQUAL} + */ + function compareIteratorEquality(a, b, cache) { + if (typeof Map === 'function' && a instanceof Map && b instanceof Map || + typeof Set === 'function' && a instanceof Set && b instanceof Set) { + if (a.size !== b.size) return NOT_EQUAL; // exit early if we detect a difference in size + } + + var ar, br; + while (true) { + ar = a.next(); + br = b.next(); + if (ar.done) { + if (br.done) return EQUAL; + if (b.return) b.return(); + return NOT_EQUAL; + } + if (br.done) { + if (a.return) a.return(); + return NOT_EQUAL; + } + if (compareEquality(ar.value, br.value, cache) === NOT_EQUAL) { + if (a.return) a.return(); + if (b.return) b.return(); + return NOT_EQUAL; + } + } + } + + /** + * @template T + * @param {Iterable} a + * @param {Iterable} b + * @param {ComparisonCache} cache + * @returns {EQUAL | NOT_EQUAL} + */ + function compareIterableEquality(a, b, cache) { + return compareIteratorEquality(a[Symbol.iterator](), b[Symbol.iterator](), cache); + } + + /** + * @template T + * @template {EQUAL | NOT_EQUAL | UNKNOWN} R + * @param {(a: T, b: T, circular?: ComparisonCache) => R} compare + * @param {ComparisonCache} [cache] + */ + function cacheComparison(a, b, compare, cache) { + var result = compare(a, b, cache); + if (cache && (result === EQUAL || result === NOT_EQUAL)) { + setCache(cache, a, b, /** @type {EQUAL | NOT_EQUAL} */(result)); + } + return result; + } + + function fail() { + return NOT_EQUAL; + } + + /** + * @param {EQUAL | NOT_EQUAL} result + * @param {ComparisonCache} cache + */ + function setCache(cache, left, right, result) { + var otherCache; + + otherCache = cache.get(left); + if (!otherCache) cache.set(left, otherCache = new Map()); + otherCache.set(right, result); + + otherCache = cache.get(right); + if (!otherCache) cache.set(right, otherCache = new Map()); + otherCache.set(left, result); + } + + /** + * @param {ComparisonCache} cache + */ + function getCache(cache, left, right) { + var otherCache; + /** @type {EQUAL | NOT_EQUAL | UNKNOWN | undefined} */ + var result; + + otherCache = cache.get(left); + result = otherCache && otherCache.get(right); + if (result) return result; + + otherCache = cache.get(right); + result = otherCache && otherCache.get(left); + if (result) return result; + + return UNKNOWN; + } + + return deepEqual; +})(); + +/** + * @template T + * @param {T} actual + * @param {T} expected + * @param {string} [message] + */ +assert.deepEqual = function (actual, expected, message) { + assert(deepEqual(actual, expected), + 'Expected ' + assert._formatValue(actual) + ' to be structurally equal to ' + assert._formatValue(expected) + '. ' + (message || '')); +}; diff --git a/harness/propertyHelper.js b/harness/propertyHelper.js index a3a57a1bebe..f4c3158eb1a 100644 --- a/harness/propertyHelper.js +++ b/harness/propertyHelper.js @@ -6,6 +6,16 @@ description: | property descriptors. ---*/ +// @ts-check +/// + +/** + * @param {object} obj + * @param {string|symbol} name + * @param {PropertyDescriptor|undefined} desc + * @param {object} [options] + * @param {boolean} [options.restore] + */ function verifyProperty(obj, name, desc, options) { assert( arguments.length > 2, diff --git a/harness/types.d.ts b/harness/types.d.ts new file mode 100644 index 00000000000..b3d415ad60e --- /dev/null +++ b/harness/types.d.ts @@ -0,0 +1,14 @@ +declare function $ERROR(text: string): void; + +// Proposal: regexp-match-indices +interface RegExpExecArray { + indices: RegExpIndicesArray; +} + +interface RegExpMatchArray { + indices: RegExpIndicesArray; +} + +interface RegExpIndicesArray extends Array<[number, number]> { + groups?: { [group: string]: [number, number] }; +} diff --git a/test/built-ins/RegExp/match-indices/indices-array-element.js b/test/built-ins/RegExp/match-indices/indices-array-element.js new file mode 100644 index 00000000000..aebfd5772a7 --- /dev/null +++ b/test/built-ins/RegExp/match-indices/indices-array-element.js @@ -0,0 +1,31 @@ +// Copyright 2019 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: A matching element of indices is an Array with exactly two number properties. +includes: [compareArray.js] +esid: sec-getmatchindicesarray +features: [regexp-match-indices] +info: | + GetMatchIndicesArray ( S, match ) + 5. Return CreateArrayFromList(ยซ _match_.[[StartIndex]], _match_.[[EndIndex]] ยป). +---*/ + +/// +/// + +let input = "abcd"; +let match = /b(c)/.exec(input); +let indices = match.indices; + +// `indices[0]` is an array +assert.sameValue(Object.getPrototypeOf(indices[0]), Array.prototype); +assert.sameValue(indices[0].length, 2); +assert.sameValue(typeof indices[0][0], "number"); +assert.sameValue(typeof indices[0][1], "number"); + +// `indices[1]` is an array +assert.sameValue(Object.getPrototypeOf(indices[1]), Array.prototype); +assert.sameValue(indices[1].length, 2); +assert.sameValue(typeof indices[1][0], "number"); +assert.sameValue(typeof indices[1][1], "number"); diff --git a/test/built-ins/RegExp/match-indices/indices-array-matched.js b/test/built-ins/RegExp/match-indices/indices-array-matched.js new file mode 100644 index 00000000000..c0b42478e49 --- /dev/null +++ b/test/built-ins/RegExp/match-indices/indices-array-matched.js @@ -0,0 +1,41 @@ +// Copyright 2019 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: The properties of the "indices" array correspond to the start/end indices of the same values in the match. +includes: [compareArray.js] +esid: sec-makeindicesarray +features: [regexp-match-indices] +info: | + MakeIndicesArray ( S, indices, groupNames ) + 4. Let _n_ be the number of elements in _indices_. + ... + 6. Set _A_ to ! ArrayCreate(_n_). + ... + 11. For each integer _i_ such that _i_ >= 0 and _i_ < _n_, do + a. Let _matchIndices_ be _indices_[_i_]. + b. If _matchIndices_ is not *undefined*, then + i. Let _matchIndicesArray_ be ! GetMatchIndicesArray(_S_, _matchIndices_). + c. Else, + i. Let _matchIndicesArray_ be *undefined*. + d. Perform ! CreateDataProperty(_A_, ! ToString(_n_), _matchIndicesArray_). + ... +---*/ + +/// +/// + +let input = "abcd"; +let match = /b(c)/.exec(input); +let indices = match.indices; + +// `indices` has the same length as match +assert.sameValue(indices.length, match.length); + +// The first element of `indices` contains the start/end indices of the match +assert.compareArray(indices[0], [1, 3]); +assert.sameValue(input.slice(indices[0][0], indices[0][1]), match[0]); + +// The second element of `indices` contains the start/end indices of the first capture +assert.compareArray(indices[1], [2, 3]); +assert.sameValue(input.slice(indices[1][0], indices[1][1]), match[1]); diff --git a/test/built-ins/RegExp/match-indices/indices-array-non-unicode-match.js b/test/built-ins/RegExp/match-indices/indices-array-non-unicode-match.js new file mode 100644 index 00000000000..7e0ff3481d4 --- /dev/null +++ b/test/built-ins/RegExp/match-indices/indices-array-non-unicode-match.js @@ -0,0 +1,80 @@ +// Copyright 2019 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Basic matching cases with non-unicode matches. +includes: [compareArray.js, propertyHelper.js, deepEqual.js] +esid: sec-regexpbuiltinexec +features: [regexp-match-indices] +info: | + Runtime Semantics: RegExpBuiltinExec ( R, S ) + ... + 4. Let _lastIndex_ be ? ToLength(? Get(_R_, `"lastIndex")). + ... + 25. Let _indices_ be a new empty List. + 26. Let _match_ be the Match { [[StartIndex]]: _lastIndex_, [[EndIndex]]: _e_ }. + 27. Add _match_ as the last element of _indices_. + ... + 33. For each integer _i_ such that _i_ > 0 and _i_ <= _n_, in ascending order, do + ... + f. Else, + i. Let _captureStart_ be _captureI_'s _startIndex_. + ii. Let _captureEnd_ be _captureI_'s _endIndex_. + ... + iv. Let _capture_ be the Match { [[StartIndex]]: _captureStart_, [[EndIndex]]: _captureEnd_ }. + v. Append _capture_ to _indices_. + ... + 34. Let _indicesArray_ be MakeIndicesArray( _S_, _indices_, _groupNames_). +---*/ + +/// +/// +/// +/// + +assert.deepEqual([[1, 2], [1, 2]], "bab".match(/(a)/).indices); +assert.deepEqual([[0, 3], [1, 2]], "bab".match(/.(a)./).indices); +assert.deepEqual([[0, 3], [1, 2], [2, 3]], "bab".match(/.(a)(.)/).indices); +assert.deepEqual([[0, 3], [1, 3]], "bab".match(/.(\w\w)/).indices); +assert.deepEqual([[0, 3], [0, 3]], "bab".match(/(\w\w\w)/).indices); +assert.deepEqual([[0, 3], [0, 2], [2, 3]], "bab".match(/(\w\w)(\w)/).indices); +assert.deepEqual([[0, 2], [0, 2], undefined], "bab".match(/(\w\w)(\W)?/).indices); + +let groups = /(?.)(?.)(?.)\k\k\k/.exec("abccba").indices.groups; +assert.compareArray([0, 1], groups.a); +assert.compareArray([1, 2], groups.b); +assert.compareArray([2, 3], groups.c); +verifyProperty(groups, "a", { + enumerable: true, + writable: true, + configurable: true +}); +verifyProperty(groups, "b", { + enumerable: true, + writable: true, + configurable: true +}); +verifyProperty(groups, "c", { + enumerable: true, + writable: true, + configurable: true +}); + +// "๐" is U+1d401 MATHEMATICAL BOLD CAPITAL B +// - Also representable as the code point "\u{1d401}" +// - Also representable as the surrogate pair "\uD835\uDC01" + +// Verify assumptions: +assert.sameValue("๐".length, 2, 'The length of "๐" is 2'); +assert.sameValue("\u{1d401}".length, 2, 'The length of "\\u{1d401}" is 2'); +assert.sameValue("\uD835\uDC01".length, 2, 'The length of "\\uD835\\uDC01" is 2'); +assert.sameValue("๐".match(/./)[0].length, 1, 'The length of a single code unit match against "๐" is 1 (without /u flag)'); +assert.sameValue("\u{1d401}".match(/./)[0].length, 1, 'The length of a single code unit match against "\\u{1d401}" is 1 (without /u flag)'); +assert.sameValue("\uD835\uDC01".match(/./)[0].length, 1, 'The length of a single code unit match against "\\ud835\\udc01" is 1 (without /u flag)'); + +assert.compareArray([0, 1], "๐".match(/./).indices[0], 'Indices for non-unicode match against "๐" (without /u flag)'); +assert.compareArray([0, 1], "\u{1d401}".match(/./).indices[0], 'Indices for non-unicode match against "\\u{1d401}" (without /u flag)'); +assert.compareArray([0, 1], "\uD835\uDC01".match(/./).indices[0], 'Indices for non-unicode match against "\\ud835\\udc01" (without /u flag)'); +assert.compareArray([0, 1], "๐".match(/(?.)/).indices.groups.a, 'Indices for non-unicode match against "๐" in groups.a (without /u flag)'); +assert.compareArray([0, 1], "\u{1d401}".match(/(?.)/).indices.groups.a, 'Indices for non-unicode match against "\\u{1d401}" in groups.a (without /u flag)'); +assert.compareArray([0, 1], "\uD835\uDC01".match(/(?.)/).indices.groups.a, 'Indices for non-unicode match against "\\ud835\\udc01" in groups.a (without /u flag)'); diff --git a/test/built-ins/RegExp/match-indices/indices-array-properties.js b/test/built-ins/RegExp/match-indices/indices-array-properties.js new file mode 100644 index 00000000000..6f48381ae66 --- /dev/null +++ b/test/built-ins/RegExp/match-indices/indices-array-properties.js @@ -0,0 +1,32 @@ +// Copyright 2019 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: The properties of the "indices" array are created with CreateDataProperty. +includes: [propertyHelper.js] +esid: sec-makeindicesarray +features: [regexp-match-indices] +info: | + MakeIndicesArray ( S, indices, groupNames ) + 11. For each integer _i_ such that _i_ >= 0 and _i_ < _n_, do + d. Perform ! CreateDataProperty(_A_, ! ToString(_n_), _matchIndicesArray_). +---*/ + +/// +/// + +let input = "abcd"; +let match = /b(c)/.exec(input); +let indices = match.indices; + +verifyProperty(indices, '0', { + enumerable: true, + configurable: true, + writable: true +}); + +verifyProperty(indices, '1', { + enumerable: true, + configurable: true, + writable: true +}); diff --git a/test/built-ins/RegExp/match-indices/indices-array-unicode-match.js b/test/built-ins/RegExp/match-indices/indices-array-unicode-match.js new file mode 100644 index 00000000000..b4b8018157d --- /dev/null +++ b/test/built-ins/RegExp/match-indices/indices-array-unicode-match.js @@ -0,0 +1,89 @@ +// Copyright 2019 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Basic matching cases with non-unicode matches. +includes: [compareArray.js, propertyHelper.js, deepEqual.js] +esid: sec-regexpbuiltinexec +features: [regexp-match-indices] +info: | + Runtime Semantics: RegExpBuiltinExec ( R, S ) + ... + 4. Let _lastIndex_ be ? ToLength(? Get(_R_, `"lastIndex")). + ... + 16. If _fullUnicode_ is *true*, set _e_ to ! GetStringIndex(_S_, _Input_, _e_). + ... + 25. Let _indices_ be a new empty List. + 26. Let _match_ be the Match { [[StartIndex]]: _lastIndex_, [[EndIndex]]: _e_ }. + 27. Add _match_ as the last element of _indices_. + ... + 33. For each integer _i_ such that _i_ > 0 and _i_ <= _n_, in ascending order, do + ... + f. Else, + i. Let _captureStart_ be _captureI_'s _startIndex_. + ii. Let _captureEnd_ be _captureI_'s _endIndex_. + iii. If _fullUnicode_ is *true*, then + 1. Set _captureStart_ to ! GetStringIndex(_S_, _Input_, _captureStart_). + 1. Set _captureEnd_ to ! GetStringIndex(_S_, _Input_, _captureEnd_). + iv. Let _capture_ be the Match { [[StartIndex]]: _captureStart_, [[EndIndex]]: _captureEnd_ }. + v. Append _capture_ to _indices_. + ... + 34. Let _indicesArray_ be MakeIndicesArray( _S_, _indices_, _groupNames_). + + GetStringIndex ( S, Input, e ) + ... + 4. Let _eUTF_ be the smallest index into _S_ that corresponds to the character at element _e_ of _Input_. If _e_ is greater than or equal to the number of elements in _Input_, then _eUTF_ is the number of code units in _S_. + 5. Return _eUTF_. +---*/ + +/// +/// +/// +/// + +assert.deepEqual([[1, 2], [1, 2]], "bab".match(/(a)/u).indices); +assert.deepEqual([[0, 3], [1, 2]], "bab".match(/.(a)./u).indices); +assert.deepEqual([[0, 3], [1, 2], [2, 3]], "bab".match(/.(a)(.)/u).indices); +assert.deepEqual([[0, 3], [1, 3]], "bab".match(/.(\w\w)/u).indices); +assert.deepEqual([[0, 3], [0, 3]], "bab".match(/(\w\w\w)/u).indices); +assert.deepEqual([[0, 3], [0, 2], [2, 3]], "bab".match(/(\w\w)(\w)/u).indices); +assert.deepEqual([[0, 2], [0, 2], undefined], "bab".match(/(\w\w)(\W)?/u).indices); + +let groups = /(?.)(?.)(?.)\k\k\k/u.exec("abccba").indices.groups; +assert.compareArray([0, 1], groups.a); +assert.compareArray([1, 2], groups.b); +assert.compareArray([2, 3], groups.c); +verifyProperty(groups, "a", { + enumerable: true, + writable: true, + configurable: true +}); +verifyProperty(groups, "b", { + enumerable: true, + writable: true, + configurable: true +}); +verifyProperty(groups, "c", { + enumerable: true, + writable: true, + configurable: true +}); + +// "๐" is U+1d401 MATHEMATICAL BOLD CAPITAL B +// - Also representable as the code point "\u{1d401}" +// - Also representable as the surrogate pair "\uD835\uDC01" + +// Verify assumptions: +assert.sameValue("๐".length, 2, 'The length of "๐" is 2'); +assert.sameValue("\u{1d401}".length, 2, 'The length of "\\u{1d401}" is 2'); +assert.sameValue("\uD835\uDC01".length, 2, 'The length of "\\uD835\\uDC01" is 2'); +assert.sameValue(2, "๐".match(/./u)[0].length, 'The length of a single code point match against "๐" is 2 (with /u flag)'); +assert.sameValue(2, "\u{1d401}".match(/./u)[0].length, 'The length of a single code point match against "\\u{1d401}" is 2 (with /u flag)'); +assert.sameValue(2, "\uD835\uDC01".match(/./u)[0].length, 'The length of a single code point match against "\\ud835\\udc01" is 2 (with /u flag)'); + +assert.compareArray([0, 2], "๐".match(/./u).indices[0], 'Indices for unicode match against "๐" (with /u flag)'); +assert.compareArray([0, 2], "\u{1d401}".match(/./u).indices[0], 'Indices for unicode match against \\u{1d401} (with /u flag)'); +assert.compareArray([0, 2], "\uD835\uDC01".match(/./u).indices[0], 'Indices for unicode match against \\ud835\\udc01 (with /u flag)'); +assert.compareArray([0, 2], "๐".match(/(?.)/u).indices.groups.a, 'Indices for unicode match against ๐ in groups.a (with /u flag)'); +assert.compareArray([0, 2], "\u{1d401}".match(/(?.)/u).indices.groups.a, 'Indices for unicode match against \\u{1d401} in groups.a (with /u flag)'); +assert.compareArray([0, 2], "\uD835\uDC01".match(/(?.)/u).indices.groups.a, 'Indices for unicode match against \\ud835\\udc01 in groups.a (with /u flag)'); diff --git a/test/built-ins/RegExp/match-indices/indices-array-unicode-property-names.js b/test/built-ins/RegExp/match-indices/indices-array-unicode-property-names.js new file mode 100644 index 00000000000..875ce165d64 --- /dev/null +++ b/test/built-ins/RegExp/match-indices/indices-array-unicode-property-names.js @@ -0,0 +1,23 @@ +// Copyright 2019 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Basic matching cases with non-unicode matches. +includes: [compareArray.js] +esid: sec-makeindicesarray +features: [regexp-match-indices] +---*/ + +/// +/// + +assert.compareArray([1, 2], /(?<ฯ€>a)/u.exec("bab").indices.groups.ฯ€); +assert.compareArray([1, 2], /(?<\u{03C0}>a)/u.exec("bab").indices.groups.ฯ€); +assert.compareArray([1, 2], /(?<ฯ€>a)/u.exec("bab").indices.groups.\u03C0); +assert.compareArray([1, 2], /(?<\u{03C0}>a)/u.exec("bab").indices.groups.\u03C0); +assert.compareArray([1, 2], /(?<$>a)/u.exec("bab").indices.groups.$); +assert.compareArray([1, 2], /(?<_>a)/u.exec("bab").indices.groups._); +assert.compareArray([1, 2], /(?<$๐’ค>a)/u.exec("bab").indices.groups.$๐’ค); +assert.compareArray([1, 2], /(?<_\u200C>a)/u.exec("bab").indices.groups._\u200C); +assert.compareArray([1, 2], /(?<_\u200D>a)/u.exec("bab").indices.groups._\u200D); +assert.compareArray([1, 2], /(?<เฒ _เฒ >a)/u.exec("bab").indices.groups.เฒ _เฒ ); diff --git a/test/built-ins/RegExp/match-indices/indices-array-unmatched.js b/test/built-ins/RegExp/match-indices/indices-array-unmatched.js new file mode 100644 index 00000000000..17c228eab9a --- /dev/null +++ b/test/built-ins/RegExp/match-indices/indices-array-unmatched.js @@ -0,0 +1,34 @@ +// Copyright 2019 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: An unmatched capture in a match corresponds to an unmatched capture in "indices" +esid: sec-makeindicesarray +features: [regexp-match-indices] +info: | + MakeIndicesArray ( S, indices, groupNames ) + 4. Let _n_ be the number of elements in _indices_. + ... + 6. Set _A_ to ! ArrayCreate(_n_). + ... + 11. For each integer _i_ such that _i_ >= 0 and _i_ < _n_, do + a. Let _matchIndices_ be _indices_[_i_]. + b. If _matchIndices_ is not *undefined*, then + i. Let _matchIndicesArray_ be ! GetMatchIndicesArray(_S_, _matchIndices_). + c. Else, + i. Let _matchIndicesArray_ be *undefined*. + d. Perform ! CreateDataProperty(_A_, ! ToString(_n_), _matchIndicesArray_). + ... +---*/ + +/// + +let input = "abd"; +let match = /b(c)?/.exec(input); +let indices = match.indices; + +// `indices` has the same length as match +assert.sameValue(indices.length, match.length); + +// The second element of `indices` should be undefined. +assert.sameValue(indices[1], undefined); diff --git a/test/built-ins/RegExp/match-indices/indices-array.js b/test/built-ins/RegExp/match-indices/indices-array.js new file mode 100644 index 00000000000..67b5a79b335 --- /dev/null +++ b/test/built-ins/RegExp/match-indices/indices-array.js @@ -0,0 +1,20 @@ +// Copyright 2019 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: The "indices" property is an Array. +esid: sec-makeindicesarray +features: [regexp-match-indices] +info: | + MakeIndicesArray ( S, indices, groupNames ) + 6. Set _A_ to ! ArrayCreate(_n_). +---*/ + +/// + +let match = /a/.exec("a"); +let indices = match.indices; + +// `indices` is an array +assert.sameValue(Object.getPrototypeOf(indices), Array.prototype); +assert(Array.isArray(indices)); \ No newline at end of file diff --git a/test/built-ins/RegExp/match-indices/indices-groups-object-undefined.js b/test/built-ins/RegExp/match-indices/indices-groups-object-undefined.js new file mode 100644 index 00000000000..0fa32f9cf35 --- /dev/null +++ b/test/built-ins/RegExp/match-indices/indices-groups-object-undefined.js @@ -0,0 +1,28 @@ +// Copyright 2019 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: The groups object of indices is created unconditionally. +includes: [propertyHelper.js] +esid: sec-makeindicesarray +features: [regexp-named-groups] +info: | + MakeIndicesArray ( S, indices, groupNames ) + 8. If _groupNames_ is not *undefined*, then + a. Let _groups_ be ! ObjectCreate(*null*). + 9. Else, + a. Let _groups_ be *undefined*. + 10. Perform ! CreateDataProperty(_A_, `"groups"`, _groups_). +---*/ + +/// +/// + +const re = /./; +const indices = re.exec("a").indices; +verifyProperty(indices, 'groups', { + writable: true, + enumerable: true, + configurable: true, + value: undefined +}); diff --git a/test/built-ins/RegExp/match-indices/indices-groups-object-unmatched.js b/test/built-ins/RegExp/match-indices/indices-groups-object-unmatched.js new file mode 100644 index 00000000000..2ffb3ab85de --- /dev/null +++ b/test/built-ins/RegExp/match-indices/indices-groups-object-unmatched.js @@ -0,0 +1,22 @@ +// Copyright 2019 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Test the groups object of indices with matched and unmatched named captures. +includes: [compareArray.js] +esid: sec-makeindicesarray +features: [regexp-named-groups] +info: | + MakeIndicesArray ( S, indices, groupNames ) + 11. For each integer _i_ such that _i_ >= 0 and _i_ < _n_, do + e. If _groupNames_ is not *undfined* and _groupNames_[_i_] is not *undefined*, then + i. Perform ! CreateDataProperty(_groups_, _groupNames_[_i_], _matchIndicesArray_). +---*/ + +/// +/// + +const re = /(?a).|(?x)/; +const result = re.exec("ab").indices; +assert.compareArray([0, 1], result.groups.a); +assert.sameValue(undefined, result.groups.x); diff --git a/test/built-ins/RegExp/match-indices/indices-groups-object.js b/test/built-ins/RegExp/match-indices/indices-groups-object.js new file mode 100644 index 00000000000..a65e1c2cfd8 --- /dev/null +++ b/test/built-ins/RegExp/match-indices/indices-groups-object.js @@ -0,0 +1,43 @@ +// Copyright 2019 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: The groups object of indices is created with CreateDataProperty +includes: [compareArray.js, propertyHelper.js] +esid: sec-makeindicesarray +features: [regexp-named-groups] +info: | + MakeIndicesArray ( S, indices, groupNames ) + 8. If _groupNames_ is not *undefined*, then + a. Let _groups_ be ! ObjectCreate(*null*). + 9. Else, + a. Let _groups_ be *undefined*. + 10. Perform ! CreateDataProperty(_A_, `"groups"`, _groups_). +---*/ + +/// +/// +/// + +// `groups` is created with Define, not Set. +let counter = 0; +Object.defineProperty(Array.prototype, "groups", { + set() { counter++; } +}); + +let indices = /(?.)/.exec("a").indices; +assert.sameValue(counter, 0); + +// `groups` is writable, enumerable and configurable +// (from CreateDataProperty). +verifyProperty(indices, 'groups', { + writable: true, + enumerable: true, + configurable: true +}); + +// The `__proto__` property on the groups object is not special, +// and does not affect the [[Prototype]] of the resulting groups object. +let {groups} = /(?<__proto__>.)/.exec("a").indices; +assert.compareArray([0, 1], groups.__proto__); +assert.sameValue(null, Object.getPrototypeOf(groups)); diff --git a/test/built-ins/RegExp/match-indices/indices-groups-properties.js b/test/built-ins/RegExp/match-indices/indices-groups-properties.js new file mode 100644 index 00000000000..484b8fdb4a5 --- /dev/null +++ b/test/built-ins/RegExp/match-indices/indices-groups-properties.js @@ -0,0 +1,38 @@ +// Copyright 2019 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: Properties of the groups object of indices are created with CreateDataProperty +includes: [compareArray.js, propertyHelper.js] +esid: sec-makeindicesarray +features: [regexp-named-groups] +info: | + MakeIndicesArray ( S, indices, groupNames ) + 11. For each integer _i_ such that _i_ >= 0 and _i_ < _n_, do + e. If _groupNames_ is not *undfined* and _groupNames_[_i_] is not *undefined*, then + i. Perform ! CreateDataProperty(_groups_, _groupNames_[_i_], _matchIndicesArray_). +---*/ + +/// +/// +/// + +// Properties created on result.groups in textual order. +let groupNames = Object.getOwnPropertyNames(/(?.)|(?.)/u.exec("abcd").indices.groups); +assert.compareArray(groupNames, ["fst", "snd"]); + +// // Properties are created with Define, not Set +// let counter = 0; +// Object.defineProperty(Object.prototype, 'x', {set() { counter++; }}); + +let indices = /(?.)/.exec('a').indices; +let groups = indices.groups; +// assert.sameValue(counter, 0); + +// Properties are writable, enumerable and configurable +// (from CreateDataProperty) +verifyProperty(groups, 'x', { + writable: true, + enumerable: true, + configurable: true +}); diff --git a/test/built-ins/RegExp/match-indices/indices-property.js b/test/built-ins/RegExp/match-indices/indices-property.js new file mode 100644 index 00000000000..4fd66b8c40e --- /dev/null +++ b/test/built-ins/RegExp/match-indices/indices-property.js @@ -0,0 +1,32 @@ +// Copyright 2019 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: The "indices" property is created with DefinePropertyOrThrow +includes: [propertyHelper.js] +esid: sec-regexpbuiltinexec +features: [regexp-match-indices] +info: | + Runtime Semantics: RegExpBuiltinExec ( R, S ) + 34. Let _indicesArray_ be MakeIndicesArray(_S_, _indices_, _groupNames_). + 35. Perform ! DefinePropertyOrThrow(_A_, `"indices"`, PropertyDescriptor { [[Value]]: _indicesArray_, [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *true* }). +---*/ + +/// +/// + +// `indices` is created with Define, not Set. +let counter = 0; +Object.defineProperty(Array.prototype, "indices", { + set() { counter++; } +}); + +let match = /a/.exec("a"); +assert.sameValue(counter, 0); + +// `indices` is a non-writable, non-enumerable, and configurable data-property. +verifyProperty(match, 'indices', { + writable: true, + enumerable: true, + configurable: true +}); diff --git a/test/harness/deepEqual-array.js b/test/harness/deepEqual-array.js new file mode 100644 index 00000000000..06d3419c48c --- /dev/null +++ b/test/harness/deepEqual-array.js @@ -0,0 +1,17 @@ +// Copyright 2019 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + array values compare correctly. +includes: [deepEqual.js] +---*/ + +/// +/// + +assert.deepEqual([], []); +assert.deepEqual([1, "a", true], [1, "a", true]); + +assert.throws(Test262Error, function () { assert.deepEqual([], [1]); }); +assert.throws(Test262Error, function () { assert.deepEqual([1, "a", true], [1, "a", false]); }); diff --git a/test/harness/deepEqual-circular.js b/test/harness/deepEqual-circular.js new file mode 100644 index 00000000000..d48420f0dbc --- /dev/null +++ b/test/harness/deepEqual-circular.js @@ -0,0 +1,20 @@ +// Copyright 2019 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + values compare correctly with circular references. +includes: [deepEqual.js] +---*/ + +/// +/// + +var a = { x: 1 }; +var b = { x: 1 }; +a.a = a; +a.b = b; +b.a = b; +b.b = a; + +assert.deepEqual(a, b); diff --git a/test/harness/deepEqual-deep.js b/test/harness/deepEqual-deep.js new file mode 100644 index 00000000000..c14829df1f1 --- /dev/null +++ b/test/harness/deepEqual-deep.js @@ -0,0 +1,16 @@ +// Copyright 2019 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + values compare correctly. +includes: [deepEqual.js] +---*/ + +/// +/// + +assert.deepEqual({ a: { x: 1 }, b: [true] }, { a: { x: 1 }, b: [true] }); + +assert.throws(Test262Error, function () { assert.deepEqual({}, { a: { x: 1 }, b: [true] }); }); +assert.throws(Test262Error, function () { assert.deepEqual({ a: { x: 1 }, b: [true] }, { a: { x: 1 }, b: [false] }); }); diff --git a/test/harness/deepEqual-mapset.js b/test/harness/deepEqual-mapset.js new file mode 100644 index 00000000000..1473097ef72 --- /dev/null +++ b/test/harness/deepEqual-mapset.js @@ -0,0 +1,22 @@ +// Copyright 2019 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + map/set values compare correctly. +includes: [deepEqual.js] +---*/ + +/// +/// + +assert.deepEqual(new Set(), new Set()); +assert.deepEqual(new Set([1, "a", true]), new Set([1, "a", true])); +assert.deepEqual(new Map(), new Map()); +assert.deepEqual(new Map([[1, "a"], ["b", true]]), new Map([[1, "a"], ["b", true]])); + +assert.throws(Test262Error, function () { assert.deepEqual(new Set([]), new Set([1])); }); +assert.throws(Test262Error, function () { assert.deepEqual(new Set([1, "a", true]), new Set([1, "a", false])); }); +assert.throws(Test262Error, function () { assert.deepEqual(new Map([]), new Map([[1, "a"], ["b", true]])); }); +assert.throws(Test262Error, function () { assert.deepEqual(new Map([[1, "a"], ["b", true]]), new Map([[1, "a"], ["b", false]])); }); +assert.throws(Test262Error, function () { assert.deepEqual(new Map([[1, "a"], ["b", true]]), new Set([[1, "a"], ["b", false]])); }); diff --git a/test/harness/deepEqual-object.js b/test/harness/deepEqual-object.js new file mode 100644 index 00000000000..0dac2b682e5 --- /dev/null +++ b/test/harness/deepEqual-object.js @@ -0,0 +1,17 @@ +// Copyright 2019 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + object values compare correctly. +includes: [deepEqual.js] +---*/ + +/// +/// + +assert.deepEqual({}, {}); +assert.deepEqual({ a: 1, b: true }, { a: 1, b: true }); + +assert.throws(Test262Error, function () { assert.deepEqual({}, { a: 1, b: true }); }); +assert.throws(Test262Error, function () { assert.deepEqual({ a: 1, b: true }, { a: 1, b: false }); }); diff --git a/test/harness/deepEqual-primitives.js b/test/harness/deepEqual-primitives.js new file mode 100644 index 00000000000..8249d22304c --- /dev/null +++ b/test/harness/deepEqual-primitives.js @@ -0,0 +1,38 @@ +// Copyright 2019 Ron Buckton. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +description: > + primitive values compare correctly. +includes: [deepEqual.js] +---*/ + +/// +/// + +var s1 = Symbol(); +var s2 = Symbol(); +assert.deepEqual(null, null); +assert.deepEqual(undefined, undefined); +assert.deepEqual("a", "a"); +assert.deepEqual(1, 1); +assert.deepEqual(1n, 1n); +assert.deepEqual(true, true); +assert.deepEqual(s1, s1); +assert.deepEqual(Object("a"), "a"); +assert.deepEqual(Object(1), 1); +assert.deepEqual(Object(1n), 1n); +assert.deepEqual(Object(true), true); +assert.deepEqual(Object(s1), s1); + +assert.throws(Test262Error, function () { assert.deepEqual(null, 0); }); +assert.throws(Test262Error, function () { assert.deepEqual(undefined, 0); }); +assert.throws(Test262Error, function () { assert.deepEqual("", 0); }); +assert.throws(Test262Error, function () { assert.deepEqual("1", 1); }); +assert.throws(Test262Error, function () { assert.deepEqual("1", "2"); }); +assert.throws(Test262Error, function () { assert.deepEqual(1n, 1); }); +assert.throws(Test262Error, function () { assert.deepEqual(1n, 2n); }); +assert.throws(Test262Error, function () { assert.deepEqual(true, 1); }); +assert.throws(Test262Error, function () { assert.deepEqual(true, false); }); +assert.throws(Test262Error, function () { assert.deepEqual(s1, "Symbol()"); }); +assert.throws(Test262Error, function () { assert.deepEqual(s1, s2); });