W3CSchemaNillable179Test.java
package failing;
// ^^^ Move under "wstxtest/msv" once passing
import java.io.StringReader;
import java.io.StringWriter;
import org.codehaus.stax2.*;
import org.codehaus.stax2.validation.*;
import wstxtest.vstream.BaseValidationTest;
/**
* Test whether nillable elements are handled correctly by both reader and writer.
* A reproducer for <a href="https://github.com/FasterXML/woodstox/issues/179">https://github.com/FasterXML/woodstox/issues/179</a>.
*/
public class W3CSchemaNillable179Test
extends BaseValidationTest
{
private static final String SCHEMA =
"<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"\n"
+ " xmlns=\"http://server.hw.demo/nillable\"\n"
+ " targetNamespace=\"http://server.hw.demo/nillable\"\n"
+ " elementFormDefault=\"qualified\" attributeFormDefault=\"qualified\">\n"
+ " <xs:element name=\"nillableParent\">\n"
+ " <xs:complexType>\n"
+ " <xs:sequence>\n"
+ " <xs:element name=\"nillableDateTime\" type=\"xs:dateTime\" nillable=\"true\" minOccurs=\"0\"/>\n"
+ " <xs:element name=\"nillableInt\" type=\"xs:int\" nillable=\"true\" minOccurs=\"0\"/>\n"
+ " <xs:element name=\"nillableString\" type=\"xs:string\" nillable=\"true\" minOccurs=\"0\"/>\n"
+ " </xs:sequence>\n"
+ " </xs:complexType>\n"
+ " </xs:element>\n"
+ "</xs:schema>";
// for [woodstox-core#179]
public void testNillableDateTime() throws Exception
{
final String xmlDocument =
"<nl:nillableParent xmlns:nl=\"http://server.hw.demo/nillable\">\n"
+ " <nl:nillableDateTime xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:nil=\"true\"/>\n"
+ "</nl:nillableParent>";
testNillable(xmlDocument, true, true);
// The same document without xsi:nil="true" must fail for both reader and writer validation
try {
testNillable(xmlDocument.replace(" xsi:nil=\"true\"", ""), true, false);
fail("Expected a LocalValidationError");
} catch (LocalValidationError expected) {
assertEquals("Unknown reason (at end element </nl:nillableDateTime>)", expected.problem.getMessage());
}
try{
testNillable(xmlDocument.replace(" xsi:nil=\"true\"", ""), false, true);
fail("Expected a LocalValidationError");
} catch (LocalValidationError expected) {
assertEquals("Unknown reason (at end element </nl:nillableDateTime>)", expected.problem.getMessage());
}
}
// for [woodstox-core#179]
public void testNillableInt() throws Exception
{
final String xmlDocument =
"<nl:nillableParent xmlns:nl=\"http://server.hw.demo/nillable\">\n"
+ " <nl:nillableInt xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:nil=\"true\"/>\n"
+ "</nl:nillableParent>";
testNillable(xmlDocument, true, true);
// The same document without xsi:nil="true" must fail for both reader and writer validation
try {
testNillable(xmlDocument.replace(" xsi:nil=\"true\"", ""), true, false);
fail("Expected a LocalValidationError");
} catch (LocalValidationError expected) {
assertEquals("Unknown reason (at end element </nl:nillableInt>)", expected.problem.getMessage());
}
try{
testNillable(xmlDocument.replace(" xsi:nil=\"true\"", ""), false, true);
fail("Expected a LocalValidationError");
} catch (LocalValidationError expected) {
assertEquals("Unknown reason (at end element </nl:nillableInt>)", expected.problem.getMessage());
}
}
// for [woodstox-core#179]
public void testNillableString() throws Exception
{
final String xmlDocument =
"<nl:nillableParent xmlns:nl=\"http://server.hw.demo/nillable\">\n"
+ " <nl:nillableString xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:nil=\"true\"/>\n"
+ "</nl:nillableParent>";
testNillable(xmlDocument, true, true);
// Empty strings are legal
testNillable(xmlDocument.replace(" xsi:nil=\"true\"", ""), true, false);
testNillable(xmlDocument.replace(" xsi:nil=\"true\"", ""), false, true);
}
void testNillable(String xmlDocument, boolean validateReader, boolean validateWriter) throws Exception
{
StringWriter writer = new StringWriter();
XMLStreamReader2 xmlReader = null;
XMLStreamWriter2 xmlWriter = null;
try {
XMLValidationSchemaFactory schF = XMLValidationSchemaFactory.newInstance(XMLValidationSchema.SCHEMA_ID_W3C_SCHEMA);
XMLValidationSchema schema = schF.createSchema(new StringReader(SCHEMA));
XMLInputFactory2 f = getInputFactory();
setValidating(f, validateReader);
xmlReader = (XMLStreamReader2) f.createXMLStreamReader(new StringReader(xmlDocument));
if (validateReader) {
xmlReader.setValidationProblemHandler(problem -> {
throw new LocalValidationError(problem);
});
xmlReader.validateAgainst(schema);
}
xmlWriter = (XMLStreamWriter2) getOutputFactory().createXMLStreamWriter(writer);
if (validateWriter) {
xmlWriter.setValidationProblemHandler(problem -> {
throw new LocalValidationError(problem);
});
xmlWriter.validateAgainst(schema);
}
xmlWriter.copyEventFromReader(xmlReader, false);
while (xmlReader.hasNext()) {
xmlReader.next();
xmlWriter.copyEventFromReader(xmlReader, false);
}
} finally {
if (xmlReader != null) {
xmlReader.close();
}
if (xmlWriter != null) {
xmlWriter.close();
}
}
assertEquals(xmlDocument, writer.toString());
}
/*
///////////////////////////////////////////////////////////////////////
// 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;
}
@Override
public String toString() {
return problem.getMessage();
}
}
}