From 88f3b36a57233d5ebc91fd98d7c43a287c6b701c Mon Sep 17 00:00:00 2001 From: Peter Palaga Date: Sat, 13 Jan 2024 15:03:18 +0100 Subject: [PATCH] Extend XMLStreamWriter validation test coverage by checking the writer validation wherever we test the reader validation --- .../com/ctc/wstx/sw/SimpleOutputElement.java | 6 +- src/test/java/stax2/BaseStax2Test.java | 52 +++- src/test/java/wstxtest/BaseWstxTest.java | 32 -- src/test/java/wstxtest/msv/TestW3CSchema.java | 104 +++++-- .../java/wstxtest/msv/TestW3CSchemaTypes.java | 13 +- .../wstxtest/vstream/BaseValidationTest.java | 70 ++++- src/test/java/wstxtest/vstream/TestDTD.java | 40 +-- .../TestDTDErrorCollection104Test.java | 148 +++++---- .../vstream/TestInvalidAttributeValue.java | 21 +- .../java/wstxtest/vstream/TestRelaxNG.java | 284 +++++++++--------- .../vstream/TestW3CSchemaComplexTypes.java | 49 ++- 11 files changed, 500 insertions(+), 319 deletions(-) diff --git a/src/main/java/com/ctc/wstx/sw/SimpleOutputElement.java b/src/main/java/com/ctc/wstx/sw/SimpleOutputElement.java index bdf6c715..596025a4 100644 --- a/src/main/java/com/ctc/wstx/sw/SimpleOutputElement.java +++ b/src/main/java/com/ctc/wstx/sw/SimpleOutputElement.java @@ -246,7 +246,11 @@ public String getNamespaceURI() { } public QName getName() { - return QNameCreator.create(mURI, mLocalName, mPrefix); + if (mPrefix != null) { + return QNameCreator.create(mURI, mLocalName, mPrefix); + } else { + return new QName(mURI, mLocalName); + } } /* diff --git a/src/test/java/stax2/BaseStax2Test.java b/src/test/java/stax2/BaseStax2Test.java index 767d14a7..526764d8 100644 --- a/src/test/java/stax2/BaseStax2Test.java +++ b/src/test/java/stax2/BaseStax2Test.java @@ -1,7 +1,9 @@ package stax2; import java.io.*; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import junit.framework.TestCase; @@ -12,6 +14,12 @@ import org.codehaus.stax2.evt.*; import org.codehaus.stax2.ri.Stax2ReaderAdapter; +import org.codehaus.stax2.validation.ValidationProblemHandler; +import org.codehaus.stax2.validation.XMLValidationException; +import org.codehaus.stax2.validation.XMLValidationProblem; +import org.codehaus.stax2.validation.XMLValidationSchema; + +import com.ctc.wstx.stax.WstxOutputFactory; /** * Base unit test class to be inherited by all unit tests that test @@ -186,6 +194,14 @@ protected XMLStreamReader2 constructNonNsStreamReader(String content, boolean co return (XMLStreamReader2) f.createXMLStreamReader(new StringReader(content)); } + protected static XMLStreamWriter2 constructStreamWriter(Writer writer, boolean nsSupported, boolean repairing) throws XMLStreamException { + WstxOutputFactory f = new WstxOutputFactory(); + f.getConfig().doSupportNamespaces(nsSupported); + f.getConfig().enableAutomaticNamespaces(repairing); + return (XMLStreamWriter2) f.createXMLStreamWriter(writer); + } + + /** * Method to force constructing a wrapper for given stream reader. * Have to use this method to work around natural resistance by @@ -328,7 +344,7 @@ protected static boolean isNamespaceAware(XMLOutputFactory f) * @return Dummy value calculated on contents; used to make sure * no dead code is eliminated */ - protected int streamThrough(XMLStreamReader sr) + protected static int streamThrough(XMLStreamReader sr) throws XMLStreamException { int result = 0; @@ -578,6 +594,40 @@ protected void verifyException(Throwable e, String match) } } + protected static void validateWriter(final String DOC, final List probs, XMLInputFactory f, + XMLValidationSchema schema, StringWriter writer, XMLStreamWriter2 sw) throws XMLStreamException { + sw.validateAgainst(schema); + final List writerProbs = new ArrayList(); + sw.setValidationProblemHandler(new ValidationProblemHandler() { + + @Override + public void reportProblem(XMLValidationProblem problem) throws XMLValidationException { + writerProbs.add(problem); + } + }); + + XMLStreamReader2 sr = (XMLStreamReader2)f.createXMLStreamReader( + new StringReader(DOC)); + + sw.copyEventFromReader(sr, false); + while (sr.hasNext()) { + /* int type = */sr.next(); + sw.copyEventFromReader(sr, false); + } + sr.close(); + sw.close(); + assertEquals(DOC, writer.toString()); + + assertEquals(probs.size(), writerProbs.size()); + for (int i = 0; i < probs.size(); i++) { + XMLValidationProblem expected = probs.get(i); + XMLValidationProblem actual = writerProbs.get(i); + assertEquals(expected.getMessage(), actual.getMessage()); + assertEquals(expected.getSeverity(), actual.getSeverity()); + } + } + + /* /////////////////////////////////////////////////////////// // Debug/output helpers diff --git a/src/test/java/wstxtest/BaseWstxTest.java b/src/test/java/wstxtest/BaseWstxTest.java index 8bcb5966..0361333e 100644 --- a/src/test/java/wstxtest/BaseWstxTest.java +++ b/src/test/java/wstxtest/BaseWstxTest.java @@ -234,38 +234,6 @@ protected static void setFixContent(XMLOutputFactory f, boolean state) ////////////////////////////////////////////////// */ - /** - * Method that will iterate through contents of an XML document - * using specified stream reader; will also access some of data - * to make sure reader reads most of lazy-loadable data. - * Method is usually called to try to get an exception for invalid - * content. - * - * @return Dummy value calculated on contents; used to make sure - * no dead code is eliminated - */ - @Override - protected int streamThrough(XMLStreamReader sr) - throws XMLStreamException - { - int result = 0; - - while (sr.hasNext()) { - int type = sr.next(); - result += type; - if (sr.hasText()) { - // will also do basic verification for text content, to - // see that all text accessor methods return same content - result += getAndVerifyText(sr).hashCode(); - } - if (sr.hasName()) { - result += sr.getName().hashCode(); - } - } - - return result; - } - @Override protected int streamThroughFailing(XMLInputFactory f, String contents, String msg) diff --git a/src/test/java/wstxtest/msv/TestW3CSchema.java b/src/test/java/wstxtest/msv/TestW3CSchema.java index 1dc918df..45de8834 100644 --- a/src/test/java/wstxtest/msv/TestW3CSchema.java +++ b/src/test/java/wstxtest/msv/TestW3CSchema.java @@ -1,10 +1,17 @@ package wstxtest.msv; +import java.io.StringReader; +import java.io.StringWriter; +import java.io.Writer; + import javax.xml.stream.*; import org.codehaus.stax2.*; import org.codehaus.stax2.validation.*; +import com.ctc.wstx.stax.WstxInputFactory; +import com.ctc.wstx.stax.WstxOutputFactory; + import wstxtest.vstream.BaseValidationTest; /** @@ -78,10 +85,10 @@ public class TestW3CSchema final static String SIMPLE_XML = "" + "" + " " + "FamilyFred" + " " - + " " + " " + + " " + " " + " " + " BlowJoe" - + " " + " " + " " + ""; + + " " + " " + " " + ""; /** * Test validation against a simple document valid according to a very @@ -90,40 +97,59 @@ public class TestW3CSchema public void testSimpleNonNs() throws XMLStreamException { XMLValidationSchema schema = parseW3CSchema(SIMPLE_NON_NS_SCHEMA); - XMLStreamReader2 sr = getReader(SIMPLE_XML); + String XML = SIMPLE_XML; + XMLStreamReader2 sr = getReader(XML); sr.validateAgainst(schema); + StringWriter writer = new StringWriter(); + XMLStreamWriter2 sw = (XMLStreamWriter2) getOutputFactory().createXMLStreamWriter(writer); + sw.validateAgainst(schema); + sw.copyEventFromReader(sr, false); + try { assertTokenType(START_ELEMENT, sr.next()); assertEquals("personnel", sr.getLocalName()); + sw.copyEventFromReader(sr, false); while (sr.hasNext()) { /* int type = */sr.next(); + sw.copyEventFromReader(sr, false); } } catch (XMLValidationException vex) { fail("Did not expect validation exception, got: " + vex); } assertTokenType(END_DOCUMENT, sr.getEventType()); + assertEquals(XML.replace("'", "\""), writer.toString()); } public void testSimplePartialNonNs() throws XMLStreamException { XMLValidationSchema schema = parseW3CSchema(SIMPLE_NON_NS_SCHEMA); - XMLStreamReader2 sr = getReader(SIMPLE_XML); + String XML = SIMPLE_XML; + XMLStreamReader2 sr = getReader(XML); + StringWriter writer = new StringWriter(); + XMLStreamWriter2 sw = (XMLStreamWriter2) getOutputFactory().createXMLStreamWriter(writer); + sw.copyEventFromReader(sr, false); + assertTokenType(START_ELEMENT, sr.next()); assertEquals("personnel", sr.getLocalName()); + sw.copyEventFromReader(sr, false); sr.validateAgainst(schema); + sw.validateAgainst(schema); try { assertTokenType(START_ELEMENT, sr.next()); assertEquals("person", sr.getLocalName()); + sw.copyEventFromReader(sr, false); while (sr.hasNext()) { /* int type = */sr.next(); + sw.copyEventFromReader(sr, false); } } catch (XMLValidationException vex) { fail("Did not expect validation exception, got: " + vex); } assertTokenType(END_DOCUMENT, sr.getEventType()); + assertEquals(XML.replace("'", "\""), writer.toString()); } /** @@ -192,6 +218,18 @@ public void testSimpleDataTypes() throws XMLStreamException } sr.close(); + // validate the same document on the writer side + sr = getReader(XML); + StringWriter writer = new StringWriter(); + XMLStreamWriter2 sw = (XMLStreamWriter2) getOutputFactory().createXMLStreamWriter(writer); + sw.validateAgainst(schema); + sw.copyEventFromReader(sr, true); + while (sr.hasNext()) { + /* int type = */sr.next(); + sw.copyEventFromReader(sr, true); + } + assertEquals(XML.replace("\r", ""), writer.toString()); + // Then invalid (wrong type for value) XML = "34b1.00"; sr.validateAgainst(schema); @@ -224,33 +262,28 @@ public void testSimpleText() throws XMLStreamException + ""; XMLValidationSchema schema = parseW3CSchema(SCHEMA); - // First, 3 valid docs: - String XML = "xyz"; - XMLStreamReader2 sr = getReader(XML); - sr.validateAgainst(schema); - streamThrough(sr); - sr.close(); - - XML = ""; - sr = getReader(XML); - sr.validateAgainst(schema); - streamThrough(sr); - sr.close(); + String XML = null; + for (ValidationMode mode : ValidationMode.values()) { + // First, 3 valid docs: + XML = "xyz"; + mode.validate(schema, XML); + + XML = ""; + mode.validate(schema, XML, ""); + + XML = ""; + mode.validate(schema, XML, ""); + } - XML = ""; - sr = getReader(XML); - sr.validateAgainst(schema); - streamThrough(sr); - sr.close(); // Then invalid? XML = ""; - sr = getReader(XML); + XMLStreamReader2 sr = getReader(XML); sr.validateAgainst(schema); verifyFailure(XML, schema, "should warn about wrong root element", "tag name \"foobar\" is not allowed", false); } - + /** * Test for reproducing [WSTX-191] */ @@ -283,20 +316,24 @@ public void testConstrainedText() throws XMLStreamException ""); _testValidDesc(schema, "??"); - _testValidDesc(schema, ""); - _testValidDesc(schema, ""); + _testValidDesc(schema, "", ""); + _testValidDesc(schema, "", ""); _testValidDesc(schema, ""); } - private void _testValidDesc(XMLValidationSchema schema, String descSnippet) throws XMLStreamException + private void _testValidDesc(XMLValidationSchema schema, String descSnippet) throws XMLStreamException { + _testValidDesc(schema, descSnippet, descSnippet); + } + private void _testValidDesc(XMLValidationSchema schema, String descSnippet, String expectedSnippet) throws XMLStreamException { - // These should all be valid according to the schema - String XML = "" - + descSnippet + ""; - XMLStreamReader2 sr = getReader(XML); - sr.validateAgainst(schema); - streamThrough(sr); - sr.close(); + for (ValidationMode mode : ValidationMode.values()) { + // These should all be valid according to the schema + String XML = "" + + descSnippet + ""; + String expectedXML = "" + + expectedSnippet + ""; + mode.validate(schema, XML, expectedXML.replace("'", "\"")); + } } public void testValidationHandler() throws XMLStreamException @@ -361,4 +398,5 @@ public XMLValidationProblem getProblem() { return problem; } } + } diff --git a/src/test/java/wstxtest/msv/TestW3CSchemaTypes.java b/src/test/java/wstxtest/msv/TestW3CSchemaTypes.java index 3295b62d..d669de53 100644 --- a/src/test/java/wstxtest/msv/TestW3CSchemaTypes.java +++ b/src/test/java/wstxtest/msv/TestW3CSchemaTypes.java @@ -6,6 +6,7 @@ import org.codehaus.stax2.validation.*; import wstxtest.vstream.BaseValidationTest; +import wstxtest.vstream.BaseValidationTest.ValidationMode; import java.io.StringWriter; @@ -45,9 +46,9 @@ public class TestW3CSchemaTypes public void testSimpleValidInt() throws Exception { XMLValidationSchema schema = parseW3CSchema(SCHEMA_INT); - XMLStreamReader2 sr = getReader("129"); - sr.validateAgainst(schema); - streamThrough(sr); + for (ValidationMode mode : ValidationMode.values()) { + mode.validate(schema, "129"); + } } public void testSimpleInvalidInt() throws Exception @@ -62,9 +63,9 @@ public void testSimpleInvalidInt() throws Exception public void testSimpleValidFloat() throws Exception { XMLValidationSchema schema = parseW3CSchema(SCHEMA_FLOAT); - XMLStreamReader2 sr = getReader("1.00"); - sr.validateAgainst(schema); - streamThrough(sr); + for (ValidationMode mode : ValidationMode.values()) { + mode.validate(schema, "1.00"); + } } public void testSimpleInvalidFloat() throws Exception diff --git a/src/test/java/wstxtest/vstream/BaseValidationTest.java b/src/test/java/wstxtest/vstream/BaseValidationTest.java index b9d0c544..4bdf6492 100644 --- a/src/test/java/wstxtest/vstream/BaseValidationTest.java +++ b/src/test/java/wstxtest/vstream/BaseValidationTest.java @@ -1,13 +1,18 @@ package wstxtest.vstream; import java.io.StringReader; +import java.io.StringWriter; import java.net.URL; import javax.xml.stream.XMLStreamException; import org.codehaus.stax2.XMLStreamReader2; +import org.codehaus.stax2.XMLStreamWriter2; import org.codehaus.stax2.validation.*; +import com.ctc.wstx.stax.WstxInputFactory; +import com.ctc.wstx.stax.WstxOutputFactory; + public abstract class BaseValidationTest extends wstxtest.stream.BaseStreamTest { @@ -51,13 +56,32 @@ protected void verifyFailure(String xml, XMLValidationSchema schema, String fail } protected void verifyFailure(String xml, XMLValidationSchema schema, String failMsg, - String failPhrase, boolean strict) throws XMLStreamException + String failPhrase, boolean strict) throws XMLStreamException + { + verifyFailure(xml, schema, failMsg, failPhrase, strict, true, false); + verifyFailure(xml, schema, failMsg, failPhrase, strict, false, true); + } + + protected void verifyFailure(String xml, XMLValidationSchema schema, String failMsg, + String failPhrase, boolean strict, + boolean validateReader, boolean validateWriter) throws XMLStreamException { XMLStreamReader2 sr = constructStreamReader(getInputFactory(), xml); - sr.validateAgainst(schema); + if (validateReader) { + sr.validateAgainst(schema); + } + XMLStreamWriter2 sw = null; + if (validateWriter) { + sw = (XMLStreamWriter2) getOutputFactory().createXMLStreamWriter(new StringWriter()); + sw.validateAgainst(schema); + sw.copyEventFromReader(sr, false); + } try { while (sr.hasNext()) { /* int type = */sr.next(); + if (validateWriter) { + sw.copyEventFromReader(sr, false); + } } fail("Expected validity exception for " + failMsg); } catch (XMLValidationException vex) { @@ -79,4 +103,46 @@ protected void verifyFailure(String xml, XMLValidationSchema schema, String fail + "; instead got " + sex.getMessage()); } } + + public enum ValidationMode { + reader() { + @Override + public void validate(XMLValidationSchema schema, String XML, String expectedXML) throws XMLStreamException { + XMLStreamReader2 sr = (XMLStreamReader2) new WstxInputFactory().createXMLStreamReader(new StringReader(XML)); + sr.validateAgainst(schema); + streamThrough(sr); + assertTokenType(END_DOCUMENT, sr.getEventType()); + sr.close(); + } + + }, + writerNsSimple() { + + @Override + public void validate(XMLValidationSchema schema, String XML, String expectedXML) + throws XMLStreamException { + XMLStreamReader2 sr = (XMLStreamReader2) new WstxInputFactory().createXMLStreamReader(new StringReader(XML)); + + StringWriter writer = new StringWriter(); + WstxOutputFactory f = new WstxOutputFactory(); + f.getConfig().doSupportNamespaces(true); + f.getConfig().enableAutomaticNamespaces(false); + XMLStreamWriter2 sw = (XMLStreamWriter2) f.createXMLStreamWriter(writer); + sw.validateAgainst(schema); + sw.copyEventFromReader(sr, false); + while (sr.hasNext()) { + /* int type = */sr.next(); + sw.copyEventFromReader(sr, false); + } + assertTokenType(END_DOCUMENT, sr.getEventType()); + sr.close(); + sw.close(); + assertEquals(expectedXML, writer.toString()); + } + }; + public void validate(XMLValidationSchema schema, String XML) throws XMLStreamException { + validate(schema, XML, XML); + } + public abstract void validate(XMLValidationSchema schema, String XML, String expectedXML) throws XMLStreamException; + } } diff --git a/src/test/java/wstxtest/vstream/TestDTD.java b/src/test/java/wstxtest/vstream/TestDTD.java index b1d10ba3..2f96f7d5 100644 --- a/src/test/java/wstxtest/vstream/TestDTD.java +++ b/src/test/java/wstxtest/vstream/TestDTD.java @@ -57,10 +57,9 @@ public void testFullValidationOk() throws XMLStreamException { String XML = ""; XMLValidationSchema schema = parseDTDSchema(SIMPLE_DTD); - XMLStreamReader2 sr = getReader(XML); - sr.validateAgainst(schema); - while (sr.next() != END_DOCUMENT) { } - sr.close(); + for (ValidationMode mode : ValidationMode.values()) { + mode.validate(schema, XML, ""); + } } // [woodstox#23] @@ -70,7 +69,6 @@ public void testFullValidationIssue23() throws XMLStreamException +"\n" ; String XML = "foobar"; - XMLInputFactory f = getInputFactory(); /* Resolver resolver = new XMLResolver() { @@ -85,19 +83,9 @@ public Object resolveEntity(String publicID, String systemID, String baseURI, St XMLValidationSchemaFactory schemaFactory = XMLValidationSchemaFactory.newInstance(XMLValidationSchema.SCHEMA_ID_DTD); XMLValidationSchema schema = schemaFactory.createSchema(new StringReader(INPUT_DTD)); - XMLStreamReader2 sr = (XMLStreamReader2)f.createXMLStreamReader( - new StringReader(XML)); - - sr.validateAgainst(schema); - while (sr.next() != END_DOCUMENT) { - /* - System.err.println("Curr == "+sr.getEventType()); - if (sr.getEventType() == CHARACTERS) { - System.err.println(" text: "+sr.getText()); - } - */ + for (ValidationMode mode : ValidationMode.values()) { + mode.validate(schema, XML, "foobar"); } - sr.close(); } /** @@ -107,13 +95,11 @@ public Object resolveEntity(String publicID, String systemID, String baseURI, St public void testPartialValidationOk() throws XMLStreamException { - String XML = ""; + String XML = ""; XMLValidationSchema schema = parseDTDSchema(SIMPLE_DTD); - XMLStreamReader2 sr = getReader(XML); - assertTokenType(START_ELEMENT, sr.next()); - sr.validateAgainst(schema); - while (sr.next() != END_DOCUMENT) { } - sr.close(); + for (ValidationMode mode : ValidationMode.values()) { + mode.validate(schema, XML); + } } /* @@ -168,14 +154,6 @@ public void testSchemaWithFunnyFilename() ////////////////////////////////////////////////////// */ - private XMLStreamReader2 getReader(String contents) - throws XMLStreamException - { - XMLInputFactory f = getInputFactory(); - setValidating(f, false); - return constructStreamReader(f, contents); - } - private XMLStreamReader getValidatingReader(String contents, XMLReporter rep) throws XMLStreamException { diff --git a/src/test/java/wstxtest/vstream/TestDTDErrorCollection104Test.java b/src/test/java/wstxtest/vstream/TestDTDErrorCollection104Test.java index 739f42bf..0e0ce4fe 100644 --- a/src/test/java/wstxtest/vstream/TestDTDErrorCollection104Test.java +++ b/src/test/java/wstxtest/vstream/TestDTDErrorCollection104Test.java @@ -3,18 +3,27 @@ import stax2.BaseStax2Test; import java.io.StringReader; +import java.io.StringWriter; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; import javax.xml.stream.*; import org.codehaus.stax2.XMLStreamReader2; +import org.codehaus.stax2.XMLStreamWriter2; import org.codehaus.stax2.validation.ValidationProblemHandler; import org.codehaus.stax2.validation.XMLValidationException; import org.codehaus.stax2.validation.XMLValidationProblem; import org.codehaus.stax2.validation.XMLValidationSchema; import org.codehaus.stax2.validation.XMLValidationSchemaFactory; +import com.ctc.wstx.stax.WstxOutputFactory; +import com.ctc.wstx.sw.RepairingNsStreamWriter; +import com.ctc.wstx.sw.SimpleNsStreamWriter; + public class TestDTDErrorCollection104Test extends BaseStax2Test { @@ -26,78 +35,97 @@ public void testValidationBeyondUnknownElement() throws Exception " \n" + " \n" + " \n" + - "\n"; + ""; final String INPUT_DTD = "\n" +"\n" ; + final List probs = new ArrayList(); + XMLInputFactory f = getInputFactory(); setCoalescing(f, true); XMLValidationSchemaFactory schemaFactory = XMLValidationSchemaFactory.newInstance(XMLValidationSchema.SCHEMA_ID_DTD); XMLValidationSchema schema = schemaFactory.createSchema(new StringReader(INPUT_DTD)); - XMLStreamReader2 sr = (XMLStreamReader2)f.createXMLStreamReader( - new StringReader(DOC)); - - final List probs = new ArrayList(); - - sr.validateAgainst(schema); - sr.setValidationProblemHandler(new ValidationProblemHandler() { - @Override - public void reportProblem(XMLValidationProblem problem) - throws XMLValidationException { - probs.add(problem); - } - }); - - assertTokenType(START_ELEMENT, sr.next()); - assertEquals("map", sr.getLocalName()); - - sr.next(); // SPACE or CHARACTERS - assertTokenType(START_ELEMENT, sr.next()); - assertEquals("val", sr.getLocalName()); - assertEquals(1, probs.size()); - assertEquals("Undefined element encountered", - probs.get(0).getMessage()); - - sr.next(); // SPACE or CHARACTERS - assertEquals(1, probs.size()); - - // From this point on, however, behavior bit unclear except - // that for DTD I guess we can at least check for undefined - // cases.... + { + XMLStreamReader2 sr = (XMLStreamReader2)f.createXMLStreamReader( + new StringReader(DOC)); + + sr.validateAgainst(schema); + sr.setValidationProblemHandler(new ValidationProblemHandler() { + @Override + public void reportProblem(XMLValidationProblem problem) + throws XMLValidationException { + probs.add(problem); + } + }); + + assertTokenType(START_ELEMENT, sr.next()); + assertEquals("map", sr.getLocalName()); + + sr.next(); // SPACE or CHARACTERS + assertTokenType(START_ELEMENT, sr.next()); + assertEquals("val", sr.getLocalName()); + assertEquals(1, probs.size()); + assertEquals("Undefined element encountered", + probs.get(0).getMessage()); + + sr.next(); // SPACE or CHARACTERS + assertEquals(1, probs.size()); + + // From this point on, however, behavior bit unclear except + // that for DTD I guess we can at least check for undefined + // cases.... + + assertTokenType(START_ELEMENT, sr.next()); + assertEquals("prop", sr.getLocalName()); + // not defined either so: + assertEquals(2, probs.size()); + assertEquals("Undefined element encountered", + probs.get(1).getMessage()); + + assertTokenType(END_ELEMENT, sr.next()); + assertEquals("prop", sr.getLocalName()); + assertEquals(2, probs.size()); + + sr.next(); // SPACE or CHARACTERS + assertEquals(2, probs.size()); + assertTokenType(END_ELEMENT, sr.next()); + assertEquals("val", sr.getLocalName()); + assertEquals(2, probs.size()); + + sr.next(); // SPACE or CHARACTERS + assertTokenType(END_ELEMENT, sr.next()); + assertEquals("map", sr.getLocalName()); + assertEquals(3, probs.size()); + assertEquals("Validation error, element : Expected at least one element ", + probs.get(2).getMessage()); + + // Plus content model now missing (s) + assertTokenType(END_DOCUMENT, sr.next()); + assertEquals(3, probs.size()); + + sr.close(); + } - assertTokenType(START_ELEMENT, sr.next()); - assertEquals("prop", sr.getLocalName()); - // not defined either so: - assertEquals(2, probs.size()); - assertEquals("Undefined element encountered", - probs.get(1).getMessage()); - - assertTokenType(END_ELEMENT, sr.next()); - assertEquals("prop", sr.getLocalName()); - assertEquals(2, probs.size()); - - sr.next(); // SPACE or CHARACTERS - assertEquals(2, probs.size()); - assertTokenType(END_ELEMENT, sr.next()); - assertEquals("val", sr.getLocalName()); - assertEquals(2, probs.size()); - - sr.next(); // SPACE or CHARACTERS - assertTokenType(END_ELEMENT, sr.next()); - assertEquals("map", sr.getLocalName()); - assertEquals(3, probs.size()); - assertEquals("Validation error, element : Expected at least one element ", - probs.get(2).getMessage()); - - // Plus content model now missing (s) - assertTokenType(END_DOCUMENT, sr.next()); - assertEquals(3, probs.size()); - - sr.close(); + // now do the same on the writer side + // and make sure that the reported problems are the same + + { + // SimpleNsStreamWriter + StringWriter writer = new StringWriter(); + SimpleNsStreamWriter sw = (SimpleNsStreamWriter) stax2.BaseStax2Test.constructStreamWriter(writer, true, false); + validateWriter(DOC, probs, f, schema, writer, sw); + } + { + // RepairingNsStreamWriter + StringWriter writer = new StringWriter(); + RepairingNsStreamWriter sw = (RepairingNsStreamWriter) stax2.BaseStax2Test.constructStreamWriter(writer, true, true); + validateWriter(DOC, probs, f, schema, writer, sw); + } } + } diff --git a/src/test/java/wstxtest/vstream/TestInvalidAttributeValue.java b/src/test/java/wstxtest/vstream/TestInvalidAttributeValue.java index 06a9f812..4f89cc03 100644 --- a/src/test/java/wstxtest/vstream/TestInvalidAttributeValue.java +++ b/src/test/java/wstxtest/vstream/TestInvalidAttributeValue.java @@ -3,6 +3,7 @@ import stax2.BaseStax2Test; import java.io.StringReader; +import java.io.StringWriter; import java.util.ArrayList; import java.util.List; @@ -15,12 +16,15 @@ import org.codehaus.stax2.validation.XMLValidationSchema; import org.codehaus.stax2.validation.XMLValidationSchemaFactory; +import com.ctc.wstx.sw.RepairingNsStreamWriter; +import com.ctc.wstx.sw.SimpleNsStreamWriter; + public class TestInvalidAttributeValue extends BaseStax2Test { public void testInvalidAttributeValue() throws Exception { - final String DOC = "\n"; + final String DOC = ""; final String INPUT_DTD = "\n" @@ -57,5 +61,20 @@ public void reportProblem(XMLValidationProblem problem) assertEquals(1, probs.size()); assertEquals("Element has no attribute \"verbose\"", probs.get(0).getMessage()); + // now do the same on the writer side + // and make sure that the reported problems are the same + { + // SimpleNsStreamWriter + StringWriter writer = new StringWriter(); + SimpleNsStreamWriter sw = (SimpleNsStreamWriter) stax2.BaseStax2Test.constructStreamWriter(writer, true, false); + validateWriter(DOC, probs, f, schema, writer, sw); + } + { + // RepairingNsStreamWriter + StringWriter writer = new StringWriter(); + RepairingNsStreamWriter sw = (RepairingNsStreamWriter) stax2.BaseStax2Test.constructStreamWriter(writer, true, true); + validateWriter(DOC, probs, f, schema, writer, sw); + } + } } diff --git a/src/test/java/wstxtest/vstream/TestRelaxNG.java b/src/test/java/wstxtest/vstream/TestRelaxNG.java index 705ab693..6fac4b17 100644 --- a/src/test/java/wstxtest/vstream/TestRelaxNG.java +++ b/src/test/java/wstxtest/vstream/TestRelaxNG.java @@ -1,10 +1,16 @@ package wstxtest.vstream; +import java.io.StringWriter; + import javax.xml.stream.*; import org.codehaus.stax2.*; import org.codehaus.stax2.validation.*; +import com.ctc.wstx.sw.NonNsStreamWriter; +import com.ctc.wstx.sw.RepairingNsStreamWriter; +import com.ctc.wstx.sw.SimpleNsStreamWriter; + /** * This is a simple base-line "smoke test" that checks that RelaxNG * validation works at least minimally. @@ -58,11 +64,11 @@ public void testSimpleNonNs() String XML = "" +"\n" - +" \n" + +" \n" +" foobar\n" +" Foo Bar\n" +" " - +" \n" + +" \n" +" fuzzy\n" +" adjective\n" +" " @@ -70,21 +76,9 @@ public void testSimpleNonNs() ; XMLValidationSchema schema = parseRngSchema(SIMPLE_RNG_SCHEMA); - XMLStreamReader2 sr = getReader(XML); - sr.validateAgainst(schema); - - try { - assertTokenType(START_ELEMENT, sr.next()); - assertEquals("dict", sr.getLocalName()); - - while (sr.hasNext()) { - sr.next(); - } - } catch (XMLValidationException vex) { - fail("Did not expect validation exception, got: "+vex); + for (ValidationMode mode : ValidationMode.values()) { + mode.validate(schema, XML); } - - assertTokenType(END_DOCUMENT, sr.getEventType()); } /** @@ -102,7 +96,7 @@ public void testInvalidNonNs() +" foobar\n" +" Foo Bar\n" +""; - verifyRngFailure(XML, schema, "wrong root element", + verifyFailure(XML, schema, "wrong root element", "is not allowed. Possible tag names are"); // Then, wrong child ordering: @@ -111,21 +105,21 @@ public void testInvalidNonNs() +" Foo Bar\n" +" foobar\n" +""; - verifyRngFailure(XML, schema, "illegal child element ordering", + verifyFailure(XML, schema, "illegal child element ordering", "tag name \"description\" is not allowed. Possible tag names are"); // Then, missing children: XML = "\n" +"\n" +""; - verifyRngFailure(XML, schema, "missing children", + verifyFailure(XML, schema, "missing children", "uncompleted content model. expecting: "); XML = "\n" +"\n" +"word" +""; - verifyRngFailure(XML, schema, "incomplete children", + verifyFailure(XML, schema, "incomplete children", "uncompleted content model. expecting: "); // Then illegal text in non-mixed element @@ -134,7 +128,7 @@ public void testInvalidNonNs() +" foobar\n" +" Foo Bar\n" +""; - verifyRngFailure(XML, schema, "invalid non-whitespace text", + verifyFailure(XML, schema, "invalid non-whitespace text", "Element has non-mixed content specification; can not contain non-white space text"); // missing attribute @@ -149,14 +143,14 @@ public void testInvalidNonNs() +" foobar\n" +" Foo Bar\n" +""; - verifyRngFailure(XML, schema, "undeclared attribute", + verifyFailure(XML, schema, "undeclared attribute", "unexpected attribute \"attr\""); XML = "\n" +"" +" foobar\n" +" Foo Bar\n" +""; - verifyRngFailure(XML, schema, "undeclared attribute", + verifyFailure(XML, schema, "undeclared attribute", "unexpected attribute \"type\""); } @@ -164,27 +158,15 @@ public void testSimpleNs() throws XMLStreamException { String XML = "\n" - +" \n" - +" \n" + +" \n" + +" \n" +"" ; XMLValidationSchema schema = parseRngSchema(SIMPLE_RNG_NS_SCHEMA); - XMLStreamReader2 sr = getReader(XML); - sr.validateAgainst(schema); - - try { - assertTokenType(START_ELEMENT, sr.next()); - assertEquals("root", sr.getLocalName()); - - while (sr.hasNext()) { - sr.next(); - } - } catch (XMLValidationException vex) { - fail("Did not expect validation exception, got: "+vex); + for (ValidationMode mode : ValidationMode.values()) { + mode.validate(schema, XML); } - - assertTokenType(END_DOCUMENT, sr.getEventType()); } /** @@ -200,21 +182,21 @@ public void testInvalidNs() String XML = "\n" +"\n" +""; - verifyRngFailure(XML, schema, "wrong root element", + verifyFailure(XML, schema, "wrong root element", "namespace URI of tag \"root\" is wrong"); // Wrong child namespace XML = "\n" +"\n" +""; - verifyRngFailure(XML, schema, "wrong child element namespace", + verifyFailure(XML, schema, "wrong child element namespace", "namespace URI of tag \"leaf\" is wrong."); // Wrong attribute namespace XML = "\n" +"\n" +""; - verifyRngFailure(XML, schema, "wrong attribute namespace", + verifyFailure(XML, schema, "wrong attribute namespace", "unexpected attribute \"attr1\""); } @@ -232,66 +214,87 @@ public void testSimplePartialNonNs() String XML = "" +"" - +"" + +"" +"" +"" ; XMLValidationSchema schema = parseRngSchema(SIMPLE_RNG_SCHEMA); + for (StopValidatingMethod method : StopValidatingMethod.values()) { + { + StringWriter writer = new StringWriter(); + SimpleNsStreamWriter sw = (SimpleNsStreamWriter) constructStreamWriter(writer, true, false); + _testSimplePartialNonNS(XML, schema, sw, writer, method); + } + { + StringWriter writer = new StringWriter(); + RepairingNsStreamWriter sw = (RepairingNsStreamWriter) constructStreamWriter(writer, true, true); + _testSimplePartialNonNS(XML, schema, sw, writer, method); + } + { + StringWriter writer = new StringWriter(); + NonNsStreamWriter sw = (NonNsStreamWriter) constructStreamWriter(writer, false, false); + _testSimplePartialNonNS(XML, schema, sw, writer, method); + } + } + } + + private enum StopValidatingMethod {schema, validator} + + private void _testSimplePartialNonNS(String XML, XMLValidationSchema schema, XMLStreamWriter2 sw, + StringWriter writer, StopValidatingMethod method) throws XMLStreamException { XMLStreamReader2 sr = getReader(XML); XMLValidator vtor = sr.validateAgainst(schema); + + XMLValidator wVtor = sw.validateAgainst(schema); + sw.copyEventFromReader(sr, false); assertTokenType(START_ELEMENT, sr.next()); assertEquals("dict", sr.getLocalName()); + sw.copyEventFromReader(sr, false); assertTokenType(START_ELEMENT, sr.next()); assertEquals("term", sr.getLocalName()); + sw.copyEventFromReader(sr, false); /* So far so good; but here we'd get an exception... so * let's stop validating */ - assertSame(vtor, sr.stopValidatingAgainst(schema)); - try { - // And should be good to go - assertTokenType(START_ELEMENT, sr.next()); - assertEquals("invalid", sr.getLocalName()); - assertTokenType(END_ELEMENT, sr.next()); - assertEquals("invalid", sr.getLocalName()); - assertTokenType(END_ELEMENT, sr.next()); - assertEquals("term", sr.getLocalName()); - assertTokenType(END_ELEMENT, sr.next()); - assertEquals("dict", sr.getLocalName()); - assertTokenType(END_DOCUMENT, sr.next()); - } catch (XMLValidationException vex) { - fail("Did not expect validation exception after stopping validation, got: "+vex); + switch (method) { + case schema: + assertSame(vtor, sr.stopValidatingAgainst(schema)); + assertSame(wVtor, sw.stopValidatingAgainst(schema)); + break; + case validator: + assertSame(vtor, sr.stopValidatingAgainst(vtor)); + assertSame(wVtor, sw.stopValidatingAgainst(wVtor)); + break; + default: + throw new IllegalStateException(); } - sr.close(); - - // And let's do the same, just using the other stopValidatingAgainst method - sr = getReader(XML); - vtor = sr.validateAgainst(schema); - - assertTokenType(START_ELEMENT, sr.next()); - assertEquals("dict", sr.getLocalName()); - assertTokenType(START_ELEMENT, sr.next()); - assertEquals("term", sr.getLocalName()); - - assertSame(vtor, sr.stopValidatingAgainst(vtor)); try { // And should be good to go assertTokenType(START_ELEMENT, sr.next()); assertEquals("invalid", sr.getLocalName()); + sw.copyEventFromReader(sr, false); assertTokenType(END_ELEMENT, sr.next()); assertEquals("invalid", sr.getLocalName()); + sw.copyEventFromReader(sr, false); assertTokenType(END_ELEMENT, sr.next()); assertEquals("term", sr.getLocalName()); + sw.copyEventFromReader(sr, false); assertTokenType(END_ELEMENT, sr.next()); assertEquals("dict", sr.getLocalName()); + sw.copyEventFromReader(sr, false); assertTokenType(END_DOCUMENT, sr.next()); + sw.copyEventFromReader(sr, false); } catch (XMLValidationException vex) { fail("Did not expect validation exception after stopping validation, got: "+vex); } sr.close(); + sw.close(); + + assertEquals(XML, writer.toString()); } public void testSimpleEnumAttr() @@ -311,15 +314,14 @@ public void testSimpleEnumAttr() XMLValidationSchema schema = parseRngSchema(schemaDef); // First, simple valid document - String XML = ""; - XMLStreamReader2 sr = getReader(XML); - sr.validateAgainst(schema); - while (sr.next() != END_DOCUMENT) { } - sr.close(); + String XML = ""; + for (ValidationMode mode : ValidationMode.values()) { + mode.validate(schema, XML); + } // And then invalid one, with unrecognized value XML = ""; - verifyRngFailure(XML, schema, "enum attribute with unknown value", + verifyFailure(XML, schema, "enum attribute with unknown value", "attribute \"enumAttr\" has a bad value"); } @@ -351,19 +353,18 @@ public void testSimpleIdAttrs() // First, a simple valid document String XML = "" - +" \n" - +" \n" - +" \n" + +" \n" + +" \n" + +" \n" +"" ; - XMLStreamReader2 sr = getReader(XML); - sr.validateAgainst(schema); - while (sr.next() != END_DOCUMENT) { } - sr.close(); + for (ValidationMode mode : ValidationMode.values()) { + mode.validate(schema, XML); + } // Then one with malformed id XML = ""; - verifyRngFailure(XML, schema, "malformed id", + verifyFailure(XML, schema, "malformed id", "attribute \"id\" has a bad value"); // Then with malformed IDREF value (would be valid IDREFS) @@ -372,7 +373,7 @@ public void testSimpleIdAttrs() +" \n" +"" ; - verifyRngFailure(XML, schema, "malformed id", + verifyFailure(XML, schema, "malformed id", "attribute \"ref\" has a bad value"); // And then invalid one, with dangling ref @@ -380,16 +381,16 @@ public void testSimpleIdAttrs() +" \n" +"" ; - verifyRngFailure(XML, schema, "reference to undefined id", - "Undefined ID"); + verifyFailure(XML, schema, "reference to undefined id", + "Undefined ID", true, true, false); // and another one with some of refs undefined XML = "" +" \n" +"" ; - verifyRngFailure(XML, schema, "reference to undefined id", - "Undefined ID"); + verifyFailure(XML, schema, "reference to undefined id", + "Undefined ID", true, true, false); } public void testSimpleIntAttr() @@ -407,25 +408,25 @@ public void testSimpleIntAttr() XMLValidationSchema schema = parseRngSchema(schemaDef); // First, a simple valid document - XMLStreamReader2 sr = getReader(""); - sr.validateAgainst(schema); - while (sr.next() != END_DOCUMENT) { } - sr.close(); + String XML = ""; + for (ValidationMode mode : ValidationMode.values()) { + mode.validate(schema, XML); + } // Then one with invalid element value - verifyRngFailure("", + verifyFailure("", schema, "invalid integer attribute value", "does not satisfy the \"integer\" type"); // And missing attribute - verifyRngFailure("", + verifyFailure("", schema, "missing integer attribute value", "is missing \"nr\" attribute"); // And then two variations of having empty value - verifyRngFailure("", + verifyFailure("", schema, "missing integer attribute value", "does not satisfy the \"integer\" type"); - verifyRngFailure("", + verifyFailure("", schema, "missing integer attribute value", "does not satisfy the \"integer\" type"); } @@ -450,19 +451,19 @@ public void testSimpleBooleanElem2() XMLValidationSchema schema = parseRngSchema(schemaDef); // First, a simple valid document - XMLStreamReader2 sr = getReader("abctrue"); - sr.validateAgainst(schema); - while (sr.next() != END_DOCUMENT) { } - sr.close(); + String XML = "abctrue"; + for (ValidationMode mode : ValidationMode.values()) { + mode.validate(schema, XML); + } // Then another valid, but with empty tag for leaf1 - sr = getReader("false"); - sr.validateAgainst(schema); - while (sr.next() != END_DOCUMENT) { } - sr.close(); + XML = "false"; + for (ValidationMode mode : ValidationMode.values()) { + mode.validate(schema, XML); + } // And then one more invalid case - verifyRngFailure("true false", + verifyFailure("true false", schema, "missing boolean element value", "does not satisfy the \"boolean\" type"); } @@ -478,20 +479,42 @@ public void testPartialValidationOk() * wrap the doc... */ String XML = - "\n" - +"\n" - +"\n" - +" foobar\n" - +" Foo Bar\n" - +"\n" - +"" - ; + "\n" + +"\n" + +"\n" + +" foobar\n" + +" Foo Bar\n" + +"\n" + +"" + ; XMLValidationSchema schema = parseRngSchema(SIMPLE_RNG_SCHEMA); + { + StringWriter writer = new StringWriter(); + SimpleNsStreamWriter sw = (SimpleNsStreamWriter) constructStreamWriter(writer, true, false); + _testPartialValidationOk(XML, schema, sw, writer); + } + { + StringWriter writer = new StringWriter(); + NonNsStreamWriter sw = (NonNsStreamWriter) constructStreamWriter(writer, false, false); + _testPartialValidationOk(XML, schema, sw, writer); + } + } + + private void _testPartialValidationOk(String XML, XMLValidationSchema schema, XMLStreamWriter2 sw, StringWriter writer) throws XMLStreamException { XMLStreamReader2 sr = getReader(XML); assertTokenType(START_ELEMENT, sr.next()); + sw.copyEventFromReader(sr, false); + sr.validateAgainst(schema); - while (sr.next() != END_DOCUMENT) { } + sw.validateAgainst(schema); + while (sr.hasNext()) { + sr.next(); + sw.copyEventFromReader(sr, false); + } sr.close(); + sw.close(); + + assertEquals(XML, writer.toString()); } @@ -508,37 +531,4 @@ private XMLStreamReader2 getReader(String contents) throws XMLStreamException return constructStreamReader(f, contents); } - private void verifyRngFailure(String xml, XMLValidationSchema schema, String failMsg, String failPhrase) - throws XMLStreamException - { - // By default, yes we are strict... - verifyRngFailure(xml, schema, failMsg, failPhrase, true); - } - - private void verifyRngFailure(String xml, XMLValidationSchema schema, String failMsg, String failPhrase, - boolean strict) - throws XMLStreamException - { - XMLStreamReader2 sr = getReader(xml); - sr.validateAgainst(schema); - try { - while (sr.hasNext()) { - /*int type =*/ sr.next(); - } - fail("Expected validity exception for "+failMsg); - } catch (XMLValidationException vex) { - String origMsg = vex.getMessage(); - String msg = (origMsg == null) ? "" : origMsg.toLowerCase(); - if (msg.indexOf(failPhrase.toLowerCase()) < 0) { - String actualMsg = "Expected validation exception for "+failMsg+", containing phrase '"+failPhrase+"': got '"+origMsg+"'"; - if (strict) { - fail(actualMsg); - } - warn("suppressing failure due to MSV bug, failure: '"+actualMsg+"'"); - } - // should get this specific type; not basic stream exception - } catch (XMLStreamException sex) { - fail("Expected XMLValidationException for "+failMsg); - } - } } diff --git a/src/test/java/wstxtest/vstream/TestW3CSchemaComplexTypes.java b/src/test/java/wstxtest/vstream/TestW3CSchemaComplexTypes.java index cdf58b69..bc84f9dd 100644 --- a/src/test/java/wstxtest/vstream/TestW3CSchemaComplexTypes.java +++ b/src/test/java/wstxtest/vstream/TestW3CSchemaComplexTypes.java @@ -1,12 +1,18 @@ package wstxtest.vstream; +import java.io.StringWriter; + import javax.xml.stream.XMLStreamException; import org.codehaus.stax2.XMLInputFactory2; import org.codehaus.stax2.XMLStreamReader2; -import org.codehaus.stax2.validation.XMLValidationException; +import org.codehaus.stax2.XMLStreamWriter2; import org.codehaus.stax2.validation.XMLValidationSchema; +import com.ctc.wstx.sw.NonNsStreamWriter; +import com.ctc.wstx.sw.RepairingNsStreamWriter; +import com.ctc.wstx.sw.SimpleNsStreamWriter; + public class TestW3CSchemaComplexTypes extends BaseValidationTest { @@ -44,21 +50,54 @@ public void testMSVGithubIssue2() throws Exception +"" +"" +""); - XMLStreamReader2 sr = getReader("" - +"" + String XML = "" + +"" +"" - +""); + +""; + + { + StringWriter writer = new StringWriter(); + SimpleNsStreamWriter sw = (SimpleNsStreamWriter) constructStreamWriter(writer, true, false); + _testMSVGithubIssue2(schema, XML, sw, writer); + } + { + StringWriter writer = new StringWriter(); + RepairingNsStreamWriter sw = (RepairingNsStreamWriter) constructStreamWriter(writer, true, true); + _testMSVGithubIssue2(schema, XML, sw, writer); + } + } + + private void _testMSVGithubIssue2(XMLValidationSchema schema, String XML, XMLStreamWriter2 sw, StringWriter writer) throws XMLStreamException { + XMLStreamReader2 sr = getReader(XML); sr.validateAgainst(schema); + sw.validateAgainst(schema); + assertTokenType(START_ELEMENT, sr.next()); assertEquals("Root", sr.getLocalName()); + sw.copyEventFromReader(sr, false); + assertTokenType(START_ELEMENT, sr.next()); assertEquals("Child", sr.getLocalName()); + sw.copyEventFromReader(sr, false); + assertTokenType(END_ELEMENT, sr.next()); + sw.copyEventFromReader(sr, false); + assertTokenType(END_ELEMENT, sr.next()); + sw.copyEventFromReader(sr, false); + assertTokenType(END_DOCUMENT, sr.next()); + sw.copyEventFromReader(sr, false); + + assertTokenType(END_DOCUMENT, sr.getEventType()); + + sr.close(); + sw.close(); - assertTokenType(END_DOCUMENT, sr.getEventType()); + // the writers collapse empty elements + String expectedXML = XML.replace(">", "/>"); + assertEquals(expectedXML, writer.toString()); } /*