зеркало из https://github.com/mozilla/gecko-dev.git
654 строки
15 KiB
HTML
654 строки
15 KiB
HTML
<!DOCTYPE HTML>
|
|
<html>
|
|
<head>
|
|
<title>Test for postMessages cloning/transferring objects</title>
|
|
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
|
</head>
|
|
|
|
<body>
|
|
<input id="fileList" type="file"></input>
|
|
<script type="application/javascript">
|
|
|
|
function setup_tests() {
|
|
SpecialPowers.pushPrefEnv({"set": [["dom.input.dirpicker", true]]}, next);
|
|
}
|
|
|
|
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().toSource(), bProps.sort().toSource(), 'Props match - using toSource()');
|
|
|
|
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.toSource(), b.toSource(), 'Matching using toSource()');
|
|
}
|
|
}
|
|
|
|
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);
|
|
|
|
fileList.getFilesAndDirectories().then(function(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");
|
|
|
|
const wasmTextToBinary = SpecialPowers.unwrap(SpecialPowers.Cu.getJSTestingFunctions().wasmTextToBinary);
|
|
const fooModuleCode = wasmTextToBinary(`(module
|
|
(func $foo (result i32) (i32.const 42))
|
|
(export "foo" $foo)
|
|
)`);
|
|
|
|
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) {
|
|
if (!obj.clonableObjectsEveryWhere) {
|
|
resolve();
|
|
return;
|
|
}
|
|
|
|
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, []).then(function(received) {
|
|
compare(received.data, object.data);
|
|
runClonableTest();
|
|
});
|
|
}
|
|
|
|
runClonableTest();
|
|
})
|
|
|
|
// clonable same process
|
|
.then(function() {
|
|
return new Promise(function(resolve, reject) {
|
|
if (!obj.clonableObjectsSameProcess) {
|
|
resolve();
|
|
return;
|
|
}
|
|
|
|
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, []).then(function(received) {
|
|
compare(received.data, object.data);
|
|
runClonableTest();
|
|
});
|
|
}
|
|
|
|
runClonableTest();
|
|
});
|
|
})
|
|
|
|
// transfering tests
|
|
.then(function() {
|
|
if (!obj.transferableObjects) {
|
|
return;
|
|
}
|
|
|
|
// MessagePort
|
|
return new Promise(function(r, rr) {
|
|
var mc = new MessageChannel();
|
|
obj.send(42, [mc.port1]).then(function(received) {
|
|
ok(received.ports.length, 1, "MessagePort has been transferred");
|
|
mc.port2.postMessage("hello world");
|
|
received.ports[0].onmessage = function(e) {
|
|
ok(e.data, "hello world", "Ports are connected!");
|
|
r();
|
|
}
|
|
});
|
|
});
|
|
})
|
|
|
|
// no dup transfering
|
|
.then(function() {
|
|
if (!obj.transferableObjects) {
|
|
return;
|
|
}
|
|
|
|
// 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);
|
|
});
|
|
})
|
|
|
|
// non transfering tests
|
|
.then(function() {
|
|
if (obj.transferableObjects) {
|
|
return;
|
|
}
|
|
|
|
// 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();
|
|
});
|
|
}
|
|
|
|
// PostMessage to the same window.
|
|
function test_windowToWindow() {
|
|
info("Testing window to window");
|
|
var resolve;
|
|
|
|
onmessage = function(e) {
|
|
if (!resolve) {
|
|
ok(false, "Unexpected message!");
|
|
return;
|
|
}
|
|
|
|
let tmp = resolve;
|
|
resolve = null;
|
|
tmp({ data: e.data, ports: e.ports });
|
|
}
|
|
|
|
runTests({
|
|
clonableObjectsEveryWhere: true,
|
|
clonableObjectsSameProcess: true,
|
|
transferableObjects: true,
|
|
send: function(what, ports) {
|
|
return new Promise(function(r, rr) {
|
|
resolve = r;
|
|
|
|
try {
|
|
postMessage(what, '*', ports);
|
|
} catch(e) {
|
|
resolve = null;
|
|
rr();
|
|
}
|
|
});
|
|
},
|
|
|
|
finished: function() {
|
|
onmessage = null;
|
|
next();
|
|
}
|
|
});
|
|
}
|
|
|
|
// PostMessage to iframe
|
|
function test_windowToIframe() {
|
|
info("Testing window to iframe");
|
|
test_windowToIframeURL('iframe_postMessages.html');
|
|
}
|
|
|
|
// PostMessage to cross-origin iframe
|
|
function test_windowToCrossOriginIframe() {
|
|
info("Testing window to cross-origin iframe");
|
|
test_windowToIframeURL('http://example.com/tests/dom/base/test/iframe_postMessages.html');
|
|
}
|
|
|
|
// iframe helper class
|
|
function test_windowToIframeURL(url) {
|
|
var resolve;
|
|
|
|
onmessage = function(e) {
|
|
if (!resolve) {
|
|
ok(false, "Unexpected message!");
|
|
return;
|
|
}
|
|
|
|
let tmp = resolve;
|
|
resolve = null;
|
|
tmp({ data: e.data, ports: e.ports });
|
|
}
|
|
|
|
var ifr = document.createElement('iframe');
|
|
ifr.src = url;
|
|
ifr.onload = function() {
|
|
runTests({
|
|
clonableObjectsEveryWhere: true,
|
|
clonableObjectsSameProcess: true,
|
|
transferableObjects: true,
|
|
send: function(what, ports) {
|
|
return new Promise(function(r, rr) {
|
|
resolve = r;
|
|
try {
|
|
ifr.contentWindow.postMessage(what, '*', ports);
|
|
} catch(e) {
|
|
resolve = null;
|
|
rr();
|
|
}
|
|
});
|
|
},
|
|
|
|
finished: function() {
|
|
document.body.removeChild(ifr);
|
|
onmessage = null;
|
|
next();
|
|
}
|
|
});
|
|
}
|
|
document.body.appendChild(ifr);
|
|
}
|
|
|
|
// PostMessage for Workers
|
|
function test_workers() {
|
|
info("Testing Workers");
|
|
|
|
var resolve;
|
|
|
|
var w = new Worker('worker_postMessages.js');
|
|
w.postMessage('workers');
|
|
w.onmessage = function(e) {
|
|
is(e.data, 'ok', "Worker ready!");
|
|
|
|
w.onmessage = function(e) {
|
|
if (!resolve) {
|
|
ok(false, "Unexpected message!");
|
|
return;
|
|
}
|
|
|
|
let tmp = resolve;
|
|
resolve = null;
|
|
tmp({ data: e.data, ports: e.ports });
|
|
}
|
|
|
|
runTests({
|
|
clonableObjectsEveryWhere: true,
|
|
clonableObjectsSameProcess: true,
|
|
transferableObjects: true,
|
|
send: function(what, ports) {
|
|
return new Promise(function(r, rr) {
|
|
resolve = r;
|
|
try {
|
|
w.postMessage(what, ports);
|
|
} catch(e) {
|
|
resolve = null;
|
|
rr();
|
|
}
|
|
});
|
|
},
|
|
|
|
finished: function() {
|
|
onmessage = null;
|
|
next();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
// PostMessage for BroadcastChannel
|
|
function test_broadcastChannel() {
|
|
info("Testing broadcastChannel");
|
|
|
|
var bc1 = new BroadcastChannel('postMessagesTest');
|
|
var bc2 = new BroadcastChannel('postMessagesTest');
|
|
|
|
var resolve;
|
|
|
|
bc2.onmessage = function(e) {
|
|
if (!resolve) {
|
|
ok(false, "Unexpected message!");
|
|
return;
|
|
}
|
|
|
|
let tmp = resolve;
|
|
resolve = null;
|
|
tmp({ data: e.data, ports: [] });
|
|
}
|
|
|
|
runTests({
|
|
clonableObjectsEveryWhere: true,
|
|
clonableObjectsSameProcess: false,
|
|
transferableObjects: false,
|
|
send: function(what, ports) {
|
|
return new Promise(function(r, rr) {
|
|
if (ports.length) {
|
|
rr();
|
|
return;
|
|
}
|
|
|
|
resolve = r;
|
|
bc1.postMessage(what);
|
|
});
|
|
},
|
|
|
|
finished: function() {
|
|
onmessage = null;
|
|
next();
|
|
}
|
|
});
|
|
}
|
|
|
|
// PostMessage for BroadcastChannel in workers
|
|
function test_broadcastChannel_inWorkers() {
|
|
info("Testing broadcastChannel in Workers");
|
|
|
|
var bc = new BroadcastChannel('postMessagesTest_inWorkers');
|
|
var resolve;
|
|
|
|
var w = new Worker('worker_postMessages.js');
|
|
w.postMessage('broadcastChannel');
|
|
w.onmessage = function(e) {
|
|
is(e.data, 'ok', "Worker ready!");
|
|
|
|
w.onmessage = function(e) {
|
|
if (!resolve) {
|
|
ok(false, "Unexpected message!");
|
|
return;
|
|
}
|
|
|
|
let tmp = resolve;
|
|
resolve = null;
|
|
tmp({ data: e.data, ports: e.ports });
|
|
}
|
|
|
|
runTests({
|
|
clonableObjectsEveryWhere: true,
|
|
clonableObjectsSameProcess: false,
|
|
transferableObjects: false,
|
|
send: function(what, ports) {
|
|
return new Promise(function(r, rr) {
|
|
if (ports.length) {
|
|
rr();
|
|
return;
|
|
}
|
|
|
|
resolve = r;
|
|
bc.postMessage(what);
|
|
});
|
|
},
|
|
|
|
finished: function() {
|
|
onmessage = null;
|
|
next();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
// PostMessage for MessagePort
|
|
function test_messagePort() {
|
|
info("Testing messagePort");
|
|
|
|
var mc = new MessageChannel();
|
|
var resolve;
|
|
|
|
mc.port2.onmessage = function(e) {
|
|
if (!resolve) {
|
|
ok(false, "Unexpected message!");
|
|
return;
|
|
}
|
|
|
|
let tmp = resolve;
|
|
resolve = null;
|
|
tmp({ data: e.data, ports: e.ports });
|
|
}
|
|
|
|
runTests({
|
|
clonableObjectsEveryWhere: true,
|
|
clonableObjectsSameProcess: false,
|
|
transferableObjects: true,
|
|
send: function(what, ports) {
|
|
return new Promise(function(r, rr) {
|
|
resolve = r;
|
|
try {
|
|
mc.port1.postMessage(what, ports);
|
|
} catch(e) {
|
|
resolve = null;
|
|
rr();
|
|
}
|
|
});
|
|
},
|
|
|
|
finished: function() {
|
|
onmessage = null;
|
|
next();
|
|
}
|
|
});
|
|
}
|
|
|
|
// PostMessage for MessagePort in Workers
|
|
function test_messagePort_inWorkers() {
|
|
info("Testing messagePort in workers");
|
|
|
|
var mc = new MessageChannel();
|
|
var resolve;
|
|
|
|
var w = new Worker('worker_postMessages.js');
|
|
w.postMessage('messagePort', [ mc.port2 ]);
|
|
w.onmessage = function(e) {
|
|
is(e.data, 'ok', "Worker ready!");
|
|
|
|
w.onmessage = function(e) {
|
|
if (!resolve) {
|
|
ok(false, "Unexpected message!");
|
|
return;
|
|
}
|
|
|
|
let tmp = resolve;
|
|
resolve = null;
|
|
tmp({ data: e.data, ports: e.ports });
|
|
}
|
|
|
|
runTests({
|
|
clonableObjectsEveryWhere: true,
|
|
clonableObjectsSameProcess: false,
|
|
transferableObjects: true,
|
|
send: function(what, ports) {
|
|
return new Promise(function(r, rr) {
|
|
resolve = r;
|
|
try {
|
|
mc.port1.postMessage(what, ports);
|
|
} catch(e) {
|
|
resolve = null;
|
|
rr();
|
|
}
|
|
});
|
|
},
|
|
|
|
finished: function() {
|
|
onmessage = null;
|
|
next();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
var tests = [
|
|
setup_tests,
|
|
|
|
create_fileList,
|
|
create_directory,
|
|
create_wasmModule,
|
|
|
|
test_windowToWindow,
|
|
test_windowToIframe,
|
|
test_windowToCrossOriginIframe,
|
|
|
|
test_workers,
|
|
|
|
test_broadcastChannel,
|
|
test_broadcastChannel_inWorkers,
|
|
|
|
test_messagePort,
|
|
test_messagePort_inWorkers,
|
|
];
|
|
|
|
function next() {
|
|
if (!tests.length) {
|
|
SimpleTest.finish();
|
|
return;
|
|
}
|
|
|
|
var test = tests.shift();
|
|
test();
|
|
}
|
|
|
|
SimpleTest.waitForExplicitFinish();
|
|
next();
|
|
</script>
|
|
</body>
|
|
</html>
|