Bug 663291: Improve the SpecialPowers and SimpleTest APIs to make it easier to write mochitests that look at error console output. Update all tests that were using ad-hoc console inspection or the old SimpleTest console handler API. r=ted

--HG--
extra : rebase_source : 013c6031577f88a764fecee9750ee890b45d1181
This commit is contained in:
Zack Weinberg 2012-11-16 15:29:21 -05:00
parent c77a8b3fb1
commit 8d246d6c65
11 changed files with 306 additions and 331 deletions

View File

@ -2,4 +2,3 @@
<meta charset=utf-8>
<title>Non-UTF form target</title>
<body onload="parent.finish();">

View File

@ -1,8 +1,7 @@
<!DOCTYPE html>
<!doctype html>
<meta charset=windows-1252>
<title>Non-UTF form</title>
<body onload="document.forms[0].submit();">
<form action="file_bug708620-2.html">
<input name=foo value=bar>
</form>

View File

@ -1,4 +1,4 @@
<!DOCTYPE HTML>
<!doctype html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=513194
@ -6,67 +6,22 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=513194
<head>
<meta charset="utf-8">
<title>Test for Bug 513194</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
var consoleService =
Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
var consoleListener = {
seenError: false,
observe: function(message) {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
if (this.seenError) {
ok(false, "Seen too many errors!");
}
this.seenError = true;
ok(message.message.indexOf("Unknown property") > -1,
"Wrong message");
},
finish: function() {
ok(this.seenError , "Didn't get message.");
SimpleTest.finish();
},
QueryInterface: function(iid) {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
if (iid.equals(Ci.nsIConsoleListener) ||
iid.equals(Ci.nsISupports)) {
return this;
}
throw Cr.NS_NOINTERFACE;
}
};
consoleService.reset();
consoleService.registerListener(consoleListener);
SimpleTest.waitForExplicitFinish();
document.write("<style>qux { foo: bar; }<\/style>");
function done() {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
consoleListener.finish();
consoleService.unregisterListener(consoleListener);
}
setTimeout(done, 0);
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=631615"
>Mozilla Bug 513194</a>
<script>
// The use of document.write is deliberate. We are testing for the
// HTML parser to call the CSS parser once and only once when it
// encounters a new <style> element.
SimpleTest.runTestExpectingConsoleMessages(
function () { document.write("<style>qux { foo : bar; }<\/style>") },
[{ errorMessage: /Unknown property/ }]
);
</script>
</pre>
</body>
</html>

View File

