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:
Alexandra Borovova 2022-06-13 14:26:56 +00:00
Родитель 19ceef4f7c
Коммит 2794384788
2 изменённых файлов: 364 добавлений и 2 удалений

Просмотреть файл

@ -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();
});