LoboEvolution/LoboEvolution

View on GitHub
LoboUnitTest/src/test/java/org/loboevolution/junit/DOMElementTest.java

Summary

Maintainability
F
6 days
Test Coverage
/*
 * MIT License
 *
 * Copyright (c) 2014 - 2024 LoboEvolution
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * Contact info: ivan.difrancesco@yahoo.it
 */

package org.loboevolution.junit;

import org.htmlunit.cssparser.dom.DOMException;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.loboevolution.css.CSSStyleDeclaration;
import org.loboevolution.driver.LoboUnitTest;
import org.loboevolution.gui.LocalHtmlRendererConfig;
import org.loboevolution.html.dom.HTMLCollection;
import org.loboevolution.html.dom.domimpl.HTMLCollectionImpl;
import org.loboevolution.html.dom.domimpl.HTMLElementImpl;
import org.loboevolution.html.dom.nodeimpl.DOMImplementationImpl;
import org.loboevolution.html.dom.nodeimpl.ElementImpl;
import org.loboevolution.html.dom.nodeimpl.NodeListImpl;
import org.loboevolution.html.node.*;
import org.loboevolution.http.UserAgentContext;

import static org.junit.jupiter.api.Assertions.*;

public class DOMElementTest extends LoboUnitTest {

    private static Document document;

    private static DOMImplementationImpl domImpl;

    @BeforeAll
    public static void setUpBeforeClass() {
        final UserAgentContext context = new UserAgentContext(new LocalHtmlRendererConfig(), true);
        context.setUserAgentEnabled(false);
        domImpl = new DOMImplementationImpl(context);
    }

    @Test
    public void testGetAttributes() {
        final Document document = domImpl.createDocument(null, null, null);
        final Element html = document.createElement("html");
        final Element body = document.createElement("body");
        html.appendChild(body);
        final NamedNodeMap attrs = body.getAttributes();
        assertNotNull(attrs);
        assertEquals(0, attrs.getLength());
        final Attr idattr = document.createAttribute("id");
        idattr.setValue("bodyId");
        body.setAttributeNode(idattr);
        final Node node = attrs.getNamedItem("id");
        assertNotNull(node);
        assertEquals(Node.ATTRIBUTE_NODE, node.getNodeType());
        assertEquals("id", node.getNodeName());
        assertEquals("bodyId", node.getNodeValue());
        assertNull(node.getNextSibling());
        assertNotNull(node.getParentNode());
        assertSame(idattr, node);
        assertEquals(1, attrs.getLength());
        assertSame(idattr, attrs.item(0));
        final Attr attr = document.createAttribute("lang");
        attr.setValue("en");
        body.setAttributeNode(attr);
        assertEquals(2, attrs.getLength());
        assertTrue(body.hasAttribute("lang"));
        assertEquals("en", body.getAttribute("lang"));
        assertSame(idattr.getNextSibling(), attr);
        assertSame(idattr, attr.getPreviousSibling());
        assertSame(idattr, attrs.getNamedItem("id"));
        assertSame(attr, attrs.getNamedItem("lang"));
        assertSame(attr, attrs.removeNamedItem("lang"));
        assertEquals(1, attrs.getLength());
        assertSame(idattr, attrs.getNamedItem("id"));
        assertSame(idattr, attrs.item(0));

        attrs.setNamedItem(attr);
        final Attr xmlns = document.createAttributeNS(Document.XMLNS_NAMESPACE_URI, "xmlns");
        xmlns.setValue(Document.HTML_NAMESPACE_URI);
        attrs.setNamedItem(xmlns);
        assertEquals(3, attrs.getLength());
        assertTrue(body.hasAttribute("xmlns"));
        final Attr version = document.createAttributeNS(Document.NAMESPACE_SVG, "version");
        version.setValue("1.1");
        attrs.setNamedItem(version);
        assertEquals(4, attrs.getLength());
        assertTrue(body.hasAttribute("version"));
        assertTrue(body.hasAttributeNS(Document.NAMESPACE_SVG, "version"));
        attrs.removeNamedItemNS(Document.NAMESPACE_SVG, "version");
        assertEquals(3, attrs.getLength());
        assertFalse(body.hasAttribute("version"));
        assertFalse(body.hasAttributeNS(Document.NAMESPACE_SVG, "version"));
    }

