summaryrefslogtreecommitdiffstats
path: root/luni/src/test/java/tests/xml/DomTest.java
diff options
context:
space:
mode:
authorPeter Hallam <peterhal@google.com>2010-05-03 12:57:15 -0700
committerPeter Hallam <peterhal@google.com>2010-05-04 16:30:12 -0700
commit6b811c5daec1b28e6f63b57f98a032236f2c3cf7 (patch)
treea733f20e87a9739253d495c14d54e7d253e35771 /luni/src/test/java/tests/xml/DomTest.java
parent0a98ab45e3566542f2d669eb0ffd28a560d97d28 (diff)
downloadlibcore-6b811c5daec1b28e6f63b57f98a032236f2c3cf7.zip
libcore-6b811c5daec1b28e6f63b57f98a032236f2c3cf7.tar.gz
libcore-6b811c5daec1b28e6f63b57f98a032236f2c3cf7.tar.bz2
Merge awt-kernel, icu, luni-kernel, prefs, security-kernel, x-net into luni
Merge xml except xmlpull and kxml into luni
Diffstat (limited to 'luni/src/test/java/tests/xml/DomTest.java')
-rw-r--r--luni/src/test/java/tests/xml/DomTest.java1383
1 files changed, 1383 insertions, 0 deletions
diff --git a/luni/src/test/java/tests/xml/DomTest.java b/luni/src/test/java/tests/xml/DomTest.java
new file mode 100644
index 0000000..1f723f7
--- /dev/null
+++ b/luni/src/test/java/tests/xml/DomTest.java
@@ -0,0 +1,1383 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tests.xml;
+
+import dalvik.annotation.KnownFailure;
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+import org.w3c.dom.Attr;
+import org.w3c.dom.CDATASection;
+import org.w3c.dom.Comment;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.DOMImplementation;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentType;
+import org.w3c.dom.Element;
+import org.w3c.dom.Entity;
+import org.w3c.dom.EntityReference;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Notation;
+import org.w3c.dom.ProcessingInstruction;
+import org.w3c.dom.Text;
+import org.w3c.dom.TypeInfo;
+import org.w3c.dom.UserDataHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static org.w3c.dom.UserDataHandler.NODE_ADOPTED;
+import static org.w3c.dom.UserDataHandler.NODE_CLONED;
+import static org.w3c.dom.UserDataHandler.NODE_IMPORTED;
+import static org.w3c.dom.UserDataHandler.NODE_RENAMED;
+
+/**
+ * Construct a DOM and then interrogate it.
+ */
+public class DomTest extends TestCase {
+
+ private Transformer transformer;
+ private DocumentBuilder builder;
+ private DOMImplementation domImplementation;
+
+ private final String xml
+ = "<!DOCTYPE menu ["
+ + " <!ENTITY sp \"Maple Syrup\">"
+ + " <!NOTATION png SYSTEM \"image/png\">"
+ + "]>"
+ + "<menu>\n"
+ + " <item xmlns=\"http://food\" xmlns:a=\"http://addons\">\n"
+ + " <name a:standard=\"strawberry\" deluxe=\"&sp;\">Waffles</name>\n"
+ + " <description xmlns=\"http://marketing\">Belgian<![CDATA[ waffles & strawberries (< 5g ]]>of fat)</description>\n"
+ + " <a:option>Whipped Cream</a:option>\n"
+ + " <a:option>&sp;</a:option>\n"
+ + " <?wafflemaker square shape?>\n"
+ + " <nutrition>\n"
+ + " <a:vitamins xmlns:a=\"http://usda\">\n"
+ + " <!-- add other vitamins? --> \n"
+ + " <a:vitaminc>60%</a:vitaminc>\n"
+ + " </a:vitamins>\n"
+ + " </nutrition>\n"
+ + " </item>\n"
+ + "</menu>";
+
+ private Document document;
+ private DocumentType doctype;
+ private Entity sp;
+ private Notation png;
+ private Element menu;
+ private Element item;
+ private Attr itemXmlns;
+ private Attr itemXmlnsA;
+ private Element name;
+ private Attr standard;
+ private Attr deluxe;
+ private Text waffles;
+ private Element description;
+ private Text descriptionText1;
+ private CDATASection descriptionText2;
+ private Text descriptionText3;
+ private Element option1;
+ private Element option2;
+ private Node option2Reference; // resolved to Text on RI, an EntityReference on Dalvik
+ private ProcessingInstruction wafflemaker;
+ private Element nutrition;
+ private Element vitamins;
+ private Attr vitaminsXmlnsA;
+ private Comment comment;
+ private Element vitaminc;
+ private Text vitamincText;
+ private List<Node> allNodes;
+
+ @Override protected void setUp() throws Exception {
+ transformer = TransformerFactory.newInstance().newTransformer();
+ transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ builder = factory.newDocumentBuilder();
+ domImplementation = builder.getDOMImplementation();
+ document = builder.parse(new InputSource(new StringReader(xml)));
+
+ // doctype nodes
+ doctype = document.getDoctype();
+ if (doctype.getEntities() != null) {
+ sp = (Entity) doctype.getEntities().item(0);
+ }
+ if (doctype.getNotations() != null) {
+ png = (Notation) doctype.getNotations().item(0);
+ }
+
+ // document nodes
+ menu = document.getDocumentElement();
+ item = (Element) menu.getChildNodes().item(1);
+ itemXmlns = item.getAttributeNode("xmlns");
+ itemXmlnsA = item.getAttributeNode("xmlns:a");
+ name = (Element) item.getChildNodes().item(1);
+ standard = name.getAttributeNode("a:standard");
+ deluxe = name.getAttributeNode("deluxe");
+ waffles = (Text) name.getChildNodes().item(0);
+ description = (Element) item.getChildNodes().item(3);
+ descriptionText1 = (Text) description.getChildNodes().item(0);
+ descriptionText2 = (CDATASection) description.getChildNodes().item(1);
+ descriptionText3 = (Text) description.getChildNodes().item(2);
+ option1 = (Element) item.getChildNodes().item(5);
+ option2 = (Element) item.getChildNodes().item(7);
+ option2Reference = option2.getChildNodes().item(0);
+ wafflemaker = (ProcessingInstruction) item.getChildNodes().item(9);
+ nutrition = (Element) item.getChildNodes().item(11);
+ vitamins = (Element) nutrition.getChildNodes().item(1);
+ vitaminsXmlnsA = vitamins.getAttributeNode("xmlns:a");
+ comment = (Comment) vitamins.getChildNodes().item(1);
+ vitaminc = (Element) vitamins.getChildNodes().item(3);
+ vitamincText = (Text) vitaminc.getChildNodes().item(0);
+
+ allNodes = new ArrayList<Node>();
+
+ if (sp != null) {
+ allNodes.add(sp);
+ }
+ if (png != null) {
+ allNodes.add(png);
+ }
+
+ allNodes.addAll(Arrays.asList(document, doctype, menu, item, itemXmlns,
+ itemXmlnsA, name, standard, deluxe, waffles, description,
+ descriptionText1, descriptionText2, descriptionText3, option1,
+ option2, option2Reference, wafflemaker, nutrition, vitamins,
+ vitaminsXmlnsA, comment, vitaminc, vitamincText));
+ }
+
+ /**
+ * Android's parsed DOM doesn't include entity declarations. These nodes will
+ * only be tested for implementations that support them.
+ */
+ @KnownFailure("Dalvik doesn't parse entity declarations")
+ public void testEntityDeclarations() {
+ assertNotNull("This implementation does not parse entity declarations", sp);
+ }
+
+ /**
+ * Android's parsed DOM doesn't include notations. These nodes will only be
+ * tested for implementations that support them.
+ */
+ @KnownFailure("Dalvik doesn't parse notations")
+ public void testNotations() {
+ assertNotNull("This implementation does not parse notations", png);
+ }
+
+ public void testLookupNamespaceURIByPrefix() {
+ assertEquals(null, doctype.lookupNamespaceURI("a"));
+ if (sp != null) {
+ assertEquals(null, sp.lookupNamespaceURI("a"));
+ }
+ if (png != null) {
+ assertEquals(null, png.lookupNamespaceURI("a"));
+ }
+ assertEquals(null, document.lookupNamespaceURI("a"));
+ assertEquals(null, menu.lookupNamespaceURI("a"));
+ assertEquals("http://addons", item.lookupNamespaceURI("a"));
+ assertEquals("http://addons", itemXmlns.lookupNamespaceURI("a"));
+ assertEquals("http://addons", itemXmlnsA.lookupNamespaceURI("a"));
+ assertEquals("http://addons", name.lookupNamespaceURI("a"));
+ assertEquals("http://addons", standard.lookupNamespaceURI("a"));
+ assertEquals("http://addons", deluxe.lookupNamespaceURI("a"));
+ assertEquals("http://addons", description.lookupNamespaceURI("a"));
+ assertEquals("http://addons", descriptionText1.lookupNamespaceURI("a"));
+ assertEquals("http://addons", descriptionText2.lookupNamespaceURI("a"));
+ assertEquals("http://addons", descriptionText3.lookupNamespaceURI("a"));
+ assertEquals("http://addons", option1.lookupNamespaceURI("a"));
+ assertEquals("http://addons", option2.lookupNamespaceURI("a"));
+ assertEquals("http://addons", option2Reference.lookupNamespaceURI("a"));
+ assertEquals("http://addons", wafflemaker.lookupNamespaceURI("a"));
+ assertEquals("http://addons", nutrition.lookupNamespaceURI("a"));
+ assertEquals("http://usda", vitamins.lookupNamespaceURI("a"));
+ assertEquals("http://usda", vitaminsXmlnsA.lookupNamespaceURI("a"));
+ assertEquals("http://usda", comment.lookupNamespaceURI("a"));
+ assertEquals("http://usda", vitaminc.lookupNamespaceURI("a"));
+ assertEquals("http://usda", vitamincText.lookupNamespaceURI("a"));
+ }
+
+ public void testLookupNamespaceURIWithNullPrefix() {
+ assertEquals(null, document.lookupNamespaceURI(null));
+ assertEquals(null, doctype.lookupNamespaceURI(null));
+ if (sp != null) {
+ assertEquals(null, sp.lookupNamespaceURI(null));
+ }
+ if (png != null) {
+ assertEquals(null, png.lookupNamespaceURI(null));
+ }
+ assertEquals(null, menu.lookupNamespaceURI(null));
+ assertEquals("http://food", item.lookupNamespaceURI(null));
+ assertEquals("http://food", itemXmlns.lookupNamespaceURI(null));
+ assertEquals("http://food", itemXmlnsA.lookupNamespaceURI(null));
+ assertEquals("http://food", name.lookupNamespaceURI(null));
+ assertEquals("http://food", standard.lookupNamespaceURI(null));
+ assertEquals("http://food", deluxe.lookupNamespaceURI(null));
+ assertEquals("http://marketing", description.lookupNamespaceURI(null));
+ assertEquals("http://marketing", descriptionText1.lookupNamespaceURI(null));
+ assertEquals("http://marketing", descriptionText2.lookupNamespaceURI(null));
+ assertEquals("http://marketing", descriptionText3.lookupNamespaceURI(null));
+ assertEquals("http://food", option1.lookupNamespaceURI(null));
+ assertEquals("http://food", option2.lookupNamespaceURI(null));
+ assertEquals("http://food", option2Reference.lookupNamespaceURI(null));
+ assertEquals("http://food", wafflemaker.lookupNamespaceURI(null));
+ assertEquals("http://food", nutrition.lookupNamespaceURI(null));
+ assertEquals("http://food", vitamins.lookupNamespaceURI(null));
+ assertEquals("http://food", vitaminsXmlnsA.lookupNamespaceURI(null));
+ assertEquals("http://food", comment.lookupNamespaceURI(null));
+ assertEquals("http://food", vitaminc.lookupNamespaceURI(null));
+ assertEquals("http://food", vitamincText.lookupNamespaceURI(null));
+ }
+
+ public void testLookupNamespaceURIWithXmlnsPrefix() {
+ for (Node node : allNodes) {
+ assertEquals(null, node.lookupNamespaceURI("xmlns"));
+ }
+ }
+
+ public void testLookupPrefixWithShadowedUri() {
+ assertEquals(null, document.lookupPrefix("http://addons"));
+ assertEquals(null, doctype.lookupPrefix("http://addons"));
+ if (sp != null) {
+ assertEquals(null, sp.lookupPrefix("http://addons"));
+ }
+ if (png != null) {
+ assertEquals(null, png.lookupPrefix("http://addons"));
+ }
+ assertEquals(null, menu.lookupPrefix("http://addons"));
+ assertEquals("a", item.lookupPrefix("http://addons"));
+ assertEquals("a", itemXmlns.lookupPrefix("http://addons"));
+ assertEquals("a", itemXmlnsA.lookupPrefix("http://addons"));
+ assertEquals("a", name.lookupPrefix("http://addons"));
+ assertEquals("a", standard.lookupPrefix("http://addons"));
+ assertEquals("a", deluxe.lookupPrefix("http://addons"));
+ assertEquals("a", description.lookupPrefix("http://addons"));
+ assertEquals("a", descriptionText1.lookupPrefix("http://addons"));
+ assertEquals("a", descriptionText2.lookupPrefix("http://addons"));
+ assertEquals("a", descriptionText3.lookupPrefix("http://addons"));
+ assertEquals("a", option1.lookupPrefix("http://addons"));
+ assertEquals("a", option2.lookupPrefix("http://addons"));
+ assertEquals("a", option2Reference.lookupPrefix("http://addons"));
+ assertEquals("a", wafflemaker.lookupPrefix("http://addons"));
+ assertEquals("a", nutrition.lookupPrefix("http://addons"));
+ assertEquals(null, vitamins.lookupPrefix("http://addons"));
+ assertEquals(null, vitaminsXmlnsA.lookupPrefix("http://addons"));
+ assertEquals(null, comment.lookupPrefix("http://addons"));
+ assertEquals(null, vitaminc.lookupPrefix("http://addons"));
+ assertEquals(null, vitamincText.lookupPrefix("http://addons"));
+ }
+
+ public void testLookupPrefixWithUnusedUri() {
+ for (Node node : allNodes) {
+ assertEquals(null, node.lookupPrefix("http://unused"));
+ }
+ }
+
+ public void testLookupPrefixWithNullUri() {
+ for (Node node : allNodes) {
+ assertEquals(null, node.lookupPrefix(null));
+ }
+ }
+
+ public void testLookupPrefixWithShadowingUri() {
+ assertEquals(null, document.lookupPrefix("http://usda"));
+ assertEquals(null, doctype.lookupPrefix("http://usda"));
+ if (sp != null) {
+ assertEquals(null, sp.lookupPrefix("http://usda"));
+ }
+ if (png != null) {
+ assertEquals(null, png.lookupPrefix("http://usda"));
+ }
+ assertEquals(null, menu.lookupPrefix("http://usda"));
+ assertEquals(null, item.lookupPrefix("http://usda"));
+ assertEquals(null, itemXmlns.lookupPrefix("http://usda"));
+ assertEquals(null, itemXmlnsA.lookupPrefix("http://usda"));
+ assertEquals(null, name.lookupPrefix("http://usda"));
+ assertEquals(null, standard.lookupPrefix("http://usda"));
+ assertEquals(null, deluxe.lookupPrefix("http://usda"));
+ assertEquals(null, description.lookupPrefix("http://usda"));
+ assertEquals(null, descriptionText1.lookupPrefix("http://usda"));
+ assertEquals(null, descriptionText2.lookupPrefix("http://usda"));
+ assertEquals(null, descriptionText3.lookupPrefix("http://usda"));
+ assertEquals(null, option1.lookupPrefix("http://usda"));
+ assertEquals(null, option2.lookupPrefix("http://usda"));
+ assertEquals(null, option2Reference.lookupPrefix("http://usda"));
+ assertEquals(null, wafflemaker.lookupPrefix("http://usda"));
+ assertEquals(null, nutrition.lookupPrefix("http://usda"));
+ assertEquals("a", vitamins.lookupPrefix("http://usda"));
+ assertEquals("a", vitaminsXmlnsA.lookupPrefix("http://usda"));
+ assertEquals("a", comment.lookupPrefix("http://usda"));
+ assertEquals("a", vitaminc.lookupPrefix("http://usda"));
+ assertEquals("a", vitamincText.lookupPrefix("http://usda"));
+ }
+
+ public void testIsDefaultNamespace() {
+ assertFalse(document.isDefaultNamespace("http://food"));
+ assertFalse(doctype.isDefaultNamespace("http://food"));
+ if (sp != null) {
+ assertFalse(sp.isDefaultNamespace("http://food"));
+ }
+ if (png != null) {
+ assertFalse(png.isDefaultNamespace("http://food"));
+ }
+ assertFalse(menu.isDefaultNamespace("http://food"));
+ assertTrue(item.isDefaultNamespace("http://food"));
+ assertTrue(itemXmlns.isDefaultNamespace("http://food"));
+ assertTrue(itemXmlnsA.isDefaultNamespace("http://food"));
+ assertTrue(name.isDefaultNamespace("http://food"));
+ assertTrue(standard.isDefaultNamespace("http://food"));
+ assertTrue(deluxe.isDefaultNamespace("http://food"));
+ assertFalse(description.isDefaultNamespace("http://food"));
+ assertFalse(descriptionText1.isDefaultNamespace("http://food"));
+ assertFalse(descriptionText2.isDefaultNamespace("http://food"));
+ assertFalse(descriptionText3.isDefaultNamespace("http://food"));
+ assertTrue(option1.isDefaultNamespace("http://food"));
+ assertTrue(option2.isDefaultNamespace("http://food"));
+ assertTrue(option2Reference.isDefaultNamespace("http://food"));
+ assertTrue(wafflemaker.isDefaultNamespace("http://food"));
+ assertTrue(nutrition.isDefaultNamespace("http://food"));
+ assertTrue(vitamins.isDefaultNamespace("http://food"));
+ assertTrue(vitaminsXmlnsA.isDefaultNamespace("http://food"));
+ assertTrue(comment.isDefaultNamespace("http://food"));
+ assertTrue(vitaminc.isDefaultNamespace("http://food"));
+ assertTrue(vitamincText.isDefaultNamespace("http://food"));
+ }
+
+ /**
+ * Xerces fails this test. It returns false always for entity, notation,
+ * document fragment and document type nodes. This contradicts its own
+ * behaviour on lookupNamespaceURI(null).
+ */
+ public void testIsDefaultNamespaceNull_XercesBugs() {
+ String message = "isDefaultNamespace() should be consistent with lookupNamespaceURI(null)";
+ assertTrue(message, doctype.isDefaultNamespace(null));
+ if (sp != null) {
+ assertTrue(message, sp.isDefaultNamespace(null));
+ }
+ if (png != null) {
+ assertTrue(message, png.isDefaultNamespace(null));
+ }
+ }
+
+ public void testIsDefaultNamespaceNull() {
+ assertTrue(document.isDefaultNamespace(null));
+ assertTrue(menu.isDefaultNamespace(null));
+ assertFalse(item.isDefaultNamespace(null));
+ assertFalse(itemXmlns.isDefaultNamespace(null));
+ assertFalse(itemXmlnsA.isDefaultNamespace(null));
+ assertFalse(name.isDefaultNamespace(null));
+ assertFalse(standard.isDefaultNamespace(null));
+ assertFalse(deluxe.isDefaultNamespace(null));
+ assertFalse(description.isDefaultNamespace(null));
+ assertFalse(descriptionText1.isDefaultNamespace(null));
+ assertFalse(descriptionText2.isDefaultNamespace(null));
+ assertFalse(descriptionText3.isDefaultNamespace(null));
+ assertFalse(option1.isDefaultNamespace(null));
+ assertFalse(option2.isDefaultNamespace(null));
+ assertFalse(option2Reference.isDefaultNamespace(null));
+ assertFalse(wafflemaker.isDefaultNamespace(null));
+ assertFalse(nutrition.isDefaultNamespace(null));
+ assertFalse(vitamins.isDefaultNamespace(null));
+ assertFalse(vitaminsXmlnsA.isDefaultNamespace(null));
+ assertFalse(comment.isDefaultNamespace(null));
+ assertFalse(vitaminc.isDefaultNamespace(null));
+ assertFalse(vitamincText.isDefaultNamespace(null));
+ }
+
+ public void testDoctypeSetTextContent() throws TransformerException {
+ String original = domToString(document);
+ doctype.setTextContent("foobar"); // strangely, this is specified to no-op
+ assertEquals(original, domToString(document));
+ }
+
+ public void testDocumentSetTextContent() throws TransformerException {
+ String original = domToString(document);
+ document.setTextContent("foobar"); // strangely, this is specified to no-op
+ assertEquals(original, domToString(document));
+ }
+
+ public void testElementSetTextContent() throws TransformerException {
+ String original = domToString(document);
+ nutrition.setTextContent("foobar");
+ String expected = original.replaceFirst(
+ "(?s)<nutrition>.*</nutrition>", "<nutrition>foobar</nutrition>");
+ assertEquals(expected, domToString(document));
+ }
+
+ public void testEntitySetTextContent() throws TransformerException {
+ if (sp == null) {
+ return;
+ }
+ try {
+ sp.setTextContent("foobar");
+ fail(); // is this implementation-specific behaviour?
+ } catch (DOMException e) {
+ }
+ }
+
+ public void testNotationSetTextContent() throws TransformerException {
+ if (png == null) {
+ return;
+ }
+ String original = domToString(document);
+ png.setTextContent("foobar");
+ String expected = original.replace("image/png", "foobar");
+ assertEquals(expected, domToString(document));
+ }
+
+ /**
+ * Tests setTextContent on entity references. Although the other tests can
+ * act on a parsed DOM, this needs to use a programmatically constructed DOM
+ * because the parser may have replaced the entity reference with the
+ * corresponding text.
+ */
+ public void testEntityReferenceSetTextContent() throws TransformerException {
+ document = builder.newDocument();
+ Element root = document.createElement("menu");
+ document.appendChild(root);
+
+ EntityReference entityReference = document.createEntityReference("sp");
+ root.appendChild(entityReference);
+
+ try {
+ entityReference.setTextContent("Lite Syrup");
+ fail();
+ } catch (DOMException e) {
+ }
+ }
+
+ public void testAttributeSetTextContent() throws TransformerException {
+ String original = domToString(document);
+ standard.setTextContent("foobar");
+ String expected = original.replace("standard=\"strawberry\"", "standard=\"foobar\"");
+ assertEquals(expected, domToString(document));
+ }
+
+ public void testTextSetTextContent() throws TransformerException {
+ String original = domToString(document);
+ descriptionText1.setTextContent("foobar");
+ String expected = original.replace(">Belgian<!", ">foobar<!");
+ assertEquals(expected, domToString(document));
+ }
+
+ public void testCdataSetTextContent() throws TransformerException {
+ String original = domToString(document);
+ descriptionText2.setTextContent("foobar");
+ String expected = original.replace(
+ " waffles & strawberries (< 5g ", "foobar");
+ assertEquals(expected, domToString(document));
+ }
+
+ public void testProcessingInstructionSetTextContent() throws TransformerException {
+ String original = domToString(document);
+ wafflemaker.setTextContent("foobar");
+ String expected = original.replace(" square shape?>", " foobar?>");
+ assertEquals(expected, domToString(document));
+ }
+
+ public void testCommentSetTextContent() throws TransformerException {
+ String original = domToString(document);
+ comment.setTextContent("foobar");
+ String expected = original.replace("-- add other vitamins? --", "--foobar--");
+ assertEquals(expected, domToString(document));
+ }
+
+ public void testCoreFeature() {
+ assertFeature("Core", null);
+ assertFeature("Core", "");
+ assertFeature("Core", "1.0");
+ assertFeature("Core", "2.0");
+ assertFeature("Core", "3.0");
+ assertFeature("CORE", "3.0");
+ assertFeature("+Core", "3.0");
+ assertNoFeature("Core", "4.0");
+ }
+
+ public void testXmlFeature() {
+ assertFeature("XML", null);
+ assertFeature("XML", "");
+ assertFeature("XML", "1.0");
+ assertFeature("XML", "2.0");
+ assertFeature("XML", "3.0");
+ assertFeature("Xml", "3.0");
+ assertFeature("+XML", "3.0");
+ assertNoFeature("XML", "4.0");
+ }
+
+ /**
+ * The RI fails this test.
+ * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#Document3-version
+ */
+ public void testXmlVersionFeature() {
+ assertFeature("XMLVersion", null);
+ assertFeature("XMLVersion", "");
+ assertFeature("XMLVersion", "1.0");
+ assertFeature("XMLVersion", "1.1");
+ assertFeature("XMLVERSION", "1.1");
+ assertFeature("+XMLVersion", "1.1");
+ assertNoFeature("XMLVersion", "1.2");
+ assertNoFeature("XMLVersion", "2.0");
+ assertNoFeature("XMLVersion", "2.0");
+ }
+
+ @KnownFailure("Dalvik doesn't support load/save")
+ public void testLoadSaveFeature() {
+ assertFeature("LS", "3.0");
+ }
+
+ @KnownFailure("Dalvik doesn't support the element traversal feature")
+ public void testElementTraversalFeature() {
+ assertFeature("ElementTraversal", "1.0");
+ }
+
+ private void assertFeature(String feature, String version) {
+ String message = "This implementation is expected to support "
+ + feature + " v. " + version + " but does not.";
+ assertTrue(message, domImplementation.hasFeature(feature, version));
+ assertNotNull(message, domImplementation.getFeature(feature, version));
+ }
+
+ private void assertNoFeature(String feature, String version) {
+ assertFalse(domImplementation.hasFeature(feature, version));
+ assertNull(domImplementation.getFeature(feature, version));
+ }
+
+ public void testIsSupported() {
+ // we don't independently test the features; instead just assume the
+ // implementation calls through to hasFeature (as tested above)
+ for (Node node : allNodes) {
+ assertTrue(node.isSupported("XML", null));
+ assertTrue(node.isSupported("XML", "3.0"));
+ assertFalse(node.isSupported("foo", null));
+ assertFalse(node.isSupported("foo", "bar"));
+ }
+ }
+
+ public void testGetFeature() {
+ // we don't independently test the features; instead just assume the
+ // implementation calls through to hasFeature (as tested above)
+ for (Node node : allNodes) {
+ assertSame(node, node.getFeature("XML", null));
+ assertSame(node, node.getFeature("XML", "3.0"));
+ assertNull(node.getFeature("foo", null));
+ assertNull(node.getFeature("foo", "bar"));
+ }
+ }
+
+ public void testNodeEqualsPositive() throws Exception {
+ DomTest copy = new DomTest();
+ copy.setUp();
+
+ for (int i = 0; i < allNodes.size(); i++) {
+ Node a = allNodes.get(i);
+ Node b = copy.allNodes.get(i);
+ assertTrue(a.isEqualNode(b));
+ }
+ }
+
+ public void testNodeEqualsNegative() throws Exception {
+ for (Node a : allNodes) {
+ for (Node b : allNodes) {
+ assertEquals(a == b, a.isEqualNode(b));
+ }
+ }
+ }
+
+ public void testNodeEqualsNegativeRecursive() throws Exception {
+ DomTest copy = new DomTest();
+ copy.setUp();
+ copy.vitaminc.setTextContent("55%");
+
+ // changing anything about a node should break equality for all parents
+ assertFalse(document.isEqualNode(copy.document));
+ assertFalse(menu.isEqualNode(copy.menu));
+ assertFalse(item.isEqualNode(copy.item));
+ assertFalse(nutrition.isEqualNode(copy.nutrition));
+ assertFalse(vitamins.isEqualNode(copy.vitamins));
+ assertFalse(vitaminc.isEqualNode(copy.vitaminc));
+
+ // but not siblings
+ assertTrue(doctype.isEqualNode(copy.doctype));
+ assertTrue(description.isEqualNode(copy.description));
+ assertTrue(option1.isEqualNode(copy.option1));
+ }
+
+ public void testNodeEqualsNull() {
+ for (Node node : allNodes) {
+ try {
+ node.isEqualNode(null);
+ fail();
+ } catch (NullPointerException e) {
+ }
+ }
+ }
+
+ public void testIsElementContentWhitespaceWithoutDeclaration() throws Exception {
+ String xml = "<menu> <item/> </menu>";
+
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ Text text = (Text) factory.newDocumentBuilder()
+ .parse(new InputSource(new StringReader(xml)))
+ .getDocumentElement().getChildNodes().item(0);
+ assertFalse(text.isElementContentWhitespace());
+ }
+
+ @KnownFailure("Dalvik doesn't recognize element content whitespace")
+ public void testIsElementContentWhitespaceWithDeclaration() throws Exception {
+ String xml = "<!DOCTYPE menu [\n"
+ + " <!ELEMENT menu (item)*>\n"
+ + " <!ELEMENT item (#PCDATA)>\n"
+ + "]><menu> <item/> </menu>";
+
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ Text text = (Text) factory.newDocumentBuilder()
+ .parse(new InputSource(new StringReader(xml)))
+ .getDocumentElement().getChildNodes().item(0);
+ assertTrue("This implementation does not recognize element content whitespace",
+ text.isElementContentWhitespace());
+ }
+
+ public void testGetWholeTextFirst() {
+ assertEquals("Belgian waffles & strawberries (< 5g of fat)",
+ descriptionText1.getWholeText());
+ }
+
+ public void testGetWholeTextMiddle() {
+ assertEquals("This implementation doesn't include preceding nodes in getWholeText()",
+ "Belgian waffles & strawberries (< 5g of fat)", descriptionText2.getWholeText());
+ }
+
+ public void testGetWholeTextLast() {
+ assertEquals("This implementation doesn't include preceding nodes in getWholeText()",
+ "Belgian waffles & strawberries (< 5g of fat)", descriptionText3.getWholeText());
+ }
+
+ public void testGetWholeTextOnly() {
+ assertEquals("60%", vitamincText.getWholeText());
+ }
+
+ @KnownFailure("Dalvik doesn't resolve entity references")
+ public void testGetWholeTextWithEntityReference() {
+ EntityReference spReference = document.createEntityReference("sp");
+ description.insertBefore(spReference, descriptionText2);
+
+ assertEquals("This implementation doesn't resolve entity references in getWholeText()",
+ "BelgianMaple Syrup waffles & strawberries (< 5g of fat)",
+ descriptionText1.getWholeText());
+ }
+
+ public void testReplaceWholeTextFirst() throws TransformerException {
+ String original = domToString(document);
+ Text replacement = descriptionText1.replaceWholeText("Eggos");
+ assertSame(descriptionText1, replacement);
+ String expected = original.replace(
+ "Belgian<![CDATA[ waffles & strawberries (< 5g ]]>of fat)", "Eggos");
+ assertEquals(expected, domToString(document));
+ }
+
+ public void testReplaceWholeTextMiddle() throws TransformerException {
+ String original = domToString(document);
+ Text replacement = descriptionText2.replaceWholeText("Eggos");
+ assertSame(descriptionText2, replacement);
+ String expected = original.replace(
+ "Belgian<![CDATA[ waffles & strawberries (< 5g ]]>of fat)", "<![CDATA[Eggos]]>");
+ assertEquals("This implementation doesn't remove preceding nodes in replaceWholeText()",
+ expected, domToString(document));
+ }
+
+ public void testReplaceWholeTextLast() throws TransformerException {
+ String original = domToString(document);
+ Text replacement = descriptionText3.replaceWholeText("Eggos");
+ assertSame(descriptionText3, replacement);
+ String expected = original.replace(
+ "Belgian<![CDATA[ waffles & strawberries (< 5g ]]>of fat)", "Eggos");
+ assertEquals("This implementation doesn't remove preceding nodes in replaceWholeText()",
+ expected, domToString(document));
+ }
+
+ public void testReplaceWholeTextOnly() throws TransformerException {
+ String original = domToString(document);
+ Text replacement = vitamincText.replaceWholeText("70%");
+ assertEquals(Node.TEXT_NODE, replacement.getNodeType());
+ assertSame(vitamincText, replacement);
+ String expected = original.replace("60%", "70%");
+ assertEquals(expected, domToString(document));
+ }
+
+ public void testReplaceWholeTextFirstWithNull() throws TransformerException {
+ String original = domToString(document);
+ assertNull(descriptionText1.replaceWholeText(null));
+ String expected = original.replaceFirst(">.*</description>", "/>");
+ assertEquals("This implementation doesn't remove adjacent nodes in replaceWholeText(null)",
+ expected, domToString(document));
+ }
+
+ public void testReplaceWholeTextMiddleWithNull() throws TransformerException {
+ String original = domToString(document);
+ assertNull(descriptionText2.replaceWholeText(null));
+ String expected = original.replaceFirst(">.*</description>", "/>");
+ assertEquals("This implementation doesn't remove adjacent nodes in replaceWholeText(null)",
+ expected, domToString(document));
+ }
+
+ public void testReplaceWholeTextLastWithNull() throws TransformerException {
+ String original = domToString(document);
+ assertNull(descriptionText3.replaceWholeText(null));
+ String expected = original.replaceFirst(">.*</description>", "/>");
+ assertEquals("This implementation doesn't remove adjacent nodes in replaceWholeText(null)",
+ expected, domToString(document));
+ }
+
+ public void testReplaceWholeTextFirstWithEmptyString() throws TransformerException {
+ String original = domToString(document);
+ assertNull(descriptionText1.replaceWholeText(""));
+ String expected = original.replaceFirst(">.*</description>", "/>");
+ assertEquals("This implementation doesn't remove adjacent nodes in replaceWholeText(null)",
+ expected, domToString(document));
+ }
+
+ public void testReplaceWholeTextOnlyWithEmptyString() throws TransformerException {
+ String original = domToString(document);
+ assertNull(vitamincText.replaceWholeText(""));
+ String expected = original.replaceFirst(">.*</a:vitaminc>", "/>");
+ assertEquals(expected, domToString(document));
+ }
+
+ public void testUserDataAttachments() {
+ Object a = new Object();
+ Object b = new Object();
+ for (Node node : allNodes) {
+ node.setUserData("a", a, null);
+ node.setUserData("b", b, null);
+ }
+ for (Node node : allNodes) {
+ assertSame(a, node.getUserData("a"));
+ assertSame(b, node.getUserData("b"));
+ assertEquals(null, node.getUserData("c"));
+ assertEquals(null, node.getUserData("A"));
+ }
+ }
+
+ public void testUserDataRejectsNullKey() {
+ try {
+ menu.setUserData(null, "apple", null);
+ fail();
+ } catch (NullPointerException e) {
+ }
+ try {
+ menu.getUserData(null);
+ fail();
+ } catch (NullPointerException e) {
+ }
+ }
+
+ /**
+ * A shallow clone requires cloning the attributes but not the child nodes.
+ */
+ public void testUserDataHandlerNotifiedOfShallowClones() {
+ RecordingHandler handler = new RecordingHandler();
+ name.setUserData("a", "apple", handler);
+ name.setUserData("b", "banana", handler);
+ standard.setUserData("c", "cat", handler);
+ waffles.setUserData("d", "dog", handler);
+
+ Element clonedName = (Element) name.cloneNode(false);
+ Attr clonedStandard = clonedName.getAttributeNode("a:standard");
+
+ Set<String> expected = new HashSet<String>();
+ expected.add(notification(NODE_CLONED, "a", "apple", name, clonedName));
+ expected.add(notification(NODE_CLONED, "b", "banana", name, clonedName));
+ expected.add(notification(NODE_CLONED, "c", "cat", standard, clonedStandard));
+ assertEquals(expected, handler.calls);
+ }
+
+ /**
+ * A deep clone requires cloning both the attributes and the child nodes.
+ */
+ public void testUserDataHandlerNotifiedOfDeepClones() {
+ RecordingHandler handler = new RecordingHandler();
+ name.setUserData("a", "apple", handler);
+ name.setUserData("b", "banana", handler);
+ standard.setUserData("c", "cat", handler);
+ waffles.setUserData("d", "dog", handler);
+
+ Element clonedName = (Element) name.cloneNode(true);
+ Attr clonedStandard = clonedName.getAttributeNode("a:standard");
+ Text clonedWaffles = (Text) clonedName.getChildNodes().item(0);
+
+ Set<String> expected = new HashSet<String>();
+ expected.add(notification(NODE_CLONED, "a", "apple", name, clonedName));
+ expected.add(notification(NODE_CLONED, "b", "banana", name, clonedName));
+ expected.add(notification(NODE_CLONED, "c", "cat", standard, clonedStandard));
+ expected.add(notification(NODE_CLONED, "d", "dog", waffles, clonedWaffles));
+ assertEquals(expected, handler.calls);
+ }
+
+ /**
+ * A shallow import requires importing the attributes but not the child
+ * nodes.
+ */
+ public void testUserDataHandlerNotifiedOfShallowImports() {
+ RecordingHandler handler = new RecordingHandler();
+ name.setUserData("a", "apple", handler);
+ name.setUserData("b", "banana", handler);
+ standard.setUserData("c", "cat", handler);
+ waffles.setUserData("d", "dog", handler);
+
+ Document newDocument = builder.newDocument();
+ Element importedName = (Element) newDocument.importNode(name, false);
+ Attr importedStandard = importedName.getAttributeNode("a:standard");
+
+ Set<String> expected = new HashSet<String>();
+ expected.add(notification(NODE_IMPORTED, "a", "apple", name, importedName));
+ expected.add(notification(NODE_IMPORTED, "b", "banana", name, importedName));
+ expected.add(notification(NODE_IMPORTED, "c", "cat", standard, importedStandard));
+ assertEquals(expected, handler.calls);
+ }
+
+ /**
+ * A deep import requires cloning both the attributes and the child nodes.
+ */
+ public void testUserDataHandlerNotifiedOfDeepImports() {
+ RecordingHandler handler = new RecordingHandler();
+ name.setUserData("a", "apple", handler);
+ name.setUserData("b", "banana", handler);
+ standard.setUserData("c", "cat", handler);
+ waffles.setUserData("d", "dog", handler);
+
+ Document newDocument = builder.newDocument();
+ Element importedName = (Element) newDocument.importNode(name, true);
+ Attr importedStandard = importedName.getAttributeNode("a:standard");
+ Text importedWaffles = (Text) importedName.getChildNodes().item(0);
+
+ Set<String> expected = new HashSet<String>();
+ expected.add(notification(NODE_IMPORTED, "a", "apple", name, importedName));
+ expected.add(notification(NODE_IMPORTED, "b", "banana", name, importedName));
+ expected.add(notification(NODE_IMPORTED, "c", "cat", standard, importedStandard));
+ expected.add(notification(NODE_IMPORTED, "d", "dog", waffles, importedWaffles));
+ assertEquals(expected, handler.calls);
+ }
+
+ public void testImportNodeDeep() throws TransformerException {
+ String original = domToStringStripElementWhitespace(document);
+
+ Document newDocument = builder.newDocument();
+ Element importedItem = (Element) newDocument.importNode(item, true);
+ assertDetached(item.getParentNode(), importedItem);
+
+ newDocument.appendChild(importedItem);
+ String expected = original.replaceAll("</?menu>", "");
+ assertEquals(expected, domToStringStripElementWhitespace(newDocument));
+ }
+
+ public void testImportNodeShallow() throws TransformerException {
+ Document newDocument = builder.newDocument();
+ Element importedItem = (Element) newDocument.importNode(item, false);
+ assertDetached(item.getParentNode(), importedItem);
+
+ newDocument.appendChild(importedItem);
+ assertEquals("<item xmlns=\"http://food\" xmlns:a=\"http://addons\"/>",
+ domToString(newDocument));
+ }
+
+ public void testNodeAdoption() throws Exception {
+ for (Node node : allNodes) {
+ if (node == document || node == doctype || node == sp || node == png) {
+ assertNotAdoptable(node);
+ } else {
+ adoptAndCheck(node);
+ }
+ }
+ }
+
+ private void assertNotAdoptable(Node node) {
+ try {
+ builder.newDocument().adoptNode(node);
+ fail();
+ } catch (DOMException e) {
+ }
+ }
+
+ /**
+ * Adopts the node into another document, then adopts the root element, and
+ * then attaches the adopted node in the proper place. The net result should
+ * be that the document's entire contents have moved to another document.
+ */
+ private void adoptAndCheck(Node node) throws Exception {
+ String original = domToString(document);
+ Document newDocument = builder.newDocument();
+
+ // remember where to insert the node in the new document
+ boolean isAttribute = node.getNodeType() == Node.ATTRIBUTE_NODE;
+ Node parent = isAttribute
+ ? ((Attr) node).getOwnerElement() : node.getParentNode();
+ Node nextSibling = node.getNextSibling();
+
+ // move the node and make sure it was detached
+ assertSame(node, newDocument.adoptNode(node));
+ assertDetached(parent, node);
+
+ // move the rest of the document and wire the adopted back into place
+ assertSame(menu, newDocument.adoptNode(menu));
+ newDocument.appendChild(menu);
+ if (isAttribute) {
+ ((Element) parent).setAttributeNodeNS((Attr) node);
+ } else if (nextSibling != null) {
+ parent.insertBefore(node, nextSibling);
+ } else if (parent != document) {
+ parent.appendChild(node);
+ }
+
+ assertEquals(original, domToString(newDocument));
+ document = newDocument;
+ }
+
+ private void assertDetached(Node formerParent, Node node) {
+ assertNull(node.getParentNode());
+ NodeList children = formerParent.getChildNodes();
+ for (int i = 0; i < children.getLength(); i++) {
+ assertTrue(children.item(i) != node);
+ }
+ if (node.getNodeType() == Node.ATTRIBUTE_NODE) {
+ assertNull(((Attr) node).getOwnerElement());
+ NamedNodeMap attributes = formerParent.getAttributes();
+ for (int i = 0; i < attributes.getLength(); i++) {
+ assertTrue(attributes.item(i) != node);
+ }
+ }
+ }
+
+ public void testAdoptionImmediatelyAfterParsing() throws Exception {
+ Document newDocument = builder.newDocument();
+ try {
+ assertSame(name, newDocument.adoptNode(name));
+ assertSame(newDocument, name.getOwnerDocument());
+ assertSame(newDocument, standard.getOwnerDocument());
+ assertSame(newDocument, waffles.getOwnerDocument());
+ } catch (Throwable e) {
+ AssertionFailedError failure = new AssertionFailedError(
+ "This implementation fails to adopt nodes before the "
+ + "document has been traversed");
+ failure.initCause(e);
+ throw failure;
+ }
+ }
+
+ /**
+ * There should be notifications for adopted node itself but none of its
+ * children. The DOM spec is vague on this, so we're consistent with the RI.
+ */
+ public void testUserDataHandlerNotifiedOfOnlyShallowAdoptions() throws Exception {
+ /*
+ * Force a traversal of the document, otherwise this test may fail for
+ * an unrelated reason on version 5 of the RI. That behavior is
+ * exercised by testAdoptionImmediatelyAfterParsing().
+ */
+ domToString(document);
+
+ RecordingHandler handler = new RecordingHandler();
+ name.setUserData("a", "apple", handler);
+ name.setUserData("b", "banana", handler);
+ standard.setUserData("c", "cat", handler);
+ waffles.setUserData("d", "dog", handler);
+
+ Document newDocument = builder.newDocument();
+ assertSame(name, newDocument.adoptNode(name));
+ assertSame(newDocument, name.getOwnerDocument());
+ assertSame(newDocument, standard.getOwnerDocument());
+ assertSame(newDocument, waffles.getOwnerDocument());
+
+ Set<String> expected = new HashSet<String>();
+ expected.add(notification(NODE_ADOPTED, "a", "apple", name, null));
+ expected.add(notification(NODE_ADOPTED, "b", "banana", name, null));
+ assertEquals(expected, handler.calls);
+ }
+
+ public void testBaseUriRelativeUriResolution() throws Exception {
+ File file = File.createTempFile("DomTest.java", "xml");
+ File parentFile = file.getParentFile();
+ FileWriter writer = new FileWriter(file);
+ writer.write("<a>"
+ + " <b xml:base=\"b1/b2\">"
+ + " <c>"
+ + " <d xml:base=\"../d1/d2\"><e/></d>"
+ + " </c>"
+ + " </b>"
+ + " <h xml:base=\"h1/h2/\">"
+ + " <i xml:base=\"../i1/i2\"/>"
+ + " </h>"
+ + "</a>");
+ writer.close();
+ document = builder.parse(file);
+
+ assertFileUriEquals("", file.getPath(), document.getBaseURI());
+ assertFileUriEquals("", file.getPath(), document.getDocumentURI());
+ Element a = document.getDocumentElement();
+ assertFileUriEquals("", file.getPath(), a.getBaseURI());
+
+ String message = "This implementation's getBaseURI() doesn't handle relative URIs";
+ Element b = (Element) a.getChildNodes().item(1);
+ Element c = (Element) b.getChildNodes().item(1);
+ Element d = (Element) c.getChildNodes().item(1);
+ Element e = (Element) d.getChildNodes().item(0);
+ Element h = (Element) a.getChildNodes().item(3);
+ Element i = (Element) h.getChildNodes().item(1);
+ assertFileUriEquals(message, parentFile + "/b1/b2", b.getBaseURI());
+ assertFileUriEquals(message, parentFile + "/b1/b2", c.getBaseURI());
+ assertFileUriEquals(message, parentFile + "/d1/d2", d.getBaseURI());
+ assertFileUriEquals(message, parentFile + "/d1/d2", e.getBaseURI());
+ assertFileUriEquals(message, parentFile + "/h1/h2/", h.getBaseURI());
+ assertFileUriEquals(message, parentFile + "/h1/i1/i2", i.getBaseURI());
+ }
+
+ /**
+ * Regrettably both "file:/tmp/foo.txt" and "file:///tmp/foo.txt" are
+ * legal URIs, and different implementations emit different forms.
+ */
+ private void assertFileUriEquals(
+ String message, String expectedFile, String actual) {
+ if (!("file:" + expectedFile).equals(actual)
+ && !("file://" + expectedFile).equals(actual)) {
+ fail("Expected URI for: " + expectedFile
+ + " but was " + actual + ". " + message);
+ }
+ }
+
+ /**
+ * According to the <a href="http://www.w3.org/TR/xmlbase/">XML Base</a>
+ * spec, fragments (like "#frag" or "") should not be dereferenced.
+ */
+ public void testBaseUriResolutionWithHashes() throws Exception {
+ document = builder.parse(new InputSource(new StringReader(
+ "<a xml:base=\"http://a1/a2\">"
+ + " <b xml:base=\"b1#b2\"/>"
+ + " <c xml:base=\"#c1\">"
+ + " <d xml:base=\"\"/>"
+ + " </c>"
+ + " <e xml:base=\"\"/>"
+ + "</a>")));
+ Element a = document.getDocumentElement();
+ assertEquals("http://a1/a2", a.getBaseURI());
+
+ String message = "This implementation's getBaseURI() doesn't handle "
+ + "relative URIs with hashes";
+ Element b = (Element) a.getChildNodes().item(1);
+ Element c = (Element) a.getChildNodes().item(3);
+ Element d = (Element) c.getChildNodes().item(1);
+ Element e = (Element) a.getChildNodes().item(5);
+ assertEquals(message, "http://a1/b1#b2", b.getBaseURI());
+ assertEquals(message, "http://a1/a2#c1", c.getBaseURI());
+ assertEquals(message, "http://a1/a2#c1", d.getBaseURI());
+ assertEquals(message, "http://a1/a2", e.getBaseURI());
+ }
+
+ public void testBaseUriInheritedForProcessingInstructions() {
+ document.setDocumentURI("http://d1/d2");
+ assertEquals("http://d1/d2", wafflemaker.getBaseURI());
+ }
+
+ public void testBaseUriInheritedForEntities() {
+ if (sp == null) {
+ return;
+ }
+ document.setDocumentURI("http://d1/d2");
+ assertEquals("http://d1/d2", sp.getBaseURI());
+ }
+
+ public void testBaseUriNotInheritedForNotations() {
+ if (png == null) {
+ return;
+ }
+ document.setDocumentURI("http://d1/d2");
+ assertNull(png.getBaseURI());
+ }
+
+ public void testBaseUriNotInheritedForDoctypes() {
+ document.setDocumentURI("http://d1/d2");
+ assertNull(doctype.getBaseURI());
+ }
+
+ public void testBaseUriNotInheritedForAttributes() {
+ document.setDocumentURI("http://d1/d2");
+ assertNull(itemXmlns.getBaseURI());
+ assertNull(itemXmlnsA.getBaseURI());
+ assertNull(standard.getBaseURI());
+ assertNull(vitaminsXmlnsA.getBaseURI());
+ }
+
+ public void testBaseUriNotInheritedForTextsOrCdatas() {
+ document.setDocumentURI("http://d1/d2");
+ assertNull(descriptionText1.getBaseURI());
+ assertNull(descriptionText2.getBaseURI());
+ assertNull(option2Reference.getBaseURI());
+ }
+
+ public void testBaseUriNotInheritedForComments() {
+ document.setDocumentURI("http://d1/d2");
+ assertNull(descriptionText1.getBaseURI());
+ assertNull(descriptionText2.getBaseURI());
+ }
+
+ public void testBaseUriNotInheritedForEntityReferences() {
+ document.setDocumentURI("http://d1/d2");
+ assertNull(option2Reference.getBaseURI());
+ }
+
+ public void testProgrammaticElementIds() {
+ vitaminc.setAttribute("name", "c");
+ assertFalse(vitaminc.getAttributeNode("name").isId());
+ assertNull(document.getElementById("c"));
+
+ // set the ID attribute...
+ vitaminc.setIdAttribute("name", true);
+ assertTrue(vitaminc.getAttributeNode("name").isId());
+ assertSame(vitaminc, document.getElementById("c"));
+
+ // ... and then take it away
+ vitaminc.setIdAttribute("name", false);
+ assertFalse(vitaminc.getAttributeNode("name").isId());
+ assertNull(document.getElementById("c"));
+ }
+
+ public void testMultipleIdsOnOneElement() {
+ vitaminc.setAttribute("name", "c");
+ vitaminc.setIdAttribute("name", true);
+ vitaminc.setAttribute("atc", "a11g");
+ vitaminc.setIdAttribute("atc", true);
+
+ assertTrue(vitaminc.getAttributeNode("name").isId());
+ assertTrue(vitaminc.getAttributeNode("atc").isId());
+ assertSame(vitaminc, document.getElementById("c"));
+ assertSame(vitaminc, document.getElementById("a11g"));
+ assertNull(document.getElementById("g"));
+ }
+
+ @KnownFailure("Dalvik treats id attributes as identifiers")
+ public void testAttributeNamedIdIsNotAnIdByDefault() {
+ String message = "This implementation incorrectly interprets the "
+ + "\"id\" attribute as an identifier by default.";
+ vitaminc.setAttribute("id", "c");
+ assertNull(message, document.getElementById("c"));
+ }
+
+ public void testElementTypeInfo() {
+ TypeInfo typeInfo = description.getSchemaTypeInfo();
+ assertNull(typeInfo.getTypeName());
+ assertNull(typeInfo.getTypeNamespace());
+ assertFalse(typeInfo.isDerivedFrom("x", "y", TypeInfo.DERIVATION_UNION));
+ }
+
+ public void testAttributeTypeInfo() {
+ TypeInfo typeInfo = standard.getSchemaTypeInfo();
+ assertNull(typeInfo.getTypeName());
+ assertNull(typeInfo.getTypeNamespace());
+ assertFalse(typeInfo.isDerivedFrom("x", "y", TypeInfo.DERIVATION_UNION));
+ }
+
+ public void testRenameElement() {
+ document.renameNode(description, null, "desc");
+ assertEquals("desc", description.getTagName());
+ assertEquals("desc", description.getLocalName());
+ assertEquals(null, description.getPrefix());
+ assertEquals(null, description.getNamespaceURI());
+ }
+
+ public void testRenameElementWithPrefix() {
+ try {
+ document.renameNode(description, null, "a:desc");
+ fail();
+ } catch (DOMException e) {
+ }
+ }
+
+ public void testRenameElementWithNamespace() {
+ document.renameNode(description, "http://sales", "desc");
+ assertEquals("desc", description.getTagName());
+ assertEquals("desc", description.getLocalName());
+ assertEquals(null, description.getPrefix());
+ assertEquals("http://sales", description.getNamespaceURI());
+ }
+
+ public void testRenameElementWithPrefixAndNamespace() {
+ document.renameNode(description, "http://sales", "a:desc");
+ assertEquals("a:desc", description.getTagName());
+ assertEquals("desc", description.getLocalName());
+ assertEquals("a", description.getPrefix());
+ assertEquals("http://sales", description.getNamespaceURI());
+ }
+
+ public void testRenameAttribute() {
+ document.renameNode(deluxe, null, "special");
+ assertEquals("special", deluxe.getName());
+ assertEquals("special", deluxe.getLocalName());
+ assertEquals(null, deluxe.getPrefix());
+ assertEquals(null, deluxe.getNamespaceURI());
+ }
+
+ public void testRenameAttributeWithPrefix() {
+ try {
+ document.renameNode(deluxe, null, "a:special");
+ fail();
+ } catch (DOMException e) {
+ }
+ }
+
+ public void testRenameAttributeWithNamespace() {
+ document.renameNode(deluxe, "http://sales", "special");
+ assertEquals("special", deluxe.getName());
+ assertEquals("special", deluxe.getLocalName());
+ assertEquals(null, deluxe.getPrefix());
+ assertEquals("http://sales", deluxe.getNamespaceURI());
+ }
+
+ public void testRenameAttributeWithPrefixAndNamespace() {
+ document.renameNode(deluxe, "http://sales", "a:special");
+ assertEquals("a:special", deluxe.getName());
+ assertEquals("special", deluxe.getLocalName());
+ assertEquals("a", deluxe.getPrefix());
+ assertEquals("http://sales", deluxe.getNamespaceURI());
+ }
+
+ public void testUserDataHandlerNotifiedOfRenames() {
+ RecordingHandler handler = new RecordingHandler();
+ description.setUserData("a", "apple", handler);
+ deluxe.setUserData("b", "banana", handler);
+ standard.setUserData("c", "cat", handler);
+
+ document.renameNode(deluxe, null, "special");
+ document.renameNode(description, null, "desc");
+
+ Set<String> expected = new HashSet<String>();
+ expected.add(notification(NODE_RENAMED, "a", "apple", description, null));
+ expected.add(notification(NODE_RENAMED, "b", "banana", deluxe, null));
+ assertEquals(expected, handler.calls);
+ }
+
+ public void testRenameToInvalid() {
+ try {
+ document.renameNode(description, null, "xmlns:foo");
+ fail();
+ } catch (DOMException e) {
+ }
+ try {
+ document.renameNode(description, null, "xml:foo");
+ fail();
+ } catch (DOMException e) {
+ }
+ try {
+ document.renameNode(deluxe, null, "xmlns");
+ fail();
+ } catch (DOMException e) {
+ }
+ }
+
+ public void testRenameNodeOtherThanElementOrAttribute() {
+ for (Node node : allNodes) {
+ if (node.getNodeType() == Node.ATTRIBUTE_NODE
+ || node.getNodeType() == Node.ELEMENT_NODE) {
+ continue;
+ }
+
+ try {
+ document.renameNode(node, null, "foo");
+ fail();
+ } catch (DOMException e) {
+ }
+ }
+ }
+
+ public void testDocumentDoesNotHaveWhitespaceChildren()
+ throws IOException, SAXException {
+ String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> \n"
+ + " <foo/>\n"
+ + " \n";
+ document = builder.parse(new InputSource(new StringReader(xml)));
+ assertEquals("Document nodes shouldn't have text children",
+ 1, document.getChildNodes().getLength());
+ }
+
+ @KnownFailure("Dalvik document nodes accept arbitrary child nodes")
+ public void testDocumentAddChild()
+ throws IOException, SAXException {
+ try {
+ document.appendChild(document.createTextNode(" "));
+ fail("Document nodes shouldn't accept child nodes");
+ } catch (DOMException e) {
+ }
+ }
+
+ private class RecordingHandler implements UserDataHandler {
+ final Set<String> calls = new HashSet<String>();
+ public void handle(short operation, String key, Object data, Node src, Node dst) {
+ calls.add(notification(operation, key, data, src, dst));
+ }
+ }
+
+ private String notification(short operation, String key, Object data, Node src, Node dst) {
+ return "op:" + operation + " key:" + key + " data:" + data + " src:" + src + " dst:" + dst;
+ }
+
+ private String domToString(Document document) throws TransformerException {
+ StringWriter writer = new StringWriter();
+ transformer.transform(new DOMSource(document), new StreamResult(writer));
+ String result = writer.toString();
+
+ /*
+ * Hack: swap <name>'s a:standard attribute and deluxe attribute if
+ * they're out of order. Some document transformations reorder the
+ * attributes, which causes pain when we try to use String comparison on
+ * them.
+ */
+ Matcher attributeMatcher = Pattern.compile(" a:standard=\"[^\"]+\"").matcher(result);
+ if (attributeMatcher.find()) {
+ result = result.substring(0, attributeMatcher.start())
+ + result.substring(attributeMatcher.end());
+ int insertionPoint = result.indexOf(" deluxe=\"");
+ result = result.substring(0, insertionPoint)
+ + attributeMatcher.group()
+ + result.substring(insertionPoint);
+ }
+
+ return result;
+ }
+
+ private String domToStringStripElementWhitespace(Document document)
+ throws TransformerException {
+ return domToString(document).replaceAll("(?m)>\\s+<", "><");
+ }
+}