mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-31 14:15:30 +00:00
493 lines
16 KiB
XML
493 lines
16 KiB
XML
<?xml version="1.0"?>
|
|
<!--
|
|
Any copyright is dedicated to the Public Domain.
|
|
http://creativecommons.org/publicdomain/zero/1.0/
|
|
-->
|
|
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
|
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
|
|
|
|
<window title="DOMRequestHelper Test"
|
|
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
|
onload="start();">
|
|
<title>DOMRequestHelper Test</title>
|
|
|
|
<script type="application/javascript"
|
|
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
|
|
|
<script type="application/javascript">
|
|
<![CDATA[
|
|
const Cc = Components.classes;
|
|
const Cu = Components.utils;
|
|
const Ci = Components.interfaces;
|
|
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
|
|
let obs = Cc["@mozilla.org/observer-service;1"].
|
|
getService(Ci.nsIObserverService);
|
|
|
|
function DummyHelperSubclass() {
|
|
this.onuninit = null;
|
|
}
|
|
DummyHelperSubclass.prototype = {
|
|
__proto__: DOMRequestIpcHelper.prototype,
|
|
uninit: function() {
|
|
if (typeof this.onuninit === "function") {
|
|
this.onuninit();
|
|
}
|
|
this.onuninit = null;
|
|
}
|
|
};
|
|
|
|
var dummy = new DummyHelperSubclass();
|
|
|
|
/**
|
|
* Init & destroy.
|
|
*/
|
|
function initDOMRequestHelperTest(aMessages) {
|
|
is(dummy._requests, undefined, "Request is undefined");
|
|
is(dummy._messages, undefined, "Messages is undefined");
|
|
is(dummy._window, undefined, "Window is undefined");
|
|
|
|
dummy.initDOMRequestHelper(window, aMessages);
|
|
|
|
ok(dummy._window, "Window exists");
|
|
is(dummy._window, window, "Correct window");
|
|
if (aMessages) {
|
|
is(typeof dummy._listeners, "object", "Listeners is an object");
|
|
}
|
|
}
|
|
|
|
function destroyDOMRequestHelperTest() {
|
|
dummy.destroyDOMRequestHelper();
|
|
|
|
is(dummy._requests, undefined, "Request is undefined");
|
|
is(dummy._messages, undefined, "Messages is undefined");
|
|
is(dummy._window, undefined, "Window is undefined");
|
|
}
|
|
|
|
/**
|
|
* Message listeners.
|
|
*/
|
|
function checkMessageListeners(aExpectedListeners, aCount) {
|
|
ok(true, "Checking message listeners\n" + "Expected listeners " +
|
|
JSON.stringify(aExpectedListeners) + " \nExpected count " + aCount);
|
|
let count = 0;
|
|
Object.keys(dummy._listeners).forEach(function(name) {
|
|
count++;
|
|
is(aExpectedListeners[name], dummy._listeners[name],
|
|
"Message found " + name + " - Same listeners");
|
|
});
|
|
is(aCount, count, "Correct number of listeners");
|
|
}
|
|
|
|
function addMessageListenersTest(aMessages, aExpectedListeners, aCount) {
|
|
dummy.addMessageListeners(aMessages);
|
|
ok(true, JSON.stringify(dummy._listeners));
|
|
checkMessageListeners(aExpectedListeners, aCount);
|
|
}
|
|
|
|
function removeMessageListenersTest(aMessages, aExpectedListeners, aCount) {
|
|
dummy.removeMessageListeners(aMessages);
|
|
checkMessageListeners(aExpectedListeners, aCount);
|
|
}
|
|
|
|
/**
|
|
* Utility function to test window destruction behavior. In general this
|
|
* function does the following:
|
|
*
|
|
* 1) Create a new iframe
|
|
* 2) Create a new DOMRequestHelper
|
|
* 3) initDOMRequestHelper(), optionally with weak or strong listeners
|
|
* 4) Optionally force a garbage collection to reap weak references
|
|
* 5) Destroy the iframe triggering an inner-window-destroyed event
|
|
* 6) Callback with a boolean indicating if DOMRequestHelper.uninit() was
|
|
* called.
|
|
*
|
|
* Example usage:
|
|
*
|
|
* checkWindowDestruction({ messages: ["foo"], gc: true },
|
|
* function(uninitCalled) {
|
|
* // expect uninitCalled === false since GC with only weak refs
|
|
* });
|
|
*/
|
|
const TOPIC = "inner-window-destroyed";
|
|
function checkWindowDestruction(aOptions, aCallback) {
|
|
aOptions = aOptions || {};
|
|
aOptions.messages = aOptions.messages || [];
|
|
aOptions.gc = !!aOptions.gc;
|
|
|
|
if (typeof aCallback !== "function") {
|
|
aCallback = function() { };
|
|
}
|
|
|
|
let uninitCalled = false;
|
|
|
|
// Use a secondary observer so we know when to expect the uninit(). We
|
|
// can then reasonably expect uninitCalled to be set properly on the
|
|
// next tick.
|
|
let observer = {
|
|
observe: function(aSubject, aTopic, aData) {
|
|
if (aTopic !== TOPIC) {
|
|
return;
|
|
}
|
|
obs.removeObserver(observer, TOPIC);
|
|
setTimeout(function() {
|
|
aCallback(uninitCalled);
|
|
});
|
|
}
|
|
};
|
|
|
|
let frame = document.createElement("iframe");
|
|
frame.onload = function() {
|
|
obs.addObserver(observer, TOPIC, false);
|
|
// Create dummy DOMRequestHelper specific to checkWindowDestruction()
|
|
let cwdDummy = new DummyHelperSubclass();
|
|
cwdDummy.onuninit = function() {
|
|
uninitCalled = true;
|
|
};
|
|
cwdDummy.initDOMRequestHelper(frame.contentWindow, aOptions.messages);
|
|
// Make sure to clear our strong ref here so that we can test our
|
|
// weak reference listeners and observer.
|
|
cwdDummy = null;
|
|
if (aOptions.gc) {
|
|
Cu.schedulePreciseGC(function() {
|
|
SpecialPowers.DOMWindowUtils.cycleCollect();
|
|
SpecialPowers.DOMWindowUtils.garbageCollect();
|
|
SpecialPowers.DOMWindowUtils.garbageCollect();
|
|
document.documentElement.removeChild(frame);
|
|
});
|
|
return;
|
|
}
|
|
document.documentElement.removeChild(frame);
|
|
};
|
|
document.documentElement.appendChild(frame);
|
|
}
|
|
|
|
/**
|
|
* Test steps.
|
|
*/
|
|
var tests = [
|
|
function() {
|
|
ok(true, "== InitDOMRequestHelper no messages");
|
|
initDOMRequestHelperTest(null);
|
|
next();
|
|
},
|
|
function() {
|
|
ok(true, "== DestroyDOMRequestHelper");
|
|
destroyDOMRequestHelperTest();
|
|
next();
|
|
},
|
|
function() {
|
|
ok(true, "== InitDOMRequestHelper empty array");
|
|
initDOMRequestHelperTest([]);
|
|
checkMessageListeners({}, 0);
|
|
next();
|
|
},
|
|
function() {
|
|
ok(true, "== DestroyDOMRequestHelper");
|
|
destroyDOMRequestHelperTest();
|
|
next();
|
|
},
|
|
function() {
|
|
ok(true, "== InitDOMRequestHelper with strings array");
|
|
initDOMRequestHelperTest(["name1", "nameN"]);
|
|
checkMessageListeners({"name1": false, "nameN": false}, 2);
|
|
next();
|
|
},
|
|
function() {
|
|
ok(true, "== DestroyDOMRequestHelper");
|
|
destroyDOMRequestHelperTest();
|
|
next();
|
|
},
|
|
function() {
|
|
ok(true, "== InitDOMRequestHelper with objects array");
|
|
initDOMRequestHelperTest([{
|
|
name: "name1",
|
|
weakRef: false
|
|
}, {
|
|
name: "nameN",
|
|
weakRef: true
|
|
}]);
|
|
checkMessageListeners({"name1": false, "nameN": true}, 2);
|
|
next();
|
|
},
|
|
function() {
|
|
ok(true, "== AddMessageListeners empty array");
|
|
addMessageListenersTest([], {"name1": false, "nameN": true}, 2);
|
|
next();
|
|
},
|
|
function() {
|
|
ok(true, "== AddMessageListeners null");
|
|
addMessageListenersTest(null, {"name1": false, "nameN": true}, 2);
|
|
next();
|
|
},
|
|
function() {
|
|
ok(true, "== AddMessageListeners new listener, string only");
|
|
addMessageListenersTest("name2", {
|
|
"name1": false,
|
|
"name2": false,
|
|
"nameN": true
|
|
}, 3);
|
|
next();
|
|
},
|
|
function() {
|
|
ok(true, "== AddMessageListeners new listeners, strings array");
|
|
addMessageListenersTest(["name3", "name4"], {
|
|
"name1": false,
|
|
"name2": false,
|
|
"name3": false,
|
|
"name4": false,
|
|
"nameN": true
|
|
}, 5);
|
|
next();
|
|
},
|
|
function() {
|
|
ok(true, "== AddMessageListeners new listeners, objects array");
|
|
addMessageListenersTest([{
|
|
name: "name5",
|
|
weakRef: true
|
|
}, {
|
|
name: "name6",
|
|
weakRef: false
|
|
}], {
|
|
"name1": false,
|
|
"name2": false,
|
|
"name3": false,
|
|
"name4": false,
|
|
"name5": true,
|
|
"name6": false,
|
|
"nameN": true
|
|
}, 7);
|
|
next();
|
|
},
|
|
function() {
|
|
ok(true, "== RemoveMessageListeners, null");
|
|
removeMessageListenersTest(null, {
|
|
"name1": false,
|
|
"name2": false,
|
|
"name3": false,
|
|
"name4": false,
|
|
"name5": true,
|
|
"name6": false,
|
|
"nameN": true
|
|
}, 7);
|
|
next();
|
|
},
|
|
function() {
|
|
ok(true, "== RemoveMessageListeners, one message");
|
|
removeMessageListenersTest("name1", {
|
|
"name2": false,
|
|
"name3": false,
|
|
"name4": false,
|
|
"name5": true,
|
|
"name6": false,
|
|
"nameN": true
|
|
}, 6);
|
|
next();
|
|
},
|
|
function() {
|
|
ok(true, "== RemoveMessageListeners, array of messages");
|
|
removeMessageListenersTest(["name2", "name3"], {
|
|
"name4": false,
|
|
"name5": true,
|
|
"name6": false,
|
|
"nameN": true
|
|
}, 4);
|
|
next();
|
|
},
|
|
function() {
|
|
ok(true, "== RemoveMessageListeners, unknown message");
|
|
removeMessageListenersTest("unknown", {
|
|
"name4": false,
|
|
"name5": true,
|
|
"name6": false,
|
|
"nameN": true
|
|
}, 4);
|
|
next();
|
|
},
|
|
function() {
|
|
try {
|
|
ok(true, "== AddMessageListeners, same message, same kind");
|
|
addMessageListenersTest("name4", {
|
|
"name4": false,
|
|
"name5": true,
|
|
"name6": false,
|
|
"nameN": true
|
|
}, 4);
|
|
next();
|
|
} catch (ex) {
|
|
ok(false, "Unexpected exception " + ex);
|
|
}
|
|
},
|
|
function() {
|
|
ok(true, "== AddMessageListeners, same message, different kind");
|
|
try {
|
|
addMessageListenersTest({name: "name4", weakRef: true}, {
|
|
"name4": true,
|
|
"name5": true,
|
|
"name6": false,
|
|
"nameN": true
|
|
}, 4);
|
|
ok(false, "Should have thrown an exception");
|
|
} catch (ex) {
|
|
ok(true, "Expected exception");
|
|
next();
|
|
}
|
|
},
|
|
function() {
|
|
ok(true, "== Test createRequest()");
|
|
ok(DOMRequest, "DOMRequest object exists");
|
|
var req = dummy.createRequest();
|
|
ok(req instanceof DOMRequest, "Returned a DOMRequest");
|
|
next();
|
|
},
|
|
function() {
|
|
ok(true, "== Test getRequestId(), removeRequest() and getRequest()");
|
|
var req = dummy.createRequest();
|
|
var id = dummy.getRequestId(req);
|
|
is(typeof id, "string", "id is a string");
|
|
var req_ = dummy.getRequest(id);
|
|
is(req, req_, "Got correct request");
|
|
dummy.removeRequest(id);
|
|
req = dummy.getRequest(id);
|
|
is(req, null, "No request");
|
|
next();
|
|
},
|
|
function() {
|
|
ok(true, "== Test createPromise()");
|
|
ok(Promise, "Promise object exists");
|
|
var promise = dummy.createPromise(function(resolve, reject) {
|
|
resolve(true);
|
|
});
|
|
ok(promise instanceof Promise, "Returned a Promise");
|
|
promise.then(next);
|
|
},
|
|
function() {
|
|
ok(true, "== Test getResolver()");
|
|
var id;
|
|
var resolver;
|
|
var promise = dummy.createPromise(function(resolve, reject) {
|
|
var r = { resolve: resolve, reject: reject };
|
|
id = dummy.getPromiseResolverId(r);
|
|
resolver = r;
|
|
ok(typeof id === "string", "id is a string");
|
|
r.resolve(true);
|
|
}).then(function(unused) {
|
|
var r = dummy.getPromiseResolver(id);
|
|
ok(resolver === r, "Get succeeded");
|
|
next();
|
|
});
|
|
},
|
|
function() {
|
|
ok(true, "== Test removeResolver");
|
|
var id;
|
|
var promise = dummy.createPromise(function(resolve, reject) {
|
|
var r = { resolve: resolve, reject: reject };
|
|
id = dummy.getPromiseResolverId(r);
|
|
ok(typeof id === "string", "id is a string");
|
|
|
|
var resolver = dummy.getPromiseResolver(id);
|
|
ok(true, "Got resolver " + JSON.stringify(resolver));
|
|
ok(resolver === r, "Resolver get succeeded");
|
|
|
|
r.resolve(true);
|
|
}).then(function(unused) {
|
|
dummy.removePromiseResolver(id);
|
|
var resolver = dummy.getPromiseResolver(id);
|
|
ok(resolver === undefined, "removeResolver: get failed");
|
|
next();
|
|
});
|
|
},
|
|
function() {
|
|
ok(true, "== Test takeResolver");
|
|
var id;
|
|
var resolver;
|
|
var promise = dummy.createPromise(function(resolve, reject) {
|
|
var r = { resolve: resolve, reject: reject };
|
|
id = dummy.getPromiseResolverId(r);
|
|
resolver = r;
|
|
ok(typeof id === "string", "id is a string");
|
|
|
|
var gotR = dummy.getPromiseResolver(id);
|
|
ok(gotR === r, "resolver get succeeded");
|
|
|
|
r.resolve(true);
|
|
}).then(function(unused) {
|
|
var r = dummy.takePromiseResolver(id);
|
|
ok(resolver === r, "take should succeed");
|
|
|
|
r = dummy.getPromiseResolver(id);
|
|
ok(r === undefined, "takeResolver: get failed");
|
|
next();
|
|
});
|
|
},
|
|
function() {
|
|
ok(true, "== Test window destroyed without messages and without GC");
|
|
checkWindowDestruction({ gc: false }, function(uninitCalled) {
|
|
ok(uninitCalled, "uninit() should have been called");
|
|
next();
|
|
});
|
|
},
|
|
function() {
|
|
ok(true, "== Test window destroyed without messages and with GC");
|
|
checkWindowDestruction({ gc: true }, function(uninitCalled) {
|
|
ok(!uninitCalled, "uninit() should NOT have been called");
|
|
next();
|
|
});
|
|
},
|
|
function() {
|
|
ok(true, "== Test window destroyed with weak messages and without GC");
|
|
checkWindowDestruction({ messages: [{ name: "foo", weakRef: true }],
|
|
gc: false }, function(uninitCalled) {
|
|
ok(uninitCalled, "uninit() should have been called");
|
|
next();
|
|
});
|
|
},
|
|
function() {
|
|
ok(true, "== Test window destroyed with weak messages and with GC");
|
|
checkWindowDestruction({ messages: [{ name: "foo", weakRef: true }],
|
|
gc: true }, function(uninitCalled) {
|
|
ok(!uninitCalled, "uninit() should NOT have been called");
|
|
next();
|
|
});
|
|
},
|
|
function() {
|
|
ok(true, "== Test window destroyed with strong messages and without GC");
|
|
checkWindowDestruction({ messages: [{ name: "foo", weakRef: false }],
|
|
gc: false }, function(uninitCalled) {
|
|
ok(uninitCalled, "uninit() should have been called");
|
|
next();
|
|
});
|
|
},
|
|
function() {
|
|
ok(true, "== Test window destroyed with strong messages and with GC");
|
|
checkWindowDestruction({ messages: [{ name: "foo", weakRef: false }],
|
|
gc: true }, function(uninitCalled) {
|
|
ok(uninitCalled, "uninit() should have been called");
|
|
next();
|
|
});
|
|
}
|
|
];
|
|
|
|
function next() {
|
|
if (!tests.length) {
|
|
SimpleTest.finish();
|
|
return;
|
|
}
|
|
|
|
var test = tests.shift();
|
|
test();
|
|
}
|
|
|
|
function start() {
|
|
SimpleTest.waitForExplicitFinish();
|
|
next();
|
|
}
|
|
]]>
|
|
</script>
|
|
|
|
<body xmlns="http://www.w3.org/1999/xhtml">
|
|
<p id="display"></p>
|
|
<div id="content" style="display: none"></div>
|
|
<pre id="test"></pre>
|
|
</body>
|
|
</window>
|