    @Test
    public void testGetAttributeNS() {
        document = sampleHtmlFile();
        final Element html = document.getDocumentElement();
        final Element body = document.createElement("body");
        Attr idattr = document.createAttributeNS(Document.HTML_NAMESPACE_URI, "id");
        idattr.setValue("bodyId");
        body.setAttributeNode(idattr);
        assertNotNull(idattr.getParentNode());
        assertEquals("bodyId", body.getAttribute("id"));
        assertEquals("bodyId", body.getAttributeNode("id").getValue());
        assertEquals("bodyId", body.getAttributeNodeNS(Document.HTML_NAMESPACE_URI, "id").getValue());
        assertTrue(body.hasAttributeNS(Document.HTML_NAMESPACE_URI, "id"));
        assertFalse(body.hasAttributeNS(Document.HTML_NAMESPACE_URI, "foo"));
        assertNull(body.getAttribute("foo"));
        assertNull(body.getAttributeNode("foo"));
        assertNull(body.getAttributeNS(Document.NAMESPACE_SVG, "id"));
        assertNull(body.getAttributeNodeNS(Document.NAMESPACE_SVG, "id"));
        assertNotNull(idattr.getOwnerElement());
        html.appendChild(body);
        body.removeAttribute("foo");
        assertTrue(body.hasAttributes());

        boolean success = false;
        try {
            body.removeAttributeNS(Document.NAMESPACE_SVG, "id");
        } catch (final DOMException ex) {
            success = (ex.getCode() == DOMException.NOT_FOUND_ERR);
        }

        assertTrue(success, "throw_NOT_FOUND_ERR");
        assertTrue(body.hasAttribute("id"));
        idattr = body.removeAttributeNode(idattr);
        assertNull(idattr.getOwnerElement());
        assertFalse(body.hasAttributes());
        body.setAttributeNode(idattr);
        assertTrue(body.hasAttribute("id"));
        assertNotNull(idattr.getOwnerElement());
        body.removeAttributeNS(Document.HTML_NAMESPACE_URI, "id");
        assertFalse(body.hasAttribute("id"));
        assertFalse(body.hasAttributes());

        final Element svg = document.createElementNS(Document.NAMESPACE_SVG, "svg");
        final Attr version = document.createAttributeNS(Document.NAMESPACE_SVG, "version");
        version.setValue("1.1");
        assertEquals(Document.NAMESPACE_SVG, version.getNamespaceURI());
        svg.setAttributeNodeNS(version);
        assertNotNull(version.getOwnerElement());
        assertEquals("1.1", svg.getAttribute("version"));
        assertEquals("1.1", svg.getAttributeNode("version").getValue());
        assertEquals("1.1", svg.getAttributeNodeNS(Document.NAMESPACE_SVG, "version").getValue());
        assertNull(svg.getAttributeNS(Document.HTML_NAMESPACE_URI, "version"));
        assertNull(svg.getAttributeNodeNS(Document.HTML_NAMESPACE_URI, "version"));
        assertFalse(svg.hasAttributeNS(Document.HTML_NAMESPACE_URI, "version"));
        assertTrue(svg.hasAttributeNS(Document.NAMESPACE_SVG, "version"));

        success = false;
        try {
            svg.removeAttributeNS(Document.HTML_NAMESPACE_URI, "version");
        } catch (final DOMException ex) {
            success = (ex.getCode() == DOMException.NOT_FOUND_ERR);
        }
        assertTrue(success, "throw_NOT_FOUND_ERR");
        assertTrue(svg.hasAttributeNS(Document.NAMESPACE_SVG, "version"));
        svg.removeAttributeNS(Document.NAMESPACE_SVG, "version");
        assertFalse(svg.hasAttributeNS(Document.NAMESPACE_SVG, "version"));
        body.appendChild(svg);
        // xml:lang
        body.setAttributeNS("http://www.w3.org/XML/1998/namespace", "xml:lang", "en_UK");
        assertTrue(body.hasAttribute("xml:lang"));
        assertEquals("en_UK", body.getAttribute("xml:lang"));
        assertEquals("en_UK", body.getAttributeNS("http://www.w3.org/XML/1998/namespace", "lang"));
    }

    @Test
    public void testSetAttribute() {
        document = sampleHtmlFile();
        final Element html = document.getDocumentElement();
        final Element body = document.createElement("body");
        html.appendChild(body);
        assertFalse(body.hasAttributes());
        body.setAttribute("foo", "bar");
        assertTrue(body.hasAttributes());
        assertEquals("bar", body.getAttribute("foo"));
        Attr attr = body.getAttributeNode("foo");
        assertFalse(attr.isId());
        assertNull(attr.getSchemaTypeInfo().getTypeName());
        assertEquals("https://www.w3.org/TR/xml/", attr.getSchemaTypeInfo().getTypeNamespace());
        body.setAttribute("id", "bodyId");
        assertTrue(body.hasAttributes());
        assertEquals(2, body.getAttributes().getLength());
        assertEquals("bodyId", body.getAttribute("id"));
        attr = body.getAttributeNode("id");
        assertTrue(attr.isId());
        assertEquals("ID", attr.getSchemaTypeInfo().getTypeName());
        assertEquals("https://www.w3.org/TR/xml/", attr.getSchemaTypeInfo().getTypeNamespace());
        body.setAttribute("id", "newId");
        assertEquals("newId", body.getAttribute("id"));
        assertSame(attr, body.getAttributeNode("id"));
        assertEquals(2, body.getAttributes().getLength());
    }

    @Test
    public void testSetAttributeNS() {
        document = sampleHtmlFile();
        final Element html = document.getDocumentElement();
        final Element body = document.createElementNS(Document.HTML_NAMESPACE_URI, "body");
        html.appendChild(body);
        assertFalse(body.hasAttributes());
        body.setAttributeNS(Document.HTML_NAMESPACE_URI, "foo", "bar");
        assertTrue(body.hasAttribute("foo"));
        assertTrue(body.hasAttributeNS(Document.HTML_NAMESPACE_URI, "foo"));
        assertEquals("bar", body.getAttributeNS(Document.HTML_NAMESPACE_URI, "foo"));
        assertEquals("bar", body.getAttribute("foo"));
        body.setAttributeNS(null, "foo", "foobar");
        assertTrue(body.hasAttribute("foo"));
        assertFalse(body.hasAttributeNS(Document.HTML_NAMESPACE_URI, "foo"));
        assertEquals("foobar", body.getAttributeNS(null, "foo"));
        assertEquals("foobar", body.getAttribute("foo"));
        body.setAttribute("foo", "bar");
        assertEquals("bar", body.getAttributeNS(null, "foo"));
        assertEquals("bar", body.getAttribute("foo"));
        final Attr attr = body.getAttributeNode("foo");
        try {
            attr.setPrefix("pre");
            fail("Must throw an exception");
        } catch (final DOMException e) {
            assertEquals(DOMException.NAMESPACE_ERR, e.getCode());
        }
    }

