1
1
package org .junit .runner .notification ;
2
2
3
- import net .jcip .annotations .ThreadSafe ;
4
- import org .junit .internal .AssumptionViolatedException ;
5
- import org .junit .runner .Description ;
6
- import org .junit .runner .Result ;
3
+ import static java .util .Arrays .asList ;
7
4
8
5
import java .util .ArrayList ;
9
- import java .util .Arrays ;
10
6
import java .util .Collection ;
11
- import java .util .concurrent .locks .ReentrantLock ;
7
+ import java .util .List ;
8
+ import java .util .concurrent .CopyOnWriteArrayList ;
9
+
10
+ import org .junit .internal .AssumptionViolatedException ;
11
+ import org .junit .runner .Description ;
12
+ import org .junit .runner .Result ;
12
13
13
14
/**
14
15
* If you write custom runners, you may need to notify JUnit of your progress running tests.
20
21
* @since 4.0
21
22
*/
22
23
public class RunNotifier {
23
- private final ReentrantLock lock = new ReentrantLock ();
24
-
25
- private volatile RunListener [] listeners = new RunListener [0 ];
26
- private volatile boolean pleaseStop = false ;
27
-
28
- private static RunListener wrapSynchronizedIfNotThreadSafe (RunListener listener ) {
29
- boolean isThreadSafe = listener .getClass ().isAnnotationPresent (ThreadSafe .class );
30
- return isThreadSafe ? listener : new SynchronizedRunListener (listener );
31
- }
32
-
33
- /**
34
- * Satisfies <tt>(o == null ? e == null : o.equals(e)</tt>
35
- * in {@link java.util.List#remove(Object)}.
36
- *
37
- * @param o listener to remove
38
- * @param e element in <code>listeners</code> which was previously added
39
- * @return {@code true} if <code>o</code> is equal with <code>e</code>
40
- */
41
- private static boolean equalListeners (Object o , Object e ) {
42
- if (o == null ) {
43
- return e == null ;
44
- } else {
45
- return e .getClass () == SynchronizedRunListener .class ? e .equals (o ) : o .equals (e );
46
- }
47
- }
24
+ private final List <RunListener > fListeners = new CopyOnWriteArrayList <RunListener >();
25
+ private volatile boolean fPleaseStop = false ;
48
26
49
27
/**
50
28
* Internal use only
51
29
*/
52
30
public void addListener (RunListener listener ) {
53
- if (listener != null ) {
54
- listener = wrapSynchronizedIfNotThreadSafe (listener );
55
- final ReentrantLock lock = this .lock ;
56
- lock .lock ();
57
- try {
58
- // same behavior as List#add(Object)
59
- RunListener [] elements = this .listeners ;
60
- int length = elements .length ;
61
- RunListener [] listeners = new RunListener [1 + length ];
62
- for (int i = 0 ; i < length ; ++i ) {
63
- listeners [i ] = elements [i ];
64
- }
65
- listeners [length ] = listener ;
66
- this .listeners = listeners ;
67
- } finally {
68
- lock .unlock ();
69
- }
70
- }
31
+ if (listener == null ) {
32
+ throw new NullPointerException ("Cannot add a null listener" );
33
+ }
34
+ fListeners .add (SynchronizedRunListener .wrapIfNotThreadSafe (listener ));
71
35
}
72
36
73
37
/**
74
38
* Internal use only
75
39
*/
76
40
public void removeListener (RunListener listener ) {
77
- if (listener != null ) {
78
- final ReentrantLock lock = this .lock ;
79
- lock .lock ();
80
- try {
81
- // same behavior as List#remove(Object)
82
- RunListener [] elements = this .listeners ;
83
- int length = elements .length ;
84
- if (length > 0 ) {
85
- RunListener [] listeners = new RunListener [length - 1 ];
86
- for (int i = 0 , newLength = listeners .length ; i < length ; ++i ) {
87
- if (equalListeners (listener , elements [i ])) {
88
- for (int k = 1 + i ; k != Integer .MAX_VALUE && k < length ; ++k ) {
89
- listeners [k - 1 ] = elements [k ];
90
- }
91
- this .listeners = listeners ;
92
- return ;
93
- } else if (i < newLength ) {
94
- listeners [i ] = elements [i ];
95
- }
96
- }
97
- }
98
- } finally {
99
- lock .unlock ();
100
- }
101
- }
41
+ if (listener == null ) {
42
+ throw new NullPointerException ("Cannot remove a null listener" );
43
+ }
44
+ fListeners .remove (SynchronizedRunListener .wrapIfNotThreadSafe (listener ));
102
45
}
103
46
104
47
private abstract class SafeNotifier {
105
- private final Collection <RunListener > currentListeners ;
48
+ private final List <RunListener > currentListeners ;
106
49
107
- SafeNotifier () {
108
- this (Arrays . asList ( listeners ) );
50
+ public SafeNotifier () {
51
+ this (fListeners );
109
52
}
110
53
111
- SafeNotifier (Collection <RunListener > currentListeners ) {
54
+ public SafeNotifier (List <RunListener > currentListeners ) {
112
55
this .currentListeners = currentListeners ;
113
56
}
114
57
@@ -134,7 +77,7 @@ void run() {
134
77
* Do not invoke.
135
78
*/
136
79
public void fireTestRunStarted (final Description description ) {
137
- new SafeNotifier () {
80
+ new SafeNotifier (fListeners ) {
138
81
@ Override
139
82
protected void notifyListener (RunListener each ) throws Exception {
140
83
each .testRunStarted (description );
@@ -161,7 +104,7 @@ protected void notifyListener(RunListener each) throws Exception {
161
104
* @throws StoppedByUserException thrown if a user has requested that the test run stop
162
105
*/
163
106
public void fireTestStarted (final Description description ) throws StoppedByUserException {
164
- if (pleaseStop ) {
107
+ if (fPleaseStop ) {
165
108
throw new StoppedByUserException ();
166
109
}
167
110
new SafeNotifier () {
@@ -178,10 +121,10 @@ protected void notifyListener(RunListener each) throws Exception {
178
121
* @param failure the description of the test that failed and the exception thrown
179
122
*/
180
123
public void fireTestFailure (Failure failure ) {
181
- fireTestFailures (Arrays . asList ( listeners ), Arrays . asList (failure ));
124
+ fireTestFailures (fListeners , asList (failure ));
182
125
}
183
126
184
- private void fireTestFailures (Collection <RunListener > listeners , final Collection <Failure > failures ) {
127
+ private void fireTestFailures (List <RunListener > listeners , final Collection <Failure > failures ) {
185
128
if (!failures .isEmpty ()) {
186
129
new SafeNotifier (listeners ) {
187
130
@ Override
@@ -247,29 +190,16 @@ protected void notifyListener(RunListener each) throws Exception {
247
190
* to be shared amongst the many runners involved.
248
191
*/
249
192
public void pleaseStop () {
250
- pleaseStop = true ;
193
+ fPleaseStop = true ;
251
194
}
252
195
253
196
/**
254
197
* Internal use only. The Result's listener must be first.
255
198
*/
256
199
public void addFirstListener (RunListener listener ) {
257
- if (listener != null ) {
258
- listener = wrapSynchronizedIfNotThreadSafe (listener );
259
- final ReentrantLock lock = this .lock ;
260
- lock .lock ();
261
- try {
262
- // same behavior as List#add(0, Object)
263
- RunListener [] elements = this .listeners ;
264
- RunListener [] listeners = new RunListener [1 + elements .length ];
265
- listeners [0 ] = listener ;
266
- for (int i = 0 , length = elements .length ; i < length ; ++i ) {
267
- listeners [1 + i ] = elements [i ];
268
- }
269
- this .listeners = listeners ;
270
- } finally {
271
- lock .unlock ();
272
- }
273
- }
200
+ if (listener == null ) {
201
+ throw new NullPointerException ("Cannot remove a null listener" );
202
+ }
203
+ fListeners .add (0 , SynchronizedRunListener .wrapIfNotThreadSafe (listener ));
274
204
}
275
- }
205
+ }
0 commit comments