1 package org.junit.runner.notification; 2 3 import java.util.ArrayList; 4 import java.util.Collections; 5 import java.util.Iterator; 6 import java.util.List; 7 8 import org.junit.internal.AssumptionViolatedException; 9 import org.junit.runner.Description; 10 import org.junit.runner.Result; 11 12 /** 13 * If you write custom runners, you may need to notify JUnit of your progress running tests. 14 * Do this by invoking the <code>RunNotifier</code> passed to your implementation of 15 * {@link org.junit.runner.Runner#run(RunNotifier)}. Future evolution of this class is likely to 16 * move {@link #fireTestRunStarted(Description)} and {@link #fireTestRunFinished(Result)} 17 * to a separate class since they should only be called once per run. 18 */ 19 public class RunNotifier { 20 private final List<RunListener> fListeners= 21 Collections.synchronizedList(new ArrayList<RunListener>()); 22 private boolean fPleaseStop= false; 23 24 /** Internal use only 25 */ addListener(RunListener listener)26 public void addListener(RunListener listener) { 27 fListeners.add(listener); 28 } 29 30 /** Internal use only 31 */ removeListener(RunListener listener)32 public void removeListener(RunListener listener) { 33 fListeners.remove(listener); 34 } 35 36 private abstract class SafeNotifier { run()37 void run() { 38 synchronized (fListeners) { 39 for (Iterator<RunListener> all= fListeners.iterator(); all.hasNext();) 40 try { 41 notifyListener(all.next()); 42 } catch (Exception e) { 43 all.remove(); // Remove the offending listener first to avoid an infinite loop 44 fireTestFailure(new Failure(Description.TEST_MECHANISM, e)); 45 } 46 } 47 } 48 notifyListener(RunListener each)49 abstract protected void notifyListener(RunListener each) throws Exception; 50 } 51 52 /** 53 * Do not invoke. 54 */ fireTestRunStarted(final Description description)55 public void fireTestRunStarted(final Description description) { 56 new SafeNotifier() { 57 @Override 58 protected void notifyListener(RunListener each) throws Exception { 59 each.testRunStarted(description); 60 }; 61 }.run(); 62 } 63 64 /** 65 * Do not invoke. 66 */ fireTestRunFinished(final Result result)67 public void fireTestRunFinished(final Result result) { 68 new SafeNotifier() { 69 @Override 70 protected void notifyListener(RunListener each) throws Exception { 71 each.testRunFinished(result); 72 }; 73 }.run(); 74 } 75 76 /** 77 * Invoke to tell listeners that an atomic test is about to start. 78 * @param description the description of the atomic test (generally a class and method name) 79 * @throws StoppedByUserException thrown if a user has requested that the test run stop 80 */ fireTestStarted(final Description description)81 public void fireTestStarted(final Description description) throws StoppedByUserException { 82 if (fPleaseStop) 83 throw new StoppedByUserException(); 84 new SafeNotifier() { 85 @Override 86 protected void notifyListener(RunListener each) throws Exception { 87 each.testStarted(description); 88 }; 89 }.run(); 90 } 91 92 /** 93 * Invoke to tell listeners that an atomic test failed. 94 * @param failure the description of the test that failed and the exception thrown 95 */ fireTestFailure(final Failure failure)96 public void fireTestFailure(final Failure failure) { 97 new SafeNotifier() { 98 @Override 99 protected void notifyListener(RunListener each) throws Exception { 100 each.testFailure(failure); 101 }; 102 }.run(); 103 } 104 105 /** 106 * Invoke to tell listeners that an atomic test flagged that it assumed 107 * something false. 108 * 109 * @param failure 110 * the description of the test that failed and the 111 * {@link AssumptionViolatedException} thrown 112 */ fireTestAssumptionFailed(final Failure failure)113 public void fireTestAssumptionFailed(final Failure failure) { 114 new SafeNotifier() { 115 @Override 116 protected void notifyListener(RunListener each) throws Exception { 117 each.testAssumptionFailure(failure); 118 }; 119 }.run(); 120 } 121 122 /** 123 * Invoke to tell listeners that an atomic test was ignored. 124 * @param description the description of the ignored test 125 */ fireTestIgnored(final Description description)126 public void fireTestIgnored(final Description description) { 127 new SafeNotifier() { 128 @Override 129 protected void notifyListener(RunListener each) throws Exception { 130 each.testIgnored(description); 131 } 132 }.run(); 133 } 134 135 /** 136 * Invoke to tell listeners that an atomic test finished. Always invoke 137 * {@link #fireTestFinished(Description)} if you invoke {@link #fireTestStarted(Description)} 138 * as listeners are likely to expect them to come in pairs. 139 * @param description the description of the test that finished 140 */ fireTestFinished(final Description description)141 public void fireTestFinished(final Description description) { 142 new SafeNotifier() { 143 @Override 144 protected void notifyListener(RunListener each) throws Exception { 145 each.testFinished(description); 146 }; 147 }.run(); 148 } 149 150 /** 151 * Ask that the tests run stop before starting the next test. Phrased politely because 152 * the test currently running will not be interrupted. It seems a little odd to put this 153 * functionality here, but the <code>RunNotifier</code> is the only object guaranteed 154 * to be shared amongst the many runners involved. 155 */ pleaseStop()156 public void pleaseStop() { 157 fPleaseStop= true; 158 } 159 160 /** 161 * Internal use only. The Result's listener must be first. 162 */ addFirstListener(RunListener listener)163 public void addFirstListener(RunListener listener) { 164 fListeners.add(0, listener); 165 } 166 }