package wstxtest.wstream;

import java.io.*;

import javax.xml.stream.*;

public class TestRepairingNsOutput
    extends BaseWriterTest
{

    /*
    ////////////////////////////////////////////////////
    // Main test methods
    ////////////////////////////////////////////////////
     */

    public void testNoDummyDefaultNs()
        throws XMLStreamException
    {
        XMLOutputFactory f = getFactory();
        StringWriter strw = new StringWriter();
        XMLStreamWriter sw = f.createXMLStreamWriter(strw);

        sw.writeStartDocument();
        sw.writeStartElement("", "root", "");
        sw.writeAttribute("attr", "value");
        sw.writeAttribute("", "", "attr2", "value2");
        sw.writeStartElement("", "leaf", "");
        sw.writeAttribute("", "", "foop", "value2");
        sw.writeCharacters("Sub-text\n");
        sw.writeEndElement();
        sw.writeEndDocument();
        sw.close();

        String result = strw.toString();

        if (result.indexOf("xmlns=\"\"") > 0) {
            fail("Did not expect unnecessary default NS declarations, but found some in result: ["+result+"]");
        }
    }

    /**
     * Starting with Woodstox 3.1, the repairing writer is to honour
     * non-conflicting namespace write requests. This may be needed to
     * either try to preserve ns declaration canonicality, and/or to
     * minimize number of declarations (a common root can bind a namespace
     * for children, even without having to use it for its own attributes
     * or element name).
     *<p>
     * Since this functionality is not required (or even suggested from what
     * I can tell) by Stax 1.0 specs (and Stax2 does not change definitions
     * of core API), this is in woodstox-specific section of tests.
     */
    public void testExplicitNsWrites()
        throws XMLStreamException
    {
        final String URI = "http://bar";
        XMLOutputFactory f = getFactory();
        StringWriter strw = new StringWriter();
        XMLStreamWriter sw = f.createXMLStreamWriter(strw);

        sw.writeStartDocument();
        /* root in no namespace, no attributes; but want to add
         * an 'early' ns declaration for ns prefix 'foo',
         * with URI 'http://bar'
         */
        sw.writeStartElement("", "root");
        sw.writeNamespace("foo", URI);
        // leaf in that namespace, then:
        sw.writeStartElement(URI, "leaf");
        sw.writeEndElement();
        sw.writeEndElement();
        sw.writeEndDocument();
        sw.close();

        String result = strw.toString();

        // Ok, so let's parse and verify:
        XMLStreamReader sr = constructNsStreamReader(result, false);
        assertTokenType(START_ELEMENT, sr.next());
        assertEquals("root", sr.getLocalName());
        // !!! TODO: if/when 'no namespace' URI changes to "", need to fix
        assertNull(sr.getNamespaceURI());
        
        int nsCount = sr.getNamespaceCount();
        assertEquals("Expected one (and only one) namespace declaration, got "+nsCount, 1, nsCount);
        assertEquals("foo", sr.getNamespacePrefix(0));
        assertEquals(URI, sr.getNamespaceURI(0));
        
        // And then the branch should have no ns decls:
        assertTokenType(START_ELEMENT, sr.next());
        assertEquals("leaf", sr.getLocalName());
        assertEquals(URI, sr.getNamespaceURI());
        
        assertEquals(0, sr.getNamespaceCount());
        
        assertTokenType(END_ELEMENT, sr.next());
        assertEquals("leaf", sr.getLocalName());
        
        // fine, rest is ok
        sr.close();
    }

    /**
     * Similar to {@link #testExplicitNsWrites}, but tests behavior
     * of calls to <code>XMLStreamWriter.writeDefaultNamespace</code>
     */
    public void testExplicitDefaultNsWrite()
        throws XMLStreamException
    {
        final String URI1 = "http://foo";
        final String URI2 = "http://bar";
        XMLOutputFactory f = getFactory();
        StringWriter strw = new StringWriter();
        XMLStreamWriter sw = f.createXMLStreamWriter(strw);

        sw.writeStartDocument();
        /* root in explicit namespace, but additionally want to
         * reserve the default ns:
         */
        sw.writeStartElement("myns", "root", URI1);
        sw.writeDefaultNamespace(URI2);
        // leaf in that namespace, then:
        sw.writeStartElement(URI2, "leaf");
        sw.writeEndElement();
        sw.writeEndElement();
        sw.writeEndDocument();
        sw.close();

        String result = strw.toString();

        // Ok, so let's parse and verify:
        XMLStreamReader sr = constructNsStreamReader(result, false);
        assertTokenType(START_ELEMENT, sr.next());
        assertEquals("root", sr.getLocalName());
        assertEquals("myns", sr.getPrefix());
        assertEquals(URI1, sr.getNamespaceURI());
        
        int nsCount = sr.getNamespaceCount();
        assertEquals("Expected two namespace declarations, got "+nsCount, 2, nsCount);
        
        // And then leaf should have no ns decls:
        assertTokenType(START_ELEMENT, sr.next());
        assertEquals("leaf", sr.getLocalName());
        assertNull(sr.getPrefix());
        assertEquals(URI2, sr.getNamespaceURI());
        assertEquals(0, sr.getNamespaceCount());
        
        assertTokenType(END_ELEMENT, sr.next());
        assertEquals("leaf", sr.getLocalName());
        
        // fine, rest is ok
        sr.close();
    }

    /**
     * This test further verifies that caller's prefix-preference
     * has higher priority than that of trying to find an existing
     * prefix to use.
     */
    public void testExplicitDupNsWrite()
        throws XMLStreamException
    {
        final String URI = "http://bar";
        XMLOutputFactory f = getFactory();
        StringWriter strw = new StringWriter();
        XMLStreamWriter sw = f.createXMLStreamWriter(strw);

        sw.writeStartDocument();
        sw.writeStartElement("ns", "root", URI);
        sw.writeAttribute("attrns", URI, "attr", "value");

        sw.writeEndElement();
        sw.writeEndDocument();
        sw.close();

        String result = strw.toString();

        // Ok, so let's parse and verify:
        XMLStreamReader sr = constructNsStreamReader(result, false);
        assertTokenType(START_ELEMENT, sr.next());
        assertEquals("root", sr.getLocalName());
	assertEquals(URI, sr.getNamespaceURI());
	assertEquals(1, sr.getAttributeCount());
        assertEquals("attr", sr.getAttributeLocalName(0));
	assertEquals(URI, sr.getAttributeNamespace(0));
	// so far so good: but let's verify prefix is also what caller specified
	assertEquals("attrns", sr.getAttributePrefix(0));

	assertEquals(2, sr.getNamespaceCount());

        // fine, rest is ok
        sr.close();
    }

    /*
    ////////////////////////////////////////////////////
    // Internal methods
    ////////////////////////////////////////////////////
     */

    private XMLOutputFactory getFactory()
        throws XMLStreamException
    {
        XMLOutputFactory f = getOutputFactory();
        setNamespaceAware(f, true);
        setRepairing(f, true);
        return f;
    }

}

