Files
Chris Tate 2b8756077f Adapt property descriptor checks for static Test262 (#553)
* Adapt property descriptor checks for static Test262

* Record preflight baselines for new corpus fixtures
2026-09-28 15:21:34 -05:00

86 lines
3.6 KiB
JavaScript

// Copyright (C) 2017 Ecma International. All rights reserved.
// This adaptation of Test262's propertyHelper.js is governed by the BSD license in vendor/LICENSE.
function propertyLabel(name, options) {
return options && options.label || String(name);
}
function propertyEnumerable(obj, name) {
if (!Object.hasOwn(obj, name)) return false;
if (typeof name !== "string") return Object.getOwnPropertyDescriptor(obj, name).enumerable;
return Object.keys(obj).includes(name);
}
function propertyWritable(obj, name) {
const oldValue = obj[name];
const hadValue = Object.hasOwn(obj, name);
if (Array.isArray(obj) && name === "length") {
try {
obj[name] = 4294967295;
} catch (error) {
if (!(error instanceof TypeError)) throw new Test262Error("Expected TypeError, got " + error);
}
const succeeded = obj[name] === 4294967295;
if (succeeded) obj[name] = oldValue;
return succeeded;
}
const alternate = oldValue === "unlikelyValue";
const newValue = alternate ? "unlikelyValue2" : "unlikelyValue";
try {
obj[name] = newValue;
} catch (error) {
if (!(error instanceof TypeError)) throw new Test262Error("Expected TypeError, got " + error);
}
const succeeded = alternate ? obj[name] === "unlikelyValue2" : obj[name] === "unlikelyValue";
if (succeeded) {
if (hadValue) obj[name] = oldValue;
else delete obj[name];
}
return succeeded;
}
function propertyConfigurable(obj, name) {
try {
delete obj[name];
} catch (error) {
if (!(error instanceof TypeError)) throw new Test262Error("Expected TypeError, got " + error);
}
return !Object.hasOwn(obj, name);
}
function verifyProperty(obj, name, desc, options) {
const label = propertyLabel(name, options);
const original = Object.getOwnPropertyDescriptor(obj, name);
if (desc === undefined) {
assert(original === undefined, label + " descriptor should be undefined");
return true;
}
assert(Object.hasOwn(obj, name), label + " should be an own property");
assert(desc !== null, "The desc argument should be an object or undefined, null");
assert(typeof desc === "object", "The desc argument should be an object or undefined, " + String(desc));
for (const field of Object.keys(desc)) {
assert(["value", "writable", "enumerable", "configurable", "get", "set"].includes(field), "Invalid descriptor field: " + field);
}
if (Object.hasOwn(desc, "value")) {
assert.sameValue(desc.value, original.value, label + " descriptor value should be " + String(desc.value));
assert.sameValue(desc.value, obj[name], label + " value should be " + String(desc.value));
}
if (Object.hasOwn(desc, "enumerable") && desc.enumerable !== undefined) {
const message = label + " descriptor should " + (desc.enumerable ? "" : "not ") + "be enumerable";
assert.sameValue(desc.enumerable, original.enumerable, message);
assert.sameValue(desc.enumerable, propertyEnumerable(obj, name), message);
}
if (Object.hasOwn(desc, "writable") && desc.writable !== undefined) {
const message = label + " descriptor should " + (desc.writable ? "" : "not ") + "be writable";
assert.sameValue(desc.writable, original.writable, message);
assert.sameValue(desc.writable, propertyWritable(obj, name), message);
}
if (Object.hasOwn(desc, "configurable") && desc.configurable !== undefined) {
const message = label + " descriptor should " + (desc.configurable ? "" : "not ") + "be configurable";
assert.sameValue(desc.configurable, original.configurable, message);
assert.sameValue(desc.configurable, propertyConfigurable(obj, name), message);
}
if (options && options.restore) Object.defineProperty(obj, name, original);
return true;
}