mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 23:31:56 +00:00
acb960676c
Differential Revision: https://phabricator.services.mozilla.com/D66128 --HG-- extra : moz-landing-system : lando
389 lines
10 KiB
JavaScript
389 lines
10 KiB
JavaScript
/* Any copyright is dedicated to the Public Domain.
|
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
/* eslint-disable no-shadow, max-nested-callbacks */
|
|
|
|
"use strict";
|
|
|
|
// Test that onEnumProperties returns the expected data
|
|
// when passing `ignoreNonIndexedProperties` and `ignoreIndexedProperties` options
|
|
// with various objects. (See Bug 1403065)
|
|
|
|
const DO_NOT_CHECK_VALUE = Symbol();
|
|
|
|
Services.prefs.setBoolPref("security.allow_eval_with_system_principal", true);
|
|
registerCleanupFunction(() => {
|
|
Services.prefs.clearUserPref("security.allow_eval_with_system_principal");
|
|
});
|
|
|
|
add_task(
|
|
threadFrontTest(async ({ threadFront, debuggee, client }) => {
|
|
debuggee.eval(
|
|
function stopMe(arg1) {
|
|
debugger;
|
|
}.toString()
|
|
);
|
|
|
|
const testCases = [
|
|
{
|
|
evaledObject: { a: 10 },
|
|
expectedIndexedProperties: [],
|
|
expectedNonIndexedProperties: [["a", 10]],
|
|
},
|
|
{
|
|
evaledObject: { length: 10 },
|
|
expectedIndexedProperties: [],
|
|
expectedNonIndexedProperties: [["length", 10]],
|
|
},
|
|
{
|
|
evaledObject: { a: 10, 0: "indexed" },
|
|
expectedIndexedProperties: [["0", "indexed"]],
|
|
expectedNonIndexedProperties: [["a", 10]],
|
|
},
|
|
{
|
|
evaledObject: { 1: 1, length: 42, a: 10 },
|
|
expectedIndexedProperties: [["1", 1]],
|
|
expectedNonIndexedProperties: [
|
|
["length", 42],
|
|
["a", 10],
|
|
],
|
|
},
|
|
{
|
|
evaledObject: { 1: 1, length: 2.34, a: 10 },
|
|
expectedIndexedProperties: [["1", 1]],
|
|
expectedNonIndexedProperties: [
|
|
["length", 2.34],
|
|
["a", 10],
|
|
],
|
|
},
|
|
{
|
|
evaledObject: { 1: 1, length: -0, a: 10 },
|
|
expectedIndexedProperties: [["1", 1]],
|
|
expectedNonIndexedProperties: [
|
|
["length", -0],
|
|
["a", 10],
|
|
],
|
|
},
|
|
{
|
|
evaledObject: { 1: 1, length: -10, a: 10 },
|
|
expectedIndexedProperties: [["1", 1]],
|
|
expectedNonIndexedProperties: [
|
|
["length", -10],
|
|
["a", 10],
|
|
],
|
|
},
|
|
{
|
|
evaledObject: { 1: 1, length: true, a: 10 },
|
|
expectedIndexedProperties: [["1", 1]],
|
|
expectedNonIndexedProperties: [
|
|
["length", true],
|
|
["a", 10],
|
|
],
|
|
},
|
|
{
|
|
evaledObject: { 1: 1, length: null, a: 10 },
|
|
expectedIndexedProperties: [["1", 1]],
|
|
expectedNonIndexedProperties: [
|
|
["length", DO_NOT_CHECK_VALUE],
|
|
["a", 10],
|
|
],
|
|
},
|
|
{
|
|
evaledObject: { 1: 1, length: Math.pow(2, 53), a: 10 },
|
|
expectedIndexedProperties: [["1", 1]],
|
|
expectedNonIndexedProperties: [
|
|
["length", 9007199254740992],
|
|
["a", 10],
|
|
],
|
|
},
|
|
{
|
|
evaledObject: { 1: 1, length: "fake", a: 10 },
|
|
expectedIndexedProperties: [["1", 1]],
|
|
expectedNonIndexedProperties: [
|
|
["length", "fake"],
|
|
["a", 10],
|
|
],
|
|
},
|
|
{
|
|
evaledObject: { 1: 1, length: Infinity, a: 10 },
|
|
expectedIndexedProperties: [["1", 1]],
|
|
expectedNonIndexedProperties: [
|
|
["length", DO_NOT_CHECK_VALUE],
|
|
["a", 10],
|
|
],
|
|
},
|
|
{
|
|
evaledObject: { 0: 0, length: 0 },
|
|
expectedIndexedProperties: [["0", 0]],
|
|
expectedNonIndexedProperties: [["length", 0]],
|
|
},
|
|
{
|
|
evaledObject: { 0: 0, 1: 1, length: 1 },
|
|
expectedIndexedProperties: [
|
|
["0", 0],
|
|
["1", 1],
|
|
],
|
|
expectedNonIndexedProperties: [["length", 1]],
|
|
},
|
|
{
|
|
evaledObject: { length: 0 },
|
|
expectedIndexedProperties: [],
|
|
expectedNonIndexedProperties: [["length", 0]],
|
|
},
|
|
{
|
|
evaledObject: { 1: 1 },
|
|
expectedIndexedProperties: [["1", 1]],
|
|
expectedNonIndexedProperties: [],
|
|
},
|
|
{
|
|
evaledObject: { a: 1, [2 ** 32 - 2]: 2, [2 ** 32 - 1]: 3 },
|
|
expectedIndexedProperties: [["4294967294", 2]],
|
|
expectedNonIndexedProperties: [
|
|
["a", 1],
|
|
["4294967295", 3],
|
|
],
|
|
},
|
|
{
|
|
evaledObject: `(() => {
|
|
x = [12, 42];
|
|
x.foo = 90;
|
|
return x;
|
|
})()`,
|
|
expectedIndexedProperties: [
|
|
["0", 12],
|
|
["1", 42],
|
|
],
|
|
expectedNonIndexedProperties: [
|
|
["length", 2],
|
|
["foo", 90],
|
|
],
|
|
},
|
|
{
|
|
evaledObject: `(() => {
|
|
x = [12, 42];
|
|
x.length = 3;
|
|
return x;
|
|
})()`,
|
|
expectedIndexedProperties: [
|
|
["0", 12],
|
|
["1", 42],
|
|
["2", undefined],
|
|
],
|
|
expectedNonIndexedProperties: [["length", 3]],
|
|
},
|
|
{
|
|
evaledObject: `(() => {
|
|
x = [12, 42];
|
|
x.length = 1;
|
|
return x;
|
|
})()`,
|
|
expectedIndexedProperties: [["0", 12]],
|
|
expectedNonIndexedProperties: [["length", 1]],
|
|
},
|
|
{
|
|
evaledObject: `(() => {
|
|
x = [, 42,,];
|
|
x.foo = 90;
|
|
return x;
|
|
})()`,
|
|
expectedIndexedProperties: [
|
|
["0", undefined],
|
|
["1", 42],
|
|
["2", undefined],
|
|
],
|
|
expectedNonIndexedProperties: [
|
|
["length", 3],
|
|
["foo", 90],
|
|
],
|
|
},
|
|
{
|
|
evaledObject: `(() => {
|
|
x = Array(2);
|
|
x.foo = "bar";
|
|
x.bar = "foo";
|
|
return x;
|
|
})()`,
|
|
expectedIndexedProperties: [
|
|
["0", undefined],
|
|
["1", undefined],
|
|
],
|
|
expectedNonIndexedProperties: [
|
|
["length", 2],
|
|
["foo", "bar"],
|
|
["bar", "foo"],
|
|
],
|
|
},
|
|
{
|
|
evaledObject: `(() => {
|
|
x = new Int8Array(new ArrayBuffer(2));
|
|
x.foo = "bar";
|
|
x.bar = "foo";
|
|
return x;
|
|
})()`,
|
|
expectedIndexedProperties: [
|
|
["0", 0],
|
|
["1", 0],
|
|
],
|
|
expectedNonIndexedProperties: [
|
|
["foo", "bar"],
|
|
["bar", "foo"],
|
|
["length", 2],
|
|
["buffer", DO_NOT_CHECK_VALUE],
|
|
["byteLength", 2],
|
|
["byteOffset", 0],
|
|
],
|
|
},
|
|
{
|
|
evaledObject: `(() => {
|
|
x = new Int8Array([1, 2]);
|
|
Object.defineProperty(x, 'length', {value: 0});
|
|
return x;
|
|
})()`,
|
|
expectedIndexedProperties: [
|
|
["0", 1],
|
|
["1", 2],
|
|
],
|
|
expectedNonIndexedProperties: [
|
|
["length", 0],
|
|
["buffer", DO_NOT_CHECK_VALUE],
|
|
["byteLength", 2],
|
|
["byteOffset", 0],
|
|
],
|
|
},
|
|
{
|
|
evaledObject: `(() => {
|
|
x = new Int32Array([1, 2]);
|
|
Object.setPrototypeOf(x, null);
|
|
return x;
|
|
})()`,
|
|
expectedIndexedProperties: [
|
|
["0", 1],
|
|
["1", 2],
|
|
],
|
|
expectedNonIndexedProperties: [],
|
|
},
|
|
{
|
|
evaledObject: `(() => {
|
|
return new (class extends Int8Array {})([1, 2]);
|
|
})()`,
|
|
expectedIndexedProperties: [
|
|
["0", 1],
|
|
["1", 2],
|
|
],
|
|
expectedNonIndexedProperties: [
|
|
["length", 2],
|
|
["buffer", DO_NOT_CHECK_VALUE],
|
|
["byteLength", 2],
|
|
["byteOffset", 0],
|
|
],
|
|
},
|
|
];
|
|
|
|
for (const test of testCases) {
|
|
await test_object_grip(debuggee, client, threadFront, test);
|
|
}
|
|
})
|
|
);
|
|
|
|
async function test_object_grip(
|
|
debuggee,
|
|
dbgClient,
|
|
threadFront,
|
|
testData = {}
|
|
) {
|
|
const {
|
|
evaledObject,
|
|
expectedIndexedProperties,
|
|
expectedNonIndexedProperties,
|
|
} = testData;
|
|
|
|
const packet = await executeOnNextTickAndWaitForPause(eval_code, threadFront);
|
|
|
|
const [grip] = packet.frame.arguments;
|
|
|
|
const objClient = threadFront.pauseGrip(grip);
|
|
|
|
info(`
|
|
Check enumProperties response for
|
|
${
|
|
typeof evaledObject === "string"
|
|
? evaledObject
|
|
: JSON.stringify(evaledObject)
|
|
}
|
|
`);
|
|
|
|
// Checks the result of enumProperties.
|
|
let response = await objClient.enumProperties({
|
|
ignoreNonIndexedProperties: true,
|
|
});
|
|
await check_enum_properties(response, expectedIndexedProperties);
|
|
|
|
response = await objClient.enumProperties({
|
|
ignoreIndexedProperties: true,
|
|
});
|
|
await check_enum_properties(response, expectedNonIndexedProperties);
|
|
|
|
await threadFront.resume();
|
|
|
|
function eval_code() {
|
|
// Be sure to run debuggee code in its own HTML 'task', so that when we call
|
|
// the onDebuggerStatement hook, the test's own microtasks don't get suspended
|
|
// along with the debuggee's.
|
|
do_timeout(0, () => {
|
|
debuggee.eval(`
|
|
stopMe(${
|
|
typeof evaledObject === "string"
|
|
? evaledObject
|
|
: JSON.stringify(evaledObject)
|
|
});
|
|
`);
|
|
});
|
|
}
|
|
}
|
|
|
|
async function check_enum_properties(iterator, expected = []) {
|
|
equal(
|
|
iterator.count,
|
|
expected.length,
|
|
"iterator.count has the expected value"
|
|
);
|
|
|
|
info("Check iterator.slice response for all properties");
|
|
const sliceResponse = await iterator.slice(0, iterator.count);
|
|
ok(
|
|
sliceResponse &&
|
|
Object.getOwnPropertyNames(sliceResponse).includes("ownProperties"),
|
|
"The response object has an ownProperties property"
|
|
);
|
|
|
|
const { ownProperties } = sliceResponse;
|
|
const names = Object.getOwnPropertyNames(ownProperties);
|
|
equal(
|
|
names.length,
|
|
expected.length,
|
|
"The response has the expected number of properties"
|
|
);
|
|
for (let i = 0; i < names.length; i++) {
|
|
const name = names[i];
|
|
const [key, value] = expected[i];
|
|
equal(name, key, "Property has the expected name");
|
|
const property = ownProperties[name];
|
|
|
|
if (value === DO_NOT_CHECK_VALUE) {
|
|
return;
|
|
}
|
|
|
|
if (value === undefined) {
|
|
equal(
|
|
property,
|
|
undefined,
|
|
`Response has no value for the "${key}" property`
|
|
);
|
|
} else {
|
|
const propValue = property.hasOwnProperty("value")
|
|
? property.value
|
|
: property.getterValue;
|
|
equal(propValue, value, `Property "${key}" has the expected value`);
|
|
}
|
|
}
|
|
}
|