diff options
Diffstat (limited to 'devtools/server/tests/xpcshell/test_objectgrips-20.js')
-rw-r--r-- | devtools/server/tests/xpcshell/test_objectgrips-20.js | 388 |
1 files changed, 388 insertions, 0 deletions
diff --git a/devtools/server/tests/xpcshell/test_objectgrips-20.js b/devtools/server/tests/xpcshell/test_objectgrips-20.js new file mode 100644 index 0000000000..5188bea40d --- /dev/null +++ b/devtools/server/tests/xpcshell/test_objectgrips-20.js @@ -0,0 +1,388 @@ +/* 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`); + } + } +} |