Bug 1173288 - Update testharness code in imptests; rs=jgraham

--HG--
extra : commitid : EaZShgcjVGF
This commit is contained in:
Ms2ger 2015-06-20 09:16:51 +02:00
parent 98d44fafe9
commit f285086ddc
9 changed files with 688 additions and 741 deletions

View File

@ -920,5 +920,5 @@
};
if (inNode) module.exports = obj;
else window.WebIDL2 = obj;
else self.WebIDL2 = obj;
}());

View File

@ -1,27 +1,21 @@
{
"DOMException exception: existence and properties of exception interface prototype object's \"name\" property": true,
"CustomEvent interface: existence and properties of interface object": true,
"EventListener interface: existence and properties of interface prototype object": true,
"EventListener interface: existence and properties of interface prototype object's \"constructor\" property": true,
"EventListener interface: operation handleEvent(Event)": true,
"MutationObserver interface: operation observe(Node,MutationObserverInit)": true,
"Node interface: existence and properties of interface object": true,
"Document interface: existence and properties of interface object": true,
"Document interface: operation prepend([object Object],[object Object])": true,
"Document interface: operation append([object Object],[object Object])": true,
"XMLDocument interface: existence and properties of interface object": true,
"Document interface: xmlDoc must inherit property \"prepend\" with the proper type (28)": true,
"Document interface: calling prepend([object Object],[object Object]) on xmlDoc with too few arguments must throw TypeError": true,
"Document interface: xmlDoc must inherit property \"append\" with the proper type (29)": true,
"Document interface: calling append([object Object],[object Object]) on xmlDoc with too few arguments must throw TypeError": true,
"DocumentFragment interface: existence and properties of interface object": true,
"DocumentFragment interface: operation prepend([object Object],[object Object])": true,
"DocumentFragment interface: operation append([object Object],[object Object])": true,
"DocumentFragment interface: document.createDocumentFragment() must inherit property \"prepend\" with the proper type (4)": true,
"DocumentFragment interface: calling prepend([object Object],[object Object]) on document.createDocumentFragment() with too few arguments must throw TypeError": true,
"DocumentFragment interface: document.createDocumentFragment() must inherit property \"append\" with the proper type (5)": true,
"DocumentFragment interface: calling append([object Object],[object Object]) on document.createDocumentFragment() with too few arguments must throw TypeError": true,
"DocumentType interface: existence and properties of interface object": true,
"DocumentType interface: operation before([object Object],[object Object])": true,
"DocumentType interface: operation after([object Object],[object Object])": true,
"DocumentType interface: operation replace([object Object],[object Object])": true,
@ -31,7 +25,6 @@
"DocumentType interface: calling after([object Object],[object Object]) on document.doctype with too few arguments must throw TypeError": true,
"DocumentType interface: document.doctype must inherit property \"replace\" with the proper type (5)": true,
"DocumentType interface: calling replace([object Object],[object Object]) on document.doctype with too few arguments must throw TypeError": true,
"Element interface: existence and properties of interface object": true,
"Element interface: attribute namespaceURI": true,
"Element interface: attribute prefix": true,
"Element interface: attribute localName": true,
@ -52,36 +45,48 @@
"Element interface: calling replace([object Object],[object Object]) on element with too few arguments must throw TypeError": true,
"Attr interface: existence and properties of interface object": true,
"Attr interface: existence and properties of interface prototype object": true,
"CharacterData interface: existence and properties of interface object": true,
"CharacterData interface: operation before([object Object],[object Object])": true,
"CharacterData interface: operation after([object Object],[object Object])": true,
"CharacterData interface: operation replace([object Object],[object Object])": true,
"Text interface: existence and properties of interface object": true,
"CharacterData interface: document.createTextNode(\"abc\") must inherit property \"before\" with the proper type (7)": true,
"CharacterData interface: calling before([object Object],[object Object]) on document.createTextNode(\"abc\") with too few arguments must throw TypeError": true,
"CharacterData interface: document.createTextNode(\"abc\") must inherit property \"after\" with the proper type (8)": true,
"CharacterData interface: calling after([object Object],[object Object]) on document.createTextNode(\"abc\") with too few arguments must throw TypeError": true,
"CharacterData interface: document.createTextNode(\"abc\") must inherit property \"replace\" with the proper type (9)": true,
"CharacterData interface: calling replace([object Object],[object Object]) on document.createTextNode(\"abc\") with too few arguments must throw TypeError": true,
"ProcessingInstruction interface: existence and properties of interface object": true,
"CharacterData interface: xmlDoc.createProcessingInstruction(\"abc\", \"def\") must inherit property \"before\" with the proper type (7)": true,
"CharacterData interface: calling before([object Object],[object Object]) on xmlDoc.createProcessingInstruction(\"abc\", \"def\") with too few arguments must throw TypeError": true,
"CharacterData interface: xmlDoc.createProcessingInstruction(\"abc\", \"def\") must inherit property \"after\" with the proper type (8)": true,
"CharacterData interface: calling after([object Object],[object Object]) on xmlDoc.createProcessingInstruction(\"abc\", \"def\") with too few arguments must throw TypeError": true,
"CharacterData interface: xmlDoc.createProcessingInstruction(\"abc\", \"def\") must inherit property \"replace\" with the proper type (9)": true,
"CharacterData interface: calling replace([object Object],[object Object]) on xmlDoc.createProcessingInstruction(\"abc\", \"def\") with too few arguments must throw TypeError": true,
"Comment interface: existence and properties of interface object": true,
"CharacterData interface: document.createComment(\"abc\") must inherit property \"before\" with the proper type (7)": true,
"CharacterData interface: calling before([object Object],[object Object]) on document.createComment(\"abc\") with too few arguments must throw TypeError": true,
"CharacterData interface: document.createComment(\"abc\") must inherit property \"after\" with the proper type (8)": true,
"CharacterData interface: calling after([object Object],[object Object]) on document.createComment(\"abc\") with too few arguments must throw TypeError": true,
"CharacterData interface: document.createComment(\"abc\") must inherit property \"replace\" with the proper type (9)": true,
"CharacterData interface: calling replace([object Object],[object Object]) on document.createComment(\"abc\") with too few arguments must throw TypeError": true,
"NodeFilter interface: existence and properties of interface object": true,
"NodeList interface: existence and properties of interface prototype object": true,
"DOMTokenList interface: operation add(DOMString)": true,
"DOMTokenList interface: operation remove(DOMString)": true,
"DOMTokenList interface: calling add(DOMString) on document.body.classList with too few arguments must throw TypeError": true,
"DOMTokenList interface: calling remove(DOMString) on document.body.classList with too few arguments must throw TypeError": true,
"DOMSettableTokenList interface: existence and properties of interface object": true
"NodeFilter interface: existence and properties of interface prototype object": true,
"NodeFilter interface: existence and properties of interface prototype object": true,
"NodeFilter interface: existence and properties of interface prototype object's \"constructor\" property": true,
"EventListener interface: existence and properties of interface object": true,
"EventListener interface object length": true,
"NodeFilter interface: constant FILTER_ACCEPT on interface prototype object": true,
"NodeFilter interface: constant FILTER_REJECT on interface prototype object": true,
"NodeFilter interface: constant FILTER_SKIP on interface prototype object": true,
"NodeFilter interface: constant SHOW_ALL on interface prototype object": true,
"NodeFilter interface: constant SHOW_ELEMENT on interface prototype object": true,
"NodeFilter interface: constant SHOW_ATTRIBUTE on interface prototype object": true,
"NodeFilter interface: constant SHOW_TEXT on interface prototype object": true,
"NodeFilter interface: constant SHOW_CDATA_SECTION on interface prototype object": true,
"NodeFilter interface: constant SHOW_ENTITY_REFERENCE on interface prototype object": true,
"NodeFilter interface: constant SHOW_ENTITY on interface prototype object": true,
"NodeFilter interface: constant SHOW_PROCESSING_INSTRUCTION on interface prototype object": true,
"NodeFilter interface: constant SHOW_COMMENT on interface prototype object": true,
"NodeFilter interface: constant SHOW_DOCUMENT on interface prototype object": true,
"NodeFilter interface: constant SHOW_DOCUMENT_TYPE on interface prototype object": true,
"NodeFilter interface: constant SHOW_DOCUMENT_FRAGMENT on interface prototype object": true,
"NodeFilter interface: constant SHOW_NOTATION on interface prototype object": true,
"NodeFilter interface: operation acceptNode(Node)": true,
"NodeList interface: existence and properties of interface prototype object": true
}

