Skip to content

Commit 02f1486

Browse files
committed
Merge branch 'Tibor17-junit.issues' into concurrent-run-listeners
Conflicts: src/test/java/org/junit/runner/notification/SynchronizedRunListenerTest.java src/test/java/org/junit/tests/AllTests.java
2 parents a04aae1 + 708d972 commit 02f1486

File tree

4 files changed

+172
-152
lines changed

4 files changed

+172
-152
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package org.junit.experimental.annotations;
2+
3+
import java.lang.annotation.*;
4+
5+
/**
6+
* Implementation is guaranteed to be free of race conditions
7+
* when accessed by multiple threads simultaneously.
8+
*
9+
* @author Tibor Digana (tibor17)
10+
* @version 4.12
11+
* @since 4.12
12+
*/
13+
@Documented
14+
@Target(ElementType.TYPE)
15+
@Retention(RetentionPolicy.RUNTIME)
16+
public @interface ThreadSafe {
17+
}

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

+7-2
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,17 @@
88
import org.junit.runner.Result;
99

1010
/**
11-
* SynchronizedRunListener decorates {@link RunListener} and
12-
* has all methods synchronized.
11+
* SynchronizedRunListener decorates {@link RunListener}, has all methods
12+
* synchronized and is <em>not</em> public.
13+
* <p>
14+
* Due to backward compatibility, this synchronized listener behaves thread
15+
* safe as {@link RunListener} in the old synchronized {@link RunNotifier}.
1316
*
1417
* @author Tibor Digana (tibor17)
1518
* @version 4.12
1619
* @since 4.12
20+
*
21+
* @see RunNotifier
1722
*/
1823
@ThreadSafe
1924
final class SynchronizedRunListener extends RunListener {
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// Copyright 2013 Google Inc. All Rights Reserved.
2-
31
package org.junit.runner.notification;
42

53
import static org.hamcrest.CoreMatchers.instanceOf;
@@ -26,150 +24,150 @@
2624
*/
2725
public class SynchronizedRunListenerTest {
2826

29-
private static class MethodSignature {
30-
private final Method method;
31-
private final String name;
32-
private final List<Class<?>> parameterTypes;
33-
34-
public MethodSignature(Method method) {
35-
this.method= method;
36-
name= method.getName();
37-
parameterTypes= Arrays.asList(method.getParameterTypes());
38-
}
39-
40-
@Override
41-
public String toString() {
42-
return method.toString();
43-
}
44-
45-
@Override
46-
public int hashCode() {
47-
return name.hashCode();
48-
}
49-
50-
@Override
51-
public boolean equals(Object obj) {
52-
if (this == obj) {
53-
return true;
54-
}
55-
if (!(obj instanceof MethodSignature)) {
56-
return false;
57-
}
58-
MethodSignature that = (MethodSignature) obj;
59-
return name.equals(that.name) && parameterTypes.equals(that.parameterTypes);
60-
}
61-
}
62-
63-
private Set<MethodSignature> getAllDeclaredMethods(Class<?> type) {
64-
Set<MethodSignature> methods = new HashSet<MethodSignature>();
65-
for (Method method : type.getDeclaredMethods()) {
66-
methods.add(new MethodSignature(method));
67-
}
68-
return methods;
69-
}
70-
71-
@Test
72-
public void overridesAllMethodsInRunListener() {
73-
Set<MethodSignature> runListenerMethods= getAllDeclaredMethods(RunListener.class);
74-
Set<MethodSignature> synchronizedRunListenerMethods= getAllDeclaredMethods(
75-
SynchronizedRunListener.class);
76-
77-
assertTrue(synchronizedRunListenerMethods.containsAll(runListenerMethods));
78-
}
79-
80-
private static class NamedListener extends RunListener {
81-
private final String name;
82-
83-
public NamedListener(String name) {
84-
this.name= name;
85-
}
86-
87-
@Override
88-
public int hashCode() {
89-
return name.hashCode();
90-
}
91-
92-
@Override
93-
public boolean equals(Object obj) {
94-
if (this == obj) {
95-
return true;
96-
}
97-
if (!(obj instanceof NamedListener)) {
98-
return false;
99-
}
100-
NamedListener that= (NamedListener) obj;
101-
return this.name.equals(that.name);
102-
}
103-
}
104-
105-
@ThreadSafe
106-
private static class ThreadSafeRunListener extends RunListener {
107-
}
108-
109-
@Test
110-
public void namedListenerCorrectlyImplementsEqualsAndHashCode() {
111-
NamedListener listener1 = new NamedListener("blue");
112-
NamedListener listener2 = new NamedListener("blue");
113-
NamedListener listener3 = new NamedListener("red");
114-
115-
assertTrue(listener1.equals(listener1));
116-
assertTrue(listener2.equals(listener2));
117-
assertTrue(listener3.equals(listener3));
118-
119-
assertFalse(listener1.equals(null));
120-
assertFalse(listener1.equals(new Object()));
121-
122-
assertTrue(listener1.equals(listener2));
123-
assertTrue(listener2.equals(listener1));
124-
assertFalse(listener1.equals(listener3));
125-
assertFalse(listener3.equals(listener1));
126-
127-
assertEquals(listener1.hashCode(), listener2.hashCode());
128-
assertNotEquals(listener1.hashCode(), listener3.hashCode());
129-
}
130-
131-
@Test
132-
public void equalsDelegates() {
133-
NamedListener listener1 = new NamedListener("blue");
134-
NamedListener listener2 = new NamedListener("blue");
135-
NamedListener listener3 = new NamedListener("red");
136-
137-
assertEquals(new SynchronizedRunListener(listener1),
138-
new SynchronizedRunListener(listener1));
139-
assertEquals(new SynchronizedRunListener(listener1),
140-
new SynchronizedRunListener(listener2));
141-
assertNotEquals(new SynchronizedRunListener(listener1),
142-
new SynchronizedRunListener(listener3));
143-
assertNotEquals(new SynchronizedRunListener(listener1), listener1);
144-
assertNotEquals(listener1, new SynchronizedRunListener(listener1));
145-
}
146-
147-
@Test
148-
public void hashCodeDelegates() {
149-
NamedListener listener = new NamedListener("blue");
150-
assertEquals(listener.hashCode(), new SynchronizedRunListener(listener).hashCode());
151-
}
152-
153-
@Test
154-
public void wrapIfNotThreadSafeShouldNotWrapThreadSafeListeners() {
155-
ThreadSafeRunListener listener= new ThreadSafeRunListener();;
156-
assertSame(listener, SynchronizedRunListener.wrapIfNotThreadSafe(listener));
157-
}
158-
159-
/**
160-
* Tests that {@link SynchronizedRunListener#wrapIfNotThreadSafe(RunListener)}
161-
* wraps listeners that are not thread-safe. This does not check if the
162-
* listener is synchronized; that is tested with the tests for {@link RunNotifier}.
163-
*/
164-
@Test
165-
public void wrapIfNotThreadSafeShouldWrapNonThreadSafeListeners() {
166-
NamedListener listener= new NamedListener("name");
167-
RunListener wrappedListener= SynchronizedRunListener.wrapIfNotThreadSafe(listener);
168-
assertThat(wrappedListener, instanceOf(SynchronizedRunListener.class));
169-
}
170-
171-
@Test
172-
public void dynamicallyLoadsThreadSafeAnnotatoin() {
173-
assertEquals(ThreadSafe.class, SynchronizedRunListener.getThreadSafeAnnotationClass());
174-
}
27+
private static class MethodSignature {
28+
private final Method method;
29+
private final String name;
30+
private final List<Class<?>> parameterTypes;
31+
32+
public MethodSignature(Method method) {
33+
this.method= method;
34+
name= method.getName();
35+
parameterTypes= Arrays.asList(method.getParameterTypes());
36+
}
37+
38+
@Override
39+
public String toString() {
40+
return method.toString();
41+
}
42+
43+
@Override
44+
public int hashCode() {
45+
return name.hashCode();
46+
}
47+
48+
@Override
49+
public boolean equals(Object obj) {
50+
if (this == obj) {
51+
return true;
52+
}
53+
if (!(obj instanceof MethodSignature)) {
54+
return false;
55+
}
56+
MethodSignature that = (MethodSignature) obj;
57+
return name.equals(that.name) && parameterTypes.equals(that.parameterTypes);
58+
}
59+
}
60+
61+
private Set<MethodSignature> getAllDeclaredMethods(Class<?> type) {
62+
Set<MethodSignature> methods = new HashSet<MethodSignature>();
63+
for (Method method : type.getDeclaredMethods()) {
64+
methods.add(new MethodSignature(method));
65+
}
66+
return methods;
67+
}
68+
69+
@Test
70+
public void overridesAllMethodsInRunListener() {
71+
Set<MethodSignature> runListenerMethods= getAllDeclaredMethods(RunListener.class);
72+
Set<MethodSignature> synchronizedRunListenerMethods= getAllDeclaredMethods(
73+
SynchronizedRunListener.class);
74+
75+
assertTrue(synchronizedRunListenerMethods.containsAll(runListenerMethods));
76+
}
77+
78+
private static class NamedListener extends RunListener {
79+
private final String name;
80+
81+
public NamedListener(String name) {
82+
this.name= name;
83+
}
84+
85+
@Override
86+
public int hashCode() {
87+
return name.hashCode();
88+
}
89+
90+
@Override
91+
public boolean equals(Object obj) {
92+
if (this == obj) {
93+
return true;
94+
}
95+
if (!(obj instanceof NamedListener)) {
96+
return false;
97+
}
98+
NamedListener that= (NamedListener) obj;
99+
return this.name.equals(that.name);
100+
}
101+
}
102+
103+
@ThreadSafe
104+
private static class ThreadSafeRunListener extends RunListener {
105+
}
106+
107+
@Test
108+
public void namedListenerCorrectlyImplementsEqualsAndHashCode() {
109+
NamedListener listener1 = new NamedListener("blue");
110+
NamedListener listener2 = new NamedListener("blue");
111+
NamedListener listener3 = new NamedListener("red");
112+
113+
assertTrue(listener1.equals(listener1));
114+
assertTrue(listener2.equals(listener2));
115+
assertTrue(listener3.equals(listener3));
116+
117+
assertFalse(listener1.equals(null));
118+
assertFalse(listener1.equals(new Object()));
119+
120+
assertTrue(listener1.equals(listener2));
121+
assertTrue(listener2.equals(listener1));
122+
assertFalse(listener1.equals(listener3));
123+
assertFalse(listener3.equals(listener1));
124+
125+
assertEquals(listener1.hashCode(), listener2.hashCode());
126+
assertNotEquals(listener1.hashCode(), listener3.hashCode());
127+
}
128+
129+
@Test
130+
public void equalsDelegates() {
131+
NamedListener listener1 = new NamedListener("blue");
132+
NamedListener listener2 = new NamedListener("blue");
133+
NamedListener listener3 = new NamedListener("red");
134+
135+
assertEquals(new SynchronizedRunListener(listener1),
136+
new SynchronizedRunListener(listener1));
137+
assertEquals(new SynchronizedRunListener(listener1),
138+
new SynchronizedRunListener(listener2));
139+
assertNotEquals(new SynchronizedRunListener(listener1),
140+
new SynchronizedRunListener(listener3));
141+
assertNotEquals(new SynchronizedRunListener(listener1), listener1);
142+
assertNotEquals(listener1, new SynchronizedRunListener(listener1));
143+
}
144+
145+
@Test
146+
public void hashCodeDelegates() {
147+
NamedListener listener = new NamedListener("blue");
148+
assertEquals(listener.hashCode(), new SynchronizedRunListener(listener).hashCode());
149+
}
150+
151+
@Test
152+
public void wrapIfNotThreadSafeShouldNotWrapThreadSafeListeners() {
153+
ThreadSafeRunListener listener= new ThreadSafeRunListener();;
154+
assertSame(listener, SynchronizedRunListener.wrapIfNotThreadSafe(listener));
155+
}
156+
157+
/**
158+
* Tests that {@link SynchronizedRunListener#wrapIfNotThreadSafe(RunListener)}
159+
* wraps listeners that are not thread-safe. This does not check if the
160+
* listener is synchronized; that is tested with the tests for {@link RunNotifier}.
161+
*/
162+
@Test
163+
public void wrapIfNotThreadSafeShouldWrapNonThreadSafeListeners() {
164+
NamedListener listener= new NamedListener("name");
165+
RunListener wrappedListener= SynchronizedRunListener.wrapIfNotThreadSafe(listener);
166+
assertThat(wrappedListener, instanceOf(SynchronizedRunListener.class));
167+
}
168+
169+
@Test
170+
public void dynamicallyLoadsThreadSafeAnnotatoin() {
171+
assertEquals(ThreadSafe.class, SynchronizedRunListener.getThreadSafeAnnotationClass());
172+
}
175173
}

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,8 @@
173173
StopwatchTest.class,
174174
RunNotifierTest.class,
175175
ConcurrentRunNotifierTest.class,
176-
SynchronizedRunListenerTest.class,
177-
AddRemoveListenerTest.class
176+
AddRemoveListenerTest.class,
177+
SynchronizedRunListenerTest.class
178178
})
179179
public class AllTests {
180180
public static Test suite() {

0 commit comments

Comments
 (0)