mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 23:02:20 +00:00
Bug 1788124 - [bidi] Deserialize remote values with handle field r=webdriver-reviewers,whimboo
Depends on D155446 With this you can retrieve a remote value with a handle from script.execute and then use it in your next call to script.callFunction Differential Revision: https://phabricator.services.mozilla.com/D155522
This commit is contained in:
parent
d3b9951dbf
commit
fb6fa92fdf
@ -145,7 +145,7 @@ function checkDateTimeString(dateString) {
|
||||
* @throws {InvalidArgumentError}
|
||||
* If <var>serializedValueList</var> is not an array.
|
||||
*/
|
||||
function deserializeValueList(/* realm, */ serializedValueList) {
|
||||
function deserializeValueList(realm, serializedValueList) {
|
||||
lazy.assert.array(
|
||||
serializedValueList,
|
||||
`Expected "serializedValueList" to be an array, got ${serializedValueList}`
|
||||
@ -154,7 +154,7 @@ function deserializeValueList(/* realm, */ serializedValueList) {
|
||||
const deserializedValues = [];
|
||||
|
||||
for (const item of serializedValueList) {
|
||||
deserializedValues.push(deserialize(/*realm, */ item));
|
||||
deserializedValues.push(deserialize(realm, item));
|
||||
}
|
||||
|
||||
return deserializedValues;
|
||||
@ -174,7 +174,7 @@ function deserializeValueList(/* realm, */ serializedValueList) {
|
||||
* If <var>serializedKeyValueList</var> is not an array or
|
||||
* not an array of key-value arrays.
|
||||
*/
|
||||
function deserializeKeyValueList(/* realm, */ serializedKeyValueList) {
|
||||
function deserializeKeyValueList(realm, serializedKeyValueList) {
|
||||
lazy.assert.array(
|
||||
serializedKeyValueList,
|
||||
`Expected "serializedKeyValueList" to be an array, got ${serializedKeyValueList}`
|
||||
@ -192,8 +192,8 @@ function deserializeKeyValueList(/* realm, */ serializedKeyValueList) {
|
||||
const deserializedKey =
|
||||
typeof serializedKey == "string"
|
||||
? serializedKey
|
||||
: deserialize(/* realm, */ serializedKey);
|
||||
const deserializedValue = deserialize(/* realm, */ serializedValue);
|
||||
: deserialize(realm, serializedKey);
|
||||
const deserializedValue = deserialize(realm, serializedValue);
|
||||
|
||||
deserializedKeyValueList.push([deserializedKey, deserializedValue]);
|
||||
}
|
||||
@ -211,21 +211,24 @@ function deserializeKeyValueList(/* realm, */ serializedKeyValueList) {
|
||||
*
|
||||
* @return {Object} Deserialized representation of the value.
|
||||
*/
|
||||
function deserialize(/* realm, */ serializedValue) {
|
||||
const { objectId, type, value } = serializedValue;
|
||||
function deserialize(realm, serializedValue) {
|
||||
const { handle, type, value } = serializedValue;
|
||||
|
||||
// With an objectId present deserialize as remote reference.
|
||||
if (objectId !== undefined) {
|
||||
// With a handle present deserialize as remote reference.
|
||||
if (handle !== undefined) {
|
||||
lazy.assert.string(
|
||||
objectId,
|
||||
`Expected "objectId" to be a string, got ${objectId}`
|
||||
handle,
|
||||
`Expected "handle" to be a string, got ${handle}`
|
||||
);
|
||||
|
||||
// TODO: Implement deserialization of remote references (bug 1693838)
|
||||
lazy.logger.warn(
|
||||
`Unsupported type remote reference with objectId ${objectId}`
|
||||
);
|
||||
return undefined;
|
||||
const object = realm.getObjectForHandle(handle);
|
||||
if (!object) {
|
||||
throw new lazy.error.InvalidArgumentError(
|
||||
`Unable to find an object reference for "handle" ${handle}`
|
||||
);
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
lazy.assert.string(type, `Expected "type" to be a string, got ${type}`);
|
||||
@ -276,7 +279,7 @@ function deserialize(/* realm, */ serializedValue) {
|
||||
|
||||
// Non-primitive protocol values
|
||||
case "array":
|
||||
return deserializeValueList(/* realm, */ value);
|
||||
return deserializeValueList(realm, value);
|
||||
case "date":
|
||||
// We want to support only Date Time String format,
|
||||
// check if the value follows it.
|
||||
@ -284,9 +287,9 @@ function deserialize(/* realm, */ serializedValue) {
|
||||
|
||||
return new Date(value);
|
||||
case "map":
|
||||
return new Map(deserializeKeyValueList(value));
|
||||
return new Map(deserializeKeyValueList(realm, value));
|
||||
case "object":
|
||||
return Object.fromEntries(deserializeKeyValueList(value));
|
||||
return Object.fromEntries(deserializeKeyValueList(realm, value));
|
||||
case "regexp":
|
||||
lazy.assert.object(
|
||||
value,
|
||||
@ -311,7 +314,7 @@ function deserialize(/* realm, */ serializedValue) {
|
||||
);
|
||||
}
|
||||
case "set":
|
||||
return new Set(deserializeValueList(/* realm, */ value));
|
||||
return new Set(deserializeValueList(realm, value));
|
||||
}
|
||||
|
||||
lazy.logger.warn(`Unsupported type for local value ${type}`);
|
||||
|
@ -233,15 +233,15 @@ class ScriptModule extends Module {
|
||||
thisParameter = null,
|
||||
} = options;
|
||||
|
||||
const realm = this.#getRealmFromSandboxName(sandboxName);
|
||||
|
||||
const deserializedArguments =
|
||||
commandArguments !== null
|
||||
? commandArguments.map(arg => lazy.deserialize(arg))
|
||||
? commandArguments.map(arg => lazy.deserialize(realm, arg))
|
||||
: [];
|
||||
|
||||
const deserializedThis =
|
||||
thisParameter !== null ? lazy.deserialize(thisParameter) : null;
|
||||
|
||||
const realm = this.#getRealmFromSandboxName(sandboxName);
|
||||
thisParameter !== null ? lazy.deserialize(realm, thisParameter) : null;
|
||||
|
||||
const rv = realm.executeInGlobalWithBindings(
|
||||
functionDeclaration,
|
||||
|
@ -306,11 +306,13 @@ const { deserialize, serialize, stringify } = ChromeUtils.import(
|
||||
);
|
||||
|
||||
add_test(function test_deserializePrimitiveTypes() {
|
||||
const realm = new Realm();
|
||||
|
||||
for (const type of PRIMITIVE_TYPES) {
|
||||
const { value: expectedValue, serialized } = type;
|
||||
|
||||
info(`Checking '${serialized.type}'`);
|
||||
const value = deserialize(serialized);
|
||||
const value = deserialize(realm, serialized);
|
||||
|
||||
if (serialized.value == "NaN") {
|
||||
ok(Number.isNaN(value), `Got expected value for ${serialized}`);
|
||||
@ -327,6 +329,8 @@ add_test(function test_deserializePrimitiveTypes() {
|
||||
});
|
||||
|
||||
add_test(function test_deserializeDateLocalValue() {
|
||||
const realm = new Realm();
|
||||
|
||||
const validaDateStrings = [
|
||||
"2009",
|
||||
"2009-05",
|
||||
@ -344,7 +348,7 @@ add_test(function test_deserializeDateLocalValue() {
|
||||
];
|
||||
for (const dateString of validaDateStrings) {
|
||||
info(`Checking '${dateString}'`);
|
||||
const value = deserialize({ type: "date", value: dateString });
|
||||
const value = deserialize(realm, { type: "date", value: dateString });
|
||||
|
||||
Assert.equal(
|
||||
value.getTime(),
|
||||
@ -357,6 +361,8 @@ add_test(function test_deserializeDateLocalValue() {
|
||||
});
|
||||
|
||||
add_test(function test_deserializeLocalValues() {
|
||||
const realm = new Realm();
|
||||
|
||||
for (const type of REMOTE_SIMPLE_VALUES.concat(REMOTE_COMPLEX_VALUES)) {
|
||||
const { value: expectedValue, serialized, deserializable } = type;
|
||||
|
||||
@ -366,36 +372,53 @@ add_test(function test_deserializeLocalValues() {
|
||||
}
|
||||
|
||||
info(`Checking '${serialized.type}'`);
|
||||
const value = deserialize(serialized);
|
||||
const value = deserialize(realm, serialized);
|
||||
assertLocalValue(serialized.type, value, expectedValue);
|
||||
}
|
||||
|
||||
let formattedValue = value;
|
||||
let formattedExpectedValue = expectedValue;
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
// Format certain types for easier assertion
|
||||
if (serialized.type == "map") {
|
||||
Assert.equal(
|
||||
Object.prototype.toString.call(expectedValue),
|
||||
"[object Map]",
|
||||
"Got expected type Map"
|
||||
);
|
||||
add_test(function test_deserializeLocalValuesByHandle() {
|
||||
// Create two realms, realm1 will be used to serialize values, while realm2
|
||||
// will be used as a reference empty realm without any object reference.
|
||||
const realm1 = new Realm();
|
||||
const realm2 = new Realm();
|
||||
|
||||
formattedValue = Array.from(value.values());
|
||||
formattedExpectedValue = Array.from(expectedValue.values());
|
||||
} else if (serialized.type == "set") {
|
||||
Assert.equal(
|
||||
Object.prototype.toString.call(expectedValue),
|
||||
"[object Set]",
|
||||
"Got expected type Set"
|
||||
);
|
||||
for (const type of REMOTE_SIMPLE_VALUES.concat(REMOTE_COMPLEX_VALUES)) {
|
||||
const { value: expectedValue, serialized } = type;
|
||||
|
||||
formattedValue = Array.from(value);
|
||||
formattedExpectedValue = Array.from(expectedValue);
|
||||
}
|
||||
// No need to skip non-deserializable cases here.
|
||||
|
||||
Assert.deepEqual(
|
||||
formattedValue,
|
||||
formattedExpectedValue,
|
||||
"Got expected structure"
|
||||
info(`Checking '${serialized.type}'`);
|
||||
// Serialize the value once to get a handle.
|
||||
const serializedValue = serialize(
|
||||
expectedValue,
|
||||
0,
|
||||
"root",
|
||||
new Map(),
|
||||
realm1
|
||||
);
|
||||
|
||||
// Create a remote reference containing only the handle.
|
||||
// `deserialize` should not need any other property.
|
||||
const remoteReference = { handle: serializedValue.handle };
|
||||
|
||||
// Check that the remote reference can be deserialized in realm1.
|
||||
const deserializedValue = deserialize(realm1, remoteReference);
|
||||
assertLocalValue(serialized.type, deserializedValue, expectedValue);
|
||||
|
||||
Assert.throws(
|
||||
() => deserialize(realm2, remoteReference),
|
||||
/InvalidArgumentError:/,
|
||||
`Got expected error when using the wrong realm for deserialize`
|
||||
);
|
||||
|
||||
realm1.removeObjectHandle(serializedValue.handle);
|
||||
Assert.throws(
|
||||
() => deserialize(realm1, remoteReference),
|
||||
/InvalidArgumentError:/,
|
||||
`Got expected error when after deleting the object handle`
|
||||
);
|
||||
}
|
||||
|
||||
@ -403,6 +426,8 @@ add_test(function test_deserializeLocalValues() {
|
||||
});
|
||||
|
||||
add_test(function test_deserializePrimitiveTypesInvalidValues() {
|
||||
const realm = new Realm();
|
||||
|
||||
const invalidValues = [
|
||||
{ type: "bigint", values: [undefined, null, false, "foo", [], {}] },
|
||||
{ type: "boolean", values: [undefined, null, 42, "foo", [], {}] },
|
||||
@ -420,7 +445,7 @@ add_test(function test_deserializePrimitiveTypesInvalidValues() {
|
||||
info(`Checking '${type}' with value ${value}`);
|
||||
|
||||
Assert.throws(
|
||||
() => deserialize({ type, value }),
|
||||
() => deserialize(realm, { type, value }),
|
||||
/InvalidArgument/,
|
||||
`Got expected error for type ${type} and value ${value}`
|
||||
);
|
||||
@ -431,6 +456,8 @@ add_test(function test_deserializePrimitiveTypesInvalidValues() {
|
||||
});
|
||||
|
||||
add_test(function test_deserializeDateLocalValueInvalidValues() {
|
||||
const realm = new Realm();
|
||||
|
||||
const invalidaDateStrings = [
|
||||
"10",
|
||||
"20009",
|
||||
@ -471,7 +498,7 @@ add_test(function test_deserializeDateLocalValueInvalidValues() {
|
||||
info(`Checking '${dateString}'`);
|
||||
|
||||
Assert.throws(
|
||||
() => deserialize({ type: "date", value: dateString }),
|
||||
() => deserialize(realm, { type: "date", value: dateString }),
|
||||
/InvalidArgumentError:/,
|
||||
`Got expected error for date string: ${dateString}`
|
||||
);
|
||||
@ -481,19 +508,25 @@ add_test(function test_deserializeDateLocalValueInvalidValues() {
|
||||
});
|
||||
|
||||
add_test(function test_deserializeLocalValuesInvalidType() {
|
||||
const realm = new Realm();
|
||||
|
||||
const invalidTypes = [undefined, null, false, 42, {}];
|
||||
|
||||
for (const invalidType of invalidTypes) {
|
||||
info(`Checking type: '${invalidType}'`);
|
||||
|
||||
Assert.throws(
|
||||
() => deserialize({ type: invalidType }),
|
||||
() => deserialize(realm, { type: invalidType }),
|
||||
/InvalidArgumentError:/,
|
||||
`Got expected error for type ${invalidType}`
|
||||
);
|
||||
|
||||
Assert.throws(
|
||||
() => deserialize({ type: "array", value: [{ type: invalidType }] }),
|
||||
() =>
|
||||
deserialize(realm, {
|
||||
type: "array",
|
||||
value: [{ type: invalidType }],
|
||||
}),
|
||||
/InvalidArgumentError:/,
|
||||
`Got expected error for nested type ${invalidType}`
|
||||
);
|
||||
@ -503,6 +536,8 @@ add_test(function test_deserializeLocalValuesInvalidType() {
|
||||
});
|
||||
|
||||
add_test(function test_deserializeLocalValuesInvalidValues() {
|
||||
const realm = new Realm();
|
||||
|
||||
const invalidValues = [
|
||||
{ type: "array", values: [undefined, null, false, 42, "foo", {}] },
|
||||
{
|
||||
@ -604,7 +639,7 @@ add_test(function test_deserializeLocalValuesInvalidValues() {
|
||||
info(`Checking '${type}' with value ${value}`);
|
||||
|
||||
Assert.throws(
|
||||
() => deserialize({ type, value }),
|
||||
() => deserialize(realm, { type, value }),
|
||||
/InvalidArgumentError:/,
|
||||
`Got expected error for type ${type} and value ${value}`
|
||||
);
|
||||
@ -739,3 +774,35 @@ add_test(function test_stringify() {
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
function assertLocalValue(type, value, expectedValue) {
|
||||
let formattedValue = value;
|
||||
let formattedExpectedValue = expectedValue;
|
||||
|
||||
// Format certain types for easier assertion
|
||||
if (type == "map") {
|
||||
Assert.equal(
|
||||
Object.prototype.toString.call(expectedValue),
|
||||
"[object Map]",
|
||||
"Got expected type Map"
|
||||
);
|
||||
|
||||
formattedValue = Array.from(value.values());
|
||||
formattedExpectedValue = Array.from(expectedValue.values());
|
||||
} else if (type == "set") {
|
||||
Assert.equal(
|
||||
Object.prototype.toString.call(expectedValue),
|
||||
"[object Set]",
|
||||
"Got expected type Set"
|
||||
);
|
||||
|
||||
formattedValue = Array.from(value);
|
||||
formattedExpectedValue = Array.from(expectedValue);
|
||||
}
|
||||
|
||||
Assert.deepEqual(
|
||||
formattedValue,
|
||||
formattedExpectedValue,
|
||||
"Got expected structure"
|
||||
);
|
||||
}
|
||||
|
@ -1,6 +1,3 @@
|
||||
[call_function.py]
|
||||
[test_default_this]
|
||||
expected: FAIL
|
||||
|
||||
[test_remote_value_argument]
|
||||
expected: FAIL
|
||||
|
Loading…
Reference in New Issue
Block a user