View Javadoc
1 /* BaseTestRunner.java */ 2 3 package org.quilt.runner; 4 5 import java.io.ByteArrayOutputStream; 6 import java.io.File; 7 import java.io.FileInputStream; 8 import java.io.IOException; 9 import java.io.OutputStream; 10 import java.io.PrintStream; 11 12 import java.lang.reflect.Method; 13 import java.util.Enumeration; 14 import java.util.Properties; 15 import java.util.Vector; 16 17 import org.apache.tools.ant.AntClassLoader; 18 import org.apache.tools.ant.BuildException; 19 import org.apache.tools.ant.Project; 20 21 import junit.framework.*; 22 23 import org.quilt.cl.*; 24 import org.quilt.framework.QuiltTest; 25 import org.quilt.reports.*; 26 27 /*** 28 * Stand-along Quilt test runner, fully compatible with Ant's JUnit 29 * options. Accepts options from Ant via QuiltTask; can also be run 30 * from the command line using TestRunner. 31 * 32 * @see QuiltTask 33 * @see QuiltTest 34 * @see TestRunner 35 */ 36 37 public class BaseTestRunner extends Runner { 38 39 /*** The QuiltTest we are currently running. */ 40 private QuiltTest qt; 41 42 /*** The JUnit test suite for this QuiltTest. Built by the constructor.*/ 43 private Test suite = null; 44 45 /*** Exception caught in constructor. */ 46 private Exception exception = null; 47 48 /*** Status code returned by main() */ 49 private int retCode = SUCCESS; 50 51 /*** JUnit test result - which has the run() method. */ 52 private TestResult res; 53 54 // RUN PARAMETERS /////////////////////////////////////////////// 55 56 /*** Formatters for this particular test. */ 57 private Vector formatters = new Vector(); 58 59 /*** Do we stop on errors? */ 60 // private boolean haltOnError = false; 61 62 /*** Do we stop on test failures? */ 63 // private boolean haltOnFailure = false; 64 65 /*** 66 * Do we send output to System.out/.err as well as to the formatters. 67 * XXX BUG or inconsistency in documentation. 68 */ 69 // private boolean showOutput = false; 70 71 /*** Error output during the test */ 72 private PrintStream systemError; 73 74 /*** Output written during the test */ 75 private PrintStream systemOut; 76 77 // CONSTRUCTORS ///////////////////////////////////////////////// 78 79 /*** 80 * Constructor used by command line test runner. And so also 81 * used when Ant forks the test runner. XXX No longer true. 82 * 83 * @param test Data structure holding parameters for a single 84 * test suite. 85 */ 86 public BaseTestRunner (QuiltTest test) { 87 this (test, null); 88 } 89 /*** 90 * Constructor used when not using Quilt class loader. XXX Not true. 91 * Uses BaseTestRunner.retCode to signal whether construction 92 * successful or not. If the operation fails, the exception 93 * involved is passed back in BaseTestRunner.exception. 94 * 95 * @param test Data structure holding parameters for a single 96 * test suite. 97 * @param loader Class loader passed from parent. 98 */ 99 public BaseTestRunner(QuiltTest test, ClassLoader loader) { 100 qt = test; 101 102 try { 103 Class testClass = null; 104 if (loader == null) { 105 testClass = Class.forName(qt.getName()); 106 } else { 107 testClass = loader.loadClass(qt.getName()); 108 if (!(loader instanceof QuiltClassLoader)) { 109 // trick JVM into initializing class statics 110 AntClassLoader.initializeClass(testClass); 111 } 112 } 113 114 Method suiteMethod = null; 115 try { 116 // check if there is a no-arg "suite" method in the class 117 suiteMethod = testClass.getMethod("suite", new Class[0]); 118 } catch (Exception e) { 119 // not found 120 } 121 if (suiteMethod != null){ 122 // we somehow have a suiteMethod; try to use it to 123 // extract the suite 124 suite = (Test) suiteMethod.invoke(null, new Class[0]); 125 } else { 126 // use the JUnit TestSuite constructor to extract a 127 // test suite 128 suite = new TestSuite(testClass); 129 } 130 131 } catch (Exception e) { 132 retCode = ERRORS; 133 exception = e; 134 } 135 } 136 // /*** 137 // * Constructor using Quilt class loader. Uses 138 // * BaseTestRunner.retCode to signal whether construction 139 // * successful or not. If the operation fails, the exception 140 // * involved is passed back in BaseTestRunner.exception. 141 // * 142 // * @param test Data structure holding parameters for a single 143 // * test suite. 144 // * @param loader QuiltClassLoader passed from parent. 145 // */ 146 // public BaseTestRunner(QuiltTest test, QuiltClassLoader loader) { 147 // this.qt = test; 148 149 // try { 150 // Class testClass = null; 151 // if (loader == null) { 152 // testClass = Class.forName(test.getName()); 153 // } else { 154 // testClass = loader.loadClass(test.getName()); 155 // // trick JVM into initializing class statics 156 // AntClassLoader.initializeClass(testClass); 157 // } 158 // 159 // Method suiteMethod = null; 160 // try { 161 // // check if there is a no-arg "suite" method in the class 162 // suiteMethod = testClass.getMethod("suite", new Class[0]); 163 // } catch (Exception e) { 164 // // not found 165 // } 166 // if (suiteMethod != null){ 167 // // if there is a suite method available, then try 168 // // to extract the suite from it. If there is an error 169 // // here it will be caught below and reported. 170 // suite = (Test) suiteMethod.invoke(null, new Class[0]); 171 // } else { 172 // // use the JUnit TestSuite constructor to extract a 173 // // test suite 174 // suite = new TestSuite(testClass); 175 // } 176 // 177 // } catch (Exception e) { 178 // retCode = ERRORS; 179 // exception = e; 180 // } 181 // } // GEEP 182 183 public void run() { 184 res = new TestResult(); 185 res.addListener(this); 186 for (int i = 0; i < formatters.size(); i++) { 187 res.addListener((TestListener) formatters.elementAt(i)); 188 } 189 190 long start = System.currentTimeMillis(); 191 192 fireStartTestSuite(); 193 if (exception != null) { // had an exception in the constructor 194 for (int i = 0; i < formatters.size(); i++) { 195 ((TestListener) formatters.elementAt(i)).addError(null, 196 exception); 197 } 198 qt.setCounts(1, 0, 1); 199 qt.setRunTime(0); 200 } else { 201 202 203 ByteArrayOutputStream errStrm = new ByteArrayOutputStream(); 204 systemError = new PrintStream(errStrm); 205 206 ByteArrayOutputStream outStrm = new ByteArrayOutputStream(); 207 systemOut = new PrintStream(outStrm); 208 209 PrintStream savedOut = null; 210 PrintStream savedErr = null; 211 212 if ( qt.getFork() ) { 213 savedOut = System.out; 214 savedErr = System.err; 215 if (!qt.getShowOutput()) { 216 System.setOut(systemOut); 217 System.setErr(systemError); 218 } else { 219 System.setOut(new PrintStream( 220 new TeeOutputStream( 221 new OutputStream[] {savedOut, 222 systemOut} 223 ) 224 ) 225 ); 226 System.setErr(new PrintStream( 227 new TeeOutputStream( 228 new OutputStream[] {savedErr, 229 systemError} 230 ) 231 ) 232 ); 233 } 234 } 235 236 237 try { 238 suite.run(res); 239 } finally { 240 if (savedOut != null) { 241 System.setOut(savedOut); 242 } 243 if (savedErr != null) { 244 System.setErr(savedErr); 245 } 246 247 systemError.close(); 248 systemError = null; 249 systemOut.close(); 250 systemOut = null; 251 sendOutAndErr(new String(outStrm.toByteArray()), 252 new String(errStrm.toByteArray())); 253 254 qt.setCounts(res.runCount(), res.failureCount(), 255 res.errorCount()); 256 qt.setRunTime(System.currentTimeMillis() - start); 257 } 258 } 259 fireEndTestSuite(); 260 261 if (retCode != SUCCESS || res.errorCount() != 0) { 262 retCode = ERRORS; 263 } else if (res.failureCount() != 0) { 264 retCode = FAILURES; 265 } 266 } 267 268 /*** 269 * Get status code from run. 270 * 271 * @return Status codes from RunnerConst 272 */ 273 public int getRetCode() { 274 return retCode; 275 } 276 277 ///////////////////////////////////////////////////////////////// 278 // INTERFACE TESTLISTENER 279 // 280 // NEEDS TO BE CHECKED CAREFULLY 281 ///////////////////////////////////////////////////////////////// 282 283 /*** Called at start of test run. */ 284 public void startTest(Test t) {} 285 286 /*** Called at end of test suite. */ 287 public void endTest(Test test) {} 288 289 /*** A test failure (or error) has occurred. */ 290 public void addFailure(Test test, Throwable t) { 291 if (qt.getHaltOnFailure()) { 292 res.stop(); 293 } 294 } 295 296 /*** A test failure (or error) has occurred. */ 297 public void addFailure(Test test, AssertionFailedError t) { 298 addFailure(test, (Throwable) t); 299 } 300 301 /*** An unexpected error occurred. */ 302 public void addError(Test test, Throwable t) { 303 if (qt.getHaltOnError()) { 304 res.stop(); 305 } 306 } 307 308 /*** Handle a block of output. */ 309 public void handleOutput(String line) { 310 if (systemOut != null) { 311 systemOut.println(line); 312 } 313 } 314 315 /*** Process an error message. */ 316 public void handleErrorOutput(String line) { 317 if (systemError != null) { 318 systemError.println(line); 319 } 320 } 321 /*** Flush standard output. */ 322 public void handleFlush(String line) { 323 if (systemOut != null) { 324 systemOut.print(line); 325 } 326 } 327 /*** Flush error output. */ 328 public void handleErrorFlush(String line) { 329 if (systemError != null) { 330 systemError.print(line); 331 } 332 } 333 /*** 334 * Whether to duplicate test output to standard output and error 335 * output streams. 336 */ 337 private void sendOutAndErr(String out, String err) { 338 for (int i = 0; i < formatters.size(); i++) { 339 Formatter formatter = 340 ((Formatter) formatters.elementAt(i)); 341 342 formatter.setSystemOutput(out); 343 formatter.setSystemError(err); 344 } 345 } 346 347 /*** Notifies each formatter at start of processing test suite. */ 348 private void fireStartTestSuite() { 349 for (int i = 0; i < formatters.size(); i++) { 350 ((Formatter) formatters.elementAt(i)) 351 .startTestSuite(qt); 352 // actually has nothing to do with fireStart but it's 353 // convenient to drop it in here 354 ((Formatter) formatters.elementAt(i)) 355 .setFiltertrace(qt.getFiltertrace()); 356 } 357 } 358 /*** Called at end of test suite, notifies each formatter. */ 359 private void fireEndTestSuite() { 360 for (int i = 0; i < formatters.size(); i++) { 361 ((Formatter) formatters.elementAt(i)) 362 .endTestSuite(qt); 363 } 364 } 365 366 /*** Add a result formatter */ 367 public void addFormatter(Formatter f) { 368 formatters.addElement(f); 369 } 370 371 // OTHER METHODS //////////////////////////////////////////////// 372 private class TeeOutputStream extends OutputStream { 373 374 private OutputStream[] outs; 375 376 private TeeOutputStream(OutputStream[] outs) { 377 this.outs = outs; 378 } 379 380 public void write(int b) throws IOException { 381 for (int i = 0; i < outs.length; i++) { 382 outs[i].write(b); 383 } 384 } 385 } 386 }

This page was automatically generated by Maven