TestClosing.java
package stax2.stream;
import java.io.*;
import javax.xml.stream.*;
import javax.xml.transform.stream.StreamSource;
import org.codehaus.stax2.*;
import org.codehaus.stax2.io.Stax2StringSource;
import stax2.BaseStax2Test;
/**
* This unit test suite verifies that the auto-closing feature works
* as expected (both explicitly, and via Source object being passed).
*
* @author Tatu Saloranta
*
* @since 3.0
*/
@SuppressWarnings("resource")
public class TestClosing
extends BaseStax2Test
{
/**
* This unit test checks the default behaviour; with no auto-close, no
* automatic closing should occur, nor explicit one unless specific
* forcing method is used.
*/
public void testNoAutoCloseReader()
throws XMLStreamException
{
final String XML = "<root>...</root>";
XMLInputFactory2 f = getFactory(false);
MyReader input = new MyReader(XML);
XMLStreamReader2 sr = (XMLStreamReader2) f.createXMLStreamReader(input);
// shouldn't be closed to begin with...
assertFalse(input.isClosed());
assertTokenType(START_ELEMENT, sr.next());
assertFalse(input.isClosed());
// nor closed half-way through with basic close()
sr.close();
assertFalse(input.isClosed());
// ok, let's finish it up:
streamThrough(sr);
// still not closed
assertFalse(input.isClosed());
// except when forced to:
sr.closeCompletely();
assertTrue(input.isClosed());
// ... and should be ok to call it multiple times:
sr.closeCompletely();
sr.closeCompletely();
assertTrue(input.isClosed());
}
public void testNoAutoCloseStream()
throws XMLStreamException, IOException
{
final String XML = "<root>...</root>";
XMLInputFactory2 f = getFactory(false);
MyStream input = new MyStream(XML.getBytes("UTF-8"));
XMLStreamReader2 sr = (XMLStreamReader2) f.createXMLStreamReader(input);
// shouldn't be closed to begin with...
assertFalse(input.isClosed());
assertTokenType(START_ELEMENT, sr.next());
assertFalse(input.isClosed());
// nor closed half-way through with basic close()
sr.close();
assertFalse(input.isClosed());
// ok, let's finish it up:
streamThrough(sr);
// still not closed
assertFalse(input.isClosed());
// except when forced to:
sr.closeCompletely();
assertTrue(input.isClosed());
// ... and should be ok to call it multiple times:
sr.closeCompletely();
assertTrue(input.isClosed());
}
/**
* This unit test checks that when auto-closing option is set, the
* passed in input stream does get properly closed both when EOF
* is hit, and when we call close() prior to EOF.
*/
public void testAutoCloseEnabled()
throws XMLStreamException
{
final String XML = "<root>...</root>";
// First, explicit close:
XMLInputFactory2 f = getFactory(true);
MyReader input = new MyReader(XML);
XMLStreamReader2 sr = (XMLStreamReader2) f.createXMLStreamReader(input);
assertFalse(input.isClosed());
assertTokenType(START_ELEMENT, sr.next());
assertFalse(input.isClosed());
sr.close();
assertTrue(input.isClosed());
// also, let's verify we can call more than once:
sr.close();
sr.close();
assertTrue(input.isClosed());
// Then implicit close (real auto-close):
input = new MyReader(XML);
sr = (XMLStreamReader2) f.createXMLStreamReader(input);
assertFalse(input.isClosed());
streamThrough(sr);
assertTrue(input.isClosed());
// And then similarly for Source abstraction for streams
MySource src = MySource.createFor(XML);
sr = (XMLStreamReader2) f.createXMLStreamReader(src);
assertFalse(src.isClosed());
assertTokenType(START_ELEMENT, sr.next());
streamThrough(sr);
assertTrue(input.isClosed());
}
/**
* This unit test checks what happens when we use Result abstraction
* for passing in result stream/writer. Their handling differs depending
* on whether caller is considered to have access to the underlying
* physical object or not.
*/
public void testAutoCloseImplicit()
throws XMLStreamException
{
final String XML = "<root>...</root>";
// Factory with auto-close disabled:
XMLInputFactory2 f = getFactory(false);
/* Ok, first: with regular (InputStream, Reader) streams no auto-closing
* because caller does have access: StreamSource retains given
* stream/reader as is.
*/
MySource input = MySource.createFor(XML);
XMLStreamReader2 sr = (XMLStreamReader2) f.createXMLStreamReader(input);
assertFalse(input.isClosed());
assertTokenType(START_ELEMENT, sr.next());
assertFalse(input.isClosed());
sr.close();
assertFalse(input.isClosed());
// also, let's verify we can call more than once:
sr.close();
sr.close();
assertFalse(input.isClosed());
/* And then more interesting case; verifying that Stax2Source
* sub-classes are implicitly auto-closed: they need to be, because
* they do not (necessarily) expose underlying physical stream.
* We can test this by using any Stax2Source impl.
*/
MyStringSource src = new MyStringSource(XML);
sr = (XMLStreamReader2) f.createXMLStreamReader(src);
assertFalse(src.isClosed());
assertTokenType(START_ELEMENT, sr.next());
assertFalse(src.isClosed());
streamThrough(sr);
assertTrue(src.isClosed());
// similarly, let's verify plain old close would do it
src = new MyStringSource(XML);
sr = (XMLStreamReader2) f.createXMLStreamReader(src);
assertFalse(src.isClosed());
assertTokenType(START_ELEMENT, sr.next());
assertFalse(src.isClosed());
sr.close();
assertTrue(src.isClosed());
}
/*
////////////////////////////////////////
// Non-test methods
////////////////////////////////////////
*/
XMLInputFactory2 getFactory(boolean autoClose)
{
XMLInputFactory2 f = getInputFactory();
f.setProperty(XMLInputFactory2.P_AUTO_CLOSE_INPUT, autoClose);
return f;
}
/*
////////////////////////////////////////
// Helper mock classes
////////////////////////////////////////
*/
final static class MyReader extends StringReader
{
boolean mIsClosed = false;
public MyReader(String contents) {
super(contents);
}
@Override
public void close() {
mIsClosed = true;
super.close();
}
public boolean isClosed() { return mIsClosed; }
}
final static class MyStream extends ByteArrayInputStream
{
boolean mIsClosed = false;
public MyStream(byte[] data) {
super(data);
}
@Override
public void close() throws IOException {
mIsClosed = true;
super.close();
}
public boolean isClosed() { return mIsClosed; }
}
final static class MySource
extends StreamSource
{
final MyReader mReader;
private MySource(MyReader reader) {
super(reader);
mReader = reader;
}
@SuppressWarnings("resource")
public static MySource createFor(String content) {
MyReader r = new MyReader(content);
return new MySource(r);
}
public boolean isClosed() {
return mReader.isClosed();
}
@Override
public Reader getReader() {
return mReader;
}
}
private final static class MyStringSource
extends Stax2StringSource
{
MyReader mReader;
public MyStringSource(String s) { super(s); }
@Override
public Reader constructReader() {
mReader = new MyReader(getText());
return mReader;
}
public boolean isClosed() { return mReader.isClosed(); }
}
}