Skip to content

Commit 36dfa17

Browse files
committed
Verify JUnit no tests shadowing
1 parent 88b48f0 commit 36dfa17

File tree

2 files changed

+72
-0
lines changed

2 files changed

+72
-0
lines changed
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License.
4+
* You may obtain a copy of the License at
5+
*
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
package io.trino.testing.services.junit;
15+
16+
import org.junit.platform.engine.support.descriptor.MethodSource;
17+
import org.junit.platform.launcher.TestExecutionListener;
18+
import org.junit.platform.launcher.TestIdentifier;
19+
import org.junit.platform.launcher.TestPlan;
20+
21+
import java.lang.reflect.Modifier;
22+
import java.util.Arrays;
23+
import java.util.List;
24+
import java.util.stream.Stream;
25+
26+
import static com.google.common.base.Throwables.getStackTraceAsString;
27+
import static io.trino.testing.services.junit.Listeners.reportListenerFailure;
28+
import static java.lang.String.format;
29+
30+
public class ReportOverriddenMethods
31+
implements TestExecutionListener
32+
{
33+
@Override
34+
public void testPlanExecutionStarted(TestPlan testPlan)
35+
{
36+
try {
37+
testPlan.accept(new TestPlan.Visitor()
38+
{
39+
@Override
40+
public void visit(TestIdentifier testIdentifier)
41+
{
42+
testIdentifier.getSource().ifPresent(source -> {
43+
if (source instanceof MethodSource methodSource) {
44+
if (!Modifier.isPublic(methodSource.getJavaMethod().getModifiers()) &&
45+
!Modifier.isProtected(methodSource.getJavaMethod().getModifiers())) {
46+
List<Class<?>> declaringClasses = Stream.<Class<?>>iterate(methodSource.getJavaClass(), clazz -> clazz.getSuperclass() != null, Class::getSuperclass)
47+
.filter(clazz ->
48+
Arrays.stream(clazz.getDeclaredMethods())
49+
.anyMatch(method -> method.getName().equals(methodSource.getJavaMethod().getName())))
50+
.toList();
51+
if (declaringClasses.size() > 1) {
52+
throw new IllegalStateException(format(
53+
"""
54+
Method %s is not public. Similar methods are defined by %s. \
55+
When tests are non-public, they do not @Override in Java sense, but they still interact with each other in JUnit, \
56+
and only one of declared tests gets executed. \
57+
This leads to tests being silently skipped without any source-level indication.""",
58+
methodSource.getJavaMethod(),
59+
declaringClasses));
60+
}
61+
}
62+
}
63+
});
64+
}
65+
});
66+
}
67+
catch (RuntimeException | Error e) {
68+
reportListenerFailure(getClass(), "%s", getStackTraceAsString(e));
69+
}
70+
}
71+
}
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
io.trino.testing.services.junit.LogTestDurationListener
2+
io.trino.testing.services.junit.ReportOverriddenMethods

0 commit comments

Comments
 (0)