| /* |
| * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package util; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.File; |
| import java.io.FileReader; |
| import java.io.IOException; |
| import java.io.StringReader; |
| import java.io.UnsupportedEncodingException; |
| import java.util.HashMap; |
| |
| import javax.xml.stream.XMLEventFactory; |
| import javax.xml.stream.XMLInputFactory; |
| import javax.xml.stream.XMLOutputFactory; |
| import javax.xml.stream.XMLResolver; |
| import javax.xml.stream.XMLStreamConstants; |
| import javax.xml.stream.XMLStreamException; |
| import javax.xml.stream.XMLStreamReader; |
| import javax.xml.stream.events.XMLEvent; |
| |
| import org.testng.Assert; |
| |
| /** |
| * Base class for all StaxTest unit test classes. Contains shared |
| * functionality for many common set up tasks, as well as for |
| * outputting diagnostics. |
| * |
| */ |
| public class BaseStAXUT implements XMLStreamConstants { |
| /** |
| * This is the de facto standard property that enables accurate reporting of |
| * CDATA events. |
| */ |
| final static String PROP_REPORT_CDATA = "http://java.sun.com/xml/stream/properties/report-cdata-event"; |
| |
| final static HashMap mTokenTypes = new HashMap(); |
| static { |
| mTokenTypes.put(new Integer(START_ELEMENT), "START_ELEMENT"); |
| mTokenTypes.put(new Integer(END_ELEMENT), "END_ELEMENT"); |
| mTokenTypes.put(new Integer(START_DOCUMENT), "START_DOCUMENT"); |
| mTokenTypes.put(new Integer(END_DOCUMENT), "END_DOCUMENT"); |
| mTokenTypes.put(new Integer(CHARACTERS), "CHARACTERS"); |
| mTokenTypes.put(new Integer(CDATA), "CDATA"); |
| mTokenTypes.put(new Integer(COMMENT), "COMMENT"); |
| mTokenTypes.put(new Integer(PROCESSING_INSTRUCTION), "PROCESSING_INSTRUCTION"); |
| mTokenTypes.put(new Integer(DTD), "DTD"); |
| mTokenTypes.put(new Integer(SPACE), "SPACE"); |
| mTokenTypes.put(new Integer(ENTITY_REFERENCE), "ENTITY_REFERENCE"); |
| mTokenTypes.put(new Integer(NAMESPACE), "NAMESPACE_DECLARATION"); |
| mTokenTypes.put(new Integer(NOTATION_DECLARATION), "NOTATION_DECLARATION"); |
| mTokenTypes.put(new Integer(ENTITY_DECLARATION), "ENTITY_DECLARATION"); |
| } |
| |
| /* |
| * /////////////////////////////////////////////////// // Consts for |
| * expected values /////////////////////////////////////////////////// |
| */ |
| |
| /** |
| * Expected return value for streamReader.getNamespaceURI() in |
| * non-namespace-aware mode. |
| */ |
| protected final String DEFAULT_URI_NON_NS = ""; |
| |
| protected final String DEFAULT_URI_NS = ""; |
| |
| /* |
| * /////////////////////////////////////////////////// // Other consts |
| * /////////////////////////////////////////////////// |
| */ |
| |
| /* |
| * /////////////////////////////////////////////////// // Cached instances |
| * /////////////////////////////////////////////////// |
| */ |
| |
| XMLInputFactory mInputFactory; |
| XMLOutputFactory mOutputFactory; |
| XMLEventFactory mEventFactory; |
| |
| protected XMLInputFactory getInputFactory() { |
| if (mInputFactory == null) { |
| mInputFactory = getNewInputFactory(); |
| } |
| return mInputFactory; |
| } |
| |
| protected static XMLInputFactory getNewInputFactory() { |
| return XMLInputFactory.newInstance(); |
| } |
| |
| protected XMLOutputFactory getOutputFactory() { |
| if (mOutputFactory == null) { |
| mOutputFactory = getNewOutputFactory(); |
| } |
| return mOutputFactory; |
| } |
| |
| protected static XMLOutputFactory getNewOutputFactory() { |
| return XMLOutputFactory.newInstance(); |
| } |
| |
| protected XMLEventFactory getEventFactory() { |
| if (mEventFactory == null) { |
| mEventFactory = XMLEventFactory.newInstance(); |
| } |
| return mEventFactory; |
| } |
| |
| protected static XMLStreamReader constructStreamReader(XMLInputFactory f, String content) throws XMLStreamException { |
| // return f.createXMLStreamReader(new StringReader(content)); |
| try { |
| byte[] data = content.getBytes("UTF-8"); |
| return constructStreamReader(f, data); |
| } catch (UnsupportedEncodingException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| protected static XMLStreamReader constructStreamReader(XMLInputFactory f, byte[] b) throws XMLStreamException { |
| return f.createXMLStreamReader(new ByteArrayInputStream(b)); |
| } |
| |
| protected static XMLStreamReader constructStreamReaderForFile(XMLInputFactory f, String filename) throws IOException, XMLStreamException { |
| File inf = new File(filename); |
| XMLStreamReader sr = f.createXMLStreamReader(inf.toURL().toString(), new FileReader(inf)); |
| Assert.assertEquals(START_DOCUMENT, sr.getEventType()); |
| return sr; |
| } |
| |
| protected XMLStreamReader constructNsStreamReader(String content) throws XMLStreamException { |
| XMLInputFactory f = getInputFactory(); |
| setNamespaceAware(f, true); |
| return f.createXMLStreamReader(new StringReader(content)); |
| } |
| |
| protected XMLStreamReader constructNsStreamReader(String content, boolean coal) throws XMLStreamException { |
| XMLInputFactory f = getInputFactory(); |
| setNamespaceAware(f, true); |
| setCoalescing(f, coal); |
| return f.createXMLStreamReader(new StringReader(content)); |
| } |
| |
| /* |
| * ////////////////////////////////////////////////// // Configuring input |
| * factory ////////////////////////////////////////////////// |
| */ |
| |
| protected static boolean isCoalescing(XMLInputFactory f) throws XMLStreamException { |
| return ((Boolean) f.getProperty(XMLInputFactory.IS_COALESCING)).booleanValue(); |
| } |
| |
| protected static void setCoalescing(XMLInputFactory f, boolean state) throws XMLStreamException { |
| Boolean b = state ? Boolean.TRUE : Boolean.FALSE; |
| f.setProperty(XMLInputFactory.IS_COALESCING, b); |
| // Let's just double-check it... |
| Assert.assertEquals(state, isCoalescing(f)); |
| } |
| |
| protected static boolean isValidating(XMLInputFactory f) throws XMLStreamException { |
| return ((Boolean) f.getProperty(XMLInputFactory.IS_VALIDATING)).booleanValue(); |
| } |
| |
| protected static void setValidating(XMLInputFactory f, boolean state) throws XMLStreamException { |
| try { |
| Boolean b = state ? Boolean.TRUE : Boolean.FALSE; |
| f.setProperty(XMLInputFactory.IS_VALIDATING, b); |
| } catch (IllegalArgumentException iae) { |
| Assert.fail("Could not set DTD validating mode to " + state + ": " + iae); |
| // throw new XMLStreamException(iae.getMessage(), iae); |
| } |
| Assert.assertEquals(state, isValidating(f)); |
| } |
| |
| protected static boolean isNamespaceAware(XMLInputFactory f) throws XMLStreamException { |
| return ((Boolean) f.getProperty(XMLInputFactory.IS_NAMESPACE_AWARE)).booleanValue(); |
| } |
| |
| /** |
| * @return True if setting succeeded, and property supposedly was |
| * succesfully set to the value specified; false if there was a |
| * problem. |
| */ |
| protected static boolean setNamespaceAware(XMLInputFactory f, boolean state) throws XMLStreamException { |
| try { |
| f.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, state ? Boolean.TRUE : Boolean.FALSE); |
| |
| /* |
| * 07-Sep-2005, TSa: Let's not assert, but instead let's see if it |
| * sticks. Some implementations might choose to silently ignore |
| * setting, at least for 'false'? |
| */ |
| return (isNamespaceAware(f) == state); |
| } catch (IllegalArgumentException e) { |
| /* |
| * Let's assume, then, that the property (or specific value for it) |
| * is NOT supported... |
| */ |
| return false; |
| } |
| } |
| |
| protected static void setReplaceEntities(XMLInputFactory f, boolean state) throws XMLStreamException { |
| Boolean b = state ? Boolean.TRUE : Boolean.FALSE; |
| f.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, b); |
| Assert.assertEquals(b, f.getProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES)); |
| } |
| |
| protected static void setSupportDTD(XMLInputFactory f, boolean state) throws XMLStreamException { |
| Boolean b = state ? Boolean.TRUE : Boolean.FALSE; |
| f.setProperty(XMLInputFactory.SUPPORT_DTD, b); |
| Assert.assertEquals(b, f.getProperty(XMLInputFactory.SUPPORT_DTD)); |
| } |
| |
| protected static boolean setSupportExternalEntities(XMLInputFactory f, boolean state) throws XMLStreamException { |
| Boolean b = state ? Boolean.TRUE : Boolean.FALSE; |
| try { |
| f.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, b); |
| Object act = f.getProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES); |
| return (act instanceof Boolean) && ((Boolean) act).booleanValue() == state; |
| } catch (IllegalArgumentException e) { |
| /* |
| * Let's assume, then, that the property (or specific value for it) |
| * is NOT supported... |
| */ |
| return false; |
| } |
| } |
| |
| protected static void setResolver(XMLInputFactory f, XMLResolver resolver) throws XMLStreamException { |
| f.setProperty(XMLInputFactory.RESOLVER, resolver); |
| } |
| |
| protected static boolean setReportCData(XMLInputFactory f, boolean state) throws XMLStreamException { |
| |
| Boolean b = state ? Boolean.TRUE : Boolean.FALSE; |
| if (f.isPropertySupported(PROP_REPORT_CDATA)) { |
| f.setProperty(PROP_REPORT_CDATA, b); |
| return true; |
| } |
| return false; |
| } |
| |
| /* |
| * ////////////////////////////////////////////////// // Stream reader |
| * accessors ////////////////////////////////////////////////// |
| */ |
| |
| /** |
| * Method that not only gets currently available text from the reader, but |
| * also checks that its consistenly accessible using different StAX methods. |
| */ |
| protected static String getAndVerifyText(XMLStreamReader sr) throws XMLStreamException { |
| String text = sr.getText(); |
| |
| /* |
| * 05-Apr-2006, TSa: Although getText() is available for DTD and |
| * ENTITY_REFERENCE, getTextXxx() are not. Thus, can not do more checks |
| * for those types. |
| */ |
| int type = sr.getEventType(); |
| if (type != ENTITY_REFERENCE && type != DTD) { |
| Assert.assertNotNull("getText() should never return null.", text); |
| int expLen = sr.getTextLength(); |
| /* |
| * Hmmh. Can only return empty text for CDATA (since empty blocks |
| * are legal). |
| */ |
| /* |
| * !!! 01-Sep-2004, TSa: note: theoretically, in coalescing mode, it |
| * could be possible to have empty CDATA section(s) get converted to |
| * CHARACTERS, which would be empty... may need to enhance this to |
| * check that mode is not coalescing? Or something |
| */ |
| if (sr.getEventType() == CHARACTERS) { |
| if (expLen == 0) { |
| Assert.fail("Stream reader should never return empty Strings."); |
| } |
| } |
| Assert.assertEquals(expLen, text.length(), "Expected text length of " + expLen + ", got " + text.length()); |
| char[] textChars = sr.getTextCharacters(); |
| int start = sr.getTextStart(); |
| String text2 = new String(textChars, start, expLen); |
| Assert.assertEquals("Expected getText() and getTextCharacters() to return same value for event of type (" + tokenTypeDesc(sr.getEventType()) + ")", |
| text, text2); |
| } else { // DTD or ENTITY_REFERENCE |
| // not sure if null is legal for these either, but... |
| if (text == null) { // let's prevent an NPE at caller |
| text = ""; |
| } |
| } |
| return text; |
| } |
| |
| protected static String getAllText(XMLStreamReader sr) throws XMLStreamException { |
| StringBuffer sb = new StringBuffer(); |
| while (true) { |
| int tt = sr.getEventType(); |
| if (tt != CHARACTERS && tt != SPACE) { |
| break; |
| } |
| sb.append(getAndVerifyText(sr)); |
| sr.next(); |
| } |
| return sb.toString(); |
| } |
| |
| protected static String getAllCData(XMLStreamReader sr) throws XMLStreamException { |
| StringBuffer sb = new StringBuffer(); |
| while (true) { |
| /* |
| * Note: CDATA sections CAN be reported as CHARACTERS, but not as |
| * SPACE |
| */ |
| int tt = sr.getEventType(); |
| if (tt != CHARACTERS && tt != CDATA) { |
| break; |
| } |
| sb.append(getAndVerifyText(sr)); |
| sr.next(); |
| } |
| return sb.toString(); |
| } |
| |
| /* |
| * ////////////////////////////////////////////////// // Derived assert/fail |
| * methods ////////////////////////////////////////////////// |
| */ |
| |
| protected static void assertTokenType(int expType, int actType) { |
| if (expType == actType) { |
| return; |
| } |
| Assert.fail("Expected token " + tokenTypeDesc(expType) + "; got " + tokenTypeDesc(actType) + "."); |
| } |
| |
| protected static void assertTokenType(int expType, int actType, XMLStreamReader sr) { |
| if (expType == actType) { |
| return; |
| } |
| Assert.fail("Expected token " + tokenTypeDesc(expType) + "; got " + tokenTypeDesc(actType, sr) + "."); |
| } |
| |
| protected static void assertTextualTokenType(int actType) { |
| if (actType != CHARACTERS && actType != SPACE && actType != CDATA) { |
| Assert.fail("Expected textual token (CHARACTERS, SPACE or CDATA)" + "; got " + tokenTypeDesc(actType) + "."); |
| } |
| } |
| |
| protected static void failStrings(String msg, String exp, String act) { |
| // !!! TODO: Indicate position where Strings differ |
| Assert.fail(msg + ": expected " + quotedPrintable(exp) + ", got " + quotedPrintable(act)); |
| } |
| |
| /** |
| * Specific method makes sense, since earlier it was not clear whether null |
| * or empty string (or perhaps both) would be the right answer when there is |
| * no prefix. |
| * <p> |
| * However: as per javadocs of {@link XMLStreamReader#getPrefix}, from JDK |
| * 1.6 indicate, the current understanding is that <b>null</b> is the |
| * ultimate right answer here. |
| */ |
| protected static void assertNoPrefix(XMLStreamReader sr) throws XMLStreamException { |
| String prefix = sr.getPrefix(); |
| if (prefix != null) { |
| if (prefix.length() != 0) { |
| Assert.fail("Current element should not have a prefix: got '" + prefix + "'"); |
| } else { |
| Assert.fail("Expected null to signify missing prefix (see XMLStreamReader#getPrefix() JavaDocs): got empty String"); |
| } |
| } |
| } |
| |
| protected static void assertNoAttrPrefix(String attrPrefix) throws XMLStreamException { |
| if (attrPrefix != null) { |
| if (attrPrefix.length() != 0) { |
| Assert.fail("Attribute should not have a prefix: got '" + attrPrefix + "'"); |
| } else { |
| Assert.fail("Expected null to signify missing attribute prefix (see XMLStreamReader#getAttributePrefix() JavaDocs): got empty String"); |
| } |
| } |
| } |
| |
| /** |
| * Similar to {@link #assertNoPrefix}, but here we do know that unbound |
| * namespace URI should be indicated as empty String. |
| */ |
| protected static void assertNoNsURI(XMLStreamReader sr) throws XMLStreamException { |
| String uri = sr.getNamespaceURI(); |
| if (uri == null) { |
| Assert.fail("Expected empty String to indicate \"no namespace\": got null"); |
| } else if (uri.length() != 0) { |
| Assert.fail("Expected empty String to indicate \"no namespace\": got '" + uri + "'"); |
| } |
| } |
| |
| protected static void assertNoAttrNamespace(String attrNsURI) throws XMLStreamException { |
| if (attrNsURI == null) { |
| // refer to 6903561; accept null for now. |
| // fail("Expected empty String to indicate \"no namespace\" (for attribute): got null"); |
| } else if (attrNsURI.length() != 0) { |
| Assert.fail("Expected empty String to indicate \"no namespace\" (for attribute): got '" + attrNsURI + "'"); |
| } |
| } |
| |
| protected static void assertNoPrefixOrNs(XMLStreamReader sr) throws XMLStreamException { |
| assertNoPrefix(sr); |
| assertNoNsURI(sr); |
| } |
| |
| /** |
| * Helper assertion that assert that the String is either null or empty |
| * (""). |
| */ |
| protected static void assertNullOrEmpty(String str) { |
| if (str != null && str.length() > 0) { |
| Assert.fail("Expected String to be empty or null; was '" + str + "' (length " + str.length() + ")"); |
| } |
| } |
| |
| /* |
| * ////////////////////////////////////////////////// // Debug/output |
| * helpers ////////////////////////////////////////////////// |
| */ |
| |
| protected static String tokenTypeDesc(int tt) { |
| String desc = (String) mTokenTypes.get(new Integer(tt)); |
| if (desc == null) { |
| return "[" + tt + "]"; |
| } |
| return desc; |
| } |
| |
| protected static String tokenTypeDesc(XMLEvent evt) { |
| return tokenTypeDesc(evt.getEventType()); |
| } |
| |
| final static int MAX_DESC_TEXT_CHARS = 8; |
| |
| protected static String tokenTypeDesc(int tt, XMLStreamReader sr) { |
| String desc = tokenTypeDesc(tt); |
| // Let's show first 8 chars or so... |
| if (tt == CHARACTERS || tt == SPACE || tt == CDATA) { |
| String str = sr.getText(); |
| if (str.length() > MAX_DESC_TEXT_CHARS) { |
| desc = "\"" + str.substring(0, MAX_DESC_TEXT_CHARS) + "\"[...]"; |
| } else { |
| desc = "\"" + desc + "\""; |
| } |
| desc = " (" + desc + ")"; |
| } |
| return desc; |
| } |
| |
| protected static String valueDesc(String value) { |
| if (value == null) { |
| return "[NULL]"; |
| } |
| return "\"" + value + "\""; |
| } |
| |
| protected static String printable(char ch) { |
| if (ch == '\n') { |
| return "\\n"; |
| } |
| if (ch == '\r') { |
| return "\\r"; |
| } |
| if (ch == '\t') { |
| return "\\t"; |
| } |
| if (ch == ' ') { |
| return "_"; |
| } |
| if (ch > 127 || ch < 32) { |
| StringBuffer sb = new StringBuffer(6); |
| sb.append("\\u"); |
| String hex = Integer.toHexString((int) ch); |
| for (int i = 0, len = 4 - hex.length(); i < len; i++) { |
| sb.append('0'); |
| } |
| sb.append(hex); |
| return sb.toString(); |
| } |
| return null; |
| } |
| |
| protected static String printable(String str) { |
| if (str == null || str.length() == 0) { |
| return str; |
| } |
| |
| int len = str.length(); |
| StringBuffer sb = new StringBuffer(len + 64); |
| for (int i = 0; i < len; ++i) { |
| char c = str.charAt(i); |
| String res = printable(c); |
| if (res == null) { |
| sb.append(c); |
| } else { |
| sb.append(res); |
| } |
| } |
| return sb.toString(); |
| } |
| |
| protected static String quotedPrintable(String str) { |
| if (str == null || str.length() == 0) { |
| return "[0]''"; |
| } |
| return "[len: " + str.length() + "] '" + printable(str) + "'"; |
| } |
| |
| protected void reportNADueToProperty(String method, String prop) { |
| String clsName = getClass().getName(); |
| /* |
| * 27-Sep-2005, TSa: Should probably use some other mechanism for |
| * reporting this. Does JUnit have something applicable? |
| */ |
| System.err.println("Skipping " + clsName + "#" + method + ": property '" + prop + "' (or one of its values) not supported."); |
| } |
| |
| protected void reportNADueToNS(String method) { |
| reportNADueToProperty(method, "IS_NAMESPACE_AWARE"); |
| } |
| |
| protected void reportNADueToExtEnt(String method) { |
| reportNADueToProperty(method, "IS_SUPPORTING_EXTERNAL_ENTITIES"); |
| } |
| |
| protected void reportNADueToEntityExpansion(String method, int type) { |
| String clsName = getClass().getName(); |
| String msg = (type > 0) ? " (next event: " + tokenTypeDesc(type) + ")" : ""; |
| System.err.println("Skipping " + clsName + "#" + method + ": entity expansion does not seem to be functioning properly" + msg + "."); |
| } |
| } |