    @Test
    public void testSetAttributeError() {
        document = sampleHtmlFile();
        final Element p = document.createElement("p");
        try {
            p.setAttribute(null, "bar");
            fail("Must throw an exception");
        } catch (final DOMException e) {
            assertEquals(DOMException.INVALID_CHARACTER_ERR, e.getCode());
        }
        try {
            p.setAttribute("foo=", "bar");
            fail("Must throw an exception");
        } catch (final DOMException e) {
            assertEquals(DOMException.INVALID_CHARACTER_ERR, e.getCode());
        }
        //
        final NamedNodeMap attrs = p.getAttributes();
        assertNull(attrs.getNamedItem(null));
    }

    @Test
    public void testSetAttributeNSError() {
        document = sampleHtmlFile();
        final Element p = document.createElement("p");
        try {
            p.setAttributeNS(Document.HTML_NAMESPACE_URI, null, "bar");
            fail("Must throw an exception");
        } catch (final DOMException e) {
            assertEquals(DOMException.INVALID_CHARACTER_ERR, e.getCode());
        }
        try {
            p.setAttributeNS(Document.HTML_NAMESPACE_URI, "foo=", "bar");
            fail("Must throw an exception");
        } catch (final DOMException e) {
            assertEquals(DOMException.INVALID_CHARACTER_ERR, e.getCode());
        }
        //
        final NamedNodeMap attrs = p.getAttributes();
        assertNull(attrs.getNamedItemNS(null, null));
    }

    @Test
    public void testRemoveAttributeNotFound() {
        document = sampleHtmlFile();
        final Element p = document.createElement("p");
        p.removeAttribute(null);
        p.removeAttribute("");
        p.removeAttribute("foo");
    }

    @Test
    public void testSetAttributeNode() {
        document = sampleHtmlFile();
        final Element html = document.getDocumentElement();
        final Element body = document.createElement("body");
        html.appendChild(body);
        Attr attr = document.createAttribute("id");
        attr.setValue("bodyId");
        assertFalse(attr.isId());
        body.setAttributeNode(attr);
        assertTrue(body.hasAttributes());
        assertTrue(attr.isId());
        assertNotNull(attr.getOwnerElement());
        assertEquals("bodyId", body.getAttribute("id"));
        assertEquals(1, body.getAttributes().getLength());
        assertEquals("bodyId", body.getId());
        assertNull(attr.lookupPrefix(Document.HTML_NAMESPACE_URI));
        assertEquals(Document.XML_NAMESPACE_URI, attr.lookupNamespaceURI("xml"));
        assertNull(attr.lookupNamespaceURI("foo"));
        // Set the attribute to itself
        body.setAttributeNode(attr);
        assertEquals(1, body.getAttributes().getLength());
        // Remove
        final Attr rmattr = body.removeAttributeNode(attr);
        assertSame(rmattr, attr);
        assertFalse(body.hasAttributes());
        assertEquals(0, body.getAttributes().getLength());
        assertNull(attr.getOwnerElement());
        assertEquals("bodyId", attr.getValue());
        assertEquals("", body.getId());
        // Class attribute
        body.setAttribute("class", "fooclass");
        assertTrue(body.hasAttributes());
        assertEquals("fooclass", body.getAttribute("class"));
        assertFalse(body.getAttributeNode("class").isId());
        // Replace class attribute, first with another namespace
        attr = document.createAttributeNS("http://www.example.com/examplens", "e:class");
        attr.setValue("barclass");
        assertEquals("class", attr.getLocalName());
        assertEquals("http://www.example.com/examplens", attr.getNamespaceURI());
        body.setAttributeNodeNS(attr);
        assertEquals("e:class=barclass", attr.getName() + "=" + attr.getNodeValue());
        assertEquals("http://www.example.com/examplens", attr.lookupNamespaceURI("e"));
        assertEquals("e", attr.lookupPrefix("http://www.example.com/examplens"));
        assertNull(attr.lookupPrefix(null));
        assertEquals("fooclass", body.getAttribute("class"));
        attr = document.createAttribute("class");
        attr.setValue("barclass");
        body.setAttributeNode(attr);
        assertEquals("barclass", body.getAttribute("class"));
        final Attr attr2 = body.getAttributeNode("class");
        assertSame(attr, attr2);
        assertNotNull(attr.getSchemaTypeInfo().getTypeName());
        // Attribute from another element
        try {
            html.setAttributeNode(attr);
            fail("Must throw an exception");
        } catch (final DOMException e) {
            assertEquals(DOMException.INUSE_ATTRIBUTE_ERR, e.getCode());
        }
        try {
            html.setAttributeNodeNS(attr);
            fail("Must throw an exception");
        } catch (final DOMException e) {
            assertEquals(DOMException.INUSE_ATTRIBUTE_ERR, e.getCode());
        }
        // Another document
        final Document otherdoc = document.getImplementation().createDocument(null, null, null);
        final Attr otherdocAttr = otherdoc.createAttribute("foo");
        try {
            body.setAttributeNode(otherdocAttr);
            fail("Must throw an exception");
        } catch (final DOMException e) {
            assertEquals(DOMException.WRONG_DOCUMENT_ERR, e.getCode());
        }
        try {
            body.setAttributeNodeNS(otherdocAttr);
            fail("Must throw an exception");
        } catch (final DOMException e) {
            assertEquals(DOMException.WRONG_DOCUMENT_ERR, e.getCode());
        }
    }

