001package junit.framework;
002
003import java.util.ArrayList;
004import java.util.Collections;
005import java.util.Enumeration;
006import java.util.List;
007
008/**
009 * A <code>TestResult</code> collects the results of executing
010 * a test case. It is an instance of the Collecting Parameter pattern.
011 * The test framework distinguishes between <i>failures</i> and <i>errors</i>.
012 * A failure is anticipated and checked for with assertions. Errors are
013 * unanticipated problems like an {@link ArrayIndexOutOfBoundsException}.
014 *
015 * @see Test
016 */
017public class TestResult {
018    protected List<TestFailure> fFailures;
019    protected List<TestFailure> fErrors;
020    protected List<TestListener> fListeners;
021    protected int fRunTests;
022    private boolean fStop;
023
024    public TestResult() {
025        fFailures = new ArrayList<TestFailure>();
026        fErrors = new ArrayList<TestFailure>();
027        fListeners = new ArrayList<TestListener>();
028        fRunTests = 0;
029        fStop = false;
030    }
031
032    /**
033     * Adds an error to the list of errors. The passed in exception
034     * caused the error.
035     */
036    public synchronized void addError(Test test, Throwable e) {
037        fErrors.add(new TestFailure(test, e));
038        for (TestListener each : cloneListeners()) {
039            each.addError(test, e);
040        }
041    }
042
043    /**
044     * Adds a failure to the list of failures. The passed in exception
045     * caused the failure.
046     */
047    public synchronized void addFailure(Test test, AssertionFailedError e) {
048        fFailures.add(new TestFailure(test, e));
049        for (TestListener each : cloneListeners()) {
050            each.addFailure(test, e);
051        }
052    }
053
054    /**
055     * Registers a TestListener.
056     */
057    public synchronized void addListener(TestListener listener) {
058        fListeners.add(listener);
059    }
060
061    /**
062     * Unregisters a TestListener.
063     */
064    public synchronized void removeListener(TestListener listener) {
065        fListeners.remove(listener);
066    }
067
068    /**
069     * Returns a copy of the listeners.
070     */
071    private synchronized List<TestListener> cloneListeners() {
072        List<TestListener> result = new ArrayList<TestListener>();
073        result.addAll(fListeners);
074        return result;
075    }
076
077    /**
078     * Informs the result that a test was completed.
079     */
080    public void endTest(Test test) {
081        for (TestListener each : cloneListeners()) {
082            each.endTest(test);
083        }
084    }
085
086    /**
087     * Gets the number of detected errors.
088     */
089    public synchronized int errorCount() {
090        return fErrors.size();
091    }
092
093    /**
094     * Returns an Enumeration for the errors.
095     */
096    public synchronized Enumeration<TestFailure> errors() {
097        return Collections.enumeration(fErrors);
098    }
099
100
101    /**
102     * Gets the number of detected failures.
103     */
104    public synchronized int failureCount() {
105        return fFailures.size();
106    }
107
108    /**
109     * Returns an Enumeration for the failures.
110     */
111    public synchronized Enumeration<TestFailure> failures() {
112        return Collections.enumeration(fFailures);
113    }
114
115    /**
116     * Runs a TestCase.
117     */
118    protected void run(final TestCase test) {
119        startTest(test);
120        Protectable p = new Protectable() {
121            public void protect() throws Throwable {
122                test.runBare();
123            }
124        };
125        runProtected(test, p);
126
127        endTest(test);
128    }
129
130    /**
131     * Gets the number of run tests.
132     */
133    public synchronized int runCount() {
134        return fRunTests;
135    }
136
137    /**
138     * Runs a TestCase.
139     */
140    public void runProtected(final Test test, Protectable p) {
141        try {
142            p.protect();
143        } catch (AssertionFailedError e) {
144            addFailure(test, e);
145        } catch (ThreadDeath e) { // don't catch ThreadDeath by accident
146            throw e;
147        } catch (Throwable e) {
148            addError(test, e);
149        }
150    }
151
152    /**
153     * Checks whether the test run should stop.
154     */
155    public synchronized boolean shouldStop() {
156        return fStop;
157    }
158
159    /**
160     * Informs the result that a test will be started.
161     */
162    public void startTest(Test test) {
163        final int count = test.countTestCases();
164        synchronized (this) {
165            fRunTests += count;
166        }
167        for (TestListener each : cloneListeners()) {
168            each.startTest(test);
169        }
170    }
171
172    /**
173     * Marks that the test run should stop.
174     */
175    public synchronized void stop() {
176        fStop = true;
177    }
178
179    /**
180     * Returns whether the entire test was successful or not.
181     */
182    public synchronized boolean wasSuccessful() {
183        return failureCount() == 0 && errorCount() == 0;
184    }
185}