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 /* 23 * 24 * FileBasedTest.java 25 * 26 */ 27 package org.apache.qetest; 28 29 import org.apache.test.android.AndroidFileUtils; 30 31 import java.io.File; 32 import java.io.FileInputStream; 33 import java.util.Enumeration; 34 import java.util.Properties; 35 36 //------------------------------------------------------------------------- 37 38 /** 39 * Base class for file-based tests. 40 * Many tests will need to operate on files external to a product 41 * under test. This class provides useful, generic functionality 42 * in these cases. 43 * <p>FileBasedTest defines a number of common fields that many 44 * tests that operate on data files may use.</p> 45 * <ul>These are each pre-initialized for you from the command line or property file. 46 * <li>inputDir (string representing dir where input files come from)</li> 47 * <li>outputDir (string representing dir where output, working, temp files go)</li> 48 * <li>goldDir (string representing dir where known good reference files are)</li> 49 * <li>debug (generic boolean flag for debugging)</li> 50 * <li>(stored in testProps) loggers (FQCN;of;Loggers to add to our Reporter)</li> 51 * <li>(stored in testProps) loggingLevel (passed to Reporters)</li> 52 * <li>(stored in testProps) logFile (string filename for any file-based Reporter)</li> 53 * <li>fileChecker</li> 54 * <li>(stored in testProps) excludes</li> 55 * <li>(stored in testProps) category</li> 56 * </ul> 57 * @author Shane_Curcuru@lotus.com 58 * @version 3.0 59 */ 60 public class FileBasedTest extends TestImpl 61 { 62 63 /** 64 * Convenience method to print out usage information. 65 * @author Shane Curcuru 66 * <p>Should be overridden by subclasses, although they are free 67 * to call super.usage() to get the common options string.</p> 68 * 69 * @return String denoting usage of this class 70 */ usage()71 public String usage() 72 { 73 74 return ("Common options supported by FileBasedTest:\n" + " -" 75 + OPT_LOAD 76 + " <file.props> (read in a .properties file,\n" 77 + " that can set any/all of the other opts)\n" 78 + " -" + OPT_INPUTDIR 79 + " <path to input files>\n" 80 + " -" + OPT_OUTPUTDIR 81 + " <path to output area - where all output is sent>\n" 82 + " -" + OPT_GOLDDIR 83 + " <path to gold reference output>\n" 84 + " -" + OPT_CATEGORY 85 + " <names;of;categories of tests to run>\n" 86 + " -" + OPT_EXCLUDES 87 + " <list;of;specific file.ext tests to skip>\n" 88 + " -" + OPT_FILECHECKER 89 + " <FQCN of a non-standard FileCheckService>\n" 90 + " -" + Reporter.OPT_LOGGERS 91 + " <FQCN;of;Loggers to use>\n" 92 + " -" + Logger.OPT_LOGFILE 93 + " <resultsFileName> (sends test results to XML file)\n" 94 + " -" + Reporter.OPT_LOGGINGLEVEL 95 + " <int> (level of msgs to log out; 0=few, 99=lots)\n" 96 + " -" + Reporter.OPT_DEBUG 97 + " (prints extra debugging info)\n"); 98 } 99 100 //----------------------------------------------------- 101 //-------- Constants for common input params -------- 102 //----------------------------------------------------- 103 104 /** 105 * Parameter: Load properties file for options 106 * <p>Will load named file as a Properties block, setting any 107 * applicable options. Command line takes precedence. 108 * Format: <code>-load FileName.prop</code></p> 109 */ 110 public static final String OPT_LOAD = "load"; 111 112 /** 113 * Parameter: Where are test input files? 114 * <p>Default: .\inputs. 115 * Format: <code>-inputDir path\to\dir</code></p> 116 */ 117 public static final String OPT_INPUTDIR = "inputDir"; 118 119 /** Field inputDir:holds String denoting local path for inputs. */ 120 protected String inputDir = "." + File.separator + "inputs"; 121 122 /** 123 * Parameter: Where should we place output files (or temp files, etc.)? 124 * <p>Default: .\outputs. 125 * Format: <code>-outputDir path\to\dir</code></p> 126 */ 127 public static final String OPT_OUTPUTDIR = "outputDir"; 128 129 /** Field outputDir:holds String denoting local path for outputs. */ 130 // Android-changed: The original directory isn't writeable on Android. 131 // protected String outputDir = "." + File.separator + "outputs"; 132 protected String outputDir = AndroidFileUtils.getOutputFile("." + File.separator + "outputs") 133 .getPath(); 134 135 /** 136 * Parameter: Where should get "gold" pre-validated XML files? 137 * <p>Default: .\golds. 138 * Format: <code>-goldDir path\to\dir</code></p> 139 */ 140 public static final String OPT_GOLDDIR = "goldDir"; 141 142 /** Field goldDir:holds String denoting local path for golds. */ 143 protected String goldDir = "." + File.separator + "golds"; 144 145 /** 146 * Parameter: Only run a single subcategory of the tests. 147 * <p>Default: blank, runs all tests - supply the directory name 148 * of a subcategory to run just that set. Set into testProps 149 * and used from there.</p> 150 */ 151 public static final String OPT_CATEGORY = "category"; 152 153 /** 154 * Parameter: Should we exclude any specific test files? 155 * <p>Default: null (no excludes; otherwise specify 156 * semicolon delimited list of bare filenames something like 157 * 'axes01.xsl;bool99.xsl'). Set into testProps and used 158 * from there</p> 159 */ 160 public static final String OPT_EXCLUDES = "excludes"; 161 162 /** 163 * Parameter: Which CheckService should we use for XML output Files? 164 * <p>Default: org.apache.qetest.XHTFileCheckService.</p> 165 */ 166 public static final String OPT_FILECHECKER = "fileChecker"; 167 168 /** 169 * Parameter-Default value: org.apache.qetest.XHTFileCheckService. 170 */ 171 public static final String OPT_FILECHECKER_DEFAULT = "org.apache.qetest.xsl.XHTFileCheckService"; 172 173 /** FileChecker instance for use by subclasses; created in preTestFileInit() */ 174 protected CheckService fileChecker = null; 175 176 /** 177 * Parameter: if Reporters should log performance data, true/false. 178 */ 179 protected boolean perfLogging = false; 180 181 /** 182 * Parameter: general purpose debugging flag. 183 */ 184 protected boolean debug = false; 185 186 //----------------------------------------------------- 187 //-------- Class members and accessors -------- 188 //----------------------------------------------------- 189 190 /** 191 * Total Number of test case methods defined in this test. 192 * <p>Tests must either set this variable or override runTestCases().</p> 193 * <p>Unless you override runTestCases(), test cases must be named like so:.</p> 194 * <p>Tests must either set this variable or override runTestCases().</p> 195 * <p> testCase<I>N</I>, where <I>N</I> is a consecutively 196 * numbered whole integer (1, 2, 3,....</p> 197 * @see #runTestCases 198 */ 199 public int numTestCases = 0; 200 201 /** 202 * Generic Properties block for storing initialization info. 203 * All startup options get stored in here for later use, both by 204 * the test itself and by any Reporters we use. 205 */ 206 protected Properties testProps = new Properties(); 207 208 /** 209 * Accessor method for our Properties block, for use by harnesses. 210 * 211 * @param p if (p != null) testProps = (Properties) p.clone(); 212 */ setProperties(Properties p)213 public void setProperties(Properties p) 214 { 215 216 // Don't allow setting to null! 217 if (p != null) 218 { 219 testProps = (Properties) p.clone(); 220 } 221 } 222 223 /** 224 * Accessor method for our Properties block, for use by harnesses. 225 * 226 * @return our Properties block itself 227 */ getProperties()228 public Properties getProperties() 229 { 230 return testProps; 231 } 232 233 /** 234 * Default constructor - initialize testName, Comment. 235 */ FileBasedTest()236 public FileBasedTest() 237 { 238 239 // Only set them if they're not set 240 if (testName == null) 241 testName = "FileBasedTest.defaultName"; 242 243 if (testComment == null) 244 testComment = "FileBasedTest.defaultComment"; 245 } 246 247 //----------------------------------------------------- 248 //-------- Implement Test/TestImpl methods -------- 249 //----------------------------------------------------- 250 251 /** 252 * Initialize this test - called once before running testcases. 253 * <p>Use the loggers field to create some loggers in a Reporter.</p> 254 * @author Shane_Curcuru@lotus.com 255 * @see TestImpl#testFileInit(java.util.Properties) 256 * 257 * @param p Properties to initialize from 258 * 259 * @return false if we should abort; true otherwise 260 */ preTestFileInit(Properties p)261 public boolean preTestFileInit(Properties p) 262 { 263 264 // Pass our properties block directly to the reporter 265 // so it can use the same values in initialization 266 // A Reporter will auto-initialize from the values 267 // in the properties block 268 setReporter(QetestFactory.newReporter(p)); 269 reporter.testFileInit(testName, testComment); 270 271 // Create a file-based CheckService for later use 272 if (null == fileChecker) 273 { 274 String tmpName = testProps.getProperty(OPT_FILECHECKER); 275 if ((null != tmpName) && (tmpName.length() > 0)) 276 { 277 // Use the user's specified class; if not available 278 // will return null which gets covered below 279 fileChecker = QetestFactory.newCheckService(reporter, tmpName); 280 } 281 282 if (null == fileChecker) 283 { 284 // If that didn't work, then ask for default one that does files 285 fileChecker = QetestFactory.newCheckService(reporter, QetestFactory.TYPE_FILES); 286 } 287 // If we're creating a new one, also applyAttributes 288 // (Assume that if we already had one, it already had this done) 289 fileChecker.applyAttributes(p); 290 } 291 292 return true; 293 } 294 295 /** 296 * Initialize this test - called once before running testcases. 297 * <p>Subclasses <b>must</b> override this to do whatever specific 298 * processing they need to initialize their product under test.</p> 299 * <p>If for any reason the test should not continue, it <b>must</b> 300 * return false from this method.</p> 301 * @author Shane_Curcuru@lotus.com 302 * @see TestImpl#testFileInit(java.util.Properties) 303 * 304 * @param p Properties to initialize from 305 * 306 * @return false if we should abort; true otherwise 307 */ doTestFileInit(Properties p)308 public boolean doTestFileInit(Properties p) 309 { 310 /* no-op; feel free to override */ 311 return true; 312 } 313 314 /** 315 * Override mostly blank routine to dump environment info. 316 * <p>Log out information about our environment in a structured 317 * way: mainly by calling logTestProps() here.</p> 318 * 319 * @param p Properties to initialize from 320 * 321 * @return false if we should abort; true otherwise 322 */ postTestFileInit(Properties p)323 public boolean postTestFileInit(Properties p) 324 { 325 logTestProps(); 326 return true; 327 } 328 329 /** 330 * Run all of our testcases. 331 * <p>use nifty FileBasedTestReporter.executeTests(). May be overridden 332 * by subclasses to do their own processing. If you do not override, 333 * you must set numTestCases properly!</p> 334 * @author Shane Curcuru 335 * 336 * @param p Properties to initialize from 337 * 338 * @return false if we should abort; true otherwise 339 */ runTestCases(Properties p)340 public boolean runTestCases(Properties p) 341 { 342 343 // Properties may be currently unused 344 reporter.executeTests(this, numTestCases, p); 345 346 return true; 347 } 348 349 /** 350 * Cleanup this test - called once after running testcases. 351 * @author Shane Curcuru 352 * <p>Tests should override if they need to do any cleanup.</p> 353 * 354 * @param p Properties to initialize from 355 * 356 * @return false if we should abort; true otherwise 357 */ doTestFileClose(Properties p)358 public boolean doTestFileClose(Properties p) 359 { 360 /* no-op; feel free to override */ 361 return true; 362 } 363 364 // Use default implementations of preTestFileClose() 365 366 /** 367 * Mark the test complete - called once after running testcases. 368 * <p>Currently logs a summary of our test status and then tells 369 * our reporter to log the testFileClose. This will calculate 370 * final results, and complete logging for any structured 371 * output logs (like XML files).</p> 372 *<p>We also call reporter.writeResultsStatus(true) to 373 * write out a pass/fail marker file. (This last part is 374 * actually optional, but it's useful and quick, so I'll 375 * do it by default for now.)</p> 376 * 377 * @param p Unused; passed through to super 378 * 379 * @return true if OK, false otherwise 380 */ postTestFileClose(Properties p)381 protected boolean postTestFileClose(Properties p) 382 { 383 // Log out a special summary status, with marker file 384 reporter.writeResultsStatus(true); 385 386 // Ask our superclass to handle this as well 387 return super.postTestFileClose(p); 388 } 389 390 //----------------------------------------------------- 391 //-------- Initialize our common input params -------- 392 //----------------------------------------------------- 393 394 /** 395 * Set our instance variables from a Properties file. 396 * <p>Must <b>not</b> use reporter.</p> 397 * @author Shane Curcuru 398 * @param Properties block to set name=value pairs from 399 * 400 * NEEDSDOC @param props 401 * @return status - true if OK, false if error. 402 * @todo improve error checking, if needed 403 */ initializeFromProperties(Properties props)404 public boolean initializeFromProperties(Properties props) 405 { 406 // Copy over all properties into our local block 407 // this is a little unusual, but it does allow users 408 // to set any new sort of properties via the properties 409 // file, and we'll pick it up - that way this class doesn't 410 // have to get updated when we have new properties 411 // Note that this may result in duplicates since we 412 // re-set many of the things from bleow 413 for (Enumeration names = props.propertyNames(); 414 names.hasMoreElements(); /* no increment portion */ ) 415 { 416 Object key = names.nextElement(); 417 418 testProps.put(key, props.get(key)); 419 } 420 421 422 // Parse out any values that match our internal convenience variables 423 // default all values to our current values 424 // String values are simply getProperty()'d 425 inputDir = props.getProperty(OPT_INPUTDIR, inputDir); 426 if (inputDir != null) 427 testProps.put(OPT_INPUTDIR, inputDir); 428 429 outputDir = props.getProperty(OPT_OUTPUTDIR, outputDir); 430 if (outputDir != null) 431 testProps.put(OPT_OUTPUTDIR, outputDir); 432 433 goldDir = props.getProperty(OPT_GOLDDIR, goldDir); 434 if (goldDir != null) 435 testProps.put(OPT_GOLDDIR, goldDir); 436 437 // The actual fileChecker object is created in preTestFileInit() 438 439 // Use a temp string for those properties we only set 440 // in our testProps, but don't bother to save ourselves 441 String temp = null; 442 443 temp = props.getProperty(OPT_FILECHECKER); 444 if (temp != null) 445 testProps.put(OPT_FILECHECKER, temp); 446 447 temp = props.getProperty(OPT_CATEGORY); 448 if (temp != null) 449 testProps.put(OPT_CATEGORY, temp); 450 451 temp = props.getProperty(OPT_EXCLUDES); 452 if (temp != null) 453 testProps.put(OPT_EXCLUDES, temp); 454 455 temp = props.getProperty(Reporter.OPT_LOGGERS); 456 if (temp != null) 457 testProps.put(Reporter.OPT_LOGGERS, temp); 458 459 temp = props.getProperty(Logger.OPT_LOGFILE); 460 if (temp != null) 461 testProps.put(Logger.OPT_LOGFILE, temp); 462 463 // boolean values just check for the non-default value 464 String dbg = props.getProperty(Reporter.OPT_DEBUG); 465 466 if ((dbg != null) && dbg.equalsIgnoreCase("true")) 467 { 468 debug = true; 469 470 testProps.put(Reporter.OPT_DEBUG, "true"); 471 } 472 473 String pLog = props.getProperty(Reporter.OPT_PERFLOGGING); 474 475 if ((pLog != null) && pLog.equalsIgnoreCase("true")) 476 { 477 perfLogging = true; 478 479 testProps.put(Reporter.OPT_PERFLOGGING, "true"); 480 } 481 482 temp = props.getProperty(Reporter.OPT_LOGGINGLEVEL); 483 484 if (temp != null) 485 testProps.put(Reporter.OPT_LOGGINGLEVEL, temp); 486 487 return true; 488 } 489 490 /** 491 * Sets the provided fields with data from an array, presumably 492 * from the command line. 493 * <p>May be overridden by subclasses, although you should probably 494 * read the code to see what default options this handles. Must 495 * not use reporter. Calls initializeFromProperties(). After that, 496 * sets any internal variables that match items in the array like: 497 * <code> -param1 value1 -paramNoValue -param2 value2 </code> 498 * Any params that do not match internal variables are simply set 499 * into our properties block for later use. This allows subclasses 500 * to simply get their initialization data from the testProps 501 * without having to make code changes here.</p> 502 * <p>Assumes all params begin with "-" dash, and that all values 503 * do <b>not</b> start with a dash.</p> 504 * @author Shane Curcuru 505 * @param String[] array of arguments 506 * 507 * @param args array of command line arguments 508 * @param flag: are we being called from a subclass? 509 * @return status - true if OK, false if error. 510 */ initializeFromArray(String[] args, boolean flag)511 public boolean initializeFromArray(String[] args, boolean flag) 512 { 513 514 // Read in command line args and setup internal variables 515 String optPrefix = "-"; 516 int nArgs = args.length; 517 518 // We don't require any arguments: but subclasses might 519 // want to require certain ones 520 // Must read in properties file first, so cmdline can 521 // override values from properties file 522 boolean propsOK = true; 523 524 // IF we are being called the first time on this 525 // array of arguments, go ahead and process unknown ones 526 // otherwise, don't bother 527 if (flag) 528 { 529 for (int k = 0; k < nArgs; k++) 530 { 531 if (args[k].equalsIgnoreCase(optPrefix + OPT_LOAD)) 532 { 533 if (++k >= nArgs) 534 { 535 System.err.println( 536 "ERROR: must supply properties filename for: " 537 + optPrefix + OPT_LOAD); 538 539 return false; 540 } 541 542 String loadPropsName = args[k]; 543 544 try 545 { 546 547 // Load named file into our properties block 548 FileInputStream fIS = new FileInputStream(loadPropsName); 549 Properties p = new Properties(); 550 551 p.load(fIS); 552 p.put(OPT_LOAD, loadPropsName); // Pass along with properties 553 554 propsOK &= initializeFromProperties(p); 555 } 556 catch (Exception e) 557 { 558 System.err.println( 559 "ERROR: loading properties file failed: " + loadPropsName); 560 e.printStackTrace(); 561 562 return false; 563 } 564 565 break; 566 } 567 } // end of for(...) 568 } // end of if ((flag)) 569 570 // Now read in the rest of the command line 571 // @todo cleanup loop to be more table-driven 572 for (int i = 0; i < nArgs; i++) 573 { 574 575 // Set any String args and place them in testProps 576 if (args[i].equalsIgnoreCase(optPrefix + OPT_INPUTDIR)) 577 { 578 if (++i >= nArgs) 579 { 580 System.err.println("ERROR: must supply arg for: " 581 + optPrefix + OPT_INPUTDIR); 582 583 return false; 584 } 585 586 inputDir = args[i]; 587 588 testProps.put(OPT_INPUTDIR, inputDir); 589 590 continue; 591 } 592 593 if (args[i].equalsIgnoreCase(optPrefix + OPT_OUTPUTDIR)) 594 { 595 if (++i >= nArgs) 596 { 597 System.err.println("ERROR: must supply arg for: " 598 + optPrefix + OPT_OUTPUTDIR); 599 600 return false; 601 } 602 603 outputDir = args[i]; 604 605 testProps.put(OPT_OUTPUTDIR, outputDir); 606 607 continue; 608 } 609 610 if (args[i].equalsIgnoreCase(optPrefix + OPT_GOLDDIR)) 611 { 612 if (++i >= nArgs) 613 { 614 System.err.println("ERROR: must supply arg for: " 615 + optPrefix + OPT_GOLDDIR); 616 617 return false; 618 } 619 620 goldDir = args[i]; 621 622 testProps.put(OPT_GOLDDIR, goldDir); 623 624 continue; 625 } 626 627 if (args[i].equalsIgnoreCase(optPrefix + OPT_CATEGORY)) 628 { 629 if (++i >= nArgs) 630 { 631 System.err.println("ERROR: must supply arg for: " 632 + optPrefix + OPT_CATEGORY); 633 634 return false; 635 } 636 637 testProps.put(OPT_CATEGORY, args[i]); 638 639 continue; 640 } 641 642 if (args[i].equalsIgnoreCase(optPrefix + OPT_EXCLUDES)) 643 { 644 if (++i >= nArgs) 645 { 646 System.err.println("ERROR: must supply arg for: " 647 + optPrefix + OPT_EXCLUDES); 648 649 return false; 650 } 651 652 testProps.put(OPT_EXCLUDES, args[i]); 653 654 continue; 655 } 656 657 if (args[i].equalsIgnoreCase(optPrefix + Reporter.OPT_LOGGERS)) 658 { 659 if (++i >= nArgs) 660 { 661 System.err.println("ERROR: must supply arg for: " 662 + optPrefix + Reporter.OPT_LOGGERS); 663 664 return false; 665 } 666 667 testProps.put(Reporter.OPT_LOGGERS, args[i]); 668 669 continue; 670 } 671 672 if (args[i].equalsIgnoreCase(optPrefix + Logger.OPT_LOGFILE)) 673 { 674 if (++i >= nArgs) 675 { 676 System.err.println("ERROR: must supply arg for: " 677 + optPrefix + Logger.OPT_LOGFILE); 678 679 return false; 680 } 681 682 testProps.put(Logger.OPT_LOGFILE, args[i]); 683 684 continue; 685 } 686 687 if (args[i].equalsIgnoreCase(optPrefix + OPT_FILECHECKER)) 688 { 689 if (++i >= nArgs) 690 { 691 System.out.println("ERROR: must supply arg for: " 692 + optPrefix + OPT_FILECHECKER); 693 694 return false; 695 } 696 697 testProps.put(OPT_FILECHECKER, args[i]); 698 699 continue; 700 } 701 702 // Boolean values are simple flags to switch from defaults only 703 if (args[i].equalsIgnoreCase(optPrefix + Reporter.OPT_DEBUG)) 704 { 705 debug = true; 706 707 testProps.put(Reporter.OPT_DEBUG, "true"); 708 709 continue; 710 } 711 712 if (args[i].equalsIgnoreCase(optPrefix 713 + Reporter.OPT_PERFLOGGING)) 714 { 715 testProps.put(Reporter.OPT_PERFLOGGING, "true"); 716 717 continue; 718 } 719 720 // Parse out the integer value 721 // This isn't strictly necessary since the catch-all 722 // below should take care of it, but better safe than sorry 723 if (args[i].equalsIgnoreCase(optPrefix 724 + Reporter.OPT_LOGGINGLEVEL)) 725 { 726 if (++i >= nArgs) 727 { 728 System.err.println("ERROR: must supply arg for: " 729 + optPrefix 730 + Reporter.OPT_LOGGINGLEVEL); 731 732 return false; 733 } 734 735 try 736 { 737 testProps.put(Reporter.OPT_LOGGINGLEVEL, args[i]); 738 } 739 catch (NumberFormatException numEx) 740 { /* no-op */ 741 } 742 743 continue; 744 } 745 746 // IF we are being called the first time on this 747 // array of arguments, go ahead and process unknown ones 748 // otherwise, don't bother 749 if (flag) 750 { 751 752 // Found an arg that we don't know how to process, 753 // so store it for any subclass' use as a catch-all 754 // If it starts with - dash, and another non-dash arg follows, 755 // set as a name=value pair in the property block 756 if ((args[i].startsWith(optPrefix)) && (i + 1 < nArgs) 757 && (!args[i + 1].startsWith(optPrefix))) 758 { 759 760 // Scrub off the "-" prefix before setting the name 761 testProps.put(args[i].substring(1), args[i + 1]); 762 763 i++; // Increment counter to skip next arg 764 } 765 766 // Otherwise, just set as name="" in the property block 767 else 768 { 769 770 // Scrub off the "-" prefix before setting the name 771 testProps.put(args[i].substring(1), ""); 772 } 773 } 774 } // end of for() loop 775 776 // If we got here, we set the array params OK, so simply return 777 // the value the initializeFromProperties method returned 778 return propsOK; 779 } 780 781 //----------------------------------------------------- 782 //-------- Other useful and utility methods -------- 783 //----------------------------------------------------- 784 785 /** 786 * Log out any System or common version info. 787 * <p>Logs System.getProperties(), and our the testProps block, etc..</p> 788 */ logTestProps()789 public void logTestProps() 790 { 791 reporter.logHashtable(reporter.CRITICALMSG, System.getProperties(), 792 "System.getProperties"); 793 reporter.logHashtable(reporter.CRITICALMSG, testProps, "testProps"); 794 reporter.logHashtable(reporter.CRITICALMSG, QetestUtils.getEnvironmentHash(), "getEnvironmentHash"); 795 } 796 797 798 /** 799 * Main worker method to run test from the command line. 800 * Test subclasses generally need not override. 801 * <p>This is primarily provided to make subclasses implementations 802 * of the main method as simple as possible: in general, they 803 * should simply do: 804 * <code> 805 * public static void main (String[] args) 806 * { 807 * TestSubClass app = new TestSubClass(); 808 * app.doMain(args); 809 * } 810 * </code> 811 * 812 * @param args command line arguments 813 */ doMain(String[] args)814 public void doMain(String[] args) 815 { 816 // Initialize any instance variables from the command line 817 // OR specified properties block 818 if (!initializeFromArray(args, true)) 819 { 820 System.err.println("ERROR in usage:"); 821 System.err.println(usage()); 822 823 // Don't use System.exit, since that will blow away any containing harnesses 824 return; 825 } 826 827 // Also pass along the command line, in case someone has 828 // specific code that's counting on this 829 StringBuffer buf = new StringBuffer(); 830 for (int i = 0; i < args.length; i++) 831 { 832 buf.append(args[i]); 833 buf.append(" "); 834 } 835 testProps.put(MAIN_CMDLINE, buf.toString()); 836 837 // Actually go and execute the test 838 runTest(testProps); 839 } 840 841 /** 842 * Main method to run test from the command line. 843 * @author Shane Curcuru 844 * <p>Test subclasses <b>must</b> override, obviously. 845 * Only provided here for debugging.</p> 846 * 847 * @param args command line arguments 848 */ main(String[] args)849 public static void main(String[] args) 850 { 851 FileBasedTest app = new FileBasedTest(); 852 app.doMain(args); 853 } 854 } // end of class FileBasedTest 855 856