    @Test
    public void testSetAttributeNodeNS() {
        document = sampleHtmlFile();
        final Element html = document.getDocumentElement();
        final Attr xsi = document.createAttributeNS(Document.XMLNS_NAMESPACE_URI, "xmlns:xsi");
        xsi.setValue("http://www.w3.org/2001/XMLSchema-instance");
        assertFalse(xsi.isId());
        html.setAttributeNode(xsi);
        assertTrue(html.hasAttributes());
        assertNotNull(xsi.getParentNode());
        assertNotNull(xsi.getOwnerElement());
        final Attr attr = document.createAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "xsi:schemaLocation");
        attr.setValue("http://www.w3.org/1999/xhtml https://www.w3.org/2002/08/xhtml/xhtml1-transitional.xsd");
        html.setAttributeNode(attr);
        assertTrue(html.hasAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation"));
        assertTrue(html.hasAttribute("xsi:schemaLocation"));
        assertNotNull(html.getAttributeNodeNS("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation"));
        assertNotNull(html.getAttributeNode("xsi:schemaLocation"));
        assertEquals("http://www.w3.org/1999/xhtml https://www.w3.org/2002/08/xhtml/xhtml1-transitional.xsd",
                html.getAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation"));
        assertEquals("http://www.w3.org/1999/xhtml https://www.w3.org/2002/08/xhtml/xhtml1-transitional.xsd",
                html.getAttribute("xsi:schemaLocation"));
        assertEquals(2, html.getAttributes().getLength());
        assertEquals("http://www.w3.org/2001/XMLSchema-instance", attr.lookupNamespaceURI("xsi"));
        assertEquals("xsi", attr.lookupPrefix("http://www.w3.org/2001/XMLSchema-instance"));
        attr.setPrefix("sch");
        assertTrue(html.hasAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation"));
        assertTrue(html.hasAttribute("sch:schemaLocation"));
        assertNotNull(html.getAttributeNodeNS("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation"));
        assertNotNull(html.getAttributeNode("sch:schemaLocation"));
        assertEquals("http://www.w3.org/1999/xhtml https://www.w3.org/2002/08/xhtml/xhtml1-transitional.xsd",
                html.getAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation"));
        assertEquals("http://www.w3.org/1999/xhtml https://www.w3.org/2002/08/xhtml/xhtml1-transitional.xsd",
                html.getAttribute("sch:schemaLocation"));
    }

    @Test
    public void testSetAttributeNodeNSXML() {
        document = sampleHtmlFile();
        final Element html = document.getDocumentElement();
        final Attr xml = document.createAttributeNS(Document.XML_NAMESPACE_URI, "xml:lang");
        xml.setValue("en");
        assertEquals(Document.XML_NAMESPACE_URI, xml.getNamespaceURI());
        assertEquals("lang", xml.getLocalName());
        assertEquals("xml:lang", xml.getName());
        assertFalse(xml.isId());
        html.setAttributeNode(xml);
        assertTrue(html.hasAttributes());
        assertNotNull(xml.getParentNode());
        assertNotNull(xml.getOwnerElement());
        assertTrue(html.hasAttributeNS(Document.XML_NAMESPACE_URI, "lang"));
        final Attr attr = document.createAttribute("lang");
        attr.setValue("en");
        html.setAttributeNode(attr);
        assertTrue(html.hasAttributeNS(Document.XML_NAMESPACE_URI, "lang"));
        assertTrue(html.hasAttributeNS(null, "lang"));
        assertTrue(html.hasAttribute("lang"));
        assertSame(attr, html.getAttributeNode("lang"));
        assertEquals(2, html.getAttributes().getLength());
        // Recognize xml:id as an implicit 'id' attribute.
        final Attr idattr = document.createAttributeNS(Document.XML_NAMESPACE_URI, "xml:id");
        idattr.setValue("foo");
        html.setAttributeNode(idattr);
        assertTrue(idattr.isId());
        assertTrue(html.hasAttributeNS(Document.XML_NAMESPACE_URI, "id"));
        assertSame(idattr, html.getAttributeNodeNS(Document.XML_NAMESPACE_URI, "id"));
        assertEquals("foo", html.getId());
        assertEquals(3, html.getAttributes().getLength());
        assertSame(idattr, html.removeAttributeNode(idattr));
        assertEquals("", html.getId());
        assertEquals(2, html.getAttributes().getLength());
        //
        try {
            document.createAttributeNS("http://www.example.com/ns", "xml:foo");
            fail("Must throw exception");
        } catch (final DOMException e) {
            assertEquals(DOMException.NAMESPACE_ERR, e.getCode());
        }
    }

    @Test
    public void testSetAttributeNodeClass() {
        document = sampleHtmlFile();
        final HTMLCollection fooelms = document.getElementsByClassName("foo");
        assertEquals(0, fooelms.getLength());
        final Element body = document.createElement("body");
        document.getDocumentElement().appendChild(body);
        final Attr attr = document.createAttribute("class");
        attr.setValue("foo bar");
        assertEquals("class", attr.getName());
        assertEquals("foo bar", attr.getValue());
        body.setAttributeNode(attr);
        assertTrue(body.hasAttribute("class"));
        assertNotNull(attr.getParentNode());
        assertSame(body, attr.getOwnerElement());
        assertEquals("foo bar", attr.getValue());
        assertEquals(1, fooelms.getLength());
        assertEquals(fooelms.toString(), document.getElementsByClassName("foo").toString());
        assertSame(body, fooelms.item(0));
        final HTMLCollection barelms = document.getElementsByClassName("bar");
        assertEquals(1, barelms.getLength());
        final HTMLCollection foobarelms = document.getElementsByClassName("bar foo");
        assertEquals(1, foobarelms.getLength());
        assertSame(body, foobarelms.item(0));
        body.getClassList().remove("bar");
        assertEquals(0, barelms.getLength());
        assertEquals(0, foobarelms.getLength());
        body.getClassList().toggle("bar");
        assertEquals(1, barelms.getLength());
        body.removeAttribute("class");
        assertNull(attr.getOwnerElement());
        assertEquals("foo bar", attr.getValue());
        assertEquals(0, fooelms.getLength());
        assertEquals(0, barelms.getLength());
    }

    @Test
    public void testGetClassList() {
        document = sampleHtmlFile();
        final Element body = document.createElement("body");
        final DOMTokenList list = body.getClassList();
        assertNotNull(list);
        assertEquals(0, list.getLength());
        assertFalse(list.contains("foo"));
        assertFalse(body.hasAttribute("class"));
        final Attr attr = document.createAttribute("class");
        attr.setValue("foo");
        body.setAttributeNode(attr);
        assertEquals(1, list.getLength());
        assertEquals("foo", list.item(0));
        assertEquals("foo", list.getValue());
        assertTrue(list.contains("foo"));
        attr.setValue("foo bar");
        assertEquals(2, list.getLength());
        assertEquals("foo", list.item(0));
        assertEquals("foo bar", list.getValue());
        assertTrue(list.contains("foo"));
        list.add("000");
        assertEquals(3, list.getLength());
        assertEquals("foo", list.item(0));
        assertEquals("000", list.item(2));
        assertEquals("foo bar 000", list.getValue());
        assertEquals("foo bar 000", attr.getValue());
        assertTrue(list.contains("foo"));
        list.toggle("111");
        assertEquals(4, list.getLength());
        list.toggle("111");
        assertEquals(3, list.getLength());
        list.replace("000", "111");
        assertEquals("foo bar 111", list.getValue());
        list.remove("111");
        assertEquals(2, list.getLength());
        assertEquals("foo bar", list.getValue());
        body.removeAttribute("class");
        assertEquals(0, list.getLength());
        assertEquals("foo bar", attr.getValue());
    }

    @Test
    public void testGetClassListQuirks() {
        document = sampleHtmlFile();
        document.removeChild(document.getDoctype());
        final Element body = document.createElement("body");
        final DOMTokenList list = body.getClassList();
        assertNotNull(list);
        assertEquals(0, list.getLength());
        assertFalse(list.contains("foo"));
        assertFalse(body.hasAttribute("class"));
        final Attr attr = document.createAttribute("class");
        attr.setValue("foo");
        body.setAttributeNode(attr);
        assertEquals(1, list.getLength());
        assertEquals("foo", list.item(0));
        assertEquals("foo", list.getValue());
        assertTrue(list.contains("foo"));
        attr.setValue("Foo bar");
        assertEquals(2, list.getLength());
        assertEquals("foo", list.item(0));
        assertEquals("foo bar", list.getValue());
        assertTrue(list.contains("foo"));
        assertTrue(list.contains("Foo"));
        list.add("000");
        assertEquals(3, list.getLength());
        assertEquals("foo", list.item(0));
        assertEquals("000", list.item(2));
        assertEquals("foo bar 000", list.getValue());
        assertEquals("foo bar 000", attr.getValue());
        list.toggle("111");
        assertEquals(4, list.getLength());
        list.toggle("111");
        assertEquals(3, list.getLength());
        list.replace("000", "111");
        assertEquals("foo bar 111", list.getValue());
        list.remove("111");
        assertEquals(2, list.getLength());
        assertEquals("foo bar", list.getValue());
        body.removeAttribute("class");
        assertEquals(0, list.getLength());
        assertEquals("foo bar", attr.getValue());
    }

    @Test
    public void testGetClassList2() {
        document = sampleHtmlFile();
        final Element body = document.createElement("body");
        final DOMTokenList list = body.getClassList();
        assertNotNull(list);
        assertEquals(0, list.getLength());
        list.add("foo");
        assertTrue(body.hasAttribute("class"));
        assertEquals("foo", body.getAttribute("class"));
        list.add("foo");
        assertEquals("foo", body.getAttribute("class"));
        list.add("bar");
        assertEquals("foo bar", body.getAttribute("class"));
        assertEquals("[object HTMLBodyElement]", body.toString());
        try {
            list.add(null);
            fail("Must throw exception");
        } catch (final DOMException e) {
            assertEquals(DOMException.SYNTAX_ERR, e.getCode());
        }
        try {
            list.add("");
            fail("Must throw exception");
        } catch (final DOMException e) {
            assertEquals(DOMException.INVALID_CHARACTER_ERR, e.getCode());
        }
        try {
            list.add("foo bar");
            fail("Must throw exception");
        } catch (final DOMException e) {
            assertEquals(DOMException.INVALID_CHARACTER_ERR, e.getCode());
        }
        list.replace("bar", "faa");
        assertEquals("foo faa", body.getAttribute("class"));
        list.replace("faa", "foo");
        assertEquals("foo", body.getAttribute("class"));
        body.setClassName("bar");
        assertEquals("bar", body.getAttribute("class"));
        assertEquals("bar", list.getValue());
        assertEquals("[object HTMLBodyElement]", body.toString());
    }

    @Test
    public void matchesStringString() {
        document = sampleHtmlFile();
        final Element body = document.createElement("body");
        document.getDocumentElement().appendChild(body);
        body.setAttribute("id", "bodyId");
        final Element div1 = document.createElement("div");
        final Element div2 = document.createElement("div");
        body.appendChild(div1);
        body.appendChild(div2);
        assertFalse(body.matches(".foo"));
        final DOMTokenList list = body.getClassList();
        assertNotNull(list);
        assertEquals(0, list.getLength());
        final Attr attr = document.createAttribute("class");
        attr.setValue("foo");
        body.setAttributeNode(attr);
        assertTrue(body.matches(".foo"));
        assertTrue(body.matches("#bodyId"));
        attr.setValue("foo bar");
        assertTrue(body.matches(".bar"));
        assertTrue(div1.matches(".bar div"));
        assertTrue(div1.matches("body > div"));
        assertTrue(div1.matches("div:first-child"));
        assertFalse(div2.matches("div:first-child"));
        assertTrue(div2.matches("div:last-child"));
        assertTrue(div1.matches("div:first-line"));
        body.removeAttribute("class");
        assertFalse(body.matches(".bar"));
    }

    @Test
    public void matchesStringStringQuirks() {
        document = sampleHtmlFile();
        final Element body = document.createElement("body");
        document.getDocumentElement().appendChild(body);
        body.setAttribute("id", "bodyId");
        final Element div1 = document.createElement("div");
        final Element div2 = document.createElement("div");
        body.appendChild(div1);
        body.appendChild(div2);
        assertFalse(body.matches(".foo"));
        final DOMTokenList list = body.getClassList();
        assertNotNull(list);
        assertEquals(0, list.getLength());
        final Attr attr = document.createAttribute("class");
        attr.setValue("foo");
        body.setAttributeNode(attr);
        assertTrue(body.matches(".foo"));
        assertTrue(body.matches(".foo"));
        assertTrue(body.matches("#bodyId"));
        attr.setValue("foo bar");
        assertTrue(body.matches(".bar"));
        assertTrue(div1.matches(".bar div"));
        assertTrue(div1.matches(".Bar div"));
        assertTrue(div1.matches("body > div"));
        assertTrue(div1.matches("div:first-child"));
        assertFalse(div2.matches("div:first-child"));
        assertTrue(div2.matches("div:last-child"));
        assertTrue(div1.matches("div:first-line"));
        body.removeAttribute("class");
        assertFalse(body.matches(".bar"));
    }

    @Test
    public void matchesStringString2() {
        document = sampleHtmlFile();
        final Element body = document.createElement("body");
        document.getDocumentElement().appendChild(body);
        body.setAttribute("id", "bodyId");
        final Element div1 = document.createElement("div");
        final Element div2 = document.createElement("div");
        body.appendChild(div1);
        body.appendChild(div2);
        assertTrue(div2.matches("div:last-child"));
        assertFalse(div1.matches("div:last-child"));
        assertFalse(body.matches("div:last-child"));
        NodeList elements = document.querySelectorAll("div:last-child");
        assertNotNull(elements);
        assertEquals(1, elements.getLength());
        assertSame(div2, elements.item(0));
        elements = document.querySelectorAll("div:first-child");
        assertNotNull(elements);
        assertEquals(1, elements.getLength());
        assertSame(div1, elements.item(0));
        elements = document.querySelectorAll("#nosuchID");
        assertNotNull(elements);
        assertEquals(0, elements.getLength());
    }

    @Test
    public void testGetStyle() {
        document = sampleHtmlFile();
        final HTMLElementImpl body = (HTMLElementImpl) document.createElement("body");
        assertNotNull(body.getStyle());
        assertFalse(body.hasAttributes());
        document.getDocumentElement().appendChild(body);
        body.setAttribute("style", "font-family: Arial");
        assertTrue(body.hasAttributes());
        assertTrue(body.hasAttribute("style"));
        assertEquals("font-family: Arial", body.getAttribute("style"));
        final CSSStyleDeclaration style = body.getStyle();
        assertNotNull(style);
        assertEquals("font-family: arial", style.getCssText());
        style.setCssText("font-family: Helvetica");
        assertEquals("font-family: Helvetica", style.getCssText());
        assertEquals("font-family: Helvetica", body.getAttribute("style"));
        body.removeAttribute("style");
        body.setAttribute("style", "font-family");
    }

    @Test
    public void testCreateElement() {
        document = sampleHtmlFile();
        final Element html = document.getDocumentElement();
        final Element body = document.createElement("body");
        html.appendChild(body);
        assertNull(body.getNamespaceURI());
        final Element svg = document.createElementNS(Document.NAMESPACE_SVG, "svg");
        body.appendChild(svg);
        assertEquals(Document.NAMESPACE_SVG, svg.getNamespaceURI());
        final Element p = document.createElementNS(null, "p");
        body.appendChild(p);
        assertNull(p.getNamespaceURI());
    }

    @Test
    public void testGetChildren() {
        document = sampleHtmlFile();
        final Element html = document.getDocumentElement();
        final Element body = document.createElement("body");
        html.appendChild(body);
        body.appendChild(document.createTextNode("\n   \n"));
        final Element div1 = document.createElement("div");
        body.appendChild(div1);
        body.appendChild(document.createTextNode("\n   \n"));
        final Element div2 = document.createElement("div");
        body.appendChild(div2);
        body.appendChild(document.createTextNode("\n   \n"));
        final Element div3 = document.createElement("div");
        body.appendChild(div3);
        body.appendChild(document.createTextNode("\n   \n"));
        body.appendChild(document.createComment("This is a comment"));
        final Element div4 = document.createElement("div");
        body.appendChild(div4);
        body.appendChild(document.createTextNode("\n   \n"));
        body.appendChild(document.createTextNode("\n   \n"));
        HTMLCollectionImpl list = (HTMLCollectionImpl) body.getChildren();
        assertNotNull(list);
        assertEquals(4, list.getLength());
        assertSame(div1, list.item(0));
        assertSame(div2, list.item(1));
        assertSame(div3, list.item(2));
        assertSame(div4, list.item(3));
        assertNull(list.item(4));
        assertSame(div1, body.getFirstElementChild());
        assertSame(div4, body.getLastElementChild());
        assertEquals(list.getLength(), body.getChildElementCount());
        assertSame(list, body.getChildren());
        assertFalse(list.isEmpty());
        //
        list = (HTMLCollectionImpl) document.getChildren();
        assertNotNull(list);
        assertEquals(1, list.getLength());
        assertSame(html, list.item(0));
        assertEquals(1, document.getChildElementCount());
        assertFalse(list.isEmpty());
        //
        list = (HTMLCollectionImpl) html.getChildren();
        assertNotNull(list);
        assertEquals(1, list.getLength());
        assertSame(body, list.item(0));
        assertNull(list.item(1));
        assertNull(list.item(-1));
        assertEquals(1, html.getChildElementCount());
        assertSame(body, html.getFirstElementChild());
        assertSame(body, html.getLastElementChild());
        assertSame(list, html.getChildren());
        assertFalse(list.isEmpty());
        //
        list = (HTMLCollectionImpl) div4.getChildren();
        assertTrue(list.isEmpty());
        div4.appendChild(document.createTextNode(" "));
        assertTrue(list.isEmpty());
    }

    @Test
    public void testGetChildNodes() {
        document = sampleHtmlFile();
        final Element html = document.getDocumentElement();
        final Element body = document.createElement("body");
        html.appendChild(body);
        final Text first = document.createTextNode("\n   \n");
        body.appendChild(first);
        final Element div1 = document.createElement("div");
        body.appendChild(div1);
        body.appendChild(document.createTextNode("\n   \n"));
        final Element div2 = document.createElement("div");
        body.appendChild(div2);
        body.appendChild(document.createTextNode("\n   \n"));
        final Element div3 = document.createElement("div");
        body.appendChild(div3);
        body.appendChild(document.createTextNode("\n   \n"));
        body.appendChild(document.createComment("This is a comment"));
        final Element div4 = document.createElement("div");
        body.appendChild(div4);
        body.appendChild(document.createTextNode("\n   \n"));
        final Text last = document.createTextNode("\n   \n");
        body.appendChild(last);
        NodeListImpl list = (NodeListImpl) body.getChildNodes();
        assertNotNull(list);
        assertEquals(11, list.getLength());
        assertSame(first, list.item(0));
        assertSame(div1, list.item(1));
        assertSame(div2, list.item(3));
        assertSame(div3, list.item(5));
        assertSame(div4, list.item(8));
        assertSame(last, list.item(10));
        assertNull(list.item(11));
        assertNull(list.item(-1));
        assertSame(first, body.getFirstChild());
        assertSame(last, body.getLastChild());
        assertSame(list, body.getChildNodes());
        assertTrue(list.contains(div4));
        assertFalse(list.contains(html));
        assertFalse(list.isEmpty());

        list = (NodeListImpl) document.getChildNodes();
        assertNotNull(list);

        assertEquals(2, list.getLength());
        assertSame(html, list.item(1));
        assertSame(document.getDoctype(), document.getFirstChild());
        assertFalse(list.contains(div4));
        assertTrue(list.contains(html));
        assertFalse(list.isEmpty());
        list = (NodeListImpl) html.getChildNodes();
        assertNotNull(list);
        assertEquals(3, list.getLength());
        assertSame(body, list.item(2));
        assertNotNull(list.item(1));
        assertNull(list.item(-1));
        assertSame(document.getHead(), html.getFirstChild());
        assertSame(body, html.getLastChild());
        assertSame(list, html.getChildNodes());
        assertTrue(list.contains(body));
        assertFalse(list.contains(div4));
        assertFalse(list.isEmpty());

        list = (NodeListImpl) div4.getChildNodes();
        assertTrue(list.isEmpty());
        div4.appendChild(document.createTextNode(" "));
        assertFalse(list.isEmpty());
    }

    @Test
    public void testGetTextContent() {
        document = sampleHtmlFile();
        final Element html = document.getDocumentElement();
        final Element body = document.createElement("body");
        html.appendChild(body);
        body.appendChild(document.createTextNode("    "));
        final Element div = document.createElement("div");
        body.appendChild(div);
        div.appendChild(document.createTextNode("   "));
        final Element span1 = document.createElement("span");
        span1.appendChild(document.createTextNode("span 1"));
        div.appendChild(span1);
        div.appendChild(document.createTextNode("   "));
        final Element span2 = document.createElement("span");
        span2.appendChild(document.createTextNode("span 2"));
        div.appendChild(span2);
        body.appendChild(document.createTextNode("   "));
        final Element span3 = document.createElement("span");
        span3.appendChild(document.createTextNode("span 3"));
        body.appendChild(span3);
        body.appendChild(document.createTextNode("     "));
        body.appendChild(document.createComment("This is a comment"));
        final Element span4 = document.createElement("span");
        span4.appendChild(document.createTextNode("span 4"));
        body.appendChild(span4);
        body.appendChild(document.createTextNode("   "));
        //
        assertEquals("       span 1   span 2   span 3     span 4   ", body.getTextContent());
    }

    @Test
    public void testGetInnerText() {
        document = sampleHtmlFile();
        final ElementImpl html = (ElementImpl) document.getDocumentElement();
        final ElementImpl body = (ElementImpl) document.createElement("body");
        html.appendChild(body);
        body.appendChild(document.createTextNode("    "));
        final Element div = document.createElement("div");
        body.appendChild(div);
        div.appendChild(document.createTextNode("   "));
        final Element span1 = document.createElement("span");
        span1.appendChild(document.createTextNode(" span   1 "));
        div.appendChild(span1);
        div.appendChild(document.createTextNode("   "));
        final Element span2 = document.createElement("span");
        span2.appendChild(document.createTextNode(" span     2 "));
        span2.setAttribute("style", "text-transform: capitalize");
        div.appendChild(span2);
        // pre
        final Element pre = document.createElement("pre");
        pre.appendChild(document.createTextNode("  white  space   must   be\n   preserved   "));
        div.appendChild(pre);
        //
        body.appendChild(document.createTextNode("   "));
        final Element span3 = document.createElement("span");
        span3.appendChild(document.createTextNode(" span 3"));
        body.appendChild(span3);
        body.appendChild(document.createTextNode("     "));
        body.appendChild(document.createComment("This is a comment"));
        final Element span4 = document.createElement("span");
        span4.appendChild(document.createTextNode(" span \n 4 "));
        span4.setAttribute("style", "white-space: pre-line; text-transform: uppercase");
        body.appendChild(span4);
        body.appendChild(document.createTextNode("   "));
        //
        assertEquals(" span 1 Span 2 \n  white  space   must   be\n   preserved   \n\nspan 3 SPAN\n4\n",
                body.getInnerText());
    }

    @Test
    public void testCloneNode() {
        final Document document = domImpl.createDocument(null, null, null);
        final Element tag = document.createElement("html");
        document.appendChild(tag);
        final Element html = document.getDocumentElement();
        final Element body = document.createElement("body");
        html.appendChild(body);
        final Attr attr = document.createAttribute("id");
        attr.setValue("bodyId");
        body.setAttributeNode(attr);
        body.setAttribute("class", "fooclass");
        final Element div = document.createElement("div");
        body.appendChild(div);
        div.appendChild(document.createTextNode("foo"));
        Element elm = (Element) body.cloneNode(false);
        assertEquals(body.getNodeName(), elm.getNodeName());
        assertEquals(body.getAttributes(), elm.getAttributes());
        final Attr cloneId = elm.getAttributeNode("id");
        assertTrue(cloneId.isId());
        assertTrue(body.isEqualNode(elm));
        assertTrue(cloneId.isId());
        elm = (Element) body.cloneNode(true);
        assertTrue(body.isEqualNode(elm));
        assertEquals("DIV", elm.getChildNodes().item(0).getNodeName());
        assertEquals("foo", elm.getChildNodes().item(0).getChildNodes().item(0).getNodeValue());
    }

    @Test
    public void testGetElementById() {
        final Document document = domImpl.createDocument(null, null, null);
        final Element body = document.createElement("body");
        document.appendChild(body);
        Attr attr = document.createAttribute("id");
        attr.setValue("myId");
        final Attr fooAttr = document.createAttribute("foo");
        fooAttr.setValue("bar");
        body.setAttributeNode(attr);
        body.setAttributeNode(fooAttr);
        assertSame(body, document.getElementById("myId"));
        body.setIdAttributeNode(fooAttr, true); // Does not work, is ignored
        assertSame(body, document.getElementById("bar"));
        body.removeAttribute("id");
        attr = document.createAttributeNS("http://www.w3.org/XML/1998/namespace", "xml:id");
        attr.setValue("xmlId");
        body.setAttributeNode(attr);
        assertTrue(attr.isId());
        assertEquals("xmlId", body.getAttributeNS("http://www.w3.org/XML/1998/namespace", "id"));
        assertSame(body, document.getElementById("xmlId"));
    }

    @Test
    public void getElementsByTagName() {
        final Document document = domImpl.createDocument(null, null, null);
        final Element html = document.createElement("html");
        final Element body = document.createElement("body");
        html.appendChild(body);
        document.appendChild(html);

        final Element docElm = document.getDocumentElement();
        final Element elem1 = document.createElement("div");
        elem1.setAttribute("id", "div1");
        docElm.appendChild(elem1);
        final Element elem2 = document.createElement("div");
        elem2.setAttribute("id", "div2");
        elem1.appendChild(elem2);
        final Element elem3 = document.createElement("div");
        elem3.setAttribute("id", "div3");
        elem2.appendChild(elem3);
        final Element elem4 = document.createElement("div");
        elem4.setAttribute("id", "div4");
        docElm.appendChild(elem4);
        HTMLCollectionImpl list = (HTMLCollectionImpl) docElm.getElementsByTagName("div");
        assertNotNull(list);
        assertEquals(4, list.getLength());
        assertNull(list.item(-1));
        assertTrue(elem1.isEqualNode(list.item(0)));
        assertTrue(elem2.isEqualNode(list.item(1)));
        assertTrue(elem3.isEqualNode(list.item(2)));
        assertTrue(elem4.isEqualNode(list.item(3)));

        list = (HTMLCollectionImpl) elem1.getElementsByTagName("div");
        assertNotNull(list);
        assertEquals(2, list.getLength());
        assertNull(list.item(-1));
        assertTrue(elem2.isEqualNode(list.item(0)));
        assertTrue(elem3.isEqualNode(list.item(1)));
        assertNull(list.item(2));
        //
        list = (HTMLCollectionImpl) elem2.getElementsByTagName("div");
        assertNotNull(list);
        assertEquals(1, list.getLength());
        assertNull(list.item(-1));
        assertSame(elem3, list.item(0));
        assertNull(list.item(1));
        //
        list = (HTMLCollectionImpl) elem4.getElementsByTagName("div");
        assertNotNull(list);
        assertEquals(0, list.getLength());
        assertNull(list.item(-1));
        assertNull(list.item(0));
        final Element foo = document.createElementNS(Document.NAMESPACE_SVG, "s:svg");
        elem4.appendChild(foo);
        list = (HTMLCollectionImpl) elem4.getElementsByTagName("svg");
        assertNotNull(list);
        assertTrue(list.isEmpty());
        //
        list = (HTMLCollectionImpl) elem4.getElementsByTagName("s:svg");
        assertNotNull(list);
        assertEquals(1, list.getLength());
    }

    @Test
    public void testGetTagName() {
        document = sampleHtmlFile();
        Element elm = document.createElement("p");
        assertEquals("P", elm.getTagName());
        elm = document.createElementNS("http://www.example.com/examplens", "e:p");
        assertEquals("P", elm.getLocalName());
        assertEquals("E:P", elm.getTagName());
    }
}