Skip to content

Commit c220ad7

Browse files
author
Tibor Digana
committed
using COWAL + backward compatible + SynchronizedRunListener
1 parent 1d6914b commit c220ad7

File tree

9 files changed

+47
-91
lines changed

9 files changed

+47
-91
lines changed

Diff for: NOTICE.txt

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,6 @@
22
== Notices and attributions required by libraries that the project depends on ==
33
===================================================================================
44

5-
The JUnit depends on Java Hamcrest (http://hamcrest.org/JavaHamcrest/).
5+
The JUnit depends on Java Hamcrest (http://hamcrest.org/JavaHamcrest).
6+
7+
The JUnit depends on net.jcip:jcip-annotations:1.0 (http://jcip.net).

Diff for: build.xml

+14-4
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@
3030
<property name="javadoczip" location="${dist}-javadoc.zip" />
3131
<property name="hamcrestlib" location="lib/hamcrest-core-1.3.jar" />
3232
<property name="hamcrestlibsources" location="lib/hamcrest-core-1.3-sources.jar" />
33+
<property name="jciplib" location="lib/jcip-annotations-1.0.jar" />
34+
<property name="jciplibsources" location="lib/jcip-annotations-1.0-sources.jar" />
3335
<property name="hamcrestsrc" location="${dist}/temp.hamcrest.source" />
36+
<property name="jcipsrc" location="${dist}/temp.jcip.source" />
3437

3538
<property name="maven.deploy.goal" value="org.apache.maven.plugins:maven-gpg-plugin:1.1:sign-and-deploy-file" />
3639

@@ -80,9 +83,10 @@
8083
</macrodef>
8184

8285
<target name="build" depends="versiontag">
83-
<junit_compilation srcdir="${src}" destdir="${bin}" classpath="${hamcrestlib}"/>
86+
<junit_compilation srcdir="${src}" destdir="${bin}" classpath="${hamcrestlib};${jciplib}"/>
8487
<unjar src="${hamcrestlib}" dest="${bin}" />
85-
<junit_compilation srcdir="${testsrc}" destdir="${testbin}" classpath="${hamcrestlib};${bin}"/>
88+
<unjar src="${jciplib}" dest="${bin}" />
89+
<junit_compilation srcdir="${testsrc}" destdir="${testbin}" classpath="${hamcrestlib};${jciplib};${bin}"/>
8690
</target>
8791

8892
<target name="jars" depends="build">
@@ -128,6 +132,10 @@
128132
<target name="unjar.hamcrest">
129133
<unjar src="${hamcrestlibsources}" dest="${hamcrestsrc}" />
130134
</target>
135+
136+
<target name="unjar.jcip">
137+
<unjar src="${jciplibsources}" dest="${jcipsrc}" />
138+
</target>
131139

132140
<target name="release-notes">
133141
<property name="basename" value="doc/ReleaseNotes${version-base}" />
@@ -138,20 +146,21 @@
138146
</exec>
139147
</target>
140148

141-
<target name="javadoc" depends="unjar.hamcrest">
149+
<target name="javadoc" depends="unjar.hamcrest, unjar.jcip">
142150
<javadoc destdir="${javadocdir}"
143151
author="false"
144152
version="false"
145153
use="false"
146154
windowtitle="JUnit API"
147-
stylesheetfile="stylesheet.css"
155+
stylesheetfile="src/main/javadoc/stylesheet.css"
148156
>
149157
<excludepackage name="junit.*" />
150158
<excludepackage name="org.junit.internal.*" />
151159
<excludepackage name="org.junit.experimental.theories.internal.*" />
152160

153161
<sourcepath location="${src}" />
154162
<sourcepath location="${hamcrestsrc}" />
163+
<sourcepath location="${jcipsrc}" />
155164
<link href="http://java.sun.com/javase/6/docs/api/" />
156165
</javadoc>
157166
</target>
@@ -198,6 +207,7 @@
198207
<pathelement location="${bin}" />
199208
<pathelement location="${testbin}" />
200209
<pathelement location="${hamcrestlib}" />
210+
<pathelement location="${jciplib}" />
201211
</classpath>
202212
</java>
203213
</sequential>

Diff for: lib/jcip-annotations-1.0-sources.jar

4.88 KB
Binary file not shown.

Diff for: lib/jcip-annotations-1.0.jar

2.2 KB
Binary file not shown.

Diff for: pom.xml

+1
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@
261261
<includeDependencySources>true</includeDependencySources>
262262
<dependencySourceIncludes>
263263
<dependencySourceInclude>org.hamcrest:hamcrest-core:*</dependencySourceInclude>
264+
<dependencySourceInclude>net.jcip:jcip-annotations:*</dependencySourceInclude>
264265
</dependencySourceIncludes>
265266
</configuration>
266267
</plugin>

Diff for: src/main/java/org/junit/runner/Result.java

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.junit.runner;
22

3+
import net.jcip.annotations.ThreadSafe;
34
import org.junit.runner.notification.Failure;
45
import org.junit.runner.notification.RunListener;
56

@@ -65,6 +66,7 @@ public boolean wasSuccessful() {
6566
return getFailureCount() == 0;
6667
}
6768

69+
@ThreadSafe
6870
private class Listener extends RunListener {
6971
@Override
7072
public void testRunStarted(Description description) throws Exception {

Diff for: src/main/java/org/junit/runner/notification/RunNotifier.java

+11-83
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
import java.util.ArrayList;
99
import java.util.Arrays;
1010
import java.util.Collection;
11-
import java.util.concurrent.locks.ReentrantLock;
11+
import java.util.List;
12+
import java.util.concurrent.CopyOnWriteArrayList;
1213

1314
/**
1415
* If you write custom runners, you may need to notify JUnit of your progress running tests.
@@ -20,92 +21,35 @@
2021
* @since 4.0
2122
*/
2223
public class RunNotifier {
23-
private final ReentrantLock lock = new ReentrantLock();
24-
25-
private volatile RunListener[] listeners = new RunListener[0];
24+
private final CopyOnWriteArrayList<RunListener> listeners = new CopyOnWriteArrayList<RunListener>();
2625
private volatile boolean pleaseStop = false;
2726

2827
private static RunListener wrapSynchronizedIfNotThreadSafe(RunListener listener) {
2928
boolean isThreadSafe = listener.getClass().isAnnotationPresent(ThreadSafe.class);
3029
return isThreadSafe ? listener : new SynchronizedRunListener(listener);
3130
}
3231

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-
}
48-
4932
/**
5033
* Internal use only
5134
*/
5235
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-
}
36+
listener = wrapSynchronizedIfNotThreadSafe(listener);
37+
listeners.add(listener);
7138
}
7239

7340
/**
7441
* Internal use only
7542
*/
7643
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-
}
44+
listener = wrapSynchronizedIfNotThreadSafe(listener);
45+
listeners.remove(listener);
10246
}
10347

10448
private abstract class SafeNotifier {
10549
private final Collection<RunListener> currentListeners;
10650

10751
SafeNotifier() {
108-
this(Arrays.asList(listeners));
52+
this(listeners);
10953
}
11054

11155
SafeNotifier(Collection<RunListener> currentListeners) {
@@ -178,10 +122,10 @@ protected void notifyListener(RunListener each) throws Exception {
178122
* @param failure the description of the test that failed and the exception thrown
179123
*/
180124
public void fireTestFailure(Failure failure) {
181-
fireTestFailures(Arrays.asList(listeners), Arrays.asList(failure));
125+
fireTestFailures(listeners, Arrays.asList(failure));
182126
}
183127

184-
private void fireTestFailures(Collection<RunListener> listeners, final Collection<Failure> failures) {
128+
private void fireTestFailures(Collection<RunListener> listeners, final List<Failure> failures) {
185129
if (!failures.isEmpty()) {
186130
new SafeNotifier(listeners) {
187131
@Override
@@ -254,22 +198,6 @@ public void pleaseStop() {
254198
* Internal use only. The Result's listener must be first.
255199
*/
256200
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-
}
201+
listeners.add(0, listener);
274202
}
275203
}

Diff for: src/main/java/org/junit/runner/notification/SynchronizedRunListener.java

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.junit.runner.notification;
22

3+
import net.jcip.annotations.ThreadSafe;
34
import org.junit.runner.Description;
45
import org.junit.runner.Result;
56

@@ -11,6 +12,7 @@
1112
* @version 4.12
1213
* @since 4.12
1314
*/
15+
@ThreadSafe
1416
final class SynchronizedRunListener extends RunListener {
1517
private final RunListener listener;
1618

@@ -60,7 +62,16 @@ public int hashCode() {
6062

6163
@Override
6264
public boolean equals(Object o) {
63-
return o.equals(listener);
65+
if (o == this) {
66+
return true;
67+
}
68+
69+
if (o instanceof SynchronizedRunListener) {
70+
SynchronizedRunListener other = (SynchronizedRunListener) o;
71+
return listener.equals(other.listener);
72+
} else {
73+
return listener.equals(o);
74+
}
6475
}
6576

6677
@Override

Diff for: src/test/java/org/junit/tests/AllTests.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
import org.junit.internal.MethodSorterTest;
66
import org.junit.internal.matchers.StacktracePrintingMatcherTest;
77
import org.junit.runner.RunWith;
8-
import org.junit.runner.notification.RunNotifierTest;
8+
import org.junit.runner.notification.AddRemoveListenerTest;
99
import org.junit.runner.notification.ConcurrentRunNotifierTest;
10+
import org.junit.runner.notification.RunNotifierTest;
1011
import org.junit.runners.Suite;
1112
import org.junit.runners.Suite.SuiteClasses;
1213
import org.junit.tests.assertion.AssertionTest;
@@ -170,7 +171,8 @@
170171
StacktracePrintingMatcherTest.class,
171172
StopwatchTest.class,
172173
RunNotifierTest.class,
173-
ConcurrentRunNotifierTest.class
174+
ConcurrentRunNotifierTest.class,
175+
AddRemoveListenerTest.class
174176
})
175177
public class AllTests {
176178
public static Test suite() {

0 commit comments

Comments
 (0)