001: package org.junit.runner.notification;
002:
003: import java.util.ArrayList;
004: import java.util.Iterator;
005: import java.util.List;
006:
007: import org.junit.runner.Description;
008: import org.junit.runner.Result;
009:
010: /**
011: * If you write custom runners, you may need to notify JUnit of your progress running tests.
012: * Do this by invoking the <code>RunNotifier</code> passed to your implementation of
013: * {@link org.junit.runner.Runner#run(RunNotifier)}. Future evolution of this class is likely to
014: * move {@link #fireTestRunStarted(Description)} and {@link #fireTestRunFinished(Result)}
015: * to a separate class since they should only be called once per run.
016: */
017: public class RunNotifier {
018: private List<RunListener> fListeners = new ArrayList<RunListener>();
019: private boolean fPleaseStop = false;
020:
021: /** Internal use only
022: */
023: public void addListener(RunListener listener) {
024: fListeners.add(listener);
025: }
026:
027: /** Internal use only
028: */
029: public void removeListener(RunListener listener) {
030: fListeners.remove(listener);
031: }
032:
033: private abstract class SafeNotifier {
034: void run() {
035: for (Iterator<RunListener> all = fListeners.iterator(); all
036: .hasNext();) {
037: try {
038: notifyListener(all.next());
039: } catch (Exception e) {
040: all.remove(); // Remove the offending listener first to avoid an infinite loop
041: fireTestFailure(new Failure(
042: Description.TEST_MECHANISM, e));
043: }
044: }
045: }
046:
047: abstract protected void notifyListener(RunListener each)
048: throws Exception;
049: }
050:
051: /**
052: * Do not invoke.
053: */
054: public void fireTestRunStarted(final Description description) {
055: new SafeNotifier() {
056: @Override
057: protected void notifyListener(RunListener each)
058: throws Exception {
059: each.testRunStarted(description);
060: };
061: }.run();
062: }
063:
064: /**
065: * Do not invoke.
066: */
067: public void fireTestRunFinished(final Result result) {
068: new SafeNotifier() {
069: @Override
070: protected void notifyListener(RunListener each)
071: throws Exception {
072: each.testRunFinished(result);
073: };
074: }.run();
075: }
076:
077: /**
078: * Invoke to tell listeners that an atomic test is about to start.
079: * @param description the description of the atomic test (generally a class and method name)
080: * @throws StoppedByUserException thrown if a user has requested that the test run stop
081: */
082: public void fireTestStarted(final Description description)
083: throws StoppedByUserException {
084: if (fPleaseStop)
085: throw new StoppedByUserException();
086: new SafeNotifier() {
087: @Override
088: protected void notifyListener(RunListener each)
089: throws Exception {
090: each.testStarted(description);
091: };
092: }.run();
093: }
094:
095: /**
096: * Invoke to tell listeners that an atomic test failed.
097: * @param failure the description of the test that failed and the exception thrown
098: */
099: public void fireTestFailure(final Failure failure) {
100: new SafeNotifier() {
101: @Override
102: protected void notifyListener(RunListener each)
103: throws Exception {
104: each.testFailure(failure);
105: };
106: }.run();
107: }
108:
109: /**
110: * Invoke to tell listeners that an atomic test was ignored.
111: * @param description the description of the ignored test
112: */
113: public void fireTestIgnored(final Description description) {
114: new SafeNotifier() {
115: @Override
116: protected void notifyListener(RunListener each)
117: throws Exception {
118: each.testIgnored(description);
119: };
120: }.run();
121: }
122:
123: /**
124: * Invoke to tell listeners that an atomic test finished. Always invoke
125: * {@link #fireTestFinished(Description)} if you invoke {@link #fireTestStarted(Description)}
126: * as listeners are likely to expect them to come in pairs.
127: * @param description the description of the test that finished
128: */
129: public void fireTestFinished(final Description description) {
130: new SafeNotifier() {
131: @Override
132: protected void notifyListener(RunListener each)
133: throws Exception {
134: each.testFinished(description);
135: };
136: }.run();
137: }
138:
139: /**
140: * Ask that the tests run stop before starting the next test. Phrased politely because
141: * the test currently running will not be interrupted. It seems a little odd to put this
142: * functionality here, but the <code>RunNotifier</code> is the only object guaranteed
143: * to be shared amongst the many runners involved.
144: */
145: public void pleaseStop() {
146: fPleaseStop = true;
147: }
148:
149: /**
150: * Internal use only. The Result's listener must be first.
151: */
152: public void addFirstListener(RunListener listener) {
153: fListeners.add(0, listener);
154: }
155:
156: public void testAborted(Description description, Throwable cause) {
157: fireTestStarted(description);
158: fireTestFailure(new Failure(description, cause));
159: fireTestFinished(description);
160: }
161: }
|