summaryrefslogtreecommitdiffstats
path: root/devtools/server/tests/xpcshell/test_objectgrips-20.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/server/tests/xpcshell/test_objectgrips-20.js')
-rw-r--r--devtools/server/tests/xpcshell/test_objectgrips-20.js387
1 files changed, 387 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..5027ca31a7
--- /dev/null
+++ b/devtools/server/tests/xpcshell/test_objectgrips-20.js
@@ -0,0 +1,387 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"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`);
+ }
+ }
+}