TestXMLReporter.java
package wstxtest.vstream;
import javax.xml.stream.*;
import org.codehaus.stax2.XMLReporter2;
import org.codehaus.stax2.validation.XMLValidationProblem;
import wstxtest.stream.BaseStreamTest;
/**
* Simple testing to ensure that {@link XMLReporter} works as
* expected with respect to validation errors.
*<p>
* As of Woodstox 4.0, we will be actually using {@link XMLReporter2}
* interface, both to test that the improved interface works, and
* to get access to more accurate information.
*/
public class TestXMLReporter
extends BaseStreamTest
{
/**
* Basic unit test for verifying that XMLReporter gets validation
* errors reported.
*/
public void testValidationError()
throws XMLStreamException
{
String XML =
"<!DOCTYPE root [\n"
+" <!ELEMENT root (#PCDATA)>\n"
+"]><root>...</root>"
;
testOldReporterProblems(XML, 0);
testNewReporterProblems(XML, null);
// Then invalid, with one error
XML =
"<!DOCTYPE root [\n"
+" <!ELEMENT root (leaf+)>\n"
+"]><root></root>";
;
testOldReporterProblems(XML, 1);
testNewReporterProblems(XML, "at least one element <leaf>");
}
/**
* Test for specific validation error, mostly to verify
* fix to [WSTX-155] (and guard against regression)
*/
public void testMissingAttrError()
throws XMLStreamException
{
String XML =
"<!DOCTYPE root [\n"
+" <!ELEMENT root (#PCDATA)>\n"
+" <!ATTLIST root attr CDATA #REQUIRED>\n"
+"]><root />";
;
testOldReporterProblems(XML, 1);
testNewReporterProblems(XML, "Required attribute");
}
public void testInvalidFixedAttr()
throws XMLStreamException
{
// Not ok to have any other value, either completely different
String XML = "<!DOCTYPE root [\n"
+"<!ELEMENT root EMPTY>\n"
+"<!ATTLIST root attr CDATA #FIXED 'fixed'>\n"
+"]>\n<root attr='wrong'/>";
testOldReporterProblems(XML, 1);
testNewReporterProblems(XML, "FIXED attribute");
// Or one with extra white space (CDATA won't get fully normalized)
XML = "<!DOCTYPE root [\n"
+"<!ELEMENT root EMPTY>\n"
+"<!ATTLIST root attr CDATA #FIXED 'fixed'>\n"
+"]>\n<root attr=' fixed '/>";
testOldReporterProblems(XML, 1);
testNewReporterProblems(XML, "FIXED attribute");
}
public void testInvalidIdAttr()
throws XMLStreamException
{
// Error: undefined id 'someId'
String XML = "<!DOCTYPE elem [\n"
+"<!ELEMENT elem (elem*)>\n"
+"<!ATTLIST elem id ID #IMPLIED>\n"
+"<!ATTLIST elem ref IDREF #IMPLIED>\n"
+"]>\n<elem ref='someId'/>";
testOldReporterProblems(XML, 1);
testNewReporterProblems(XML, "Undefined id");
// Error: empty idref value
XML = "<!DOCTYPE elem [\n"
+"<!ELEMENT elem (elem*)>\n"
+"<!ATTLIST elem id ID #IMPLIED>\n"
+"<!ATTLIST elem ref IDREF #IMPLIED>\n"
+"]>\n<elem ref=''/>";
testOldReporterProblems(XML, 1);
testNewReporterProblems(XML, "IDREF value");
}
public void testInvalidSimpleChoiceStructure()
throws XMLStreamException
{
String XML = "<!DOCTYPE root [\n"
+"<!ELEMENT root (a1 | a2)+>\n"
+"<!ELEMENT a1 EMPTY>\n"
+"<!ELEMENT a2 (#PCDATA)>\n"
+"]>\n"
+"<root />";
testOldReporterProblems(XML, 1);
testNewReporterProblems(XML, "Expected at least one of elements");
}
/**
* This test verifies that exception XMLReporter rethrows gets
* properly propagated.
*/
public void testErrorRethrow()
throws XMLStreamException
{
String XML =
"<!DOCTYPE root [\n"
+" <!ELEMENT root (leaf+)>\n"
+"]><root></root>";
;
MyReporterOld rep = new MyReporterOld();
rep.enableThrow();
XMLStreamReader sr = getReader(XML, rep);
try {
streamThrough(sr);
fail("Expected a re-thrown exception for invalid content");
} catch (XMLStreamException xse) {
;
}
sr.close();
assertEquals(1, rep.getCount());
testNewReporterProblems(XML, "element <leaf>");
}
/*
//////////////////////////////////////////////////
// Helper methods
//////////////////////////////////////////////////
*/
private XMLStreamReader getReader(String xml, XMLReporter rep)
throws XMLStreamException
{
XMLInputFactory f = getInputFactory();
setNamespaceAware(f, true);
setSupportDTD(f, true);
setValidating(f, true);
f.setXMLReporter(rep);
return constructStreamReader(f, xml);
}
private void testOldReporterProblems(String XML, int expFails)
throws XMLStreamException
{
MyReporterOld rep = new MyReporterOld();
XMLStreamReader sr = getReader(XML, rep);
streamThrough(sr);
sr.close();
int actFails = rep.getCount();
assertEquals("Expected "+expFails+" fail(s), got "+actFails,
expFails, actFails);
}
private void testNewReporterProblems(String XML, String expMsg)
throws XMLStreamException
{
MyReporter2 rep = new MyReporter2();
XMLStreamReader sr = getReader(XML, rep);
streamThrough(sr);
sr.close();
int actFails = rep.getCount();
int expFails = (expMsg == null) ? 0 : 1;
assertEquals("Expected "+expFails+" fail(s), got "+actFails,
expFails, actFails);
if (expFails > 0) {
String actMsg = rep.getMessage();
if (actMsg == null) {
actMsg = "";
}
if (!actMsg.contains(expMsg)) {
fail("Expected failure to contain phrase '"+expMsg+"', did not, was: '"+actMsg+"'");
}
}
}
/*
//////////////////////////////////////////////////
// Helper classes
//////////////////////////////////////////////////
*/
/**
* Base Report class, used to verify some aspects of using
* plain old XMLReporter class (for example that we do
* get 'relatedInfo' populated with XMLValidationProblem)
*/
static class MyReporterOld
implements XMLReporter
{
protected int _count = 0;
protected String _firstMessage;
protected boolean _doThrow = false;
public MyReporterOld() { }
public void enableThrow() { _doThrow = true; }
@Override
public void report(String message,String errorType,
Object relatedInfo, Location location)
throws XMLStreamException
{
++_count;
if (_firstMessage != null) {
_firstMessage = message;
}
if (_doThrow) {
throw new XMLStreamException(message, location);
}
/* 30-May-2008, TSa: Need to ensure that extraArg is of
* type XMLValidationProblem; new constraint for Woodstox
*/
if (relatedInfo == null) {
throw new IllegalArgumentException("relatedInformation null, should be an instance of XMLValidationProblem");
}
if (!(relatedInfo instanceof XMLValidationProblem)) {
throw new IllegalArgumentException("relatedInformation not an instance of XMLValidationProblem (but "+relatedInfo.getClass().getName()+")");
}
}
public int getCount() { return _count; }
public String getMessage() { return _firstMessage; }
}
static class MyReporter2
extends MyReporterOld
implements XMLReporter2
{
public MyReporter2() { super(); }
@Override
public void report(String message, String errorType,
Object relatedInfo, Location location)
throws XMLStreamException
{
throw new Error("Should not get a call through old XMLReporter interface, when registering XMLReporter2");
}
@Override
public void report(XMLValidationProblem prob)
throws XMLStreamException
{
++_count;
String msg = prob.getMessage();
// Let's require a message here... for now
if (msg == null) {
throw new RuntimeException("Problem object missing 'message' property");
}
if (_firstMessage == null) {
_firstMessage = msg;
}
if (_doThrow) {
throw prob.toException();
}
}
}
}