TestNameValidation.java
package wstxtest.wstream;
import java.io.*;
import javax.xml.stream.*;
import org.codehaus.stax2.*;
/**
* Woodstox-specific stream writer test suite that will ensure that the
* name validation property works properly (as expected)
*/
public class TestNameValidation
extends BaseWriterTest
{
final static String DUMMY_URL = "http://someurl";
final static String ATTR_VALUE = "value";
final static String PI_DATA = "just some proc.instr. content!!";
/* Notes about validity
*
* - Dot is valid, but not as first name char
*/
final static String[] VALID_NS_PREFIXES = new String[] {
"a", "ab_123", "this.attr", "_uber", "pre-fix"
};
final static String[] VALID_NS_NAMES = new String[] {
"tag", "i", "my.dotted.name",
// note: dot is valid only as non-first char...
"x.12", "a_32", "__mymy", "a-ha"
};
final static String[] VALID_NON_NS_NAMES = new String[] {
"ns:elem", ":::a", "xyz"
};
final static String[] VALID_NS_ROOT_NAMES = new String[] {
"ns:elem", "abc", "a1:foobar"
};
final static String[] INVALID_NS_PREFIXES = new String[] {
"a:1", "1abc", "xy+z", "r&b", "", "fun\tny", ".ns", "-a"
};
final static String[] INVALID_NS_NAMES = new String[] {
":abc", "ns:elem", ".name", "", "1", "a<b", "stuff with spaces",
"-xyz"
};
final static String[] INVALID_NON_NS_NAMES = new String[] {
"ab>foo", "", "1abc", " space", ".abc", "-23"
};
final static String[] INVALID_NS_ROOT_NAMES = new String[] {
"ns:elem:blah", "a<>2", "", ".x", "-ab", "3cpu"
};
/*
////////////////////////////////////////////////////
// Main test methods
////////////////////////////////////////////////////
*/
public void testValidElemNames()
throws XMLStreamException
{
for (int n = 0; n < 4; ++n) {
boolean ns = ((n & 1) == 0);
boolean validate = ((n & 2) == 0);
XMLStreamWriter sw = startDoc(validate, ns);
// Let's add a dummy root:
sw.writeStartElement("dummy");
if (ns) { // need to check both prefixes and names
/* Note: when not repairing, need not worry about
* namespace binding... makes life easier here
*/
for (String name : VALID_NS_NAMES) {
sw.writeEmptyElement(name);
sw.writeStartElement(name);
sw.writeEndElement();
}
for (String prefix : VALID_NS_PREFIXES) {
sw.writeEmptyElement(prefix, "elem", DUMMY_URL);
sw.writeStartElement(prefix, "elem", DUMMY_URL);
sw.writeEndElement();
}
} else {
for (String name : VALID_NON_NS_NAMES) {
sw.writeEmptyElement(name);
sw.writeStartElement(name);
sw.writeEndElement();
}
}
sw.writeEndElement();
closeDoc(sw);
}
}
public void testInvalidElemNames()
throws XMLStreamException
{
for (int n = 0; n < 2; ++n) {
boolean ns = (n == 1);
if (ns) { // need to check both prefixes and names
for (String name : INVALID_NS_NAMES) {
for (String prefix : INVALID_NS_PREFIXES) {
doTestInvalidElemName(true, prefix, name);
doTestInvalidElemName(true, null, name);
}
}
} else {
for (String name : INVALID_NON_NS_NAMES) {
doTestInvalidElemName(false, null, name);
}
}
}
}
private void doTestInvalidElemName(boolean ns, String prefix, String name)
throws XMLStreamException
{
for (int i = 0; i < 2; ++i) { // to test both empty and non-empty elems
boolean empty = (i == 1);
try {
XMLStreamWriter sw = startDoc(true, ns);
sw.writeStartElement("dummy");
if (prefix == null) {
if (empty) {
sw.writeEmptyElement(name);
} else {
sw.writeStartElement(name);
sw.writeEndElement();
}
} else {
if (empty) {
sw.writeEmptyElement(prefix, name, DUMMY_URL);
} else {
sw.writeStartElement(prefix, name, DUMMY_URL);
sw.writeEndElement();
}
}
sw.writeEndElement();
closeDoc(sw);
} catch (XMLStreamException iae) {
continue; // good
}
fail("Failed to catch an invalid element name/prefix (ns = "+ns+"); name='"
+name+"', prefix = "
+((prefix == null) ? "NULL" : ("'"+prefix+"'"))+".");
}
}
// [woodstox-core#107]: need to include more info
public void testInvalidElemNameExceptionMessage() throws XMLStreamException
{
// First, empty "name":
_testInvalidElemNameExceptionMessage(false, null, "", -1);
_testInvalidElemNameExceptionMessage(false, "prefix", "", -1);
_testInvalidElemNameExceptionMessage(true, null, "", -1);
_testInvalidElemNameExceptionMessage(true, "prefix", "", -1);
// Then non-empty, first char bad
_testInvalidElemNameExceptionMessage(false, null, "1", 0);
_testInvalidElemNameExceptionMessage(false, "prefix", "1", 0);
_testInvalidElemNameExceptionMessage(true, null, "1", 0);
_testInvalidElemNameExceptionMessage(true, "prefix", "1", 0);
_testInvalidElemNameExceptionMessage(true, null, ":", 0);
_testInvalidElemNameExceptionMessage(true, "prefix", ":", 0);
// and then some other
_testInvalidElemNameExceptionMessage(false, null, "a b", 1);
_testInvalidElemNameExceptionMessage(false, "prefix", "a b", 1);
_testInvalidElemNameExceptionMessage(true, null, "a b", 1);
_testInvalidElemNameExceptionMessage(true, "prefix", "a b", 1);
_testInvalidElemNameExceptionMessage(true, null, "a:b", 1);
_testInvalidElemNameExceptionMessage(true, "prefix", "a:b", 1);
}
private void _testInvalidElemNameExceptionMessage(boolean ns, String prefix,
String name, int index)
throws XMLStreamException
{
try {
XMLStreamWriter sw = startDoc(true, ns);
sw.writeStartElement("dummy");
if (prefix == null) {
sw.writeStartElement(name);
sw.writeEndElement();
} else {
sw.writeStartElement(prefix, name, DUMMY_URL);
sw.writeEndElement();
}
sw.writeEndElement();
closeDoc(sw);
fail("Failed to catch an invalid element name/prefix (ns = "+ns+"); name='"
+name+"', prefix = "
+((prefix == null) ? "NULL" : ("'"+prefix+"'"))+".");
} catch (XMLStreamException sex) {
if (name.isEmpty()) {
verifyException(sex, "Illegal to pass empty name");
} else if (index == 0) {
verifyException(sex, "Illegal first name character '");
verifyException(sex, "in name \""+name+"\"");
} else {
verifyException(sex, "Illegal name character '");
verifyException(sex, "in name \""+name+"\"");
verifyException(sex, " (index #"+index+")");
}
}
}
public void testValidAttrNames()
throws Exception
{
for (int n = 0; n < 4; ++n) {
boolean ns = ((n & 1) == 0);
boolean validate = ((n & 2) == 0);
XMLStreamWriter sw = startDoc(validate, ns);
// Let's add a dummy root:
sw.writeStartElement("dummy");
if (ns) {
for (String name : VALID_NS_NAMES) {
sw.writeAttribute(name, ATTR_VALUE);
}
for (String prefix : VALID_NS_PREFIXES) {
sw.writeAttribute(prefix, DUMMY_URL, "attr", ATTR_VALUE);
}
} else {
for (String name : VALID_NON_NS_NAMES) {
sw.writeAttribute(name, ATTR_VALUE);
}
}
sw.writeEndElement();
closeDoc(sw);
}
}
public void testInvalidAttrNames()
throws Exception
{
for (int n = 0; n < 2; ++n) {
boolean ns = (n == 1);
if (ns) { // need to check both prefixes and names
for (String name : INVALID_NS_NAMES) {
for (String prefix : INVALID_NS_PREFIXES) {
doTestInvalidAttrName(true, prefix, name);
doTestInvalidAttrName(true, null, name);
}
}
} else {
for (String name : INVALID_NON_NS_NAMES) {
doTestInvalidAttrName(false, null, name);
}
}
}
}
private void doTestInvalidAttrName(boolean ns, String prefix, String name)
throws XMLStreamException
{
XMLStreamWriter sw = startDoc(true, ns);
sw.writeStartElement("dummy");
try {
if (prefix == null) {
sw.writeAttribute(name, ATTR_VALUE);
} else {
sw.writeAttribute(prefix, DUMMY_URL, name, ATTR_VALUE);
}
} catch (XMLStreamException sex) {
sw.writeEndElement();
closeDoc(sw);
return; // good
}
fail("Failed to catch an invalid attr name/prefix (ns = "+ns+"); name='"
+name+"', prefix = "
+((prefix == null) ? "NULL" : ("'"+prefix+"'"))+".");
}
/**
* According to XML Namespaces 1.1 specification, PI targets
* can not contain colons either...
*/
public void testValidPiNames()
throws Exception
{
for (int n = 0; n < 4; ++n) {
boolean ns = ((n & 1) == 0);
boolean validate = ((n & 2) == 0);
XMLStreamWriter sw = startDoc(validate, ns);
// Let's add a dummy root:
sw.writeStartElement("dummy");
/* No colons allowed in namespace-aware mode
*/
String[] strs = ns ? VALID_NS_NAMES : VALID_NON_NS_NAMES;
for (String name : strs) {
sw.writeProcessingInstruction(name);
sw.writeProcessingInstruction(name, PI_DATA);
}
sw.writeEndElement();
closeDoc(sw);
}
}
public void testInvalidPiNames()
throws Exception
{
for (int n = 0; n < 4; ++n) {
boolean ns = ((n & 1) == 0);
boolean empty = ((n & 2) == 0);
String[] strs = ns ? INVALID_NS_NAMES : INVALID_NON_NS_NAMES;
for (String name : strs) {
XMLStreamWriter sw = startDoc(true, ns);
sw.writeStartElement("dummy");
try {
if (empty) {
sw.writeProcessingInstruction(name);
} else {
sw.writeProcessingInstruction(name, PI_DATA);
}
} catch (XMLStreamException sex) {
sw.writeEndElement();
closeDoc(sw);
continue; // good
}
fail("Failed to catch an invalid proc.instr. name (ns = "+ns+") '"
+name+"'.");
}
}
}
/**
* Since the root element name is NOT really properly split (ie. it's
* never dealt with as a scoped name), we can only check if that it has
* zero or one colons (in NS-awre) mode, but nothing further
*/
public void testValidRootNames()
throws Exception
{
for (int n = 0; n < 4; ++n) {
boolean ns = ((n & 1) == 0);
boolean validate = ((n & 2) == 0);
String[] strs = ns ? VALID_NS_ROOT_NAMES : VALID_NON_NS_NAMES;
for (String rootName : strs) {
XMLStreamWriter2 sw = (XMLStreamWriter2) startDoc(validate, ns);
// only root name is mandatory, others are optional
sw.writeDTD(rootName, null, null, null);
// need a matching root, then:
if (ns) { // may need to split
int ix = rootName.indexOf(':');
if (ix > 0) {
sw.writeEmptyElement(rootName.substring(0, ix),
rootName.substring(ix+1),
DUMMY_URL);
} else {
sw.writeEmptyElement(rootName);
}
} else {
sw.writeEmptyElement(rootName);
}
closeDoc(sw);
}
}
}
public void testInvalidRootNames()
throws Exception
{
for (int n = 0; n < 2; ++n) {
boolean ns = ((n & 1) == 0);
String[] strs = ns ? INVALID_NS_ROOT_NAMES : INVALID_NON_NS_NAMES;
for (String rootName : strs) {
XMLStreamWriter2 sw = (XMLStreamWriter2) startDoc(true, ns);
try {
// only root name is mandatory, others are optional
sw.writeDTD(rootName, null, null, null);
sw.writeEmptyElement(rootName); // need a root...and should match too
} catch (XMLStreamException sex) {
continue; // good
}
fail("Failed to catch an invalid DTD root name (ns = "+ns+") '"
+rootName+"'.");
}
}
}
/**
* According to XML Namespaces 1.1 specification, entity names (ids)
* can not contain colons either...
*<p>
* Note: Here we count on the fact that the current stream writer
* does not (and actually, can not!) verify whether the entity
* has been properly declared.
*/
public void testValidEntityNames()
throws Exception
{
for (int n = 0; n < 4; ++n) {
boolean ns = ((n & 1) == 0);
boolean validate = ((n & 2) == 0);
XMLStreamWriter sw = startDoc(validate, ns);
// Let's add a dummy root:
sw.writeStartElement("dummy");
/* No colons allowed in namespace-aware mode
*/
String[] strs = ns ? VALID_NS_NAMES : VALID_NON_NS_NAMES;
for (String name : strs) {
sw.writeEntityRef(name);
}
sw.writeEndElement();
closeDoc(sw);
}
}
public void testInvalidEntityNames()
throws XMLStreamException
{
for (int n = 0; n < 2; ++n) {
boolean ns = ((n & 1) == 0);
String[] strs = ns ? INVALID_NS_ROOT_NAMES : INVALID_NON_NS_NAMES;
for (String name : strs) {
XMLStreamWriter2 sw = (XMLStreamWriter2) startDoc(true, ns);
sw.writeStartElement("dummy");
try {
// only root name is mandatory, others are optional
sw.writeEntityRef(name);
} catch (XMLStreamException sex) {
sw.writeEndElement();
closeDoc(sw);
continue; // good
}
fail("Failed to catch an invalid entity name (ns = "+ns+") '"
+name+"'.");
}
}
}
/*
////////////////////////////////////////////////////
// Internal methods
////////////////////////////////////////////////////
*/
private XMLOutputFactory getFactory(boolean validateNames, boolean ns)
throws XMLStreamException
{
XMLOutputFactory f = getOutputFactory();
setValidateNames(f, validateNames);
setNamespaceAware(f, ns);
// Let's disable repairing
setRepairing(f, false);
return f;
}
private XMLStreamWriter startDoc(boolean validateNames, boolean ns)
throws XMLStreamException
{
XMLOutputFactory f = getFactory(validateNames, ns);
XMLStreamWriter sw = f.createXMLStreamWriter(new StringWriter());
sw.writeStartDocument();
return sw;
}
private void closeDoc(XMLStreamWriter sw)
throws XMLStreamException
{
sw.writeEndDocument();
sw.close();
}
}