/*
 * Copyright (c) 2008, Aaron Digulla
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in
 *       the documentation and/or other materials provided with the
 *       distribution.
 *     * Neither the name of Aaron Digulla nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package de.pdark.decentxml;

import static org.junit.Assert.*;

import de.pdark.decentxml.XMLTokenizer.Type;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;

public class DocumentTest {
  @Test
  public void testDocument() throws Exception {
    Document doc = new Document();
    assertNull(doc.getRootElement());
    assertEquals("", doc.toXML());
  }

  @Test
  public void testDocument2() throws Exception {
    Document doc = new Document();
    Element root = new Element("root");
    doc.setRootNode(root);
    assertEquals("<root/>", doc.toXML());
  }

  @Test
  public void testDocument3() throws Exception {
    Document doc = new Document();
    Document doc2 = new Document();
    Element root = new Element("root");

    doc.setRootNode(root);
    assertEquals(root, doc.getRootElement());
    assertEquals(root, doc.getNode(0));
    assertEquals(doc, root.getParent());

    doc2.setRootNode(root);
    assertEquals("", doc.toXML());
    assertFalse(doc.hasNodes());
    assertNull(doc.getRootElement());
    assertEquals("<root/>", doc2.toXML());
    assertEquals(root, doc2.getRootElement());
    assertEquals(root, doc2.getNode(0));
    assertEquals(doc2, root.getParent());
  }

  @Test
  public void testDocument4() throws Exception {
    Document doc = new Document();
    Element root = new Element("root");
    Element root2 = new Element("root2");

    doc.setRootNode(root);
    assertEquals(root, doc.getRootElement());
    assertEquals(root, doc.getNode(0));
    assertEquals(doc, root.getParent());

    doc.setRootNode(root2);
    assertEquals("<root2/>", doc.toXML());
    assertTrue(doc.hasNodes());
    assertEquals(root2, doc.getRootElement());
    assertNull(root.getParent());
    assertEquals(doc, root2.getParent());
  }

  @Test
  public void testDocument5() throws Exception {
    Document doc = new Document();
    Element root = new Element("root");
    Element root2 = new Element("root");
    doc.setRootNode(root);

    assertFalse(doc.removeNode(root2));
  }

  @Test
  public void testDocument6() throws Exception {
    Document doc = new Document().addNodes(new Text(" "), new Text(" "));
    try {
      doc.addNodes(1, new Attribute("x", "1"));
      fail("No exception was thrown");
    } catch (XMLParseException e) {
      assertEquals("Line 1, column 2: ATTRIBUTE node is not allowed here", e.getMessage());
    }
  }

  @Test
  public void testDocument7() throws Exception {
    Document doc = new Document();
    List<Node> l = new ArrayList<Node>();
    Element root = new Element("root");
    l.add(root);
    doc.addNodes(l);

    assertEquals(root, doc.getRootElement());
    assertEquals(doc, root.getParent());
  }

  @Test
  public void testDocument8() throws Exception {
    Document doc = new Document();
    Element root = new Element("root");
    doc.setRootNode(root);

    assertEquals(root, doc.removeNode(0));
    assertNull(doc.getRootElement());
    assertNull(root.getParent());
  }

  @Test
  public void testDocument9() throws Exception {
    Document doc = new Document();
    Element root = new Element("root");
    doc.setRootNode(root);

    assertTrue(doc.removeNode(root));
    assertNull(doc.getRootElement());
    assertNull(root.getParent());
  }

  @Test
  public void testDocument10() throws Exception {
    Document doc = new Document();
    doc.setVersion("1.0");
    Node n = doc.getNode(0);
    assertEquals(Type.PROCESSING_INSTRUCTION, n.getType());
    doc.removeNode(0);
  }

  @Test
  public void testDocument11() throws Exception {
    Document doc = new Document();
    doc.setVersion("1.0");
    Node n = doc.getNode(0);
    assertEquals(Type.PROCESSING_INSTRUCTION, n.getType());
    doc.removeNode(n);
  }

  @Test
  public void testDocument12() throws Exception {
    Document doc = new Document();
    assertFalse(doc.removeNode(null));
  }

  @Test
  public void testDocument13() throws Exception {
    Document doc = new Document();
    doc.parseXMLDeclaration();
  }

  @Test
  public void testAddNullNode() throws Exception {
    try {
      new Document().addNode(null);
      fail("No exception was thrown");
    } catch (NullPointerException ex) {
      assertEquals("node is null", ex.getMessage());
    }
  }

  /** Show various ways to build an XML document from scratch */
  @Test
  public void testBuildDocument() throws Exception {
    Document doc =
        new Document(
            new ProcessingInstruction("xml", "version=\"1.0\" encoding=\"utf-8\""),
            new Text("\n\n"),
            new Comment(" Comment "),
            new Text("\n"));

    Element root =
        new Element("root")
            .addNode(new Text("\n    "))
            .addNode(new Comment(" comment "))
            .addNode(new Text("\n    "));
    doc.addNode(root);

    root.addNodes(
        new Element("e")
            .addNodes(
                new Text("\n\ttext<>\n\t"), new Text(Type.CDATA, "text<></e>"), new Text("\n    ")),
        new Text("\n    "),
        new Element("empty"),
        new Text("\n    "),
        new Element("empty "),
        new Text("\n    "));

    new Element(root, "a")
        .addAttributes(
            new Attribute("x", "1", '\''),
            new Attribute("y", "2"),
            new Attribute("f1", "\""),
            new Attribute("f2", "'"))
        .setPostSpace(" ");

    List<Node> l = new ArrayList<Node>();
    l.add(new Text("\n    "));
    Element e = new Element("a");
    l.add(e);

    root.addNodes(l);

    e.addAttribute(new Attribute("x", "1", '\''));
    e.addAttribute(new Attribute("y", "2", '"'));
    e.addAttribute(new Attribute("f1", "\""));
    e.addAttribute(new Attribute("f2", "\"'"));
    e.setPostSpace(" ");

    e.addNode(new Text("b"));

    e.setBeginName(" a");
    e.setEndName(" a ");

    root.addNode(new Text("\n"));
    doc.addNode(new Text("\n"));

    assertEquals(XMLTokenizerTest.XML, doc.toXML());
  }

  @Test
  public void testIllegalText() throws Exception {
    Document doc = new Document();
    doc.addNode(new Element("e"));
    doc.setEncoding(XMLInputStreamReader.ENCODING_ISO_Latin_1);

    try {
      doc.addNode(2, new Text("xxx"));
      fail("No exception was thrown");
    } catch (XMLParseException e) {
      assertEquals("Line 2, column 1: TEXT node is not allowed here", e.getMessage());
    }
  }
}
