/*
* Copyright 2008-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.item.xml.stax;
import java.util.NoSuchElementException;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.XMLEvent;
import junit.framework.TestCase;
import org.springframework.batch.item.xml.EventHelper;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
/**
* Tests for {@link DefaultFragmentEventReader}.
*
* @author Robert Kasanicky
*/
public class DefaultFragmentEventReaderTests extends TestCase {
// object under test
private FragmentEventReader fragmentReader;
// wrapped event fragmentReader
private XMLEventReader eventReader;
// test xml input
private String xml = "<root> <fragment> <misc1/> </fragment> <misc2/> <fragment> </fragment> </root>";
/**
* Setup the fragmentReader to read the test input.
*/
@Override
protected void setUp() throws Exception {
Resource input = new ByteArrayResource(xml.getBytes());
eventReader = XMLInputFactory.newInstance().createXMLEventReader(
input.getInputStream());
fragmentReader = new DefaultFragmentEventReader(eventReader);
}
/**
* Marked element should be wrapped with StartDocument and EndDocument
* events.
* Test uses redundant peek() calls before nextEvent() in important moments to assure
* peek() has no side effects on the inner state of reader.
*/
public void testFragmentWrapping() throws XMLStreamException {
assertTrue(fragmentReader.hasNext());
moveCursorBeforeFragmentStart();
fragmentReader.markStartFragment(); // mark the fragment
assertTrue(EventHelper.startElementName(eventReader.peek()).equals("fragment"));
// StartDocument inserted before StartElement
assertTrue(fragmentReader.peek().isStartDocument());
assertTrue(fragmentReader.nextEvent().isStartDocument());
// StartElement follows in the next step
assertTrue(EventHelper.startElementName(fragmentReader.nextEvent()).equals("fragment"));
moveCursorToNextElementEvent(); // misc1 start
fragmentReader.nextEvent(); // skip it
moveCursorToNextElementEvent(); // misc1 end
fragmentReader.nextEvent(); // skip it
moveCursorToNextElementEvent(); // move to end of fragment
// expected EndElement, peek first which should have no side effect
assertTrue(EventHelper.endElementName(fragmentReader.nextEvent()).equals("fragment"));
// inserted EndDocument
assertTrue(fragmentReader.peek().isEndDocument());
assertTrue(fragmentReader.nextEvent().isEndDocument());
// now the reader should behave like the document has finished
assertTrue(fragmentReader.peek() == null);
assertFalse(fragmentReader.hasNext());
try{
fragmentReader.nextEvent();
fail("nextEvent should simulate behavior as if document ended");
}
catch (NoSuchElementException expected) {
//expected
}
}
/**
* When fragment is marked as processed the cursor is moved after the end of
* the fragment.
*/
public void testMarkFragmentProcessed() throws XMLStreamException {
moveCursorBeforeFragmentStart();
fragmentReader.markStartFragment(); // mark the fragment start
// read only one event to move inside the fragment
XMLEvent startFragment = fragmentReader.nextEvent();
assertTrue(startFragment.isStartDocument());
fragmentReader.markFragmentProcessed(); // mark fragment as processed
fragmentReader.nextEvent(); // skip whitespace
// the next element after fragment end is <misc2/>
XMLEvent misc2 = fragmentReader.nextEvent();
assertTrue(EventHelper.startElementName(misc2).equals("misc2"));
}
/**
* Cursor is moved to the end of the fragment as usually even
* if nothing was read from the event reader after beginning
* of fragment was marked.
*/
public void testMarkFragmentProcessedImmediatelyAfterMarkFragmentStart() throws Exception {
moveCursorBeforeFragmentStart();
fragmentReader.markStartFragment();
fragmentReader.markFragmentProcessed();
fragmentReader.nextEvent(); // skip whitespace
// the next element after fragment end is <misc2/>
XMLEvent misc2 = fragmentReader.nextEvent();
assertTrue(EventHelper.startElementName(misc2).equals("misc2"));
}
private void moveCursorToNextElementEvent() throws XMLStreamException {
XMLEvent event = eventReader.peek();
while (!event.isStartElement() && !event.isEndElement()) {
eventReader.nextEvent();
event = eventReader.peek();
}
}
private void moveCursorBeforeFragmentStart() throws XMLStreamException {
XMLEvent event = eventReader.peek();
while (!event.isStartElement() || !EventHelper.startElementName(event).equals("fragment")) {
eventReader.nextEvent();
event = eventReader.peek();
}
}
}