diff --git a/src/test/java/wstxtest/msv/TestW3CSchemaNillable.java b/src/test/java/wstxtest/msv/TestW3CSchemaNillable.java new file mode 100644 index 00000000..7df252f2 --- /dev/null +++ b/src/test/java/wstxtest/msv/TestW3CSchemaNillable.java @@ -0,0 +1,156 @@ +package wstxtest.msv; + +import java.io.IOException; +import java.io.InputStream; +import java.io.StringWriter; + +import javax.xml.XMLConstants; +import javax.xml.stream.*; +import javax.xml.transform.Source; +import javax.xml.transform.stream.StreamSource; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; +import javax.xml.validation.Validator; + +import org.codehaus.stax2.*; +import org.codehaus.stax2.validation.*; +import org.xml.sax.SAXException; + +import wstxtest.vstream.BaseValidationTest; + +/** + * Test whether MSV validator behaves the same w.r.t. nillable elements as javax.xml.validation validator. + * A reproducer for https://github.com/FasterXML/woodstox/issues/179. + */ +public class TestW3CSchemaNillable + extends BaseValidationTest +{ + + public void testNillableDateTime() throws XMLStreamException, IOException, SAXException + { + testNillable("wstxtest/msv/nillableDateTime.xml"); + } + public void testNillableInt() throws XMLStreamException, IOException, SAXException + { + testNillable("wstxtest/msv/nillableInt.xml"); + } + public void testNillableString() throws XMLStreamException, IOException, SAXException + { + testNillable("wstxtest/msv/nillableString.xml"); + } + + void testNillable(String xmlResource) throws XMLStreamException, IOException, SAXException + { + boolean woodstoxPassed = true; + // Woodstox + final String xsdResource = "wstxtest/msv/nillable.xsd"; + { + XMLValidationSchemaFactory schF = XMLValidationSchemaFactory.newInstance(XMLValidationSchema.SCHEMA_ID_W3C_SCHEMA); + InputStream schemaInput = getClass().getClassLoader().getResourceAsStream(xsdResource); + InputStream xmlInput = getClass().getClassLoader().getResourceAsStream(xmlResource); + try { + XMLValidationSchema schema = schF.createSchema(schemaInput); + XMLInputFactory2 f = getInputFactory(); + setValidating(f, false); + + XMLStreamReader2 xmlReader = (XMLStreamReader2) f.createXMLStreamReader(xmlInput); + + /* the validation exception is only thrown from the writer + xmlReader.setValidationProblemHandler(new ValidationProblemHandler() { + @Override + public void reportProblem(XMLValidationProblem problem) + throws XMLValidationException { + throw new LocalValidationError(problem); + } + }); + xmlReader.validateAgainst(schema); + */ + + StringWriter writer = new StringWriter(); + XMLStreamWriter2 xmlWriter = (XMLStreamWriter2) getOutputFactory().createXMLStreamWriter(writer); + xmlWriter.setValidationProblemHandler(new ValidationProblemHandler() { + @Override + public void reportProblem(XMLValidationProblem problem) + throws XMLValidationException { + throw new LocalValidationError(problem); + } + }); + xmlWriter.validateAgainst(schema); + + try { + xmlWriter.copyEventFromReader(xmlReader, false); + while (xmlReader.hasNext()) { + xmlReader.next(); + xmlWriter.copyEventFromReader(xmlReader, false); + } + } catch (LocalValidationError e) { + e.printStackTrace(); + woodstoxPassed = false; + } + } finally { + if (xmlInput != null) { + xmlInput.close(); + } + if (schemaInput != null) { + schemaInput.close(); + } + } + } + + // javax.xml.validation + boolean javaxXmlValidationPassed = true; + { + InputStream schemaInput = getClass().getClassLoader().getResourceAsStream(xsdResource); + InputStream xmlInput = getClass().getClassLoader().getResourceAsStream(xmlResource); + SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); + try { + Source schemaFile = new StreamSource(schemaInput); + Schema schema = factory.newSchema(schemaFile); + Validator validator = schema.newValidator(); + try { + validator.validate(new StreamSource(xmlInput)); + } catch (SAXException e) { + javaxXmlValidationPassed = false; + e.printStackTrace(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } finally { + if (xmlInput != null) { + xmlInput.close(); + } + if (schemaInput != null) { + schemaInput.close(); + } + } + } + + if (woodstoxPassed != javaxXmlValidationPassed) { + fail("Woodstox MSV validator " + (woodstoxPassed ? "passed" : "did not pass") + + " but javax.xml.validation validator "+ (javaxXmlValidationPassed ? "passed" : "did not pass") + + " for " + xsdResource + " and "+ xmlResource); + } + + } + + /* + /////////////////////////////////////////////////////////////////////// + // Helper classes + /////////////////////////////////////////////////////////////////////// + */ + + public static class LocalValidationError extends RuntimeException + { + private static final long serialVersionUID = 1L; + + protected XMLValidationProblem problem; + + LocalValidationError(XMLValidationProblem problem) { + this.problem = problem; + } + + public XMLValidationProblem getProblem() { + return problem; + } + } +} diff --git a/src/test/resources/wstxtest/msv/nillable.xsd b/src/test/resources/wstxtest/msv/nillable.xsd new file mode 100644 index 00000000..1b21dd53 --- /dev/null +++ b/src/test/resources/wstxtest/msv/nillable.xsd @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/src/test/resources/wstxtest/msv/nillableDateTime.xml b/src/test/resources/wstxtest/msv/nillableDateTime.xml new file mode 100644 index 00000000..0bbefaa8 --- /dev/null +++ b/src/test/resources/wstxtest/msv/nillableDateTime.xml @@ -0,0 +1,3 @@ + + + diff --git a/src/test/resources/wstxtest/msv/nillableInt.xml b/src/test/resources/wstxtest/msv/nillableInt.xml new file mode 100644 index 00000000..f3f406a6 --- /dev/null +++ b/src/test/resources/wstxtest/msv/nillableInt.xml @@ -0,0 +1,3 @@ + + + diff --git a/src/test/resources/wstxtest/msv/nillableString.xml b/src/test/resources/wstxtest/msv/nillableString.xml new file mode 100644 index 00000000..a8e0de4d --- /dev/null +++ b/src/test/resources/wstxtest/msv/nillableString.xml @@ -0,0 +1,3 @@ + + +