Skip to content

Commit 2bc4a71

Browse files
authored
Add TemporaryClasspathExecutor test utility (#4544)
This commit extracts the logic previously in `LauncherFactoryTests` to execute code with an extra classpath root, which is required for SPI-based tests.
1 parent 4a55860 commit 2bc4a71

File tree

2 files changed

+56
-16
lines changed

2 files changed

+56
-16
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright 2015-2025 the original author or authors.
3+
*
4+
* All rights reserved. This program and the accompanying materials are
5+
* made available under the terms of the Eclipse Public License v2.0 which
6+
* accompanies this distribution and is available at
7+
*
8+
* https://www.eclipse.org/legal/epl-v20.html
9+
*/
10+
11+
package org.junit.jupiter.api;
12+
13+
import java.io.IOException;
14+
import java.io.UncheckedIOException;
15+
import java.net.URL;
16+
import java.net.URLClassLoader;
17+
18+
/**
19+
* Utility class for executing code with a temporary classpath.
20+
*
21+
* @since 5.13
22+
*/
23+
public class TemporaryClasspathExecutor {
24+
25+
private TemporaryClasspathExecutor() {
26+
}
27+
28+
/**
29+
* Execute the {@link Runnable} within a custom classpath, temporarily modifying the
30+
* thread's {@link Thread#getContextClassLoader() context class loader} to include
31+
* the provided {@code classpathRoot}.
32+
*
33+
* <p>After the given {@code Runnable} completes, the original context class loader is
34+
* restored.
35+
*
36+
* @param classpathRoot the root path to be added to the classpath, resolved relative
37+
* to the current thread's context class loader.
38+
* @param runnable the {@code Runnable} to execute with the temporary classpath.
39+
*/
40+
public static void withAdditionalClasspathRoot(String classpathRoot, Runnable runnable) {
41+
var current = Thread.currentThread().getContextClassLoader();
42+
try (var classLoader = new URLClassLoader(new URL[] { current.getResource(classpathRoot) }, current)) {
43+
Thread.currentThread().setContextClassLoader(classLoader);
44+
runnable.run();
45+
}
46+
catch (IOException e) {
47+
throw new UncheckedIOException(e);
48+
}
49+
finally {
50+
Thread.currentThread().setContextClassLoader(current);
51+
}
52+
}
53+
54+
}

platform-tests/src/test/java/org/junit/platform/launcher/core/LauncherFactoryTests.java

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,12 @@
1414
import static org.junit.jupiter.api.Assertions.assertFalse;
1515
import static org.junit.jupiter.api.Assertions.assertThrows;
1616
import static org.junit.jupiter.api.Assertions.assertTrue;
17+
import static org.junit.jupiter.api.TemporaryClasspathExecutor.withAdditionalClasspathRoot;
1718
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
1819
import static org.junit.platform.launcher.LauncherConstants.DEACTIVATE_LISTENERS_PATTERN_PROPERTY_NAME;
1920
import static org.junit.platform.launcher.LauncherConstants.ENABLE_LAUNCHER_INTERCEPTORS;
2021
import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request;
2122

22-
import java.io.IOException;
23-
import java.io.UncheckedIOException;
24-
import java.net.URL;
25-
import java.net.URLClassLoader;
2623
import java.util.concurrent.atomic.AtomicReference;
2724
import java.util.logging.LogRecord;
2825

@@ -434,18 +431,7 @@ private static void withSystemProperty(String key, String value, Runnable runnab
434431
}
435432

436433
private static void withTestServices(Runnable runnable) {
437-
var current = Thread.currentThread().getContextClassLoader();
438-
var url = LauncherFactoryTests.class.getClassLoader().getResource("testservices/");
439-
try (var classLoader = new URLClassLoader(new URL[] { url }, current)) {
440-
Thread.currentThread().setContextClassLoader(classLoader);
441-
runnable.run();
442-
}
443-
catch (IOException e) {
444-
throw new UncheckedIOException(e);
445-
}
446-
finally {
447-
Thread.currentThread().setContextClassLoader(current);
448-
}
434+
withAdditionalClasspathRoot("testservices/", runnable);
449435
}
450436

451437
private LauncherDiscoveryRequest createLauncherDiscoveryRequestForBothStandardEngineExampleClasses() {

0 commit comments

Comments
 (0)