diff options
Diffstat (limited to 'test/java/src/org/apache/qetest/xalanj2/TransformStateTestlet.java')
-rw-r--r-- | test/java/src/org/apache/qetest/xalanj2/TransformStateTestlet.java | 493 |
1 files changed, 493 insertions, 0 deletions
diff --git a/test/java/src/org/apache/qetest/xalanj2/TransformStateTestlet.java b/test/java/src/org/apache/qetest/xalanj2/TransformStateTestlet.java new file mode 100644 index 0000000..9a4e791 --- /dev/null +++ b/test/java/src/org/apache/qetest/xalanj2/TransformStateTestlet.java @@ -0,0 +1,493 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * $Id$ + */ + +/* + * + * TransformStateTestlet.java + * + */ +package org.apache.qetest.xalanj2; + +import java.util.Hashtable; + +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.sax.SAXResult; +import javax.xml.transform.stream.StreamSource; + +import org.apache.qetest.Datalet; +import org.apache.qetest.Logger; +import org.apache.qetest.LoggingHandler; +import org.apache.qetest.QetestUtils; +import org.apache.qetest.TestletImpl; +import org.apache.qetest.XMLFileLogger; +import org.apache.xalan.templates.ElemTemplate; +import org.apache.xalan.templates.ElemTemplateElement; +import org.apache.xalan.transformer.TransformState; +import org.apache.xalan.transformer.TransformerClient; +import org.w3c.dom.Node; +import org.w3c.dom.traversal.NodeIterator; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; + +/** + * Testlet for testing TransformState of a stylesheet. + * + * In progress - data-driven tests for tooling API's. + * Currently uses cheap-o validation method + * + * @author Shane_Curcuru@lotus.com + * @version $Id$ + */ +public class TransformStateTestlet extends TestletImpl + implements ContentHandler, TransformerClient + +{ + // Initialize our classname for TestletImpl's main() method + static { thisClassName = "org.apache.qetest.xsl.TransformStateTestlet"; } + + // Initialize our defaultDatalet + { defaultDatalet = (Datalet)new TransformStateDatalet(); } + + /** + * Class-wide copy of TransformStateDatalet. + * This is used in execute() and in various worker methods + * underneath the ContentHandler interface. + */ + protected TransformStateDatalet tsDatalet = null; + + /** + * Accesor method for a brief description of this test. + * + * @return String describing what this TransformStateTestlet does. + */ + public String getDescription() + { + return "TransformStateTestlet"; + } + + + /** + * Run this TransformStateTestlet: execute it's test and return. + * + * @param Datalet to use as data point for the test. + */ + public void execute(Datalet d) + { + try + { + tsDatalet = (TransformStateDatalet)d; + } + catch (ClassCastException e) + { + logger.checkErr("Datalet provided is not a TransformStateDatalet; cannot continue with " + d); + return; + } + + logger.logMsg(Logger.STATUSMSG, "About to test: " + + (null == tsDatalet.inputName + ? tsDatalet.xmlName + : tsDatalet.inputName)); + try + { + // Perform the transform + TransformerFactory factory = TransformerFactory.newInstance(); + logger.logMsg(Logger.TRACEMSG, "---- About to newTransformer " + QetestUtils.filenameToURL(tsDatalet.inputName)); + Transformer transformer = factory.newTransformer(new StreamSource(QetestUtils.filenameToURL(tsDatalet.inputName))); + logger.logMsg(Logger.TRACEMSG, "---- About to transform " + QetestUtils.filenameToURL(tsDatalet.xmlName) + " into: SAXResult(this-no disk output)"); + + // Note most validation happens here: we get ContentHandler + // callbacks from being in the SAXResult, and that's where + // we do our validation + transformer.transform(new StreamSource(QetestUtils.filenameToURL(tsDatalet.xmlName)), + new SAXResult(this)); // use us to handle result + + logger.logMsg(Logger.INFOMSG, "---- Afterwards, this.transformState=" + transformState); + } + catch (Throwable t) + { + // Put the logThrowable first, so it appears before + // the Fail record, and gets color-coded + logger.logThrowable(Logger.ERRORMSG, t, getDescription() + " " + tsDatalet.getDescription()); + logger.checkFail(getDescription() + " " + tsDatalet.getDescription() + + " threw: " + t.toString()); + return; + } + } + ////////////////// partially Implement LoggingHandler ////////////////// + /** Cheap-o string representation of last event we got. */ + protected String lastItem = LoggingHandler.NOTHING_HANDLED; + + + /** + * Accessor for string representation of last event we got. + * @param s string to set + */ + protected void setLastItem(String s) + { + lastItem = s; + } + + + /** + * Accessor for string representation of last event we got. + * @return last event string we had + */ + public String getLast() + { + return lastItem; + } + + /** + * Worker routine to validate a TransformState based on an event/value. + * Note: this may not be threadsafe! + * //@todo actually add validation code - just logs out now + * @param ts TransformState to validate, if null, just logs it + * @param event our String constant of START_ELEMENT, etc. + * @param value any String value of the current event + */ + protected void validateTransformState(TransformState ts, String event, String value) + { + if(null == transformState) + { + // We should never have a null TransformState since the + // transformer should have always filled it in + logger.checkErr("validateTransformState(ts-NULL!, " + event + ")=" + value); + return; + } + logTransformStateDump(logger, Logger.INFOMSG, ts, event, value); + + // Cheap-o validation: only validate items on column 99 + if (99 == ts.getCurrentElement().getColumnNumber()) + { + int line = ts.getCurrentElement().getLineNumber(); + // Get cheap-o validation from the datalet for this line.. + String exp = (String)tsDatalet.validate99.get(line + ".current.name"); + // .. If there's an expected value for this line's property.. + if (null != exp) + // .. Then check if it's equal and report pass/fail + checkString(ts.getCurrentTemplate().getName().toString(), exp, + "Validate L" + line + "C99 .current.name"); + + exp = (String)tsDatalet.validate99.get(line + ".current.match"); + if (null != exp) + checkString(ts.getCurrentTemplate().getMatch().getPatternString(), exp, + "Validate L" + line + "C99 .current.match"); + + exp = (String)tsDatalet.validate99.get(line + ".current.mode"); + if (null != exp) + checkString(ts.getCurrentTemplate().getMode().toString(), exp, + "Validate L" + line + "C99 .current.mode"); + + + exp = (String)tsDatalet.validate99.get(line + ".matched.name"); + if (null != exp) + checkString(ts.getMatchedTemplate().getName().toString(), exp, + "Validate L" + line + "C99 .matched.name"); + + exp = (String)tsDatalet.validate99.get(line + ".matched.match"); + if (null != exp) + checkString(ts.getMatchedTemplate().getMatch().getPatternString(), exp, + "Validate L" + line + "C99 .matched.match"); + + exp = (String)tsDatalet.validate99.get(line + ".matched.mode"); + if (null != exp) + checkString(ts.getMatchedTemplate().getMode().toString(), exp, + "Validate L" + line + "C99 .matched.mode"); + } + +/*********************************************** +// Comment out validation using ExpectedObjects since they hang 28-Jun-01 -sc + // See if we have a matching expected state for this event + //@todo use event string as part of hashkey!!! + String marker = ExpectedTransformState.getHashKey(ts); + // Add on the event as well; see ExpectedTransformState.getHashKey() + // for why we have to do this separately + marker += ExpectedTransformState.SEP + event; + ExpectedTransformState ets = (ExpectedTransformState)tsDatalet.expectedTransformStates.get(marker); + logger.logMsg(Logger.TRACEMSG, "ETS-HACK:" + marker + "=" + ets); + if (null != ets) + { + // Ask it to validate itself as needed + synchronized(ets) // voodoo: attempt to solve hang problems + { + ExpectedObjectCheckService.check(logger, ts, ets, "Compare ExpectedTransformState of " + marker); + } + } +// Comment out validation using ExpectedObjects since they hang 28-Jun-01 -sc +***********************************************/ + } + + private void checkString(String act, String exp, String comment) + { + if (exp.equals(act)) + logger.checkPass(comment); + else + logger.checkFail(comment + "; act(" + act + ") exp(" + exp + ")"); + } + + ////////////////// Utility methods for TransformState ////////////////// + /** + * Utility method to dump data from TransformState. + * @return String describing various bits of the state + */ + protected void logTransformStateDump(Logger logger, int traceLoggingLevel, + TransformState ts, String event, String value) + { + String elemName = "transformStateDump"; + Hashtable attrs = new Hashtable(); + attrs.put("event", event); + if (null != value) + attrs.put("value", value); + attrs.put("location", "L" + ts.getCurrentElement().getLineNumber() + + "C" + ts.getCurrentElement().getColumnNumber()); + + StringBuffer buf = new StringBuffer(); + ElemTemplateElement elem = ts.getCurrentElement(); // may be actual or default template + buf.append(" <currentElement>" + + XMLFileLogger.escapeString(XalanDumper.dump(elem, XalanDumper.DUMP_DEFAULT)) + "</currentElement>"); + + ElemTemplate currentTempl = ts.getCurrentTemplate(); // Actual current template + buf.append("\n <currentTemplate>" + + XMLFileLogger.escapeString(XalanDumper.dump(currentTempl, XalanDumper.DUMP_DEFAULT)) + "</currentTemplate>"); + + ElemTemplate matchTempl = ts.getMatchedTemplate(); // Actual matched template + if (matchTempl != currentTempl) + buf.append("\n <matchedTemplate>" + + XMLFileLogger.escapeString(XalanDumper.dump(matchTempl, XalanDumper.DUMP_DEFAULT)) + "</matchedTemplate>"); + + // Optimization: skip most logging when on endElement + if (!END_ELEMENT.equals(event)) + { + Node n = ts.getCurrentNode(); // current context node in source tree + buf.append("\n <currentNode>" + + XMLFileLogger.escapeString(XalanDumper.dump(n, XalanDumper.DUMP_DEFAULT)) + "</currentNode>"); + + Node matchedNode = ts.getMatchedNode(); // node in source matched via getMatchedTemplate + // Optimization: only output if different + if (n != matchedNode) + buf.append("\n <matchedNode>" + + XMLFileLogger.escapeString(XalanDumper.dump(matchedNode, XalanDumper.DUMP_DEFAULT)) + "</matchedNode>"); + + NodeIterator contextNodeList = ts.getContextNodeList(); // current context node list + Node rootNode = contextNodeList.getRoot(); + // Optimization: only output if different + if (n != rootNode) + buf.append("\n <contextNodeListGetRoot>" + + XMLFileLogger.escapeString(XalanDumper.dump(rootNode, XalanDumper.DUMP_DEFAULT)) + "</contextNodeListGetRoot>"); + + Transformer transformer = ts.getTransformer(); // current transformer working + // Optimization: only dump transformer at startElement to save space + if (START_ELEMENT.equals(event)) + { + buf.append("\n <transformer>" + + XMLFileLogger.escapeString(XalanDumper.dump(transformer, XalanDumper.DUMP_DEFAULT)) + "</transformer>"); + } + else + { + // Just log error case if transformer is ever null + if (null == transformer) + buf.append("\n <transformer>" + + "ERROR! Transformer was null!" + "</transformer>"); + } + } + + logger.logElement(traceLoggingLevel, elemName, attrs, buf.toString()); + } + + //----------------------------------------------------------- + //---- Implement the TransformerClient interface + //----------------------------------------------------------- + /** + * A TransformState object that we use to log state data. + * This is the equivalent of the defaultHandler, even though + * that's not really the right metaphor. This class could be + * upgraded to have both a default ContentHandler and a + * defaultTransformerClient in the future. + */ + protected TransformState transformState = null; + + + /** + * Implement TransformerClient.setTransformState interface. + * Pass in a reference to a TransformState object, which + * can be used during SAX ContentHandler events to obtain + * information about he state of the transformation. This + * method will be called before each startDocument event. + * + * @param ts A reference to a TransformState object + */ + public void setTransformState(TransformState ts) + { + transformState = ts; + } + + //----------------------------------------------------------- + //---- Implement the ContentHandler interface + //----------------------------------------------------------- + protected final String START_ELEMENT = "startElement:"; + protected final String END_ELEMENT = "endElement:"; + protected final String CHARACTERS = "characters:"; + + // String Locator.getPublicId() null if none available + // String Locator.getPublicId() null if none available + // int Locator.getLineNumber() -1 if none available + // int Locator.getColumnNumber() -1 if none available + protected Locator ourLocator = null; + + /** + * Implement ContentHandler.setDocumentLocator. + * If available, this should always be called prior to a + * startDocument event. + */ + public void setDocumentLocator (Locator locator) + { + // Note: this implies this class is !not! threadsafe + ourLocator = locator; // future use + if (null != locator) + setLastItem("setDocumentLocator.getSystemId():" + locator.getSystemId()); + else + setLastItem("setDocumentLocator:NULL"); + logger.logMsg(Logger.INFOMSG, getLast()); + } + + + /** Cached TransformState object during lifetime startDocument -> endDocument. */ + // Note: is this correct? Will it always be the same object? + protected TransformState docCachedTransformState = null; + /** Implement ContentHandler.startDocument. */ + public void startDocument () + throws SAXException + { + setLastItem("startDocument"); + logger.logMsg(Logger.INFOMSG, getLast()); + // Comment out check call since the spec'd functionality + // is very likely to change to *not* be in startDocument 19-Jun-01 -sc + // logger.check((null != transformState), true, "transformState non-null in startDocument"); + logger.logMsg(Logger.STATUSMSG, "transformState in startDocument is: " + transformState); + docCachedTransformState = transformState; // see endDocument + } + + + /** Implement ContentHandler.endDocument. */ + public void endDocument() + throws SAXException + { + setLastItem("endDocument"); + logger.logMsg(Logger.INFOMSG, getLast()); + // Comment out check call since the spec'd functionality + // is very likely to change to *not* be in startDocument 19-Jun-01 -sc + // logger.checkObject(docCachedTransformState, transformState, + // "transformState same in endDocument as startDocument"); // see startDocument + logger.logMsg(Logger.STATUSMSG, "transformState in endDocument is: " + transformState); + docCachedTransformState = null; + } + + + /** Implement ContentHandler.startPrefixMapping. */ + public void startPrefixMapping (String prefix, String uri) + throws SAXException + { + setLastItem("startPrefixMapping: " + prefix + ", " + uri); + logger.logMsg(Logger.INFOMSG, getLast()); + } + + + /** Implement ContentHandler.endPrefixMapping. */ + public void endPrefixMapping (String prefix) + throws SAXException + { + setLastItem("endPrefixMapping: " + prefix); + logger.logMsg(Logger.INFOMSG, getLast()); + } + + + /** Implement ContentHandler.startElement. */ + public void startElement (String namespaceURI, String localName, + String qName, Attributes atts) + throws SAXException + { + StringBuffer buf = new StringBuffer(); + buf.append(namespaceURI + ", " + + localName + ", " + qName + ";"); + + int n = atts.getLength(); + for(int i = 0; i < n; i++) + { + buf.append(", " + atts.getQName(i)); + } + setLastItem(START_ELEMENT + buf.toString()); + + validateTransformState(transformState, START_ELEMENT, buf.toString()); + } + + + /** Implement ContentHandler.endElement. */ + public void endElement (String namespaceURI, String localName, String qName) + throws SAXException + { + setLastItem(END_ELEMENT + namespaceURI + ", " + localName + ", " + qName); + + validateTransformState(transformState, END_ELEMENT, null); + } + + + /** Implement ContentHandler.characters. */ + public void characters (char ch[], int start, int length) + throws SAXException + { + String s = new String(ch, start, length); + setLastItem(CHARACTERS + "\"" + s + "\""); + + validateTransformState(transformState, CHARACTERS, s); + } + + + /** Implement ContentHandler.ignorableWhitespace. */ + public void ignorableWhitespace (char ch[], int start, int length) + throws SAXException + { + setLastItem("ignorableWhitespace: len " + length); + logger.logMsg(Logger.INFOMSG, getLast()); + } + + + /** Implement ContentHandler.processingInstruction. */ + public void processingInstruction (String target, String data) + throws SAXException + { + setLastItem("processingInstruction: " + target + ", " + data); + logger.logMsg(Logger.INFOMSG, getLast()); + } + + + /** Implement ContentHandler.skippedEntity. */ + public void skippedEntity (String name) + throws SAXException + { + setLastItem("skippedEntity: " + name); + logger.logMsg(Logger.INFOMSG, getLast()); + } + +} // end of class TransformStateTestlet + |