• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the  "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 /*
19  * $Id$
20  */
21 
22 package org.apache.qetest;
23 
24 import java.io.File;
25 import java.io.FilenameFilter;
26 import java.lang.reflect.Constructor;
27 import java.util.Enumeration;
28 import java.util.Properties;
29 import java.util.Vector;
30 
31 /**
32  * Generic Test driver for FileTestlets.
33  *
34  * <p>This driver provides basic services for iterating over a tree
35  * of test files and executing a specified testlet on each test that
36  * is selected by a set of specified filters.  It automatically handles
37  * iteration and optional recursion down the tree, and by default
38  * assumes there are three 'matching' trees for inputs, golds, and
39  * creates a tree for outputs.</p>
40  *
41  * <p>Key methods are separated into worker methods so subclasses can
42  * override just the parts of the algorithm they need to change.</p>
43  *
44  * <p>//@todo move and refactor XSLProcessorTestBase to
45  * be more generic and reduce dependencies; also reduce dependency
46  * on internal variables and instead always use lookups into
47  * our testProps object.</p>
48  *
49  * @author shane_curcuru@us.ibm.com
50  * @version $Id$
51  */
52 public class FileTestletDriver extends FileBasedTest /// extends XSLProcessorTestBase
53 {
54 
55     //-----------------------------------------------------
56     //-------- Constants for common input params --------
57     //-----------------------------------------------------
58 
59     /**
60      * Parameter: Run a specific list of files, instead of
61      * iterating over directories.
62      * <p>Default: null, do normal iteration.</p>
63      */
64     public static final String OPT_FILELIST = "fileList";
65 
66     /**
67      * Parameter: FQCN or simple classname of Testlet to use.
68      * <p>User may pass in either a FQCN or just a base classname,
69      * and we will attempt to look it up in any of the most common
70      * Xalan-testing packages.  See QetestUtils.testClassForName().</p>
71      * <p>Default: null, use StylesheetTestlet.</p>
72      */
73     public static final String OPT_TESTLET = "testlet";
74 
75     /** Classname of Testlet to use.   */
76     protected String testlet = null;
77 
78     /**
79      * Parameter: FQCN or simple classname of FilenameFilter for
80      * directories under testDir we will process.
81      * If fileList is not set, we simply go to our inputDir, and
82      * then use this filter to iterate through directories returned.
83      * <p>Default: null, use ConformanceDirRules.</p>
84      */
85     public static final String OPT_DIRFILTER = "dirFilter";
86 
87     /** Classname of FilenameFilter to use for dirs.  */
88     protected String dirFilter = null;
89 
90     /**
91      * Parameter: FQCN or simple classname of FilenameFilter for
92      * files within subdirs we will process.
93      * If fileList is not set, we simply go through all directories
94      * specified by directoryFilter, and then use this filter to
95      * find all stylesheet test files in that directory to test.
96      * Note that this does <b>not</b> handle embedded tests, where
97      * the XML document has an xml-stylesheet PI that defines the
98      * stylesheet to use to process it.
99      * <p>Default: null, use ConformanceFileRules.</p>
100      */
101     public static final String OPT_FILEFILTER = "fileFilter";
102 
103     /** Classname of FilenameFilter to use for files.  */
104     protected String fileFilter = null;
105 
106     /** Unique runId for each specific invocation of this test driver.  */
107     protected String runId = null;
108 
109     /** Convenience constant: .gold extension for gold files.  */
110     public static final String GLD_EXTENSION = ".gld";
111 
112     /** Convenience constant: .out extension for output result file.  */
113     public static final String OUT_EXTENSION = ".out";
114 
115 
116     /** Just initialize test name, comment; numTestCases is not used. */
FileTestletDriver()117     public FileTestletDriver()
118     {
119         testName = "FileTestletDriver";
120         testComment = "Test driver for File-based Testlets";
121     }
122 
123 
124     /**
125      * Initialize this test - fill in parameters.
126      * Simply fills in convenience variables from user parameters.
127      *
128      * @param p unused
129      * @return true
130      */
doTestFileInit(Properties p)131     public boolean doTestFileInit(Properties p)
132     {
133         // Copy any of our parameters from testProps to
134         //  our local convenience variables
135         testlet = testProps.getProperty(OPT_TESTLET, testlet);
136         dirFilter = testProps.getProperty(OPT_DIRFILTER, dirFilter);
137         fileFilter = testProps.getProperty(OPT_FILEFILTER, fileFilter);
138 
139         // Grab a unique runid for logging out with our tests
140         //  Used in results reporting stylesheets to differentiate
141         //  between different test runs
142         runId = QetestUtils.createRunId(testProps.getProperty("runId"));
143         testProps.put("runId", runId);  // put back in the properties
144                                         // for later use
145         return true;
146     }
147 
148 
149     /**
150      * Run through the directory given to us and run tests found
151      * in subdirs; or run through our fileList.
152      *
153      * This method logs some basic runtime data (like the actual
154      * testlet and ProcessorWrapper implementations used) and
155      * then decides to either run a user-specified fileList or to
156      * use our dirFilter to iterate over the inputDir.
157      *
158      * @param p Properties block of options to use - unused
159      * @return true if OK, false if we should abort
160      */
runTestCases(Properties p)161     public boolean runTestCases(Properties p)
162     {
163         // First log out any other runtime information, like the
164         //  actual current testlet and filters
165         try
166         {
167             // Note that each of these calls actually force the
168             //  creation of an actual object of each type: this is
169             //  required since we may default the types or our call
170             //  to QetestUtils.testClassForName() may return a
171             //  different classname than the user actually specified
172             // Care should be taken that the construction of objects
173             //  here does not affect our testing later on
174             Properties runtimeProps = new Properties();
175             // ... and add a few extra things ourselves
176             runtimeProps.put("actual.testlet", getTestlet());
177             runtimeProps.put("actual.dirFilter", getDirFilter());
178             runtimeProps.put("actual.fileFilter", getFileFilter());
179             reporter.logHashtable(Logger.CRITICALMSG, runtimeProps,
180                                   "actual.runtime information");
181         }
182         catch (Exception e)
183         {
184             // This is not necessarily an error
185             reporter.logThrowable(Logger.WARNINGMSG, e, "Logging actual.runtime threw");
186         }
187 
188         // Now either run a list of specific tests the user specified,
189         //  or do the default of iterating over a set of directories
190         String fileList = testProps.getProperty(OPT_FILELIST);
191         if (null != fileList)
192         {
193             // Process the specific list of tests the user supplied
194             String desc = "User-supplied fileList: " + fileList; // provide default value
195             // Use static worker class to process the list
196             Vector datalets = FileDataletManager.readFileList(reporter, fileList, desc, testProps);
197 
198             // Actually process the specified files in a testCase
199             processFileList(datalets, desc);
200         }
201         else
202         {
203             // Do the default, which is to iterate over the inputDir
204             // Note that this calls the testCaseInit/testCaseClose
205             //  logging methods itself
206             processInputDir();
207         }
208         return true;
209     }
210 
211 
212     /**
213      * Do the default: test all files found in subdirs
214      * of our inputDir, using FilenameFilters for dirs and files.
215      * Parameters: none, uses our internal members inputDir,
216      * outputDir, goldDir, etc.  Will attempt to use a default
217      * inputDir if the specified one doesn't exist.
218      *
219      * This is a special case of recurseSubDir, since we report
220      * differently from the top level.
221      */
processInputDir()222     public void processInputDir()
223     {
224         // Ensure the inputDir is there - we must have a valid location for input files
225         File topInputDir = new File(inputDir);
226 
227         if (!topInputDir.exists())
228         {
229             // Try a default inputDir
230             String oldInputDir = inputDir; // cache for potential error message
231             topInputDir = new File((inputDir = getDefaultInputDir()));
232             if (!topInputDir.exists())
233             {
234                 // No inputDir, can't do any tests!
235                 // Note we put this in a fake testCase, since this
236                 //  is likely the only thing our test reports
237                 reporter.testCaseInit("processInputDir - mock testcase");
238                 reporter.checkErr("topInputDir(" + oldInputDir
239                                   + ", or " + inputDir + ") does not exist, aborting!");
240                 reporter.testCaseClose();
241                 return;
242             }
243         }
244 
245         FileDatalet topDirs = new FileDatalet(topInputDir.getPath(), outputDir, goldDir);
246 
247         // Optionally process this topDirs, and always recurse at
248         //  least one level below it
249         recurseSubDir(topDirs, getProcessTopDir(), true);
250     }
251 
252 
253     /**
254      * Optionally process all the files in this dir and optionally
255      * recurse downwards using our dirFilter.
256      *
257      * This is a pre-order traversal; we process files in this
258      * dir first and then optionally recurse.
259      *
260      * @param base FileDatalet representing the input, output,
261      * gold directory triplet we should use
262      * @param process if we should call processSubDir on this dir
263      * @param recurse if we should recurse below this directory,
264      * or just stop here after processSubDir()
265      */
recurseSubDir(FileDatalet base, boolean process, boolean recurse)266     public void recurseSubDir(FileDatalet base, boolean process, boolean recurse)
267     {
268         // Process this directory first: pre-order traversal
269         if (process)
270             processSubDir(base);
271 
272         if (!recurse)
273             return;
274 
275         // If we should recurse, do so now
276         File inputDir = new File(base.getInput());
277         FilenameFilter filter = getDirFilter();
278         reporter.logTraceMsg("recurseSubDir(" + inputDir.getPath()
279                             + ") looking for subdirs with: " + filter);
280 
281         // Use our filter to get a list of directories to process
282         String subdirs[] = inputDir.list(filter);
283 
284         // Validate that we have some valid directories to process
285         if ((null == subdirs) || (subdirs.length <= 0))
286         {
287             reporter.logWarningMsg("recurseSubDir(" + inputDir.getPath()
288                                + ") no valid subdirs found!");
289             return;
290         }
291 
292         // For every subdirectory, check if we should run tests in it
293         for (int i = 0; i < subdirs.length; i++)
294         {
295             File subTestDir = new File(inputDir, subdirs[i]);
296 
297             if ((null == subTestDir) || (!subTestDir.exists()))
298             {
299                 // Just log it and continue; presumably we'll find
300                 //  other directories to test
301                 reporter.logWarningMsg("subTestDir(" + subTestDir.getPath()
302                                        + ") does not exist, skipping!");
303                 continue;
304             }
305             FileDatalet subdir = new FileDatalet(base, subdirs[i]);
306 
307             // Process each other directory, and optionally continue
308             //  to recurse downwards
309             recurseSubDir(subdir, true, getRecurseDirs());
310         } // end of for...
311     }
312 
313 
314     /**
315      * Process a single subdirectory and run our testlet over
316      * every file found by our fileFilter therein.
317      *
318      * @param base FileDatalet representing the input, output,
319      * gold directory triplet we should use
320      */
processSubDir(FileDatalet base)321     public void processSubDir(FileDatalet base)
322     {
323         // Validate that each of the specified dirs exists
324         // Ask it to be strict in ensuring output, gold are created
325         if (!base.validate(true))
326         {
327             // Just log it and continue; presumably we'll find
328             //  other directories to test
329             reporter.logWarningMsg("processSubDir(" + base.getInput()
330                                    + ", " + base.getOutput()
331                                    + ", " + base.getGold()
332                                    + ") some dir does not exist, skipping!");
333             return;
334         }
335 
336         File subInputDir = new File(base.getInput());
337         // Call worker method to process the individual directory
338         //  and get a list of .xsl files to test
339         Vector files = getFilesFromDir(subInputDir, getFileFilter());
340 
341         if ((null == files) || (0 == files.size()))
342         {
343             reporter.logStatusMsg("processSubDir(" + base.getInput()
344                                    + ") no files found(1), skipping!");
345             return;
346         }
347 
348         // 'Transform' the list of individual test files into a
349         //  list of Datalets with all fields filled in
350         //@todo should getFilesFromDir and buildDatalets be combined?
351         Vector datalets = buildDatalets(files, base);
352 
353         if ((null == datalets) || (0 == datalets.size()))
354         {
355             reporter.logWarningMsg("processSubDir(" + base.getInput()
356                                    + ") no tests found(2), skipping!");
357             return;
358         }
359 
360         // Now process the list of files found in this dir
361         processFileList(datalets, "Testing subdir: " + base.getInput());
362     }
363 
364 
365     /**
366      * Run a list of stylesheet tests through a Testlet.
367      * The file names are assumed to be fully specified, and we assume
368      * the corresponding directories exist.
369      * Each fileList is turned into a testcase.
370      *
371      * @param vector of Datalet objects to pass in
372      * @param desc String to use as testCase description
373      */
processFileList(Vector datalets, String desc)374     public void processFileList(Vector datalets, String desc)
375     {
376         // Validate arguments
377         if ((null == datalets) || (0 == datalets.size()))
378         {
379             // Bad arguments, report it as an error
380             // Note: normally, this should never happen, since
381             //  this class normally validates these arguments
382             //  before calling us
383             reporter.checkErr("processFileList: Testlet or datalets are null/blank, nothing to test!");
384             return;
385         }
386 
387         // Put each fileList into a testCase
388         reporter.testCaseInit(desc);
389 
390         // Now just go through the list and process each set
391         int numDatalets = datalets.size();
392         reporter.logInfoMsg("processFileList() with " + numDatalets
393                             + " potential tests");
394         // Iterate over every datalet and test it
395         for (int ctr = 0; ctr < numDatalets; ctr++)
396         {
397             try
398             {
399                 // Create a Testlet to execute a test with this
400                 //  next datalet - the Testlet will log all info
401                 //  about the test, including calling check*()
402                 getTestlet().execute((Datalet)datalets.elementAt(ctr));
403             }
404             catch (Throwable t)
405             {
406                 // Log any exceptions as fails and keep going
407                 reporter.logThrowable(Logger.ERRORMSG, t, "Datalet threw");
408                 reporter.checkErr("Datalet num " + ctr + " threw: " + t.toString());
409             }
410         }  // of while...
411         reporter.testCaseClose();
412     }
413 
414 
415     /**
416      * Use the supplied filter on given directory to return a list
417      * of tests to be run.
418      *
419      * The real logic is in the filter, which can be specified as
420      * an option or by overriding getDefaultFileFilter().
421      *
422      * @param dir directory to scan
423      * @param filter to use on this directory; if null, uses default
424      * @return Vector of local path\filenames of tests to run;
425      * the tests themselves will exist; null if error
426      */
getFilesFromDir(File dir, FilenameFilter filter)427     public Vector getFilesFromDir(File dir, FilenameFilter filter)
428     {
429         // Validate arguments
430         if ((null == dir) || (!dir.exists()))
431         {
432             // Bad arguments, report it as an error
433             // Note: normally, this should never happen, since
434             //  this class normally validates these arguments
435             //  before calling us
436             reporter.logWarningMsg("getFilesFromDir(" + dir.toString() + ") dir null or does not exist");
437             return null;
438         }
439         // Get the list of 'normal' test files
440         String[] files = dir.list(filter);
441         Vector v = new Vector(files.length);
442         for (int i = 0; i < files.length; i++)
443         {
444             v.addElement(files[i]);
445         }
446         reporter.logTraceMsg("getFilesFromDir(" + dir.toString() + ") found " + v.size() + " total files to test");
447         return v;
448     }
449 
450 
451     /**
452      * Transform a vector of individual test names into a Vector
453      * of filled-in datalets to be tested
454      *
455      * This basically just calculates local path\filenames across
456      * the three presumably-parallel directory trees of
457      * inputDir, outputDir and goldDir.
458      * It then stuffs each of these values plus some
459      * generic info like our testProps into each datalet it creates.
460      *
461      * @param files Vector of local path\filenames to be tested
462      * @param base FileDatalet denoting directories
463      * input, output, gold
464      * @return Vector of FileDatalets that are fully filled in,
465      * i.e. output, gold, etc are filled in respectively
466      * to input
467      */
buildDatalets(Vector files, FileDatalet base)468     public Vector buildDatalets(Vector files, FileDatalet base)
469     {
470         // Validate arguments
471         if ((null == files) || (files.size() < 1))
472         {
473             // Bad arguments, report it as an error
474             // Note: normally, this should never happen, since
475             //  this class normally validates these arguments
476             //  before calling us
477             reporter.logWarningMsg("buildDatalets null or empty file vector");
478             return null;
479         }
480         Vector v = new Vector(files.size());
481 
482         // For every file in the vector, construct the matching
483         //  out, gold, and xml/xsl files
484         for (Enumeration elements = files.elements();
485                 elements.hasMoreElements(); /* no increment portion */ )
486         {
487             String file = null;
488             try
489             {
490                 file = (String)elements.nextElement();
491             }
492             catch (ClassCastException cce)
493             {
494                 // Just skip this entry
495                 reporter.logWarningMsg("Bad file element found, skipping: " + cce.toString());
496                 continue;
497             }
498             v.addElement(buildDatalet(base, file));
499         }
500         return v;
501     }
502 
503     /**
504      * Construct a FileDatalet with corresponding output, gold files.
505      *
506      * This basically just calls worker methods to construct and
507      * set options on a datalet to return.
508      *
509      * @param base FileDatalet denoting directories
510      * input, output, gold
511      * @param name bare name of the input file
512      * @return FileDatalet that is fully filled in,
513      * i.e. output, gold, etc are filled in respectively
514      * to input and any options are set
515      */
buildDatalet(FileDatalet base, String name)516     protected FileDatalet buildDatalet(FileDatalet base, String name)
517     {
518         // Worker method to construct paths
519         FileDatalet d = buildDataletPaths(base, name);
520         // Worker method to set any other options, etc.
521         setDataletOptions(d);
522         return d;
523     }
524 
525     /**
526      * Construct a FileDatalet with corresponding output, gold files.
527      *
528      * This worker method just has the logic to construct the
529      * corresponding output and gold filenames; feel free to subclass.
530      *
531      * This class simply appends .out and .gld to the end of the
532      * existing names: foo.xml: foo.xml.out, foo.xml.gld.
533      *
534      * @param base FileDatalet denoting directories
535      * input, output, gold
536      * @param name bare name of the input file
537      * @return FileDatalet that is fully filled in,
538      * i.e. output, gold, etc are filled in respectively
539      * to input
540      */
buildDataletPaths(FileDatalet base, String name)541     protected FileDatalet buildDataletPaths(FileDatalet base, String name)
542     {
543         return new FileDatalet(base.getInput() + File.separator + name,
544                 base.getOutput() + File.separator + name + OUT_EXTENSION,
545                 base.getGold() + File.separator + name + GLD_EXTENSION);
546     }
547 
548     /**
549      * Fillin FileDatalet.setOptions and any other processing.
550      *
551      * This is designed to be overriden so subclasses can put any
552      * special items in the datalet's options or do other
553      * preprocessing of the datalet.
554      *
555      * @param base FileDatalet to apply options, etc. to
556      */
setDataletOptions(FileDatalet base)557     protected void setDataletOptions(FileDatalet base)
558     {
559         base.setDescription(base.getInput());
560         // Optimization: put in a copy of our fileChecker, so
561         //  that each testlet doesn't have to create it's own
562         //  fileCheckers should not store state, so this
563         //  shouldn't affect the testing at all
564         base.setOptions(testProps);
565         // Note: set our options in the datalet first, then
566         //  put the fileChecker directly into their options
567         base.getOptions().put("fileCheckerImpl", fileChecker);
568     }
569 
570     /** If we should process the top level directory (default:false).   */
getProcessTopDir()571     protected boolean getProcessTopDir()
572     { return false; }
573 
574     /** If we should always recurse lower level directories (default:false).   */
getRecurseDirs()575     protected boolean getRecurseDirs()
576     { return false; }
577 
578     /** Default FilenameFilter FQCN for directories.   */
getDefaultDirFilter()579     protected String getDefaultDirFilter()
580     { return "org.apache.qetest.DirFilter"; }
581 
582     /** Default FilenameFilter FQCN for files.   */
getDefaultFileFilter()583     protected String getDefaultFileFilter()
584     { return "org.apache.qetest.FilePatternFilter"; }
585 
586     /** Default Testlet FQCN for executing stylesheet tests.   */
getDefaultTestlet()587     protected String getDefaultTestlet()
588     { return "org.apache.qetest.FileTestlet"; }
589 
590     /** Default list of packages to search for classes.   */
getDefaultPackages()591     protected String[] getDefaultPackages()
592     { return QetestUtils.defaultPackages; }
593 
594     /** Cached Testlet Class; used for life of this test.   */
595     protected Class cachedTestletClazz = null;
596 
597     /**
598      * Convenience method to get a Testlet to use.
599      * Attempts to return one as specified by our testlet parameter,
600      * otherwise returns a default StylesheetTestlet.
601      *
602      * @return Testlet for use in this test; null if error
603      */
getTestlet()604     public Testlet getTestlet()
605     {
606         // Find a Testlet class to use if we haven't already
607         if (null == cachedTestletClazz)
608         {
609             cachedTestletClazz = QetestUtils.testClassForName(testlet,
610                                                               getDefaultPackages(),
611                                                               getDefaultTestlet());
612         }
613         try
614         {
615             // Create it and set our reporter into it
616             Testlet t = (Testlet)cachedTestletClazz.newInstance();
617             t.setLogger((Logger)reporter);
618             return (Testlet)t;
619         }
620         catch (Exception e)
621         {
622             // Ooops, none found! This should be very rare, since
623             //  we know the defaultTestlet should be found
624             return null;
625         }
626     }
627 
628 
629     /**
630      * Convenience method to get a default filter for directories.
631      * Uses category member variable if set.
632      *
633      * @return FilenameFilter using DirFilter(category, null).
634      */
getDirFilter()635     public FilenameFilter getDirFilter()
636     {
637         // Find a FilenameFilter class to use
638         Class clazz = QetestUtils.testClassForName(dirFilter,
639                                                    getDefaultPackages(),
640                                                    getDefaultDirFilter());
641         try
642         {
643             // Create it, optionally with a category
644             String category = testProps.getProperty(OPT_CATEGORY);
645             if ((null != category) && (category.length() > 1))  // Arbitrary check for non-null, non-blank string
646             {
647                 Class[] parameterTypes =
648                 {
649                     java.lang.String.class,
650                     java.lang.String.class
651                 };
652                 Constructor ctor = clazz.getConstructor(parameterTypes);
653 
654                 Object[] ctorArgs =
655                 {
656                     category,
657                     null
658                 };
659                 return (FilenameFilter)ctor.newInstance(ctorArgs);
660             }
661             else
662             {
663                 return (FilenameFilter)clazz.newInstance();
664             }
665         }
666         catch (Exception e)
667         {
668             // Ooops, none found!
669             return null;
670         }
671     }
672 
673 
674     /**
675      * Convenience method to get a default filter for files.
676      * Uses excludes member variable if set.
677      *
678      * @return FilenameFilter using FileExtensionFilter(null, excludes).
679      */
getFileFilter()680     public FilenameFilter getFileFilter()
681     {
682         // Find a FilenameFilter class to use
683         Class clazz = QetestUtils.testClassForName(fileFilter,
684                                                    getDefaultPackages(),
685                                                    getDefaultFileFilter());
686         try
687         {
688             // Create it, optionally with excludes
689             String excludes = testProps.getProperty(OPT_EXCLUDES);
690             if ((null != excludes) && (excludes.length() > 1))  // Arbitrary check for non-null, non-blank string
691             {
692                 Class[] parameterTypes =
693                 {
694                     java.lang.String.class,
695                     java.lang.String.class
696                 };
697                 Constructor ctor = clazz.getConstructor(parameterTypes);
698 
699                 Object[] ctorArgs =
700                 {
701                     null,
702                     excludes
703                 };
704                 return (FilenameFilter)ctor.newInstance(ctorArgs);
705             }
706             else
707             {
708                 return (FilenameFilter)clazz.newInstance();
709             }
710         }
711         catch (Exception e)
712         {
713             // Ooops, none found!
714             return null;
715         }
716     }
717 
718 
719     /**
720      * Convenience method to get a default inputDir when none or
721      * a bad one was given.
722      * @return String pathname of default inputDir "tests\conf".
723      */
getDefaultInputDir()724     public String getDefaultInputDir()
725     {
726         return "tests" + File.separator + "conf";
727     }
728 
729 
730     /**
731      * Convenience method to print out usage information - update if needed.
732      * @return String denoting usage of this test class
733      */
usage()734     public String usage()
735     {
736         return ("Additional options supported by FileTestletDriver:\n"
737                 + "    -" + OPT_FILELIST
738                 + "   <name of listfile of tests to run>\n"
739                 + "    -" + OPT_DIRFILTER
740                 + "  <classname of FilenameFilter for dirs>\n"
741                 + "    -" + OPT_FILEFILTER
742                 + " <classname of FilenameFilter for files>\n"
743                 + "    -" + OPT_TESTLET
744                 + "    <classname of Testlet to execute tests with>\n"
745                 + super.usage());   // Grab our parent classes usage as well
746     }
747 
748 
749     /**
750      * Main method to run test from the command line - can be left alone.
751      * @param args command line argument array
752      */
main(String[] args)753     public static void main(String[] args)
754     {
755         FileTestletDriver app = new FileTestletDriver();
756         app.doMain(args);
757     }
758 }
759