/* * 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$ */ package org.apache.qetest.xsl; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.Properties; import java.util.Vector; import org.apache.qetest.Logger; /** * Simple services for getting lists of StylesheetDatalets. * * * @author shane_curcuru@us.ibm.com * @version $Id$ */ public abstract class StylesheetDataletManager // provide static services only { /** * Token in xsl file denoting the text of an expected exception. * Used in getInfoItem. */ public static final String INFOITEM_EXPECTED_EXCEPTION = "ExpectedException:"; /** * Get specified information about the datalet. * *

Note that different kinds of information may be read * or discovered in different ways.

* *

Currently only implemented for * INFOITEM_EXPECTED_EXCEPTION.

* * @param logger to report problems to * @param datalet to get information about * @param infoItem to get information about * @return Vector of object(s) of appropriate type; * or null if error */ public static Vector getInfoItem(Logger logger, StylesheetDatalet datalet, String infoItem) { if ((null == datalet) || (null == infoItem)) { logger.logMsg(Logger.ERRORMSG, "getTestInfo called with null datalet or infoItem!"); return null; } if (INFOITEM_EXPECTED_EXCEPTION.equals(infoItem)) { return getExpectedException(logger, datalet); } else { logger.logMsg(Logger.WARNINGMSG, "getTestInfo unsupported infoItem: " + infoItem); return null; } } /** * Worker method to get expected exception text about a stylesheet. * * Currently parses the inputDir stylesheet for a line that contains * EXPECTED_EXCEPTION inside an xsl comment, on a single line, and * trims off the closing comment -->. * Future work: allow options on datalet to specify some other * expected data in another format - a whole Throwable object to * compare to, or a stacktrace, etc. * * @author Shane Curcuru * @param d Datalet that contains info about the exception * @return Vector of Strings denoting toString of exception(s) * we might expect - any one of them will pass; null if error */ protected static Vector getExpectedException(Logger logger, StylesheetDatalet d) { final String EXPECTED_EXCEPTION_END = "-->"; Vector v = null; // Read in the testName file to see if it's expecting something try { FileReader fr = new FileReader(d.inputName); BufferedReader br = new BufferedReader(fr); for (;;) { String inbuf = br.readLine(); if (inbuf == null) break; // end of file, break out and return int idx = inbuf.indexOf(INFOITEM_EXPECTED_EXCEPTION); if (idx < 0) continue; // not on this line, keep going // The expected exception.getMessage is the rest of the line... String expExc = inbuf.substring(idx + INFOITEM_EXPECTED_EXCEPTION.length(), inbuf.length()); // ... less the trailing " -->" comment end; trimmed int endComment = expExc.indexOf(EXPECTED_EXCEPTION_END); if (endComment > -1) expExc = expExc.substring(0, endComment).trim(); else expExc = expExc.trim(); if (null == v) v = new Vector(); // only create if needed v.addElement(expExc); // Continue reading the file for more potential // expected exception strings - read them all //@todo optimization: stop parsing after xx lines? } // end for (;;) } catch (java.io.IOException ioe) { logger.logMsg(Logger.ERRORMSG, "getExpectedException() threw: " + ioe.toString()); return null; } return v; } /** '[' character, first char in first line of xsltmark fileList. */ public static final String XSLTMARK_CHAR = "["; /** '#' character, comment char in qetest fileList. */ public static final String QETEST_COMMENT_CHAR = "#"; /** * Read in a file specifying a list of files to test. *

File format is determined from first line in file, * which is a little bit dangerous!

*

If first line starts with '[', it's an xsltmark-style * fileList, otherwise it's a qetest-style fileList.

* * @param logger to report problems to * @param fileName String; name of the file * @param desc description; caller's copy changed * @param defaults default properties to potentially add to each datalet * @return Vector of StylesheetDatalets, or null if error */ public static Vector readFileList(Logger logger, String fileName, String desc, Properties defaults) { // Verify the file is there File f = new File(fileName); if (!f.exists()) { logger.logMsg(Logger.ERRORMSG, "readFileList: " + fileName + " does not exist!"); return null; } BufferedReader br = null; String line = null; try { br = new BufferedReader(new FileReader(f)); line = br.readLine(); // read just first line } catch (IOException ioe) { logger.logMsg(Logger.ERRORMSG, "readFileList: " + fileName + " threw: " + ioe.toString()); return null; } // Verify the first line if (line == null) { logger.logMsg(Logger.ERRORMSG, "readFileList: " + fileName + " appears to be blank!"); return null; } // Determine which kind of fileList this is // we support the 'native' org.apache.qetest format, and // alternately the .ini file format used in xsltmark Vector vec = null; if (line.startsWith(XSLTMARK_CHAR)) { // This is an xsltmark .ini style file vec = readXsltmarkFileList(logger, br, line, fileName, desc, defaults); } else if (line.startsWith(QETEST_COMMENT_CHAR)) { // This is a native qetest style file vec = readQetestFileList(logger, br, line, fileName, desc, defaults); } else { logger.logMsg(Logger.WARNINGMSG, "readFileList: " + fileName + " could not determine file type; assuming qetest!"); vec = readQetestFileList(logger, br, line, fileName, desc, defaults); } if (vec.size() == 0) { logger.logMsg(Logger.ERRORMSG, "readFileList: " + fileName + " did not have any non-comment lines!"); return null; } return vec; } /** * Read in a qetest fileList specifying a list of files to test. *

File format is pretty simple:

* *

Most items are optional, but not having them may result * in validation oddities. Future work would be to coordinate * this with various Datalet's implementations of .load() so * that Datalets can do better defaulting of non-provided * items; or maybe so that a user can specific a default 'mask' * of values to use for unspecified items.

* * @param logger to report problems to * @param br BufferedReader to read from * @param firstLine already read from br * @param fileName String; name of the file * @param desc to use of this file * @param defaults default properties to potentially add to each datalet * @return Vector of StylesheetDatalets, or null if error */ protected static Vector readQetestFileList(Logger logger, BufferedReader br, String firstLine, String fileName, String desc, Properties defaults) { final String ABSOLUTE = "absolute"; final String RELATIVE = "relative"; Vector vec = new Vector(); String line = firstLine; // Check if the first line is a comment if (line.startsWith(QETEST_COMMENT_CHAR)) { // Save it as the description desc = line; // Parse the next line try { line = br.readLine(); } catch (IOException ioe) { logger.logMsg(Logger.ERRORMSG, "readQetestFileList: " + fileName + " threw: " + ioe.toString()); return null; } } // Load each line into a StylesheetDatalet for (;;) { // Skip any lines beginning with # comment char or that are blank if ((!line.startsWith(QETEST_COMMENT_CHAR)) && (line.length() > 0)) { // Create a Datalet and initialize with the line's // contents and default properties StylesheetDatalet d = new StylesheetDatalet(line, defaults); // Also pass over the global runId, if set d.options.put("runId", defaults.getProperty("runId")); //@todo Avoid spurious passes when output & gold not specified // needs to detect when StylesheetDatalet doesn't // properly have outputName and goldName set // Add it to our vector vec.addElement(d); } // Read next line and loop try { line = br.readLine(); } catch (IOException ioe2) { // Just force us out of the loop; if we've already // read part of the file, fine logger.logMsg(Logger.WARNINGMSG, "readQetestFileList: " + fileName + " threw: " + ioe2.toString()); break; } if (line == null) break; } // end of for (;;) return vec; } /** * Read in an xsltmark fileList specifying a list of files to test. *

File format is an .ini file like so:

*
     * [avts]
     * input=db100.xml
     * stylesheet=avts.xsl
     * output=avts.out
     * reference=avts.ref
     * iterations=100
     * 
*

Note that additional attributes will be logged as warnings * and will be ignored.

* * @param logger to report problems to * @param br BufferedReader to read from * @param firstLine already read from br * @param fileName String; name of the file * @param desc to use of this file * @param defaults default properties to potentially add to each datalet * @return Vector of StylesheetDatalets, or null if error */ protected static Vector readXsltmarkFileList(Logger logger, BufferedReader br, String firstLine, String fileName, String desc, Properties defaults) { Vector vec = new Vector(); String line = firstLine; // Parse each line and build a datalet for (;;) { // If we're starting a section, parse the section to a datalet if (line.startsWith(XSLTMARK_CHAR)) { StylesheetDatalet d = readXsltmarkDatalet(logger, br, line, fileName, desc, defaults); // Also pass over the global runId, if set d.options.put("runId", defaults.getProperty("runId")); // Add datalet to our vector vec.addElement(d); } // Skip blank lines else if (line.length() == 0) { /* no-op */ } // Ooops, readXsltmarkDatalet didn't work right else { logger.logMsg(Logger.WARNINGMSG, "readXsltmarkFileList parse error, unknown line: " + line); } // Read next line and loop try { line = br.readLine(); } catch (IOException ioe2) { // Just force us out of the loop; if we've already // read part of the file, fine logger.logMsg(Logger.WARNINGMSG, "readXsltmarkFileList: " + fileName + " threw: " + ioe2.toString()); break; } if (line == null) break; } // end of for (;;) return vec; } /** * Read in an xsltmark fileList specifying a list of files to test. *

File format is an .ini file

* * @param logger to report problems to * @param br BufferedReader to read from * @param firstLine already read from br * @param fileName String; name of the file * @param desc to use of this file * @param defaults default properties to potentially add to each datalet * @return StylesheetDatalet with appropriate data, or null if error */ private static StylesheetDatalet readXsltmarkDatalet(Logger logger, BufferedReader br, String firstLine, String fileName, String desc, Properties defaults) { final String STYLESHEET_MARKER = "stylesheet="; final String INPUT_MARKER = "input="; final String OUTPUT_MARKER = "output="; final String REFERENCE_MARKER = "reference="; final String ITERATIONS_MARKER = "iterations="; String line = firstLine; StylesheetDatalet d = new StylesheetDatalet(); // Also pass over the default properties as well d.options = new Properties(defaults); // Parse lines throughout the section to build the datalet for (;;) { // Each .ini file line starts with name of item to fill if (line.startsWith(STYLESHEET_MARKER)) { d.inputName = line.substring(STYLESHEET_MARKER.length()); } else if (line.startsWith(INPUT_MARKER)) { d.xmlName = line.substring(INPUT_MARKER.length()); } else if (line.startsWith(OUTPUT_MARKER)) { d.outputName = line.substring(OUTPUT_MARKER.length()); } else if (line.startsWith(REFERENCE_MARKER)) { d.goldName = line.substring(REFERENCE_MARKER.length()); } else if (line.startsWith(XSLTMARK_CHAR)) { d.setDescription(line); } else if (line.startsWith(ITERATIONS_MARKER)) { d.options.put("iterations", line.substring(ITERATIONS_MARKER.length())); } else if (line.length() == 0) { // Blank lines mean end-of-section; return datalet // This is the primary exit point for this method return d; } else { logger.logMsg(Logger.WARNINGMSG, "readXsltmarkDatalet, unknown line: " + line); } // Read next line and loop try { line = br.readLine(); } catch (IOException ioe2) { // Just force us out of the loop; if we've already // read part of the file, fine logger.logMsg(Logger.WARNINGMSG, "readXsltmarkDatalet: " + fileName + " threw: " + ioe2.toString()); break; } if (line == null) break; } // end of for (;;) logger.logMsg(Logger.ERRORMSG, "readXsltmarkDatalet: " + fileName + " no data found!"); return null; } }