Skip to content

Commit 990a095

Browse files
Remove junit4 support (#383)
Co-authored-by: Valentin Böhm <valentin.boehm@tum.de>
1 parent e217e7a commit 990a095

17 files changed

Lines changed: 77 additions & 126 deletions

pom.xml

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,6 @@
8080
<artifactId>junit-jupiter-params</artifactId>
8181
<version>${junit-jupiter-version}</version>
8282
</dependency>
83-
<dependency>
84-
<groupId>org.junit.vintage</groupId>
85-
<artifactId>junit-vintage-engine</artifactId>
86-
<version>${junit-jupiter-version}</version>
87-
<scope>provided</scope>
88-
<optional>true</optional>
89-
</dependency>
9083
<dependency>
9184
<groupId>org.hamcrest</groupId>
9285
<artifactId>hamcrest</artifactId>

src/main/java/de/tum/in/test/api/internal/sanitization/MultipleFailuresErrorSanitizer.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package de.tum.in.test.api.internal.sanitization;
22

33
import java.util.*;
4-
import java.util.stream.Collectors;
54

65
import org.assertj.core.error.AssertJMultipleFailuresError;
76
import org.opentest4j.MultipleFailuresError;
@@ -22,8 +21,7 @@ public Throwable sanitize(Throwable t, MessageTransformer messageTransformer) {
2221
MultipleFailuresError mfe = (MultipleFailuresError) t;
2322
ThrowableInfo info = ThrowableInfo.getEssentialInfosSafeFrom(mfe).sanitize();
2423
// list is safe here because of defensive copying in MultipleFailuresError
25-
List<Throwable> failures = mfe.getFailures().stream().map(ThrowableSanitizer::sanitize)
26-
.collect(Collectors.toUnmodifiableList());
24+
List<Throwable> failures = mfe.getFailures().stream().map(ThrowableSanitizer::sanitize).toList();
2725
/*
2826
* Message already contains the failures and separating both is more difficult.
2927
* So we just pass the message constructed be the old object, as the new object

src/main/java/de/tum/in/test/api/internal/sanitization/SafeTypeThrowableSanitizer.java

Lines changed: 1 addition & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,8 @@
77
import java.util.*;
88
import java.util.function.Supplier;
99

10-
import org.junit.experimental.theories.internal.ParameterizedAssertionError;
1110
import org.slf4j.*;
1211

13-
import junit.framework.*;
14-
1512
import de.tum.in.test.api.internal.sanitization.ThrowableInfo.PropertyKey;
1613
import de.tum.in.test.api.util.LruCache;
1714

@@ -38,11 +35,7 @@ enum SafeTypeThrowableSanitizer implements SpecificThrowableSanitizer {
3835
entry("java.net.HttpRetryException", new HttpRetryExceptionCreator()), //$NON-NLS-1$
3936
entry("java.time.format.DateTimeParseException", new DateTimeParseExceptionCreator()), //$NON-NLS-1$
4037
entry("java.util.IllformedLocaleException", new IllformedLocaleExceptionCreator()), //$NON-NLS-1$
41-
entry("java.util.MissingResourceException", new MissingResourceExceptionCreator()), //$NON-NLS-1$
42-
entry("junit.framework.ComparisonFailure", new ThrowableCreatorWrapper(ComparisonFailureCreator::new)), //$NON-NLS-1$
43-
entry("org.junit.ComparisonFailure", new ThrowableCreatorWrapper(ComparisonFailureCreator::new)), //$NON-NLS-1$
44-
entry("org.junit.experimental.theories.internal.ParameterizedAssertionError", //$NON-NLS-1$
45-
new ThrowableCreatorWrapper(ParameterizedAssertionErrorCreator::new)) //
38+
entry("java.util.MissingResourceException", new MissingResourceExceptionCreator()) //$NON-NLS-1$
4639
);
4740

4841
final Map<Class<? extends Throwable>, ThrowableCreator> cachedThrowableCreators = Collections
@@ -146,47 +139,4 @@ public Throwable create(ThrowableInfo info) {
146139
return new MissingResourceException(message, className, key);
147140
}
148141
}
149-
150-
private static class ComparisonFailureCreator implements ThrowableCreator {
151-
152-
private static final int MAX_CONTEXT_LENGTH = 20;
153-
154-
private static final PropertyKey<String> EXPECTED = new PropertyKey<>(String.class, "expected"); //$NON-NLS-1$
155-
private static final PropertyKey<String> ACTUAL = new PropertyKey<>(String.class, "actual"); //$NON-NLS-1$
156-
157-
@Override
158-
public Throwable create(ThrowableInfo info) {
159-
var message = info.getMessage();
160-
var expected = info.getProperty(EXPECTED);
161-
var actual = info.getProperty(ACTUAL);
162-
String withoutMessage = new ComparisonCompactor(MAX_CONTEXT_LENGTH, expected, actual).compact(""); //$NON-NLS-1$
163-
var start = SanitizationUtils.removeSuffixMatching(message, withoutMessage);
164-
if (start == null)
165-
message = ""; //$NON-NLS-1$
166-
else
167-
message = start.trim();
168-
if (ComparisonFailure.class.isAssignableFrom(info.getType()))
169-
return new ComparisonFailure(message, expected, actual);
170-
return new org.junit.ComparisonFailure(message, expected, actual);
171-
}
172-
}
173-
174-
private static class ParameterizedAssertionErrorCreator implements ThrowableCreator {
175-
176-
@Override
177-
public Throwable create(ThrowableInfo info) {
178-
var targetException = info.getCause();
179-
var message = info.getMessage();
180-
var methodName = message;
181-
var params = new Object[0];
182-
try {
183-
var parts = message.substring(0, message.length() - 1).split("\\(", 2); //$NON-NLS-1$
184-
methodName = parts[0];
185-
params = parts[1].split(","); //$NON-NLS-1$
186-
} catch (@SuppressWarnings("unused") RuntimeException e) {
187-
// ignore
188-
}
189-
return new ParameterizedAssertionError(targetException, methodName, params);
190-
}
191-
}
192142
}

src/main/java/de/tum/in/test/api/internal/sanitization/ThrowableInfo.java

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
import org.apiguardian.api.API;
1010
import org.apiguardian.api.API.Status;
11+
import org.assertj.core.error.AssertJMultipleFailuresError;
12+
import org.assertj.core.util.Throwables;
1113

1214
/**
1315
* Contains information about a Throwable without the Throwable instance itself.
@@ -172,13 +174,44 @@ public static ThrowableInfo of(Class<? extends Throwable> type, Map<String, Obje
172174
}
173175

174176
public static ThrowableInfo getEssentialInfosSafeFrom(Throwable source) {
175-
String message = invoke(source::getMessage);
177+
String message = (source instanceof AssertJMultipleFailuresError)
178+
? saveAssertJMultipleFailuresMessage((AssertJMultipleFailuresError) source)
179+
: invoke(source::getMessage);
176180
Throwable cause = invoke(source::getCause);
177181
StackTraceElement[] stackTrace = invoke(source::getStackTrace);
178182
Throwable[] suppressed = source.getSuppressed(); // OK: final method
179183
return ThrowableInfo.of(source.getClass(), message, cause, stackTrace, suppressed, Map.of());
180184
}
181185

186+
/**
187+
* Custom reconstruction of {@link AssertJMultipleFailuresError#getMessage()}.
188+
* <p>
189+
* AssertJ's own getMessage() implementation introspects nested failures and can
190+
* trigger reflection, which breaks when using
191+
* {@link de.tum.in.test.api.internal.BlacklistedInvoker}. To avoid that, we
192+
* extract the failures, their messages, and the first user-relevant stack frame
193+
* ourselves without reflections.
194+
*/
195+
private static String saveAssertJMultipleFailuresMessage(AssertJMultipleFailuresError e) {
196+
return invoke(() -> {
197+
List<Throwable> failures = e.getFailures();
198+
StringBuilder sb = new StringBuilder();
199+
sb.append("Multiple Failures (").append(failures.size()).append(" failures)");
200+
for (int i = 0; i < failures.size(); i++) {
201+
Throwable failure = failures.get(i);
202+
sb.append("\n-- failure ").append(i + 1).append(" --");
203+
sb.append(failure.getMessage());
204+
205+
StackTraceElement[] stackTrace = failure.getStackTrace();
206+
StackTraceElement firstUserFrame = Throwables.getFirstStackTraceElementFromTest(stackTrace);
207+
if (firstUserFrame != null) {
208+
sb.append("\n").append(formatStackTraceElement(firstUserFrame));
209+
}
210+
}
211+
return sb.toString();
212+
});
213+
}
214+
182215
public static class PropertyKey<T> {
183216

184217
private final Class<T> type;

src/main/java/de/tum/in/test/api/internal/sanitization/ThrowableSets.java

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ final class ThrowableSets {
2626

2727
private static final Logger LOG = LoggerFactory.getLogger(ThrowableSets.class);
2828

29-
private static final String JUNIT4_CHECK_CLASS = "junit.framework.AssertionFailedError"; //$NON-NLS-1$
3029
private static final String JUNIT5_CHECK_CLASS = "org.junit.platform.commons.JUnitException"; //$NON-NLS-1$
3130
private static final String JQWIK_CHECK_CLASS = "net.jqwik.api.JqwikException"; //$NON-NLS-1$
3231
private static final String ASSERTJ_CHECK_CLASS = "org.assertj.core.api.Assertions"; //$NON-NLS-1$
@@ -35,8 +34,6 @@ final class ThrowableSets {
3534
static {
3635
HashSet<Class<? extends Throwable>> safeTypesJoin = new HashSet<>(Java.SAFE_TYPES);
3736
safeTypesJoin.addAll(Own.SAFE_TYPES);
38-
if (classCanBeFound(JUNIT4_CHECK_CLASS))
39-
safeTypesJoin.addAll(JUnit4.SAFE_TYPES);
4037
if (classCanBeFound(JUNIT5_CHECK_CLASS))
4138
safeTypesJoin.addAll(JUnit5.SAFE_TYPES);
4239
if (classCanBeFound(JQWIK_CHECK_CLASS))
@@ -206,25 +203,6 @@ private Java() {
206203
java.util.zip.ZipException.class);
207204
}
208205

209-
static final class JUnit4 {
210-
211-
private JUnit4() {
212-
}
213-
214-
static final Set<Class<? extends Throwable>> SAFE_TYPES = Set.of(junit.framework.AssertionFailedError.class,
215-
junit.framework.ComparisonFailure.class, org.junit.ComparisonFailure.class, org.junit.Test.None.class,
216-
org.junit.TestCouldNotBeSkippedException.class,
217-
org.junit.experimental.max.CouldNotReadCoreException.class,
218-
org.junit.experimental.theories.PotentialAssignment.CouldNotGenerateValueException.class,
219-
org.junit.experimental.theories.internal.ParameterizedAssertionError.class,
220-
org.junit.internal.ArrayComparisonFailure.class,
221-
org.junit.runner.FilterFactory.FilterNotCreatedException.class,
222-
org.junit.runner.manipulation.InvalidOrderingException.class,
223-
org.junit.runner.manipulation.NoTestsRemainException.class,
224-
org.junit.runner.notification.StoppedByUserException.class,
225-
org.junit.runners.model.TestTimedOutException.class);
226-
}
227-
228206
static final class JUnit5 {
229207

230208
private JUnit5() {

src/main/java/de/tum/in/test/api/internal/sanitization/ThrowableUtils.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,4 +149,11 @@ static Object[] provideArguments(Constructor<?> constructor, Map<Class<?>, List<
149149
return null;
150150
}).toArray();
151151
}
152+
153+
static String formatStackTraceElement(StackTraceElement ste) {
154+
String className = ste.getClassName();
155+
String simpleName = className.substring(className.lastIndexOf('.') + 1);
156+
return "at " + simpleName + "." + ste.getMethodName() + "(" + ste.getFileName() + ":" + ste.getLineNumber()
157+
+ ")";
158+
}
152159
}

src/test/java/de/tum/in/test/api/util/ClassMemberAccessorTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package de.tum.in.test.api.util;
22

33
import static org.assertj.core.api.Assertions.assertThat;
4-
import static org.junit.Assert.assertThrows;
4+
import static org.junit.jupiter.api.Assertions.assertThrows;
55

66
import java.lang.reflect.*;
77

src/test/java/de/tum/in/test/integration/ExceptionFailureTest.java

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,19 @@ class ExceptionFailureTest {
1818
@UserTestResults
1919
private static Events tests;
2020

21-
private final String assertJMultipleFailures = "assertJMultipleFailures";
22-
private final String assertionFailOnly = "assertionFailOnly";
23-
private final String assertionFailed = "assertionFailed";
24-
private final String customException = "customException";
25-
private final String exceptionInInitializer = "exceptionInInitializer";
26-
private final String faultyGetCauseException = "faultyGetCauseException";
27-
private final String faultyToStringException = "faultyToStringException";
28-
private final String multipleAssertions = "multipleAssertions";
29-
private final String multipleFailures = "multipleFailures";
30-
private final String nullPointer = "nullPointer";
31-
private final String softAssertion = "softAssertion";
32-
private final String throwExceptionInInitializerError = "throwExceptionInInitializerError";
33-
private final String throwNullPointerException = "throwNullPointerException";
21+
private static final String assertJMultipleFailures = "assertJMultipleFailures";
22+
private static final String assertionFailOnly = "assertionFailOnly";
23+
private static final String assertionFailed = "assertionFailed";
24+
private static final String customException = "customException";
25+
private static final String exceptionInInitializer = "exceptionInInitializer";
26+
private static final String faultyGetCauseException = "faultyGetCauseException";
27+
private static final String faultyToStringException = "faultyToStringException";
28+
private static final String multipleAssertions = "multipleAssertions";
29+
private static final String multipleFailures = "multipleFailures";
30+
private static final String nullPointer = "nullPointer";
31+
private static final String softAssertion = "softAssertion";
32+
private static final String throwExceptionInInitializerError = "throwExceptionInInitializerError";
33+
private static final String throwNullPointerException = "throwNullPointerException";
3434

3535
@TestTest
3636
void test_assertJMultipleFailures() {
@@ -120,8 +120,8 @@ void test_multipleAssertions() {
120120
void test_multipleFailures() {
121121
tests.assertThatEvents().haveExactly(1, testFailedWith(multipleFailures, MultipleFailuresError.class, //
122122
"Multiple Failures (2 failures)\n" + //
123-
"\tjava.lang.AssertionError: A\n" + //
124-
"\tjava.lang.AssertionError: B", //
123+
"\torg.opentest4j.AssertionFailedError: A\n" + //
124+
"\torg.opentest4j.AssertionFailedError: B", //
125125
new Condition<>(t -> t.getSuppressed().length == 2, "two suppressed exceptions"),
126126
Option.MESSAGE_NORMALIZE_NEWLINE));
127127
}

src/test/java/de/tum/in/test/integration/InputOutputTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44

55
import java.lang.annotation.AnnotationFormatError;
66

7-
import org.junit.ComparisonFailure;
87
import org.junit.jupiter.api.extension.ParameterResolutionException;
98
import org.junit.platform.testkit.engine.Events;
9+
import org.opentest4j.AssertionFailedError;
1010

1111
import de.tum.in.test.integration.testuser.InputOutputUser;
1212
import de.tum.in.test.testutilities.*;
@@ -58,7 +58,7 @@ void test_testPenguin1() {
5858

5959
@TestTest
6060
void test_testPenguin2() {
61-
tests.assertThatEvents().haveExactly(1, testFailedWith(testPenguin2, ComparisonFailure.class));
61+
tests.assertThatEvents().haveExactly(1, testFailedWith(testPenguin2, AssertionFailedError.class));
6262
}
6363

6464
@TestTest

src/test/java/de/tum/in/test/integration/SecurityTest.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
import java.nio.file.Path;
77

8-
import org.junit.ComparisonFailure;
98
import org.junit.platform.testkit.engine.Events;
109
import org.opentest4j.AssertionFailedError;
1110

@@ -53,7 +52,7 @@ void test_doSystemExit() {
5352

5453
@TestTest
5554
void test_longOutputJUnit4() {
56-
tests.assertThatEvents().haveExactly(1, testFailedWith(longOutputJUnit4, ComparisonFailure.class));
55+
tests.assertThatEvents().haveExactly(1, testFailedWith(longOutputJUnit4, AssertionFailedError.class));
5756
}
5857

5958
@TestTest

0 commit comments

Comments
 (0)