001 package junit.textui;
002
003 import java.io.PrintStream;
004 import java.text.NumberFormat;
005 import java.util.Enumeration;
006
007 import junit.framework.AssertionFailedError;
008 import junit.framework.Test;
009 import junit.framework.TestFailure;
010 import junit.framework.TestListener;
011 import junit.framework.TestResult;
012 import junit.runner.BaseTestRunner;
013
014 public class ResultPrinter implements TestListener {
015 PrintStream fWriter;
016 int fColumn = 0;
017
018 public ResultPrinter(PrintStream writer) {
019 fWriter = writer;
020 }
021
022 /* API for use by textui.TestRunner */
023
024 synchronized void print(TestResult result, long runTime) {
025 printHeader(runTime);
026 printErrors(result);
027 printFailures(result);
028 printFooter(result);
029 }
030
031 void printWaitPrompt() {
032 getWriter().println();
033 getWriter().println("<RETURN> to continue");
034 }
035
036 /* Internal methods */
037
038 protected void printHeader(long runTime) {
039 getWriter().println();
040 getWriter().println("Time: " + elapsedTimeAsString(runTime));
041 }
042
043 protected void printErrors(TestResult result) {
044 printDefects(result.errors(), result.errorCount(), "error");
045 }
046
047 protected void printFailures(TestResult result) {
048 printDefects(result.failures(), result.failureCount(), "failure");
049 }
050
051 protected void printDefects(Enumeration<TestFailure> booBoos, int count, String type) {
052 if (count == 0) return;
053 if (count == 1) {
054 getWriter().println("There was " + count + " " + type + ":");
055 } else {
056 getWriter().println("There were " + count + " " + type + "s:");
057 }
058 for (int i = 1; booBoos.hasMoreElements(); i++) {
059 printDefect(booBoos.nextElement(), i);
060 }
061 }
062
063 public void printDefect(TestFailure booBoo, int count) { // only public for testing purposes
064 printDefectHeader(booBoo, count);
065 printDefectTrace(booBoo);
066 }
067
068 protected void printDefectHeader(TestFailure booBoo, int count) {
069 // I feel like making this a println, then adding a line giving the throwable a chance to print something
070 // before we get to the stack trace.
071 getWriter().print(count + ") " + booBoo.failedTest());
072 }
073
074 protected void printDefectTrace(TestFailure booBoo) {
075 getWriter().print(BaseTestRunner.getFilteredTrace(booBoo.trace()));
076 }
077
078 protected void printFooter(TestResult result) {
079 if (result.wasSuccessful()) {
080 getWriter().println();
081 getWriter().print("OK");
082 getWriter().println(" (" + result.runCount() + " test" + (result.runCount() == 1 ? "" : "s") + ")");
083
084 } else {
085 getWriter().println();
086 getWriter().println("FAILURES!!!");
087 getWriter().println("Tests run: " + result.runCount() +
088 ", Failures: " + result.failureCount() +
089 ", Errors: " + result.errorCount());
090 }
091 getWriter().println();
092 }
093
094 /**
095 * Returns the formatted string of the elapsed time.
096 * Duplicated from BaseTestRunner. Fix it.
097 */
098 protected String elapsedTimeAsString(long runTime) {
099 return NumberFormat.getInstance().format((double) runTime / 1000);
100 }
101
102 public PrintStream getWriter() {
103 return fWriter;
104 }
105
106 /**
107 * @see junit.framework.TestListener#addError(Test, Throwable)
108 */
109 public void addError(Test test, Throwable e) {
110 getWriter().print("E");
111 }
112
113 /**
114 * @see junit.framework.TestListener#addFailure(Test, AssertionFailedError)
115 */
116 public void addFailure(Test test, AssertionFailedError t) {
117 getWriter().print("F");
118 }
119
120 /**
121 * @see junit.framework.TestListener#endTest(Test)
122 */
123 public void endTest(Test test) {
124 }
125
126 /**
127 * @see junit.framework.TestListener#startTest(Test)
128 */
129 public void startTest(Test test) {
130 getWriter().print(".");
131 if (fColumn++ >= 40) {
132 getWriter().println();
133 fColumn = 0;
134 }
135 }
136
137 }