/* 
 * E-XML Library:  For XML, XML-RPC, HTTP, and related.
 * Copyright (C) 2002-2008  Elias Ross
 * 
 * genman@noderunner.net
 * http://noderunner.net/~genman
 * 
 * 1025 NE 73RD ST
 * SEATTLE WA 98115
 * USA
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * $Id$
 */

package net.noderunner.exml;

import java.io.BufferedWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Vector;

/**
 * This class tests the Xml writer against a DOM parser.
 */
public class XmlWriterTest
	extends junit.framework.TestCase
{

	public XmlWriterTest(String name) {
		super(name);
	}

	/*
	public static junit.framework.TestSuite suite() {
		return new org.hansel.CoverageDecorator(XmlWriterTest.class,
			new Class[] { XmlWriter.class });
	} 
	*/

	public static void main(String[] args) {
		junit.textui.TestRunner.run(XmlWriterTest.class);
	}

	static StringWriter sw;
	static XmlWriter xw;
	static XmlReader xr;
	static StringReader sr;

	/**
	 * Create a new XmlWriter around a StringWriter for testing.
	 */
	public static void newWriter() {
		sw = new StringWriter();
		xw = new XmlWriter(new BufferedWriter(sw));
	}

	public static void newReader() 
		throws java.io.IOException
	{
		xw.close();
		xr = new XmlReader(new StringReader(sw.getBuffer().toString()));
	}

	public void testEmptyDoc() 
		throws Exception
	{
		newWriter();
		xw.writeHeader("UTF-16");
		xw.emptyElement("root");
		newReader();
		Document d = xr.document();
		assertEquals("got <root/> ? ", d.getRootElement().getName(), "root");
		while (xr.Misc(null));
		assertEquals("Read everything in document", xr.hasMoreData(), false);
	}

	public void testSetWriter()
		throws Exception
	{
		newWriter();
		xw.writeHeader("UTF-16");
		xw.emptyElement("root");
		sw = new StringWriter();
		xw.setWriter(sw);
		xw.emptyElement("bob");
		assertEquals("<bob/>", sw.toString());
	}

	public void testWriteCData()
		throws Exception
	{
		newWriter();
		CharacterData cd = new CharacterData();
		cd.getWriter().write("&");
		xw.writeCData(cd);
		xw.close();
		assertEquals("&amp;", sw.toString());
	}

	public void testWriteElementTree()
		throws Exception
	{
		newWriter();
		Element e = new Element("f");
		e.appendChild(new PI("php"));
		CharacterData cd = new CharacterData();
		cd.getWriter().write("x");
		e.appendChild(cd);
		xw.element(e);
		xw.close();
		assertEquals("<f><?php ?>x</f>", sw.toString());
	}

	public void testWriteCharArray()
		throws Exception
	{
		newWriter();
		xw.write("&amp;".toCharArray());
		xw.close();
		assertEquals("&amp;", sw.toString());
	}

	public void testEmpty()
		throws Exception
	{
		newWriter();
		Element e = new Element("frank");
		Element e2 = new Element("larry");
		e.appendChild(e2);
		xw.emptyElement(e);
		xw.close();
		assertEquals("<frank></frank>", sw.toString());

		newWriter();
		e2.setOpen(false);
		xw.emptyElement(e2);
		xw.close();
		assertEquals("<larry/>", sw.toString());
	}
	public void testEntities()
		throws Exception
	{
		newWriter();
		String sect = "<>&\"\'";
		xw.writeCData(sect);

		newReader();

		assertNull(xr.Reference());
		// StringWriter out = new StringWriter();
		// xr.CharData(out);
		// assertEquals("Should have <>& reference", sect, out.getBuffer().toString());
	}

	public void testWrite()
		throws Exception
	{
		newWriter();
		String s = "<>&'\"";
		xw.write(s);
		xw.flush();
		assertTrue("No escape", s.equals(sw.toString()));
	}

	public void testWrite2()
		throws Exception
	{
		newWriter();
		String s = "<>&'\"";
		char chars[] = s.toCharArray();
		xw.write(chars, 0, chars.length);
		xw.flush();
		assertTrue("No escape", s.equals(sw.toString()));
	}

	public void testSmallDoc()
		throws Exception
	{
		newWriter();
		xw.writeHeader("UTF-16");

		// document
		Element e = new Element("root");
		e.appendChild(new Element("a"));
		List l = new Vector();
		l.add(new Attribute("key", "value"));
		e.appendChild(new Element("b", l, false));
		e.appendChild(new Element("c", l, true));
		xw.element(e);

		newReader();
		xr.document();
		xr.Misc(null);
		assertEquals("Read everything in document", xr.hasMoreData(), false);
	}

	public void testCDSection()
		throws Exception
	{
		newWriter();
		String sect = "<>!>&amp;d '' \"[[ ] ";
		xw.writeCDSection(sect);

		newReader();
		StringWriter out = new StringWriter();
		assertEquals("Read CDSect", xr.CDSect(out), true);
		assertEquals("Content match", out.getBuffer().toString(), sect);
	}

	public void testCData()
		throws Exception
	{
		newWriter();
		String sect = "abcabadababa";
		xw.writeCData(sect + "<");
		xw.close();

		newReader();
		StringWriter out = new StringWriter();
		xr.CharData(out);
		assertEquals("Content matches", out.getBuffer().toString(), sect);
	}

	public void testEmptyList() 
		throws Exception
	{
		newWriter();
		String attrs4[] = new String[] { "a", "&", "c", "'" };	
		newWriter();
		xw.emptyElement("baz", attrs4);
		xw.up(0);
		newReader();
		Document d = xr.document();
		Element e = d.getRootElement();
		assertEquals("got <baz/> ? ", e.getName(), "baz");
		assertTrue("closed", !e.isOpen());
		assertEquals("Read everything in document " + xr, false, xr.hasMoreData());
	}

	public void testBad() 
		throws Exception
	{
		newWriter();
		String attrs[] = new String[] { };	
		String attrs3[] = new String[] { "a", "b", "c" };	
		String attrs4[] = new String[] { "a", "&", "c", "'" };	
		xw.startElement("foo", attrs);
		try {
			xw.startElement("bar", attrs3);
			fail("bad bar, bad!");
		} catch (ArrayIndexOutOfBoundsException e) { }

		newWriter();
		xw.startElement("baz", attrs4);
		xw.up(0);
		newReader();
		Document d = xr.document();
		assertEquals("got <baz/> ? ", d.getRootElement().getName(), "baz");
		List l = d.getRootElement().getAttributes();
		assertEquals("2 attrs? ", 2, l.size());
		Attribute a;
		a = (Attribute)l.get(0);
		assertEquals("1st attr & ? ", "&", a.getValue());
		a = (Attribute)l.get(1);
		assertEquals("2nd attr ' ? ", "'", a.getValue());

		newWriter();
		try {
			xw.startElement("bar", null);
			fail("null, bad!");
		} catch (NullPointerException e) { }
	}

	public void testUp() 
		throws Exception
	{
		newWriter();
		for (int i = 0; i < 128; i++)
			xw.startElement("element-" + i);
		assertEquals("Depth of 128", 128, xw.getDepth());
		xw.up(64);
		assertEquals("Depth of 64", 64, xw.getDepth());
		xw.up(0);
		assertEquals("Depth of 0", 0, xw.getDepth());
		try {
			xw.endElement();
			fail("Should fail");
		} catch (NoSuchElementException e) {
		}
		newReader();
		xr.document();
		assertEquals("Read everything in document", true, xr.hasMoreData());
	}

}
