<!DOCTYPE html>
<title>Geometry Interfaces: Serialize and deserialize</title>
<link rel="help" href="https://drafts.fxtf.org/geometry/#structured-serialization">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id=log></div>
<script>
function clone(obj) {
return new Promise((resolve, reject) => {
const channel = new MessageChannel();
channel.port2.onmessage = e => resolve(e.data);
channel.port1.postMessage(obj);
});
}
function defineThrowingGetters(object, attrs) {
for (let attr of attrs) {
Object.defineProperty(object, attr, {
get: () => assert_unreached(`getter for ${attr}`)
});
}
}
[
["DOMPointReadOnly", "x", "y", "z", "w"],
["DOMPoint", "x", "y", "z", "w"],
["DOMRectReadOnly", "x", "y", "width", "height"],
["DOMRect", "x", "y", "width", "height"],
["DOMQuad", "p1", "p2", "p3", "p4"],
["DOMMatrixReadOnly", "a", "b", "c", "d", "e", "f", "m11", "m12", "m13", "m14", "m21", "m22", "m23", "m24", "m31", "m32", "m33", "m34", "m41", "m42", "m43", "m44", "is2D"],
["DOMMatrix", "a", "b", "c", "d", "e", "f", "m11", "m12", "m13", "m14", "m21", "m22", "m23", "m24", "m31", "m32", "m33", "m34", "m41", "m42", "m43", "m44", "is2D"],
].forEach(([constr, ...attrs]) => {
const prefix = `${constr} clone:`;
promise_test(t => {
const object = new self[constr]();
return clone(object).then(other => {
assert_not_equals(object, other);
assert_class_string(other, constr);
for (let attr of attrs) {
if (constr === "DOMQuad") {
assert_not_equals(other[attr], object[attr], attr);
assert_class_string(other[attr], "DOMPoint", attr);
assert_equals(other[attr].x, object.p1.x, `${attr}.x`);
assert_equals(other[attr].y, object.p1.y, `${attr}.y`);
assert_equals(other[attr].z, object.p1.z, `${attr}.z`);
assert_equals(other[attr].w, object.p1.w, `${attr}.w`);
} else {
assert_equals(other[attr], object[attr], attr);
}
}
t.done();
});
}, `${prefix} basic`);
promise_test(t => {
const object = new self[constr]();
object.foo = "bar";
return clone(object).then(other => {
assert_false("foo" in other, 'foo should not exist in other');
t.done();
});
}, `${prefix} custom property`);
promise_test(t => {
const object = new self[constr]();
// The custom throwing getter on object should not be copied to other.
defineThrowingGetters(object, attrs);
return clone(object).then(other => {
for (let attr of attrs) {
// This should call the standard getter, and therefore not throw.
// If this were to call the throwing getter defined on object, the test would fail.
other[attr];
}
t.done();
});
}, `${prefix} throwing getters`);
// More specific tests for each type
switch(constr) {
case "DOMPointReadOnly":
case "DOMPoint":
case "DOMRectReadOnly":
case "DOMRect":
promise_test(t => {
const object = new self[constr](1, -0, Infinity, NaN);
return clone(object).then(other => {
for (let attr of attrs) {
assert_equals(other[attr], object[attr], attr);
}
t.done();
});
}, `${prefix} non-initial values`);
break;
case "DOMQuad":
promise_test(t => {
const object = new self[constr]({x:1, y:2, z:3, w:4},
{x:-0, y:-0, z:-0, w:-0},
{x:Infinity, y:Infinity, z:Infinity, w:Infinity},
{x:NaN, y:NaN, z:NaN, w:NaN});
return clone(object).then(other => {
for (let attr of attrs) {
assert_equals(other[attr].x, object[attr].x, `${attr}.x`);
assert_equals(other[attr].y, object[attr].y, `${attr}.y`);
assert_equals(other[attr].z, object[attr].z, `${attr}.z`);
assert_equals(other[attr].w, object[attr].w, `${attr}.w`);
}
t.done();
});
}, `${prefix} non-initial values`);
break;
case "DOMMatrixReadOnly":
case "DOMMatrix":
promise_test(t => {
const object = new self[constr]([1, -0, Infinity, NaN, 5, 6]);
object.m13 = -0;
object.m14 = -0;
object.m23 = -0;
object.m24 = -0;
object.m31 = -0;
object.m32 = -0;
object.m34 = -0;
object.m43 = -0;
assert_true(object.is2D, 'is2D after setting m13 etc to -0');
return clone(object).then(other => {
for (let attr of attrs) {
if (attr === 'm13' ||
attr === 'm14' ||
attr === 'm23' ||
attr === 'm24' ||
attr === 'm31' ||
attr === 'm32' ||
attr === 'm34' ||
attr === 'm43') {
assert_equals(other[attr], 0, attr);
} else {
assert_equals(other[attr], object[attr], attr);
}
}
t.done();
});
}, `${prefix} non-initial values (2d)`);
promise_test(t => {
const object = new self[constr]([11, -0, Infinity, NaN,
21, 22, 23, 24,
31, 32, 33, 34,
41, 42, 43, 44]);
return clone(object).then(other => {
for (let attr of attrs) {
assert_equals(other[attr], object[attr], attr);
}
t.done();
});
}, `${prefix} non-initial values (3d)`);
break;
default:
throw new Error(`Test bug: ${constr} has no test for non-initial values`);
}
});
promise_test((t) => {
const object = document.getElementById('log').getClientRects();
return promise_rejects_dom(t, "DataCloneError", clone(object));
}, 'DOMRectList clone');0
</script>