| var namespaces = { | |
| "html":"http://www.w3.org/1999/xhtml", | |
| "mathml":"http://www.w3.org/1998/Math/MathML", | |
| "svg":"http://www.w3.org/2000/svg", | |
| "xlink":"http://www.w3.org/1999/xlink", | |
| "xml":"http://www.w3.org/XML/1998/namespace", | |
| "xmlns":"http://www.w3.org/2000/xmlns/" | |
| }; | |
| var prefixes = {}; | |
| for (var prefix in namespaces) { | |
| if (namespaces.hasOwnProperty(prefix)) { | |
| prefixes[namespaces[prefix]] = prefix; | |
| } | |
| } | |
| prefixes[namespaces["mathml"]] = "math"; | |
| function format(format_string) { | |
| var insertions = Array.prototype.slice.call(arguments, 1); | |
| var regexp = /%s/g; | |
| var match_count = 0; | |
| var rv = format_string.replace(regexp, function(match) { | |
| var rv = insertions[match_count]; | |
| match_count++; | |
| return rv; | |
| }); | |
| return rv; | |
| } | |
| function test_serializer(element) { | |
| element.normalize(); | |
| var lines = []; | |
| function serialize_element(element, indent) { | |
| var indent_spaces = (new Array(indent)).join(" "); | |
| switch(element.nodeType) { | |
| case Node.DOCUMENT_TYPE_NODE: | |
| if (element.name) { | |
| if (element.publicId || element.systemId) { | |
| var publicId = element.publicId ? element.publicId : ""; | |
| var systemId = element.systemId ? element.systemId : ""; | |
| lines.push(format("|%s<!DOCTYPE %s \"%s\" \"%s\">", indent_spaces, | |
| element.name, publicId, systemId)); | |
| } else { | |
| lines.push(format("|%s<!DOCTYPE %s>", indent_spaces, | |
| element.name)); | |
| } | |
| } else { | |
| lines.push(format("|%s<!DOCTYPE >", indent_spaces)); | |
| } | |
| break; | |
| case Node.DOCUMENT_NODE: | |
| lines.push("#document"); | |
| break; | |
| case Node.DOCUMENT_FRAGMENT_NODE: | |
| lines.push("#document-fragment"); | |
| break; | |
| case Node.COMMENT_NODE: | |
| lines.push(format("|%s<!-- %s -->", indent_spaces, element.nodeValue)); | |
| break; | |
| case Node.TEXT_NODE: | |
| lines.push(format("|%s\"%s\"", indent_spaces, element.nodeValue)); | |
| break; | |
| case Node.ELEMENT_NODE: | |
| if (element.getAttribute("data-skip") !== null) { | |
| return; | |
| } | |
| if (element.namespaceURI !== null && element.namespaceURI !== namespaces.html) { | |
| var name = format("%s %s", prefixes[element.namespaceURI], | |
| element.localName); | |
| } else { | |
| var name = element.localName; | |
| } | |
| lines.push(format("|%s<%s>", indent_spaces, name)); | |
| var attributes = Array.prototype.map.call( | |
| element.attributes, | |
| function(attr) { | |
| var name = (attr.namespaceURI ? prefixes[attr.namespaceURI] + " " : "") + | |
| attr.localName; | |
| return [name, attr.value]; | |
| }); | |
| attributes.sort(function (a, b) { | |
| var x = a[0]; | |
| var y = b[0]; | |
| if (x === y) { | |
| return 0; | |
| } | |
| return x > y ? 1 : -1; | |
| }); | |
| attributes.forEach( | |
| function(attr) { | |
| var indent_spaces = (new Array(indent + 2)).join(" "); | |
| lines.push(format("|%s%s=\"%s\"", indent_spaces, attr[0], attr[1])); | |
| } | |
| ); | |
| break; | |
| } | |
| indent += 2; | |
| Array.prototype.forEach.call(element.childNodes, | |
| function(node) { | |
| serialize_element(node, indent); | |
| }); | |
| } | |
| serialize_element(element, 0); | |
| return lines.join("\n"); | |
| } | |
| function parse_query() { | |
| var query = location.search.slice(1); | |
| var vars = query.split("&"); | |
| var fields = vars.map(function (x) { | |
| var split = x.split("="); | |
| return [split[0], split.slice(1).join("=")]; | |
| }); | |
| return fields; | |
| } | |
| function get_type() { | |
| var run_type = "uri"; | |
| var fields = parse_query(); | |
| fields.forEach(function(x) { | |
| if(x[0] == "run_type") { | |
| run_type = x[1]; | |
| } | |
| }); | |
| return run_type; | |
| }; | |
| var test_in_data_uri = get_test_func(function (iframe, uri_encoded_input) { | |
| iframe.src = "data:text/html;charset=utf8," + uri_encoded_input; | |
| }); | |
| var test_document_write = get_test_func(function(iframe, uri_encoded_input) { | |
| iframe.contentDocument.open(); | |
| var input = decodeURIComponent(uri_encoded_input); | |
| iframe.contentDocument.write(input); | |
| iframe.contentDocument.close(); | |
| }); | |
| var test_document_write_single = get_test_func(function(iframe, uri_encoded_input) { | |
| iframe.contentDocument.open(); | |
| var input = decodeURIComponent(uri_encoded_input); | |
| for (var i=0; i< input.length; i++) { | |
| iframe.contentDocument.write(input[i]); | |
| } | |
| iframe.contentDocument.close(); | |
| }); | |
| function get_test_func(inject_func) { | |
| function test_func(iframe, t, test_id, uri_encoded_input, escaped_expected) { | |
| var expected = decodeURIComponent(escaped_expected); | |
| current_tests[iframe.id] = {test_id:test_id, | |
| uri_encoded_input:uri_encoded_input, | |
| expected:expected, | |
| actual:null | |
| }; | |
| iframe.onload = function() { | |
| t.step(function() { | |
| iframe.onload = null; | |
| var serialized_dom = test_serializer(iframe.contentDocument); | |
| current_tests[iframe.id].actual = serialized_dom; | |
| assert_equals(serialized_dom, expected); | |
| t.done(); | |
| } | |
| ); | |
| }; | |
| inject_func(iframe, uri_encoded_input); | |
| } | |
| return test_func; | |
| } | |
| function test_fragment(iframe, t, test_id, uri_encoded_input, escaped_expected, container) { | |
| var input_string = decodeURIComponent(uri_encoded_input); | |
| var expected = decodeURIComponent(escaped_expected); | |
| current_tests[iframe.id] = { | |
| test_id:test_id, | |
| input:uri_encoded_input, | |
| expected:expected, | |
| actual:null, | |
| container:container | |
| }; | |
| var components = container.split(" "); | |
| var container_elem = null; | |
| if (components.length > 1) { | |
| var namespace = namespaces[components[0]]; | |
| container_elem = document.createElementNS(namespace, | |
| components[0] + ":" + | |
| components[1]); | |
| } else { | |
| container_elem = document.createElement(container); | |
| } | |
| container_elem.innerHTML = input_string; | |
| var serialized_dom = test_serializer(container_elem); | |
| current_tests[iframe.id].actual = serialized_dom; | |
| serialized_dom = convert_innerHTML(serialized_dom); | |
| assert_equals(serialized_dom, expected); | |
| t.done(); | |
| } | |
| function convert_innerHTML(serialized_dom) { | |
| var lines = serialized_dom.split("\n"); | |
| lines[0] = "#document"; | |
| return lines.join("\n"); | |
| } | |
| function print_diffs(test_id, uri_encoded_input, expected, actual, container) { | |
| container = container ? container : null; | |
| if (actual) { | |
| var diffs = mark_diffs(expected, actual); | |
| var expected_text = diffs[0]; | |
| var actual_text = diffs[1]; | |
| } else { | |
| var expected_text = expected; | |
| var actual_text = ""; | |
| } | |
| var tmpl = ["div", {"id":"${test_id}"}, | |
| ["h2", {}, "${test_id}"], | |
| function(vars) { | |
| if (vars.container !== null) { | |
| return ["div", {"class":"container"}, | |
| ["h3", {}, "innerHTML Container"], | |
| ["pre", {}, vars.container]]; | |
| } else { | |
| return null; | |
| } | |
| }, | |
| ["div", {"id":"input_${test_id}"}, ["h3", {}, "Input"], ["pre", {}, | |
| ["code", {}, decodeURIComponent(uri_encoded_input)]]], | |
| ["div", {"id":"expected_${test_id}"}, ["h3", {}, "Expected"], | |
| ["pre", {}, ["code", {}, expected_text]]], | |
| ["div", {"id":"actual_${test_id}"}, ["h3", {}, "Actual"], | |
| ["pre", {}, ["code", {}, actual_text]]] | |
| ]; | |
| var diff_dom = template.render(tmpl, {test_id:test_id, container:container}); | |
| document.body.appendChild(diff_dom); | |
| } | |
| var current_tests = {}; | |
| var iframe_map = {}; | |
| function init_tests(test_type) { | |
| var test_func = null; | |
| var test_funcs = { | |
| "write":test_document_write, | |
| "write_single":test_document_write_single, | |
| "uri":test_in_data_uri, | |
| "innerHTML":test_fragment | |
| }; | |
| var tests_started = 0; | |
| var tests_complete = 0; | |
| setup(function() { | |
| test_func = test_funcs[test_type]; | |
| var fails = []; | |
| add_result_callback(function(test) { | |
| tests_complete++; | |
| var iframe = document.getElementById(iframe_map[test.name]); | |
| if (test.status !== test.PASS) { | |
| fails.push(current_tests[iframe.id]); | |
| var new_iframe = document.createElement("iframe"); | |
| new_iframe.style.display = "none"; | |
| new_iframe.id = iframe.id; | |
| document.body.replaceChild(new_iframe, iframe); | |
| iframe = new_iframe; | |
| } | |
| if (tests_complete === order.length) { | |
| done(); | |
| } else if (tests_started < order.length) { | |
| test_next(iframe); | |
| } | |
| }); | |
| add_completion_callback(function() { | |
| fails.forEach(function(t) { | |
| print_diffs(t.test_id, t.uri_encoded_input, | |
| t.expected, t.actual); | |
| }); | |
| }); | |
| //Create the iframes we will use to test | |
| //in the innerHTML case these are not actually used | |
| //but it is convenient to reuse the same code | |
| for (var i=0; i<num_iframes; i++) { | |
| var iframe = document.createElement("iframe"); | |
| iframe.id = "iframe_" + i; | |
| iframe.style.display = "none"; | |
| document.body.appendChild(iframe); | |
| } | |
| }, | |
| {explicit_done:true}); | |
| function test_next(iframe) { | |
| var test_id = order[tests_started]; | |
| tests_started++; | |
| var x = tests[test_id]; | |
| var t = x[0]; | |
| iframe_map[t.name] = iframe.id; | |
| setTimeout(function() { | |
| t.step(function() { | |
| var string_uri_encoded_input = x[1]; | |
| var string_escaped_expected = x[2]; | |
| if (test_type === "innerHTML") { | |
| var container = x[3]; | |
| } | |
| test_func(iframe, t, test_id, string_uri_encoded_input, string_escaped_expected, | |
| container); | |
| }); | |
| }, 0); | |
| } | |
| onload = function() { | |
| Array.prototype.forEach.call(document.getElementsByTagName("iframe"), | |
| function(iframe) { | |
| if (tests_started<order.length) { | |
| test_next(iframe); | |
| } | |
| }); | |
| }; | |
| } |