| /* | |
| * Copyright 2008 Google Inc. | |
| * | |
| * 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 com.google.gwt.xml.client; | |
| import com.google.gwt.junit.DoNotRunWith; | |
| import com.google.gwt.junit.Platform; | |
| import com.google.gwt.junit.client.GWTTestCase; | |
| import com.google.gwt.user.client.Window; | |
| import com.google.gwt.xml.client.impl.DOMParseException; | |
| import com.google.gwt.xml.client.impl.XMLParserImplSafari; | |
| import java.util.Arrays; | |
| import java.util.Iterator; | |
| import java.util.List; | |
| /** | |
| * This class poorly tests all the methods in the GWT XML parser. | |
| */ | |
| public class XMLTest extends GWTTestCase { | |
| private static List<Node> asList(Node[] nodes) { | |
| return Arrays.asList(nodes); | |
| } | |
| private static void assertAttributeMapEquals(NamedNodeMap listA, | |
| NamedNodeMap listB) { | |
| // This is only for checking attribute maps. | |
| assertEquals(listA.getLength(), listB.getLength()); | |
| for (int i = 0, n = listA.getLength(); i < n; ++i) { | |
| final Node itemA = listA.item(i); | |
| final Node itemB = listB.getNamedItem(itemA.getNodeName()); | |
| assertNotNull(itemB); | |
| assertEquals(itemA.getNodeType(), itemB.getNodeType()); | |
| assertEquals(itemA.getNodeValue(), itemB.getNodeValue()); | |
| } | |
| } | |
| private static void assertCharacterDataEquals(CharacterData charDataA, | |
| CharacterData charDataB) { | |
| assertEquals(charDataA.getData(), charDataB.getData()); | |
| } | |
| private static void assertDocumentEquals(Document docA, Document docB) { | |
| assertNodeListEquals(docA.getChildNodes(), docB.getChildNodes()); | |
| } | |
| private static void assertElementEquals(Element elemA, Element elemB) { | |
| assertEquals(elemA.getNodeName(), elemB.getNodeName()); | |
| assertAttributeMapEquals(elemA.getAttributes(), elemB.getAttributes()); | |
| assertNodeListEquals(elemA.getChildNodes(), elemB.getChildNodes()); | |
| } | |
| private static void assertNodeEquals(Node nodeA, Node nodeB) { | |
| assertNotNull(nodeA); | |
| assertNotNull(nodeB); | |
| final int typeA = nodeA.getNodeType(); | |
| final int typeB = nodeB.getNodeType(); | |
| assertEquals(typeA, typeB); | |
| switch (typeA) { | |
| case Node.ELEMENT_NODE: | |
| assertElementEquals((Element) nodeA, (Element) nodeB); | |
| break; | |
| case Node.COMMENT_NODE: | |
| case Node.CDATA_SECTION_NODE: | |
| case Node.TEXT_NODE: | |
| assertCharacterDataEquals((CharacterData) nodeA, (CharacterData) nodeB); | |
| break; | |
| case Node.PROCESSING_INSTRUCTION_NODE: | |
| assertProcessingInstructionEquals((ProcessingInstruction) nodeA, | |
| (ProcessingInstruction) nodeB); | |
| break; | |
| default: | |
| fail("Unexpected node type: " + nodeA.toString()); | |
| break; | |
| } | |
| } | |
| private static void assertNodeListEquals(NodeList listA, NodeList listB) { | |
| final int sizeA = listA.getLength(); | |
| final int sizeB = listB.getLength(); | |
| assertEquals(sizeA, sizeB); | |
| for (int i = 0, n = sizeA; i < n; ++i) { | |
| assertNodeEquals(listA.item(i), listB.item(i)); | |
| } | |
| } | |
| private static void assertProcessingInstructionEquals( | |
| ProcessingInstruction piA, ProcessingInstruction piB) { | |
| assertEquals(piA.getData(), piB.getData()); | |
| } | |
| private static Document createTestDocument() { | |
| Document d = XMLParser.createDocument(); | |
| Element top = d.createElement("doc"); | |
| top.setAttribute("fluffy", "true"); | |
| top.setAttribute("numAttributes", "2"); | |
| d.appendChild(top); | |
| ProcessingInstruction commentBefore = d.createProcessingInstruction( | |
| "target", "some data"); | |
| d.insertBefore(commentBefore, top); | |
| Comment commentAfter = d.createComment("after the element"); | |
| d.insertBefore(commentAfter, null); | |
| for (int i = 0; i < 3; i++) { | |
| Element e = d.createElement("e" + i); | |
| e.setAttribute("id", "e" + i + "Id"); | |
| top.appendChild(e); | |
| } | |
| Element deep = d.createElement("deep"); | |
| top.getFirstChild().appendChild(deep); | |
| deep.setAttribute("depth", "1 foot"); | |
| Element deep2 = d.createElement("deep"); | |
| deep2.setAttribute("depth", "2 feet"); | |
| top.getFirstChild().getFirstChild().appendChild(deep2); | |
| top.appendChild(d.createTextNode("0123456789")); | |
| top.appendChild(d.createTextNode("abcdefghij")); | |
| top.appendChild(d.createElement("e4")); | |
| top.appendChild(d.createCDATASection("klmnopqrst")); | |
| return d; | |
| } | |
| /** | |
| * Returns the module name for GWT unit test running. | |
| */ | |
| @Override | |
| public String getModuleName() { | |
| return "com.google.gwt.xml.XML"; | |
| } | |
| @DoNotRunWith({Platform.HtmlUnitBug}) | |
| public void testAttr() { | |
| Document d = createTestDocument(); | |
| Element de = d.getDocumentElement(); | |
| de.setAttribute("created", "true"); | |
| assertEquals("true", de.getAttribute("created")); | |
| de.setAttribute("set", "toAValue"); | |
| assertEquals(de.getAttribute("set"), "toAValue"); | |
| assertTrue(de.getAttributeNode("set").getSpecified()); | |
| assertEquals(de.getAttributeNode("unset"), null); | |
| } | |
| @DoNotRunWith({Platform.HtmlUnitBug}) | |
| public void testCreate() { | |
| Document d = XMLParser.createDocument(); | |
| CDATASection createCDATA; | |
| if (XMLParser.supportsCDATASection()) { | |
| createCDATA = d.createCDATASection("sampl<<< >>e data"); | |
| } else { | |
| createCDATA = d.createCDATASection("sample data"); | |
| } | |
| Comment createComment = d.createComment("a sample comment"); | |
| DocumentFragment createDocumentFragment = d.createDocumentFragment(); | |
| Element elementWithChildren = d.createElement("elementWithChildren"); | |
| ProcessingInstruction createProcessingInstruction = d.createProcessingInstruction( | |
| "target", "processing instruction data"); | |
| Text createTextNode = d.createTextNode("sample text node"); | |
| List<Node> canHaveChildren = asList(new Node[] { | |
| createDocumentFragment, elementWithChildren}); | |
| List<Node> canBeChildren = asList(new Node[] { | |
| createCDATA, createComment, elementWithChildren, | |
| createProcessingInstruction, createTextNode}); | |
| for (int i = 0; i < canHaveChildren.size(); i++) { | |
| Node parent = canHaveChildren.get(i); | |
| Node cloneParent = parent.cloneNode(false); | |
| if (canBeChildren.contains(parent)) { | |
| d.appendChild(cloneParent); | |
| } | |
| for (int j = 0; j < canBeChildren.size(); j++) { | |
| Node child = canBeChildren.get(j); | |
| cloneParent.appendChild(child.cloneNode(false)); | |
| } | |
| for (int j = 0; j < canBeChildren.size(); j++) { | |
| Node clonedChild = cloneParent.getChildNodes().item(j); | |
| Node hopefullySameChild = canBeChildren.get(j); | |
| assertEquals(hopefullySameChild.cloneNode(false).toString(), | |
| clonedChild.toString()); | |
| } | |
| Node deepClonedNode = parent.cloneNode(true); | |
| assertEquals(parent.toString(), deepClonedNode.toString()); | |
| } | |
| // Now check the document. | |
| XMLParser.removeWhitespace(d); | |
| if (XMLParser.supportsCDATASection()) { | |
| assertDocumentEquals(XMLParser.parse("<elementWithChildren>" | |
| + "<![CDATA[sampl<<< >>e data]]>" + "<!--a sample comment-->" | |
| + "<elementWithChildren/>" + "<?target processing instruction data?>" | |
| + "sample text node" + "</elementWithChildren>"), d); | |
| } else { | |
| assertDocumentEquals(XMLParser.parse("<elementWithChildren>" | |
| + "sample data" + "<!--a sample comment-->" | |
| + "<elementWithChildren/>" + "<?target processing instruction data?>" | |
| + "sample text node" + "</elementWithChildren>"), d); | |
| } | |
| } | |
| @DoNotRunWith({Platform.HtmlUnitBug}) | |
| public void testDocument() { | |
| Document d = createTestDocument(); | |
| NodeList e1Nodes = d.getElementsByTagName("e1"); | |
| assertEquals(e1Nodes.getLength(), 1); | |
| Node e1Node = e1Nodes.item(0); | |
| assertEquals(((Element) e1Node).getTagName(), "e1"); | |
| // we didn't define a dtd, so no id for us | |
| Element e1NodeDirect = d.getElementById("e1Id"); | |
| // Chrome 11 and up fail to implement this behavior | |
| if (!Window.Navigator.getUserAgent().matches(".*Chrome/(1[1-9]|[2-9][0-9])\\..*")) { | |
| assertNull(e1NodeDirect); | |
| } | |
| Document alienDoc = XMLParser.createDocument(); | |
| Node alienNode11 = alienDoc.importNode(e1Node, true); | |
| alienDoc.appendChild(alienNode11); | |
| assertNotSame(e1Node, alienNode11); | |
| assertEquals(e1Node.toString(), alienNode11.toString()); | |
| } | |
| public void testElement() { | |
| Document d = createTestDocument(); | |
| Element top = d.getDocumentElement(); | |
| NodeList el = top.getElementsByTagName("e1"); | |
| assertEquals(el.getLength(), 1); | |
| NodeList deepNodes = top.getElementsByTagName("deep"); | |
| assertEquals(deepNodes.getLength(), 2); | |
| Element d1 = (Element) deepNodes.item(0); | |
| assertTrue(d1.hasAttribute("depth")); | |
| assertFalse(d1.hasAttribute("height")); | |
| d1.removeAttribute("depth"); | |
| assertFalse(d1.hasAttribute("depth")); | |
| Element d2 = (Element) deepNodes.item(1); | |
| assertTrue(d2.hasAttribute("depth")); | |
| Attr depthAttr = d2.getAttributeNode("depth"); | |
| assertNotNull(depthAttr); | |
| d2.removeAttribute("depth"); | |
| assertFalse(d2.hasAttribute("depth")); | |
| } | |
| public void testForIssue733() { | |
| // TODO (knorton): | |
| // http://code.google.com/p/google-web-toolkit/issues/detail?id=2346 | |
| // Fixing issue #733 has been deferred for Safari2. See the bug URL for more | |
| // details. This should be enabled as soon as that bug is fixed. | |
| if (XMLParserImplSafari.isSafari2LevelWebKit()) { | |
| return; | |
| } | |
| final Document document = XMLParser.createDocument(); | |
| final Element element = document.createElement("foo"); | |
| document.appendChild(element); | |
| element.setAttribute("bar", "<"); | |
| final String xmlAsString = document.toString(); | |
| try { | |
| XMLParser.parse(xmlAsString); | |
| } catch (DOMParseException e) { | |
| fail(xmlAsString + " is invalid XML."); | |
| } | |
| } | |
| public void testNamedNodeMap() { | |
| Document d = createTestDocument(); | |
| NamedNodeMap m = d.getDocumentElement().getAttributes(); | |
| assertEquals(((Attr) m.getNamedItem("fluffy")).getValue(), "true"); | |
| assertEquals(m.getLength(), 2); | |
| } | |
| public void testNavigation() { | |
| Document d = createTestDocument(); | |
| Element documentElement = d.getDocumentElement(); | |
| assertEquals("getPreviousSibling", documentElement.getPreviousSibling(), | |
| d.getChildNodes().item(0)); | |
| assertEquals("getNextSibling", documentElement.getNextSibling(), | |
| d.getChildNodes().item(2)); | |
| assertEquals("getDocumentElement", documentElement, d.getChildNodes().item( | |
| 1)); | |
| assertEquals("getTagName", documentElement.getTagName(), "doc"); | |
| NodeList documentElementChildNodes = documentElement.getChildNodes(); | |
| int deChildNodesLength = documentElementChildNodes.getLength(); | |
| assertEquals("getFirstChild", documentElement.getFirstChild(), | |
| documentElementChildNodes.item(0)); | |
| assertEquals("getLastChild", documentElement.getLastChild(), | |
| documentElementChildNodes.item(deChildNodesLength - 1)); | |
| assertEquals("getNextSibling2", | |
| documentElement.getFirstChild().getNextSibling(), | |
| documentElementChildNodes.item(1)); | |
| assertEquals("getPreviousSibling2", | |
| documentElement.getLastChild().getPreviousSibling(), | |
| documentElementChildNodes.item(deChildNodesLength - 2)); | |
| } | |
| public void testNode() { | |
| Document ns = XMLParser.parse("<x:doc xmlns:x=\"http://x\"/>"); | |
| String xUrl = "http://x"; | |
| assertEquals(xUrl, ns.getFirstChild().getNamespaceURI()); | |
| Element top = ns.getDocumentElement(); | |
| Text xxx = ns.createTextNode("xxx"); | |
| top.appendChild(xxx); | |
| Text yyy = ns.createTextNode("yyy"); | |
| top.appendChild(yyy); | |
| assertEquals(xxx.getNodeValue(), "xxx"); | |
| assertEquals(xxx.getParentNode(), top); | |
| xxx.setNodeValue("x"); | |
| assertEquals(xxx.getData(), "x"); | |
| assertEquals(xxx.getOwnerDocument(), ns); | |
| top.removeChild(xxx); | |
| assertEquals(top.getChildNodes().getLength(), 1); | |
| Comment commentNode = ns.createComment("comment ccc"); | |
| top.replaceChild(commentNode, yyy); | |
| assertEquals(top.getFirstChild(), commentNode); | |
| assertEquals(top.getChildNodes().getLength(), 1); | |
| } | |
| /** | |
| * At one point, this test was failing on one Safari configuration in | |
| * Production Mode in the 1.5 release branch. | |
| */ | |
| @DoNotRunWith({Platform.HtmlUnitUnknown}) | |
| public void testParse() { | |
| Document docA = XMLParser.parse("<!--hello--> <a spam=\"ham\">\n <?pi hello ?>dfgdfg <b/>\t</a>"); | |
| Document docB = XMLParser.createDocument(); | |
| docB.appendChild(docB.createComment("hello")); | |
| final Element eleB = docB.createElement("a"); | |
| docB.appendChild(eleB); | |
| eleB.setAttribute("spam", "ham"); | |
| eleB.appendChild(docB.createTextNode("\n ")); | |
| eleB.appendChild(docB.createProcessingInstruction("pi", "hello ")); | |
| eleB.appendChild(docB.createTextNode("dfgdfg ")); | |
| eleB.appendChild(docB.createElement("b")); | |
| eleB.appendChild(docB.createTextNode("\t")); | |
| assertDocumentEquals(docA, docB); | |
| try { | |
| XMLParser.parse("<<<"); | |
| fail(); | |
| } catch (DOMParseException e) { | |
| } | |
| } | |
| public void testPrefix() { | |
| Document d = XMLParser.parse("<?xml version=\"1.0\"?>\r\n" | |
| + "<!-- both namespace prefixes are available throughout -->\r\n" | |
| + "<bk:book xmlns:bk=\'urn:loc.gov:books\'\r\n" | |
| + " xmlns:isbn=\'urn:ISBN:0-395-36341-6\'>\r\n" | |
| + " <bk:title>Cheaper by the Dozen</bk:title>\r\n" | |
| + " <isbn:number>1568491379</isbn:number>\r\n" + "</bk:book>"); | |
| assertEquals(d.getDocumentElement().getNodeName(), "bk:book"); | |
| assertEquals(d.getDocumentElement().getPrefix(), "bk"); | |
| assertEquals(d.getElementsByTagName("book").getLength(), 1); | |
| assertEquals(d.getElementsByTagName("book").item(0), d.getDocumentElement()); | |
| } | |
| public void testProcessingInstruction() { | |
| Document d = createTestDocument(); | |
| ProcessingInstruction pi = (ProcessingInstruction) d.getChildNodes().item(0); | |
| assertEquals(pi.getTarget(), "target"); | |
| assertEquals(pi.getData(), "some data"); | |
| pi.setData("other data"); | |
| assertEquals(pi.getData(), "other data"); | |
| } | |
| @DoNotRunWith({Platform.HtmlUnitBug}) | |
| public void testText() { | |
| Document d = createTestDocument(); | |
| List<Node> textLikeNodes = Arrays.asList(new Node[] { | |
| d.createTextNode(""), d.createCDATASection(""), d.createComment("")}); | |
| StringBuffer b = new StringBuffer(); | |
| for (char i = 32; i < 30000; i++) { | |
| b.append(i); | |
| } | |
| for (Iterator<Node> iter = textLikeNodes.iterator(); iter.hasNext();) { | |
| CharacterData textLike = (CharacterData) iter.next(); | |
| textLike.setData(b.toString()); | |
| // CHECKSTYLE_OFF | |
| assertEquals("initialLength type:" + textLike.getNodeType(), 30000 - 32, | |
| textLike.getLength()); | |
| assertEquals("initialEquals", textLike.getData(), b.toString()); | |
| // CHECKSTYLE_ON | |
| } | |
| for (int i = 32; i < 29900; i += 100) { | |
| for (Iterator<Node> iter = textLikeNodes.iterator(); iter.hasNext();) { | |
| CharacterData textLike = (CharacterData) iter.next(); | |
| // CHECKSTYLE_OFF | |
| assertEquals("substring type:" + textLike.getNodeType() + " count: " | |
| + i, b.substring(i, i + 100), textLike.substringData(i, 100)); | |
| // CHECKSTYLE_ON | |
| } | |
| } | |
| for (Iterator<Node> iter = textLikeNodes.iterator(); iter.hasNext();) { | |
| StringBuffer bTemp = new StringBuffer(b.toString()); | |
| CharacterData textLike = (CharacterData) iter.next(); | |
| textLike.deleteData(100, 100); | |
| bTemp.delete(100, 200); | |
| // CHECKSTYLE_OFF | |
| assertEquals("deleteLength type:" + textLike.getNodeType(), | |
| bTemp.length(), textLike.getData().length()); | |
| assertEquals("deleteEquals type:" + textLike.getNodeType(), | |
| bTemp.toString(), textLike.getData()); | |
| // CHECKSTYLE_ON | |
| bTemp.setLength(0); | |
| } | |
| for (Iterator<Node> iter = textLikeNodes.iterator(); iter.hasNext();) { | |
| StringBuffer bTemp = new StringBuffer(b.toString()); | |
| CharacterData textLike = (CharacterData) iter.next(); | |
| textLike.setData(bTemp.toString()); | |
| textLike.replaceData(50, 100, " "); | |
| bTemp.replace(50, 150, " "); | |
| // CHECKSTYLE_OFF | |
| assertEquals("replaceLength type:" + textLike.getNodeType(), | |
| bTemp.length(), textLike.getData().length()); | |
| assertEquals("replaceEquals type:" + textLike.getNodeType(), | |
| bTemp.toString(), textLike.getData()); | |
| // CHECKSTYLE_ON | |
| bTemp.setLength(0); | |
| } | |
| for (Iterator<Node> iter = textLikeNodes.iterator(); iter.hasNext();) { | |
| CharacterData textLike = (CharacterData) iter.next(); | |
| textLike.appendData("!!!"); | |
| assertTrue("endswith!!!", textLike.getData().endsWith("!!!")); | |
| textLike.insertData(0, "!"); | |
| textLike.insertData(1, "@@"); | |
| assertTrue("startsWith !@@", textLike.getData().startsWith("!@@")); | |
| } | |
| Text t = (Text) d.getDocumentElement().getChildNodes().item(3); | |
| Text rightT = t.splitText(5); | |
| assertEquals("t and leftT parent equality", t.getParentNode(), | |
| rightT.getParentNode()); | |
| assertEquals("leftT.getPreviousSibling", rightT.getPreviousSibling(), t); | |
| assertEquals("t.length", t.getData().length(), 5); | |
| assertEquals("leftT.length", rightT.getData().length(), 5); | |
| assertEquals("t data", t.getData(), "01234"); | |
| assertEquals("LeftT data", rightT.getData(), "56789"); | |
| CDATASection cd = (CDATASection) d.getDocumentElement().getChildNodes().item( | |
| 7); | |
| Text rightCD = cd.splitText(5); | |
| assertEquals("cd and leftCd parent equality", cd.getParentNode(), | |
| rightCD.getParentNode()); | |
| assertEquals("leftCD.getPreviousSibling", rightCD.getPreviousSibling(), cd); | |
| assertEquals("cd length", cd.getData().length(), 5); | |
| assertEquals("leftCD.length", rightCD.getData().length(), 5); | |
| assertEquals("cd data", cd.getData(), "klmno"); | |
| assertEquals("leftCD data", rightCD.getData(), "pqrst"); | |
| d.getDocumentElement().normalize(); | |
| assertEquals("normalized t", d.getDocumentElement().getChildNodes().item( | |
| 3).toString(), "0123456789abcdefghij"); | |
| } | |
| } |