// Path: src/main/java/nl/ulso/sprox/XmlProcessor.java
// public interface XmlProcessor<T> {
// 
//     /**
//      * Process XML by pulling it from a reader. The reader is not closed. If buffering is needed, this must be
//      * provided by the caller.
//      *
//      * @param reader The reader to pull the XML from.
//      * @return The result of processing the XML; is {@code null} only if {@code T} is {@link java.lang.Void}.
//      * @throws XmlProcessorException If an error occurred while processing the XML
//      */
//     T execute(Reader reader) throws XmlProcessorException;
// 
//     /**
//      * Process XML by pulling it from an input stream. The input stream is not closed. If buffering is needed, this
//      * must be provided by the caller.
//      *
//      * @param inputStream The stream to pull the XML from.
//      * @return The result of processing the XML; is {@code null} only if {@code T} is {@link java.lang.Void}.
//      * @throws XmlProcessorException If an error occurred while processing the XML
//      */
//     T execute(InputStream inputStream) throws XmlProcessorException;
// }
// 
// Path: src/test/java/nl/ulso/sprox/SproxTests.java
// public static <T> XmlProcessorBuilder<T> createXmlProcessorBuilder(Class<T> resultClass) {
//     return new StaxBasedXmlProcessorBuilderFactory().createXmlProcessorBuilder(requireNonNull(resultClass));
// }


import nl.ulso.sprox.Attribute;
import nl.ulso.sprox.Node;
import nl.ulso.sprox.XmlProcessor;
import org.junit.Test;
import java.util.Optional;
import static nl.ulso.sprox.SproxTests.createXmlProcessorBuilder;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
        final String id = processor.execute(getClass().getResourceAsStream("/movies.xml"));
        assertThat(id, is("tt0111161"));
    }

    @Test
    public void testCountAllByInvalidRequiredAttribute() throws Exception {
        final MovieCounterByInvalidRequiredAttribute counter = new MovieCounterByInvalidRequiredAttribute();
        final XmlProcessor<Void> processor = createXmlProcessorBuilder(Void.class)
                .addControllerObject(counter)
                .buildXmlProcessor();
        processor.execute(getClass().getResourceAsStream("/movies.xml"));
        assertThat(counter.count, is(0));
    }

    @Test
    public void testCountAllByInvalidOptionalAttribute() throws Exception {
        final MovieCounterByInvalidOptionalAttribute counter = new MovieCounterByInvalidOptionalAttribute();
        final XmlProcessor<Void> processor = createXmlProcessorBuilder(Void.class)
                .addControllerObject(counter)
                .buildXmlProcessor();
        processor.execute(getClass().getResourceAsStream("/movies.xml"));
        assertThat(counter.count, is(5));
    }

    public static final class MovieIdFinder {
        private boolean first = true;

        @Node("movie")
        public String findFirstMovie(@Attribute("id") String id) {
            if (first) {
// Path: src/main/java/nl/ulso/sprox/XmlProcessor.java
// public interface XmlProcessor<T> {
// 
//     /**
//      * Process XML by pulling it from a reader. The reader is not closed. If buffering is needed, this must be
//      * provided by the caller.
//      *
//      * @param reader The reader to pull the XML from.
//      * @return The result of processing the XML; is {@code null} only if {@code T} is {@link java.lang.Void}.
//      * @throws XmlProcessorException If an error occurred while processing the XML
//      */
//     T execute(Reader reader) throws XmlProcessorException;
// 
//     /**
//      * Process XML by pulling it from an input stream. The input stream is not closed. If buffering is needed, this
//      * must be provided by the caller.
//      *
//      * @param inputStream The stream to pull the XML from.
//      * @return The result of processing the XML; is {@code null} only if {@code T} is {@link java.lang.Void}.
//      * @throws XmlProcessorException If an error occurred while processing the XML
//      */
//     T execute(InputStream inputStream) throws XmlProcessorException;
// }
// 
// Path: src/test/java/nl/ulso/sprox/SproxTests.java
// public static <T> XmlProcessorBuilder<T> createXmlProcessorBuilder(Class<T> resultClass) {
//     return new StaxBasedXmlProcessorBuilderFactory().createXmlProcessorBuilder(requireNonNull(resultClass));
// }


// Path: src/test/java/nl/ulso/sprox/movies/MovieIdFinderTest.java
import nl.ulso.sprox.Attribute;
import nl.ulso.sprox.Node;
import nl.ulso.sprox.XmlProcessor;
import org.junit.Test;
import java.util.Optional;
import static nl.ulso.sprox.SproxTests.createXmlProcessorBuilder;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

        final String id = processor.execute(getClass().getResourceAsStream("/movies.xml"));
        assertThat(id, is("tt0111161"));
    }

    @Test
    public void testCountAllByInvalidRequiredAttribute() throws Exception {
        final MovieCounterByInvalidRequiredAttribute counter = new MovieCounterByInvalidRequiredAttribute();
        final XmlProcessor<Void> processor = createXmlProcessorBuilder(Void.class)
                .addControllerObject(counter)
                .buildXmlProcessor();
        processor.execute(getClass().getResourceAsStream("/movies.xml"));
        assertThat(counter.count, is(0));
    }

    @Test
    public void testCountAllByInvalidOptionalAttribute() throws Exception {
        final MovieCounterByInvalidOptionalAttribute counter = new MovieCounterByInvalidOptionalAttribute();
        final XmlProcessor<Void> processor = createXmlProcessorBuilder(Void.class)
                .addControllerObject(counter)
                .buildXmlProcessor();
        processor.execute(getClass().getResourceAsStream("/movies.xml"));
        assertThat(counter.count, is(5));
    }

    public static final class MovieIdFinder {
        private boolean first = true;

        @Node("movie")
        public String findFirstMovie(@Attribute("id") String id) {
            if (first) {
                first = false;