mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-26 19:55:39 +00:00
452dc60022
We did an automated conversion for many of these in another bug, but these instances were either missed or have been added since then.
625 lines
15 KiB
JavaScript
625 lines
15 KiB
JavaScript
/**
|
|
* Any copyright is dedicated to the Public Domain.
|
|
* http://creativecommons.org/publicdomain/zero/1.0/
|
|
*/
|
|
|
|
// testSteps is expected to be defined by the test using this file.
|
|
/* global testSteps:false */
|
|
|
|
var testGenerator = testSteps();
|
|
// The test js is shared between xpcshell (which has no SpecialPowers object)
|
|
// and content mochitests (where the |Components| object is accessible only as
|
|
// SpecialPowers.Components). Expose Components if necessary here to make things
|
|
// work everywhere.
|
|
//
|
|
// Even if the real |Components| doesn't exist, we might shim in a simple JS
|
|
// placebo for compat. An easy way to differentiate this from the real thing
|
|
// is whether the property is read-only or not.
|
|
var c = Object.getOwnPropertyDescriptor(this, "Components");
|
|
if ((!c.value || c.writable) && typeof SpecialPowers === "object") {
|
|
// eslint-disable-next-line no-native-reassign
|
|
Components = SpecialPowers.Components;
|
|
}
|
|
|
|
function executeSoon(aFun)
|
|
{
|
|
let comp = SpecialPowers.wrap(Components);
|
|
|
|
let tm = comp.classes["@mozilla.org/thread-manager;1"]
|
|
.getService(comp.interfaces.nsIThreadManager);
|
|
|
|
tm.dispatchToMainThread({
|
|
run() {
|
|
aFun();
|
|
}
|
|
});
|
|
}
|
|
|
|
function clearAllDatabases(callback) {
|
|
let qms = SpecialPowers.Services.qms;
|
|
let principal = SpecialPowers.wrap(document).nodePrincipal;
|
|
let request = qms.clearStoragesForPrincipal(principal);
|
|
let cb = SpecialPowers.wrapCallback(callback);
|
|
request.callback = cb;
|
|
}
|
|
|
|
var testHarnessGenerator = testHarnessSteps();
|
|
testHarnessGenerator.next();
|
|
|
|
function* testHarnessSteps() {
|
|
function nextTestHarnessStep(val) {
|
|
testHarnessGenerator.next(val);
|
|
}
|
|
|
|
let testScriptPath;
|
|
let testScriptFilename;
|
|
|
|
let scripts = document.getElementsByTagName("script");
|
|
for (let i = 0; i < scripts.length; i++) {
|
|
let src = scripts[i].src;
|
|
let match = src.match(/indexedDB\/test\/unit\/(test_[^\/]+\.js)$/);
|
|
if (match && match.length == 2) {
|
|
testScriptPath = src;
|
|
testScriptFilename = match[1];
|
|
break;
|
|
}
|
|
}
|
|
|
|
yield undefined;
|
|
|
|
info("Running" +
|
|
(testScriptFilename ? " '" + testScriptFilename + "'" : ""));
|
|
|
|
info("Pushing preferences");
|
|
|
|
SpecialPowers.pushPrefEnv(
|
|
{
|
|
"set": [
|
|
["dom.indexedDB.testing", true],
|
|
["dom.indexedDB.experimental", true],
|
|
]
|
|
},
|
|
nextTestHarnessStep
|
|
);
|
|
yield undefined;
|
|
|
|
info("Pushing permissions");
|
|
|
|
SpecialPowers.pushPermissions(
|
|
[
|
|
{
|
|
type: "indexedDB",
|
|
allow: true,
|
|
context: document
|
|
}
|
|
],
|
|
nextTestHarnessStep
|
|
);
|
|
yield undefined;
|
|
|
|
info("Clearing old databases");
|
|
|
|
clearAllDatabases(nextTestHarnessStep);
|
|
yield undefined;
|
|
|
|
if (testScriptFilename && !window.disableWorkerTest) {
|
|
info("Running test in a worker");
|
|
|
|
let workerScriptBlob =
|
|
new Blob([ "(" + workerScript.toString() + ")();" ],
|
|
{ type: "text/javascript" });
|
|
let workerScriptURL = URL.createObjectURL(workerScriptBlob);
|
|
|
|
let worker = new Worker(workerScriptURL);
|
|
|
|
worker._expectingUncaughtException = false;
|
|
worker.onerror = function(event) {
|
|
if (worker._expectingUncaughtException) {
|
|
ok(true, "Worker had an expected error: " + event.message);
|
|
worker._expectingUncaughtException = false;
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
ok(false, "Worker had an error: " + event.message);
|
|
worker.terminate();
|
|
nextTestHarnessStep();
|
|
};
|
|
|
|
worker.onmessage = function(event) {
|
|
let message = event.data;
|
|
switch (message.op) {
|
|
case "ok":
|
|
ok(message.condition, message.name, message.diag);
|
|
break;
|
|
|
|
case "todo":
|
|
todo(message.condition, message.name, message.diag);
|
|
break;
|
|
|
|
case "info":
|
|
info(message.msg);
|
|
break;
|
|
|
|
case "ready":
|
|
worker.postMessage({ op: "load", files: [ testScriptPath ] });
|
|
break;
|
|
|
|
case "loaded":
|
|
worker.postMessage({ op: "start", wasmSupported: isWasmSupported() });
|
|
break;
|
|
|
|
case "done":
|
|
ok(true, "Worker finished");
|
|
nextTestHarnessStep();
|
|
break;
|
|
|
|
case "expectUncaughtException":
|
|
worker._expectingUncaughtException = message.expecting;
|
|
break;
|
|
|
|
case "clearAllDatabases":
|
|
clearAllDatabases(function() {
|
|
worker.postMessage({ op: "clearAllDatabasesDone" });
|
|
});
|
|
break;
|
|
|
|
case "getWasmBinary":
|
|
worker.postMessage({ op: "getWasmBinaryDone",
|
|
wasmBinary: getWasmBinarySync(message.text) });
|
|
break;
|
|
|
|
default:
|
|
ok(false,
|
|
"Received a bad message from worker: " + JSON.stringify(message));
|
|
nextTestHarnessStep();
|
|
}
|
|
};
|
|
|
|
URL.revokeObjectURL(workerScriptURL);
|
|
|
|
yield undefined;
|
|
|
|
if (worker._expectingUncaughtException) {
|
|
ok(false, "expectUncaughtException was called but no uncaught " +
|
|
"exception was detected!");
|
|
}
|
|
|
|
worker.terminate();
|
|
worker = null;
|
|
|
|
clearAllDatabases(nextTestHarnessStep);
|
|
yield undefined;
|
|
} else if (testScriptFilename) {
|
|
todo(false,
|
|
"Skipping test in a worker because it is explicitly disabled: " +
|
|
window.disableWorkerTest);
|
|
} else {
|
|
todo(false,
|
|
"Skipping test in a worker because it's not structured properly");
|
|
}
|
|
|
|
info("Running test in main thread");
|
|
|
|
// Now run the test script in the main thread.
|
|
testGenerator.next();
|
|
|
|
yield undefined;
|
|
}
|
|
|
|
if (!window.runTest) {
|
|
window.runTest = function()
|
|
{
|
|
SimpleTest.waitForExplicitFinish();
|
|
testHarnessGenerator.next();
|
|
}
|
|
}
|
|
|
|
function finishTest()
|
|
{
|
|
SpecialPowers.notifyObserversInParentProcess(null,
|
|
"disk-space-watcher",
|
|
"free");
|
|
|
|
SimpleTest.executeSoon(function() {
|
|
clearAllDatabases(function() { SimpleTest.finish(); });
|
|
});
|
|
}
|
|
|
|
function browserRunTest()
|
|
{
|
|
testGenerator.next();
|
|
}
|
|
|
|
function browserFinishTest()
|
|
{
|
|
}
|
|
|
|
function grabEventAndContinueHandler(event)
|
|
{
|
|
testGenerator.next(event);
|
|
}
|
|
|
|
function continueToNextStep()
|
|
{
|
|
SimpleTest.executeSoon(function() {
|
|
testGenerator.next();
|
|
});
|
|
}
|
|
|
|
function continueToNextStepSync()
|
|
{
|
|
testGenerator.next();
|
|
}
|
|
|
|
function errorHandler(event)
|
|
{
|
|
ok(false, "indexedDB error, '" + event.target.error.name + "'");
|
|
finishTest();
|
|
}
|
|
|
|
// For error callbacks where the argument is not an event object.
|
|
function errorCallbackHandler(err)
|
|
{
|
|
ok(false, "got unexpected error callback: " + err);
|
|
finishTest();
|
|
}
|
|
|
|
function expectUncaughtException(expecting)
|
|
{
|
|
SimpleTest.expectUncaughtException(expecting);
|
|
}
|
|
|
|
function browserErrorHandler(event)
|
|
{
|
|
browserFinishTest();
|
|
throw new Error("indexedDB error (" + event.code + "): " + event.message);
|
|
}
|
|
|
|
function unexpectedSuccessHandler()
|
|
{
|
|
ok(false, "Got success, but did not expect it!");
|
|
finishTest();
|
|
}
|
|
|
|
function expectedErrorHandler(name)
|
|
{
|
|
return function(event) {
|
|
is(event.type, "error", "Got an error event");
|
|
is(event.target.error.name, name, "Expected error was thrown.");
|
|
event.preventDefault();
|
|
grabEventAndContinueHandler(event);
|
|
};
|
|
}
|
|
|
|
function ExpectError(name, preventDefault)
|
|
{
|
|
this._name = name;
|
|
this._preventDefault = preventDefault;
|
|
}
|
|
ExpectError.prototype = {
|
|
handleEvent(event)
|
|
{
|
|
is(event.type, "error", "Got an error event");
|
|
is(event.target.error.name, this._name, "Expected error was thrown.");
|
|
if (this._preventDefault) {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
}
|
|
grabEventAndContinueHandler(event);
|
|
}
|
|
};
|
|
|
|
function compareKeys(_k1_, _k2_) {
|
|
let t = typeof _k1_;
|
|
if (t != typeof _k2_)
|
|
return false;
|
|
|
|
if (t !== "object")
|
|
return _k1_ === _k2_;
|
|
|
|
if (_k1_ instanceof Date) {
|
|
return (_k2_ instanceof Date) &&
|
|
_k1_.getTime() === _k2_.getTime();
|
|
}
|
|
|
|
if (_k1_ instanceof Array) {
|
|
if (!(_k2_ instanceof Array) ||
|
|
_k1_.length != _k2_.length)
|
|
return false;
|
|
|
|
for (let i = 0; i < _k1_.length; ++i) {
|
|
if (!compareKeys(_k1_[i], _k2_[i]))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
function removePermission(type, url)
|
|
{
|
|
if (!url) {
|
|
url = window.document;
|
|
}
|
|
SpecialPowers.removePermission(type, url);
|
|
}
|
|
|
|
function gc()
|
|
{
|
|
SpecialPowers.forceGC();
|
|
SpecialPowers.forceCC();
|
|
}
|
|
|
|
function scheduleGC()
|
|
{
|
|
SpecialPowers.exactGC(continueToNextStep);
|
|
}
|
|
|
|
function isWasmSupported()
|
|
{
|
|
let testingFunctions = SpecialPowers.Cu.getJSTestingFunctions();
|
|
return testingFunctions.wasmIsSupported();
|
|
}
|
|
|
|
function getWasmBinarySync(text)
|
|
{
|
|
let testingFunctions = SpecialPowers.Cu.getJSTestingFunctions();
|
|
let wasmTextToBinary = SpecialPowers.unwrap(testingFunctions.wasmTextToBinary);
|
|
let binary = wasmTextToBinary(text);
|
|
return binary;
|
|
}
|
|
|
|
function workerScript() {
|
|
"use strict";
|
|
|
|
self.wasmSupported = false;
|
|
|
|
self.repr = function(_thing_) {
|
|
if (typeof(_thing_) == "undefined") {
|
|
return "undefined";
|
|
}
|
|
|
|
let str;
|
|
|
|
try {
|
|
str = _thing_ + "";
|
|
} catch (e) {
|
|
return "[" + typeof(_thing_) + "]";
|
|
}
|
|
|
|
if (typeof(_thing_) == "function") {
|
|
str = str.replace(/^\s+/, "");
|
|
let idx = str.indexOf("{");
|
|
if (idx != -1) {
|
|
str = str.substr(0, idx) + "{...}";
|
|
}
|
|
}
|
|
|
|
return str;
|
|
};
|
|
|
|
self.ok = function(_condition_, _name_, _diag_) {
|
|
self.postMessage({ op: "ok",
|
|
condition: !!_condition_,
|
|
name: _name_,
|
|
diag: _diag_ });
|
|
};
|
|
|
|
self.is = function(_a_, _b_, _name_) {
|
|
let pass = (_a_ == _b_);
|
|
let diag = pass ? "" : "got " + repr(_a_) + ", expected " + repr(_b_);
|
|
ok(pass, _name_, diag);
|
|
};
|
|
|
|
self.isnot = function(_a_, _b_, _name_) {
|
|
let pass = (_a_ != _b_);
|
|
let diag = pass ? "" : "didn't expect " + repr(_a_) + ", but got it";
|
|
ok(pass, _name_, diag);
|
|
};
|
|
|
|
self.todo = function(_condition_, _name_, _diag_) {
|
|
self.postMessage({ op: "todo",
|
|
condition: !!_condition_,
|
|
name: _name_,
|
|
diag: _diag_ });
|
|
};
|
|
|
|
self.info = function(_msg_) {
|
|
self.postMessage({ op: "info", msg: _msg_ });
|
|
};
|
|
|
|
self.executeSoon = function(_fun_) {
|
|
var channel = new MessageChannel();
|
|
channel.port1.postMessage("");
|
|
channel.port2.onmessage = function(event) { _fun_(); };
|
|
};
|
|
|
|
self.finishTest = function() {
|
|
if (self._expectingUncaughtException) {
|
|
self.ok(false, "expectUncaughtException was called but no uncaught "
|
|
+ "exception was detected!");
|
|
}
|
|
self.postMessage({ op: "done" });
|
|
};
|
|
|
|
self.grabEventAndContinueHandler = function(_event_) {
|
|
testGenerator.next(_event_);
|
|
};
|
|
|
|
self.continueToNextStep = function() {
|
|
executeSoon(function() {
|
|
testGenerator.next();
|
|
});
|
|
};
|
|
|
|
self.continueToNextStepSync = function() {
|
|
testGenerator.next();
|
|
};
|
|
|
|
self.errorHandler = function(_event_) {
|
|
ok(false, "indexedDB error, '" + _event_.target.error.name + "'");
|
|
finishTest();
|
|
};
|
|
|
|
self.unexpectedSuccessHandler = function()
|
|
{
|
|
ok(false, "Got success, but did not expect it!");
|
|
finishTest();
|
|
};
|
|
|
|
self.expectedErrorHandler = function(_name_)
|
|
{
|
|
return function(_event_) {
|
|
is(_event_.type, "error", "Got an error event");
|
|
is(_event_.target.error.name, _name_, "Expected error was thrown.");
|
|
_event_.preventDefault();
|
|
grabEventAndContinueHandler(_event_);
|
|
};
|
|
};
|
|
|
|
self.ExpectError = function(_name_, _preventDefault_)
|
|
{
|
|
this._name = _name_;
|
|
this._preventDefault = _preventDefault_;
|
|
}
|
|
self.ExpectError.prototype = {
|
|
handleEvent(_event_)
|
|
{
|
|
is(_event_.type, "error", "Got an error event");
|
|
is(_event_.target.error.name, this._name, "Expected error was thrown.");
|
|
if (this._preventDefault) {
|
|
_event_.preventDefault();
|
|
_event_.stopPropagation();
|
|
}
|
|
grabEventAndContinueHandler(_event_);
|
|
}
|
|
};
|
|
|
|
self.compareKeys = function(_k1_, _k2_) {
|
|
let t = typeof _k1_;
|
|
if (t != typeof _k2_)
|
|
return false;
|
|
|
|
if (t !== "object")
|
|
return _k1_ === _k2_;
|
|
|
|
if (_k1_ instanceof Date) {
|
|
return (_k2_ instanceof Date) &&
|
|
_k1_.getTime() === _k2_.getTime();
|
|
}
|
|
|
|
if (_k1_ instanceof Array) {
|
|
if (!(_k2_ instanceof Array) ||
|
|
_k1_.length != _k2_.length)
|
|
return false;
|
|
|
|
for (let i = 0; i < _k1_.length; ++i) {
|
|
if (!compareKeys(_k1_[i], _k2_[i]))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
self.getRandomBuffer = function(_size_) {
|
|
let buffer = new ArrayBuffer(_size_);
|
|
is(buffer.byteLength, _size_, "Correct byte length");
|
|
let view = new Uint8Array(buffer);
|
|
for (let i = 0; i < _size_; i++) {
|
|
view[i] = parseInt(Math.random() * 255)
|
|
}
|
|
return buffer;
|
|
};
|
|
|
|
self._expectingUncaughtException = false;
|
|
self.expectUncaughtException = function(_expecting_) {
|
|
self._expectingUncaughtException = !!_expecting_;
|
|
self.postMessage({ op: "expectUncaughtException", expecting: !!_expecting_ });
|
|
};
|
|
|
|
self._clearAllDatabasesCallback = undefined;
|
|
self.clearAllDatabases = function(_callback_) {
|
|
self._clearAllDatabasesCallback = _callback_;
|
|
self.postMessage({ op: "clearAllDatabases" });
|
|
}
|
|
|
|
self.onerror = function(_message_, _file_, _line_) {
|
|
if (self._expectingUncaughtException) {
|
|
self._expectingUncaughtException = false;
|
|
ok(true, "Worker: expected exception [" + _file_ + ":" + _line_ + "]: '" +
|
|
_message_ + "'");
|
|
return false;
|
|
}
|
|
ok(false,
|
|
"Worker: uncaught exception [" + _file_ + ":" + _line_ + "]: '" +
|
|
_message_ + "'");
|
|
self.finishTest();
|
|
self.close();
|
|
return true;
|
|
};
|
|
|
|
self.isWasmSupported = function() {
|
|
return self.wasmSupported;
|
|
}
|
|
|
|
self.getWasmBinarySync = function(_text_) {
|
|
self.ok(false, "This can't be used on workers");
|
|
}
|
|
|
|
self.getWasmBinary = function(_text_) {
|
|
self.postMessage({ op: "getWasmBinary", text: _text_ });
|
|
}
|
|
|
|
self.getWasmModule = function(_binary_) {
|
|
let module = new WebAssembly.Module(_binary_);
|
|
return module;
|
|
}
|
|
|
|
self.verifyWasmModule = function(_module) {
|
|
self.todo(false, "Need a verifyWasmModule implementation on workers");
|
|
self.continueToNextStep();
|
|
}
|
|
|
|
self.onmessage = function(_event_) {
|
|
let message = _event_.data;
|
|
switch (message.op) {
|
|
case "load":
|
|
info("Worker: loading " + JSON.stringify(message.files));
|
|
self.importScripts(message.files);
|
|
self.postMessage({ op: "loaded" });
|
|
break;
|
|
|
|
case "start":
|
|
self.wasmSupported = message.wasmSupported;
|
|
executeSoon(function() {
|
|
info("Worker: starting tests");
|
|
testGenerator.next();
|
|
});
|
|
break;
|
|
|
|
case "clearAllDatabasesDone":
|
|
info("Worker: all databases are cleared");
|
|
if (self._clearAllDatabasesCallback) {
|
|
self._clearAllDatabasesCallback();
|
|
}
|
|
break;
|
|
|
|
case "getWasmBinaryDone":
|
|
info("Worker: get wasm binary done");
|
|
testGenerator.next(message.wasmBinary);
|
|
break;
|
|
|
|
default:
|
|
throw new Error("Received a bad message from parent: " +
|
|
JSON.stringify(message));
|
|
}
|
|
};
|
|
|
|
self.postMessage({ op: "ready" });
|
|
}
|