source: other-projects/trunk/gs3-release-maker/apache-ant-1.6.5/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java@ 14627

Last change on this file since 14627 was 14627, checked in by oranfry, 17 years ago

initial import of the gs3-release-maker

File size: 21.8 KB
Line 
1/*
2 * Copyright 2000-2005 The Apache Software Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17
18package org.apache.tools.ant.taskdefs.optional.junit;
19
20import java.io.BufferedReader;
21import java.io.ByteArrayOutputStream;
22import java.io.File;
23import java.io.FileInputStream;
24import java.io.IOException;
25import java.io.PrintStream;
26import java.io.PrintWriter;
27import java.io.StringReader;
28import java.io.StringWriter;
29import java.lang.reflect.Method;
30import java.util.Enumeration;
31import java.util.Hashtable;
32import java.util.Properties;
33import java.util.StringTokenizer;
34import java.util.Vector;
35import junit.framework.AssertionFailedError;
36import junit.framework.Test;
37import junit.framework.TestListener;
38import junit.framework.TestResult;
39import junit.framework.TestSuite;
40import org.apache.tools.ant.BuildException;
41import org.apache.tools.ant.Project;
42import org.apache.tools.ant.types.Permissions;
43import org.apache.tools.ant.util.StringUtils;
44import org.apache.tools.ant.util.TeeOutputStream;
45
46/**
47 * Simple Testrunner for JUnit that runs all tests of a testsuite.
48 *
49 * <p>This TestRunner expects a name of a TestCase class as its
50 * argument. If this class provides a static suite() method it will be
51 * called and the resulting Test will be run. So, the signature should be
52 * <pre><code>
53 * public static junit.framework.Test suite()
54 * </code></pre>
55 *
56 * <p> If no such method exists, all public methods starting with
57 * "test" and taking no argument will be run.
58 *
59 * <p> Summary output is generated at the end.
60 *
61 * @since Ant 1.2
62 */
63
64public class JUnitTestRunner implements TestListener {
65
66 /**
67 * No problems with this test.
68 */
69 public static final int SUCCESS = 0;
70
71 /**
72 * Some tests failed.
73 */
74 public static final int FAILURES = 1;
75
76 /**
77 * An error occurred.
78 */
79 public static final int ERRORS = 2;
80
81 /**
82 * Used in formatter arguments as a placeholder for the basename
83 * of the output file (which gets replaced by a test specific
84 * output file name later).
85 *
86 * @since Ant 1.6.3
87 */
88 public static final String IGNORED_FILE_NAME = "IGNORETHIS";
89
90 /**
91 * Holds the registered formatters.
92 */
93 private Vector formatters = new Vector();
94
95 /**
96 * Collects TestResults.
97 */
98 private TestResult res;
99
100 /**
101 * Do we filter junit.*.* stack frames out of failure and error exceptions.
102 */
103 private static boolean filtertrace = true;
104
105 /**
106 * Do we send output to System.out/.err in addition to the formatters?
107 */
108 private boolean showOutput = false;
109
110 /**
111 * The permissions set for the test to run.
112 */
113 private Permissions perm = null;
114
115 private static final String[] DEFAULT_TRACE_FILTERS = new String[] {
116 "junit.framework.TestCase",
117 "junit.framework.TestResult",
118 "junit.framework.TestSuite",
119 "junit.framework.Assert.", // don't filter AssertionFailure
120 "junit.swingui.TestRunner",
121 "junit.awtui.TestRunner",
122 "junit.textui.TestRunner",
123 "java.lang.reflect.Method.invoke(",
124 "sun.reflect.",
125 "org.apache.tools.ant."
126 };
127
128
129 /**
130 * Do we stop on errors.
131 */
132 private boolean haltOnError = false;
133
134 /**
135 * Do we stop on test failures.
136 */
137 private boolean haltOnFailure = false;
138
139 /**
140 * Returncode
141 */
142 private int retCode = SUCCESS;
143
144 /**
145 * The TestSuite we are currently running.
146 */
147 private JUnitTest junitTest;
148
149 /** output written during the test */
150 private PrintStream systemError;
151
152 /** Error output during the test */
153 private PrintStream systemOut;
154
155 /** is this runner running in forked mode? */
156 private boolean forked = false;
157
158 /** Running more than one test suite? */
159 private static boolean multipleTests = false;
160
161 /** ClassLoader passed in in non-forked mode. */
162 private ClassLoader loader;
163
164 /**
165 * Constructor for fork=true or when the user hasn't specified a
166 * classpath.
167 */
168 public JUnitTestRunner(JUnitTest test, boolean haltOnError,
169 boolean filtertrace, boolean haltOnFailure) {
170 this(test, haltOnError, filtertrace, haltOnFailure, false);
171 }
172
173 /**
174 * Constructor for fork=true or when the user hasn't specified a
175 * classpath.
176 */
177 public JUnitTestRunner(JUnitTest test, boolean haltOnError,
178 boolean filtertrace, boolean haltOnFailure,
179 boolean showOutput) {
180 this(test, haltOnError, filtertrace, haltOnFailure, showOutput, null);
181 }
182
183 /**
184 * Constructor to use when the user has specified a classpath.
185 */
186 public JUnitTestRunner(JUnitTest test, boolean haltOnError,
187 boolean filtertrace, boolean haltOnFailure,
188 ClassLoader loader) {
189 this(test, haltOnError, filtertrace, haltOnFailure, false, loader);
190 }
191
192 /**
193 * Constructor to use when the user has specified a classpath.
194 */
195 public JUnitTestRunner(JUnitTest test, boolean haltOnError,
196 boolean filtertrace, boolean haltOnFailure,
197 boolean showOutput, ClassLoader loader) {
198 this.filtertrace = filtertrace;
199 this.junitTest = test;
200 this.haltOnError = haltOnError;
201 this.haltOnFailure = haltOnFailure;
202 this.showOutput = showOutput;
203 this.loader = loader;
204 }
205
206 public void run() {
207 res = new TestResult();
208 res.addListener(this);
209 for (int i = 0; i < formatters.size(); i++) {
210 res.addListener((TestListener) formatters.elementAt(i));
211 }
212
213 ByteArrayOutputStream errStrm = new ByteArrayOutputStream();
214 systemError = new PrintStream(errStrm);
215
216 ByteArrayOutputStream outStrm = new ByteArrayOutputStream();
217 systemOut = new PrintStream(outStrm);
218
219 PrintStream savedErr = null;
220 PrintStream savedOut = null;
221
222 if (forked) {
223 savedOut = System.out;
224 savedErr = System.err;
225 if (!showOutput) {
226 System.setOut(systemOut);
227 System.setErr(systemError);
228 } else {
229 System.setOut(new PrintStream(
230 new TeeOutputStream(savedOut, systemOut)
231 )
232 );
233 System.setErr(new PrintStream(
234 new TeeOutputStream(savedErr,
235 systemError)
236 )
237 );
238 }
239 perm = null;
240 } else {
241 if (perm != null) {
242 perm.setSecurityManager();
243 }
244 }
245
246 Test suite = null;
247 Throwable exception = null;
248
249 try {
250
251 try {
252 Class testClass = null;
253 if (loader == null) {
254 testClass = Class.forName(junitTest.getName());
255 } else {
256 testClass = Class.forName(junitTest.getName(), true,
257 loader);
258 }
259
260 Method suiteMethod = null;
261 try {
262 // check if there is a suite method
263 suiteMethod = testClass.getMethod("suite", new Class[0]);
264 } catch (NoSuchMethodException e) {
265 // no appropriate suite method found. We don't report any
266 // error here since it might be perfectly normal.
267 }
268 if (suiteMethod != null) {
269 // if there is a suite method available, then try
270 // to extract the suite from it. If there is an error
271 // here it will be caught below and reported.
272 suite = (Test) suiteMethod.invoke(null, new Class[0]);
273 } else {
274 // try to extract a test suite automatically this
275 // will generate warnings if the class is no
276 // suitable Test
277 suite = new TestSuite(testClass);
278 }
279
280 } catch (Throwable e) {
281 retCode = ERRORS;
282 exception = e;
283 }
284
285 long start = System.currentTimeMillis();
286
287 fireStartTestSuite();
288 if (exception != null) { // had an exception constructing suite
289 for (int i = 0; i < formatters.size(); i++) {
290 ((TestListener) formatters.elementAt(i))
291 .addError(null, exception);
292 }
293 junitTest.setCounts(1, 0, 1);
294 junitTest.setRunTime(0);
295 } else {
296 try {
297 suite.run(res);
298 } finally {
299 junitTest.setCounts(res.runCount(), res.failureCount(),
300 res.errorCount());
301 junitTest.setRunTime(System.currentTimeMillis() - start);
302 }
303 }
304 } finally {
305 if (perm != null) {
306 perm.restoreSecurityManager();
307 }
308 if (savedOut != null) {
309 System.setOut(savedOut);
310 }
311 if (savedErr != null) {
312 System.setErr(savedErr);
313 }
314
315 systemError.close();
316 systemError = null;
317 systemOut.close();
318 systemOut = null;
319 sendOutAndErr(new String(outStrm.toByteArray()),
320 new String(errStrm.toByteArray()));
321 }
322 fireEndTestSuite();
323
324 if (retCode != SUCCESS || res.errorCount() != 0) {
325 retCode = ERRORS;
326 } else if (res.failureCount() != 0) {
327 retCode = FAILURES;
328 }
329 }
330
331 /**
332 * Returns what System.exit() would return in the standalone version.
333 *
334 * @return 2 if errors occurred, 1 if tests failed else 0.
335 */
336 public int getRetCode() {
337 return retCode;
338 }
339
340 /**
341 * Interface TestListener.
342 *
343 * <p>A new Test is started.
344 */
345 public void startTest(Test t) {
346 }
347
348 /**
349 * Interface TestListener.
350 *
351 * <p>A Test is finished.
352 */
353 public void endTest(Test test) {
354 }
355
356 /**
357 * Interface TestListener for JUnit &lt;= 3.4.
358 *
359 * <p>A Test failed.
360 */
361 public void addFailure(Test test, Throwable t) {
362 if (haltOnFailure) {
363 res.stop();
364 }
365 }
366
367 /**
368 * Interface TestListener for JUnit &gt; 3.4.
369 *
370 * <p>A Test failed.
371 */
372 public void addFailure(Test test, AssertionFailedError t) {
373 addFailure(test, (Throwable) t);
374 }
375
376 /**
377 * Interface TestListener.
378 *
379 * <p>An error occurred while running the test.
380 */
381 public void addError(Test test, Throwable t) {
382 if (haltOnError) {
383 res.stop();
384 }
385 }
386
387 /**
388 * Permissions for the test run.
389 * @since Ant 1.6
390 * @param permissions
391 */
392 public void setPermissions(Permissions permissions) {
393 perm = permissions;
394 }
395
396 protected void handleOutput(String output) {
397 if (systemOut != null) {
398 systemOut.print(output);
399 }
400 }
401
402 /**
403 * @see org.apache.tools.ant.Task#handleInput(byte[], int, int)
404 *
405 * @since Ant 1.6
406 */
407 protected int handleInput(byte[] buffer, int offset, int length)
408 throws IOException {
409 return -1;
410 }
411
412 protected void handleErrorOutput(String output) {
413 if (systemError != null) {
414 systemError.print(output);
415 }
416 }
417
418 protected void handleFlush(String output) {
419 if (systemOut != null) {
420 systemOut.print(output);
421 }
422 }
423
424 protected void handleErrorFlush(String output) {
425 if (systemError != null) {
426 systemError.print(output);
427 }
428 }
429
430 private void sendOutAndErr(String out, String err) {
431 for (int i = 0; i < formatters.size(); i++) {
432 JUnitResultFormatter formatter =
433 ((JUnitResultFormatter) formatters.elementAt(i));
434
435 formatter.setSystemOutput(out);
436 formatter.setSystemError(err);
437 }
438 }
439
440 private void fireStartTestSuite() {
441 for (int i = 0; i < formatters.size(); i++) {
442 ((JUnitResultFormatter) formatters.elementAt(i))
443 .startTestSuite(junitTest);
444 }
445 }
446
447 private void fireEndTestSuite() {
448 for (int i = 0; i < formatters.size(); i++) {
449 ((JUnitResultFormatter) formatters.elementAt(i))
450 .endTestSuite(junitTest);
451 }
452 }
453
454 public void addFormatter(JUnitResultFormatter f) {
455 formatters.addElement(f);
456 }
457
458 /**
459 * Entry point for standalone (forked) mode.
460 *
461 * Parameters: testcaseclassname plus parameters in the format
462 * key=value, none of which is required.
463 *
464 * <table cols="4" border="1">
465 * <tr><th>key</th><th>description</th><th>default value</th></tr>
466 *
467 * <tr><td>haltOnError</td><td>halt test on
468 * errors?</td><td>false</td></tr>
469 *
470 * <tr><td>haltOnFailure</td><td>halt test on
471 * failures?</td><td>false</td></tr>
472 *
473 * <tr><td>formatter</td><td>A JUnitResultFormatter given as
474 * classname,filename. If filename is ommitted, System.out is
475 * assumed.</td><td>none</td></tr>
476 *
477 * <tr><td>showoutput</td><td>send output to System.err/.out as
478 * well as to the formatters?</td><td>false</td></tr>
479 *
480 * </table>
481 */
482 public static void main(String[] args) throws IOException {
483 boolean haltError = false;
484 boolean haltFail = false;
485 boolean stackfilter = true;
486 Properties props = new Properties();
487 boolean showOut = false;
488
489 if (args.length == 0) {
490 System.err.println("required argument TestClassName missing");
491 System.exit(ERRORS);
492 }
493
494 if (args[0].startsWith("testsfile=")) {
495 multipleTests = true;
496 args[0] = args[0].substring(10 /* "testsfile=".length() */);
497 }
498
499 for (int i = 1; i < args.length; i++) {
500 if (args[i].startsWith("haltOnError=")) {
501 haltError = Project.toBoolean(args[i].substring(12));
502 } else if (args[i].startsWith("haltOnFailure=")) {
503 haltFail = Project.toBoolean(args[i].substring(14));
504 } else if (args[i].startsWith("filtertrace=")) {
505 stackfilter = Project.toBoolean(args[i].substring(12));
506 } else if (args[i].startsWith("formatter=")) {
507 try {
508 createAndStoreFormatter(args[i].substring(10));
509 } catch (BuildException be) {
510 System.err.println(be.getMessage());
511 System.exit(ERRORS);
512 }
513 } else if (args[i].startsWith("propsfile=")) {
514 FileInputStream in = new FileInputStream(args[i]
515 .substring(10));
516 props.load(in);
517 in.close();
518 } else if (args[i].startsWith("showoutput=")) {
519 showOut = Project.toBoolean(args[i].substring(11));
520 }
521 }
522
523 // Add/overlay system properties on the properties from the Ant project
524 Hashtable p = System.getProperties();
525 for (Enumeration e = p.keys(); e.hasMoreElements();) {
526 Object key = e.nextElement();
527 props.put(key, p.get(key));
528 }
529
530 int returnCode = SUCCESS;
531 if (multipleTests) {
532 try {
533 java.io.BufferedReader reader =
534 new java.io.BufferedReader(new java.io.FileReader(args[0]));
535 String testCaseName;
536 int code = 0;
537 boolean errorOccured = false;
538 boolean failureOccured = false;
539 String line = null;
540 while ((line = reader.readLine()) != null) {
541 StringTokenizer st = new StringTokenizer(line, ",");
542 testCaseName = st.nextToken();
543 JUnitTest t = new JUnitTest(testCaseName);
544 t.setTodir(new File(st.nextToken()));
545 t.setOutfile(st.nextToken());
546 code = launch(t, haltError, stackfilter, haltFail,
547 showOut, props);
548 errorOccured = (code == ERRORS);
549 failureOccured = (code != SUCCESS);
550 if (errorOccured || failureOccured ) {
551 if ((errorOccured && haltError)
552 || (failureOccured && haltFail)) {
553 System.exit(code);
554 } else {
555 if (code > returnCode) {
556 returnCode = code;
557 }
558 System.out.println("TEST " + t.getName()
559 + " FAILED");
560 }
561 }
562 }
563 } catch(IOException e) {
564 e.printStackTrace();
565 }
566 } else {
567 returnCode = launch(new JUnitTest(args[0]), haltError,
568 stackfilter, haltFail, showOut, props);
569 }
570
571 System.exit(returnCode);
572 }
573
574 private static Vector fromCmdLine = new Vector();
575
576 private static void transferFormatters(JUnitTestRunner runner,
577 JUnitTest test) {
578 for (int i = 0; i < fromCmdLine.size(); i++) {
579 FormatterElement fe = (FormatterElement) fromCmdLine.elementAt(i);
580 if (multipleTests && fe.getUseFile()) {
581 File destFile =
582 new File(test.getTodir(),
583 test.getOutfile() + fe.getExtension());
584 fe.setOutfile(destFile);
585 }
586 runner.addFormatter(fe.createFormatter());
587 }
588 }
589
590 /**
591 * Line format is: formatter=<classname>(,<pathname>)?
592 */
593 private static void createAndStoreFormatter(String line)
594 throws BuildException {
595 FormatterElement fe = new FormatterElement();
596 int pos = line.indexOf(',');
597 if (pos == -1) {
598 fe.setClassname(line);
599 fe.setUseFile(false);
600 } else {
601 fe.setClassname(line.substring(0, pos));
602 fe.setUseFile(true);
603 if (!multipleTests) {
604 fe.setOutfile(new File(line.substring(pos + 1)));
605 } else {
606 int fName = line.indexOf(IGNORED_FILE_NAME);
607 if (fName > -1) {
608 fe.setExtension(line
609 .substring(fName
610 + IGNORED_FILE_NAME.length()));
611 }
612 }
613 }
614 fromCmdLine.addElement(fe);
615 }
616
617 /**
618 * Returns a filtered stack trace.
619 * This is ripped out of junit.runner.BaseTestRunner.
620 */
621 public static String getFilteredTrace(Throwable t) {
622 String trace = StringUtils.getStackTrace(t);
623 return JUnitTestRunner.filterStack(trace);
624 }
625
626 /**
627 * Filters stack frames from internal JUnit and Ant classes
628 */
629 public static String filterStack(String stack) {
630 if (!filtertrace) {
631 return stack;
632 }
633 StringWriter sw = new StringWriter();
634 PrintWriter pw = new PrintWriter(sw);
635 StringReader sr = new StringReader(stack);
636 BufferedReader br = new BufferedReader(sr);
637
638 String line;
639 try {
640 while ((line = br.readLine()) != null) {
641 if (!filterLine(line)) {
642 pw.println(line);
643 }
644 }
645 } catch (Exception IOException) {
646 return stack; // return the stack unfiltered
647 }
648 return sw.toString();
649 }
650
651 private static boolean filterLine(String line) {
652 for (int i = 0; i < DEFAULT_TRACE_FILTERS.length; i++) {
653 if (line.indexOf(DEFAULT_TRACE_FILTERS[i]) > 0) {
654 return true;
655 }
656 }
657 return false;
658 }
659
660 /**
661 * @since Ant 1.6.2
662 */
663 private static int launch(JUnitTest t, boolean haltError,
664 boolean stackfilter, boolean haltFail,
665 boolean showOut, Properties props) {
666 t.setProperties(props);
667 JUnitTestRunner runner =
668 new JUnitTestRunner(t, haltError, stackfilter, haltFail, showOut);
669 runner.forked = true;
670 transferFormatters(runner, t);
671
672 runner.run();
673 return runner.getRetCode();
674 }
675} // JUnitTestRunner
Note: See TracBrowser for help on using the repository browser.