| /* |
| * The Apache Software License, Version 1.1 |
| * |
| * |
| * Copyright (c) 2001-2003 The Apache Software Foundation. All rights |
| * reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * 3. The end-user documentation included with the redistribution, |
| * if any, must include the following acknowledgment: |
| * "This product includes software developed by the |
| * Apache Software Foundation (http://www.apache.org/)." |
| * Alternately, this acknowledgment may appear in the software itself, |
| * if and wherever such third-party acknowledgments normally appear. |
| * |
| * 4. The names "Xalan" and "Apache Software Foundation" must |
| * not be used to endorse or promote products derived from this |
| * software without prior written permission. For written |
| * permission, please contact apache@apache.org. |
| * |
| * 5. Products derived from this software may not be called "Apache", |
| * nor may "Apache" appear in their name, without prior written |
| * permission of the Apache Software Foundation. |
| * |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR |
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| * ==================================================================== |
| * |
| * This software consists of voluntary contributions made by many |
| * individuals on behalf of the Apache Software Foundation and was |
| * originally based on software copyright (c) 2000, Lotus |
| * Development Corporation., http://www.lotus.com. For more |
| * information on the Apache Software Foundation, please see |
| * <http://www.apache.org/>. |
| */ |
| |
| package org.apache.qetest; |
| |
| import java.io.File; |
| import java.util.Enumeration; |
| import java.util.Hashtable; |
| import java.util.Properties; |
| import java.util.StringTokenizer; |
| |
| /** |
| * Datalet representing set of paths to files: input, output, gold. |
| * |
| * <p>This is a fairly simplistic Datalet implementation that's |
| * useful for the many programs where the test requires reading |
| * an input file, performing an operation with the program, and |
| * then verifying an output file.</p> |
| * |
| * <p>We normally operate on local path/filenames, since the Java |
| * SDK's implementation of URLs and File objects is so poor at |
| * handling proper URI/URL's according to the RFCs. A potential |
| * future improvement is to add convenience accessor methods, like |
| * getInputName() (just the bare filename) etc. but I'm not quite |
| * convinced we need them yet.</p> |
| * |
| * @see FileTestlet |
| * @see FileTestletDriver |
| * @see FileDataletManager |
| * @author Shane_Curcuru@us.ibm.com |
| * @version $Id$ |
| */ |
| public class FileDatalet implements Datalet |
| { |
| /** Path of the location to get input resources from. */ |
| protected String input = "tests/defaultInput"; |
| |
| /** Accessor method for input; never null. */ |
| public String getInput() { return input; } |
| |
| /** Path to put actual output resources into. */ |
| protected String output = "output/defaultOutput"; |
| |
| /** Accessor method for output; never null. */ |
| public String getOutput() { return output; } |
| |
| /** Path of the location to get gold or reference resources from. */ |
| protected String gold = "gold/defaultGold"; |
| |
| /** Accessor method for gold; never null. */ |
| public String getGold() { return gold; } |
| |
| |
| /** |
| * Worker method to validate the files/dirs we represent. |
| * |
| * <p>By default, ensures that the input already exists in some |
| * format; and attempts to create the output. If asked to be |
| * strict, then we will fail if the output cannot be created, |
| * and we additionally will attempt to create the gold and |
| * will fail if it can't be created.</p> |
| * |
| * <p>Note that we only attempt to create the gold if asked to |
| * be strict, since users may simply want to run a 'crash test' |
| * and get all {@link org.apache.qetest.Logger#AMBG_RESULT AMBG} |
| * results when prototyping new tests.</p> |
| * |
| * @param strict if true, requires that output and gold must |
| * be created; otherwise they're optional |
| * @return false if input doesn't already exist; true otherwise |
| */ |
| public boolean validate(boolean strict) |
| { |
| File f = new File(getInput()); |
| if (!f.exists()) |
| return false; |
| |
| f = new File(getOutput()); |
| if (!f.exists()) |
| { |
| if (!f.mkdirs()) |
| { |
| // Only fail if asked to be strict |
| if (strict) |
| return false; |
| } |
| } |
| |
| f = new File(getGold()); |
| if (!f.exists()) |
| { |
| // For gold, only attempt to mkdirs if asked... |
| if (strict) |
| { |
| // ...Only fail here if we can't |
| if (!f.mkdirs()) |
| return false; |
| } |
| } |
| // If we get here, we're happy either way |
| return true; |
| } |
| |
| |
| /** |
| * Generic placeholder for any additional options. |
| * |
| * <p>This allows FileDatalets to support additional kinds |
| * of tests, like performance tests, without having to change |
| * this data model. These options can serve as a catch-all |
| * for any new properties or options or what-not that new |
| * tests need, without having to change how the most basic |
| * member variables here work.</p> |
| * <p>Note that while this needs to be a Properties object to |
| * take advantage of the parent/default behavior in |
| * getProperty(), this doesn't necessarily mean they can only |
| * store Strings; however only String-valued items can make |
| * use of the default properties mechanisim.</p> |
| * |
| * <p>Default is a null object; note that getOptions() will |
| * never return null, but will create a blank Properties |
| * block if needed.</p> |
| */ |
| protected Properties options = null; |
| |
| /** |
| * Accessor method for optional properties. |
| * |
| * Should never return null; if it has no options then |
| * it will create a blank Properties block to return. |
| */ |
| public Properties getOptions() |
| { |
| if (null == options) |
| options = new Properties(); |
| |
| return options; |
| } |
| |
| /** |
| * Accessor method for optional properties; settable. |
| * <p>Note this method creates a new Properties that simply |
| * defaults to the passed in properties instead of cloning it.</p> |
| * <p>This used to simply assign this variable to the passed |
| * in variable, but that leads to problems when errant |
| * Testlets mutate their Datalet's Options, which can result |
| * in the master test's testProps getting changed.</p> |
| * |
| * @param p Properties to set as our defaults; if null, we |
| * do not change anything |
| */ |
| public void setOptions(Properties p) |
| { |
| if (null != p) |
| options = new Properties(p); |
| } |
| |
| |
| /** |
| * Accessor method for optional properties that are ints. |
| * Convenience method to take care of parse/cast to int. |
| * |
| * @param name of property to try to get |
| * @param defValue value if property not available |
| * @return integer value of property, or the default |
| */ |
| public int getIntOption(String name, int defValue) |
| { |
| if (null == options) |
| return defValue; |
| |
| try |
| { |
| return Integer.parseInt(options.getProperty(name)); |
| } |
| catch (Exception e) |
| { |
| return defValue; |
| } |
| } |
| |
| |
| /** Description of what this Datalet tests. */ |
| protected String description = "FileDatalet: default description"; |
| |
| |
| /** |
| * Accesor method for a brief description of this Datalet. |
| * |
| * @return String describing the specific set of data |
| * this Datalet contains (can often be used as the description |
| * of any check() calls made from the Testlet). |
| */ |
| public String getDescription() |
| { |
| return description; |
| } |
| |
| |
| /** |
| * Accesor method for a brief description of this Datalet. |
| * |
| * @param s description to use for this Datalet. |
| */ |
| public void setDescription(String s) |
| { |
| description = s; |
| } |
| |
| |
| /** |
| * Worker method to auto-set the description of this Datalet. |
| * Conglomeration of input, output, gold values. |
| */ |
| protected void setDescription() |
| { |
| setDescription("input=" + input |
| + " output=" + output |
| + " gold=" + gold); |
| } |
| |
| |
| /** |
| * No argument constructor is a no-op; not very useful. |
| */ |
| public FileDatalet() { /* no-op */ } |
| |
| |
| /** |
| * Initialize this datalet from another FileDatalet which |
| * serves as a 'base' location, and a filename. |
| * |
| * <p>We set each of our input, output, gold to be concatenations |
| * of the base + File.separator + fileName, and also copy |
| * over the options from the base. Note we always attempt to |
| * deal with local path/filename conventions.</p> |
| * |
| * @param base FileDatalet object to serve as base directories |
| * @param fileName to concatenate for each of input/output/gold |
| */ |
| public FileDatalet(FileDatalet base, String fileName) |
| { |
| if ((null == base) || (null == fileName)) |
| throw new IllegalArgumentException("FileDatalet(base, fileName) called with null base!"); |
| |
| StringBuffer buf = new StringBuffer(File.separator + fileName); |
| input = base.getInput() + buf; |
| output = base.getOutput() + buf; |
| gold = base.getGold() + buf; |
| setOptions(base.getOptions()); |
| |
| setDescription(); |
| } |
| |
| |
| /** |
| * Initialize this datalet from a list of paths. |
| * |
| * <p>Our options are not initialized, and left as null.<p> |
| * |
| * @param i path for input |
| * @param o path for output |
| * @param g path for gold |
| */ |
| public FileDatalet(String i, String o, String g) |
| { |
| input = i; |
| output = o; |
| gold = g; |
| |
| setDescription(); |
| } |
| |
| |
| /** |
| * Initialize this datalet from a string and defaults. |
| * |
| * <p>Our options are created as a new Properties block that |
| * defaults to the existing one passed in, then |
| * we parse the string for input, output, gold, and |
| * optionally add additional args to the options.</p> |
| * |
| * @param args command line to initialize from |
| * @param defaults for our options |
| */ |
| public FileDatalet(String args, Properties defaults) |
| { |
| options = new Properties(defaults); |
| |
| StringTokenizer st = new StringTokenizer(args); |
| |
| // Fill in as many items as we can; leave as default otherwise |
| // Note that order is important! |
| if (st.hasMoreTokens()) |
| { |
| input = st.nextToken(); |
| if (st.hasMoreTokens()) |
| { |
| output = st.nextToken(); |
| if (st.hasMoreTokens()) |
| { |
| gold = st.nextToken(); |
| } |
| } |
| } |
| // EXPERIMENTAL add extra name value pairs to our options |
| while (st.hasMoreTokens()) |
| { |
| String name = st.nextToken(); |
| if (st.hasMoreTokens()) |
| { |
| options.put(name, st.nextToken()); |
| } |
| else |
| { |
| // Just put it as 'true' for boolean options |
| options.put(name, "true"); |
| } |
| } |
| } |
| |
| |
| /** |
| * Load fields of this Datalet from a Hashtable. |
| * Caller must provide data for all of our fields. |
| * Additionally, we set all values from the hash into |
| * our options block. |
| * |
| * @param Hashtable to load |
| */ |
| public void load(Hashtable h) |
| { |
| if (null == h) |
| return; //@todo should this have a return val or exception? |
| |
| input = (String)h.get("input"); |
| output = (String)h.get("output"); |
| gold = (String)h.get("gold"); |
| |
| // Also copy over all items in hash to options |
| options = new Properties(); |
| for (Enumeration enum = h.keys(); |
| enum.hasMoreElements(); |
| /* no increment portion */) |
| { |
| String key = (String)enum.nextElement(); |
| options.put(key, h.get(key)); |
| } |
| } |
| |
| |
| /** |
| * Load fields of this Datalet from an array. |
| * Order: input, output, gold. Options are left null. |
| * If too few args, then fields at end of list are left at default value. |
| * @param args array of Strings |
| */ |
| public void load(String[] args) |
| { |
| if (null == args) |
| return; //@todo should this have a return val or exception? |
| |
| try |
| { |
| input = args[0]; |
| output = args[1]; |
| gold = args[2]; |
| } |
| catch (ArrayIndexOutOfBoundsException aioobe) |
| { |
| // No-op, leave remaining items as default |
| } |
| } |
| |
| } // end of class FileDatalet |
| |