diff options
Diffstat (limited to 'testing/web-platform/tests/html/dom/original-harness.js')
-rw-r--r-- | testing/web-platform/tests/html/dom/original-harness.js | 339 |
1 files changed, 339 insertions, 0 deletions
diff --git a/testing/web-platform/tests/html/dom/original-harness.js b/testing/web-platform/tests/html/dom/original-harness.js new file mode 100644 index 0000000000..89a8067033 --- /dev/null +++ b/testing/web-platform/tests/html/dom/original-harness.js @@ -0,0 +1,339 @@ +var ReflectionHarness = {}; + +// @private +ReflectionHarness.passed = document.getElementById("passed"); +ReflectionHarness.failed = document.getElementById("failed"); + +/** + * In conformance testing mode, all tests will be run. Otherwise, we'll skip + * tests for attributes that have an entirely incorrect type. + */ +ReflectionHarness.conformanceTesting = false; + +/** + * Returns a string representing val. Basically just adds quotes for strings, + * and passes through other recognized types literally. + * + * @public + */ +ReflectionHarness.stringRep = function(val) { + if (val === null) { + // typeof is object, so the switch isn't useful + return "null"; + } + // In JavaScript, -0 === 0 and String(-0) == "0", so we have to + // special-case. + if (val === -0 && 1/val === -Infinity) { + return "-0"; + } + switch (typeof val) { + case "string": + for (var i = 0; i < 32; i++) { + var replace = "\\"; + switch (i) { + case 0: replace += "0"; break; + case 1: replace += "x01"; break; + case 2: replace += "x02"; break; + case 3: replace += "x03"; break; + case 4: replace += "x04"; break; + case 5: replace += "x05"; break; + case 6: replace += "x06"; break; + case 7: replace += "x07"; break; + case 8: replace += "b"; break; + case 9: replace += "t"; break; + case 10: replace += "n"; break; + case 11: replace += "v"; break; + case 12: replace += "f"; break; + case 13: replace += "r"; break; + case 14: replace += "x0e"; break; + case 15: replace += "x0f"; break; + case 16: replace += "x10"; break; + case 17: replace += "x11"; break; + case 18: replace += "x12"; break; + case 19: replace += "x13"; break; + case 20: replace += "x14"; break; + case 21: replace += "x15"; break; + case 22: replace += "x16"; break; + case 23: replace += "x17"; break; + case 24: replace += "x18"; break; + case 25: replace += "x19"; break; + case 26: replace += "x1a"; break; + case 27: replace += "x1b"; break; + case 28: replace += "x1c"; break; + case 29: replace += "x1d"; break; + case 30: replace += "x1e"; break; + case 31: replace += "x1f"; break; + } + val = val.replace(String.fromCharCode(i), replace); + } + return '"' + val.replace('"', '\\"') + '"'; + case "boolean": + case "undefined": + case "number": + return val + ""; + default: + return typeof val + ' "' + val + '"'; + } +} + +/** + * An object representing info about the current test, used for printing out + * nice messages and so forth. + */ +ReflectionHarness.currentTestInfo = {}; + +/** + * .test() sets this, and it's used by .assertEquals()/.assertThrows(). + * Calling .test() recursively is an error. + */ +ReflectionHarness.currentTestDescription = null; + +/** + * Run a group of one or more assertions. If any exceptions are thrown, catch + * them and report a failure. + */ +ReflectionHarness.test = function(fn, description) { + if (this.currentTestDescription) { + throw "TEST BUG: test() may not be called recursively!"; + } + this.currentTestDescription = description; + try { + fn(); + // Not throwing is a success + this.success(); + } catch(err) { + this.failure("Exception thrown during tests with " + description); + } + this.currentTestDescription = null; +} + +/** + * If question === answer, output a success, else report a failure with the + * given description. Currently success and failure both increment counters, + * and failures output a message to a <ul>. Which <ul> is decided by the type + * parameter -- different attribute types are separated for readability. + * + * @public + */ +ReflectionHarness.assertEquals = function(expected, actual, description) { + // Special-case -0 yay! + if (expected === 0 && actual === 0 && 1/expected === 1/actual) { + this.increment(this.passed); + } else if (expected === actual) { + this.increment(this.passed); + } else { + this.increment(this.failed); + this.reportFailure(this.currentTestDescription + + (description ? " followed by " + description : "") + + ' (expected ' + this.stringRep(actual) + ', got ' + + this.stringRep(expected) + ')'); + } +} + +/** + * If calling fn causes a DOMException of the type given by the string + * exceptionName (e.g., "IndexSizeError"), output a success. Otherwise, report + * a failure. + * + * @public + */ +ReflectionHarness.assertThrows = function(exceptionName, fn) { + try { + fn(); + } catch (e) { + if (e instanceof DOMException && (e.code == DOMException[exceptionName] || + e.name == exceptionName)) { + this.increment(this.passed); + return true; + } + } + this.increment(this.failed); + this.reportFailure(this.currentTestDescription + " must throw " + + exceptionName); + return false; +} + +/** + * Get a description of the current type, e.g., "a.href". + */ +ReflectionHarness.getTypeDescription = function() { + var domNode = this.currentTestInfo.domObj.tagName.toLowerCase(); + var idlNode = this.currentTestInfo.idlObj.nodeName.toLowerCase(); + var domName = this.currentTestInfo.domName; + var idlName = this.currentTestInfo.idlName; + var comment = this.currentTestInfo.data.comment; + var typeDesc = idlNode + "." + idlName; + if (!comment && (domNode != idlNode || domName != idlName)) { + comment = "<" + domNode + " " + domName + ">"; + } + if (comment) { + typeDesc += " (" + comment + ")"; + } + return typeDesc; +} + +/** + * Report a failure with the given description, adding context from the + * currentTestInfo member. + * + * @private + */ +ReflectionHarness.reportFailure = function(description) { + var typeDesc = this.getTypeDescription(); + var idlName = this.currentTestInfo.idlName; + var comment = this.currentTestInfo.data.comment; + typeDesc = typeDesc.replace("&", "&").replace("<", "<"); + description = description.replace("&", "&").replace("<", "<"); + + var type = this.currentTestInfo.data.type; + + // Special case for undefined attributes, which we don't want getting in + // the way of everything else. + if (description.search('^typeof IDL attribute \\(expected ".*", got "undefined"\\)$') != -1) { + type = "undefined"; + } + + var done = false; + var ul = document.getElementById("errors-" + type.replace(" ", "-")); + if (ul === null) { + ul = document.createElement("ul"); + ul.id = "errors-" + type.replace(" ", "-"); + var div = document.getElementById("errors"); + p = document.createElement("p"); + if (type == "undefined") { + div.parentNode.insertBefore(ul, div.nextSibling); + p.innerHTML = "These IDL attributes were of undefined type, presumably representing unimplemented features (cordoned off into a separate section for tidiness):"; + } else { + div.appendChild(ul); + p.innerHTML = "Errors for type " + type + ":"; + } + ul.parentNode.insertBefore(p, ul); + } else if (type != "undefined") { + var existingErrors = ul.getElementsByClassName("desc"); + for (var i = 0; i < existingErrors.length; i++) { + if (existingErrors[i].innerHTML == description) { + var typeSpan = existingErrors[i].parentNode.getElementsByClassName("type")[0]; + // Check if we have lots of the same error for the same + // attribute. If so, we want to collapse them -- the exact + // elements that exhibit the error aren't going to be important + // to report in this case, and it can take a lot of space if + // there's an error in a global attribute like dir or id. + var types = typeSpan.innerHTML.split(", "); + var count = 0; + for (var i = 0; i < types.length; i++) { + if (types[i].search("^\\([0-9]* elements\\)\\." + idlName + "$") != -1) { + types[i] = "(" + (1 + parseInt(/[0-9]+/.exec(types[i])[0])) + " elements)." + idlName; + typeSpan.innerHTML = types.join(", "); + return; + } else if (types[i].search("\\." + idlName + "$") != -1) { + count++; + } + } + if (comment || count < 10) { + // Just add the extra error to the end, not many duplicates + // (or we have a comment) + typeSpan.innerHTML += ", " + typeDesc; + } else { + var filteredTypes = types.filter(function(type) { return type.search("\\." + idlName + "$") == -1; }); + if (filteredTypes.length) { + typeSpan.innerHTML = filteredTypes.join(", ") + ", "; + } else { + typeSpan.innerHTML = ""; + } + typeSpan.innerHTML += "(" + (types.length - filteredTypes.length) + " elements)." + idlName; + } + return; + } + } + } + + if (type == "undefined") { + ul.innerHTML += "<li>" + typeDesc; + } else { + ul.innerHTML += "<li><span class=\"type\">" + typeDesc + "</span>: <span class=\"desc\">" + description + "</span>"; + } +} + +/** + * Shorthand function for when we have a failure outside of + * assertEquals()/assertThrows(). Generally used when the failure is an + * exception thrown unexpectedly or such, something not equality-based. + * + * @public + */ +ReflectionHarness.failure = function(message) { + this.increment(this.failed); + this.reportFailure(message); +} + +/** + * Shorthand function for when we have a success outside of + * assertEquals()/assertThrows(). + * + * @public + */ +ReflectionHarness.success = function() { + this.increment(this.passed); +} + +/** + * Increment the count in either "passed" or "failed". el should always be one + * of those two variables. The implementation of this function amuses me. + * + * @private + */ +ReflectionHarness.increment = function(el) { + el.innerHTML = parseInt(el.innerHTML) + 1; + var percent = document.getElementById("percent"); + var passed = document.getElementById("passed"); + var failed = document.getElementById("failed"); + percent.innerHTML = (parseInt(passed.innerHTML)/(parseInt(passed.innerHTML) + parseInt(failed.innerHTML))*100).toPrecision(3); +} + +/** + * Hide all displayed errors matching a given regex, so it's easier to filter + * out repetitive failures. TODO: Fix this so it works right with the new + * "lump many errors in one <li>" thing. + * + * @private (kind of, only called in the original reflection.html) + */ +ReflectionHarness.maskErrors = function(regex) { + var uls = document.getElementsByTagName("ul"); + for (var i = 0; i < uls.length; i++) { + var lis = uls[i].children; + for (var j = 0; j < lis.length; j++) { + if (regex !== "" && lis[j].innerHTML.match(regex)) { + lis[j].style.display = "none"; + } else { + lis[j].style.display = "list-item"; + } + } + } +} + +// Now for some stuff that has nothing to do with ReflectionHarness and +// everything to do with initialization needed for reflection.js, which seems +// pointless to put in an extra file. + +var elements = {}; + +var extraTests = []; + +/** + * Used for combining a number of small arrays of element data into one big + * one. + */ +function mergeElements(src) { + for (var key in src) { + if (!src.hasOwnProperty(key)) { + // This is inherited from a prototype or something. + continue; + } + + if (key in elements) { + elements[key] = elements[key].concat(src[key]); + } else { + elements[key] = src[key]; + } + } +} |