View File

@ -1,6 +0,0 @@
# THIS FILE IS AUTOGENERATED BY parseFailures.py - DO NOT EDIT
[DEFAULT]
support-files =
[test_interfaces.html.json]

View File

@ -1,4 +0,0 @@
{
"XMLHttpRequestUpload interface: existence and properties of interface object": true,
"XMLHttpRequest interface: existence and properties of interface object": true
}

View File

@ -10,35 +10,6 @@
<div id=log></div>
<script type=text/plain>
exception DOMException {
const unsigned short INDEX_SIZE_ERR = 1;
const unsigned short DOMSTRING_SIZE_ERR = 2; // historical
const unsigned short HIERARCHY_REQUEST_ERR = 3;
const unsigned short WRONG_DOCUMENT_ERR = 4;
const unsigned short INVALID_CHARACTER_ERR = 5;
const unsigned short NO_DATA_ALLOWED_ERR = 6; // historical
const unsigned short NO_MODIFICATION_ALLOWED_ERR = 7;
const unsigned short NOT_FOUND_ERR = 8;
const unsigned short NOT_SUPPORTED_ERR = 9;
const unsigned short INUSE_ATTRIBUTE_ERR = 10; // historical
const unsigned short INVALID_STATE_ERR = 11;
const unsigned short SYNTAX_ERR = 12;
const unsigned short INVALID_MODIFICATION_ERR = 13;
const unsigned short NAMESPACE_ERR = 14;
const unsigned short INVALID_ACCESS_ERR = 15;
const unsigned short VALIDATION_ERR = 16; // historical
const unsigned short TYPE_MISMATCH_ERR = 17; // historical; use TypeError instead
const unsigned short SECURITY_ERR = 18;
const unsigned short NETWORK_ERR = 19;
const unsigned short ABORT_ERR = 20;
const unsigned short URL_MISMATCH_ERR = 21;
const unsigned short QUOTA_EXCEEDED_ERR = 22;
const unsigned short TIMEOUT_ERR = 23;
const unsigned short INVALID_NODE_TYPE_ERR = 24;
const unsigned short DATA_CLONE_ERR = 25;
unsigned short code;
};
[Constructor(DOMString name)]
interface DOMError {
readonly attribute DOMString name;
@ -451,11 +422,10 @@ interface DOMSettableTokenList : DOMTokenList {
</script>
<script>
"use strict";
var xmlDoc, domException, detachedRange, element;
var xmlDoc, detachedRange, element;
var idlArray;
setup(function() {
xmlDoc = document.implementation.createDocument(null, "", null);
try { document.appendChild(document); } catch(e) { domException = e; }
detachedRange = document.createRange();
detachedRange.detach();
element = xmlDoc.createElementNS(null, "test");
@ -464,7 +434,6 @@ setup(function() {
idlArray = new IdlArray();
idlArray.add_idls(document.querySelector("script[type=text\\/plain]").textContent);
idlArray.add_objects({
DOMException: ['domException'],
Event: ['document.createEvent("Event")', 'new Event("foo")'],
CustomEvent: ['new CustomEvent("foo")'],
XMLDocument: ['xmlDoc'],

File diff suppressed because it is too large Load Diff

View File

@ -32,5 +32,4 @@ MOCHITEST_MANIFESTS += [
'failures/html/microdata/microdata-dom-api/mochitest.ini',
'failures/html/typedarrays/mochitest.ini',
'failures/webapps/WebStorage/tests/submissions/Infraware/mochitest.ini',
'failures/webapps/XMLHttpRequest/tests/submissions/Ms2ger/mochitest.ini',
]

View File

@ -14,11 +14,6 @@ html {
background: red;
}
#log pre {
border: 1px solid black;
padding: 1em;
}
section#summary {
margin-bottom:1em;
}

View File

@ -22,7 +22,8 @@ policies and contribution forms [3].
"normal":10000,
"long":60000
},
test_timeout:null
test_timeout:null,
message_events: ["start", "test_state", "result", "completion"]
};
var xhtml_ns = "http://www.w3.org/1999/xhtml";
@ -64,6 +65,40 @@ policies and contribution forms [3].
this.output_handler = null;
this.all_loaded = false;
var this_obj = this;
this.message_events = [];
this.message_functions = {
start: [add_start_callback, remove_start_callback,
function (properties) {
this_obj._dispatch("start_callback", [properties],
{type: "start", properties: properties});
}],
test_state: [add_test_state_callback, remove_test_state_callback,
function(test) {
this_obj._dispatch("test_state_callback", [test],
{type: "test_state",
test: test.structured_clone()});
}],
result: [add_result_callback, remove_result_callback,
function (test) {
this_obj.output_handler.show_status();
this_obj._dispatch("result_callback", [test],
{type: "result",
test: test.structured_clone()});
}],
completion: [add_completion_callback, remove_completion_callback,
function (tests, harness_status) {
var cloned_tests = map(tests, function(test) {
return test.structured_clone();
});
this_obj._dispatch("completion_callback", [tests, harness_status],
{type: "complete",
tests: cloned_tests,
status: harness_status.structured_clone()});
}]
}
on_event(window, 'load', function() {
this_obj.all_loaded = true;
});
@ -71,13 +106,22 @@ policies and contribution forms [3].
WindowTestEnvironment.prototype._dispatch = function(selector, callback_args, message_arg) {
this._forEach_windows(
function(w, is_same_origin) {
if (is_same_origin && selector in w) {
function(w, same_origin) {
if (same_origin) {
try {
w[selector].apply(undefined, callback_args);
} catch (e) {
if (debug) {
throw e;
var has_selector = selector in w;
} catch(e) {
// If document.domain was set at some point same_origin can be
// wrong and the above will fail.
has_selector = false;
}
if (has_selector) {
try {
w[selector].apply(undefined, callback_args);
} catch (e) {
if (debug) {
throw e;
}
}
}
}
@ -141,30 +185,39 @@ policies and contribution forms [3].
this.output_handler = output;
var this_obj = this;
add_start_callback(function (properties) {
this_obj.output_handler.init(properties);
this_obj._dispatch("start_callback", [properties],
{ type: "start", properties: properties });
});
add_test_state_callback(function(test) {
this_obj.output_handler.show_status();
this_obj._dispatch("test_state_callback", [test],
{ type: "test_state", test: test.structured_clone() });
});
add_result_callback(function (test) {
this_obj.output_handler.show_status();
this_obj._dispatch("result_callback", [test],
{ type: "result", test: test.structured_clone() });
});
add_completion_callback(function (tests, harness_status) {
this_obj.output_handler.show_results(tests, harness_status);
var cloned_tests = map(tests, function(test) { return test.structured_clone(); });
this_obj._dispatch("completion_callback", [tests, harness_status],
{ type: "complete", tests: cloned_tests,
status: harness_status.structured_clone() });
});
this.setup_messages(settings.message_events);
};
WindowTestEnvironment.prototype.setup_messages = function(new_events) {
var this_obj = this;
forEach(settings.message_events, function(x) {
var current_dispatch = this_obj.message_events.indexOf(x) !== -1;
var new_dispatch = new_events.indexOf(x) !== -1;
if (!current_dispatch && new_dispatch) {
this_obj.message_functions[x][0](this_obj.message_functions[x][2]);
} else if (current_dispatch && !new_dispatch) {
this_obj.message_functions[x][1](this_obj.message_functions[x][2]);
}
});
this.message_events = new_events;
}
WindowTestEnvironment.prototype.next_default_test_name = function() {
//Don't use document.title to work around an Opera bug in XHTML documents
var title = document.getElementsByTagName("title")[0];
@ -176,6 +229,9 @@ policies and contribution forms [3].
WindowTestEnvironment.prototype.on_new_harness_properties = function(properties) {
this.output_handler.setup(properties);
if (properties.hasOwnProperty("message_events")) {
this.setup_messages(properties.message_events);
}
};
WindowTestEnvironment.prototype.add_on_loaded_callback = function(callback) {
@ -359,8 +415,20 @@ policies and contribution forms [3].
self.addEventListener("message",
function(event) {
if (event.data.type && event.data.type === "connect") {
this_obj._add_message_port(event.ports[0]);
event.ports[0].start();
if (event.ports && event.ports[0]) {
// If a MessageChannel was passed, then use it to
// send results back to the main window. This
// allows the tests to work even if the browser
// does not fully support MessageEvent.source in
// ServiceWorkers yet.
this_obj._add_message_port(event.ports[0]);
event.ports[0].start();
} else {
// If there is no MessageChannel, then attempt to
// use the MessageEvent.source to send results
// back to the main window.
this_obj._add_message_port(event.source);
}
}
});
@ -464,6 +532,12 @@ policies and contribution forms [3].
}));
}
function promise_rejects(test, expected, promise) {
return promise.then(test.unreached_func("Should have rejected.")).catch(function(e) {
assert_throws(expected, function() { throw e });
});
}
/**
* This constructor helper allows DOM events to be handled using Promises,
* which can make it a lot easier to test a very specific series of events,
@ -579,6 +653,7 @@ policies and contribution forms [3].
expose(test, 'test');
expose(async_test, 'async_test');
expose(promise_test, 'promise_test');
expose(promise_rejects, 'promise_rejects');
expose(generate_tests, 'generate_tests');
expose(setup, 'setup');
expose(done, 'done');
@ -842,7 +917,7 @@ policies and contribution forms [3].
for (var i = 0; i < actual.length; i++) {
assert(actual.hasOwnProperty(i) === expected.hasOwnProperty(i),
"assert_array_equals", description,
"property ${i}, property expected to be $expected but was $actual",
"property ${i}, property expected to be ${expected} but was ${actual}",
{i:i, expected:expected.hasOwnProperty(i) ? "present" : "missing",
actual:actual.hasOwnProperty(i) ? "present" : "missing"});
assert(same_value(expected[i], actual[i]),
@ -933,7 +1008,7 @@ policies and contribution forms [3].
{type_actual:typeof actual});
assert(actual <= expected,
"assert_less_than", description,
"assert_less_than_equal", description,
"expected a number less than or equal to ${expected} but got ${actual}",
{expected:expected, actual:actual});
}
@ -1125,12 +1200,15 @@ policies and contribution forms [3].
InvalidNodeTypeError: 24,
DataCloneError: 25,
EncodingError: 0,
NotReadableError: 0,
UnknownError: 0,
ConstraintError: 0,
DataError: 0,
TransactionInactiveError: 0,
ReadOnlyError: 0,
VersionError: 0
VersionError: 0,
OperationError: 0,
};
if (!(name in name_code_map)) {
@ -1140,7 +1218,10 @@ policies and contribution forms [3].
var required_props = { code: name_code_map[name] };
if (required_props.code === 0 ||
("name" in e && e.name !== e.name.toUpperCase() && e.name !== "DOMException")) {
(typeof e == "object" &&
"name" in e &&
e.name !== e.name.toUpperCase() &&
e.name !== "DOMException")) {
// New style exception: also test the name property.
required_props.name = name;
}
@ -1214,6 +1295,7 @@ policies and contribution forms [3].
}
this.message = null;
this.stack = null;
this.steps = [];
@ -1250,6 +1332,7 @@ policies and contribution forms [3].
}
this._structured_clone.status = this.status;
this._structured_clone.message = this.message;
this._structured_clone.stack = this.stack;
this._structured_clone.index = this.index;
return this._structured_clone;
};
@ -1282,15 +1365,10 @@ policies and contribution forms [3].
if (this.phase >= this.phases.HAS_RESULT) {
return;
}
var message = (typeof e === "object" && e !== null) ? e.message : e;
if (typeof e.stack != "undefined" && typeof e.message == "string") {
//Try to make it more informative for some exceptions, at least
//in Gecko and WebKit. This results in a stack dump instead of
//just errors like "Cannot read property 'parentNode' of null"
//or "root is null". Makes it a lot longer, of course.
message += "(stack: " + e.stack + ")";
}
this.set_status(this.FAIL, message);
var message = String((typeof e === "object" && e !== null) ? e.message : e);
var stack = e.stack ? e.stack : null;
this.set_status(this.FAIL, message, stack);
this.phase = this.phases.HAS_RESULT;
this.done();
}
@ -1356,10 +1434,11 @@ policies and contribution forms [3].
}
};
Test.prototype.set_status = function(status, message)
Test.prototype.set_status = function(status, message, stack)
{
this.status = status;
this.message = message;
this.stack = stack ? stack : null;
};
Test.prototype.timeout = function()
@ -1416,13 +1495,13 @@ policies and contribution forms [3].
RemoteTest.prototype.structured_clone = function() {
var clone = {};
Object.keys(this).forEach(
function(key) {
(function(key) {
if (typeof(this[key]) === "object") {
clone[key] = merge({}, this[key]);
} else {
clone[key] = this[key];
}
});
}).bind(this));
clone.phases = merge({}, this.phases);
return clone;
};
@ -1432,6 +1511,7 @@ policies and contribution forms [3].
RemoteTest.prototype.update_state_from = function(clone) {
this.status = clone.status;
this.message = clone.message;
this.stack = clone.stack;
if (this.phase === this.phases.INITIAL) {
this.phase = this.phases.STARTED;
}
@ -1455,15 +1535,24 @@ policies and contribution forms [3].
var message_port;
if (is_service_worker(worker)) {
// The ServiceWorker's implicit MessagePort is currently not
// reliably accessible from the ServiceWorkerGlobalScope due to
// Blink setting MessageEvent.source to null for messages sent via
// ServiceWorker.postMessage(). Until that's resolved, create an
// explicit MessageChannel and pass one end to the worker.
var message_channel = new MessageChannel();
message_port = message_channel.port1;
message_port.start();
worker.postMessage({type: "connect"}, [message_channel.port2]);
if (window.MessageChannel) {
// The ServiceWorker's implicit MessagePort is currently not
// reliably accessible from the ServiceWorkerGlobalScope due to
// Blink setting MessageEvent.source to null for messages sent
// via ServiceWorker.postMessage(). Until that's resolved,
// create an explicit MessageChannel and pass one end to the
// worker.
var message_channel = new MessageChannel();
message_port = message_channel.port1;
message_port.start();
worker.postMessage({type: "connect"}, [message_channel.port2]);
} else {
// If MessageChannel is not available, then try the
// ServiceWorker.postMessage() approach using MessageEvent.source
// on the other end.
message_port = navigator.serviceWorker;
worker.postMessage({type: "connect"});
}
} else if (is_shared_worker(worker)) {
message_port = worker.port;
} else {
@ -1491,7 +1580,8 @@ policies and contribution forms [3].
this.worker_done({
status: {
status: tests.status.ERROR,
message: "Error in worker" + filename + ": " + message
message: "Error in worker" + filename + ": " + message,
stack: error.stack
}
});
error.preventDefault();
@ -1519,6 +1609,7 @@ policies and contribution forms [3].
data.status.status !== data.status.OK) {
tests.status.status = data.status.status;
tests.status.message = data.status.message;
tests.status.stack = data.status.stack;
}
this.running = false;
this.worker = null;
@ -1541,6 +1632,7 @@ policies and contribution forms [3].
{
this.status = null;
this.message = null;
this.stack = null;
}
TestsStatus.statuses = {
@ -1558,7 +1650,8 @@ policies and contribution forms [3].
msg = msg ? String(msg) : msg;
this._structured_clone = merge({
status:this.status,
message:msg
message:msg,
stack:this.stack
}, TestsStatus.statuses);
}
return this._structured_clone;
@ -1648,6 +1741,7 @@ policies and contribution forms [3].
} catch (e) {
this.status.status = this.status.ERROR;
this.status.message = String(e);
this.status.stack = e.stack ? e.stack : null;
}
}
this.set_timeout();
@ -1811,14 +1905,12 @@ policies and contribution forms [3].
tests.test_state_callbacks.push(callback);
}
function add_result_callback(callback)
{
function add_result_callback(callback) {
tests.test_done_callbacks.push(callback);
}
function add_completion_callback(callback)
{
tests.all_done_callbacks.push(callback);
function add_completion_callback(callback) {
tests.all_done_callbacks.push(callback);
}
expose(add_start_callback, 'add_start_callback');
@ -1826,6 +1918,29 @@ policies and contribution forms [3].
expose(add_result_callback, 'add_result_callback');
expose(add_completion_callback, 'add_completion_callback');
function remove(array, item) {
var index = array.indexOf(item);
if (index > -1) {
array.splice(index, 1);
}
}
function remove_start_callback(callback) {
remove(tests.start_callbacks, callback);
}
function remove_test_state_callback(callback) {
remove(tests.test_state_callbacks, callback);
}
function remove_result_callback(callback) {
remove(tests.test_done_callbacks, callback);
}
function remove_completion_callback(callback) {
remove(tests.all_done_callbacks, callback);
}
/*
* Output listener
*/
@ -2005,6 +2120,9 @@ policies and contribution forms [3].
if (harness_status.status === harness_status.ERROR) {
rv[0].push(["pre", {}, harness_status.message]);
if (harness_status.stack) {
rv[0].push(["pre", {}, harness_status.stack]);
}
}
return rv;
},
@ -2102,6 +2220,9 @@ policies and contribution forms [3].
"</td><td>" +
(assertions ? escape_html(get_assertion(tests[i])) + "</td><td>" : "") +
escape_html(tests[i].message ? tests[i].message : " ") +
(tests[i].stack ? "<pre>" +
escape_html(tests[i].stack) +
"</pre>": "") +
"</td></tr>";
}
html += "</tbody></table>";
@ -2297,11 +2418,34 @@ policies and contribution forms [3].
function AssertionError(message)
{
this.message = message;
this.stack = this.get_stack();
}
AssertionError.prototype.toString = function() {
return this.message;
};
AssertionError.prototype = Object.create(Error.prototype);
AssertionError.prototype.get_stack = function() {
var stack = new Error().stack;
if (!stack) {
try {
throw new Error();
} catch (e) {
stack = e.stack;
}
}
var lines = stack.split("\n");
var rv = [];
var re = /\/resources\/testharness\.js/;
var i = 0;
// Fire remove any preamble that doesn't match the regexp
while (!re.test(lines[i])) {
i++
}
// Then remove top frames in testharness.js itself
while (re.test(lines[i])) {
i++
}
return lines.slice(i).join("\n");
}
function make_message(function_name, description, error, substitutions)
{
@ -2440,14 +2584,14 @@ policies and contribution forms [3].
if (test.phase >= test.phases.HAS_RESULT) {
return;
}
var message = e.message;
test.set_status(test.FAIL, message);
test.set_status(test.FAIL, e.message, e.stack);
test.phase = test.phases.HAS_RESULT;
test.done();
done();
} else if (!tests.allow_uncaught_exception) {
tests.status.status = tests.status.ERROR;
tests.status.message = e.message;
tests.status.stack = e.stack;
}
});