@ -1,4 +1,4 @@
<!DOCTYPE HTML>
<!doctype html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=631615
@ -6,76 +6,21 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=631615
<head>
<meta charset="utf-8">
<title>Test for Bug 631615</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=631615">Mozilla Bug 631615</a>
<pre id="monitor">
</pre>
<script type="application/javascript">
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
var consoleService =
Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
var messageCount = 0;
var monitor = document.getElementById("monitor");
var listener = {
observe: function(message) {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
if (message.message === "sentinel") {
is(messageCount, 0, "should have been no console messages");
removeListener();
SimpleTest.finish();
} else {
messageCount++;
var err = "" + messageCount + ": " + message.message + "\n";
monitor.appendChild(document.createTextNode(err));
}
},
QueryInterface: function(iid) {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
if (iid.equals(Ci.nsIConsoleListener) ||
iid.equals(Ci.nsISupports)) {
return this;
}
throw Cr.NS_NOINTERFACE;
}
};
function addListener() {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
consoleService.reset();
consoleService.registerListener(listener);
}
function removeListener() {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
consoleService.unregisterListener(listener);
}
function postSentinel() {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
consoleService.logStringMessage("sentinel");
}
SimpleTest.waitForExplicitFinish();
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=631615"
>Mozilla Bug 631615</a>
<pre id="monitor"></pre>
<script>
function doTest() {
var monitor = document.getElementById("monitor");
var html = document.documentElement;
var results;
var matches = html.matchesSelector || html.mozMatchesSelector;
addListener();
try {
results = "return: " +
matches.call(html, "[test!='']:sizzle") + "\n";
@ -85,11 +30,9 @@ function doTest() {
monitor.appendChild(document.createTextNode(results));
is(results.slice(0, 6), "throws", "looking for an exception");
postSentinel();
}
doTest();
SimpleTest.runTestExpectingConsoleMessages(doTest, []);
</script>
</body>
</html>

View File

@ -1,4 +1,4 @@
<!DOCTYPE HTML>
<!doctype html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=708620
@ -6,61 +6,36 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=708620
<head>
<meta charset="utf-8">
<title>Test for Bug 708620</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head>
<body onload="start();">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=708620">Mozilla Bug 708620</a>
<p id="display"></p>
<div id="content" style="display: none">
<iframe></iframe>
</div>
<pre id="test">
<script type="application/javascript">
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=708620"
>Mozilla Bug 708620</a>
<iframe></iframe>
<script>
/** Test for Bug 708620 **/
SimpleTest.waitForExplicitFinish();
SimpleTest.monitorConsole(SimpleTest.finish, [
{ errorMessage: "A form was submitted in the windows-1252 encoding "+
"which cannot encode all Unicode characters, so user "+
"input may get corrupted. To avoid this problem, the "+
"page should be changed so that the form is submitted "+
"in the UTF-8 encoding either by changing the encoding "+
"of the page itself to UTF-8 or by specifying "+
"accept-charset=utf-8 on the form element.",
isWarning: true }
]);
var tests = [
"file_bug708620.html"
];
function resolveURL(relative) {
var a = document.createElement('a');
a.href = relative;
return a.href;
}
var resolvedURL = resolveURL(tests[0]);
var expectedErrors = [
'[JavaScript Warning: "A form was submitted in the windows-1252 encoding which cannot encode all Unicode characters, so user input may get corrupted. To avoid this problem, the page should be changed so that the form is submitted in the UTF-8 encoding either by changing the encoding of the page itself to UTF-8 or by specifying accept-charset=utf-8 on the form element." {file: "' + resolvedURL + '" line: 1}]'
];
function consoleError(msg, fileName) {
// Ignore messages not generated by the test
if (fileName !== resolvedURL) {
return;
}
var expected = expectedErrors.shift();
is(msg, expected, "Not the right error message");
}
SpecialPowers.addErrorConsoleListener(consoleError);
function start() {
var url = tests.shift();
document.getElementsByTagName("iframe")[0].src = url;
window.onload = function () {
document.getElementsByTagName("iframe")[0].src = "file_bug708620.html";
}
function finish() {
is(expectedErrors.length, 0, "The error supply was not exhausted");
SpecialPowers.removeErrorConsoleListener(consoleError);
SimpleTest.finish();
SimpleTest.endMonitorConsole();
}
</script>
</pre>
</body>
</html>

View File

@ -1,4 +1,4 @@
<!DOCTYPE HTML>
<!doctype html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=489671
@ -6,68 +6,20 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=489671
<head>
<meta charset="utf-8">
<title>Test for Bug 489671</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=489671">Mozilla Bug 489671</a>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=489671"
>Mozilla Bug 489671</a>
<p id="display" onclick="throw 'Got click'"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 489671 **/
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
var listener = {
observe: function(message) {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
is(message.QueryInterface(Ci.nsIScriptError).errorMessage,
"uncaught exception: Got click");
SimpleTest.executeSoon(nextTest);
},
QueryInterface: function(iid) {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
if (iid.equals(Ci.nsIConsoleListener) ||
iid.equals(Ci.nsISupports)) {
return this;
}
throw Cr.NS_NOINTERFACE;
}
};
function addListener() {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
var consoleService =
Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
consoleService.reset();
consoleService.registerListener(listener);
}
function removeListener() {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
var consoleService =
Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
consoleService.unregisterListener(listener);
}
SimpleTest.waitForExplicitFinish();
addListener();
<script>
// override window.onerror so it won't see our exceptions
window.onerror = function() {}
var testNum = 0;
function nextTest() {
function doTest() {
switch(testNum++) {
case 0:
var event = document.createEvent("MouseEvents");
@ -84,15 +36,20 @@ function nextTest() {
window.setTimeout("throw 'Got click'", 0);
break;
case 3:
removeListener();
SimpleTest.finish();
break;
SimpleTest.endMonitorConsole();
return;
}
SimpleTest.executeSoon(doTest);
}
nextTest();
SimpleTest.waitForExplicitFinish();
SimpleTest.monitorConsole(SimpleTest.finish, [
{ errorMessage: "uncaught exception: Got click" },
{ errorMessage: "uncaught exception: Got click" },
{ errorMessage: "uncaught exception: Got click" }
]);
doTest();
</script>
</pre>
</body>
</html>

View File

@ -63,6 +63,7 @@ MOCHITEST_FILES = parser_datreader.js \
test_bug655682.html \
file_bug655682.sjs \
test_bug667533.html \
test_bug672453.html \
file_bug672453_not_declared.html \
file_bug672453_late_meta.html \
file_bug672453_meta_restart.html \
@ -103,7 +104,4 @@ endif
# Disable test due to frequent orange on Mac
# test_bug534293.html \
# Disabled due to frequent orange (bug 739354)
# test_bug672453.html \
include $(topsrcdir)/config/rules.mk

View File

@ -1,4 +1,4 @@
<!DOCTYPE HTML>
<!doctype html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=672453
@ -6,22 +6,17 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=672453
<head>
<meta charset="utf-8">
<title>Test for Bug 672453</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=672453">Mozilla Bug 672453</a>
<p id="display"></p>
<div id="content" style="display: none">
<iframe onload="runNextTest();"></iframe>
</div>
<pre id="test">
<script type="application/javascript">
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=672453"
>Mozilla Bug 672453</a>
<iframe></iframe>
<script>
/** Test for Bug 672453 **/
SimpleTest.waitForExplicitFinish();
var tests = [
"file_bug672453_not_declared.html",
"file_bug672453_late_meta.html",
@ -34,35 +29,66 @@ var tests = [
];
var expectedErrors = [
'[JavaScript Warning: "The character encoding of a framed document was not declared. The document may appear different if viewed without the document framing it." {file: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_not_declared.html" line: 0}]',
'[JavaScript Warning: "The character encoding declaration of the framed HTML document was not found when prescanning the first 1024 bytes of the file. When viewed without the document framing it, the page will reload automatically. The encoding declaration needs to be moved to be within the first 1024 bytes of the file." {file: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_late_meta.html" line: 1028}]',
'[JavaScript Warning: "The page was reloaded, because the character encoding declaration of the HTML document was not found when prescanning the first 1024 bytes of the file. The encoding declaration needs to be moved to be within the first 1024 bytes of the file." {file: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_meta_restart.html" line: 1028}]',
'[JavaScript Error: "An unsupported character encoding was declared for the HTML document using a meta tag. The declaration was ignored." {file: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_meta_unsupported.html" line: 1}]',
'[JavaScript Error: "An unsupported character encoding was declared on the transfer protocol level. The declaration was ignored." {file: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_http_unsupported.html" line: 0}]',
'[JavaScript Error: "Detected UTF-16-encoded Basic Latin-only text without a byte order mark and without a transfer protocol-level declaration. Encoding this content in UTF-16 is inefficient and the character encoding should have been declared in any case." {file: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_bomless_utf16.html" line: 0}]',
'[JavaScript Error: "A meta tag was used to declare the character encoding as UTF-16. This was interpreted as an UTF-8 declaration instead." {file: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_meta_utf16.html" line: 1}]',
'[JavaScript Error: "A meta tag was used to declare a character encoding the does not encode the Basic Latin range roughly like US-ASCII. The declaration was ignored." {file: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_meta_non_superset.html" line: 1}]'
{ errorMessage: "The character encoding of a framed document was not declared. The document may appear different if viewed without the document framing it.",
sourceName: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_not_declared.html",
lineNumber: 0,
isWarning: true,
isException: false },
{ errorMessage: "The character encoding declaration of the framed HTML document was not found when prescanning the first 1024 bytes of the file. When viewed without the document framing it, the page will reload automatically. The encoding declaration needs to be moved to be within the first 1024 bytes of the file.",
sourceName: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_late_meta.html",
lineNumber: 1028,
isWarning: true,
isException: false },
{ errorMessage: "The page was reloaded, because the character encoding declaration of the HTML document was not found when prescanning the first 1024 bytes of the file. The encoding declaration needs to be moved to be within the first 1024 bytes of the file.",
sourceName: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_meta_restart.html",
lineNumber: 1028,
isWarning: true,
isException: false },
{ errorMessage: "An unsupported character encoding was declared for the HTML document using a meta tag. The declaration was ignored.",
sourceName: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_meta_unsupported.html",
lineNumber: 1,
isWarning: false,
isException: false },
{ errorMessage: "An unsupported character encoding was declared on the transfer protocol level. The declaration was ignored.",
sourceName: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_http_unsupported.html",
lineNumber: 0,
isWarning: false,
isException: false },
{ errorMessage: "Detected UTF-16-encoded Basic Latin-only text without a byte order mark and without a transfer protocol-level declaration. Encoding this content in UTF-16 is inefficient and the character encoding should have been declared in any case.",
sourceName: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_bomless_utf16.html",
lineNumber: 0,
isWarning: false,
isException: false },
{ errorMessage: "A meta tag was used to declare the character encoding as UTF-16. This was interpreted as an UTF-8 declaration instead.",
sourceName: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_meta_utf16.html",
lineNumber: 1,
isWarning: false,
isException: false },
{ errorMessage: "A meta tag was used to declare a character encoding the does not encode the Basic Latin range roughly like US-ASCII. The declaration was ignored.",
sourceName: "http://mochi.test:8888/tests/parser/htmlparser/tests/mochitest/file_bug672453_meta_non_superset.html",
lineNumber: 1,
isWarning: false,
isException: false }
];
function consoleError(msg) {
var expected = expectedErrors.shift();
is(msg, expected, "Not the right error message");
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.addErrorConsoleListener(consoleError);
window.onload = function() {
var iframe = document.getElementsByTagName("iframe")[0];
function runNextTest() {
var url = tests.shift();
if (!url) {
is(expectedErrors.length, 0, "The error supply was not exhausted");
SpecialPowers.removeErrorConsoleListener(consoleError);
SimpleTest.finish();
return;
function runNextTest() {
var url = tests.shift();
if (!url) {
SimpleTest.endMonitorConsole();
return;
}
iframe.src = url;
}
document.getElementsByTagName("iframe")[0].src = url;
}
iframe.onload = runNextTest;
SimpleTest.monitorConsole(SimpleTest.finish, expectedErrors);
runNextTest();
}
</script>
</pre>
</body>
</html>

View File

@ -693,6 +693,89 @@ SimpleTest.finish = function () {
}
};
/**
* Monitor console output from now until endMonitorConsole is called.
*
* Expect to receive as many console messages as there are elements of
* |msgs|, an array; each element is an object which may have any
* number of the following properties:
* message, errorMessage, sourceName, sourceLine, category:
* string or regexp
* lineNumber, columnNumber: number
* isScriptError, isWarning, isException, isStrict: boolean
* Strings, numbers, and booleans must compare equal to the named
* property of the Nth console message. Regexps must match. Any
* fields present in the message but not in the pattern object are ignored.
*
* After endMonitorConsole is called, |continuation| will be called
* asynchronously. (Normally, you will want to pass |SimpleTest.finish| here.)
*
* It is incorrect to use this function in a test which has not called
* SimpleTest.waitForExplicitFinish.
*/
SimpleTest.monitorConsole = function (continuation, msgs) {
if (SimpleTest._stopOnLoad) {
ok(false, "Console monitoring requires use of waitForExplicitFinish.");
}
var counter = 0;
function listener(msg) {
if (msg.message === "SENTINEL" && !msg.isScriptError) {
is(counter, msgs.length, "monitorConsole | number of messages");
SimpleTest.executeSoon(continuation);
} else if (counter >= msgs.length) {
ok(false, "monitorConsole | extra message | " + JSON.stringify(msg));
} else {
var pat = msgs[counter];
for (k in pat) {
ok(k in msg, "monitorConsole | [" + counter + "]." + k + " present");
if (k in msg) {
if (pat[k] instanceof RegExp && typeof(msg[k]) === 'string') {
ok(pat[k].test(msg[k]),
"monitorConsole | [" + counter + "]." + k + " value - " +
msg[k].quote() + " contains /" + pat[k].source + "/");
} else {
ise(msg[k], pat[k],
"monitorConsole | [" + counter + "]." + k + " value");
}
}
}
counter++;
}
}
SpecialPowers.registerConsoleListener(listener);
};
/**
* Stop monitoring console output.
*/
SimpleTest.endMonitorConsole = function () {
SpecialPowers.postConsoleSentinel();
};
/**
* Run |testfn| synchronously, and monitor its console output.
*
* |msgs| is handled as described above for monitorConsole.
*
* After |testfn| returns, console monitoring will stop, and
* |continuation| will be called asynchronously.
*/
SimpleTest.expectConsoleMessages = function (testfn, msgs, continuation) {
SimpleTest.monitorConsole(continuation, msgs);
testfn();
SimpleTest.executeSoon(SimpleTest.endMonitorConsole);
};
/**
* Wrapper around |expectConsoleMessages| for the case where the test has
* only one |testfn| to run.
*/
SimpleTest.runTestExpectingConsoleMessages = function(testfn, msgs) {
SimpleTest.waitForExplicitFinish();
SimpleTest.expectConsoleMessages(testfn, msgs, SimpleTest.finish);
};
/**
* Indicates to the test framework that the current test expects one or
* more crashes (from plugins or IPC documents), and that the minidumps from

View File

@ -11,22 +11,23 @@ function SpecialPowers(window) {
this._unexpectedCrashDumpFiles = { };
this._crashDumpDir = null;
this.DOMWindowUtils = bindDOMWindowUtils(window);
Object.defineProperty(this, 'Components', { configurable: true, enumerable: true,
get: function() { var win = this.window.get();
if (!win)
return null;
return getRawComponents(win); } });
Object.defineProperty(this, 'Components', {
configurable: true, enumerable: true, get: function() {
var win = this.window.get();
if (!win)
return null;
return getRawComponents(win);
}});
this._pongHandlers = [];
this._messageListener = this._messageReceived.bind(this);
addMessageListener("SPPingService", this._messageListener);
this._consoleListeners = [];
}
SpecialPowers.prototype = new SpecialPowersAPI();
SpecialPowers.prototype.toString = function() { return "[SpecialPowers]"; };
SpecialPowers.prototype.sanityCheck = function() { return "foo"; };
// This gets filled in in the constructor.
SpecialPowers.prototype.DOMWindowUtils = undefined;
SpecialPowers.prototype.Components = undefined;

View File

@ -9,12 +9,13 @@ var Ci = Components.interfaces;
var Cc = Components.classes;
var Cu = Components.utils;
Components.utils.import("resource://specialpowers/MockFilePicker.jsm");
Components.utils.import("resource://specialpowers/MockPermissionPrompt.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
Cu.import("resource://specialpowers/MockFilePicker.jsm");
Cu.import("resource://specialpowers/MockPermissionPrompt.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
function SpecialPowersAPI() {
function SpecialPowersAPI() {
this._consoleListeners = [];
this._encounteredCrashDumpFiles = [];
this._unexpectedCrashDumpFiles = { };
@ -379,6 +380,58 @@ SpecialPowersHandler.prototype.enumerate = function() {
return this.getPropertyNames().filter(filt);
};
// SPConsoleListener reflects nsIConsoleMessage objects into JS in a
// tidy, XPCOM-hiding way. Messages that are nsIScriptError objects
// have their properties exposed in detail. It also auto-unregisters
// itself when it receives a "sentinel" message.
function SPConsoleListener(callback) {
this.callback = callback;
}
SPConsoleListener.prototype = {
observe: function(msg) {
let m = { message: msg.message,
errorMessage: null,
sourceName: null,
sourceLine: null,
lineNumber: null,
columnNumber: null,
category: null,
windowID: null,
isScriptError: false,
isWarning: false,
isException: false,
isStrict: false };
if (msg instanceof Ci.nsIScriptError) {
m.errorMessage = msg.errorMessage;
m.sourceName = msg.sourceName;
m.sourceLine = msg.sourceLine;
m.lineNumber = msg.lineNumber;
m.columnNumber = msg.columnNumber;
m.category = msg.category;
m.windowID = msg.outerWindowID;
m.isScriptError = true;
m.isWarning = ((msg.flags & Ci.nsIScriptError.warningFlag) === 1);
m.isException = ((msg.flags & Ci.nsIScriptError.exceptionFlag) === 1);
m.isStrict = ((msg.flags & Ci.nsIScriptError.strictFlag) === 1);
}
// expose all props of 'm' as read-only
let expose = {};
for (let prop in m)
expose[prop] = 'r';
m.__exposedProps__ = expose;
Object.freeze(m);
this.callback.call(undefined, m);
if (!m.isScriptError && m.message === "SENTINEL")
Services.console.unregisterListener(this);
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIConsoleListener])
};
SpecialPowersAPI.prototype = {
/*
@ -749,6 +802,15 @@ SpecialPowersAPI.prototype = {
return(this._sendSyncMessage('SPPrefService', msg)[0]);
},
_getDocShell: function(window) {
return window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
},
_getMUDV: function(window) {
return this._getDocShell(window).contentViewer
.QueryInterface(Ci.nsIMarkupDocumentViewer);
},
//XXX: these APIs really ought to be removed, they're not e10s-safe.
// (also they're pretty Firefox-specific)
_getTopChromeWindow: function(window) {
@ -760,15 +822,6 @@ SpecialPowersAPI.prototype = {
.getInterface(Ci.nsIDOMWindow)
.QueryInterface(Ci.nsIDOMChromeWindow);
},
_getDocShell: function(window) {
return window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
},
_getMUDV: function(window) {
return this._getDocShell(window).contentViewer
.QueryInterface(Ci.nsIMarkupDocumentViewer);
},
_getAutoCompletePopup: function(window) {
return this._getTopChromeWindow(window).document
.getElementById("PopupAutoComplete");
@ -800,6 +853,7 @@ SpecialPowersAPI.prototype = {
.getElementById("Browser:Back")
.hasAttribute("disabled");
},
//XXX end of problematic APIs
addChromeEventListener: function(type, listener, capture, allowUntrusted) {
addEventListener(type, listener, capture, allowUntrusted);
@ -808,36 +862,21 @@ SpecialPowersAPI.prototype = {
removeEventListener(type, listener, capture);
},
addErrorConsoleListener: function(listener) {
var consoleListener = {
userListener: listener,
observe: function(consoleMessage) {
var fileName;
try {
fileName = consoleMessage.QueryInterface(Ci.nsIScriptError)
.sourceName;
} catch (e) {
}
this.userListener(consoleMessage.message, fileName);
}
};
Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService)
.registerListener(consoleListener);
this._consoleListeners.push(consoleListener);
// Note: each call to registerConsoleListener MUST be paired with a
// call to postConsoleSentinel; when the callback receives the
// sentinel it will unregister itself (_after_ calling the
// callback). SimpleTest.expectConsoleMessages does this for you.
// If you register more than one console listener, a call to
// postConsoleSentinel will zap all of them.
registerConsoleListener: function(callback) {
let listener = new SPConsoleListener(callback);
Services.console.registerListener(listener);
},
removeErrorConsoleListener: function(listener) {
for (var index in this._consoleListeners) {
var consoleListener = this._consoleListeners[index];
if (consoleListener.userListener == listener) {
Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService)
.unregisterListener(consoleListener);
this._consoleListeners = this._consoleListeners.splice(index, 1);
break;
}
}
postConsoleSentinel: function() {
Services.console.logStringMessage("SENTINEL");
},
resetConsole: function() {
Services.console.reset();
},
getMaxLineBoxWidth: function(window) {
@ -899,11 +938,11 @@ SpecialPowersAPI.prototype = {
},
forceGC: function() {
Components.utils.forceGC();
Cu.forceGC();
},
forceCC: function() {
Components.utils.forceCC();
Cu.forceCC();
},
exactGC: function(win, callback) {
@ -921,14 +960,14 @@ SpecialPowersAPI.prototype = {
}
}
Components.utils.schedulePreciseGC(scheduledGCCallback);
Cu.schedulePreciseGC(scheduledGCCallback);
}
doPreciseGCandCC();
},
setGCZeal: function(zeal) {
Components.utils.setGCZeal(zeal);
Cu.setGCZeal(zeal);
},
isMainProcess: function() {
@ -1202,7 +1241,7 @@ SpecialPowersAPI.prototype = {
} else if (arg.manifestURL) {
// It's a thing representing an app.
let tmp = {};
Components.utils.import("resource://gre/modules/Webapps.jsm", tmp);
Cu.import("resource://gre/modules/Webapps.jsm", tmp);
let app = tmp.DOMApplicationRegistry.getAppByManifestURL(arg.manifestURL);
if (!app) {