Source code

Revision control

Copy as Markdown

Other Tools

/* eslint-disable mozilla/no-comparison-or-assignment-inside-ok */
function getType(a) {
if (a === null || a === undefined) {
return "null";
}
if (Array.isArray(a)) {
return "array";
}
if (typeof a == "object") {
return "object";
}
if (
SpecialPowers.Cu.getJSTestingFunctions().wasmIsSupported() &&
a instanceof WebAssembly.Module
) {
return "wasm";
}
return "primitive";
}
function compare(a, b) {
is(getType(a), getType(b), "Type matches");
var type = getType(a);
if (type == "array") {
is(a.length, b.length, "Array.length matches");
for (var i = 0; i < a.length; ++i) {
compare(a[i], b[i]);
}
return;
}
if (type == "object") {
ok(a !== b, "They should not match");
var aProps = [];
for (var p in a) {
aProps.push(p);
}
var bProps = [];
for (var p in b) {
bProps.push(p);
}
is(aProps.length, bProps.length, "Props match");
is(aProps.sort().toString(), bProps.sort().toString(), "Props names match");
for (var p in a) {
compare(a[p], b[p]);
}
return;
}
if (type == "wasm") {
var wasmA = new WebAssembly.Instance(a);
ok(wasmA instanceof WebAssembly.Instance, "got an instance");
var wasmB = new WebAssembly.Instance(b);
ok(wasmB instanceof WebAssembly.Instance, "got an instance");
ok(wasmA.exports.foo() === wasmB.exports.foo(), "Same result!");
ok(wasmB.exports.foo() === 42, "We want 42");
}
if (type != "null") {
is(a, b, "Same value");
}
}
var clonableObjects = [
{ target: "all", data: "hello world" },
{ target: "all", data: 123 },
{ target: "all", data: null },
{ target: "all", data: true },
{ target: "all", data: new Date() },
{ target: "all", data: [1, "test", true, new Date()] },
{
target: "all",
data: { a: true, b: null, c: new Date(), d: [true, false, {}] },
},
{ target: "all", data: new Blob([123], { type: "plain/text" }) },
{ target: "all", data: new ImageData(2, 2) },
];
function create_fileList() {
var url = SimpleTest.getTestFileURL("script_postmessages_fileList.js");
var script = SpecialPowers.loadChromeScript(url);
function onOpened(message) {
var fileList = document.getElementById("fileList");
SpecialPowers.wrap(fileList).mozSetFileArray([message.file]);
// Just a simple test
var domFile = fileList.files[0];
is(domFile.name, "prefs.js", "fileName should be prefs.js");
clonableObjects.push({ target: "all", data: fileList.files });
script.destroy();
next();
}
script.addMessageListener("file.opened", onOpened);
script.sendAsyncMessage("file.open");
}
function create_directory() {
if (navigator.userAgent.toLowerCase().includes("Android")) {
next();
return;
}
var url = SimpleTest.getTestFileURL("script_postmessages_fileList.js");
var script = SpecialPowers.loadChromeScript(url);
function onOpened(message) {
var fileList = document.getElementById("fileList");
SpecialPowers.wrap(fileList).mozSetDirectory(message.dir);
SpecialPowers.wrap(fileList)
.getFilesAndDirectories()
.then(function (list) {
list = SpecialPowers.unwrap(list);
// Just a simple test
is(list.length, 1, "This list has 1 element");
ok(list[0] instanceof Directory, "We have a directory.");
clonableObjects.push({ target: "all", data: list[0] });
script.destroy();
next();
});
}
script.addMessageListener("dir.opened", onOpened);
script.sendAsyncMessage("dir.open");
}
function create_wasmModule() {
info("Checking if we can play with WebAssembly...");
if (!SpecialPowers.Cu.getJSTestingFunctions().wasmIsSupported()) {
next();
return;
}
ok(WebAssembly, "WebAssembly object should exist");
ok(WebAssembly.compile, "WebAssembly.compile function should exist");
/*
js -e '
t = wasmTextToBinary(`
(module
(func $foo (result i32) (i32.const 42))
(export "foo" (func $foo))
)
`);
print(t)
'
*/
// prettier-ignore
const fooModuleCode = new Uint8Array([0,97,115,109,1,0,0,0,1,5,1,96,0,1,127,3,2,1,0,7,7,1,3,102,111,111,0,0,10,6,1,4,0,65,42,11,0,13,4,110,97,109,101,1,6,1,0,3,102,111,111]);
WebAssembly.compile(fooModuleCode).then(
m => {
ok(m instanceof WebAssembly.Module, "The WasmModule has been compiled.");
clonableObjects.push({ target: "sameProcess", data: m });
next();
},
() => {
ok(false, "The compilation of the wasmModule failed.");
}
);
}
function runTests(obj) {
ok(
"clonableObjectsEveryWhere" in obj &&
"clonableObjectsSameProcess" in obj &&
"transferableObjects" in obj &&
(obj.clonableObjectsEveryWhere ||
obj.clonableObjectsSameProcess ||
obj.transferableObjects),
"We must run some test!"
);
// cloning tests - everyWhere
new Promise(function (resolve, reject) {
var clonableObjectsId = 0;
function runClonableTest() {
if (clonableObjectsId >= clonableObjects.length) {
resolve();
return;
}
var object = clonableObjects[clonableObjectsId++];
if (object.target != "all") {
runClonableTest();
return;
}
obj
.send(object.data, [])
.catch(() => {
return { error: true };
})
.then(received => {
if (!obj.clonableObjectsEveryWhere) {
ok(received.error, "Error expected");
} else {
ok(!received.error, "Error not expected");
compare(received.data, object.data);
}
runClonableTest();
});
}
runClonableTest();
})
// clonable same process
.then(function () {
return new Promise(function (resolve, reject) {
var clonableObjectsId = 0;
function runClonableTest() {
if (clonableObjectsId >= clonableObjects.length) {
resolve();
return;
}
var object = clonableObjects[clonableObjectsId++];
if (object.target != "sameProcess") {
runClonableTest();
return;
}
obj
.send(object.data, [])
.catch(() => {
return { error: true };
})
.then(received => {
if (!obj.clonableObjectsSameProcess) {
ok(received.error, "Error expected");
} else {
ok(!received.error, "Error not expected");
compare(received.data, object.data);
}
runClonableTest();
});
}
runClonableTest();
});
})
// transfering tests
.then(function () {
if (!obj.transferableObjects) {
return Promise.resolve();
}
// MessagePort
return new Promise(function (r, rr) {
var mc = new MessageChannel();
obj.send(42, [mc.port1]).then(function (received) {
is(received.ports.length, 1, "MessagePort has been transferred");
mc.port2.postMessage("hello world");
received.ports[0].onmessage = function (e) {
is(e.data, "hello world", "Ports are connected!");
r();
};
});
});
})
// no dup transfering
.then(function () {
if (!obj.transferableObjects) {
return Promise.resolve();
}
// MessagePort
return new Promise(function (r, rr) {
var mc = new MessageChannel();
obj
.send(42, [mc.port1, mc.port1])
.then(
function (received) {
ok(false, "Duplicate ports should throw!");
},
function () {
ok(true, "Duplicate ports should throw!");
}
)
.then(r);
});
})
// maintaining order of transferred ports
.then(function () {
if (!obj.transferableObjects) {
return Promise.resolve();
}
// MessagePort
return new Promise(function (r, rr) {
var mcs = [];
const NPORTS = 50;
for (let i = 0; i < NPORTS; i++) {
mcs.push(new MessageChannel());
}
obj
.send(
42,
mcs.map(channel => channel.port1)
)
.then(function (received) {
is(
received.ports.length,
NPORTS,
`all ${NPORTS} ports transferred`
);
const promises = Array(NPORTS)
.fill()
.map(
(_, i) =>
new Promise(function (subr, subrr) {
mcs[i].port2.postMessage(i);
received.ports[i].onmessage = e => subr(e.data == i);
})
);
return Promise.all(promises);
})
.then(function (result) {
let in_order = 0;
for (const correct of result) {
if (correct) {
in_order++;
}
}
is(in_order, NPORTS, "All transferred ports are in order");
})
.then(r);
});
})
// non transfering tests
.then(function () {
if (obj.transferableObjects) {
return Promise.resolve();
}
// MessagePort
return new Promise(function (r, rr) {
var mc = new MessageChannel();
obj
.send(42, [mc.port1])
.then(
function (received) {
ok(false, "This object should not support port transferring");
},
function () {
ok(true, "This object should not support port transferring");
}
)
.then(r);
});
})
// done.
.then(function () {
obj.finished();
});
}
function next() {
if (!tests.length) {
SimpleTest.finish();
return;
}
var test = tests.shift();
test();
}
var tests = [create_fileList, create_directory, create_wasmModule];