michael@0: /* michael@0: Copyright (c) 2001-2005 World Wide Web Consortium, michael@0: (Massachusetts Institute of Technology, Institut National de michael@0: Recherche en Informatique et en Automatique, Keio University). All michael@0: Rights Reserved. This program is distributed under the W3C's Software michael@0: Intellectual Property License. This program is distributed in the michael@0: hope that it will be useful, but WITHOUT ANY WARRANTY; without even michael@0: the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR michael@0: PURPOSE. michael@0: See W3C License http://www.w3.org/Consortium/Legal/ for more details. michael@0: */ michael@0: michael@0: function assertNull(descr, actual) { michael@0: return ok(actual === null, descr); michael@0: } michael@0: michael@0: michael@0: function assertNotNull(descr, actual) { michael@0: return ok(actual !== null, descr); michael@0: } michael@0: michael@0: function assertTrue(descr, actual) { michael@0: return ok(actual === true, descr); michael@0: } michael@0: michael@0: function assertFalse(descr, actual) { michael@0: return ok(actual === false, descr); michael@0: } michael@0: michael@0: function assertEquals(descr, expected, actual) { michael@0: return is(expected, actual, descr); michael@0: } michael@0: michael@0: function assertSize(descr, expected, actual) { michael@0: ok(actual !== null, descr); michael@0: /* michael@0: // Work around too strict checks. michael@0: if (!actual) { michael@0: ok(actual, "[assertSize()] 'actual' has a value"); michael@0: return; michael@0: } michael@0: */ michael@0: michael@0: is(actual.length, expected, descr); michael@0: } michael@0: michael@0: function assertEqualsAutoCase(context, descr, expected, actual) { michael@0: if (builder.contentType == "text/html") { michael@0: if(context == "attribute") { michael@0: is(actual.toLowerCase(), expected.toLowerCase(), descr); michael@0: } else { michael@0: is(actual, expected.toUpperCase(), descr); michael@0: } michael@0: } else { michael@0: is(expected, actual, descr); michael@0: } michael@0: } michael@0: michael@0: michael@0: function assertEqualsCollectionAutoCase(context, descr, expected, actual) { michael@0: // michael@0: // if they aren't the same size, they aren't equal michael@0: is(actual.length, expected.length, descr); michael@0: michael@0: // michael@0: // if there length is the same, then every entry in the expected list michael@0: // must appear once and only once in the actual list michael@0: var expectedLen = expected.length; michael@0: var expectedValue; michael@0: var actualLen = actual.length; michael@0: var i; michael@0: var j; michael@0: var matches; michael@0: for(i = 0; i < expectedLen; i++) { michael@0: matches = 0; michael@0: expectedValue = expected[i]; michael@0: for(j = 0; j < actualLen; j++) { michael@0: if (builder.contentType == "text/html") { michael@0: if (context == "attribute") { michael@0: if (expectedValue.toLowerCase() == actual[j].toLowerCase()) { michael@0: matches++; michael@0: } michael@0: } else { michael@0: if (expectedValue.toUpperCase() == actual[j]) { michael@0: matches++; michael@0: } michael@0: } michael@0: } else { michael@0: if(expectedValue == actual[j]) { michael@0: matches++; michael@0: } michael@0: } michael@0: } michael@0: if(matches == 0) { michael@0: ok(false, descr + ": No match found for " + expectedValue); michael@0: } michael@0: if(matches > 1) { michael@0: ok(false, descr + ": Multiple matches found for " + expectedValue); michael@0: } michael@0: } michael@0: } michael@0: michael@0: function assertEqualsCollection(descr, expected, actual) { michael@0: // michael@0: // if they aren't the same size, they aren't equal michael@0: is(actual.length, expected.length, descr); michael@0: // michael@0: // if there length is the same, then every entry in the expected list michael@0: // must appear once and only once in the actual list michael@0: var expectedLen = expected.length; michael@0: var expectedValue; michael@0: var actualLen = actual.length; michael@0: var i; michael@0: var j; michael@0: var matches; michael@0: for(i = 0; i < expectedLen; i++) { michael@0: matches = 0; michael@0: expectedValue = expected[i]; michael@0: for(j = 0; j < actualLen; j++) { michael@0: if(expectedValue == actual[j]) { michael@0: matches++; michael@0: } michael@0: } michael@0: if(matches == 0) { michael@0: ok(false, descr + ": No match found for " + expectedValue); michael@0: } michael@0: if(matches > 1) { michael@0: ok(false, descr + ": Multiple matches found for " + expectedValue); michael@0: } michael@0: } michael@0: } michael@0: michael@0: michael@0: function assertEqualsListAutoCase(context, descr, expected, actual) { michael@0: var minLength = expected.length; michael@0: if (actual.length < minLength) { michael@0: minLength = actual.length; michael@0: } michael@0: // michael@0: for(var i = 0; i < minLength; i++) { michael@0: assertEqualsAutoCase(context, descr, expected[i], actual[i]); michael@0: } michael@0: // michael@0: // if they aren't the same size, they aren't equal michael@0: is(actual.length, expected.length, descr); michael@0: } michael@0: michael@0: michael@0: function assertEqualsList(descr, expected, actual) { michael@0: var minLength = expected.length; michael@0: if (actual.length < minLength) { michael@0: minLength = actual.length; michael@0: } michael@0: // michael@0: for(var i = 0; i < minLength; i++) { michael@0: if(expected[i] != actual[i]) { michael@0: is(actual[i], expected[i], descr); michael@0: } michael@0: } michael@0: // michael@0: // if they aren't the same size, they aren't equal michael@0: is(actual.length, expected.length, descr); michael@0: } michael@0: michael@0: function assertInstanceOf(descr, type, obj) { michael@0: if(type == "Attr") { michael@0: is(2, obj.nodeType, descr); michael@0: var specd = obj.specified; michael@0: } michael@0: /* michael@0: else { michael@0: // Ensure at least one SimpleTest check is reported. (Bug 483992) michael@0: todo_is(type, "Attr", "[DOMTestCase.assertInstanceOf()] Fake default check."); michael@0: } michael@0: */ michael@0: } michael@0: michael@0: function assertSame(descr, expected, actual) { michael@0: if(expected != actual) { michael@0: is(expected.nodeType, actual.nodeType, descr); michael@0: is(expected.nodeValue, actual.nodeValue, descr); michael@0: } michael@0: /* michael@0: else { michael@0: // Ensure at least one SimpleTest check is reported. (Bug 483992) michael@0: todo_isnot(expected, actual, "[DOMTestCase.assertSame()] Fake default check." + michael@0: " (Type=" + actual.nodeType + ", Value=" + actual.nodeValue + ")"); michael@0: } michael@0: */ michael@0: } michael@0: michael@0: function assertURIEquals(assertID, scheme, path, host, file, name, query, fragment, isAbsolute, actual) { michael@0: // michael@0: // URI must be non-null michael@0: ok(assertID, "[assertURIEquals()] 'assertID' has a value"); michael@0: ok(actual, "[assertURIEquals()] 'actual' has a value"); michael@0: /* michael@0: // Add missing early return. michael@0: if (!actual) michael@0: return; michael@0: */ michael@0: michael@0: var uri = actual; michael@0: michael@0: var lastPound = actual.lastIndexOf("#"); michael@0: var actualFragment = ""; michael@0: if(lastPound != -1) { michael@0: // michael@0: // substring before pound michael@0: // michael@0: uri = actual.substring(0,lastPound); michael@0: actualFragment = actual.substring(lastPound+1); michael@0: } michael@0: if(fragment != null) is(actualFragment, fragment, assertID); michael@0: michael@0: var lastQuestion = uri.lastIndexOf("?"); michael@0: var actualQuery = ""; michael@0: if(lastQuestion != -1) { michael@0: // michael@0: // substring before pound michael@0: // michael@0: uri = actual.substring(0,lastQuestion); michael@0: actualQuery = actual.substring(lastQuestion+1); michael@0: } michael@0: if(query != null) is(actualQuery, query, assertID); michael@0: michael@0: var firstColon = uri.indexOf(":"); michael@0: var firstSlash = uri.indexOf("/"); michael@0: var actualPath = uri; michael@0: var actualScheme = ""; michael@0: if(firstColon != -1 && firstColon < firstSlash) { michael@0: actualScheme = uri.substring(0,firstColon); michael@0: actualPath = uri.substring(firstColon + 1); michael@0: } michael@0: michael@0: if(scheme != null) { michael@0: is(scheme, actualScheme, assertID); michael@0: } michael@0: michael@0: if(path != null) { michael@0: is(path, actualPath, assertID); michael@0: } michael@0: michael@0: if(host != null) { michael@0: var actualHost = ""; michael@0: if(actualPath.substring(0,2) == "//") { michael@0: var termSlash = actualPath.substring(2).indexOf("/") + 2; michael@0: actualHost = actualPath.substring(0,termSlash); michael@0: } michael@0: is(actualHost, host, assertID); michael@0: } michael@0: michael@0: if(file != null || name != null) { michael@0: var actualFile = actualPath; michael@0: var finalSlash = actualPath.lastIndexOf("/"); michael@0: if(finalSlash != -1) { michael@0: actualFile = actualPath.substring(finalSlash+1); michael@0: } michael@0: if (file != null) { michael@0: is(actualFile, file, assertID); michael@0: } michael@0: if (name != null) { michael@0: var actualName = actualFile; michael@0: var finalDot = actualFile.lastIndexOf("."); michael@0: if (finalDot != -1) { michael@0: actualName = actualName.substring(0, finalDot); michael@0: } michael@0: is(actualName, name, assertID); michael@0: } michael@0: } michael@0: michael@0: if(isAbsolute != null) { michael@0: is(actualPath.substring(0,1) == "/", isAbsolute, assertID); michael@0: } michael@0: } michael@0: michael@0: michael@0: // size() used by assertSize element michael@0: function size(collection) michael@0: { michael@0: return collection.length; michael@0: } michael@0: michael@0: function same(expected, actual) michael@0: { michael@0: return expected === actual; michael@0: } michael@0: michael@0: function getSuffix(contentType) { michael@0: switch(contentType) { michael@0: case "text/html": michael@0: return ".html"; michael@0: michael@0: case "text/xml": michael@0: return ".xml"; michael@0: michael@0: case "application/xhtml+xml": michael@0: return ".xhtml"; michael@0: michael@0: case "image/svg+xml": michael@0: return ".svg"; michael@0: michael@0: case "text/mathml": michael@0: return ".mml"; michael@0: } michael@0: return ".html"; michael@0: } michael@0: michael@0: function equalsAutoCase(context, expected, actual) { michael@0: if (builder.contentType == "text/html") { michael@0: if (context == "attribute") { michael@0: return expected.toLowerCase() == actual; michael@0: } michael@0: return expected.toUpperCase() == actual; michael@0: } michael@0: return expected == actual; michael@0: } michael@0: michael@0: function catchInitializationError(blder, ex) { michael@0: if (blder == null) { michael@0: alert(ex); michael@0: } else { michael@0: blder.initializationError = ex; michael@0: blder.initializationFatalError = ex; michael@0: } michael@0: } michael@0: michael@0: function checkInitialization(blder, testname) { michael@0: if (blder.initializationError != null) { michael@0: // Fake a "warn()" function, as it was missing :-| michael@0: function warn(msg) { michael@0: info("[checkInitialization() warning] " + msg); michael@0: } michael@0: michael@0: if (blder.skipIncompatibleTests) { michael@0: warn(testname + " not run:" + blder.initializationError); michael@0: return blder.initializationError; michael@0: } else { michael@0: // michael@0: // if an exception was thrown michael@0: // rethrow it and do not run the test michael@0: if (blder.initializationFatalError != null) { michael@0: throw blder.initializationFatalError; michael@0: } else { michael@0: // michael@0: // might be recoverable, warn but continue the test michael@0: warn(testname + ": " + blder.initializationError); michael@0: } michael@0: } michael@0: } michael@0: return null; michael@0: } michael@0: function createTempURI(scheme) { michael@0: if (scheme == "http") { michael@0: return "http://localhost:8080/webdav/tmp" + Math.floor(Math.random() * 100000) + ".xml"; michael@0: } michael@0: return "file:///tmp/domts" + Math.floor(Math.random() * 100000) + ".xml"; michael@0: } michael@0: michael@0: michael@0: function EventMonitor() { michael@0: this.atEvents = new Array(); michael@0: this.bubbledEvents = new Array(); michael@0: this.capturedEvents = new Array(); michael@0: this.allEvents = new Array(); michael@0: } michael@0: michael@0: EventMonitor.prototype.handleEvent = function(evt) { michael@0: switch(evt.eventPhase) { michael@0: case 1: michael@0: monitor.capturedEvents[monitor.capturedEvents.length] = evt; michael@0: break; michael@0: michael@0: case 2: michael@0: monitor.atEvents[monitor.atEvents.length] = evt; michael@0: break; michael@0: michael@0: case 3: michael@0: monitor.bubbledEvents[monitor.bubbledEvents.length] = evt; michael@0: break; michael@0: } michael@0: monitor.allEvents[monitor.allEvents.length] = evt; michael@0: } michael@0: michael@0: function DOMErrorImpl(err) { michael@0: this.severity = err.severity; michael@0: this.message = err.message; michael@0: this.type = err.type; michael@0: this.relatedException = err.relatedException; michael@0: this.relatedData = err.relatedData; michael@0: this.location = err.location; michael@0: } michael@0: michael@0: michael@0: michael@0: function DOMErrorMonitor() { michael@0: this.allErrors = new Array(); michael@0: } michael@0: michael@0: DOMErrorMonitor.prototype.handleError = function(err) { michael@0: errorMonitor.allErrors[errorMonitor.allErrors.length] = new DOMErrorImpl(err); michael@0: } michael@0: michael@0: DOMErrorMonitor.prototype.assertLowerSeverity = function(id, severity) { michael@0: var i; michael@0: for (i = 0; i < errorMonitor.allErrors.length; i++) { michael@0: if (errorMonitor.allErrors[i].severity >= severity) { michael@0: assertEquals(id, severity - 1, errorMonitor.allErrors[i].severity); michael@0: } michael@0: } michael@0: } michael@0: michael@0: function UserDataNotification(operation, key, data, src, dst) { michael@0: this.operation = operation; michael@0: this.key = key; michael@0: this.data = data; michael@0: this.src = src; michael@0: this.dst = dst; michael@0: } michael@0: michael@0: function UserDataMonitor() { michael@0: this.allNotifications = new Array(); michael@0: } michael@0: michael@0: UserDataMonitor.prototype.handle = function(operation, key, data, src, dst) { michael@0: userDataMonitor.allNotifications[this.allNotifications.length] = michael@0: new UserDataNotification(operation, key, data, src, dst); michael@0: } michael@0: michael@0: michael@0: michael@0: function IFrameBuilder() { michael@0: this.contentType = "text/html"; michael@0: this.supportedContentTypes = [ "text/html", michael@0: "text/xml", michael@0: "image/svg+xml", michael@0: "application/xhtml+xml" ]; michael@0: michael@0: this.supportsAsyncChange = false; michael@0: this.async = true; michael@0: this.fixedAttributeNames = [ michael@0: "validating", "expandEntityReferences", "coalescing", michael@0: "signed", "hasNullString", "ignoringElementContentWhitespace", "namespaceAware", "ignoringComments", "schemaValidating"]; michael@0: michael@0: this.fixedAttributeValues = [false, true, false, true, true , false, false, true, false ]; michael@0: this.configurableAttributeNames = [ ]; michael@0: this.configurableAttributeValues = [ ]; michael@0: this.initializationError = null; michael@0: this.initializationFatalError = null; michael@0: this.skipIncompatibleTests = false; michael@0: } michael@0: michael@0: IFrameBuilder.prototype.hasFeature = function(feature, version) { michael@0: return document.implementation.hasFeature(feature, version); michael@0: } michael@0: michael@0: IFrameBuilder.prototype.getImplementation = function() { michael@0: return document.implementation; michael@0: } michael@0: michael@0: IFrameBuilder.prototype.setContentType = function(contentType) { michael@0: this.contentType = contentType; michael@0: if (contentType == "text/html") { michael@0: this.fixedAttributeValues[6] = false; michael@0: } else { michael@0: this.fixedAttributeValues[6] = true; michael@0: } michael@0: } michael@0: michael@0: michael@0: michael@0: IFrameBuilder.prototype.preload = function(frame, varname, url) { michael@0: var suffix; michael@0: if (this.contentType == "text/html" || michael@0: this.contentType == "application/xhtml+xml") { michael@0: if (url.substring(0,5) == "staff" || url == "nodtdstaff" || michael@0: url == "datatype_normalization") { michael@0: suffix = ".xml"; michael@0: } michael@0: } michael@0: michael@0: if (!suffix) suffix = getSuffix(this.contentType); michael@0: michael@0: var iframe = document.createElement("iframe"); michael@0: var srcname = url + suffix; michael@0: iframe.setAttribute("name", srcname); michael@0: iframe.setAttribute("src", fileBase + srcname); michael@0: // michael@0: // HTML and XHTML have onload attributes that will invoke loadComplete michael@0: // michael@0: if (suffix.indexOf("html") < 0) { michael@0: iframe.addEventListener("load", loadComplete, false); michael@0: } michael@0: document.getElementsByTagName("body").item(0).appendChild(iframe); michael@0: return 0; michael@0: } michael@0: michael@0: IFrameBuilder.prototype.load = function(frame, varname, url) { michael@0: var suffix; michael@0: if (url.substring(0,5) == "staff" || url == "nodtdstaff" || url == "datatype_normalization") { michael@0: suffix = ".xml"; michael@0: } michael@0: if (!suffix) suffix = getSuffix(this.contentType); michael@0: var name = url + suffix; michael@0: var iframes = document.getElementsByTagName("iframe"); michael@0: for(var i = 0; i < iframes.length; i++) { michael@0: if (iframes.item(i).getAttribute("name") == name) { michael@0: var item = iframes.item(i); michael@0: if (typeof(item.contentDocument) != 'undefined') { michael@0: return item.contentDocument; michael@0: } michael@0: if (typeof(item.document) != 'undefined') { michael@0: return item.document; michael@0: } michael@0: return null; michael@0: } michael@0: } michael@0: return null; michael@0: } michael@0: michael@0: IFrameBuilder.prototype.getImplementationAttribute = function(attr) { michael@0: for (var i = 0; i < this.fixedAttributeNames.length; i++) { michael@0: if (this.fixedAttributeNames[i] == attr) { michael@0: return this.fixedAttributeValues[i]; michael@0: } michael@0: } michael@0: throw "Unrecognized implementation attribute: " + attr; michael@0: } michael@0: michael@0: michael@0: michael@0: IFrameBuilder.prototype.setImplementationAttribute = function(attribute, value) { michael@0: var supported = this.getImplementationAttribute(attribute); michael@0: if (supported != value) { michael@0: this.initializationError = "IFrame loader does not support " + attribute + "=" + value; michael@0: } michael@0: } michael@0: michael@0: michael@0: IFrameBuilder.prototype.canSetImplementationAttribute = function(attribute, value) { michael@0: var supported = this.getImplementationAttribute(attribute); michael@0: return (supported == value); michael@0: } michael@0: michael@0: michael@0: function createBuilder(implementation) { michael@0: if (implementation == null) { michael@0: return new IFrameBuilder(); michael@0: } michael@0: switch(implementation) { michael@0: /* case "msxml3": michael@0: return new MSXMLBuilder("Msxml2.DOMDocument.3.0"); michael@0: michael@0: case "msxml4": michael@0: return new MSXMLBuilder("Msxml2.DOMDocument.4.0");*/ michael@0: michael@0: case "mozillaXML": michael@0: return new MozillaXMLBuilder(); michael@0: /* michael@0: case "svgplugin": michael@0: return new SVGPluginBuilder(); michael@0: michael@0: case "dom3ls": michael@0: return new DOM3LSBuilder(); */ michael@0: michael@0: case "iframe": michael@0: return new IFrameBuilder(); michael@0: michael@0: case "xmlhttprequest": michael@0: return new XMLHttpRequestBuilder(); michael@0: michael@0: default: michael@0: alert ("unrecognized implementation " + implementation); michael@0: } michael@0: return new IFrameBuilder(); michael@0: } michael@0: michael@0: function checkFeature(feature, version) michael@0: { michael@0: if (!builder.hasFeature(feature, version)) michael@0: { michael@0: // michael@0: // don't throw exception so that users can select to ignore the precondition michael@0: // michael@0: builder.initializationError = "builder does not support feature " + feature + " version " + version; michael@0: } michael@0: } michael@0: michael@0: function createConfiguredBuilder() { michael@0: var builder = null; michael@0: var contentType = null; michael@0: var i; michael@0: var contentTypeSet = false; michael@0: var parm = null; michael@0: builder = new IFrameBuilder(); michael@0: return builder; michael@0: } michael@0: michael@0: michael@0: function preload(frame, varname, url) { michael@0: return builder.preload(frame, varname, url); michael@0: } michael@0: michael@0: function load(frame, varname, url) { michael@0: return builder.load(frame, varname, url); michael@0: } michael@0: michael@0: function getImplementationAttribute(attr) { michael@0: return builder.getImplementationAttribute(attr); michael@0: } michael@0: michael@0: michael@0: function setImplementationAttribute(attribute, value) { michael@0: builder.setImplementationAttribute(attribute, value); michael@0: } michael@0: michael@0: function setAsynchronous(value) { michael@0: if (builder.supportsAsyncChange) { michael@0: builder.async = value; michael@0: } else { michael@0: update(); michael@0: } michael@0: } michael@0: michael@0: michael@0: function createXPathEvaluator(doc) { michael@0: try { michael@0: return doc.getFeature("XPath", null); michael@0: } michael@0: catch(ex) { michael@0: } michael@0: return doc; michael@0: } michael@0: michael@0: function toLowerArray(src) { michael@0: var newArray = new Array(); michael@0: var i; michael@0: for (i = 0; i < src.length; i++) { michael@0: newArray[i] = src[i].toLowerCase(); michael@0: } michael@0: return newArray; michael@0: } michael@0: michael@0: function MSXMLBuilder_onreadystatechange() { michael@0: if (builder.parser.readyState == 4) { michael@0: loadComplete(); michael@0: } michael@0: } michael@0: michael@0: michael@0: michael@0: var fileBase = location.href; michael@0: if (fileBase.indexOf('?') != -1) { michael@0: fileBase = fileBase.substring(0, fileBase.indexOf('?')); michael@0: } michael@0: fileBase = fileBase.substring(0, fileBase.lastIndexOf('/') + 1) + "files/"; michael@0: michael@0: function getResourceURI(name, scheme, contentType) { michael@0: return fileBase + name + getSuffix(contentType); michael@0: } michael@0: michael@0: michael@0: function getImplementation() { michael@0: return builder.getImplementation(); michael@0: } michael@0: michael@0: // Count of failures overridden as todos. michael@0: var gFailuresAsTodos = 0; michael@0: michael@0: // Override SimpleTest result logger. michael@0: var ST_logResult = SimpleTest._logResult; michael@0: SimpleTest._logResult = function overrideSTlR(test, passString, failString) { michael@0: if (todoTests[docName] && !test.result && !test.todo) { michael@0: test.name = "[failure as todo] " + test.name; michael@0: test.todo = true; michael@0: failString = "TEST-KNOWN-FAIL"; michael@0: michael@0: ++gFailuresAsTodos; michael@0: } michael@0: michael@0: ST_logResult(test, passString, failString); michael@0: } michael@0: michael@0: window.doc = window; michael@0: SimpleTest.waitForExplicitFinish(); michael@0: addLoadEvent(function(){ setUpPage(); }); michael@0: michael@0: // Actual marking code is in overrideSTlR() now. michael@0: function markTodos() { michael@0: if (todoTests[docName]) { michael@0: isnot(gFailuresAsTodos, 0, "test marked todo should have failed somewhere"); michael@0: } michael@0: } michael@0: michael@0: function runJSUnitTests() { michael@0: builder = createConfiguredBuilder(); michael@0: try { michael@0: var tests = exposeTestFunctionNames(); michael@0: for (var i = 0; i < tests.length; i++) { michael@0: window[tests[i]](); michael@0: } michael@0: } catch (ex) { michael@0: if (todoTests[docName]) { michael@0: todo(false, "[failure as todo] Test threw exception: " + ex); michael@0: ++gFailuresAsTodos; michael@0: } else { michael@0: ok(false, "Test threw exception: " + ex); michael@0: } michael@0: } michael@0: }