diff options
Diffstat (limited to 'dom/base/test/unit')
43 files changed, 3507 insertions, 0 deletions
diff --git a/dom/base/test/unit/1_original.xml b/dom/base/test/unit/1_original.xml new file mode 100644 index 0000000000..4b7915159d --- /dev/null +++ b/dom/base/test/unit/1_original.xml @@ -0,0 +1,3 @@ +<?xml version="1.0"?> + +<foo /> <!-- é -->
\ No newline at end of file diff --git a/dom/base/test/unit/1_result.xml b/dom/base/test/unit/1_result.xml new file mode 100644 index 0000000000..61d4458be9 --- /dev/null +++ b/dom/base/test/unit/1_result.xml @@ -0,0 +1,3 @@ +<?xml version="1.0" encoding="UTF-8"?> +<foo/> +<!-- é -->
\ No newline at end of file diff --git a/dom/base/test/unit/2_original.xml b/dom/base/test/unit/2_original.xml new file mode 100644 index 0000000000..a6b9e340ba --- /dev/null +++ b/dom/base/test/unit/2_original.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE whatever PUBLIC + "-//MOZ//WHATEVER//EN" + "http://mozilla.org/ns/foo"> +<foo xmlns="htp://mozilla.org/ns"> + <baz /><!-- a comment --> <bar> <robots> & <aliens> +<mozilla> a a a a a éèàùûî</mozilla> + <firefox>Lorem ip<!-- aaa -->sum dolor sit amet, consectetuer adipiscing elit. Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. Nam tellus massa, fringilla aliquam, fermentum sit amet, posuere ac, est. Duis tristique egestas ligula. Mauris quis felis. Fusce a ipsum non lacus posuere aliquet. Sed fermentum posuere nulla. Donec tempor. Donec sollicitudin tortor lacinia libero ullamcorper laoreet. Cras quis nisi at odio consectetuer molestie.</firefox> + <?xml-foo "hey" ?> +</bar> + <!-- a comment + on several lines--> + <?xml-foo "another pi on two lines" + example="hello"?> +</foo>
\ No newline at end of file diff --git a/dom/base/test/unit/2_result_1.xml b/dom/base/test/unit/2_result_1.xml new file mode 100644 index 0000000000..16eeb817ff --- /dev/null +++ b/dom/base/test/unit/2_result_1.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE whatever PUBLIC "-//MOZ//WHATEVER//EN" "http://mozilla.org/ns/foo"> +<foo xmlns="htp://mozilla.org/ns"> + <baz/><!-- a comment --> <bar> <robots> & <aliens> +<mozilla> a a a a a éèàùûî</mozilla> + <firefox>Lorem ip<!-- aaa -->sum dolor sit amet, consectetuer adipiscing elit. Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. Nam tellus massa, fringilla aliquam, fermentum sit amet, posuere ac, est. Duis tristique egestas ligula. Mauris quis felis. Fusce a ipsum non lacus posuere aliquet. Sed fermentum posuere nulla. Donec tempor. Donec sollicitudin tortor lacinia libero ullamcorper laoreet. Cras quis nisi at odio consectetuer molestie.</firefox> + <?xml-foo "hey" ?> +</bar> + <!-- a comment + on several lines--> + <?xml-foo "another pi on two lines" + example="hello"?> +</foo>
\ No newline at end of file diff --git a/dom/base/test/unit/2_result_2.xml b/dom/base/test/unit/2_result_2.xml new file mode 100644 index 0000000000..c3eeadb58f --- /dev/null +++ b/dom/base/test/unit/2_result_2.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE whatever PUBLIC "-//MOZ//WHATEVER//EN" "http://mozilla.org/ns/foo"> +<foo xmlns="htp://mozilla.org/ns"> + <baz/><!-- a comment --> + <bar> <robots> & <aliens> + <mozilla> a a a a a éèàùûî</mozilla> + <firefox>Lorem ip<!-- aaa -->sum dolor sit amet, consectetuer adipiscing elit. Nam eu sapien. Sed viverra lacus. Donec quis ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. Nam tellus massa, fringilla aliquam, fermentum sit amet, posuere ac, est. Duis tristique egestas ligula. Mauris quis felis. Fusce a ipsum non lacus posuere aliquet. Sed fermentum posuere nulla. Donec tempor. Donec sollicitudin tortor lacinia libero ullamcorper laoreet. Cras quis nisi at odio consectetuer molestie.</firefox> + <?xml-foo "hey" ?> + </bar> + <!-- a comment + on several lines--> + <?xml-foo "another pi on two lines" + example="hello"?> +</foo>
\ No newline at end of file diff --git a/dom/base/test/unit/2_result_3.xml b/dom/base/test/unit/2_result_3.xml new file mode 100644 index 0000000000..906ac89ee5 --- /dev/null +++ b/dom/base/test/unit/2_result_3.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE whatever PUBLIC "-//MOZ//WHATEVER//EN" "http://mozilla.org/ns/foo"> +<foo xmlns="htp://mozilla.org/ns"> + <baz/><!-- a comment --> + <bar> <robots> & <aliens> + <mozilla> a a a a a éèàùûî</mozilla> + <firefox>Lorem ip<!-- aaa -->sum dolor sit amet, consectetuer + adipiscing elit. Nam eu sapien. Sed viverra lacus. Donec quis + ipsum. Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent + taciti sociosqu ad litora torquent per conubia nostra, per + inceptos hymenaeos. Nam tellus massa, fringilla aliquam, fermentum + sit amet, posuere ac, est. Duis tristique egestas ligula. Mauris + quis felis. Fusce a ipsum non lacus posuere aliquet. Sed fermentum + posuere nulla. Donec tempor. Donec sollicitudin tortor lacinia + libero ullamcorper laoreet. Cras quis nisi at odio consectetuer + molestie.</firefox> + <?xml-foo "hey" ?> + </bar> + <!-- a comment + on several lines--> + <?xml-foo "another pi on two lines" + example="hello"?> +</foo>
\ No newline at end of file diff --git a/dom/base/test/unit/2_result_4.xml b/dom/base/test/unit/2_result_4.xml new file mode 100644 index 0000000000..27ed219211 --- /dev/null +++ b/dom/base/test/unit/2_result_4.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE whatever PUBLIC "-//MOZ//WHATEVER//EN" "http://mozilla.org/ns/foo"> +<foo xmlns="htp://mozilla.org/ns"> + <baz/><!-- a comment --> <bar> <robots> & <aliens> +<mozilla> a a a a a éèàùûî</mozilla> + <firefox>Lorem ip<!-- aaa -->sum dolor sit amet, consectetuer +adipiscing elit. Nam eu sapien. Sed viverra lacus. Donec quis ipsum. +Nunc cursus aliquet lectus. Nunc vitae eros. Class aptent taciti +sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. +Nam tellus massa, fringilla aliquam, fermentum sit amet, posuere ac, +est. Duis tristique egestas ligula. Mauris quis felis. Fusce a ipsum non + lacus posuere aliquet. Sed fermentum posuere nulla. Donec tempor. Donec + sollicitudin tortor lacinia libero ullamcorper laoreet. Cras quis nisi +at odio consectetuer molestie.</firefox> + <?xml-foo "hey" ?> +</bar> + <!-- a comment + on several lines--> + <?xml-foo "another pi on two lines" + example="hello"?> +</foo>
\ No newline at end of file diff --git a/dom/base/test/unit/3_original.xml b/dom/base/test/unit/3_original.xml new file mode 100644 index 0000000000..eb9c1bd656 --- /dev/null +++ b/dom/base/test/unit/3_original.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<foo> +Lorem ip<!-- aaa -->sum dolorsitamet, consectetuer adipiscing elit. Nameusapien. Sed viverralacus. this_is_a_very_long_long_word_which_has_a_length_higher_than_the_max_column Donecquisipsum. Nunc cursus aliquet lectus. Nunc vitae eros. +</foo>
\ No newline at end of file diff --git a/dom/base/test/unit/3_result.xml b/dom/base/test/unit/3_result.xml new file mode 100644 index 0000000000..e556c61e58 --- /dev/null +++ b/dom/base/test/unit/3_result.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<foo> + Lorem ip<!-- aaa -->sum dolorsitamet, consectetuer adipiscing elit. + Nameusapien. Sed viverralacus. + this_is_a_very_long_long_word_which_has_a_length_higher_than_the_max_column + Donecquisipsum. Nunc cursus aliquet lectus. Nunc vitae eros. +</foo>
\ No newline at end of file diff --git a/dom/base/test/unit/3_result_2.xml b/dom/base/test/unit/3_result_2.xml new file mode 100644 index 0000000000..2df257ca75 --- /dev/null +++ b/dom/base/test/unit/3_result_2.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<foo> +Lorem ip<!-- aaa -->sum dolorsitamet, consectetuer adipiscing elit. +Nameusapien. Sed viverralacus. +this_is_a_very_long_long_word_which_has_a_length_higher_than_the_max_column + Donecquisipsum. Nunc cursus aliquet lectus. Nunc vitae eros. +</foo>
\ No newline at end of file diff --git a/dom/base/test/unit/4_original.xml b/dom/base/test/unit/4_original.xml new file mode 100644 index 0000000000..4c9c61b5dd --- /dev/null +++ b/dom/base/test/unit/4_original.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE whatever PUBLIC "-//MOZ//WHATEVER//EN" "http://mozilla.org/ns/foo"> +<foo xmlns="http://mozilla.org/ns" xmlns:falsexul="http://mozilla.org/ns3"> + <!-- document to test namespaces--> + <baz /> + <bar> <robots> & <aliens> + <mozilla xmlns="http://mozilla.org/ns2"> a a a <moz>a a</moz> éèàùûî</mozilla> + <firefox>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</firefox> + </bar> + + <xul xmlns="http://mozilla.org/ns3" xmlns:other="http://mozilla.org/ns/other"> + <box> + <other:what>lorem ipsum</other:what> + <description other:yes="no">xul fake</description> + </box> + </xul> + + <falsexul:xul xmlns:other="http://mozilla.org/ns/other"> + <box> + <other:what>lorem ipsum</other:what> + <description>xul fake</description> + <what xmlns="http://mozilla.org/ns/other">lorem ipsum <falsexul:label value="hello" /> the return</what> + </box> + </falsexul:xul> + + <ho:xul xmlns="http://mozilla.org/ns4" xmlns:ho="http://mozilla.org/ns4" xmlns:other="http://mozilla.org/ns/other"> + <box> + <other:what>lorem ipsum</other:what> + <description ho:foo="bar" bla="hello" other:yes="no" ho:foo2="bar2">xul fake</description> + </box> + </ho:xul> +</foo>
\ No newline at end of file diff --git a/dom/base/test/unit/4_result_1.xml b/dom/base/test/unit/4_result_1.xml new file mode 100644 index 0000000000..b985da960e --- /dev/null +++ b/dom/base/test/unit/4_result_1.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE whatever PUBLIC "-//MOZ//WHATEVER//EN" "http://mozilla.org/ns/foo"> +<foo xmlns="http://mozilla.org/ns" xmlns:falsexul="http://mozilla.org/ns3"> + <!-- document to test namespaces--> + <baz/> + <bar> <robots> & <aliens> + <mozilla xmlns="http://mozilla.org/ns2"> a a a <moz>a a</moz> éèàùûî</mozilla> + <firefox>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</firefox> + </bar> + + <xul xmlns="http://mozilla.org/ns3" xmlns:other="http://mozilla.org/ns/other"> + <box> + <other:what>lorem ipsum</other:what> + <description other:yes="no">xul fake</description> + </box> + </xul> + + <falsexul:xul xmlns:other="http://mozilla.org/ns/other"> + <box> + <other:what>lorem ipsum</other:what> + <description>xul fake</description> + <what xmlns="http://mozilla.org/ns/other">lorem ipsum <falsexul:label value="hello"/> the return</what> + </box> + </falsexul:xul> + + <ho:xul xmlns="http://mozilla.org/ns4" xmlns:ho="http://mozilla.org/ns4" xmlns:other="http://mozilla.org/ns/other"> + <box> + <other:what>lorem ipsum</other:what> + <description ho:foo="bar" bla="hello" other:yes="no" ho:foo2="bar2">xul fake</description> + </box> + </ho:xul> +</foo>
\ No newline at end of file diff --git a/dom/base/test/unit/4_result_2.xml b/dom/base/test/unit/4_result_2.xml new file mode 100644 index 0000000000..bc408b431c --- /dev/null +++ b/dom/base/test/unit/4_result_2.xml @@ -0,0 +1,7 @@ +<falsexul:xul xmlns:falsexul="http://mozilla.org/ns3" xmlns:other="http://mozilla.org/ns/other"> + <box xmlns="http://mozilla.org/ns"> + <other:what>lorem ipsum</other:what> + <description>xul fake</description> + <what xmlns="http://mozilla.org/ns/other">lorem ipsum <falsexul:label value="hello"/> the return</what> + </box> + </falsexul:xul>
\ No newline at end of file diff --git a/dom/base/test/unit/4_result_3.xml b/dom/base/test/unit/4_result_3.xml new file mode 100644 index 0000000000..30c8b47de7 --- /dev/null +++ b/dom/base/test/unit/4_result_3.xml @@ -0,0 +1,4 @@ +<box xmlns="http://mozilla.org/ns3"> + <other:what xmlns:other="http://mozilla.org/ns/other">lorem ipsum</other:what> + <description other:yes="no" xmlns:other="http://mozilla.org/ns/other">xul fake</description> + </box>
\ No newline at end of file diff --git a/dom/base/test/unit/4_result_4.xml b/dom/base/test/unit/4_result_4.xml new file mode 100644 index 0000000000..9346d5d170 --- /dev/null +++ b/dom/base/test/unit/4_result_4.xml @@ -0,0 +1,4 @@ +<box xmlns="http://mozilla.org/ns4"> + <other:what xmlns:other="http://mozilla.org/ns/other">lorem ipsum</other:what> + <description ho:foo="bar" xmlns:ho="http://mozilla.org/ns4" bla="hello" other:yes="no" xmlns:other="http://mozilla.org/ns/other" ho:foo2="bar2">xul fake</description> + </box>
\ No newline at end of file diff --git a/dom/base/test/unit/4_result_5.xml b/dom/base/test/unit/4_result_5.xml new file mode 100644 index 0000000000..936dd950bd --- /dev/null +++ b/dom/base/test/unit/4_result_5.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE whatever PUBLIC "-//MOZ//WHATEVER//EN" "http://mozilla.org/ns/foo"> +<foo xmlns="http://mozilla.org/ns" + xmlns:falsexul="http://mozilla.org/ns3"> + <!-- document to test namespaces--> + <baz/> + <bar> <robots> & + <aliens> + <mozilla + xmlns="http://mozilla.org/ns2"> a + a a + <moz>a a</moz> éèàùûî</mozilla> + <firefox>Lorem ipsum dolor sit amet, + consectetuer adipiscing elit.</firefox> + </bar> + <xul xmlns="http://mozilla.org/ns3" +xmlns:other="http://mozilla.org/ns/other"> + <box> + <other:what>lorem ipsum</other:what> + <description other:yes="no">xul + fake</description> + </box> + </xul> + <falsexul:xul +xmlns:other="http://mozilla.org/ns/other"> + <box> + <other:what>lorem ipsum</other:what> + <description>xul fake</description> + <what + xmlns="http://mozilla.org/ns/other">lorem + ipsum + <falsexul:label value="hello"/> + the return</what> + </box> + </falsexul:xul> + <ho:xul xmlns="http://mozilla.org/ns4" + xmlns:ho="http://mozilla.org/ns4" +xmlns:other="http://mozilla.org/ns/other"> + <box> + <other:what>lorem ipsum</other:what> + <description ho:foo="bar" + bla="hello" other:yes="no" + ho:foo2="bar2">xul fake</description> + </box> + </ho:xul> +</foo>
\ No newline at end of file diff --git a/dom/base/test/unit/4_result_6.xml b/dom/base/test/unit/4_result_6.xml new file mode 100644 index 0000000000..e9917cfdc7 --- /dev/null +++ b/dom/base/test/unit/4_result_6.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE whatever PUBLIC "-//MOZ//WHATEVER//EN" "http://mozilla.org/ns/foo"> +<foo xmlns="http://mozilla.org/ns" +xmlns:falsexul="http://mozilla.org/ns3"> + <!-- document to test namespaces--> + <baz/> + <bar> <robots> & +<aliens> + <mozilla +xmlns="http://mozilla.org/ns2"> a a a <moz>a + a</moz> éèàùûî</mozilla> + <firefox>Lorem ipsum dolor sit +amet, consectetuer adipiscing elit.</firefox> + </bar> + + <xul xmlns="http://mozilla.org/ns3" +xmlns:other="http://mozilla.org/ns/other"> + <box> + <other:what>lorem ipsum</other:what> + <description other:yes="no">xul +fake</description> + </box> + </xul> + + <falsexul:xul +xmlns:other="http://mozilla.org/ns/other"> + <box> + <other:what>lorem ipsum</other:what> + <description>xul fake</description> + <what +xmlns="http://mozilla.org/ns/other">lorem + ipsum <falsexul:label value="hello"/> +the return</what> + </box> + </falsexul:xul> + + <ho:xul +xmlns="http://mozilla.org/ns4" +xmlns:ho="http://mozilla.org/ns4" +xmlns:other="http://mozilla.org/ns/other"> + <box> + <other:what>lorem ipsum</other:what> + <description ho:foo="bar" +bla="hello" other:yes="no" +ho:foo2="bar2">xul fake</description> + </box> + </ho:xul> +</foo>
\ No newline at end of file diff --git a/dom/base/test/unit/empty_document.xml b/dom/base/test/unit/empty_document.xml new file mode 100644 index 0000000000..ebd60b08c7 --- /dev/null +++ b/dom/base/test/unit/empty_document.xml @@ -0,0 +1,3 @@ +<?xml version="1.0" ?> +<!-- empty document for use in tests that don't need any particular DOM --> +<root/> diff --git a/dom/base/test/unit/head_utilities.js b/dom/base/test/unit/head_utilities.js new file mode 100644 index 0000000000..d3b68520da --- /dev/null +++ b/dom/base/test/unit/head_utilities.js @@ -0,0 +1,40 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +Components.utils.import("resource://testing-common/httpd.js"); +Components.utils.import("resource://gre/modules/NetUtil.jsm"); + +const nsIDocumentEncoder = Components.interfaces.nsIDocumentEncoder; +const replacementChar = Components.interfaces.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER; + +function loadContentFile(aFile, aCharset) { + //if(aAsIso == undefined) aAsIso = false; + if(aCharset == undefined) + aCharset = 'UTF-8'; + + var file = do_get_file(aFile); + var ios = Components.classes['@mozilla.org/network/io-service;1'] + .getService(Components.interfaces.nsIIOService); + var chann = NetUtil.newChannel({ + uri: ios.newFileURI(file), + loadUsingSystemPrincipal: true + }); + chann.contentCharset = aCharset; + + /*var inputStream = Components.classes["@mozilla.org/scriptableinputstream;1"] + .createInstance(Components.interfaces.nsIScriptableInputStream); + inputStream.init(chann.open2()); + return inputStream.read(file.fileSize); + */ + + var inputStream = Components.classes["@mozilla.org/intl/converter-input-stream;1"] + .createInstance(Components.interfaces.nsIConverterInputStream); + inputStream.init(chann.open2(), aCharset, 1024, replacementChar); + var str = {}, content = ''; + while (inputStream.readString(4096, str) != 0) { + content += str.value; + } + return content; +} diff --git a/dom/base/test/unit/head_xml.js b/dom/base/test/unit/head_xml.js new file mode 100644 index 0000000000..3d445b7484 --- /dev/null +++ b/dom/base/test/unit/head_xml.js @@ -0,0 +1,156 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const I = Components.interfaces; +const C = Components.classes; + +const nsILocalFile = I.nsILocalFile; +const nsIProperties = I.nsIProperties; +const nsIFileInputStream = I.nsIFileInputStream; +const nsIInputStream = I.nsIInputStream; + +const nsIDOMParser = I.nsIDOMParser; +const nsIDOMSerializer = I.nsIDOMSerializer; +const nsIDOMDocument = I.nsIDOMDocument; +const nsIDOMElement = I.nsIDOMElement; +const nsIDOMNode = I.nsIDOMNode; +const nsIDOMCharacterData = I.nsIDOMCharacterData; +const nsIDOMAttr = I.nsIDOMAttr; +const nsIDOMNodeList = I.nsIDOMNodeList; +const nsIDOMXULElement = I.nsIDOMXULElement; +const nsIDOMProcessingInstruction = I.nsIDOMProcessingInstruction; + +function DOMParser() { + var parser = C["@mozilla.org/xmlextras/domparser;1"].createInstance(nsIDOMParser); + parser.init(); + return parser; +} + +var __testsDirectory = null; + +function ParseFile(file) { + if (typeof(file) == "string") { + if (!__testsDirectory) { + __testsDirectory = do_get_cwd(); + } + var fileObj = __testsDirectory.clone(); + fileObj.append(file); + file = fileObj; + } + + do_check_eq(file instanceof nsILocalFile, true); + + var fileStr = C["@mozilla.org/network/file-input-stream;1"] + .createInstance(nsIFileInputStream); + // Init for readonly reading + fileStr.init(file, 0x01, 0o400, nsIFileInputStream.CLOSE_ON_EOF); + return ParseXML(fileStr); +} + +function ParseXML(data) { + if (typeof(data) == "string") { + return DOMParser().parseFromString(data, "application/xml"); + } + + do_check_eq(data instanceof nsIInputStream, true); + + return DOMParser().parseFromStream(data, "UTF-8", data.available(), + "application/xml"); +} + +function DOMSerializer() { + return C["@mozilla.org/xmlextras/xmlserializer;1"] + .createInstance(nsIDOMSerializer); +} + +function SerializeXML(node) { + return DOMSerializer().serializeToString(node); +} + +function roundtrip(obj) { + if (typeof(obj) == "string") { + return SerializeXML(ParseXML(obj)); + } + + do_check_eq(obj instanceof nsIDOMNode, true); + return ParseXML(SerializeXML(obj)); +} + +function do_compare_attrs(e1, e2) { + const xmlns = "http://www.w3.org/2000/xmlns/"; + + var a1 = e1.attributes; + var a2 = e2.attributes; + for (var i = 0; i < a1.length; ++i) { + var att = a1.item(i); + // Don't test for namespace decls, since those can just sorta be + // scattered about + if (att.namespaceURI != xmlns) { + var att2 = a2.getNamedItemNS(att.namespaceURI, att.localName); + if (!att2) { + do_throw("Missing attribute with namespaceURI '" + att.namespaceURI + + "' and localName '" + att.localName + "'"); + } + do_check_eq(att.QueryInterface(nsIDOMAttr).value, + att2.QueryInterface(nsIDOMAttr).value); + } + } +} + +function do_check_equiv(dom1, dom2) { + do_check_eq(dom1.nodeType, dom2.nodeType); + // There's no classinfo around, so we'll need to do some QIing to + // make sure the right interfaces are flattened as needed. + switch (dom1.nodeType) { + case nsIDOMNode.PROCESSING_INSTRUCTION_NODE: + do_check_eq(dom1.QueryInterface(nsIDOMProcessingInstruction).target, + dom2.QueryInterface(nsIDOMProcessingInstruction).target); + do_check_eq(dom1.data, dom2.data); + case nsIDOMNode.TEXT_NODE: + case nsIDOMNode.CDATA_SECTION_NODE: + case nsIDOMNode.COMMENT_NODE: + do_check_eq(dom1.QueryInterface(nsIDOMCharacterData).data, + dom2.QueryInterface(nsIDOMCharacterData).data); + break; + case nsIDOMNode.ELEMENT_NODE: + do_check_eq(dom1.namespaceURI, dom2.namespaceURI); + do_check_eq(dom1.localName, dom2.localName); + // Compare attrs in both directions -- do_compare_attrs does a + // subset check. + do_compare_attrs(dom1, dom2); + do_compare_attrs(dom2, dom1); + // Fall through + case nsIDOMNode.DOCUMENT_NODE: + do_check_eq(dom1.childNodes.length, dom2.childNodes.length); + for (var i = 0; i < dom1.childNodes.length; ++i) { + do_check_equiv(dom1.childNodes.item(i), dom2.childNodes.item(i)); + } + break; + } +} + +function do_check_serialize(dom) { + do_check_equiv(dom, roundtrip(dom)); +} + +function Pipe() { + var p = C["@mozilla.org/pipe;1"].createInstance(I.nsIPipe); + p.init(false, false, 0, 0xffffffff, null); + return p; +} + +function ScriptableInput(arg) { + if (arg instanceof I.nsIPipe) { + arg = arg.inputStream; + } + + var str = C["@mozilla.org/scriptableinputstream;1"]. + createInstance(I.nsIScriptableInputStream); + + str.init(arg); + + return str; +} diff --git a/dom/base/test/unit/isequalnode_data.xml b/dom/base/test/unit/isequalnode_data.xml new file mode 100644 index 0000000000..4b72f5d502 --- /dev/null +++ b/dom/base/test/unit/isequalnode_data.xml @@ -0,0 +1,150 @@ +<?xml version="1.0" ?> +<!DOCTYPE Test [ + <!ATTLIST test id ID #REQUIRED> +]> + +<root> + + <test id="test_setAttribute"> + <foo/> + <foo/> + </test> + + <test id="test_normalization"> + <bar/> + <bar/> + </test> + + <test id="test_whitespace"> + + <!-- + Tests here consist of isEqualNode comparisons of the first and third + (zero-indexed) child nodes of each test. + + In the typical case this means that the zeroth, second, and fourth + children are whitespace and the first and third are the nodes being + compared for equality or inequality. + + In some cases, however, where either node is a Text node, this pattern + must of necessity be violated. Examples of such tests include the + test_text# tests. + + As a result of this, BE CAREFUL NOT TO INTRODUCE STRAY WHITESPACE WHEN + EDITING THIS FILE. You have been warned. + --> + + <test id="test_pi1"> + <?pi data?> + <?pi data?> + </test> + <test id="test_pi2"> + <?pi data?> + <?pi data?> + </test> + <test id="test_pi3"> + <?pi data?> + <?pi data ?> + </test> + <test id="test_pi4"> + <?pi ?> + <?pi ?> + </test> + <test id="test_pi5"> + <?pi?> + <?pi ?> + </test> + + <test id="test_elt1"> + <foo></foo> + <foo> </foo> + </test> + <test id="test_elt2"> + <foo></foo> + <foo> +</foo> + </test> + <test id="test_elt3"> + <foo ></foo> + <foo></foo> + </test> + <test id="test_elt4"> + <bar xmlns="http://example.com/"/> + <bar/> + </test> + <test id="test_elt5"> + <bar xmlns="http://example.com/"/> + <bar xmlns="http://example.com"/> + </test> + + <test id="test_comment1"> + <!--foo--> + <!--foo--> + </test> + <test id="test_comment2"> + <!--foo--> + <!--foo --> + </test> + <test id="test_comment3"> + <!--foo--> + <!--foo +--> + </test> + <test id="test_comment4"> + <!-- +foo--> + <!-- +foo--> + </test> + + <test id="test_text1"><placeholder-dont-move/> +<placeholder-dont-move/> +<placeholder-dont-move/> + </test> + <test id="test_text2"><placeholder-dont-move/> +<placeholder-dont-move/> <placeholder-dont-move/> + </test> + <test id="test_text3"><placeholder-dont-move/> +<placeholder-dont-move/><![CDATA[ +]]> + </test> + + <test id="test_cdata1"> + <![CDATA[ ]]><placeholder-dont-move/> <placeholder-dont-move/> + </test> + <test id="test_cdata2"> + <![CDATA[ ]]> + <![CDATA[ ]]> + </test> + <test id="test_cdata3"> + <![CDATA[ ]]> + <![CDATA[ ]]> + </test> + <test id="test_cdata4"> + <![CDATA[]]> + <![CDATA[ +]]> + </test> + <test id="test_cdata5"> + <![CDATA[ ]]> + <![CDATA[ +]]> + </test> + + </test> + + <test id="test_namespaces"> + <test id="test_ns1"> + <foo xmlns:quiz="http://example.com/" + quiz:q="fun"/> + <foo xmlns:f="http://example.com/" + f:q="fun"/> + </test> + <test id="test_ns2"> + <quiz:foo xmlns:quiz="http://example.com/" + q="fun"/> + <f:foo xmlns:f="http://example.com/" + q="fun"/> + </test> + </test> + +</root> diff --git a/dom/base/test/unit/nodelist_data_1.xml b/dom/base/test/unit/nodelist_data_1.xml new file mode 100644 index 0000000000..ddde596a27 --- /dev/null +++ b/dom/base/test/unit/nodelist_data_1.xml @@ -0,0 +1,58 @@ +<?xml version="1.0" ?> +<!DOCTYPE Test [ + <!ATTLIST test id ID #REQUIRED> + <!ATTLIST foo:test id ID #REQUIRED> + <!ATTLIST foo2:test id ID #REQUIRED> + <!ATTLIST bar:test id ID #REQUIRED> +]> + +<!-- Comment --> + +<?This-is-a-PI ?> + +<root xmlns:foo="foo" + xmlns:bar="bar" + xmlns:foo2="foo"> + + <test id="test1"> + </test> + + <test id="test2"> + <!-- Another comment --> + <test id="test3"> + </test> + + <test id="test4" xmlns="foo"> + <test id="test5"> + </test> + + <bar:test id="test6" /> + </test> + + <foo:test id="test7"> + </foo:test> + + <foo2:test id="test8"> + <?Another-PI ?> + <baz /> + </foo2:test> + + <bar:test id="test9"> + </bar:test> + </test> + + <foo:test id="test10"> + <foo2:test id="test11"> + <bar:test id="test12"> + </bar:test> + </foo2:test> + </foo:test> + + <foo2:test id="test13"> + </foo2:test> + + <bar:test id="test14"> + </bar:test> + +</root> + diff --git a/dom/base/test/unit/nodelist_data_2.xul b/dom/base/test/unit/nodelist_data_2.xul new file mode 100644 index 0000000000..247ef0353c --- /dev/null +++ b/dom/base/test/unit/nodelist_data_2.xul @@ -0,0 +1,45 @@ +<?xml version="1.0"?> +<!DOCTYPE window [ + <!ENTITY fooSet ' + <addOrRemove foo:foo="foo"/> + <addOrRemove foo:foo="bar"/> + <addOrRemove foo:bar="foo"/> + <addOrRemove foo:bar="bar"/> + <addOrRemove foo:foo="foo" foo:bar="bar"/> + <addOrRemove foo2:foo="foo"/> + <addOrRemove foo="foo"/> + <addOrRemove foo="bar"/> + <addOrRemove bar="bar" foo="foo"/> +'> +]> +<window + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + xmlns:foo="foo" + xmlns:foo2="foo" + xmlns:bar="bar" + > + <vbox id="boxes"> + <groupbox id="master1" foo:foo="bar"> + &fooSet; + <groupbox foo:foo="foo"> + &fooSet; + </groupbox> + </groupbox> + <groupbox id="master2" foo:foo="foo"> + &fooSet; + <groupbox foo:foo="bar"> + &fooSet; + </groupbox> + </groupbox> + <groupbox id="master3"> + &fooSet; + <groupbox foo2:foo="foo"> + &fooSet; + </groupbox> + </groupbox> + <groupbox id="external"> + &fooSet; + </groupbox> + </vbox> +</window> diff --git a/dom/base/test/unit/test_bloburi.js b/dom/base/test/unit/test_bloburi.js new file mode 100644 index 0000000000..36e2e1eb72 --- /dev/null +++ b/dom/base/test/unit/test_bloburi.js @@ -0,0 +1,33 @@ +var Cc = Components.classes; +var Ci = Components.interfaces; +var Cr = Components.results; + +var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); + +var uris = [ + { + uri: "blob:https://example.com/230d5d50-35f9-9745-a64a-15e47b731a81", + local: true, + }, + { + uri: "rstp://1.2.3.4/some_path?param=a", + local: false, + }, + { + uri: "moz-fonttable://something", + local: true, + } +]; + +function run_test() +{ + for (let i = 0; i < uris.length; i++) { + let uri = ios.newURI(uris[i].uri); + let handler = ios.getProtocolHandler(uri.scheme).QueryInterface(Ci.nsIProtocolHandler); + let flags = handler.protocolFlags; + + do_check_eq(Ci.nsIProtocolHandler.URI_IS_LOCAL_RESOURCE & flags, + (uris[i].local) ? Ci.nsIProtocolHandler.URI_IS_LOCAL_RESOURCE : 0); + } +} + diff --git a/dom/base/test/unit/test_bug553888.js b/dom/base/test/unit/test_bug553888.js new file mode 100644 index 0000000000..036d51211d --- /dev/null +++ b/dom/base/test/unit/test_bug553888.js @@ -0,0 +1,60 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +Components.utils.import("resource://testing-common/httpd.js"); + +var server = new HttpServer(); +server.start(-1); + +const SERVER_PORT = server.identity.primaryPort; +const HTTP_BASE = "http://localhost:" + SERVER_PORT; +const redirectPath = "/redirect"; +const headerCheckPath = "/headerCheck"; +const redirectURL = HTTP_BASE + redirectPath; +const headerCheckURL = HTTP_BASE + headerCheckPath; + +function redirectHandler(metadata, response) { + response.setStatusLine(metadata.httpVersion, 302, "Found"); + response.setHeader("Location", headerCheckURL, false); +} + +function headerCheckHandler(metadata, response) { + try { + let headerValue = metadata.getHeader("X-Custom-Header"); + do_check_eq(headerValue, "present"); + } catch(e) { + do_throw("No header present after redirect"); + } + try { + metadata.getHeader("X-Unwanted-Header"); + do_throw("Unwanted header present after redirect"); + } catch (x) { + } + response.setStatusLine(metadata.httpVersion, 200, "OK"); + response.setHeader("Content-Type", "text/plain"); + response.write(""); +} + +function run_test() { + server.registerPathHandler(redirectPath, redirectHandler); + server.registerPathHandler(headerCheckPath, headerCheckHandler); + + do_test_pending(); + var request = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"] + .createInstance(Components.interfaces.nsIXMLHttpRequest); + request.open("GET", redirectURL, true); + request.setRequestHeader("X-Custom-Header", "present"); + request.addEventListener("readystatechange", function() { + if (request.readyState == 4) { + do_check_eq(request.status, 200); + server.stop(do_test_finished); + } + }, false); + request.send(); + try { + request.setRequestHeader("X-Unwanted-Header", "present"); + do_throw("Shouldn't be able to set a header after send"); + } catch (x) { + } +} diff --git a/dom/base/test/unit/test_bug737966.js b/dom/base/test/unit/test_bug737966.js new file mode 100644 index 0000000000..448f6fa74e --- /dev/null +++ b/dom/base/test/unit/test_bug737966.js @@ -0,0 +1,20 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* If charset parameter is invalid, the encoding should be detected as UTF-8 */ + +function run_test() +{ + let body = '<?xml version="1.0"><html>%c3%80</html>'; + let result = '<?xml version="1.0"><html>\u00c0</html>'; + + let xhr = Components.classes['@mozilla.org/xmlextras/xmlhttprequest;1']. + createInstance(Components.interfaces.nsIXMLHttpRequest); + xhr.open('GET', + 'data:text/xml;charset=abc,' + body, + false); + xhr.send(null); + + do_check_eq(xhr.responseText, result); +} diff --git a/dom/base/test/unit/test_cancelPrefetch.js b/dom/base/test/unit/test_cancelPrefetch.js new file mode 100644 index 0000000000..1a10240a90 --- /dev/null +++ b/dom/base/test/unit/test_cancelPrefetch.js @@ -0,0 +1,134 @@ +//Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); +const Cc = Components.classes; +const Ci = Components.interfaces; +var prefetch = Cc["@mozilla.org/prefetch-service;1"]. + getService(Ci.nsIPrefetchService); +var ios = Cc["@mozilla.org/network/io-service;1"]. + getService(Ci.nsIIOService); +var prefs = Cc["@mozilla.org/preferences-service;1"]. + getService(Ci.nsIPrefBranch); + +var parser = Cc["@mozilla.org/xmlextras/domparser;1"]. + createInstance(Ci.nsIDOMParser); + +var doc; + +var docbody = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + + '<link id="node1"/><link id="node2"/>' + + '</body></html>'; + +var node1; +var node2; + +function run_test() { + prefs.setBoolPref("network.prefetch-next", true); + + parser.init(); + doc = parser.parseFromString(docbody, "text/html"); + + node1 = doc.getElementById("node1"); + node2 = doc.getElementById("node2"); + + run_next_test(); +} + +add_test(function test_cancel1() { + + var uri = ios.newURI("http://localhost/1", null, null); + prefetch.prefetchURI(uri, uri, node1, true); + + do_check_true(prefetch.hasMoreElements(), 'There is a request in the queue'); + + // Trying to prefetch again the same uri with the same node will fail. + var didFail = 0; + + try { + prefetch.prefetchURI(uri, uri, node1, true); + } catch(e) { + didFail = 1; + } + + do_check_true(didFail == 1, 'Prefetching the same request with the same ' + + 'node fails.'); + + do_check_true(prefetch.hasMoreElements(), 'There is still request in ' + + 'the queue'); + + prefetch.cancelPrefetchURI(uri, node1); + + do_check_false(prefetch.hasMoreElements(), 'There is no request in the ' + + 'queue'); + run_next_test(); +}); + +add_test(function test_cancel2() { + // Prefetch a uri with 2 different nodes. There should be 2 request + // in the queue and canceling one will not cancel the other. + + var uri = ios.newURI("http://localhost/1", null, null); + prefetch.prefetchURI(uri, uri, node1, true); + prefetch.prefetchURI(uri, uri, node2, true); + + do_check_true(prefetch.hasMoreElements(), 'There are requests in the queue'); + + prefetch.cancelPrefetchURI(uri, node1); + + do_check_true(prefetch.hasMoreElements(), 'There is still one more request ' + + 'in the queue'); + + prefetch.cancelPrefetchURI(uri, node2); + + do_check_false(prefetch.hasMoreElements(), 'There is no request in the queue'); + run_next_test(); +}); + +add_test(function test_cancel3() { + // Request a prefetch of a uri. Trying to cancel a prefetch for the same uri + // with a different node will fail. + var uri = ios.newURI("http://localhost/1", null, null); + prefetch.prefetchURI(uri, uri, node1, true); + + do_check_true(prefetch.hasMoreElements(), 'There is a request in the queue'); + + var didFail = 0; + + try { + prefetch.cancelPrefetchURI(uri, node2); + } catch(e) { + didFail = 1; + } + do_check_true(didFail == 1, 'Canceling the request failed'); + + do_check_true(prefetch.hasMoreElements(), 'There is still a request ' + + 'in the queue'); + + prefetch.cancelPrefetchURI(uri, node1); + do_check_false(prefetch.hasMoreElements(), 'There is no request in the queue'); + run_next_test(); +}); + +add_test(function test_cancel4() { + // Request a prefetch of a uri. Trying to cancel a prefetch for a different uri + // with the same node will fail. + var uri1 = ios.newURI("http://localhost/1", null, null); + var uri2 = ios.newURI("http://localhost/2", null, null); + prefetch.prefetchURI(uri1, uri1, node1, true); + + do_check_true(prefetch.hasMoreElements(), 'There is a request in the queue'); + + var didFail = 0; + + try { + prefetch.cancelPrefetchURI(uri2, node1); + } catch(e) { + didFail = 1; + } + do_check_true(didFail == 1, 'Canceling the request failed'); + + do_check_true(prefetch.hasMoreElements(), 'There is still a request ' + + 'in the queue'); + + prefetch.cancelPrefetchURI(uri1, node1); + do_check_false(prefetch.hasMoreElements(), 'There is no request in the queue'); + run_next_test(); +}); diff --git a/dom/base/test/unit/test_chromeutils_base64.js b/dom/base/test/unit/test_chromeutils_base64.js new file mode 100644 index 0000000000..361392c44d --- /dev/null +++ b/dom/base/test/unit/test_chromeutils_base64.js @@ -0,0 +1,105 @@ +"use strict"; + +function run_test() { + test_base64URLEncode(); + test_base64URLDecode(); +} + +// Test vectors from RFC 4648, section 10. +let textTests = { + "": "", + "f": "Zg", + "fo": "Zm8", + "foo": "Zm9v", + "foob": "Zm9vYg", + "fooba": "Zm9vYmE", + "foobar": "Zm9vYmFy", +} + +// Examples from RFC 4648, section 9. +let binaryTests = [{ + decoded: new Uint8Array([0x14, 0xfb, 0x9c, 0x03, 0xd9, 0x7e]), + encoded: "FPucA9l-", +}, { + decoded: new Uint8Array([0x14, 0xfb, 0x9c, 0x03, 0xd9]), + encoded: "FPucA9k", +}, { + decoded: new Uint8Array([0x14, 0xfb, 0x9c, 0x03]), + encoded: "FPucAw", +}]; + +function padEncodedValue(value) { + switch (value.length % 4) { + case 0: + return value; + case 2: + return value + "=="; + case 3: + return value + "="; + default: + throw new TypeError("Invalid encoded value"); + } +} + +function testEncode(input, encoded) { + equal(ChromeUtils.base64URLEncode(input, { pad: false }), + encoded, encoded + " without padding"); + equal(ChromeUtils.base64URLEncode(input, { pad: true }), + padEncodedValue(encoded), encoded + " with padding"); +} + +function test_base64URLEncode() { + throws(_ => ChromeUtils.base64URLEncode(new Uint8Array(0)), /TypeError/, + "Should require encoding options"); + throws(_ => ChromeUtils.base64URLEncode(new Uint8Array(0), {}), /TypeError/, + "Encoding should require the padding option"); + + for (let {decoded, encoded} of binaryTests) { + testEncode(decoded, encoded); + } + + let textEncoder = new TextEncoder("utf-8"); + for (let decoded of Object.keys(textTests)) { + let input = textEncoder.encode(decoded); + testEncode(input, textTests[decoded]); + } +} + +function testDecode(input, decoded) { + let buffer = ChromeUtils.base64URLDecode(input, { padding: "reject" }); + deepEqual(new Uint8Array(buffer), decoded, input + " with padding rejected"); + + let paddedValue = padEncodedValue(input); + buffer = ChromeUtils.base64URLDecode(paddedValue, { padding: "ignore" }); + deepEqual(new Uint8Array(buffer), decoded, input + " with padding ignored"); + + if (paddedValue.length > input.length) { + throws(_ => ChromeUtils.base64URLDecode(paddedValue, { padding: "reject" }), + paddedValue + " with padding rejected should throw"); + + throws(_ => ChromeUtils.base64URLDecode(input, { padding: "require" }), + input + " with padding required should throw"); + + buffer = ChromeUtils.base64URLDecode(paddedValue, { padding: "require" }); + deepEqual(new Uint8Array(buffer), decoded, paddedValue + " with padding required"); + } +} + +function test_base64URLDecode() { + throws(_ => ChromeUtils.base64URLDecode(""), /TypeError/, + "Should require decoding options"); + throws(_ => ChromeUtils.base64URLDecode("", {}), /TypeError/, + "Decoding should require the padding option"); + throws(_ => ChromeUtils.base64URLDecode("", { padding: "chocolate" }), + "Decoding should throw for invalid padding policy"); + + for (let {decoded, encoded} of binaryTests) { + testDecode(encoded, decoded); + } + + let textEncoder = new TextEncoder("utf-8"); + for (let decoded of Object.keys(textTests)) { + let expectedBuffer = textEncoder.encode(decoded); + testDecode(textTests[decoded], expectedBuffer); + } +} diff --git a/dom/base/test/unit/test_delete_range.xml b/dom/base/test/unit/test_delete_range.xml new file mode 100644 index 0000000000..c8d50bd32a --- /dev/null +++ b/dom/base/test/unit/test_delete_range.xml @@ -0,0 +1,125 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +This file holds serialized tests for DOM Range tests on extractContents. +The <test/> elements designate individual tests. Each one has the following: + +* A <source/> element, designating the start conditions of the test, +* A <result/> element, designating what the source element should look like + after the extraction, +* An <extract/> element, designating what the extracted content should look like. + +The <split/> element designates a split between two DOM nodes. This element will +be removed before the actual test, and the two nodes on either side will not be +merged. + +The <empty-cdata/> element designates an empty character data section. Before +the test executes, this element is replaced with an actual CDATASection node. + +For the <source/> element, there are four attributes: + +* startContainer: A XPath to the startContainer of the range. +* endContainer: A XPath to the endContainer of the range. +* startOffset: The startOffset of the range. +* endOffset: The endOffset of the range. + +Note this test may need updating with a fix for bug 401276. The spec states +adjacent nodes after an extraction should be merged if possible, but using the +normalize() method, which could have unintended side effects... For now, we're +not permitting that, pending clarification. + +Please make sure the first test in this document always tests a range where the +start container and end container are the same text node, and where the start +offset and end offsets are valid and inequal. Some of the additional range +tests (after the bulk of the delete/extract tests) depend on it. + --> +<root> + <!-- Extracting from a text node. --> + <test> + <source startContainer="text()[1]" + endContainer="text()[1]" + startOffset="4" + endOffset="10">The quick fox</source> + <result>The fox</result> + <extract>quick </extract> + </test> + + <!-- Extracting from a CDATA section. --> + <test> + <source startContainer="text()[1]" + endContainer="text()[1]" + startOffset="4" + endOffset="10"><![CDATA[The quick fox]]></source> + <result><![CDATA[The fox]]></result> + <extract><![CDATA[quick ]]></extract> + </test> + + <!-- Snipping the start of a text node. --> + <test> + <source startContainer="text()[1]" + endContainer="text()[1]" + startOffset="0" + endOffset="4"><![CDATA[The quick fox]]></source> + <result><![CDATA[quick fox]]></result> + <extract><![CDATA[The ]]></extract> + </test> + + <!-- Extracting from a comment. --> + <test> + <source startContainer="comment()[1]" + endContainer="comment()[1]" + startOffset="4" + endOffset="10"><!--The quick fox--></source> + <result><!--The fox--></result> + <extract><!--quick --></extract> + </test> + + <!-- Snipping whole nodes --> + <test> + <source startContainer="." + endContainer="." + startOffset="0" + endOffset="2">Fox<fox/>Fox<bear/><!--comment--></source> + <result>Fox<bear/><!--comment--></result> + <extract>Fox<fox/></extract> + </test> + + <!-- Snipping whole nodes --> + <test> + <source startContainer="." + endContainer="." + startOffset="1" + endOffset="3">Fox<fox/>Fox<bear/><!--comment--></source> + <result>Fox<bear/><!--comment--></result> + <extract><fox/>Fox</extract> + </test> + + <!-- Snipping a mixture of nodes and portions of text --> + <test> + <source startContainer="text()[2]" + startOffset="1" + endContainer="comment()[1]" + endOffset="3">Fox<fox/>Fox<bear><?cow ?></bear><!--comment--></source> + <result>Fox<fox/>F<!--ment--></result> + <extract>ox<bear><?cow ?></bear><!--com--></extract> + </test> + + <!-- Extracting with a collapsed range from a text node. --> + <test> + <source startContainer="text()[1]" + endContainer="text()[1]" + startOffset="4" + endOffset="4">The quick fox</source> + <result>The quick fox</result> + <extract/> + </test> + + <!-- Extracting with a collapsed range from a non-text node. --> + <test> + <source startContainer="." + endContainer="." + startOffset="0" + endOffset="0">Fox<fox/>Fox<bear/><!--comment--></source> + <result>Fox<fox/>Fox<bear/><!--comment--></result> + <extract/> + </test> +</root> diff --git a/dom/base/test/unit/test_error_codes.js b/dom/base/test/unit/test_error_codes.js new file mode 100644 index 0000000000..c4f488f189 --- /dev/null +++ b/dom/base/test/unit/test_error_codes.js @@ -0,0 +1,68 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +var gExpectedStatus = null; +var gNextTestFunc = null; + +var prefs = Components.classes["@mozilla.org/preferences-service;1"]. + getService(Components.interfaces.nsIPrefBranch); + +var asyncXHR = { + load: function() { + var request = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"] + .createInstance(Components.interfaces.nsIXMLHttpRequest); + request.open("GET", "http://localhost:4444/test_error_code.xml", true); + + var self = this; + request.addEventListener("error", function(event) { self.onError(event); }, false); + request.send(null); + }, + onError: function doAsyncRequest_onError(event) { + var request = event.target.channel.QueryInterface(Components.interfaces.nsIRequest); + do_check_eq(request.status, gExpectedStatus); + gNextTestFunc(); + } +} + +function run_test() { + do_test_pending(); + do_timeout(0, run_test_pt1); +} + +// network offline +function run_test_pt1() { + var ioService = Components.classes["@mozilla.org/network/io-service;1"] + .getService(Components.interfaces.nsIIOService); + + try { + ioService.manageOfflineStatus = false; + } + catch (e) { + } + ioService.offline = true; + prefs.setBoolPref("network.dns.offline-localhost", false); + + gExpectedStatus = Components.results.NS_ERROR_OFFLINE; + gNextTestFunc = run_test_pt2; + dump("Testing error returned by async XHR when the network is offline\n"); + asyncXHR.load(); +} + +// connection refused +function run_test_pt2() { + var ioService = Components.classes["@mozilla.org/network/io-service;1"] + .getService(Components.interfaces.nsIIOService); + ioService.offline = false; + prefs.clearUserPref("network.dns.offline-localhost"); + + gExpectedStatus = Components.results.NS_ERROR_CONNECTION_REFUSED; + gNextTestFunc = end_test; + dump("Testing error returned by aync XHR when the connection is refused\n"); + asyncXHR.load(); +} + +function end_test() { + do_test_finished(); +} diff --git a/dom/base/test/unit/test_isequalnode.js b/dom/base/test/unit/test_isequalnode.js new file mode 100644 index 0000000000..5d44b5b50c --- /dev/null +++ b/dom/base/test/unit/test_isequalnode.js @@ -0,0 +1,435 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +function run_test() +{ + /* + * NOTE: [i] is not allowed in this test, since it's done via classinfo and + * we don't have that in xpcshell; the workaround is item(i). Suck. + */ + init(); + + test_isEqualNode_setAttribute(); + test_isEqualNode_clones(); + test_isEqualNode_variety(); + test_isEqualNode_normalization(); + test_isEqualNode_whitespace(); + test_isEqualNode_namespaces(); + test_isEqualNode_wholeDoc(); + + // XXX should Node.isEqualNode(null) throw or return false? + //test_isEqualNode_null(); + +} + +// TEST CODE + +var doc, root; // cache for use in all tests + +function init() +{ + doc = ParseFile("isequalnode_data.xml"); + root = doc.documentElement; +} + +function test_isEqualNode_setAttribute() +{ + // NOTE: 0, 2 are whitespace + var test1 = doc.getElementById("test_setAttribute"); + var node1 = test1.childNodes.item(1); + var node2 = test1.childNodes.item(3); + + check_eq_nodes(node1, node2); + + + el(node1).setAttribute("bar", "baz"); + check_neq_nodes(node1, node2); + + el(node2).setAttribute("bar", "baz"); + check_eq_nodes(node1, node2); + + + // the null namespace is equivalent to no namespace -- section 1.3.3 + // (XML Namespaces) of DOM 3 Core + node1.setAttributeNS(null, "quux", "17"); + check_neq_nodes(node1, node2); + + node2.setAttribute("quux", "17"); + check_eq_nodes(node1, node2); + + + node2.setAttributeNS("http://mozilla.org/", "seamonkey", "rheet"); + check_neq_nodes(node1, node2); + + node1.setAttribute("seamonkey", "rheet"); + check_neq_nodes(node1, node2); + + node1.setAttributeNS("http://mozilla.org/", "seamonkey", "rheet"); + check_neq_nodes(node1, node2); + + // this overwrites the namespaced "seamonkey" attribute added to node2 + // earlier, because this simply sets whatever attribute has the fully + // qualified name "seamonkey" (the setAttributeNS attribute string wasn't + // prefixed) -- consequently, node1 and node2 are still unequal + node2.setAttribute("seamonkey", "rheet"); + check_neq_nodes(node1, node2); +} + +function test_isEqualNode_clones() +{ + // tests all elements and attributes in the document + var all_elts = doc.getElementsByTagName("*"); + for (var i = 0; i < all_elts.length; i++) + { + var elt = el(all_elts.item(i)); + check_eq_nodes(elt, elt.cloneNode(true)); + + var attrs = elt.attributes; + for (var j = 0; j < attrs.length; j++) + { + var attr = attrs.item(j); + check_eq_nodes(attr, attr.cloneNode(true)); + } + } + + var elm = doc.createElement("foo"); + check_eq_nodes(elm, elm.cloneNode(true)); + check_eq_nodes(elm, elm.cloneNode(false)); + + elm.setAttribute("fiz", "eit"); + check_eq_nodes(elm, elm.cloneNode(true)); + check_eq_nodes(elm, elm.cloneNode(false)); + + elm.setAttributeNS("http://example.com/", "trendoid", "arthroscope"); + check_eq_nodes(elm, elm.cloneNode(true)); + check_eq_nodes(elm, elm.cloneNode(false)); + + var elm2 = elm.cloneNode(true); + check_eq_nodes(elm, elm2); + + const TEXT = "fetishist"; + + elm.textContent = TEXT; + check_neq_nodes(elm, elm2); + + check_neq_nodes(elm, elm.cloneNode(false)); + check_eq_nodes(elm, elm.cloneNode(true)); + + elm2.appendChild(doc.createTextNode(TEXT)); + check_eq_nodes(elm, elm2); + + var att = doc.createAttribute("bar"); + check_eq_nodes(att, att.cloneNode(true)); + check_eq_nodes(att, att.cloneNode(false)); +} + +function test_isEqualNode_variety() +{ + const nodes = + [ + doc.createElement("foo"), + doc.createElementNS("http://example.com/", "foo"), + doc.createElementNS("http://example.org/", "foo"), + doc.createElementNS("http://example.com/", "FOO"), + doc.createAttribute("foo", "href='biz'"), + doc.createAttributeNS("http://example.com/", "foo", "href='biz'"), + doc.createTextNode("foo"), + doc.createTextNode(" "), + doc.createTextNode(" "), + doc.createComment("foo"), + doc.createProcessingInstruction("foo", "href='biz'"), + doc.implementation.createDocumentType("foo", "href='biz'", ""), + doc.implementation.createDocument("http://example.com/", "foo", null), + doc.createDocumentFragment() + ]; + + for (var i = 0; i < nodes.length; i++) + { + for (var j = i; j < nodes.length; j++) + { + if (i == j) + check_eq_nodes(nodes[i], nodes[j]); + else + check_neq_nodes(nodes[i], nodes[j]); + } + } +} + +function test_isEqualNode_normalization() +{ + var norm = doc.getElementById("test_normalization"); + var node1 = norm.childNodes.item(1); + var node2 = norm.childNodes.item(3); + + check_eq_nodes(node1, node2); + + node1.appendChild(doc.createTextNode("")); + check_neq_nodes(node1, node2); + + node1.normalize(); + check_eq_nodes(node1, node2); + + node2.appendChild(doc.createTextNode("fun")); + node2.appendChild(doc.createTextNode("ctor")); + node1.appendChild(doc.createTextNode("functor")); + check_neq_nodes(node1, node2); + + node1.normalize(); + check_neq_nodes(node1, node2); + + node2.normalize(); + check_eq_nodes(node1, node2); + + // reset + while (node1.hasChildNodes()) + node1.removeChild(node1.childNodes.item(0)); + while (node2.hasChildNodes()) + node2.removeChild(node2.childNodes.item(0)); + + // attribute normalization testing + + var at1 = doc.createAttribute("foo"); + var at2 = doc.createAttribute("foo"); + check_eq_nodes(at1, at2); + + // Attr.appendChild isn't implemented yet (bug 56758), so don't run this yet + if (false) + { + at1.appendChild(doc.createTextNode("rasp")); + at2.appendChild(doc.createTextNode("rasp")); + check_eq_nodes(at1, at2); + + at1.appendChild(doc.createTextNode("")); + check_neq_nodes(at1, at2); + + at1.normalize(); + check_eq_nodes(at1, at2); + + at1.appendChild(doc.createTextNode("berry")); + check_neq_nodes(at1, at2); + + at2.appendChild(doc.createTextNode("ber")); + check_neq_nodes(at1, at2); + + at2.appendChild(doc.createTextNode("ry")); + check_neq_nodes(at1, at2); + + at1.normalize(); + check_neq_nodes(at1, at2); + + at2.normalize(); + check_eq_nodes(at1, at2); + } + + node1.setAttributeNode(at1); + check_neq_nodes(node1, node2); + + node2.setAttributeNode(at2); + check_eq_nodes(node1, node2); + + var n1text1 = doc.createTextNode("ratfink"); + var n1elt = doc.createElement("fruitcake"); + var n1text2 = doc.createTextNode("hydrospanner"); + + node1.appendChild(n1text1); + node1.appendChild(n1elt); + node1.appendChild(n1text2); + + check_neq_nodes(node1, node2); + + var n2text1a = doc.createTextNode("rat"); + var n2text1b = doc.createTextNode("fink"); + var n2elt = doc.createElement("fruitcake"); + var n2text2 = doc.createTextNode("hydrospanner"); + + node2.appendChild(n2text1b); + node2.appendChild(n2elt); + node2.appendChild(n2text2); + check_neq_nodes(node1, node2); + + node2.insertBefore(n2text1a, n2text1b); + check_neq_nodes(node1, node2); + + var tmp_node1 = node1.cloneNode(true); + tmp_node1.normalize(); + var tmp_node2 = node2.cloneNode(true); + tmp_node2.normalize(); + check_eq_nodes(tmp_node1, tmp_node2); + + n2elt.appendChild(doc.createTextNode("")); + check_neq_nodes(node1, node2); + + tmp_node1 = node1.cloneNode(true); + tmp_node1.normalize(); + tmp_node2 = node2.cloneNode(true); + tmp_node2.normalize(); + check_eq_nodes(tmp_node1, tmp_node2); + + var typeText1 = doc.createTextNode("type"); + n2elt.appendChild(typeText1); + tmp_node1 = node1.cloneNode(true); + tmp_node1.normalize(); + tmp_node2 = node2.cloneNode(true); + tmp_node2.normalize(); + check_neq_nodes(tmp_node1, tmp_node2); + + n1elt.appendChild(doc.createTextNode("typedef")); + tmp_node1 = node1.cloneNode(true); + tmp_node1.normalize(); + tmp_node2 = node2.cloneNode(true); + tmp_node2.normalize(); + check_neq_nodes(tmp_node1, tmp_node2); + check_neq_nodes(n1elt, n2elt); + + var typeText2 = doc.createTextNode("def"); + n2elt.appendChild(typeText2); + tmp_node1 = node1.cloneNode(true); + tmp_node1.normalize(); + tmp_node2 = node2.cloneNode(true); + tmp_node2.normalize(); + check_eq_nodes(tmp_node1, tmp_node2); + check_neq_nodes(node1, node2); + + n2elt.insertBefore(doc.createTextNode(""), typeText2); + check_neq_nodes(node1, node2); + + n2elt.insertBefore(doc.createTextNode(""), typeText2); + check_neq_nodes(node1, node2); + + n2elt.insertBefore(doc.createTextNode(""), typeText1); + check_neq_nodes(node1, node2); + + node1.normalize(); + node2.normalize(); + check_eq_nodes(node1, node2); +} + +function test_isEqualNode_whitespace() +{ + equality_check_kids("test_pi1", true); + equality_check_kids("test_pi2", true); + equality_check_kids("test_pi3", false); + equality_check_kids("test_pi4", true); + equality_check_kids("test_pi5", true); + + equality_check_kids("test_elt1", false); + equality_check_kids("test_elt2", false); + equality_check_kids("test_elt3", true); + equality_check_kids("test_elt4", false); + equality_check_kids("test_elt5", false); + + equality_check_kids("test_comment1", true); + equality_check_kids("test_comment2", false); + equality_check_kids("test_comment3", false); + equality_check_kids("test_comment4", true); + + equality_check_kids("test_text1", true); + equality_check_kids("test_text2", false); + equality_check_kids("test_text3", false); + + equality_check_kids("test_cdata1", false); + equality_check_kids("test_cdata2", true); + equality_check_kids("test_cdata3", false); + equality_check_kids("test_cdata4", false); + equality_check_kids("test_cdata5", false); +} + +function test_isEqualNode_namespaces() +{ + equality_check_kids("test_ns1", false); + equality_check_kids("test_ns2", false); + + // XXX want more tests here! +} + +function test_isEqualNode_null() +{ + check_neq_nodes(doc, null); + + var elts = doc.getElementsByTagName("*"); + for (var i = 0; i < elts.length; i++) + { + var elt = elts.item(i); + check_neq_nodes(elt, null); + + var attrs = elt.attributes; + for (var j = 0; j < attrs.length; j++) + { + var att = attrs.item(j); + check_neq_nodes(att, null); + + for (var k = 0; k < att.childNodes.length; k++) + { + check_neq_nodes(att.childNodes.item(k), null); + } + } + } +} + +function test_isEqualNode_wholeDoc() +{ + doc = ParseFile("isequalnode_data.xml"); + var doc2 = ParseFile("isequalnode_data.xml"); + var tw1 = + doc.createTreeWalker(doc, Components.interfaces.nsIDOMNodeFilter.SHOW_ALL, + null); + var tw2 = + doc2.createTreeWalker(doc2, Components.interfaces.nsIDOMNodeFilter.SHOW_ALL, + null); + do { + check_eq_nodes(tw1.currentNode, tw2.currentNode); + tw1.nextNode(); + } while(tw2.nextNode()); +} + +// UTILITY FUNCTIONS + +function n(node) { return node ? node.QueryInterface(nsIDOMNode) : null; } +function el(node) { return node ? node.QueryInterface(nsIDOMElement) : null; } +function at(node) { return node ? node.QueryInterface(nsIDOMAttr) : null; } + + +// TESTING FUNCTIONS + +/** + * Compares the first and third (zero-indexed) child nodes of the element + * (typically to allow whitespace) referenced by parentId for isEqualNode + * equality or inequality based on the value of areEqual. + * + * Note that this means that the contents of the element referenced by parentId + * are whitespace-sensitive, and a stray space introduced during an edit to the + * file could result in a correct but unexpected (in)equality failure. + */ +function equality_check_kids(parentId, areEqual) +{ + var parent = doc.getElementById(parentId); + var kid1 = parent.childNodes.item(1); + var kid2 = parent.childNodes.item(3); + + if (areEqual) + check_eq_nodes(kid1, kid2); + else + check_neq_nodes(kid1, kid2); +} + +function check_eq_nodes(n1, n2) +{ + if (n1 && !n1.isEqualNode(n2)) + do_throw(n1 + " should be equal to " + n2); + if (n2 && !n2.isEqualNode(n1)) + do_throw(n2 + " should be equal to " + n1); + if (!n1 && !n2) + do_throw("nodes both null!"); +} + +function check_neq_nodes(n1, n2) +{ + if (n1 && n1.isEqualNode(n2)) + do_throw(n1 + " should not be equal to " + n2); + if (n2 && n2.isEqualNode(n1)) + do_throw(n2 + " should not be equal to " + n1); + if (!n1 && !n2) + do_throw("n1 and n2 both null!"); +} diff --git a/dom/base/test/unit/test_nodelist.js b/dom/base/test/unit/test_nodelist.js new file mode 100644 index 0000000000..50c79da72e --- /dev/null +++ b/dom/base/test/unit/test_nodelist.js @@ -0,0 +1,394 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +function run_test() +{ + + /** + * NOTE: [i] is not allowed in this test, since it's done via classinfo and + * we don't have that in xpcshell. + */ + + test_getElementsByTagName(); + test_getElementsByTagNameNS(); + test_getElementsByAttribute(); + test_getElementsByAttributeNS(); + + // What else should we test? + // XXXbz we need more tests here to test liveness! + +} + +function test_getElementsByTagName() +{ + var doc = ParseFile("nodelist_data_1.xml"); + var root = doc.documentElement; + + // Check that getElementsByTagName returns a nodelist. + do_check_true(doc.getElementsByTagName("*") instanceof nsIDOMNodeList); + do_check_true(root.getElementsByTagName("*") instanceof nsIDOMNodeList); + + // Check that getElementsByTagName excludes the element it's called on. + do_check_eq(doc.getElementsByTagName("*").length, + root.getElementsByTagName("*").length + 1); + do_check_eq(doc.getElementById("test2").getElementsByTagName("*").length, + 8); + do_check_eq(doc.getElementById("test2").getElementsByTagName("test").length, + 3); + + // Check that the first element of getElementsByTagName on the document is + // the right thing. + do_check_eq(doc.getElementsByTagName("*").item(0), root); + + // Check that we get the right things in the right order + var numTests = doc.getElementsByTagName("test").length; + do_check_eq(numTests, 5); + + for (var i = 1; i <= numTests; ++i) { + do_check_true(doc.getElementById("test" + i) instanceof nsIDOMElement); + do_check_eq(doc.getElementById("test" + i), + doc.getElementsByTagName("test").item(i-1)); + } + + // Check that we handle tagnames containing ':' correctly + do_check_true(doc.getElementsByTagName("foo:test") + instanceof nsIDOMNodeList); + do_check_eq(doc.getElementsByTagName("foo:test").length, 2); + + do_check_true(doc.getElementsByTagName("foo2:test") + instanceof nsIDOMNodeList); + do_check_eq(doc.getElementsByTagName("foo2:test").length, 3); + + do_check_true(doc.getElementsByTagName("bar:test") + instanceof nsIDOMNodeList); + do_check_eq(doc.getElementsByTagName("bar:test").length, 4); +} + +function test_getElementsByTagNameNS() +{ + var doc = ParseFile("nodelist_data_1.xml"); + var root = doc.documentElement; + + // Check that getElementsByTagNameNS returns a nodelist. + do_check_true(doc.getElementsByTagNameNS("*", "*") instanceof nsIDOMNodeList); + do_check_true(root.getElementsByTagNameNS("*", "*") instanceof nsIDOMNodeList); + + // Check that passing "" and null for the namespace URI gives the same result + var list1 = doc.getElementsByTagNameNS("", "test"); + var list2 = doc.getElementsByTagNameNS(null, "test"); + do_check_eq(list1.length, list2.length); + for (var i = 0; i < list1.length; ++i) { + do_check_eq(list1.item(i), list2.item(i)); + } + + // Check that getElementsByTagNameNS excludes the element it's called on. + do_check_eq(doc.getElementsByTagNameNS("*", "*").length, + root.getElementsByTagNameNS("*", "*").length + 1); + do_check_eq(doc.getElementById("test2") + .getElementsByTagNameNS("*", "*").length, + 8); + do_check_eq(doc.getElementById("test2") + .getElementsByTagNameNS("", "test").length, + 1); + do_check_eq(doc.getElementById("test2") + .getElementsByTagNameNS("*", "test").length, + 7); + + // Check that the first element of getElementsByTagNameNS on the document is + // the right thing. + do_check_eq(doc.getElementsByTagNameNS("*", "*").item(0), root); + do_check_eq(doc.getElementsByTagNameNS(null, "*").item(0), root); + + // Check that we get the right things in the right order + + + var numTests = doc.getElementsByTagNameNS("*", "test").length; + do_check_eq(numTests, 14); + + for (var i = 1; i <= numTests; ++i) { + do_check_true(doc.getElementById("test" + i) instanceof nsIDOMElement); + do_check_eq(doc.getElementById("test" + i), + doc.getElementsByTagNameNS("*", "test").item(i-1)); + } + + // Check general proper functioning of having a non-wildcard namespace. + var test2 = doc.getElementById("test2"); + do_check_eq(doc.getElementsByTagNameNS("", "test").length, + 3); + do_check_eq(test2.getElementsByTagNameNS("", "test").length, + 1); + do_check_eq(doc.getElementsByTagNameNS("foo", "test").length, + 7); + do_check_eq(test2.getElementsByTagNameNS("foo", "test").length, + 4); + do_check_eq(doc.getElementsByTagNameNS("foo2", "test").length, + 0); + do_check_eq(test2.getElementsByTagNameNS("foo2", "test").length, + 0); + do_check_eq(doc.getElementsByTagNameNS("bar", "test").length, + 4); + do_check_eq(test2.getElementsByTagNameNS("bar", "test").length, + 2); + + // Check that we handle tagnames containing ':' correctly + do_check_true(doc.getElementsByTagNameNS(null, "foo:test") + instanceof nsIDOMNodeList); + do_check_eq(doc.getElementsByTagNameNS(null, "foo:test").length, 0); + do_check_eq(doc.getElementsByTagNameNS("foo", "foo:test").length, 0); + do_check_eq(doc.getElementsByTagNameNS("bar", "foo:test").length, 0); + do_check_eq(doc.getElementsByTagNameNS("*", "foo:test").length, 0); + + do_check_true(doc.getElementsByTagNameNS(null, "foo2:test") + instanceof nsIDOMNodeList); + do_check_eq(doc.getElementsByTagNameNS(null, "foo2:test").length, 0); + do_check_eq(doc.getElementsByTagNameNS("foo2", "foo2:test").length, 0); + do_check_eq(doc.getElementsByTagNameNS("bar", "foo2:test").length, 0); + do_check_eq(doc.getElementsByTagNameNS("*", "foo2:test").length, 0); + + do_check_true(doc.getElementsByTagNameNS(null, "bar:test") + instanceof nsIDOMNodeList); + do_check_eq(doc.getElementsByTagNameNS(null, "bar:test").length, 0); + do_check_eq(doc.getElementsByTagNameNS("bar", "bar:test").length, 0); + do_check_eq(doc.getElementsByTagNameNS("*", "bar:test").length, 0); + + // Check that previously-unknown namespaces are handled right. Note that we + // can just hardcode the strings, since we're running only once in XPCshell. + // If someone wants to run these in a browser, some use of Math.random() may + // be in order. + list1 = doc.getElementsByTagNameNS("random-bogus-namespace", "foo"); + list2 = doc.documentElement.getElementsByTagNameNS("random-bogus-namespace2", + "foo"); + do_check_neq(list1, list2); + do_check_eq(list1.length, 0); + do_check_eq(list2.length, 0); + var newNode = doc.createElementNS("random-bogus-namespace", "foo"); + doc.documentElement.appendChild(newNode); + var newNode = doc.createElementNS("random-bogus-namespace2", "foo"); + doc.documentElement.appendChild(newNode); + do_check_eq(list1.length, 1); + do_check_eq(list2.length, 1); +} + +function test_getElementsByAttribute() +{ + var doc = ParseFile("nodelist_data_2.xul"); + var root = doc.documentElement; + + // Sadly, DOMParser can't create XULDocument objects. But at least we have a + // XULElement! + + do_check_true(root instanceof nsIDOMXULElement); + + do_check_true(root.getElementsByAttribute("foo", "foo") instanceof + nsIDOMNodeList); + + var master1 = doc.getElementById("master1"); + var master2 = doc.getElementById("master2"); + var master3 = doc.getElementById("master3"); + var external = doc.getElementById("external"); + + do_check_true(master1 instanceof nsIDOMXULElement); + do_check_true(master2 instanceof nsIDOMXULElement); + do_check_true(master3 instanceof nsIDOMXULElement); + do_check_true(external instanceof nsIDOMXULElement); + + // Basic tests + do_check_eq(root.getElementsByAttribute("foo", "foo").length, + 14); + do_check_eq(master1.getElementsByAttribute("foo", "foo").length, + 4); + + do_check_eq(root.getElementsByAttribute("foo", "bar").length, + 7); + do_check_eq(master1.getElementsByAttribute("foo", "bar").length, + 2); + + do_check_eq(root.getElementsByAttribute("bar", "bar").length, + 7); + do_check_eq(master1.getElementsByAttribute("bar", "bar").length, + 2); + + do_check_eq(root.getElementsByAttribute("foo", "*").length, + 21); + do_check_eq(master1.getElementsByAttribute("foo", "*").length, + 6); + + // Test the various combinations of attributes with colons in the name + do_check_eq(root.getElementsByAttribute("foo:foo", "foo").length, + 16); + do_check_eq(master1.getElementsByAttribute("foo:foo", "foo").length, + 5); + do_check_eq(master2.getElementsByAttribute("foo:foo", "foo").length, + 4); + do_check_eq(master3.getElementsByAttribute("foo:foo", "foo").length, + 4); + do_check_eq(external.getElementsByAttribute("foo:foo", "foo").length, + 2); + + do_check_eq(root.getElementsByAttribute("foo:foo", "bar").length, + 9); + do_check_eq(master1.getElementsByAttribute("foo:foo", "bar").length, + 2); + do_check_eq(master2.getElementsByAttribute("foo:foo", "bar").length, + 3); + do_check_eq(master3.getElementsByAttribute("foo:foo", "bar").length, + 2); + do_check_eq(external.getElementsByAttribute("foo:foo", "bar").length, + 1); + + do_check_eq(root.getElementsByAttribute("foo:bar", "foo").length, + 7); + do_check_eq(master1.getElementsByAttribute("foo:bar", "foo").length, + 2); + do_check_eq(master2.getElementsByAttribute("foo:bar", "foo").length, + 2); + do_check_eq(master3.getElementsByAttribute("foo:bar", "foo").length, + 2); + do_check_eq(external.getElementsByAttribute("foo:bar", "foo").length, + 1); + + do_check_eq(root.getElementsByAttribute("foo:bar", "bar").length, + 14); + do_check_eq(master1.getElementsByAttribute("foo:bar", "bar").length, + 4); + do_check_eq(master2.getElementsByAttribute("foo:bar", "bar").length, + 4); + do_check_eq(master3.getElementsByAttribute("foo:bar", "bar").length, + 4); + do_check_eq(external.getElementsByAttribute("foo:bar", "bar").length, + 2); + + do_check_eq(root.getElementsByAttribute("foo2:foo", "foo").length, + 8); + do_check_eq(master1.getElementsByAttribute("foo2:foo", "foo").length, + 2); + do_check_eq(master2.getElementsByAttribute("foo2:foo", "foo").length, + 2); + do_check_eq(master3.getElementsByAttribute("foo2:foo", "foo").length, + 3); + do_check_eq(external.getElementsByAttribute("foo2:foo", "foo").length, + 1); + + do_check_eq(root.getElementsByAttribute("foo:foo", "*").length, + 25); + do_check_eq(master1.getElementsByAttribute("foo:foo", "*").length, + 7); + do_check_eq(master2.getElementsByAttribute("foo:foo", "*").length, + 7); + do_check_eq(master3.getElementsByAttribute("foo:foo", "*").length, + 6); + do_check_eq(external.getElementsByAttribute("foo:foo", "*").length, + 3); + + do_check_eq(root.getElementsByAttribute("foo2:foo", "bar").length, + 0); + do_check_eq(root.getElementsByAttribute("foo:foo", "baz").length, + 0); +} + +function test_getElementsByAttributeNS() +{ + var doc = ParseFile("nodelist_data_2.xul"); + var root = doc.documentElement; + + // Sadly, DOMParser can't create XULDocument objects. But at least we have a + // XULElement! + + do_check_true(root instanceof nsIDOMXULElement); + + // Check that getElementsByAttributeNS returns a nodelist. + do_check_true(root.getElementsByAttributeNS("*", "*", "*") instanceof + nsIDOMNodeList); + + var master1 = doc.getElementById("master1"); + var master2 = doc.getElementById("master2"); + var master3 = doc.getElementById("master3"); + var external = doc.getElementById("external"); + + do_check_true(master1 instanceof nsIDOMXULElement); + do_check_true(master2 instanceof nsIDOMXULElement); + do_check_true(master3 instanceof nsIDOMXULElement); + do_check_true(external instanceof nsIDOMXULElement); + + // Test wildcard namespace + do_check_eq(root.getElementsByAttributeNS("*", "foo", "foo").length, + 38); + do_check_eq(master1.getElementsByAttributeNS("*", "foo", "foo").length, + 11); + do_check_eq(master2.getElementsByAttributeNS("*", "foo", "foo").length, + 10); + do_check_eq(master3.getElementsByAttributeNS("*", "foo", "foo").length, + 11); + + do_check_eq(root.getElementsByAttributeNS("*", "foo", "bar").length, + 16); + do_check_eq(master1.getElementsByAttributeNS("*", "foo", "bar").length, + 4); + do_check_eq(master2.getElementsByAttributeNS("*", "foo", "bar").length, + 5); + do_check_eq(master3.getElementsByAttributeNS("*", "foo", "bar").length, + 4); + + do_check_eq(root.getElementsByAttributeNS("*", "bar", "bar").length, + 21); + do_check_eq(master1.getElementsByAttributeNS("*", "bar", "bar").length, + 6); + do_check_eq(master2.getElementsByAttributeNS("*", "bar", "bar").length, + 6); + do_check_eq(master3.getElementsByAttributeNS("*", "bar", "bar").length, + 6); + + do_check_eq(root.getElementsByAttributeNS("*", "foo", "*").length, + 54); + do_check_eq(master1.getElementsByAttributeNS("*", "foo", "*").length, + 15); + do_check_eq(master2.getElementsByAttributeNS("*", "foo", "*").length, + 15); + do_check_eq(master3.getElementsByAttributeNS("*", "foo", "*").length, + 15); + + // Test null namespace. This should be the same as getElementsByAttribute. + do_check_eq(root.getElementsByAttributeNS("", "foo", "foo").length, + root.getElementsByAttribute("foo", "foo").length); + do_check_eq(master1.getElementsByAttributeNS("", "foo", "foo").length, + master1.getElementsByAttribute("foo", "foo").length); + do_check_eq(master2.getElementsByAttributeNS("", "foo", "foo").length, + master2.getElementsByAttribute("foo", "foo").length); + do_check_eq(master3.getElementsByAttributeNS("", "foo", "foo").length, + master3.getElementsByAttribute("foo", "foo").length); + + // Test namespace "foo" + do_check_eq(root.getElementsByAttributeNS("foo", "foo", "foo").length, + 24); + do_check_eq(master1.getElementsByAttributeNS("foo", "foo", "foo").length, + 7); + do_check_eq(master2.getElementsByAttributeNS("foo", "foo", "foo").length, + 6); + do_check_eq(master3.getElementsByAttributeNS("foo", "foo", "foo").length, + 7); + + do_check_eq(root.getElementsByAttributeNS("foo", "foo", "bar").length, + 9); + do_check_eq(master1.getElementsByAttributeNS("foo", "foo", "bar").length, + 2); + do_check_eq(master2.getElementsByAttributeNS("foo", "foo", "bar").length, + 3); + do_check_eq(master3.getElementsByAttributeNS("foo", "foo", "bar").length, + 2); + + do_check_eq(root.getElementsByAttributeNS("foo", "bar", "foo").length, + 7); + do_check_eq(master1.getElementsByAttributeNS("foo", "bar", "foo").length, + 2); + do_check_eq(master2.getElementsByAttributeNS("foo", "bar", "foo").length, + 2); + do_check_eq(master3.getElementsByAttributeNS("foo", "bar", "foo").length, + 2); + + do_check_eq(root.getElementsByAttributeNS("foo", "bar", "bar").length, + 14); + do_check_eq(master1.getElementsByAttributeNS("foo", "bar", "bar").length, + 4); + do_check_eq(master2.getElementsByAttributeNS("foo", "bar", "bar").length, + 4); + do_check_eq(master3.getElementsByAttributeNS("foo", "bar", "bar").length, + 4); +} diff --git a/dom/base/test/unit/test_normalize.js b/dom/base/test/unit/test_normalize.js new file mode 100644 index 0000000000..a4f1b4df72 --- /dev/null +++ b/dom/base/test/unit/test_normalize.js @@ -0,0 +1,109 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +function run_test() +{ + /* + * NOTE: [i] is not allowed in this test, since it's done via classinfo and + * we don't have that in xpcshell; the workaround is item(i). Suck. + */ + init(); + + test_element(); + + // more tests would be nice here (such as for documents), but the primary + // uses of Node.normalize() are in test_element; stuff beyond this is either + // unimplemented or is unlikely to be used all that much within a browser + // DOM implementation +} + +// TEST CODE + +var doc; // cache for use in all tests + +function init() +{ + doc = ParseFile("empty_document.xml"); +} + +function test_element() +{ + var x = doc.createElement("funk"); + + // one empty Text node + x.appendChild(doc.createTextNode("")); + do_check_eq(x.childNodes.length, 1); + + x.normalize(); + do_check_eq(x.childNodes.length, 0); + + + // multiple empty Text nodes + x.appendChild(doc.createTextNode("")); + x.appendChild(doc.createTextNode("")); + do_check_eq(x.childNodes.length, 2); + + x.normalize(); + do_check_eq(x.childNodes.length, 0); + + + // empty Text node followed by other Text node + x.appendChild(doc.createTextNode("")); + x.appendChild(doc.createTextNode("Guaraldi")); + do_check_eq(x.childNodes.length, 2); + + x.normalize(); + do_check_eq(x.childNodes.length, 1); + do_check_eq(x.childNodes.item(0).nodeValue, "Guaraldi"); + + + // Text node followed by empty Text node + clearKids(x); + x.appendChild(doc.createTextNode("Guaraldi")); + x.appendChild(doc.createTextNode("")); + do_check_eq(x.childNodes.length, 2); + + x.normalize(); + do_check_eq(x.childNodes.item(0).nodeValue, "Guaraldi"); + + + // Text node followed by empty Text node followed by other Node + clearKids(x); + x.appendChild(doc.createTextNode("Guaraldi")); + x.appendChild(doc.createTextNode("")); + x.appendChild(doc.createElement("jazzy")); + do_check_eq(x.childNodes.length, 3); + + x.normalize(); + do_check_eq(x.childNodes.length, 2); + do_check_eq(x.childNodes.item(0).nodeValue, "Guaraldi"); + do_check_eq(x.childNodes.item(1).nodeName, "jazzy"); + + + // Nodes are recursively normalized + clearKids(x); + var kid = doc.createElement("eit"); + kid.appendChild(doc.createTextNode("")); + + x.appendChild(doc.createTextNode("Guaraldi")); + x.appendChild(doc.createTextNode("")); + x.appendChild(kid); + do_check_eq(x.childNodes.length, 3); + do_check_eq(x.childNodes.item(2).childNodes.length, 1); + + x.normalize(); + do_check_eq(x.childNodes.length, 2); + do_check_eq(x.childNodes.item(0).nodeValue, "Guaraldi"); + do_check_eq(x.childNodes.item(1).childNodes.length, 0); +} + + +// UTILITY FUNCTIONS + +function clearKids(node) +{ + while (node.hasChildNodes()) + node.removeChild(node.childNodes.item(0)); +} diff --git a/dom/base/test/unit/test_range.js b/dom/base/test/unit/test_range.js new file mode 100644 index 0000000000..0ba1e1cd80 --- /dev/null +++ b/dom/base/test/unit/test_range.js @@ -0,0 +1,465 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const C_i = Components.interfaces; + +const UNORDERED_TYPE = C_i.nsIDOMXPathResult.ANY_UNORDERED_NODE_TYPE; + +/** + * Determine if the data node has only ignorable white-space. + * + * @return nsIDOMNodeFilter.FILTER_SKIP if it does. + * @return nsIDOMNodeFilter.FILTER_ACCEPT otherwise. + */ +function isWhitespace(aNode) { + return ((/\S/).test(aNode.nodeValue)) ? + C_i.nsIDOMNodeFilter.FILTER_SKIP : + C_i.nsIDOMNodeFilter.FILTER_ACCEPT; +} + +/** + * Create a DocumentFragment with cloned children equaling a node's children. + * + * @param aNode The node to copy from. + * + * @return DocumentFragment node. + */ +function getFragment(aNode) { + var frag = aNode.ownerDocument.createDocumentFragment(); + for (var i = 0; i < aNode.childNodes.length; i++) { + frag.appendChild(aNode.childNodes.item(i).cloneNode(true)); + } + return frag; +} + +// Goodies from head_content.js +const serializer = new DOMSerializer(); +const parser = new DOMParser(); + +/** + * Dump the contents of a document fragment to the console. + * + * @param aFragment The fragment to serialize. + */ +function dumpFragment(aFragment) { + dump(serializer.serializeToString(aFragment) + "\n\n"); +} + +/** + * Translate an XPath to a DOM node. This method uses a document + * fragment as context node. + * + * @param aContextNode The context node to apply the XPath to. + * @param aPath The XPath to use. + * + * @return nsIDOMNode The target node retrieved from the XPath. + */ +function evalXPathInDocumentFragment(aContextNode, aPath) { + do_check_true(aContextNode instanceof C_i.nsIDOMDocumentFragment); + do_check_true(aContextNode.childNodes.length > 0); + if (aPath == ".") { + return aContextNode; + } + + // Separate the fragment's xpath lookup from the rest. + var firstSlash = aPath.indexOf("/"); + if (firstSlash == -1) { + firstSlash = aPath.length; + } + var prefix = aPath.substr(0, firstSlash); + var realPath = aPath.substr(firstSlash + 1); + if (!realPath) { + realPath = "."; + } + + // Set up a special node filter to look among the fragment's child nodes. + var childIndex = 1; + var bracketIndex = prefix.indexOf("["); + if (bracketIndex != -1) { + childIndex = Number(prefix.substring(bracketIndex + 1, prefix.indexOf("]"))); + do_check_true(childIndex > 0); + prefix = prefix.substr(0, bracketIndex); + } + + var targetType = C_i.nsIDOMNodeFilter.SHOW_ELEMENT; + var targetNodeName = prefix; + if (prefix.indexOf("processing-instruction(") == 0) { + targetType = C_i.nsIDOMNodeFilter.SHOW_PROCESSING_INSTRUCTION; + targetNodeName = prefix.substring(prefix.indexOf("(") + 2, prefix.indexOf(")") - 1); + } + switch (prefix) { + case "text()": + targetType = C_i.nsIDOMNodeFilter.SHOW_TEXT | + C_i.nsIDOMNodeFilter.SHOW_CDATA_SECTION; + targetNodeName = null; + break; + case "comment()": + targetType = C_i.nsIDOMNodeFilter.SHOW_COMMENT; + targetNodeName = null; + break; + case "node()": + targetType = C_i.nsIDOMNodeFilter.SHOW_ALL; + targetNodeName = null; + } + + var filter = { + count: 0, + + // nsIDOMNodeFilter + acceptNode: function acceptNode(aNode) { + if (aNode.parentNode != aContextNode) { + // Don't bother looking at kids either. + return C_i.nsIDOMNodeFilter.FILTER_REJECT; + } + + if (targetNodeName && targetNodeName != aNode.nodeName) { + return C_i.nsIDOMNodeFilter.FILTER_SKIP; + } + + this.count++; + if (this.count != childIndex) { + return C_i.nsIDOMNodeFilter.FILTER_SKIP; + } + + return C_i.nsIDOMNodeFilter.FILTER_ACCEPT; + } + }; + + // Look for the node matching the step from the document fragment. + var walker = aContextNode.ownerDocument.createTreeWalker( + aContextNode, + targetType, + filter); + var targetNode = walker.nextNode(); + do_check_neq(targetNode, null); + + // Apply our remaining xpath to the found node. + var expr = aContextNode.ownerDocument.createExpression(realPath, null); + var result = expr.evaluate(targetNode, UNORDERED_TYPE, null); + return result.singleNodeValue; +} + +/** + * Get a DOM range corresponding to the test's source node. + * + * @param aSourceNode <source/> element with range information. + * @param aFragment DocumentFragment generated with getFragment(). + * + * @return Range object. + */ +function getRange(aSourceNode, aFragment) { + do_check_true(aSourceNode instanceof C_i.nsIDOMElement); + do_check_true(aFragment instanceof C_i.nsIDOMDocumentFragment); + var doc = aSourceNode.ownerDocument; + + var containerPath = aSourceNode.getAttribute("startContainer"); + var startContainer = evalXPathInDocumentFragment(aFragment, containerPath); + var startOffset = Number(aSourceNode.getAttribute("startOffset")); + + containerPath = aSourceNode.getAttribute("endContainer"); + var endContainer = evalXPathInDocumentFragment(aFragment, containerPath); + var endOffset = Number(aSourceNode.getAttribute("endOffset")); + + var range = doc.createRange(); + range.setStart(startContainer, startOffset); + range.setEnd(endContainer, endOffset); + return range; +} + +/** + * Get the document for a given path, and clean it up for our tests. + * + * @param aPath The path to the local document. + */ +function getParsedDocument(aPath) { + return do_parse_document(aPath, "application/xml").then(processParsedDocument); +} + +function processParsedDocument(doc) { + do_check_true(doc.documentElement.localName != "parsererror"); + do_check_true(doc instanceof C_i.nsIDOMXPathEvaluator); + do_check_true(doc instanceof C_i.nsIDOMDocument); + + // Clean out whitespace. + var walker = doc.createTreeWalker(doc, + C_i.nsIDOMNodeFilter.SHOW_TEXT | + C_i.nsIDOMNodeFilter.SHOW_CDATA_SECTION, + isWhitespace); + while (walker.nextNode()) { + var parent = walker.currentNode.parentNode; + parent.removeChild(walker.currentNode); + walker.currentNode = parent; + } + + // Clean out mandatory splits between nodes. + var splits = doc.getElementsByTagName("split"); + var i; + for (i = splits.length - 1; i >= 0; i--) { + var node = splits.item(i); + node.parentNode.removeChild(node); + } + splits = null; + + // Replace empty CDATA sections. + var emptyData = doc.getElementsByTagName("empty-cdata"); + for (i = emptyData.length - 1; i >= 0; i--) { + var node = emptyData.item(i); + var cdata = doc.createCDATASection(""); + node.parentNode.replaceChild(cdata, node); + } + + return doc; +} + +/** + * Run the extraction tests. + */ +function run_extract_test() { + var filePath = "test_delete_range.xml"; + getParsedDocument(filePath).then(do_extract_test); +} + +function do_extract_test(doc) { + var tests = doc.getElementsByTagName("test"); + + // Run our deletion, extraction tests. + for (var i = 0; i < tests.length; i++) { + dump("Configuring for test " + i + "\n"); + var currentTest = tests.item(i); + + // Validate the test is properly formatted for what this harness expects. + var baseSource = currentTest.firstChild; + do_check_eq(baseSource.nodeName, "source"); + var baseResult = baseSource.nextSibling; + do_check_eq(baseResult.nodeName, "result"); + var baseExtract = baseResult.nextSibling; + do_check_eq(baseExtract.nodeName, "extract"); + do_check_eq(baseExtract.nextSibling, null); + + /* We do all our tests on DOM document fragments, derived from the test + element's children. This lets us rip the various fragments to shreds, + while preserving the original elements so we can make more copies of + them. + + After the range's extraction or deletion is done, we use + nsIDOMNode.isEqualNode() between the altered source fragment and the + result fragment. We also run isEqualNode() between the extracted + fragment and the fragment from the baseExtract node. If they are not + equal, we have failed a test. + + We also have to ensure the original nodes on the end points of the + range are still in the source fragment. This is bug 332148. The nodes + may not be replaced with equal but separate nodes. The range extraction + may alter these nodes - in the case of text containers, they will - but + the nodes must stay there, to preserve references such as user data, + event listeners, etc. + + First, an extraction test. + */ + + var resultFrag = getFragment(baseResult); + var extractFrag = getFragment(baseExtract); + + dump("Extract contents test " + i + "\n\n"); + var baseFrag = getFragment(baseSource); + var baseRange = getRange(baseSource, baseFrag); + var startContainer = baseRange.startContainer; + var endContainer = baseRange.endContainer; + + var cutFragment = baseRange.extractContents(); + dump("cutFragment: " + cutFragment + "\n"); + if (cutFragment) { + do_check_true(extractFrag.isEqualNode(cutFragment)); + } else { + do_check_eq(extractFrag.firstChild, null); + } + do_check_true(baseFrag.isEqualNode(resultFrag)); + + dump("Ensure the original nodes weren't extracted - test " + i + "\n\n"); + var walker = doc.createTreeWalker(baseFrag, + C_i.nsIDOMNodeFilter.SHOW_ALL, + null); + var foundStart = false; + var foundEnd = false; + do { + if (walker.currentNode == startContainer) { + foundStart = true; + } + + if (walker.currentNode == endContainer) { + // An end container node should not come before the start container node. + do_check_true(foundStart); + foundEnd = true; + break; + } + } while (walker.nextNode()) + do_check_true(foundEnd); + + /* Now, we reset our test for the deleteContents case. This one differs + from the extractContents case only in that there is no extracted document + fragment to compare against. So we merely compare the starting fragment, + minus the extracted content, against the result fragment. + */ + dump("Delete contents test " + i + "\n\n"); + baseFrag = getFragment(baseSource); + baseRange = getRange(baseSource, baseFrag); + var startContainer = baseRange.startContainer; + var endContainer = baseRange.endContainer; + baseRange.deleteContents(); + do_check_true(baseFrag.isEqualNode(resultFrag)); + + dump("Ensure the original nodes weren't deleted - test " + i + "\n\n"); + walker = doc.createTreeWalker(baseFrag, + C_i.nsIDOMNodeFilter.SHOW_ALL, + null); + foundStart = false; + foundEnd = false; + do { + if (walker.currentNode == startContainer) { + foundStart = true; + } + + if (walker.currentNode == endContainer) { + // An end container node should not come before the start container node. + do_check_true(foundStart); + foundEnd = true; + break; + } + } while (walker.nextNode()) + do_check_true(foundEnd); + + // Clean up after ourselves. + walker = null; + } +} + +/** + * Miscellaneous tests not covered above. + */ +function run_miscellaneous_tests() { + var filePath = "test_delete_range.xml"; + getParsedDocument(filePath).then(do_miscellaneous_tests); +} + +function do_miscellaneous_tests(doc) { + var tests = doc.getElementsByTagName("test"); + + // Let's try some invalid inputs to our DOM range and see what happens. + var currentTest = tests.item(0); + var baseSource = currentTest.firstChild; + var baseResult = baseSource.nextSibling; + var baseExtract = baseResult.nextSibling; + + var baseFrag = getFragment(baseSource); + + var baseRange = getRange(baseSource, baseFrag); + var startContainer = baseRange.startContainer; + var endContainer = baseRange.endContainer; + var startOffset = baseRange.startOffset; + var endOffset = baseRange.endOffset; + + // Text range manipulation. + if ((endOffset > startOffset) && + (startContainer == endContainer) && + (startContainer instanceof C_i.nsIDOMText)) { + // Invalid start node + try { + baseRange.setStart(null, 0); + do_throw("Should have thrown NOT_OBJECT_ERR!"); + } catch (e) { + do_check_eq(e.constructor.name, "TypeError"); + } + + // Invalid start node + try { + baseRange.setStart({}, 0); + do_throw("Should have thrown SecurityError!"); + } catch (e) { + do_check_eq(e.constructor.name, "TypeError"); + } + + // Invalid index + try { + baseRange.setStart(startContainer, -1); + do_throw("Should have thrown IndexSizeError!"); + } catch (e) { + do_check_eq(e.name, "IndexSizeError"); + } + + // Invalid index + var newOffset = startContainer instanceof C_i.nsIDOMText ? + startContainer.nodeValue.length + 1 : + startContainer.childNodes.length + 1; + try { + baseRange.setStart(startContainer, newOffset); + do_throw("Should have thrown IndexSizeError!"); + } catch (e) { + do_check_eq(e.name, "IndexSizeError"); + } + + newOffset--; + // Valid index + baseRange.setStart(startContainer, newOffset); + do_check_eq(baseRange.startContainer, baseRange.endContainer); + do_check_eq(baseRange.startOffset, newOffset); + do_check_true(baseRange.collapsed); + + // Valid index + baseRange.setEnd(startContainer, 0); + do_check_eq(baseRange.startContainer, baseRange.endContainer); + do_check_eq(baseRange.startOffset, 0); + do_check_true(baseRange.collapsed); + } else { + do_throw("The first test should be a text-only range test. Test is invalid.") + } + + /* See what happens when a range has a startContainer in one fragment, and an + endContainer in another. According to the DOM spec, section 2.4, the range + should collapse to the new container and offset. */ + baseRange = getRange(baseSource, baseFrag); + startContainer = baseRange.startContainer; + var startOffset = baseRange.startOffset; + endContainer = baseRange.endContainer; + var endOffset = baseRange.endOffset; + + dump("External fragment test\n\n"); + + var externalTest = tests.item(1); + var externalSource = externalTest.firstChild; + var externalFrag = getFragment(externalSource); + var externalRange = getRange(externalSource, externalFrag); + + baseRange.setEnd(externalRange.endContainer, 0); + do_check_eq(baseRange.startContainer, externalRange.endContainer); + do_check_eq(baseRange.startOffset, 0); + do_check_true(baseRange.collapsed); + + /* + // XXX ajvincent if rv == WRONG_DOCUMENT_ERR, return false? + do_check_false(baseRange.isPointInRange(startContainer, startOffset)); + do_check_false(baseRange.isPointInRange(startContainer, startOffset + 1)); + do_check_false(baseRange.isPointInRange(endContainer, endOffset)); + */ + + // Requested by smaug: A range involving a comment as a document child. + doc = parser.parseFromString("<!-- foo --><foo/>", "application/xml"); + do_check_true(doc instanceof C_i.nsIDOMDocument); + do_check_eq(doc.childNodes.length, 2); + baseRange = doc.createRange(); + baseRange.setStart(doc.firstChild, 1); + baseRange.setEnd(doc.firstChild, 2); + var frag = baseRange.extractContents(); + do_check_eq(frag.childNodes.length, 1); + do_check_true(frag.firstChild instanceof C_i.nsIDOMComment); + do_check_eq(frag.firstChild.nodeValue, "f"); + + /* smaug also requested attribute tests. Sadly, those are not yet supported + in ranges - see https://bugzilla.mozilla.org/show_bug.cgi?id=302775. + */ +} + +function run_test() { + run_extract_test(); + run_miscellaneous_tests(); +} diff --git a/dom/base/test/unit/test_thirdpartyutil.js b/dom/base/test/unit/test_thirdpartyutil.js new file mode 100644 index 0000000000..2c4ef47458 --- /dev/null +++ b/dom/base/test/unit/test_thirdpartyutil.js @@ -0,0 +1,96 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// Test ThirdPartyUtil methods. See mozIThirdPartyUtil. + +var Cc = Components.classes; +var Ci = Components.interfaces; +var Cu = Components.utils; + +Cu.import("resource://gre/modules/NetUtil.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + +var prefs = Cc["@mozilla.org/preferences-service;1"]. + getService(Ci.nsIPrefBranch); + +// Since this test creates a TYPE_DOCUMENT channel via javascript, it will +// end up using the wrong LoadInfo constructor. Setting this pref will disable +// the ContentPolicyType assertion in the constructor. +prefs.setBoolPref("network.loadinfo.skip_type_assertion", true); + +var NS_ERROR_INVALID_ARG = Components.results.NS_ERROR_INVALID_ARG; + +function do_check_throws(f, result, stack) +{ + if (!stack) { + try { + // We might not have a 'Components' object. + stack = Components.stack.caller; + } catch (e) { + } + } + + try { + f(); + } catch (exc) { + do_check_eq(exc.result, result); + return; + } + do_throw("expected " + result + " exception, none thrown", stack); +} + +function run_test() { + let util = Cc["@mozilla.org/thirdpartyutil;1"].getService(Ci.mozIThirdPartyUtil); + + // Create URIs and channels pointing to foo.com and bar.com. + // We will use these to put foo.com into first and third party contexts. + let spec1 = "http://foo.com/foo.html"; + let spec2 = "http://bar.com/bar.html"; + let uri1 = NetUtil.newURI(spec1); + let uri2 = NetUtil.newURI(spec2); + const contentPolicyType = Ci.nsIContentPolicy.TYPE_DOCUMENT; + let channel1 = NetUtil.newChannel({uri: uri1, loadUsingSystemPrincipal: true, contentPolicyType}); + let channel2 = NetUtil.newChannel({uri: uri2, loadUsingSystemPrincipal: true, contentPolicyType}); + + // Create some file:// URIs. + let filespec1 = "file://foo.txt"; + let filespec2 = "file://bar.txt"; + let fileuri1 = NetUtil.newURI(filespec1); + let fileuri2 = NetUtil.newURI(filespec2); + let filechannel1 = NetUtil.newChannel({uri: fileuri1, loadUsingSystemPrincipal: true}); + let filechannel2 = NetUtil.newChannel({uri: fileuri2, loadUsingSystemPrincipal: true}); + + // Test isThirdPartyURI. + do_check_false(util.isThirdPartyURI(uri1, uri1)); + do_check_true(util.isThirdPartyURI(uri1, uri2)); + do_check_true(util.isThirdPartyURI(uri2, uri1)); + do_check_false(util.isThirdPartyURI(fileuri1, fileuri1)); + do_check_false(util.isThirdPartyURI(fileuri1, fileuri2)); + do_check_true(util.isThirdPartyURI(uri1, fileuri1)); + do_check_throws(function() { util.isThirdPartyURI(uri1, null); }, + NS_ERROR_INVALID_ARG); + do_check_throws(function() { util.isThirdPartyURI(null, uri1); }, + NS_ERROR_INVALID_ARG); + do_check_throws(function() { util.isThirdPartyURI(null, null); }, + NS_ERROR_INVALID_ARG); + + // We can't test isThirdPartyWindow since we can't really set up a window + // hierarchy. We leave that to mochitests. + + // Test isThirdPartyChannel. As above, we can't test the bits that require + // a load context or window heirarchy. Because of bug 1259873, we assume + // that these are not third-party. + do_check_throws(function() { util.isThirdPartyChannel(null); }, + NS_ERROR_INVALID_ARG); + do_check_false(util.isThirdPartyChannel(channel1)); + do_check_false(util.isThirdPartyChannel(channel1, uri1)); + do_check_true(util.isThirdPartyChannel(channel1, uri2)); + + let httpchannel1 = channel1.QueryInterface(Ci.nsIHttpChannelInternal); + httpchannel1.forceAllowThirdPartyCookie = true; + do_check_false(util.isThirdPartyChannel(channel1)); + do_check_false(util.isThirdPartyChannel(channel1, uri1)); + do_check_true(util.isThirdPartyChannel(channel1, uri2)); +} + diff --git a/dom/base/test/unit/test_treewalker.js b/dom/base/test/unit/test_treewalker.js new file mode 100644 index 0000000000..e9aff3435c --- /dev/null +++ b/dom/base/test/unit/test_treewalker.js @@ -0,0 +1,26 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +function run_test() +{ + test_treeWalker_currentNode(); +} + +// TEST CODE + +function test_treeWalker_currentNode() +{ + var XHTMLDocString = '<html xmlns="http://www.w3.org/1999/xhtml">'; + XHTMLDocString += '<body><input/>input</body></html>'; + + var doc = ParseXML(XHTMLDocString); + + var body = doc.getElementsByTagName("body")[0]; + var filter = I.nsIDOMNodeFilter.SHOW_ELEMENT | I.nsIDOMNodeFilter.SHOW_TEXT; + var walker = doc.createTreeWalker(body, filter, null); + walker.currentNode = body.firstChild; + walker.nextNode(); +} + diff --git a/dom/base/test/unit/test_xhr_document.js b/dom/base/test/unit/test_xhr_document.js new file mode 100644 index 0000000000..5a090d598f --- /dev/null +++ b/dom/base/test/unit/test_xhr_document.js @@ -0,0 +1,42 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +var Cc = Components.classes; +var Ci = Components.interfaces; +var Cu = Components.utils; + +Cu.import("resource://testing-common/httpd.js"); +Cu.import("resource://gre/modules/NetUtil.jsm"); + +var server = new HttpServer(); +server.start(-1); + +var docbody = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body></body></html>'; + +function handler(metadata, response) { + let body = NetUtil.readInputStreamToString(metadata.bodyInputStream, + metadata.bodyInputStream.available()); + response.setStatusLine(metadata.httpVersion, 200, "OK"); + response.write(body, body.length); +} + +function run_test() { + do_test_pending(); + server.registerPathHandler("/foo", handler); + + var parser = Cc["@mozilla.org/xmlextras/domparser;1"].createInstance(Ci.nsIDOMParser); + parser.init(); + let doc = parser.parseFromString(docbody, "text/html"); + let xhr = Cc['@mozilla.org/xmlextras/xmlhttprequest;1'].createInstance(Ci.nsIXMLHttpRequest); + xhr.onload = function() { + do_check_eq(xhr.responseText, docbody); + server.stop(do_test_finished); + }; + xhr.onerror = function() { + do_check_false(false); + server.stop(do_test_finished); + }; + xhr.open("POST", "http://localhost:" + server.identity.primaryPort + "/foo", true); + xhr.send(doc); +} diff --git a/dom/base/test/unit/test_xhr_origin_attributes.js b/dom/base/test/unit/test_xhr_origin_attributes.js new file mode 100644 index 0000000000..5c53771dad --- /dev/null +++ b/dom/base/test/unit/test_xhr_origin_attributes.js @@ -0,0 +1,50 @@ +let Cc = Components.classes; +let Ci = Components.interfaces; +let Cu = Components.utils; + +Cu.import("resource://testing-common/httpd.js"); + +let server = new HttpServer(); +server.start(-1); + +let body = "<!DOCTYPE HTML><html><head><meta charset='utf-8'></head><body></body></html>"; + +function handler(request, response) { + response.setStatusLine(request.httpVersion, 200, "Ok"); + response.setHeader("Content-Type", "text/html", false); + + if (!request.hasHeader("Cookie")) { + response.setHeader("Set-Cookie", "test", false); + ok(true); + } else { + ok(false); + } + + response.bodyOutputStream.write(body, body.length); +} + +function run_test() { + do_test_pending(); + server.registerPathHandler("/foo", handler); + + let xhr = Cc['@mozilla.org/xmlextras/xmlhttprequest;1'].createInstance(Ci.nsIXMLHttpRequest); + xhr.open("GET", "http://localhost:" + server.identity.primaryPort + "/foo", true); + xhr.send(null); + + xhr.onload = function() { + // We create another XHR to connect to the same site, but this time we + // specify with different origin attributes, which will make the XHR use a + // different cookie-jar than the previous one. + let xhr2 = Cc['@mozilla.org/xmlextras/xmlhttprequest;1'].createInstance(Ci.nsIXMLHttpRequest); + xhr2.open("GET", "http://localhost:" + server.identity.primaryPort + "/foo", true); + xhr2.setOriginAttributes({userContextId: 1}); + xhr2.send(null); + + let loadInfo = xhr2.channel.loadInfo; + Assert.equal(loadInfo.originAttributes.userContextId, 1); + + xhr2.onload = function() { + server.stop(do_test_finished); + } + }; +} diff --git a/dom/base/test/unit/test_xhr_standalone.js b/dom/base/test/unit/test_xhr_standalone.js new file mode 100644 index 0000000000..e1e55f3f58 --- /dev/null +++ b/dom/base/test/unit/test_xhr_standalone.js @@ -0,0 +1,21 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// Test setting .responseType and .withCredentials is allowed +// in non-window non-Worker context + +function run_test() +{ + var xhr = Components.classes['@mozilla.org/xmlextras/xmlhttprequest;1']. + createInstance(Components.interfaces.nsIXMLHttpRequest); + xhr.open('GET', 'data:,', false); + var exceptionThrown = false; + try { + xhr.responseType = ''; + xhr.withCredentials = false; + } catch (e) { + exceptionThrown = true; + } + do_check_eq(false, exceptionThrown); +} diff --git a/dom/base/test/unit/test_xml_parser.js b/dom/base/test/unit/test_xml_parser.js new file mode 100644 index 0000000000..a87c216726 --- /dev/null +++ b/dom/base/test/unit/test_xml_parser.js @@ -0,0 +1,48 @@ +function run_test () { + for (var i = 0; i < tests.length && tests[i][0]; ++i) { + if (!tests[i][0].call()) { + do_throw(tests[i][1]); + } + } +} + +var tests = [ + [ test1, "Unable to parse basic XML document" ], + [ test2, "ParseXML doesn't return nsIDOMDocument" ], + [ test3, "ParseXML return value's documentElement is not nsIDOMElement" ], + [ test4, "" ], + [ test5, "" ], + [ test6, "" ], + [ null ] +]; + +function test1() { + return ParseXML("<root/>"); +} + +function test2() { + return (ParseXML("<root/>") instanceof nsIDOMDocument); +} + +function test3() { + return (ParseXML("<root/>").documentElement instanceof nsIDOMElement); +} + +function test4() { + var doc = ParseXML("<root/>"); + do_check_eq(doc.documentElement.namespaceURI, null); + return true; +} + +function test5() { + var doc = ParseXML("<root xmlns=''/>"); + do_check_eq(doc.documentElement.namespaceURI, null); + return true; +} + +function test6() { + var doc = ParseXML("<root xmlns='ns1'/>"); + do_check_neq(doc.documentElement.namespaceURI, null); + do_check_eq(doc.documentElement.namespaceURI, 'ns1'); + return true; +} diff --git a/dom/base/test/unit/test_xml_serializer.js b/dom/base/test/unit/test_xml_serializer.js new file mode 100644 index 0000000000..c74d067a81 --- /dev/null +++ b/dom/base/test/unit/test_xml_serializer.js @@ -0,0 +1,374 @@ + +// The xml serializer uses the default line break of the plateform. +// So we need to know the value of this default line break, in order +// to build correctly the reference strings for tests. +// This variable will contain this value. +var LB; + +function run_test() { + + if (mozinfo.os == "win") { + LB = "\r\n"; + } else { + LB = "\n"; + } + + for (var i = 0; i < tests.length && tests[i]; ++i) { + tests[i].call(); + } +} + +var tests = [ + test1, + test2, + test3, + test4, + test5, + test6, + test7, + test8, + test9, + test10, + null +]; + +function testString(str) { + do_check_eq(roundtrip(str), str); +} + +function test1() { + // Basic round-tripping which we expect to hand back the same text + // as we passed in (not strictly required for correctness in some of + // those cases, but best for readability of serializer output) + testString('<root/>'); + testString('<root><child/></root>'); + testString('<root xmlns=""/>'); + testString('<root xml:lang="en"/>'); + testString('<root xmlns="ns1"><child xmlns="ns2"/></root>') + testString('<root xmlns="ns1"><child xmlns=""/></root>') + testString('<a:root xmlns:a="ns1"><child/></a:root>') + testString('<a:root xmlns:a="ns1"><a:child/></a:root>') + testString('<a:root xmlns:a="ns1"><b:child xmlns:b="ns1"/></a:root>') + testString('<a:root xmlns:a="ns1"><a:child xmlns:a="ns2"/></a:root>') + testString('<a:root xmlns:a="ns1"><b:child xmlns:b="ns1" b:attr=""/></a:root>') +} + +function test2() { + // Test setting of "xmlns" attribute in the null namespace + + // XXXbz are these tests needed? What should happen here? These + // may be bogus. + + // Setting random "xmlns" attribute + var doc = ParseXML('<root xmlns="ns1"/>'); + doc.documentElement.setAttribute("xmlns", "ns2"); + do_check_serialize(doc); +} + +function test3() { + // Test basic appending of kids. Again, we're making assumptions + // about how our serializer will serialize simple DOMs. + var doc = ParseXML('<root xmlns="ns1"/>'); + var root = doc.documentElement; + var child = doc.createElementNS("ns2", "child"); + root.appendChild(child); + do_check_serialize(doc); + do_check_eq(SerializeXML(doc), + '<root xmlns="ns1"><child xmlns="ns2"/></root>'); + + doc = ParseXML('<root xmlns="ns1"/>'); + root = doc.documentElement; + child = doc.createElementNS("ns2", "prefix:child"); + root.appendChild(child); + do_check_serialize(doc); + do_check_eq(SerializeXML(doc), + '<root xmlns="ns1"><prefix:child xmlns:prefix="ns2"/></root>'); + + doc = ParseXML('<prefix:root xmlns:prefix="ns1"/>'); + root = doc.documentElement; + child = doc.createElementNS("ns2", "prefix:child"); + root.appendChild(child); + do_check_serialize(doc); + do_check_eq(SerializeXML(doc), + '<prefix:root xmlns:prefix="ns1"><a0:child xmlns:a0="ns2"/>'+ + '</prefix:root>'); + +} + +function test4() { + // setAttributeNS tests + + var doc = ParseXML('<root xmlns="ns1"/>'); + var root = doc.documentElement; + root.setAttributeNS("ns1", "prefix:local", "val"); + do_check_serialize(doc); + do_check_eq(SerializeXML(doc), + '<root xmlns="ns1" prefix:local="val" xmlns:prefix="ns1"/>'); + + doc = ParseXML('<prefix:root xmlns:prefix="ns1"/>'); + root = doc.documentElement; + root.setAttributeNS("ns1", "local", "val"); + do_check_serialize(doc); + do_check_eq(SerializeXML(doc), + '<prefix:root xmlns:prefix="ns1" prefix:local="val"/>'); + + doc = ParseXML('<root xmlns="ns1"/>'); + root = doc.documentElement; + root.setAttributeNS("ns2", "local", "val"); + do_check_serialize(doc); + do_check_eq(SerializeXML(doc), + '<root xmlns="ns1" a0:local="val" xmlns:a0="ns2"/>'); + + // Handling of prefix-generation for non-null-namespace attributes + // which have the same namespace as the current default namespace + // (bug 301260). + doc = ParseXML('<root xmlns="ns1"/>'); + root = doc.documentElement; + root.setAttributeNS("ns1", "local", "val"); + do_check_serialize(doc); + do_check_eq(SerializeXML(doc), + '<root xmlns="ns1" a0:local="val" xmlns:a0="ns1"/>'); + + // Tree-walking test + doc = ParseXML('<root xmlns="ns1" xmlns:a="ns2">'+ + '<child xmlns:b="ns2" xmlns:a="ns3">'+ + '<child2/></child></root>'); + root = doc.documentElement; + // Have to QI here -- no classinfo flattening in xpcshell, apparently + var node = root.firstChild.firstChild.QueryInterface(nsIDOMElement); + node.setAttributeNS("ns4", "l1", "v1"); + node.setAttributeNS("ns4", "p2:l2", "v2"); + node.setAttributeNS("", "l3", "v3"); + node.setAttributeNS("ns3", "l4", "v4"); + node.setAttributeNS("ns3", "p5:l5", "v5"); + node.setAttributeNS("ns3", "a:l6", "v6"); + node.setAttributeNS("ns2", "l7", "v7"); + node.setAttributeNS("ns2", "p8:l8", "v8"); + node.setAttributeNS("ns2", "b:l9", "v9"); + node.setAttributeNS("ns2", "a:l10", "v10"); + node.setAttributeNS("ns1", "a:l11", "v11"); + node.setAttributeNS("ns1", "b:l12", "v12"); + node.setAttributeNS("ns1", "l13", "v13"); + do_check_serialize(doc); + // Note: we end up with "a2" as the prefix on "l11" and "l12" because we use + // "a1" earlier, and discard it in favor of something we get off the + // namespace stack, apparently + do_check_eq(SerializeXML(doc), + '<root xmlns="ns1" xmlns:a="ns2">'+ + '<child xmlns:b="ns2" xmlns:a="ns3">'+ + '<child2 a0:l1="v1" xmlns:a0="ns4"' + + ' a0:l2="v2"' + + ' l3="v3"' + + ' a:l4="v4"' + + ' a:l5="v5"' + + ' a:l6="v6"' + + ' b:l7="v7"' + + ' b:l8="v8"' + + ' b:l9="v9"' + + ' b:l10="v10"' + + ' a2:l11="v11" xmlns:a2="ns1"' + + ' a2:l12="v12"' + + ' a2:l13="v13"/></child></root>'); +} + +function test5() { + // Handling of kids in the null namespace when the default is a + // different namespace (bug 301260). + var doc = ParseXML('<root xmlns="ns1"/>') + var child = doc.createElement('child'); + doc.documentElement.appendChild(child); + do_check_serialize(doc); + do_check_eq(SerializeXML(doc), + '<root xmlns="ns1"><child xmlns=""/></root>'); +} + +function test6() { + // Handling of not using a namespace prefix (or default namespace!) + // that's not bound to our namespace in our scope (bug 301260). + var doc = ParseXML('<prefix:root xmlns:prefix="ns1"/>'); + var root = doc.documentElement; + var child1 = doc.createElementNS("ns2", "prefix:child1"); + var child2 = doc.createElementNS("ns1", "prefix:child2"); + child1.appendChild(child2); + root.appendChild(child1); + do_check_serialize(doc); + do_check_eq(SerializeXML(doc), + '<prefix:root xmlns:prefix="ns1"><a0:child1 xmlns:a0="ns2">'+ + '<prefix:child2/></a0:child1></prefix:root>'); + + doc = ParseXML('<root xmlns="ns1"><prefix:child1 xmlns:prefix="ns2"/></root>'); + root = doc.documentElement; + child1 = root.firstChild; + child2 = doc.createElementNS("ns1", "prefix:child2"); + child1.appendChild(child2); + do_check_serialize(doc); + do_check_eq(SerializeXML(doc), + '<root xmlns="ns1"><prefix:child1 xmlns:prefix="ns2">'+ + '<child2/></prefix:child1></root>'); + + doc = ParseXML('<prefix:root xmlns:prefix="ns1">'+ + '<prefix:child1 xmlns:prefix="ns2"/></prefix:root>'); + root = doc.documentElement; + child1 = root.firstChild; + child2 = doc.createElementNS("ns1", "prefix:child2"); + child1.appendChild(child2); + do_check_serialize(doc); + do_check_eq(SerializeXML(doc), + '<prefix:root xmlns:prefix="ns1"><prefix:child1 xmlns:prefix="ns2">'+ + '<a0:child2 xmlns:a0="ns1"/></prefix:child1></prefix:root>'); + + + doc = ParseXML('<root xmlns="ns1"/>'); + root = doc.documentElement; + child1 = doc.createElementNS("ns2", "child1"); + child2 = doc.createElementNS("ns1", "child2"); + child1.appendChild(child2); + root.appendChild(child1); + do_check_serialize(doc); + do_check_eq(SerializeXML(doc), + '<root xmlns="ns1"><child1 xmlns="ns2"><child2 xmlns="ns1"/>'+ + '</child1></root>'); +} + +function test7() { + // Handle xmlns attribute declaring a default namespace on a non-namespaced + // element (bug 326994). + var doc = ParseXML('<root xmlns=""/>') + var root = doc.documentElement; + root.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns", + "http://www.w3.org/1999/xhtml"); + do_check_serialize(doc); + do_check_eq(SerializeXML(doc), '<root/>'); + + doc = ParseXML('<root xmlns=""><child1/></root>') + root = doc.documentElement; + root.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns", + "http://www.w3.org/1999/xhtml"); + do_check_serialize(doc); + do_check_eq(SerializeXML(doc), '<root><child1/></root>'); + + doc = ParseXML('<root xmlns="http://www.w3.org/1999/xhtml">' + + '<child1 xmlns=""><child2/></child1></root>') + root = doc.documentElement; + + // No interface flattening in xpcshell + var child1 = root.firstChild.QueryInterface(nsIDOMElement); + child1.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns", + "http://www.w3.org/1999/xhtml"); + do_check_serialize(doc); + do_check_eq(SerializeXML(doc), + '<root xmlns="http://www.w3.org/1999/xhtml"><child1 xmlns="">' + + '<child2/></child1></root>'); + + doc = ParseXML('<root xmlns="http://www.w3.org/1999/xhtml">' + + '<child1 xmlns="">' + + '<child2 xmlns="http://www.w3.org/1999/xhtml"></child2>' + + '</child1></root>') + root = doc.documentElement; + // No interface flattening in xpcshell + child1 = root.firstChild.QueryInterface(nsIDOMElement); + var child2 = child1.firstChild.QueryInterface(nsIDOMElement); + child1.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns", + "http://www.w3.org/1999/xhtml"); + child2.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns", ""); + do_check_serialize(doc); + do_check_eq(SerializeXML(doc), + '<root xmlns="http://www.w3.org/1999/xhtml"><child1 xmlns="">' + + '<a0:child2 xmlns:a0="http://www.w3.org/1999/xhtml" xmlns=""></a0:child2></child1></root>'); +} + +function test8() { + // Test behavior of serializing with a given charset. + var str1 = '<?xml version="1.0" encoding="ISO-8859-1"?>'+LB+'<root/>'; + var str2 = '<?xml version="1.0" encoding="UTF8"?>'+LB+'<root/>'; + var doc1 = ParseXML(str1); + var doc2 = ParseXML(str2); + + var p = Pipe(); + DOMSerializer().serializeToStream(doc1, p.outputStream, "ISO-8859-1"); + p.outputStream.close(); + do_check_eq(ScriptableInput(p).read(-1), str1); + + p = Pipe(); + DOMSerializer().serializeToStream(doc2, p.outputStream, "ISO-8859-1"); + p.outputStream.close(); + do_check_eq(ScriptableInput(p).read(-1), str1); + + p = Pipe(); + DOMSerializer().serializeToStream(doc1, p.outputStream, "UTF8"); + p.outputStream.close(); + do_check_eq(ScriptableInput(p).read(-1), str2); + + p = Pipe(); + DOMSerializer().serializeToStream(doc2, p.outputStream, "UTF8"); + p.outputStream.close(); + do_check_eq(ScriptableInput(p).read(-1), str2); +} + +function test9() { + // Test behavior of serializing between given charsets, using + // ISO-8859-1-representable text. + var contents = '<root>' + + '\u00BD + \u00BE == \u00BD\u00B2 + \u00BC + \u00BE' + + '</root>'; + var str1 = '<?xml version="1.0" encoding="ISO-8859-1"?>'+ LB + contents; + var str2 = '<?xml version="1.0" encoding="UTF8"?>'+ LB + contents; + var str3 = '<?xml version="1.0" encoding="UTF-16"?>'+ LB + contents; + var doc1 = ParseXML(str1); + var doc2 = ParseXML(str2); + var doc3 = ParseXML(str3); + + checkSerialization(doc1, "ISO-8859-1", str1); + checkSerialization(doc2, "ISO-8859-1", str1); + checkSerialization(doc3, "ISO-8859-1", str1); + + checkSerialization(doc1, "UTF8", str2); + checkSerialization(doc2, "UTF8", str2); + checkSerialization(doc3, "UTF8", str2); + + checkSerialization(doc1, "UTF-16", str3); + checkSerialization(doc2, "UTF-16", str3); + checkSerialization(doc3, "UTF-16", str3); +} + +function test10() { + // Test behavior of serializing between given charsets, using + // Unicode characters (XXX but only BMP ones because I don't know + // how to create one with non-BMP characters, either with JS strings + // or using DOM APIs). + var contents = '<root>' + + 'AZaz09 \u007F ' + // U+000000 to U+00007F + '\u0080 \u0398 \u03BB \u0725 ' + // U+000080 to U+0007FF + '\u0964 \u0F5F \u20AC \uFFFB' + // U+000800 to U+00FFFF + '</root>'; + var str1 = '<?xml version="1.0" encoding="UTF8"?>'+ LB + contents; + var str2 = '<?xml version="1.0" encoding="UTF-16"?>'+ LB + contents; + var doc1 = ParseXML(str1); + var doc2 = ParseXML(str2); + + checkSerialization(doc1, "UTF8", str1); + checkSerialization(doc2, "UTF8", str1); + + checkSerialization(doc1, "UTF-16", str2); + checkSerialization(doc2, "UTF-16", str2); +} + +function checkSerialization(doc, toCharset, expectedString) { + var p = Pipe(); + DOMSerializer().serializeToStream(doc, p.outputStream, toCharset); + p.outputStream.close(); + + var cin = C["@mozilla.org/intl/converter-input-stream;1"] + .createInstance(I.nsIConverterInputStream); + cin.init(p.inputStream, toCharset, 1024, 0x0); + + // compare the first expectedString.length characters for equality + var outString = {}; + var count = cin.readString(expectedString.length, outString); + do_check_true(count == expectedString.length); + do_check_true(outString.value == expectedString); + + // if there's anything more in the stream, it's a bug + do_check_eq(0, cin.readString(1, outString)); + do_check_eq(outString.value, ""); +} diff --git a/dom/base/test/unit/test_xmlserializer.js b/dom/base/test/unit/test_xmlserializer.js new file mode 100644 index 0000000000..8c6020a70c --- /dev/null +++ b/dom/base/test/unit/test_xmlserializer.js @@ -0,0 +1,112 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +function xmlEncode(aFile, aFlags, aCharset) { + if(aFlags == undefined) aFlags = 0; + if(aCharset == undefined) aCharset = "UTF-8"; + + return do_parse_document(aFile, "text/xml").then(doc => { + var encoder = Components.classes["@mozilla.org/layout/documentEncoder;1?type=text/xml"] + .createInstance(nsIDocumentEncoder); + encoder.setCharset(aCharset); + encoder.init(doc, "text/xml", aFlags); + return encoder.encodeToString(); + }); +} + +function run_test() +{ + var result, expected; + const de = Components.interfaces.nsIDocumentEncoder; + + xmlEncode("1_original.xml", de.OutputLFLineBreak).then(result => { + expected = loadContentFile("1_result.xml"); + do_check_eq(expected, result); + }); + + xmlEncode("2_original.xml", de.OutputLFLineBreak).then(result => { + expected = loadContentFile("2_result_1.xml"); + do_check_eq(expected, result); + }); + + xmlEncode("2_original.xml", de.OutputCRLineBreak).then(result => { + expected = expected.replace(/\n/g, "\r"); + do_check_eq(expected, result); + }); + + xmlEncode("2_original.xml", de.OutputLFLineBreak | de.OutputCRLineBreak).then(result => { + expected = expected.replace(/\r/mg, "\r\n"); + do_check_eq(expected, result); + }); + + xmlEncode("2_original.xml", de.OutputLFLineBreak | de.OutputFormatted).then(result => { + expected = loadContentFile("2_result_2.xml"); + do_check_eq(expected, result); + }); + + xmlEncode("2_original.xml", de.OutputLFLineBreak | de.OutputFormatted | de.OutputWrap).then(result => { + expected = loadContentFile("2_result_3.xml"); + do_check_eq(expected, result); + }); + + xmlEncode("2_original.xml", de.OutputLFLineBreak | de.OutputWrap).then(result => { + expected = loadContentFile("2_result_4.xml"); + do_check_eq(expected, result); + }); + + xmlEncode("3_original.xml", de.OutputLFLineBreak | de.OutputFormatted | de.OutputWrap).then(result => { + expected = loadContentFile("3_result.xml"); + do_check_eq(expected, result); + }); + + xmlEncode("3_original.xml", de.OutputLFLineBreak | de.OutputWrap).then(result => { + expected = loadContentFile("3_result_2.xml"); + do_check_eq(expected, result); + }); + + // tests on namespaces + do_parse_document("4_original.xml", "text/xml").then(run_namespace_tests); +} + +function run_namespace_tests(doc) { + const de = Components.interfaces.nsIDocumentEncoder; + var encoder = Components.classes["@mozilla.org/layout/documentEncoder;1?type=text/xml"] + .createInstance(nsIDocumentEncoder); + encoder.setCharset("UTF-8"); + encoder.init(doc, "text/xml", de.OutputLFLineBreak); + + result = encoder.encodeToString(); + expected = loadContentFile("4_result_1.xml"); + do_check_eq(expected, result); + + encoder.setNode(doc.documentElement.childNodes[9]); + result = encoder.encodeToString(); + expected = loadContentFile("4_result_2.xml"); + do_check_eq(expected, result); + + encoder.setNode(doc.documentElement.childNodes[7].childNodes[1]); + result = encoder.encodeToString(); + expected = loadContentFile("4_result_3.xml"); + do_check_eq(expected, result); + + encoder.setNode(doc.documentElement.childNodes[11].childNodes[1]); + result = encoder.encodeToString(); + expected = loadContentFile("4_result_4.xml"); + do_check_eq(expected, result); + + encoder.setCharset("UTF-8"); + // it doesn't support this flags + encoder.init(doc, "text/xml", de.OutputLFLineBreak | de.OutputFormatted | de.OutputWrap); + encoder.setWrapColumn(40); + result = encoder.encodeToString(); + expected = loadContentFile("4_result_5.xml"); + do_check_eq(expected, result); + + encoder.init(doc, "text/xml", de.OutputLFLineBreak | de.OutputWrap); + encoder.setWrapColumn(40); + result = encoder.encodeToString(); + expected = loadContentFile("4_result_6.xml"); + do_check_eq(expected, result); +} diff --git a/dom/base/test/unit/xpcshell.ini b/dom/base/test/unit/xpcshell.ini new file mode 100644 index 0000000000..201b53d91f --- /dev/null +++ b/dom/base/test/unit/xpcshell.ini @@ -0,0 +1,55 @@ +[DEFAULT] +head = head_utilities.js +tail = +support-files = + 1_original.xml + 1_result.xml + 2_original.xml + 2_result_1.xml + 2_result_2.xml + 2_result_3.xml + 2_result_4.xml + 3_original.xml + 3_result.xml + 3_result_2.xml + 4_original.xml + 4_result_1.xml + 4_result_2.xml + 4_result_3.xml + 4_result_4.xml + 4_result_5.xml + 4_result_6.xml + empty_document.xml + isequalnode_data.xml + nodelist_data_1.xml + nodelist_data_2.xul + test_delete_range.xml + +[test_bloburi.js] +[test_bug553888.js] +[test_bug737966.js] +[test_error_codes.js] +run-sequentially = Hardcoded 4444 port. +# Bug 1018414: hardcoded localhost doesn't work properly on some OS X installs +skip-if = os == 'mac' +[test_isequalnode.js] +head = head_xml.js +[test_nodelist.js] +head = head_xml.js +[test_normalize.js] +head = head_xml.js +[test_range.js] +head = head_xml.js +[test_thirdpartyutil.js] +[test_treewalker.js] +head = head_xml.js +[test_xhr_document.js] +[test_xhr_standalone.js] +[test_xhr_origin_attributes.js] +[test_xml_parser.js] +head = head_xml.js +[test_xml_serializer.js] +head = head_xml.js +[test_xmlserializer.js] +[test_cancelPrefetch.js] +[test_chromeutils_base64.js] |