зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1770752 - Add support for serialization of complex objects with simple value fields. r=webdriver-reviewers,jdescottes,whimboo
Differential Revision: https://phabricator.services.mozilla.com/D148100
This commit is contained in:
Родитель
19ceef4f7c
Коммит
2794384788
|
@ -98,6 +98,89 @@ function deserialize(serializedValue) {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to serialize as a list.
|
||||
*
|
||||
* @see https://w3c.github.io/webdriver-bidi/#serialize-as-a-list
|
||||
*
|
||||
* @param {Iterable} iterable
|
||||
* List of values to be serialized.
|
||||
*
|
||||
* @param {number=} maxDepth
|
||||
* Depth of a serialization.
|
||||
*
|
||||
* @return {Array} List of serialized values.
|
||||
*/
|
||||
function serializeList(
|
||||
iterable,
|
||||
maxDepth /*,
|
||||
childOwnership,
|
||||
serializationInternalMap,
|
||||
realm*/
|
||||
) {
|
||||
const serialized = [];
|
||||
const childDepth = maxDepth !== null ? maxDepth - 1 : null;
|
||||
|
||||
for (const item of iterable) {
|
||||
serialized.push(
|
||||
serialize(
|
||||
item,
|
||||
childDepth /*, childOwnership, serializationInternalMap, realm*/
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return serialized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to serialize as a mapping.
|
||||
*
|
||||
* @see https://w3c.github.io/webdriver-bidi/#serialize-as-a-mapping
|
||||
*
|
||||
* @param {Iterable} iterable
|
||||
* List of values to be serialized.
|
||||
*
|
||||
* @param {number=} maxDepth
|
||||
* Depth of a serialization.
|
||||
*
|
||||
* @return {Array} List of serialized values.
|
||||
*/
|
||||
function serializeMapping(
|
||||
iterable,
|
||||
maxDepth /*,
|
||||
childOwnership,
|
||||
serializationInternalMap,
|
||||
realm*/
|
||||
) {
|
||||
const serialized = [];
|
||||
const childDepth = maxDepth !== null ? maxDepth - 1 : null;
|
||||
|
||||
for (const [key, item] of iterable) {
|
||||
const serializedKey =
|
||||
typeof key == "string"
|
||||
? key
|
||||
: serialize(
|
||||
key,
|
||||
childDepth /*,
|
||||
childOwnership,
|
||||
serializationInternalMap,
|
||||
realm*/
|
||||
);
|
||||
const serializedValue = serialize(
|
||||
item,
|
||||
childDepth /*,
|
||||
childOwnership,
|
||||
serializationInternalMap,
|
||||
realm*/
|
||||
);
|
||||
|
||||
serialized.push([serializedKey, serializedValue]);
|
||||
}
|
||||
|
||||
return serialized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize a value as a remote value.
|
||||
*
|
||||
|
@ -106,9 +189,18 @@ function deserialize(serializedValue) {
|
|||
* @param {Object} value
|
||||
* Value of any type to be serialized.
|
||||
*
|
||||
* @param {number=} maxDepth
|
||||
* Depth of a serialization.
|
||||
*
|
||||
* @returns {Object} Serialized representation of the value.
|
||||
*/
|
||||
function serialize(value /*, maxDepth, nodeDetails, knownObjects */) {
|
||||
function serialize(
|
||||
value,
|
||||
maxDepth /*,
|
||||
ownershipType,
|
||||
serializationInternalMap,
|
||||
realm */
|
||||
) {
|
||||
const type = typeof value;
|
||||
|
||||
// Primitive protocol values
|
||||
|
@ -130,6 +222,63 @@ function serialize(value /*, maxDepth, nodeDetails, knownObjects */) {
|
|||
return { type, value };
|
||||
}
|
||||
|
||||
lazy.logger.warn(`Unsupported type for remote value: ${value.toString()}`);
|
||||
const className = ChromeUtils.getClassName(value);
|
||||
|
||||
// Remote values
|
||||
if (className == "Array") {
|
||||
const remoteValue = { type: "array" };
|
||||
|
||||
if (maxDepth !== null && maxDepth > 0) {
|
||||
remoteValue.value = serializeList(
|
||||
value,
|
||||
maxDepth /*,
|
||||
ownershipType,
|
||||
serializationInternalMap,
|
||||
realm */
|
||||
);
|
||||
}
|
||||
|
||||
return remoteValue;
|
||||
} else if (className == "RegExp") {
|
||||
return {
|
||||
type: "regexp",
|
||||
value: { pattern: value.source, flags: value.flags },
|
||||
};
|
||||
} else if (className == "Date") {
|
||||
return { type: "date", value: value.toString() };
|
||||
} else if (className == "Map") {
|
||||
const remoteValue = { type: "map" };
|
||||
|
||||
if (maxDepth !== null && maxDepth > 0) {
|
||||
remoteValue.value = serializeMapping(
|
||||
value.entries(),
|
||||
maxDepth /*,
|
||||
ownershipType,
|
||||
serializationInternalMap,
|
||||
realm */
|
||||
);
|
||||
}
|
||||
|
||||
return remoteValue;
|
||||
} else if (className == "Set") {
|
||||
const remoteValue = { type: "set" };
|
||||
|
||||
if (maxDepth !== null && maxDepth > 0) {
|
||||
remoteValue.value = serializeList(
|
||||
value.values(),
|
||||
maxDepth /*,
|
||||
ownershipType,
|
||||
serializationInternalMap,
|
||||
realm */
|
||||
);
|
||||
}
|
||||
|
||||
return remoteValue;
|
||||
}
|
||||
|
||||
lazy.logger.warn(
|
||||
`Unsupported type: ${type} for remote value: ${value.toString()}`
|
||||
);
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,13 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
class MockDate extends Date {}
|
||||
|
||||
// Mock `toString` to avoid timezone differences.
|
||||
MockDate.prototype.toString = function() {
|
||||
return "Tue May 31 2022 15:47:29 GMT+0200 (Central European Summer Time)";
|
||||
};
|
||||
|
||||
const PRIMITIVE_TYPES = [
|
||||
{ value: undefined, serialized: { type: "undefined" } },
|
||||
{ value: null, serialized: { type: "null" } },
|
||||
|
@ -22,6 +29,186 @@ const PRIMITIVE_TYPES = [
|
|||
{ value: 42n, serialized: { type: "bigint", value: "42" } },
|
||||
];
|
||||
|
||||
const REMOTE_SIMPLE_VALUES = [
|
||||
{
|
||||
value: new RegExp(/foo/g),
|
||||
serialized: {
|
||||
type: "regexp",
|
||||
value: {
|
||||
pattern: "foo",
|
||||
flags: "g",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
value: new MockDate(1654004849000),
|
||||
serialized: {
|
||||
type: "date",
|
||||
value: "Tue May 31 2022 15:47:29 GMT+0200 (Central European Summer Time)",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const REMOTE_COMPLEX_VALUES = [
|
||||
{
|
||||
value: [1],
|
||||
serialized: {
|
||||
type: "array",
|
||||
},
|
||||
},
|
||||
{
|
||||
value: [1],
|
||||
maxDepth: 0,
|
||||
serialized: {
|
||||
type: "array",
|
||||
},
|
||||
},
|
||||
{
|
||||
value: [1, "2", true, new RegExp(/foo/g)],
|
||||
maxDepth: 1,
|
||||
serialized: {
|
||||
type: "array",
|
||||
value: [
|
||||
{ type: "number", value: 1 },
|
||||
{ type: "string", value: "2" },
|
||||
{ type: "boolean", value: true },
|
||||
{
|
||||
type: "regexp",
|
||||
value: {
|
||||
pattern: "foo",
|
||||
flags: "g",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
value: [1, [3, "4"]],
|
||||
maxDepth: 1,
|
||||
serialized: {
|
||||
type: "array",
|
||||
value: [{ type: "number", value: 1 }, { type: "array" }],
|
||||
},
|
||||
},
|
||||
{
|
||||
value: [1, [3, "4"]],
|
||||
maxDepth: 2,
|
||||
serialized: {
|
||||
type: "array",
|
||||
value: [
|
||||
{ type: "number", value: 1 },
|
||||
{
|
||||
type: "array",
|
||||
value: [
|
||||
{ type: "number", value: 3 },
|
||||
{ type: "string", value: "4" },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
value: new Map(),
|
||||
maxDepth: 1,
|
||||
serialized: {
|
||||
type: "map",
|
||||
value: [],
|
||||
},
|
||||
},
|
||||
{
|
||||
value: new Map([]),
|
||||
maxDepth: 1,
|
||||
serialized: {
|
||||
type: "map",
|
||||
value: [],
|
||||
},
|
||||
},
|
||||
{
|
||||
value: new Map([
|
||||
[1, 2],
|
||||
["2", "3"],
|
||||
[true, false],
|
||||
]),
|
||||
serialized: {
|
||||
type: "map",
|
||||
},
|
||||
},
|
||||
{
|
||||
value: new Map([
|
||||
[1, 2],
|
||||
["2", "3"],
|
||||
[true, false],
|
||||
]),
|
||||
maxDepth: 0,
|
||||
serialized: {
|
||||
type: "map",
|
||||
},
|
||||
},
|
||||
{
|
||||
value: new Map([
|
||||
[1, 2],
|
||||
["2", "3"],
|
||||
[true, false],
|
||||
]),
|
||||
maxDepth: 1,
|
||||
serialized: {
|
||||
type: "map",
|
||||
value: [
|
||||
[
|
||||
{ type: "number", value: 1 },
|
||||
{ type: "number", value: 2 },
|
||||
],
|
||||
["2", { type: "string", value: "3" }],
|
||||
[
|
||||
{ type: "boolean", value: true },
|
||||
{ type: "boolean", value: false },
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
value: new Set(),
|
||||
maxDepth: 1,
|
||||
serialized: {
|
||||
type: "set",
|
||||
value: [],
|
||||
},
|
||||
},
|
||||
{
|
||||
value: new Set([]),
|
||||
maxDepth: 1,
|
||||
serialized: {
|
||||
type: "set",
|
||||
value: [],
|
||||
},
|
||||
},
|
||||
{
|
||||
value: new Set([1, "2", true]),
|
||||
serialized: {
|
||||
type: "set",
|
||||
},
|
||||
},
|
||||
{
|
||||
value: new Set([1, "2", true]),
|
||||
maxDepth: 0,
|
||||
serialized: {
|
||||
type: "set",
|
||||
},
|
||||
},
|
||||
{
|
||||
value: new Set([1, "2", true]),
|
||||
maxDepth: 1,
|
||||
serialized: {
|
||||
type: "set",
|
||||
value: [
|
||||
{ type: "number", value: 1 },
|
||||
{ type: "string", value: "2" },
|
||||
{ type: "boolean", value: true },
|
||||
],
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const { deserialize, serialize } = ChromeUtils.import(
|
||||
"chrome://remote/content/webdriver-bidi/RemoteValue.jsm"
|
||||
);
|
||||
|
@ -93,3 +280,29 @@ add_test(function test_serializePrimitiveTypes() {
|
|||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_serializeRemoteSimpleValues() {
|
||||
for (const type of REMOTE_SIMPLE_VALUES) {
|
||||
const { value, serialized } = type;
|
||||
|
||||
info(`Checking '${serialized.type}'`);
|
||||
const serializedValue = serialize(value);
|
||||
|
||||
Assert.deepEqual(serialized, serializedValue, "Got expected structure");
|
||||
}
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_serializeRemoteComplexValues() {
|
||||
for (const type of REMOTE_COMPLEX_VALUES) {
|
||||
const { value, serialized, maxDepth } = type;
|
||||
|
||||
info(`Checking '${serialized.type}'`);
|
||||
const serializedValue = serialize(value, maxDepth);
|
||||
|
||||
Assert.deepEqual(serialized, serializedValue, "Got expected structure");
|
||||
}
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
|
Загрузка…
Ссылка в новой задаче