Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions third_party/test262/harness/assert.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/*---
description: |
Collection of assertion functions used throughout test262
defines: [assert]
defines: [assert, isPrimitive]
---*/


Expand Down Expand Up @@ -113,15 +113,15 @@ assert.compareArray = function (actual, expected, message) {
}

if (isPrimitive(actual)) {
assert(false, `Actual argument [${actual}] shouldn't be primitive. ${message}`);
assert(false, "Actual argument [" + actual + "] shouldn't be primitive. " + String(message));
} else if (isPrimitive(expected)) {
assert(false, `Expected argument [${expected}] shouldn't be primitive. ${message}`);
assert(false, "Expected argument [" + expected + "] shouldn't be primitive. " + String(message));
}
var result = compareArray(actual, expected);
if (result) return;

var format = compareArray.format;
assert(false, `Actual ${format(actual)} and expected ${format(expected)} should have the same contents. ${message}`);
assert(false, "Actual " + format(actual) + " and expected " + format(expected) + " should have the same contents. " + String(message));
};

function compareArray(a, b) {
Expand All @@ -137,15 +137,15 @@ function compareArray(a, b) {
}

compareArray.format = function (arrayLike) {
return `[${Array.prototype.map.call(arrayLike, String).join(', ')}]`;
return "[" + Array.prototype.map.call(arrayLike, String).join(", ") + "]";
};

assert._formatIdentityFreeValue = function formatIdentityFreeValue(value) {
switch (value === null ? 'null' : typeof value) {
case 'string':
return typeof JSON !== "undefined" ? JSON.stringify(value) : `"${value}"`;
return typeof JSON !== "undefined" ? JSON.stringify(value) : '"' + value + '"';
case 'bigint':
return `${value}n`;
return String(value) + "n";
case 'number':
if (value === 0 && 1 / value === -Infinity) return '-0';
// falls through
Expand Down
181 changes: 160 additions & 21 deletions third_party/test262/harness/propertyHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ description: |
defines:
- verifyProperty
- verifyCallableProperty
- verifyAccessorProperty
- verifyEqualTo # deprecated
- verifyWritable # deprecated
- verifyNotWritable # deprecated
Expand All @@ -16,6 +17,7 @@ defines:
- verifyNotConfigurable # deprecated
- verifyPrimordialProperty
- verifyPrimordialCallableProperty
- verifyPrimordialAccessorProperty
---*/

// @ts-check
Expand All @@ -37,33 +39,31 @@ var nonIndexNumericPropertyName = Math.pow(2, 32) - 1;
* @param {string|symbol} name
* @param {PropertyDescriptor|undefined} desc
* @param {object} [options]
* @param {boolean} [options.label]
* @param {boolean} [options.restore] revert mutations from verifying writable/configurable
*/
function verifyProperty(obj, name, desc, options) {
assert(
arguments.length > 2,
'verifyProperty should receive at least 3 arguments: obj, name, and descriptor'
);
var label = options && options.label || String(name);

var originalDesc = __getOwnPropertyDescriptor(obj, name);
var nameStr = String(name);

// Allows checking for undefined descriptor if it's explicitly given.
if (desc === undefined) {
assert.sameValue(
originalDesc,
undefined,
"obj['" + nameStr + "'] descriptor should be undefined"
label + " descriptor should be undefined"
);

// desc and originalDesc are both undefined, problem solved;
return true;
}

assert(
__hasOwnProperty(obj, name),
"obj should have an own property " + nameStr
);
assert(__hasOwnProperty(obj, name), label + " should be an own property");

assert.notSameValue(
desc,
Expand All @@ -86,25 +86,25 @@ function verifyProperty(obj, name, desc, options) {
names[i] === "configurable" ||
names[i] === "get" ||
names[i] === "set",
"Invalid descriptor field: " + names[i],
"Invalid descriptor field: " + names[i]
);
}

var failures = [];

if (__hasOwnProperty(desc, 'value')) {
if (!isSameValue(desc.value, originalDesc.value)) {
__push(failures, "obj['" + nameStr + "'] descriptor value should be " + desc.value);
__push(failures, label + " descriptor value should be " + String(desc.value));
}
if (!isSameValue(desc.value, obj[name])) {
__push(failures, "obj['" + nameStr + "'] value should be " + desc.value);
__push(failures, label + " value should be " + String(desc.value));
}
}

if (__hasOwnProperty(desc, 'enumerable') && desc.enumerable !== undefined) {
if (desc.enumerable !== originalDesc.enumerable ||
desc.enumerable !== isEnumerable(obj, name)) {
__push(failures, "obj['" + nameStr + "'] descriptor should " + (desc.enumerable ? '' : 'not ') + "be enumerable");
__push(failures, label + " descriptor should " + (desc.enumerable ? '' : 'not ') + "be enumerable");
}
}

Expand All @@ -113,14 +113,14 @@ function verifyProperty(obj, name, desc, options) {
if (__hasOwnProperty(desc, 'writable') && desc.writable !== undefined) {
if (desc.writable !== originalDesc.writable ||
desc.writable !== isWritable(obj, name)) {
__push(failures, "obj['" + nameStr + "'] descriptor should " + (desc.writable ? '' : 'not ') + "be writable");
__push(failures, label + " descriptor should " + (desc.writable ? '' : 'not ') + "be writable");
}
}

if (__hasOwnProperty(desc, 'configurable') && desc.configurable !== undefined) {
if (desc.configurable !== originalDesc.configurable ||
desc.configurable !== isConfigurable(obj, name)) {
__push(failures, "obj['" + nameStr + "'] descriptor should " + (desc.configurable ? '' : 'not ') + "be configurable");
__push(failures, label + " descriptor should " + (desc.configurable ? '' : 'not ') + "be configurable");
}
}

Expand Down Expand Up @@ -219,13 +219,17 @@ function isWritable(obj, name, verifyProp, value) {
* @param {number} functionLength
* @param {PropertyDescriptor} [desc] defaults to data property conventions (writable, non-enumerable, configurable)
* @param {object} [options]
* @param {boolean} [options.label]
* @param {typeof verifyProperty} [options.verifyProperty]
* @param {boolean} [options.restore] revert mutations from verifying writable/configurable
*/
function verifyCallableProperty(obj, name, functionName, functionLength, desc, options) {
var value = obj[name];
var label = options && options.label || String(name);
var propertyVerifier = options && options.verifyProperty || verifyProperty;

var value = obj && obj[name];

assert.sameValue(typeof value, "function",
"obj['" + String(name) + "'] descriptor should be a function");
assert.sameValue(typeof value, "function", label + " should be a function");

// Every other data property described in clauses 19 through 28 and in
// Annex B.2 has the attributes { [[Writable]]: true, [[Enumerable]]: false,
Expand All @@ -242,7 +246,7 @@ function verifyCallableProperty(obj, name, functionName, functionLength, desc, o
desc.value = value;
}

verifyProperty(obj, name, desc, options);
propertyVerifier(obj, name, desc, options);

if (functionName === undefined) {
if (typeof name === "symbol") {
Expand All @@ -256,24 +260,125 @@ function verifyCallableProperty(obj, name, functionName, functionLength, desc, o
// [[Configurable]]: true }.
// https://tc39.es/ecma262/multipage/ecmascript-standard-built-in-objects.html#sec-ecmascript-standard-built-in-objects
// https://tc39.es/ecma262/multipage/ordinary-and-exotic-objects-behaviours.html#sec-setfunctionname
verifyProperty(value, "name", {
propertyVerifier(value, "name", {
value: functionName,
writable: false,
enumerable: false,
configurable: desc.configurable
}, options);
}, { label: label + " name", restore: options && options.restore });

// Unless otherwise specified, the "length" property of a built-in function
// object has the attributes { [[Writable]]: false, [[Enumerable]]: false,
// [[Configurable]]: true }.
// https://tc39.es/ecma262/multipage/ecmascript-standard-built-in-objects.html#sec-ecmascript-standard-built-in-objects
// https://tc39.es/ecma262/multipage/ordinary-and-exotic-objects-behaviours.html#sec-setfunctionlength
verifyProperty(value, "length", {
propertyVerifier(value, "length", {
value: functionLength,
writable: false,
enumerable: false,
configurable: desc.configurable
}, options);
}, { label: label + " length", restore: options && options.restore });
}

/**
* Verify that there is an accessor property associated with `obj[name]` and
* following the conventions for built-in objects.
*
* @param {object} obj
* @param {string|symbol} name
* @param {object} desc
* @param {boolean} [desc.enumerable] defaults to accessor property conventions (non-enumerable)
* @param {boolean} [desc.configurable] defaults to accessor property conventions (configurable)
* @param {undefined | Function | {name?: string|symbol, length?: number}} [desc.get] if an object,
* absent fields default to getter conventions (name derived from the property key with a "get "
* prefix, length 0)
* @param {undefined | Function | {name?: string|symbol, length?: number}} [desc.set] if an object,
* absent fields default to getter conventions (name derived from the property key with a "set "
* prefix, length 1)
* @param {object} [options]
* @param {boolean} [options.label]
* @param {typeof verifyProperty} [options.verifyProperty]
* @param {typeof verifyCallableProperty} [options.verifyCallableProperty]
* @param {boolean} [options.restore] revert mutations from verifying property attributes
*/
function verifyAccessorProperty(obj, name, desc, options) {
var checkGet = __hasOwnProperty(desc, "get");
var checkSet = __hasOwnProperty(desc, "set");
assert(
checkGet || checkSet,
'verifyAccessorProperty requires at least one of "get" and "set"'
);
var label = options && options.label || String(name);
var propertyVerifier = options && options.verifyProperty || verifyProperty;
var callabilityVerifier = options && options.verifyCallableProperty || verifyCallableProperty;

var originalDesc = __getOwnPropertyDescriptor(obj, name);

// Every built-in function object, including constructors, has a "name"
// property whose value is a String. Unless otherwise specified, this value is
// the name that is given to the function in this specification. Functions
// that are identified as anonymous functions use the empty String as the
// value of the "name" property. For functions that are specified as
// properties of objects, the name value is the property name string used to
// access the function. Functions that are specified as get or set accessor
// functions of built-in properties have "get" or "set" (respectively) passed
// to the prefix parameter when calling CreateBuiltinFunction.
//
// The value of the "name" property is explicitly specified for each built-in
// functions whose property key is a Symbol value. If such an explicitly
// specified value starts with the prefix "get " or "set " and the function
// for which it is specified is a get or set accessor function of a built-in
// property, the value without the prefix is passed to the name parameter, and
// the value "get" or "set" (respectively) is passed to the prefix parameter
// when calling CreateBuiltinFunction.
// https://tc39.es/ecma262/multipage/ecmascript-standard-built-in-objects.html
if (checkGet) {
var expectGetter = desc.get;
var getterLabel = label + " getter";
if (expectGetter === undefined || typeof expectGetter === "function") {
assert.sameValue(originalDesc.get, expectGetter, getterLabel);
} else {
var getterName = expectGetter.name;
if (getterName === undefined) {
getterName = "get " + (typeof name === "symbol" ? "[" + name.description + "]" : name);
}
var getterLength = expectGetter.length !== undefined ? expectGetter.length : 0;
var getterOptions = { label: getterLabel };
callabilityVerifier(originalDesc, "get", getterName, getterLength, {}, getterOptions);
}
}
if (checkSet) {
var expectSetter = desc.set;
var setterLabel = label + " setter";
if (expectSetter === undefined || typeof expectSetter === "function") {
assert.sameValue(originalDesc.set, expectSetter, setterLabel);
} else {
var setterName = expectSetter.name;
if (setterName === undefined) {
setterName = "set " + (typeof name === "symbol" ? "[" + name.description + "]" : name);
}
var setterLength = expectSetter.length !== undefined ? expectSetter.length : 1;
var setterOptions = { label: setterLabel };
callabilityVerifier(originalDesc, "set", setterName, setterLength, {}, setterOptions);
}
}

// Every accessor property described in clauses 19 through 28 and in Annex B.2
// has the attributes { [[Enumerable]]: false, [[Configurable]]: true } unless
// otherwise specified.
// https://tc39.es/ecma262/multipage/ecmascript-standard-built-in-objects.html
var resolvedDesc = { get: originalDesc.get, set: originalDesc.set };
if (!__hasOwnProperty(desc, "enumerable")) {
resolvedDesc.enumerable = false;
} else if (desc.enumerable !== undefined) {
resolvedDesc.enumerable = desc.enumerable;
}
if (!__hasOwnProperty(desc, "configurable")) {
resolvedDesc.configurable = true;
} else if (desc.configurable !== undefined) {
resolvedDesc.configurable = desc.configurable;
}
propertyVerifier(obj, name, resolvedDesc, options);
}

/**
Expand Down Expand Up @@ -367,5 +472,39 @@ var verifyPrimordialProperty = verifyProperty;
* Use this function to verify the primordial function-valued properties.
* For non-primordial functions, use verifyCallableProperty.
* See: https://github.com/tc39/how-we-work/blob/main/terminology.md#primordial
*
* @type {typeof verifyCallableProperty}
*/
var verifyPrimordialCallableProperty = verifyCallableProperty;
function verifyPrimordialCallableProperty(obj, name, functionName, functionLength, desc, options) {
var resolvedOptions = {
verifyProperty: options && options.verifyProperty !== undefined
? options.verifyProperty
: verifyPrimordialProperty
};
if (options && options.label !== undefined) resolvedOptions.label = options.label;
if (options && options.restore !== undefined) resolvedOptions.restore = options.restore;

return verifyCallableProperty(obj, name, functionName, functionLength, desc, resolvedOptions);
}

/**
* Use this function to verify the primordial accessor properties.
* For non-primordial functions, use verifyAccessorProperty.
* See: https://github.com/tc39/how-we-work/blob/main/terminology.md#primordial
*
* @type {typeof verifyAccessorProperty}
*/
function verifyPrimordialAccessorProperty(obj, name, desc, options) {
var resolvedOptions = {
verifyProperty: options && options.verifyProperty !== undefined
? options.verifyProperty
: verifyPrimordialProperty,
verifyCallableProperty: options && options.verifyCallableProperty !== undefined
? options.verifyCallableProperty
: verifyPrimordialCallableProperty
};
if (options && options.label !== undefined) resolvedOptions.label = options.label;
if (options && options.restore !== undefined) resolvedOptions.restore = options.restore;

return verifyAccessorProperty(obj, name, desc, resolvedOptions);
}
Loading