summaryrefslogtreecommitdiff
path: root/test/java/src/org/apache/qetest/xalanj2/TransformStateTestlet.java
diff options
context:
space:
mode:
Diffstat (limited to 'test/java/src/org/apache/qetest/xalanj2/TransformStateTestlet.java')
-rw-r--r--test/java/src/org/apache/qetest/xalanj2/TransformStateTestlet.java493
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
+