From 02ef1082ea6c381ba15daee6d43a4a2bf837798a Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Tue, 9 Jan 2024 19:28:49 +0100 Subject: [PATCH 01/78] Support scanning for class path resources Fixes: #3630 --- .../commons/support/ReflectionSupport.java | 151 +++++++++++++++++- .../platform/commons/support/Resource.java | 61 +++++++ .../commons/util/ClasspathResource.java | 51 ++++++ .../commons/util/ClasspathScanner.java | 107 ++++++++++++- .../platform/commons/util/ModuleUtils.java | 17 ++ .../commons/util/ReflectionUtils.java | 101 ++++++++++++ .../commons/util/ResourceFileVisitor.java | 66 ++++++++ .../platform/commons/util/ResourceFilter.java | 73 +++++++++ .../platform/commons/util/ModuleUtils.java | 95 ++++++++++- .../support/ReflectionSupportTests.java | 66 ++++++++ .../commons/util/ClasspathScannerTests.java | 109 +++++++++++++ .../test/resources/default-package.resource | 1 + platform-tests/src/test/resources/jartest.jar | Bin 2550 -> 3368 bytes .../junit/platform/commons/example.resource | 1 + .../platform/commons/other-example.resource | 1 + 15 files changed, 892 insertions(+), 8 deletions(-) create mode 100644 junit-platform-commons/src/main/java/org/junit/platform/commons/support/Resource.java create mode 100644 junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathResource.java create mode 100644 junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFileVisitor.java create mode 100644 junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java create mode 100644 platform-tests/src/test/resources/default-package.resource create mode 100644 platform-tests/src/test/resources/org/junit/platform/commons/example.resource create mode 100644 platform-tests/src/test/resources/org/junit/platform/commons/other-example.resource diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java index 99e6ec7601ec..dcc8dcdb1fb5 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java @@ -67,7 +67,6 @@ private ReflectionSupport() { */ @API(status = DEPRECATED, since = "1.4") @Deprecated - @SuppressWarnings("deprecation") public static Optional> loadClass(String name) { return ReflectionUtils.loadClass(name); } @@ -137,6 +136,30 @@ public static List> findAllClassesInClasspathRoot(URI root, PredicateThe classpath scanning algorithm searches recursively in subpackages + * beginning with the root of the classpath. + * + * @param root the URI for the classpath root in which to scan; never + * {@code null} + * @param resourceFilter the resource type filter; never {@code null} + * @param resourceNameFilter the resource name filter; never {@code null} + * @return an immutable list of all such resources found; never {@code null} + * but potentially empty + * @see #findAllResourcesInPackage(String, Predicate, Predicate) + * @see #findAllResourcesInModule(String, Predicate, Predicate) + */ + @API(status = EXPERIMENTAL, since = "1.11") + public static List findAllResourcesInClasspathRoot(URI root, Predicate resourceFilter, + Predicate resourceNameFilter) { + + return ReflectionUtils.findAllResourcesInClasspathRoot(root, resourceFilter, resourceNameFilter); + } + /** * Find all {@linkplain Class classes} in the supplied classpath {@code root} * that match the specified {@code classFilter} and {@code classNameFilter} @@ -162,6 +185,31 @@ public static Stream> streamAllClassesInClasspathRoot(URI root, Predica return ReflectionUtils.streamAllClassesInClasspathRoot(root, classFilter, classNameFilter); } + /** + * Find all {@linkplain Resource resources} in the supplied classpath {@code root} + * that match the specified {@code resourceFilter} and {@code resourceNameFilter} + * predicates. + * + *

The classpath scanning algorithm searches recursively in subpackages + * beginning with the root of the classpath. + * + * @param root the URI for the classpath root in which to scan; never + * {@code null} + * @param resourceFilter the resource type filter; never {@code null} + * @param resourceNameFilter the resources name filter; never {@code null} + * @return a stream of all such classes found; never {@code null} + * but potentially empty + * @since 1.10 + * @see #streamAllResourcesInPackage(String, Predicate, Predicate) + * @see #streamAllResourcesInModule(String, Predicate, Predicate) + */ + @API(status = EXPERIMENTAL, since = "1.11") + public static Stream streamAllResourcesInClasspathRoot(URI root, Predicate resourceFilter, + Predicate resourceNameFilter) { + + return ReflectionUtils.streamAllResourcesInClasspathRoot(root, resourceFilter, resourceNameFilter); + } + /** * Find all {@linkplain Class classes} in the supplied {@code basePackageName} * that match the specified {@code classFilter} and {@code classNameFilter} @@ -186,6 +234,31 @@ public static List> findAllClassesInPackage(String basePackageName, Pre return ReflectionUtils.findAllClassesInPackage(basePackageName, classFilter, classNameFilter); } + /** + * Find all {@linkplain Resource resources} in the supplied {@code basePackageName} + * that match the specified {@code resourceFilter} and {@code resourceNameFilter} + * predicates. + * + *

The classpath scanning algorithm searches recursively in subpackages + * beginning within the supplied base package. + * + * @param basePackageName the name of the base package in which to start + * scanning; must not be {@code null} and must be valid in terms of Java + * syntax + * @param resourceFilter the resource type filter; never {@code null} + * @param resourceNameFilter the resource name filter; never {@code null} + * @return an immutable list of all such classes found; never {@code null} + * but potentially empty + * @see #findAllResourcesInClasspathRoot(URI, Predicate, Predicate) + * @see #findAllResourcesInModule(String, Predicate, Predicate) + */ + @API(status = EXPERIMENTAL, since = "1.11") + public static List findAllResourcesInPackage(String basePackageName, Predicate resourceFilter, + Predicate resourceNameFilter) { + + return ReflectionUtils.findAllResourcesInPackage(basePackageName, resourceFilter, resourceNameFilter); + } + /** * Find all {@linkplain Class classes} in the supplied {@code basePackageName} * that match the specified {@code classFilter} and {@code classNameFilter} @@ -212,6 +285,32 @@ public static Stream> streamAllClassesInPackage(String basePackageName, return ReflectionUtils.streamAllClassesInPackage(basePackageName, classFilter, classNameFilter); } + /** + * Find all {@linkplain Resource resources} in the supplied {@code basePackageName} + * that match the specified {@code resourceFilter} and {@code resourceNameFilter} + * predicates. + * + *

The classpath scanning algorithm searches recursively in subpackages + * beginning within the supplied base package. + * + * @param basePackageName the name of the base package in which to start + * scanning; must not be {@code null} and must be valid in terms of Java + * syntax + * @param resourceFilter the resource type filter; never {@code null} + * @param resourceNameFilter the resource name filter; never {@code null} + * @return a stream of all such resources found; never {@code null} + * but potentially empty + * @since 1.10 + * @see #streamAllResourcesInClasspathRoot(URI, Predicate, Predicate) + * @see #streamAllResourcesInModule(String, Predicate, Predicate) + */ + @API(status = EXPERIMENTAL, since = "1.11") + public static Stream streamAllResourcesInPackage(String basePackageName, + Predicate resourceFilter, Predicate resourceNameFilter) { + + return ReflectionUtils.streamAllResourcesInPackage(basePackageName, resourceFilter, resourceNameFilter); + } + /** * Find all {@linkplain Class classes} in the supplied {@code moduleName} * that match the specified {@code classFilter} and {@code classNameFilter} @@ -236,6 +335,31 @@ public static List> findAllClassesInModule(String moduleName, Predicate return ReflectionUtils.findAllClassesInModule(moduleName, classFilter, classNameFilter); } + /** + * Find all {@linkplain Resource resources} in the supplied {@code moduleName} + * that match the specified {@code resourceFilter} and {@code resourceNameFilter} + * predicates. + * + *

The module-path scanning algorithm searches recursively in all + * packages contained in the module. + * + * @param moduleName the name of the module to scan; never {@code null} or + * empty + * @param resourceFilter the resource type filter; never {@code null} + * @param resourceNameFilter the resource name filter; never {@code null} + * @return an immutable list of all such resources found; never {@code null} + * but potentially empty + * @since 1.1.1 + * @see #findAllResourcesInClasspathRoot(URI, Predicate, Predicate) + * @see #findAllResourcesInPackage(String, Predicate, Predicate) + */ + @API(status = EXPERIMENTAL, since = "1.11") + public static List findAllResourcesInModule(String moduleName, Predicate resourceFilter, + Predicate resourceNameFilter) { + + return ReflectionUtils.findAllResourcesInModule(moduleName, resourceFilter, resourceNameFilter); + } + /** * Find all {@linkplain Class classes} in the supplied {@code moduleName} * that match the specified {@code classFilter} and {@code classNameFilter} @@ -261,6 +385,31 @@ public static Stream> streamAllClassesInModule(String moduleName, Predi return ReflectionUtils.streamAllClassesInModule(moduleName, classFilter, classNameFilter); } + /** + * Find all {@linkplain Resource resources} in the supplied {@code moduleName} + * that match the specified {@code resourceFilter} and {@code resourceNameFilter} + * predicates. + * + *

The module-path scanning algorithm searches recursively in all + * packages contained in the module. + * + * @param moduleName the name of the module to scan; never {@code null} or + * empty + * @param resourceFilter the resource type filter; never {@code null} + * @param resourceNameFilter the resource name filter; never {@code null} + * @return a stream of all such resources found; never {@code null} + * but potentially empty + * @since 1.10 + * @see #streamAllResourcesInClasspathRoot(URI, Predicate, Predicate) + * @see #streamAllResourcesInPackage(String, Predicate, Predicate) + */ + @API(status = EXPERIMENTAL, since = "1.11") + public static Stream streamAllResourcesInModule(String moduleName, Predicate resourceFilter, + Predicate resourceNameFilter) { + + return ReflectionUtils.streamAllResourcesInModule(moduleName, resourceFilter, resourceNameFilter); + } + /** * Create a new instance of the specified {@link Class} by invoking * the constructor whose argument list matches the types of the supplied diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/Resource.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/Resource.java new file mode 100644 index 000000000000..fc90e7427d6c --- /dev/null +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/Resource.java @@ -0,0 +1,61 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.support; + +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.util.function.Predicate; + +import org.apiguardian.api.API; + +/** + * Represents a resource on the classpath. + * + * @see ReflectionSupport#findAllResourcesInClasspathRoot(URI, Predicate, Predicate) + * @see ReflectionSupport#findAllResourcesInPackage(String, Predicate, Predicate) + * @see ReflectionSupport#findAllResourcesInModule(String, Predicate, Predicate) + * @see ReflectionSupport#streamAllResourcesInClasspathRoot(URI, Predicate, Predicate) + * @see ReflectionSupport#streamAllResourcesInPackage(String, Predicate, Predicate) + * @see ReflectionSupport#streamAllResourcesInModule(String, Predicate, Predicate) + */ +@API(status = EXPERIMENTAL, since = "1.11") +public interface Resource { + + /** + * Get the resource name. + *

+ * The resource name is a {@code /}-separated path. The path is relative to + * the classpath root in which the resource is located. + * + * @return the resource name; never {@code null} + */ + String getName(); + + /** + * Get URI to a resource. + * + * @return the uri of the resource; never {@code null} + */ + URI getUri(); + + /** + * Returns an input stream for reading this resource. + * + * @return an input stream for this resource; never {@code null} + * @throws IOException if an I/O exception occurs + */ + default InputStream getInputStream() throws IOException { + return getUri().toURL().openStream(); + } +} diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathResource.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathResource.java new file mode 100644 index 000000000000..17a9b54f3d79 --- /dev/null +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathResource.java @@ -0,0 +1,51 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.util; + +import java.net.URI; +import java.util.Objects; + +import org.junit.platform.commons.support.Resource; + +class ClasspathResource implements Resource { + private final String name; + private final URI uri; + + ClasspathResource(String name, URI uri) { + this.name = Preconditions.notNull(name, "name must not be null"); + this.uri = Preconditions.notNull(uri, "uri must not be null"); + } + + @Override + public String getName() { + return name; + } + + @Override + public URI getUri() { + return uri; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + ClasspathResource that = (ClasspathResource) o; + return name.equals(that.name) && uri.equals(that.uri); + } + + @Override + public int hashCode() { + return Objects.hash(name, uri); + } +} diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java index 3a040c577405..a8f47fa921a6 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java @@ -37,6 +37,7 @@ import org.junit.platform.commons.function.Try; import org.junit.platform.commons.logging.Logger; import org.junit.platform.commons.logging.LoggerFactory; +import org.junit.platform.commons.support.Resource; /** *

DISCLAIMER

@@ -80,8 +81,8 @@ List> scanForClassesInPackage(String basePackageName, ClassFilter class Preconditions.notNull(classFilter, "classFilter must not be null"); basePackageName = basePackageName.trim(); - return findClassesForUris(getRootUrisForPackageNameOnClassPathAndModulePath(basePackageName), basePackageName, - classFilter); + List roots = getRootUrisForPackageNameOnClassPathAndModulePath(basePackageName); + return findClassesForUris(roots, basePackageName, classFilter); } List> scanForClassesInClasspathRoot(URI root, ClassFilter classFilter) { @@ -91,8 +92,26 @@ List> scanForClassesInClasspathRoot(URI root, ClassFilter classFilter) return findClassesForUri(root, PackageUtils.DEFAULT_PACKAGE_NAME, classFilter); } + List scanForResourcesInPackage(String basePackageName, ResourceFilter resourceFilter) { + Preconditions.condition( + PackageUtils.DEFAULT_PACKAGE_NAME.equals(basePackageName) || isNotBlank(basePackageName), + "basePackageName must not be null or blank"); + Preconditions.notNull(resourceFilter, "resourceFilter must not be null"); + basePackageName = basePackageName.trim(); + + List roots = getRootUrisForPackageNameOnClassPathAndModulePath(basePackageName); + return findResourcesForUris(roots, basePackageName, resourceFilter); + } + + List scanForResourcesInClasspathRoot(URI root, ResourceFilter resourceFilter) { + Preconditions.notNull(root, "root must not be null"); + Preconditions.notNull(resourceFilter, "resourceFilter must not be null"); + + return findResourcesForUri(root, PackageUtils.DEFAULT_PACKAGE_NAME, resourceFilter); + } + /** - * Recursively scan for classes in all of the supplied source directories. + * Recursively scan for classes in all the supplied source directories. */ private List> findClassesForUris(List baseUris, String basePackageName, ClassFilter classFilter) { // @formatter:off @@ -118,6 +137,34 @@ private List> findClassesForUri(URI baseUri, String basePackageName, Cl } } + /** + * Recursively scan for resources in all the supplied source directories. + */ + private List findResourcesForUris(List baseUris, String basePackageName, + ResourceFilter resourceFilter) { + // @formatter:off + return baseUris.stream() + .map(baseUri -> findResourcesForUri(baseUri, basePackageName, resourceFilter)) + .flatMap(Collection::stream) + .distinct() + .collect(toList()); + // @formatter:on + } + + private List findResourcesForUri(URI baseUri, String basePackageName, ResourceFilter resourceFilter) { + try (CloseablePath closeablePath = CloseablePath.create(baseUri)) { + Path baseDir = closeablePath.getPath(); + return findResourcesForPath(baseDir, basePackageName, resourceFilter); + } + catch (PreconditionViolationException ex) { + throw ex; + } + catch (Exception ex) { + logger.warn(ex, () -> "Error scanning files for URI " + baseUri); + return emptyList(); + } + } + private List> findClassesForPath(Path baseDir, String basePackageName, ClassFilter classFilter) { Preconditions.condition(Files.exists(baseDir), () -> "baseDir must exist: " + baseDir); List> classes = new ArrayList<>(); @@ -131,6 +178,19 @@ private List> findClassesForPath(Path baseDir, String basePackageName, return classes; } + private List findResourcesForPath(Path baseDir, String basePackageName, ResourceFilter resourceFilter) { + Preconditions.condition(Files.exists(baseDir), () -> "baseDir must exist: " + baseDir); + List resources = new ArrayList<>(); + try { + Files.walkFileTree(baseDir, new ResourceFileVisitor(resourceFile -> processResourceFileSafely(baseDir, + basePackageName, resourceFilter, resourceFile, resources::add))); + } + catch (IOException ex) { + logger.warn(ex, () -> "I/O error scanning files in " + baseDir); + } + return resources; + } + private void processClassFileSafely(Path baseDir, String basePackageName, ClassFilter classFilter, Path classFile, Consumer> classConsumer) { try { @@ -154,6 +214,23 @@ private void processClassFileSafely(Path baseDir, String basePackageName, ClassF } } + private void processResourceFileSafely(Path baseDir, String basePackageName, ResourceFilter resourceFilter, + Path resourceFile, Consumer resourceConsumer) { + try { + String fullyQualifiedResourceName = determineFullyQualifiedResourceName(baseDir, basePackageName, + resourceFile); + if (resourceFilter.match(fullyQualifiedResourceName)) { + Resource resource = new ClasspathResource(fullyQualifiedResourceName, resourceFile.toUri()); + if (resourceFilter.test(resource)) { // Always use ".test(classFilter)" to include future predicates. + resourceConsumer.accept(resource); + } + } + } + catch (Throwable throwable) { + handleThrowable(resourceFile, throwable); + } + } + private String determineFullyQualifiedClassName(Path baseDir, String basePackageName, Path classFile) { // @formatter:off return Stream.of( @@ -166,11 +243,34 @@ private String determineFullyQualifiedClassName(Path baseDir, String basePackage // @formatter:on } + /** + * The fully qualified resource name is a {@code /}-separated path. + *

+ * The path is relative to the classpath root in which the resource is located. + + * @return the resource name; never {@code null} + */ + private String determineFullyQualifiedResourceName(Path baseDir, String basePackageName, Path resourceFile) { + // @formatter:off + return Stream.of( + packagePath(basePackageName), + packagePath(determineSubpackageName(baseDir, resourceFile)), + determineSimpleResourceName(resourceFile) + ) + .filter(value -> !value.isEmpty()) // Handle default package appropriately. + .collect(joining(CLASSPATH_RESOURCE_PATH_SEPARATOR_STRING)); + // @formatter:on + } + private String determineSimpleClassName(Path classFile) { String fileName = classFile.getFileName().toString(); return fileName.substring(0, fileName.length() - CLASS_FILE_SUFFIX.length()); } + private String determineSimpleResourceName(Path resourceFile) { + return resourceFile.getFileName().toString(); + } + private String determineSubpackageName(Path baseDir, Path classFile) { Path relativePath = baseDir.relativize(classFile.getParent()); String pathSeparator = baseDir.getFileSystem().getSeparator(); @@ -209,6 +309,7 @@ private void logMalformedClassName(Path classFile, String fullyQualifiedClassNam } private void logGenericFileProcessingException(Path classFile, Throwable throwable) { + // TODO: Can't mention java.lang.Class here, could be a resource logger.debug(throwable, () -> format("Failed to load java.lang.Class for path [%s] during classpath scanning.", classFile.toAbsolutePath())); } diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ModuleUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ModuleUtils.java index 8f6b45ce6f56..949824501556 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ModuleUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ModuleUtils.java @@ -21,6 +21,7 @@ import org.apiguardian.api.API; import org.junit.platform.commons.logging.Logger; import org.junit.platform.commons.logging.LoggerFactory; +import org.junit.platform.commons.support.Resource; /** * Collection of utilities for working with {@code java.lang.Module} @@ -97,4 +98,20 @@ public static List> findAllClassesInModule(String moduleName, ClassFilt return emptyList(); } + /** + * TODO: DOC + * + * @param moduleName + * @param filter + * @return + */ + @API(status = INTERNAL, since = "1.11") + public static List findAllResourcesInModule(String moduleName, ResourceFilter filter) { + Preconditions.notBlank(moduleName, "Module name must not be null or empty"); + Preconditions.notNull(filter, "Resource filter must not be null"); + + logger.config(() -> "Basic version of findAllResourcesInModule() always returns an empty list!"); + return emptyList(); + } + } diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java index 5e693f6be77e..7832890004f0 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java @@ -59,6 +59,7 @@ import org.junit.platform.commons.function.Try; import org.junit.platform.commons.logging.Logger; import org.junit.platform.commons.logging.LoggerFactory; +import org.junit.platform.commons.support.Resource; /** * Collection of utilities for working with the Java reflection APIs. @@ -961,6 +962,16 @@ public static List> findAllClassesInClasspathRoot(URI root, Predicate findAllResourcesInClasspathRoot(URI root, Predicate resourceFilter, + Predicate resourceNameFilter) { + // unmodifiable since returned by public, non-internal method(s) + return findAllResourcesInClasspathRoot(root, ResourceFilter.of(resourceNameFilter, resourceFilter)); + } + /** * @since 1.10 * @see org.junit.platform.commons.support.ReflectionSupport#streamAllClassesInClasspathRoot(URI, Predicate, Predicate) @@ -970,6 +981,15 @@ public static Stream> streamAllClassesInClasspathRoot(URI root, Predica return streamAllClassesInClasspathRoot(root, ClassFilter.of(classNameFilter, classFilter)); } + /** + * @since 1.11 + * @see org.junit.platform.commons.support.ReflectionSupport#streamAllResourcesInClasspathRoot(URI, Predicate, Predicate) + */ + public static Stream streamAllResourcesInClasspathRoot(URI root, Predicate resourceFilter, + Predicate resourceNameFilter) { + return streamAllResourcesInClasspathRoot(root, ResourceFilter.of(resourceNameFilter, resourceFilter)); + } + /** * @since 1.1 */ @@ -977,6 +997,13 @@ public static List> findAllClassesInClasspathRoot(URI root, ClassFilter return Collections.unmodifiableList(classpathScanner.scanForClassesInClasspathRoot(root, classFilter)); } + /** + * @since 1.11 + */ + public static List findAllResourcesInClasspathRoot(URI root, ResourceFilter classFilter) { + return Collections.unmodifiableList(classpathScanner.scanForResourcesInClasspathRoot(root, classFilter)); + } + /** * @since 1.10 */ @@ -984,6 +1011,13 @@ public static Stream> streamAllClassesInClasspathRoot(URI root, ClassFi return findAllClassesInClasspathRoot(root, classFilter).stream(); } + /** + * @since 1.11 + */ + public static Stream streamAllResourcesInClasspathRoot(URI root, ResourceFilter resourceFilter) { + return findAllResourcesInClasspathRoot(root, resourceFilter).stream(); + } + /** * @see org.junit.platform.commons.support.ReflectionSupport#findAllClassesInPackage(String, Predicate, Predicate) */ @@ -993,6 +1027,16 @@ public static List> findAllClassesInPackage(String basePackageName, Pre return findAllClassesInPackage(basePackageName, ClassFilter.of(classNameFilter, classFilter)); } + /** + * @since 1.11 + * @see org.junit.platform.commons.support.ReflectionSupport#findAllClassesInPackage(String, Predicate, Predicate) + */ + public static List findAllResourcesInPackage(String basePackageName, Predicate resourceFilter, + Predicate resourceNameFilter) { + // unmodifiable since returned by public, non-internal method(s) + return findAllResourcesInPackage(basePackageName, ResourceFilter.of(resourceNameFilter, resourceFilter)); + } + /** * since 1.10 * @see org.junit.platform.commons.support.ReflectionSupport#streamAllClassesInPackage(String, Predicate, Predicate) @@ -1002,6 +1046,15 @@ public static Stream> streamAllClassesInPackage(String basePackageName, return streamAllClassesInPackage(basePackageName, ClassFilter.of(classNameFilter, classFilter)); } + /** + * since 1.11 + * @see org.junit.platform.commons.support.ReflectionSupport#streamAllResourcesInPackage(String, Predicate, Predicate) + */ + public static Stream streamAllResourcesInPackage(String basePackageName, + Predicate resourceFilter, Predicate resourceNameFilter) { + return streamAllResourcesInPackage(basePackageName, ResourceFilter.of(resourceNameFilter, resourceFilter)); + } + /** * @since 1.1 */ @@ -1009,6 +1062,14 @@ public static List> findAllClassesInPackage(String basePackageName, Cla return Collections.unmodifiableList(classpathScanner.scanForClassesInPackage(basePackageName, classFilter)); } + /** + * @since 1.11 + */ + public static List findAllResourcesInPackage(String basePackageName, ResourceFilter resourceFilter) { + return Collections.unmodifiableList( + classpathScanner.scanForResourcesInPackage(basePackageName, resourceFilter)); + } + /** * @since 1.10 */ @@ -1016,6 +1077,13 @@ public static Stream> streamAllClassesInPackage(String basePackageName, return findAllClassesInPackage(basePackageName, classFilter).stream(); } + /** + * @since 1.11 + */ + public static Stream streamAllResourcesInPackage(String basePackageName, ResourceFilter resourceFilter) { + return findAllResourcesInPackage(basePackageName, resourceFilter).stream(); + } + /** * @since 1.1.1 * @see org.junit.platform.commons.support.ReflectionSupport#findAllClassesInModule(String, Predicate, Predicate) @@ -1026,6 +1094,16 @@ public static List> findAllClassesInModule(String moduleName, Predicate return findAllClassesInModule(moduleName, ClassFilter.of(classNameFilter, classFilter)); } + /** + * @since 1.11 + * @see org.junit.platform.commons.support.ReflectionSupport#findAllResourcesInModule(String, Predicate, Predicate) + */ + public static List findAllResourcesInModule(String moduleName, Predicate resourceFilter, + Predicate resourceNameFilter) { + // unmodifiable since returned by public, non-internal method(s) + return findAllResourcesInModule(moduleName, ResourceFilter.of(resourceNameFilter, resourceFilter)); + } + /** * @since 1.10 * @see org.junit.platform.commons.support.ReflectionSupport#streamAllClassesInModule(String, Predicate, Predicate) @@ -1035,6 +1113,15 @@ public static Stream> streamAllClassesInModule(String moduleName, Predi return streamAllClassesInModule(moduleName, ClassFilter.of(classNameFilter, classFilter)); } + /** + * @since 1.11 + * @see org.junit.platform.commons.support.ReflectionSupport#streamAllResourcesInModule(String, Predicate, Predicate) + */ + public static Stream streamAllResourcesInModule(String moduleName, Predicate resourceFilter, + Predicate resourceNameFilter) { + return streamAllResourcesInModule(moduleName, ResourceFilter.of(resourceNameFilter, resourceFilter)); + } + /** * @since 1.1.1 */ @@ -1042,6 +1129,13 @@ public static List> findAllClassesInModule(String moduleName, ClassFilt return Collections.unmodifiableList(ModuleUtils.findAllClassesInModule(moduleName, classFilter)); } + /** + * @since 1.11 + */ + public static List findAllResourcesInModule(String moduleName, ResourceFilter resourceFilter) { + return Collections.unmodifiableList(ModuleUtils.findAllResourcesInModule(moduleName, resourceFilter)); + } + /** * @since 1.10 */ @@ -1049,6 +1143,13 @@ public static Stream> streamAllClassesInModule(String moduleName, Class return findAllClassesInModule(moduleName, classFilter).stream(); } + /** + * @since 1.11 + */ + public static Stream streamAllResourcesInModule(String moduleName, ResourceFilter resourceFilter) { + return findAllResourcesInModule(moduleName, resourceFilter).stream(); + } + /** * @see org.junit.platform.commons.support.ReflectionSupport#findNestedClasses(Class, Predicate) */ diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFileVisitor.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFileVisitor.java new file mode 100644 index 000000000000..65d511b0aa2b --- /dev/null +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFileVisitor.java @@ -0,0 +1,66 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.util; + +import static java.nio.file.FileVisitResult.CONTINUE; + +import java.io.IOException; +import java.nio.file.FileVisitResult; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.function.Consumer; + +import org.junit.platform.commons.logging.Logger; +import org.junit.platform.commons.logging.LoggerFactory; + +/** + * @since 1.11 + */ +class ResourceFileVisitor extends SimpleFileVisitor { + + private static final Logger logger = LoggerFactory.getLogger(ResourceFileVisitor.class); + + static final String CLASS_FILE_SUFFIX = ".class"; + + private final Consumer classFileConsumer; + + ResourceFileVisitor(Consumer classFileConsumer) { + this.classFileConsumer = classFileConsumer; + } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attributes) { + if (isNotClassFile(file)) { + classFileConsumer.accept(file); + } + return CONTINUE; + } + + @Override + public FileVisitResult visitFileFailed(Path file, IOException ex) { + logger.warn(ex, () -> "I/O error visiting file: " + file); + return CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException ex) { + if (ex != null) { + logger.warn(ex, () -> "I/O error visiting directory: " + dir); + } + return CONTINUE; + } + + private static boolean isNotClassFile(Path file) { + return !file.getFileName().toString().endsWith(CLASS_FILE_SUFFIX); + } + +} diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java new file mode 100644 index 000000000000..bde54890c85e --- /dev/null +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java @@ -0,0 +1,73 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.util; + +import static org.apiguardian.api.API.Status.INTERNAL; + +import java.util.function.Predicate; + +import org.apiguardian.api.API; +import org.junit.platform.commons.support.Resource; + +/** + * Resource-related predicate used by reflection utilities. + * + *

DISCLAIMER

+ * + *

These utilities are intended solely for usage within the JUnit framework + * itself. Any usage by external parties is not supported. + * Use at your own risk! + * + * @since 1.11 + */ +@API(status = INTERNAL, since = "1.11") +public class ResourceFilter implements Predicate { + + /** + * Create a {@link ResourceFilter} instance that accepts all names but filters resources. + */ + public static ResourceFilter of(Predicate resourcePredicate) { + return of(name -> true, resourcePredicate); + } + + /** + * Create a {@link ResourceFilter} instance that filters by resource names and resources. + */ + public static ResourceFilter of(Predicate namePredicate, Predicate resourcePredicate) { + return new ResourceFilter(namePredicate, resourcePredicate); + } + + private final Predicate namePredicate; + private final Predicate resourcePredicate; + + private ResourceFilter(Predicate namePredicate, Predicate resourcePredicate) { + this.namePredicate = Preconditions.notNull(namePredicate, "name predicate must not be null"); + this.resourcePredicate = Preconditions.notNull(resourcePredicate, "resource predicate must not be null"); + } + + public boolean match(String name) { + return namePredicate.test(name); + } + + public boolean match(Resource resource) { + return resourcePredicate.test(resource); + } + + /** + * @implNote This implementation combines all tests stored in the predicates + * of this instance. Any new predicate must be added to this test method as + * well. + */ + @Override + public boolean test(Resource resource) { + return match(resource.getName()) && match(resource); + } +} diff --git a/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java b/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java index 100b1034c936..4523f10bf29b 100644 --- a/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java +++ b/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java @@ -21,6 +21,8 @@ import java.lang.module.ModuleReader; import java.lang.module.ModuleReference; import java.lang.module.ResolvedModule; +import java.net.URI; +import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashSet; @@ -35,6 +37,7 @@ import org.junit.platform.commons.JUnitException; import org.junit.platform.commons.logging.Logger; import org.junit.platform.commons.logging.LoggerFactory; +import org.junit.platform.commons.support.Resource; /** * Collection of utilities for working with {@code java.lang.Module} @@ -93,7 +96,7 @@ public static Optional getModuleVersion(Class type) { } /** - * Find all classes for the given module name. + * Find all {@linkplain Class classes} for the given module name. * * @param moduleName the name of the module to scan; never {@code null} or * empty @@ -114,6 +117,29 @@ public static List> findAllClassesInModule(String moduleName, ClassFilt return scan(moduleReferences, filter, ModuleUtils.class.getClassLoader()); } + /** + * Find all {@linkplain Resource resources} for the given module name. + * + * @param moduleName the name of the module to scan; never {@code null} or + * empty + * @param filter the class filter to apply; never {@code null} + * @return an immutable list of all such resources found; never {@code null} + * but potentially empty + */ + @API(status = INTERNAL, since = "1.11") + public static List findAllResourcesInModule(String moduleName, ResourceFilter filter) { + Preconditions.notBlank(moduleName, "Module name must not be null or empty"); + Preconditions.notNull(filter, "Resource filter must not be null"); + + logger.debug(() -> "Looking for classes in module: " + moduleName); + // @formatter:off + Set moduleReferences = streamResolvedModules(isEqual(moduleName)) + .map(ResolvedModule::reference) + .collect(toSet()); + // @formatter:on + return scan(moduleReferences, filter, ModuleUtils.class.getClassLoader()); + } + /** * Stream resolved modules from current (or boot) module layer. */ @@ -146,7 +172,7 @@ private static Stream streamResolvedModules(Predicate mo */ private static List> scan(Set references, ClassFilter filter, ClassLoader loader) { logger.debug(() -> "Scanning " + references.size() + " module references: " + references); - ModuleReferenceScanner scanner = new ModuleReferenceScanner(filter, loader); + ModuleReferenceClassScanner scanner = new ModuleReferenceClassScanner(filter, loader); List> classes = new ArrayList<>(); for (ModuleReference reference : references) { classes.addAll(scanner.scan(reference)); @@ -155,15 +181,30 @@ private static List> scan(Set references, ClassFilter return Collections.unmodifiableList(classes); } + /** + * Scan for classes using the supplied set of module references, class + * filter, and loader. + */ + private static List scan(Set references, ResourceFilter filter, ClassLoader loader) { + logger.debug(() -> "Scanning " + references.size() + " module references: " + references); + ModuleReferenceResourceScanner scanner = new ModuleReferenceResourceScanner(filter, loader); + List classes = new ArrayList<>(); + for (ModuleReference reference : references) { + classes.addAll(scanner.scan(reference)); + } + logger.debug(() -> "Found " + classes.size() + " classes: " + classes); + return Collections.unmodifiableList(classes); + } + /** * {@link ModuleReference} scanner. */ - static class ModuleReferenceScanner { + static class ModuleReferenceClassScanner { private final ClassFilter classFilter; private final ClassLoader classLoader; - ModuleReferenceScanner(ClassFilter classFilter, ClassLoader classLoader) { + ModuleReferenceClassScanner(ClassFilter classFilter, ClassLoader classLoader) { this.classFilter = classFilter; this.classLoader = classLoader; } @@ -180,6 +221,7 @@ List> scan(ModuleReference reference) { .filter(name -> !name.equals("module-info")) .filter(classFilter::match) .map(this::loadClassUnchecked) + // TODO: The ClasspathScanner invokes Predicate.test here .filter(classFilter::match) .collect(Collectors.toList()); // @formatter:on @@ -214,5 +256,50 @@ private Class loadClassUnchecked(String binaryName) { } } + /** + * {@link ModuleReference} scanner. + */ + static class ModuleReferenceResourceScanner { + + private final ResourceFilter resourceFilter; + private final ClassLoader classLoader; + + ModuleReferenceResourceScanner(ResourceFilter resourceFilter, ClassLoader classLoader) { + this.resourceFilter = resourceFilter; + this.classLoader = classLoader; + } + + /** + * Scan module reference for resources that potentially contain testable resources. + */ + List scan(ModuleReference reference) { + try (ModuleReader reader = reference.open()) { + try (Stream names = reader.list()) { + // @formatter:off + return names.filter(name -> !name.endsWith(".class")) + .filter(resourceFilter::match) + .map(this::loadResourceUnchecked) + // TODO: The ClasspathScanner invokes Predicate.test here + .filter(resourceFilter::match) + .collect(Collectors.toList()); + // @formatter:on + } + } + catch (IOException e) { + throw new JUnitException("Failed to read contents of " + reference + ".", e); + } + } + + private Resource loadResourceUnchecked(String binaryName) { + try { + URI uri = classLoader.getResource(binaryName).toURI(); + return new ClasspathResource(binaryName, uri); + } + catch (URISyntaxException e) { + throw new JUnitException("Failed to load resource with name '" + binaryName + "'.", e); + } + } + + } } diff --git a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java index bcaac336fa45..94c883c81d73 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java @@ -36,6 +36,7 @@ class ReflectionSupportTests { private static final Predicate> allTypes = type -> true; + private static final Predicate allResources = type -> true; private static final Predicate allNames = name -> true; private static final Predicate allMethods = name -> true; private static final Predicate allFields = name -> true; @@ -132,6 +133,36 @@ void findAllClassesInClasspathRootPreconditions() { () -> ReflectionSupport.findAllClassesInClasspathRoot(path, allTypes, null)); } + @TestFactory + List findAllResourcesInClasspathRootDelegates() throws Throwable { + List tests = new ArrayList<>(); + List paths = new ArrayList<>(); + paths.add(Path.of(".").toRealPath()); + paths.addAll(ReflectionUtils.getAllClasspathRootDirectories()); + for (var path : paths) { + var root = path.toUri(); + var displayName = root.getPath(); + if (displayName.length() > 42) { + displayName = "..." + displayName.substring(displayName.length() - 42); + } + tests.add(DynamicTest.dynamicTest(displayName, + () -> assertEquals(ReflectionUtils.findAllResourcesInClasspathRoot(root, allResources, allNames), + ReflectionSupport.findAllResourcesInClasspathRoot(root, allResources, allNames)))); + } + return tests; + } + + @Test + void findAllResourcesInClasspathRootPreconditions() { + var path = Path.of(".").toUri(); + assertPreconditionViolationException("root", + () -> ReflectionSupport.findAllResourcesInClasspathRoot(null, allResources, allNames)); + assertPreconditionViolationException("resource predicate", + () -> ReflectionSupport.findAllResourcesInClasspathRoot(path, null, allNames)); + assertPreconditionViolationException("name predicate", + () -> ReflectionSupport.findAllResourcesInClasspathRoot(path, allResources, null)); + } + @Test void findAllClassesInPackageDelegates() { assertNotEquals(0, ReflectionSupport.findAllClassesInPackage("org.junit", allTypes, allNames).size()); @@ -149,6 +180,24 @@ void findAllClassesInPackagePreconditions() { () -> ReflectionSupport.findAllClassesInPackage("org.junit", allTypes, null)); } + @Test + void findAllResourcesInPackageDelegates() { + assertNotEquals(0, ReflectionSupport.findAllResourcesInPackage("org.junit", allResources, allNames).size()); + + assertEquals(ReflectionUtils.findAllResourcesInPackage("org.junit", allResources, allNames), + ReflectionSupport.findAllResourcesInPackage("org.junit", allResources, allNames)); + } + + @Test + void findAllResourcesInPackagePreconditions() { + assertPreconditionViolationExceptionForString("basePackageName", + () -> ReflectionSupport.findAllResourcesInPackage(null, allResources, allNames)); + assertPreconditionViolationException("resource predicate", + () -> ReflectionSupport.findAllResourcesInPackage("org.junit", null, allNames)); + assertPreconditionViolationException("name predicate", + () -> ReflectionSupport.findAllResourcesInPackage("org.junit", allResources, null)); + } + @Test void findAllClassesInModuleDelegates() { assertEquals(ReflectionUtils.findAllClassesInModule("org.junit.platform.commons", allTypes, allNames), @@ -166,6 +215,23 @@ void findAllClassesInModulePreconditions() { () -> ReflectionSupport.findAllClassesInModule("org.junit.platform.commons", allTypes, null)); } + @Test + void findAllResourcesInModuleDelegates() { + assertEquals(ReflectionUtils.findAllResourcesInModule("org.junit.platform.commons", allResources, allNames), + ReflectionSupport.findAllResourcesInModule("org.junit.platform.commons", allResources, allNames)); + } + + @Test + void findAllResourcesInModulePreconditions() { + var exception = assertThrows(PreconditionViolationException.class, + () -> ReflectionSupport.findAllResourcesInModule(null, allResources, allNames)); + assertEquals("Module name must not be null or empty", exception.getMessage()); + assertPreconditionViolationException("resource predicate", + () -> ReflectionSupport.findAllResourcesInModule("org.junit.platform.commons", null, allNames)); + assertPreconditionViolationException("name predicate", + () -> ReflectionSupport.findAllResourcesInModule("org.junit.platform.commons", allResources, null)); + } + @Test void newInstanceDelegates() { assertEquals(ReflectionUtils.newInstance(String.class, "foo"), diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java index 3835a2713cd5..b7e7bfba0785 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java @@ -10,6 +10,7 @@ package org.junit.platform.commons.util; +import static java.util.Objects.requireNonNull; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertSame; @@ -17,12 +18,16 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assumptions.assumeFalse; import static org.junit.platform.commons.test.ConcurrencyTestingUtils.executeConcurrently; +import static org.junit.platform.commons.util.Preconditions.notNull; import java.io.IOException; +import java.io.InputStream; import java.lang.module.ModuleFinder; import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; import java.net.URLClassLoader; +import java.nio.charset.StandardCharsets; import java.nio.file.FileSystemNotFoundException; import java.nio.file.FileSystems; import java.nio.file.Files; @@ -45,6 +50,7 @@ import org.junit.platform.commons.PreconditionViolationException; import org.junit.platform.commons.function.Try; import org.junit.platform.commons.logging.LogRecordListener; +import org.junit.platform.commons.support.Resource; /** * Unit tests for {@link ClasspathScanner}. @@ -55,6 +61,7 @@ class ClasspathScannerTests { private static final ClassFilter allClasses = ClassFilter.of(type -> true); + private static final ResourceFilter allResources = ResourceFilter.of(type -> true); private final List> loadedClasses = new ArrayList<>(); @@ -182,6 +189,14 @@ void scanForClassesInPackage() { assertTrue(classes.contains(MemberClassToBeFound.class)); } + @Test + void scanForResourcesInPackage() throws URISyntaxException { + var resources = classpathScanner.scanForResourcesInPackage("org.junit.platform.commons", allResources); + assertThat(resources).extracting(Resource::getUri).containsExactly( + uriOf("/org/junit/platform/commons/example.resource"), + uriOf("/org/junit/platform/commons/other-example.resource")); + } + @Test // #2500 void scanForClassesInPackageWithinModulesSharingNamePrefix(@TempDir Path temp) throws Exception { @@ -248,6 +263,33 @@ void findAllClassesInPackageWithinJarFileConcurrently() throws Exception { } } + @Test + void findAllResourcesInPackageWithinJarFileConcurrently() throws Exception { + var jarFile = getClass().getResource("/jartest.jar"); + var jarUri = URI.create("jar:" + jarFile); + + try (var classLoader = new URLClassLoader(new URL[] { jarFile })) { + var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass); + + var results = executeConcurrently(10, + () -> classpathScanner.scanForResourcesInPackage("org.junit.platform.jartest.included", allResources)); + + assertThrows(FileSystemNotFoundException.class, () -> FileSystems.getFileSystem(jarUri), + "FileSystem should be closed"); + + results.forEach(resources -> { + // TODO: Actual URI's start with `jar:file:///` instead of `jar:file:/` which seems weird. + assertThat(resources).extracting(Resource::getUri).extracting(URI::toString).anyMatch( + s -> s.endsWith("!/org/junit/platform/jartest/included/included.resource")); + assertThat(resources).extracting(Resource::getUri).extracting(URI::toString).anyMatch( + s -> s.endsWith("!/org/junit/platform/jartest/included/recursive/recursively-included.resource")); + assertThat(resources).extracting(Resource::getUri).extracting(URI::toString).noneMatch( + s -> s.endsWith("!/org/junit/platform/jartest/not-included/not-included.resource")); + + }); + } + } + @Test void scanForClassesInDefaultPackage() { var classFilter = ClassFilter.of(this::inDefaultPackage); @@ -258,6 +300,16 @@ void scanForClassesInDefaultPackage() { assertTrue(classes.stream().anyMatch(clazz -> "DefaultPackageTestCase".equals(clazz.getName()))); } + @Test + void scanForResourcesInDefaultPackage() { + var resourceFilter = ResourceFilter.of(this::inDefaultPackage); + var resources = classpathScanner.scanForResourcesInPackage("", resourceFilter); + + assertThat(resources).as("number of resources found in default package").isNotEmpty(); + assertTrue(resources.stream().allMatch(this::inDefaultPackage)); + assertTrue(resources.stream().anyMatch(resource -> "default-package.resource".equals(resource.getName()))); + } + @Test void scanForClassesInPackageWithFilter() { var thisClassOnly = ClassFilter.of(clazz -> clazz == ClasspathScannerTests.class); @@ -265,18 +317,54 @@ void scanForClassesInPackageWithFilter() { assertSame(ClasspathScannerTests.class, classes.get(0)); } + @Test + void scanForResourcesInPackageWithFilter() { + var thisResourceOnly = ResourceFilter.of( + resource -> "org/junit/platform/commons/example.resource".equals(resource.getName())); + var resources = classpathScanner.scanForResourcesInPackage("org.junit.platform.commons", thisResourceOnly); + assertThat(resources).extracting(Resource::getName).containsExactly( + "org/junit/platform/commons/example.resource"); + } + + @Test + void resourcesCanBeRead() throws IOException { + var thisResourceOnly = ResourceFilter.of( + resource -> "org/junit/platform/commons/example.resource".equals(resource.getName())); + var resources = classpathScanner.scanForResourcesInPackage("org.junit.platform.commons", thisResourceOnly); + Resource resource = resources.get(0); + + assertThat(resource.getName()).isEqualTo("org/junit/platform/commons/example.resource"); + assertThat(resource.getUri()).isEqualTo(uriOf("/org/junit/platform/commons/example.resource")); + try (InputStream is = resource.getInputStream()) { + String contents = new String(is.readAllBytes(), StandardCharsets.UTF_8); + assertThat(contents).isEqualTo("This file was unintentionally left blank."); + } + } + @Test void scanForClassesInPackageForNullBasePackage() { assertThrows(PreconditionViolationException.class, () -> classpathScanner.scanForClassesInPackage(null, allClasses)); } + @Test + void scanForResourcesInPackageForNullBasePackage() { + assertThrows(PreconditionViolationException.class, + () -> classpathScanner.scanForResourcesInPackage(null, allResources)); + } + @Test void scanForClassesInPackageForWhitespaceBasePackage() { assertThrows(PreconditionViolationException.class, () -> classpathScanner.scanForClassesInPackage(" ", allClasses)); } + @Test + void scanForResourcesInPackageForWhitespaceBasePackage() { + assertThrows(PreconditionViolationException.class, + () -> classpathScanner.scanForResourcesInPackage(" ", allResources)); + } + @Test void scanForClassesInPackageForNullClassFilter() { assertThrows(PreconditionViolationException.class, @@ -290,6 +378,13 @@ void scanForClassesInPackageWhenIOExceptionOccurs() { assertThat(classes).isEmpty(); } + @Test + void scanForResourcesInPackageWhenIOExceptionOccurs() { + var scanner = new ClasspathScanner(ThrowingClassLoader::new, ReflectionUtils::tryToLoadClass); + var classes = scanner.scanForResourcesInPackage("org.junit.platform.commons", allResources); + assertThat(classes).isEmpty(); + } + @Test void scanForClassesInPackageOnlyLoadsClassesThatAreIncludedByTheClassNameFilter() { Predicate classNameFilter = name -> ClasspathScannerTests.class.getName().equals(name); @@ -340,6 +435,10 @@ private boolean inDefaultPackage(Class clazz) { return pkg == null || "".equals(clazz.getPackage().getName()); } + private boolean inDefaultPackage(Resource resource) { + return !resource.getName().contains("/"); + } + @Test void findAllClassesInClasspathRootWithFilter() throws Exception { var root = getTestClasspathRoot(); @@ -377,6 +476,16 @@ void onlyLoadsClassesInClasspathRootThatAreIncludedByTheClassNameFilter() throws assertThat(loadedClasses).containsExactly(ClasspathScannerTests.class); } + private static URI uriOf(String name) { + var resource = ClasspathScannerTests.class.getResource(name); + try { + return requireNonNull(resource).toURI(); + } + catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } + private URI getTestClasspathRoot() throws Exception { var location = getClass().getProtectionDomain().getCodeSource().getLocation(); return location.toURI(); diff --git a/platform-tests/src/test/resources/default-package.resource b/platform-tests/src/test/resources/default-package.resource new file mode 100644 index 000000000000..7b5facc9c20c --- /dev/null +++ b/platform-tests/src/test/resources/default-package.resource @@ -0,0 +1 @@ +This file was unintentionally left blank. \ No newline at end of file diff --git a/platform-tests/src/test/resources/jartest.jar b/platform-tests/src/test/resources/jartest.jar index d470846c87451d6dee05105ce21a443842ca1cdc..02f12e1b9d4571ee99ac748a92cb1754d9acc6bc 100644 GIT binary patch delta 1072 zcmew+yh6$)z?+#xgn@yBgMlsTg9if;Fo6gl;ACK7@O2Gw)b;dp)Bkshfq|I;Rq@Yn z+<%>c3SB0KBuqT=i;-dSUv}}$*BFHuC)+bhOcr3a5CxeV68XV{za{kc8=%rMMg|7= z$%4#=oBNpAA)9S)8~3XHVE4= z$V^t`keQsv$y1+~U!t3tmz-0YlA5AdlvzL`9cQEYM~yB3oyI|6Xu-!i;-`#DyPik0uDZ=V@zO;`plwm)jK&9nS_|3 z!orjLm?eR#wHT8p2XGnz9o5XK$hZQ?)|z~tQ&@|UNsbwNjM^|r03FT108FC{TN)p- z0u9uR#F4&OA?XV(Z3TGaHr*7(^j0>obJsI+hGI!Qq?_)IV!9GLEHJzYqzha&v9f_e Pf*%NNSs56vvV(X4^$sQc delta 409 zcmZ1>^-VY=z?+#xgn@&DgMlsTg9if=;ACK7@O2Gw)b;dp)Bkshfq|JJz?+=|q=E^m z42R~4E(yHs96!Ht|8)i`bYWnaxbUwK$cm6iWGgmrV3c44D!f~o!h8>?(2)_SPjE5%Iau_l`nY^CEoRMd8A*a~nzZ_aX zxk664$!?rljAcNUK2XO(PDREYK(_kiSDY41-siDn+i`O-y?_Y5Wf2q$@MdKLx{84Z2-h<+Fc^Y)0JoG?@&Et; diff --git a/platform-tests/src/test/resources/org/junit/platform/commons/example.resource b/platform-tests/src/test/resources/org/junit/platform/commons/example.resource new file mode 100644 index 000000000000..7b5facc9c20c --- /dev/null +++ b/platform-tests/src/test/resources/org/junit/platform/commons/example.resource @@ -0,0 +1 @@ +This file was unintentionally left blank. \ No newline at end of file diff --git a/platform-tests/src/test/resources/org/junit/platform/commons/other-example.resource b/platform-tests/src/test/resources/org/junit/platform/commons/other-example.resource new file mode 100644 index 000000000000..7b5facc9c20c --- /dev/null +++ b/platform-tests/src/test/resources/org/junit/platform/commons/other-example.resource @@ -0,0 +1 @@ +This file was unintentionally left blank. \ No newline at end of file From 2f76493be26d5dc4652058d74c5d4c822ab784f2 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Sun, 25 Feb 2024 22:50:29 +0100 Subject: [PATCH 02/78] Formatting --- .../java/org/junit/platform/commons/util/ClasspathResource.java | 1 + 1 file changed, 1 insertion(+) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathResource.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathResource.java index 17a9b54f3d79..1c426906f63f 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathResource.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathResource.java @@ -16,6 +16,7 @@ import org.junit.platform.commons.support.Resource; class ClasspathResource implements Resource { + private final String name; private final URI uri; From 277272ad471d242c324f18746db0337fb27ba713 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Sun, 25 Feb 2024 23:20:37 +0100 Subject: [PATCH 03/78] Doc --- .../org/junit/platform/commons/util/ModuleUtils.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ModuleUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ModuleUtils.java index 949824501556..bf083e63bed4 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ModuleUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ModuleUtils.java @@ -99,11 +99,13 @@ public static List> findAllClassesInModule(String moduleName, ClassFilt } /** - * TODO: DOC + * Find all resources for the given module name. * - * @param moduleName - * @param filter - * @return + * @param moduleName the name of the module to scan; never {@code null} or + * empty + * @param filter the class filter to apply; never {@code null} + * @return an immutable list of all such resources found; never {@code null} + * but potentially empty */ @API(status = INTERNAL, since = "1.11") public static List findAllResourcesInModule(String moduleName, ResourceFilter filter) { From f683debfe2ac5402b0b817ed5410c288beef29cc Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Sun, 25 Feb 2024 23:36:10 +0100 Subject: [PATCH 04/78] Fix --- .../junit/platform/commons/util/ClasspathScannerTests.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java index b7e7bfba0785..07c7a4b6933a 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java @@ -18,7 +18,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assumptions.assumeFalse; import static org.junit.platform.commons.test.ConcurrencyTestingUtils.executeConcurrently; -import static org.junit.platform.commons.util.Preconditions.notNull; import java.io.IOException; import java.io.InputStream; @@ -190,9 +189,9 @@ void scanForClassesInPackage() { } @Test - void scanForResourcesInPackage() throws URISyntaxException { + void scanForResourcesInPackage() { var resources = classpathScanner.scanForResourcesInPackage("org.junit.platform.commons", allResources); - assertThat(resources).extracting(Resource::getUri).containsExactly( + assertThat(resources).extracting(Resource::getUri).containsExactlyInAnyOrder( uriOf("/org/junit/platform/commons/example.resource"), uriOf("/org/junit/platform/commons/other-example.resource")); } From c457b58cc5a72e703a5d8fd50bbc73d43c935ddc Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Thu, 29 Feb 2024 22:22:12 +0100 Subject: [PATCH 05/78] Clean up todos --- .../org/junit/platform/commons/util/ClasspathScanner.java | 6 ++++-- .../org/junit/platform/commons/util/ModuleUtils.java | 8 ++++---- .../src/test/resources/default-package.resource | 2 +- .../resources/org/junit/platform/commons/example.resource | 2 +- .../org/junit/platform/commons/other-example.resource | 2 +- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java index a8f47fa921a6..65e8313e72af 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java @@ -200,7 +200,8 @@ private void processClassFileSafely(Path baseDir, String basePackageName, ClassF // @formatter:off loadClass.apply(fullyQualifiedClassName, getClassLoader()) .toOptional() - .filter(classFilter) // Always use ".filter(classFilter)" to include future predicates. + // Always use ".filter(classFilter)" to include future predicates. + .filter(classFilter) .ifPresent(classConsumer); // @formatter:on } @@ -221,7 +222,8 @@ private void processResourceFileSafely(Path baseDir, String basePackageName, Res resourceFile); if (resourceFilter.match(fullyQualifiedResourceName)) { Resource resource = new ClasspathResource(fullyQualifiedResourceName, resourceFile.toUri()); - if (resourceFilter.test(resource)) { // Always use ".test(classFilter)" to include future predicates. + // Always use ".test(classFilter)" to include future predicates. + if (resourceFilter.test(resource)) { resourceConsumer.accept(resource); } } diff --git a/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java b/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java index 4523f10bf29b..3747026e8353 100644 --- a/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java +++ b/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java @@ -221,8 +221,8 @@ List> scan(ModuleReference reference) { .filter(name -> !name.equals("module-info")) .filter(classFilter::match) .map(this::loadClassUnchecked) - // TODO: The ClasspathScanner invokes Predicate.test here - .filter(classFilter::match) + // Always use ".filter(classFilter)" to include future predicates. + .filter(classFilter) .collect(Collectors.toList()); // @formatter:on } @@ -279,8 +279,8 @@ List scan(ModuleReference reference) { return names.filter(name -> !name.endsWith(".class")) .filter(resourceFilter::match) .map(this::loadResourceUnchecked) - // TODO: The ClasspathScanner invokes Predicate.test here - .filter(resourceFilter::match) + // Always use ".filter(resourceFilter)" to include future predicates. + .filter(resourceFilter) .collect(Collectors.toList()); // @formatter:on } diff --git a/platform-tests/src/test/resources/default-package.resource b/platform-tests/src/test/resources/default-package.resource index 7b5facc9c20c..3f8177ae5d6c 100644 --- a/platform-tests/src/test/resources/default-package.resource +++ b/platform-tests/src/test/resources/default-package.resource @@ -1 +1 @@ -This file was unintentionally left blank. \ No newline at end of file +This file was unintentionally left blank. diff --git a/platform-tests/src/test/resources/org/junit/platform/commons/example.resource b/platform-tests/src/test/resources/org/junit/platform/commons/example.resource index 7b5facc9c20c..3f8177ae5d6c 100644 --- a/platform-tests/src/test/resources/org/junit/platform/commons/example.resource +++ b/platform-tests/src/test/resources/org/junit/platform/commons/example.resource @@ -1 +1 @@ -This file was unintentionally left blank. \ No newline at end of file +This file was unintentionally left blank. diff --git a/platform-tests/src/test/resources/org/junit/platform/commons/other-example.resource b/platform-tests/src/test/resources/org/junit/platform/commons/other-example.resource index 7b5facc9c20c..3f8177ae5d6c 100644 --- a/platform-tests/src/test/resources/org/junit/platform/commons/other-example.resource +++ b/platform-tests/src/test/resources/org/junit/platform/commons/other-example.resource @@ -1 +1 @@ -This file was unintentionally left blank. \ No newline at end of file +This file was unintentionally left blank. From c9b3b0e7922c744e91b830d943908bce306f8baa Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Thu, 29 Feb 2024 22:23:54 +0100 Subject: [PATCH 06/78] Clean up todos --- .../org/junit/platform/commons/util/ClasspathScanner.java | 7 +++---- .../platform/commons/util/ClasspathScannerTests.java | 8 ++++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java index 65e8313e72af..8b1fab732a2a 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java @@ -310,10 +310,9 @@ private void logMalformedClassName(Path classFile, String fullyQualifiedClassNam } } - private void logGenericFileProcessingException(Path classFile, Throwable throwable) { - // TODO: Can't mention java.lang.Class here, could be a resource - logger.debug(throwable, () -> format("Failed to load java.lang.Class for path [%s] during classpath scanning.", - classFile.toAbsolutePath())); + private void logGenericFileProcessingException(Path classpathFile, Throwable throwable) { + logger.debug(throwable, + () -> format("Failed to load [%s] during classpath scanning.", classpathFile.toAbsolutePath())); } private ClassLoader getClassLoader() { diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java index 07c7a4b6933a..8927af0d480d 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java @@ -82,7 +82,7 @@ void scanForClassesInClasspathRootWhenMalformedClassnameInternalErrorOccursWithN }; assertClassesScannedWhenExceptionIsThrown(malformedClassNameSimulationFilter); - assertDebugMessageLogged(listener, "Failed to load java.lang.Class for path .+ during classpath scanning."); + assertDebugMessageLogged(listener, "Failed to load .+ during classpath scanning."); } @Test @@ -110,7 +110,7 @@ void scanForClassesInClasspathRootWhenOtherInternalErrorOccurs(LogRecordListener }; assertClassesScannedWhenExceptionIsThrown(otherInternalErrorSimulationFilter); - assertDebugMessageLogged(listener, "Failed to load java.lang.Class for path .+ during classpath scanning."); + assertDebugMessageLogged(listener, "Failed to load .+ during classpath scanning."); } @Test @@ -123,7 +123,7 @@ void scanForClassesInClasspathRootWhenGenericRuntimeExceptionOccurs(LogRecordLis }; assertClassesScannedWhenExceptionIsThrown(runtimeExceptionSimulationFilter); - assertDebugMessageLogged(listener, "Failed to load java.lang.Class for path .+ during classpath scanning."); + assertDebugMessageLogged(listener, "Failed to load .+ during classpath scanning."); } private void assertClassesScannedWhenExceptionIsThrown(Predicate> filter) throws Exception { @@ -336,7 +336,7 @@ void resourcesCanBeRead() throws IOException { assertThat(resource.getUri()).isEqualTo(uriOf("/org/junit/platform/commons/example.resource")); try (InputStream is = resource.getInputStream()) { String contents = new String(is.readAllBytes(), StandardCharsets.UTF_8); - assertThat(contents).isEqualTo("This file was unintentionally left blank."); + assertThat(contents).isEqualTo("This file was unintentionally left blank.\n"); } } From e5a175197fbf4a06406324bd575f5f4d5a271c88 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Thu, 7 Mar 2024 21:50:18 +0100 Subject: [PATCH 07/78] Clean up --- .../commons/util/ClasspathScanner.java | 2 +- .../commons/util/ClasspathScannerTests.java | 32 +++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java index 8b1fab732a2a..118738045176 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java @@ -222,7 +222,7 @@ private void processResourceFileSafely(Path baseDir, String basePackageName, Res resourceFile); if (resourceFilter.match(fullyQualifiedResourceName)) { Resource resource = new ClasspathResource(fullyQualifiedResourceName, resourceFile.toUri()); - // Always use ".test(classFilter)" to include future predicates. + // Always use "resourceFilter.test" to include future predicates. if (resourceFilter.test(resource)) { resourceConsumer.accept(resource); } diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java index 8927af0d480d..a127ec867635 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java @@ -253,12 +253,14 @@ void findAllClassesInPackageWithinJarFileConcurrently() throws Exception { assertThrows(FileSystemNotFoundException.class, () -> FileSystems.getFileSystem(jarUri), "FileSystem should be closed"); - results.forEach(classes -> { - assertThat(classes).hasSize(2); - var classNames = classes.stream().map(Class::getSimpleName).toList(); - assertTrue(classNames.contains("Included")); - assertTrue(classNames.contains("RecursivelyIncluded")); - }); + // @formatter:off + results.forEach(classes -> assertThat(classes) + .hasSize(2) + .extracting(Class::getSimpleName).containsExactlyInAnyOrder( + "Included", + "RecursivelyIncluded" + )); + // @formatter:on } } @@ -276,16 +278,14 @@ void findAllResourcesInPackageWithinJarFileConcurrently() throws Exception { assertThrows(FileSystemNotFoundException.class, () -> FileSystems.getFileSystem(jarUri), "FileSystem should be closed"); - results.forEach(resources -> { - // TODO: Actual URI's start with `jar:file:///` instead of `jar:file:/` which seems weird. - assertThat(resources).extracting(Resource::getUri).extracting(URI::toString).anyMatch( - s -> s.endsWith("!/org/junit/platform/jartest/included/included.resource")); - assertThat(resources).extracting(Resource::getUri).extracting(URI::toString).anyMatch( - s -> s.endsWith("!/org/junit/platform/jartest/included/recursive/recursively-included.resource")); - assertThat(resources).extracting(Resource::getUri).extracting(URI::toString).noneMatch( - s -> s.endsWith("!/org/junit/platform/jartest/not-included/not-included.resource")); - - }); + // @formatter:off + results.forEach(resources -> assertThat(resources) + .hasSize(2) + .extracting(Resource::getName).containsExactlyInAnyOrder( + "org/junit/platform/jartest/included/included.resource", + "org/junit/platform/jartest/included/recursive/recursively-included.resource" + )); + // @formatter:on } } From 2bab069978f844d78c21d4ddb5c437aeaec0e5e5 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Thu, 7 Mar 2024 22:22:29 +0100 Subject: [PATCH 08/78] Extract common code in findClassesForPath and findResourcesForPath --- .../commons/util/ClasspathScanner.java | 59 +++++++------------ 1 file changed, 20 insertions(+), 39 deletions(-) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java index 118738045176..a8cd067bd32c 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.net.URI; import java.net.URL; +import java.nio.file.FileVisitor; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -30,6 +31,7 @@ import java.util.Set; import java.util.function.BiFunction; import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Stream; @@ -124,17 +126,10 @@ private List> findClassesForUris(List baseUris, String basePackage } private List> findClassesForUri(URI baseUri, String basePackageName, ClassFilter classFilter) { - try (CloseablePath closeablePath = CloseablePath.create(baseUri)) { - Path baseDir = closeablePath.getPath(); - return findClassesForPath(baseDir, basePackageName, classFilter); - } - catch (PreconditionViolationException ex) { - throw ex; - } - catch (Exception ex) { - logger.warn(ex, () -> "Error scanning files for URI " + baseUri); - return emptyList(); - } + List> classes = new ArrayList<>(); + walkFilesForUri(baseUri, baseDir -> new ClassFileVisitor( + classFile -> processClassFileSafely(baseDir, basePackageName, classFilter, classFile, classes::add))); + return classes; } /** @@ -152,43 +147,29 @@ private List findResourcesForUris(List baseUris, String basePacka } private List findResourcesForUri(URI baseUri, String basePackageName, ResourceFilter resourceFilter) { + List resources = new ArrayList<>(); + walkFilesForUri(baseUri, baseDir -> new ResourceFileVisitor(resourceFile -> processResourceFileSafely(baseDir, + basePackageName, resourceFilter, resourceFile, resources::add))); + return resources; + } + + private static void walkFilesForUri(URI baseUri, Function> visitorConstructor) { try (CloseablePath closeablePath = CloseablePath.create(baseUri)) { Path baseDir = closeablePath.getPath(); - return findResourcesForPath(baseDir, basePackageName, resourceFilter); + Preconditions.condition(Files.exists(baseDir), () -> "baseDir must exist: " + baseDir); + try { + Files.walkFileTree(baseDir, visitorConstructor.apply(baseDir)); + } + catch (IOException ex) { + logger.warn(ex, () -> "I/O error scanning files in " + baseDir); + } } catch (PreconditionViolationException ex) { throw ex; } catch (Exception ex) { logger.warn(ex, () -> "Error scanning files for URI " + baseUri); - return emptyList(); - } - } - - private List> findClassesForPath(Path baseDir, String basePackageName, ClassFilter classFilter) { - Preconditions.condition(Files.exists(baseDir), () -> "baseDir must exist: " + baseDir); - List> classes = new ArrayList<>(); - try { - Files.walkFileTree(baseDir, new ClassFileVisitor( - classFile -> processClassFileSafely(baseDir, basePackageName, classFilter, classFile, classes::add))); - } - catch (IOException ex) { - logger.warn(ex, () -> "I/O error scanning files in " + baseDir); } - return classes; - } - - private List findResourcesForPath(Path baseDir, String basePackageName, ResourceFilter resourceFilter) { - Preconditions.condition(Files.exists(baseDir), () -> "baseDir must exist: " + baseDir); - List resources = new ArrayList<>(); - try { - Files.walkFileTree(baseDir, new ResourceFileVisitor(resourceFile -> processResourceFileSafely(baseDir, - basePackageName, resourceFilter, resourceFile, resources::add))); - } - catch (IOException ex) { - logger.warn(ex, () -> "I/O error scanning files in " + baseDir); - } - return resources; } private void processClassFileSafely(Path baseDir, String basePackageName, ClassFilter classFilter, Path classFile, From f34c4c96606900cf49b302b7c1c2375933b434d0 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Thu, 7 Mar 2024 22:46:36 +0100 Subject: [PATCH 09/78] Extract common file visitor code --- .../commons/util/ClassFileVisitor.java | 76 ------------------- ...Visitor.java => ClasspathFileVisitor.java} | 27 ++++--- .../commons/util/ClasspathFilters.java | 45 +++++++++++ .../commons/util/ClasspathScanner.java | 24 +++--- 4 files changed, 73 insertions(+), 99 deletions(-) delete mode 100644 junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClassFileVisitor.java rename junit-platform-commons/src/main/java/org/junit/platform/commons/util/{ResourceFileVisitor.java => ClasspathFileVisitor.java} (67%) create mode 100644 junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathFilters.java diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClassFileVisitor.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClassFileVisitor.java deleted file mode 100644 index 7a49471c16b1..000000000000 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClassFileVisitor.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.commons.util; - -import static java.nio.file.FileVisitResult.CONTINUE; - -import java.io.IOException; -import java.nio.file.FileVisitResult; -import java.nio.file.Path; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.function.Consumer; - -import org.junit.platform.commons.logging.Logger; -import org.junit.platform.commons.logging.LoggerFactory; - -/** - * @since 1.0 - */ -class ClassFileVisitor extends SimpleFileVisitor { - - private static final Logger logger = LoggerFactory.getLogger(ClassFileVisitor.class); - - static final String CLASS_FILE_SUFFIX = ".class"; - private static final String PACKAGE_INFO_FILE_NAME = "package-info" + CLASS_FILE_SUFFIX; - private static final String MODULE_INFO_FILE_NAME = "module-info" + CLASS_FILE_SUFFIX; - - private final Consumer classFileConsumer; - - ClassFileVisitor(Consumer classFileConsumer) { - this.classFileConsumer = classFileConsumer; - } - - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attributes) { - if (isNotPackageInfo(file) && isNotModuleInfo(file) && isClassFile(file)) { - classFileConsumer.accept(file); - } - return CONTINUE; - } - - @Override - public FileVisitResult visitFileFailed(Path file, IOException ex) { - logger.warn(ex, () -> "I/O error visiting file: " + file); - return CONTINUE; - } - - @Override - public FileVisitResult postVisitDirectory(Path dir, IOException ex) { - if (ex != null) { - logger.warn(ex, () -> "I/O error visiting directory: " + dir); - } - return CONTINUE; - } - - private static boolean isNotPackageInfo(Path path) { - return !path.endsWith(PACKAGE_INFO_FILE_NAME); - } - - private static boolean isNotModuleInfo(Path path) { - return !path.endsWith(MODULE_INFO_FILE_NAME); - } - - private static boolean isClassFile(Path file) { - return file.getFileName().toString().endsWith(CLASS_FILE_SUFFIX); - } - -} diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFileVisitor.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathFileVisitor.java similarity index 67% rename from junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFileVisitor.java rename to junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathFileVisitor.java index 65d511b0aa2b..7f2ad8195085 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFileVisitor.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathFileVisitor.java @@ -17,7 +17,8 @@ import java.nio.file.Path; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; -import java.util.function.Consumer; +import java.util.function.BiConsumer; +import java.util.function.Predicate; import org.junit.platform.commons.logging.Logger; import org.junit.platform.commons.logging.LoggerFactory; @@ -25,22 +26,24 @@ /** * @since 1.11 */ -class ResourceFileVisitor extends SimpleFileVisitor { +class ClasspathFileVisitor extends SimpleFileVisitor { - private static final Logger logger = LoggerFactory.getLogger(ResourceFileVisitor.class); + private static final Logger logger = LoggerFactory.getLogger(ClasspathFileVisitor.class); - static final String CLASS_FILE_SUFFIX = ".class"; + private final Path basePath; + private final BiConsumer consumer; + private final Predicate filter; - private final Consumer classFileConsumer; - - ResourceFileVisitor(Consumer classFileConsumer) { - this.classFileConsumer = classFileConsumer; + ClasspathFileVisitor(Path basePath, Predicate filter, BiConsumer consumer) { + this.basePath = basePath; + this.filter = filter; + this.consumer = consumer; } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attributes) { - if (isNotClassFile(file)) { - classFileConsumer.accept(file); + if (filter.test(file)) { + consumer.accept(basePath, file); } return CONTINUE; } @@ -59,8 +62,4 @@ public FileVisitResult postVisitDirectory(Path dir, IOException ex) { return CONTINUE; } - private static boolean isNotClassFile(Path file) { - return !file.getFileName().toString().endsWith(CLASS_FILE_SUFFIX); - } - } diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathFilters.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathFilters.java new file mode 100644 index 000000000000..7ad6cd3b0682 --- /dev/null +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathFilters.java @@ -0,0 +1,45 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.util; + +import java.nio.file.Path; +import java.util.function.Predicate; + +/** + * @since 1.11 + */ +class ClasspathFilters { + + static final String CLASS_FILE_SUFFIX = ".class"; + private static final String PACKAGE_INFO_FILE_NAME = "package-info" + CLASS_FILE_SUFFIX; + private static final String MODULE_INFO_FILE_NAME = "module-info" + CLASS_FILE_SUFFIX; + + static Predicate classFiles() { + return file -> isNotPackageInfo(file) && isNotModuleInfo(file) && isClassFile(file); + } + + static Predicate resourceFiles() { + return file -> !isClassFile(file); + } + + private static boolean isNotPackageInfo(Path path) { + return !path.endsWith(PACKAGE_INFO_FILE_NAME); + } + + private static boolean isNotModuleInfo(Path path) { + return !path.endsWith(MODULE_INFO_FILE_NAME); + } + + private static boolean isClassFile(Path file) { + return file.getFileName().toString().endsWith(CLASS_FILE_SUFFIX); + } + +} diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java index a8cd067bd32c..24ae9ed6e59b 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java @@ -14,13 +14,12 @@ import static java.util.Collections.emptyList; import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toList; -import static org.junit.platform.commons.util.ClassFileVisitor.CLASS_FILE_SUFFIX; +import static org.junit.platform.commons.util.ClasspathFilters.CLASS_FILE_SUFFIX; import static org.junit.platform.commons.util.StringUtils.isNotBlank; import java.io.IOException; import java.net.URI; import java.net.URL; -import java.nio.file.FileVisitor; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -29,9 +28,10 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Set; +import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Consumer; -import java.util.function.Function; +import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Stream; @@ -127,8 +127,11 @@ private List> findClassesForUris(List baseUris, String basePackage private List> findClassesForUri(URI baseUri, String basePackageName, ClassFilter classFilter) { List> classes = new ArrayList<>(); - walkFilesForUri(baseUri, baseDir -> new ClassFileVisitor( - classFile -> processClassFileSafely(baseDir, basePackageName, classFilter, classFile, classes::add))); + // @formatter:off + walkFilesForUri(baseUri, ClasspathFilters.classFiles(), + (baseDir, file) -> + processClassFileSafely(baseDir, basePackageName, classFilter, file, classes::add)); + // @formatter:on return classes; } @@ -148,17 +151,20 @@ private List findResourcesForUris(List baseUris, String basePacka private List findResourcesForUri(URI baseUri, String basePackageName, ResourceFilter resourceFilter) { List resources = new ArrayList<>(); - walkFilesForUri(baseUri, baseDir -> new ResourceFileVisitor(resourceFile -> processResourceFileSafely(baseDir, - basePackageName, resourceFilter, resourceFile, resources::add))); + // @formatter:off + walkFilesForUri(baseUri, ClasspathFilters.resourceFiles(), + (baseDir, file) -> + processResourceFileSafely(baseDir, basePackageName, resourceFilter, file, resources::add)); + // @formatter:on return resources; } - private static void walkFilesForUri(URI baseUri, Function> visitorConstructor) { + private static void walkFilesForUri(URI baseUri, Predicate filter, BiConsumer consumer) { try (CloseablePath closeablePath = CloseablePath.create(baseUri)) { Path baseDir = closeablePath.getPath(); Preconditions.condition(Files.exists(baseDir), () -> "baseDir must exist: " + baseDir); try { - Files.walkFileTree(baseDir, visitorConstructor.apply(baseDir)); + Files.walkFileTree(baseDir, new ClasspathFileVisitor(baseDir, filter, consumer)); } catch (IOException ex) { logger.warn(ex, () -> "I/O error scanning files in " + baseDir); From c84ad5e454e3462839bfbadf6e13eafd545167dd Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Thu, 7 Mar 2024 22:58:55 +0100 Subject: [PATCH 10/78] Docs --- .../junit/platform/commons/util/ClasspathResource.java | 3 +++ .../org/junit/platform/commons/util/ModuleUtils.java | 9 +++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathResource.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathResource.java index 1c426906f63f..720c5166c297 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathResource.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathResource.java @@ -15,6 +15,9 @@ import org.junit.platform.commons.support.Resource; +/** + * @since 1.11 + */ class ClasspathResource implements Resource { private final String name; diff --git a/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java b/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java index 3747026e8353..137c76ec3ddc 100644 --- a/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java +++ b/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java @@ -197,7 +197,9 @@ private static List scan(Set references, ResourceFilt } /** - * {@link ModuleReference} scanner. + * {@link ModuleReference} class scanner. + * + * @since 1.1 */ static class ModuleReferenceClassScanner { @@ -256,8 +258,11 @@ private Class loadClassUnchecked(String binaryName) { } } + /** - * {@link ModuleReference} scanner. + * {@link ModuleReference} resource class scanner. + * + * @since 1.11 */ static class ModuleReferenceResourceScanner { From e43258e2aa1a6ab1dd53dbe6fbed825e593ec7fc Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Thu, 7 Mar 2024 23:36:47 +0100 Subject: [PATCH 11/78] Tests --- .../commons/util/ClasspathScannerTests.java | 58 +++++++++++++++++- .../jar test with spaces.jar | Bin 2550 -> 3368 bytes 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java index a127ec867635..1ff431f578c8 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java @@ -132,6 +132,26 @@ private void assertClassesScannedWhenExceptionIsThrown(Predicate> filte assertThat(classes).hasSizeGreaterThanOrEqualTo(150); } + @Test + void scanForResourcesInClasspathRootWhenGenericRuntimeExceptionOccurs(LogRecordListener listener) throws Exception { + Predicate runtimeExceptionSimulationFilter = resource -> { + if (resource.getName().equals("org/junit/platform/commons/other-example.resource")) { + throw new RuntimeException("a generic exception"); + } + return true; + }; + + assertResourcesScannedWhenExceptionIsThrown(runtimeExceptionSimulationFilter); + assertDebugMessageLogged(listener, "Failed to load .+ during classpath scanning."); + } + + private void assertResourcesScannedWhenExceptionIsThrown(Predicate filter) { + var resourceFilter = ResourceFilter.of(filter); + var resources = this.classpathScanner.scanForResourcesInClasspathRoot(getTestClasspathResourceRoot(), resourceFilter); + assertThat(resources).hasSizeGreaterThanOrEqualTo(150); + } + + private void assertDebugMessageLogged(LogRecordListener listener, String regex) { // @formatter:off assertThat(listener.stream(ClasspathScanner.class, Level.FINE) @@ -172,14 +192,40 @@ private void scanForClassesInClasspathRootWithinJarFile(String resourceName) thr var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass); var classes = classpathScanner.scanForClassesInClasspathRoot(jarfile.toURI(), allClasses); - var classNames = classes.stream().map(Class::getName).collect(Collectors.toList()); - assertThat(classNames).hasSize(3) // - .contains("org.junit.platform.jartest.notincluded.NotIncluded", + assertThat(classes).extracting(Class::getName) // + .containsExactlyInAnyOrder("org.junit.platform.jartest.notincluded.NotIncluded", "org.junit.platform.jartest.included.recursive.RecursivelyIncluded", "org.junit.platform.jartest.included.Included"); } } + @Test + void scanForResourcesInClasspathRootWithinJarFile() throws Exception { + scanForResourcesInClasspathRootWithinJarFile("/jartest.jar"); + } + + @Test + void scanForResourcesInClasspathRootWithinJarWithSpacesInPath() throws Exception { + scanForResourcesInClasspathRootWithinJarFile("/folder with spaces/jar test with spaces.jar"); + } + + private void scanForResourcesInClasspathRootWithinJarFile(String resourceName) throws Exception { + var jarfile = getClass().getResource(resourceName); + + try (var classLoader = new URLClassLoader(new URL[] { jarfile })) { + var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass); + + var resources = classpathScanner.scanForResourcesInClasspathRoot(jarfile.toURI(), allResources); + assertThat(resources).extracting(Resource::getName) // + .containsExactlyInAnyOrder("org/junit/platform/jartest/notincluded/not-included.resource", + "org/junit/platform/jartest/included/included.resource", + "org/junit/platform/jartest/included/recursive/recursively-included.resource", + // TODO: This is interesting. Would we also scan classes in META-INF/versions? + "META-INF/MANIFEST.MF" + ); + } + } + @Test void scanForClassesInPackage() { var classes = classpathScanner.scanForClassesInPackage("org.junit.platform.commons", allClasses); @@ -489,6 +535,12 @@ private URI getTestClasspathRoot() throws Exception { var location = getClass().getProtectionDomain().getCodeSource().getLocation(); return location.toURI(); } + private URI getTestClasspathResourceRoot() { + // Gradle puts classes and resources in different roots. + var defaultPackageResource = "/default-package.resource"; + var resourceUri = getClass().getResource(defaultPackageResource).toString(); + return URI.create(resourceUri.substring(0, resourceUri.length() - defaultPackageResource.length())); + } class MemberClassToBeFound { } diff --git a/platform-tests/src/test/resources/folder with spaces/jar test with spaces.jar b/platform-tests/src/test/resources/folder with spaces/jar test with spaces.jar index d470846c87451d6dee05105ce21a443842ca1cdc..02f12e1b9d4571ee99ac748a92cb1754d9acc6bc 100644 GIT binary patch delta 1072 zcmew+yh6$)z?+#xgn@yBgMlsTg9if;Fo6gl;ACK7@O2Gw)b;dp)Bkshfq|I;Rq@Yn z+<%>c3SB0KBuqT=i;-dSUv}}$*BFHuC)+bhOcr3a5CxeV68XV{za{kc8=%rMMg|7= z$%4#=oBNpAA)9S)8~3XHVE4= z$V^t`keQsv$y1+~U!t3tmz-0YlA5AdlvzL`9cQEYM~yB3oyI|6Xu-!i;-`#DyPik0uDZ=V@zO;`plwm)jK&9nS_|3 z!orjLm?eR#wHT8p2XGnz9o5XK$hZQ?)|z~tQ&@|UNsbwNjM^|r03FT108FC{TN)p- z0u9uR#F4&OA?XV(Z3TGaHr*7(^j0>obJsI+hGI!Qq?_)IV!9GLEHJzYqzha&v9f_e Pf*%NNSs56vvV(X4^$sQc delta 409 zcmZ1>^-VY=z?+#xgn@&DgMlsTg9if=;ACK7@O2Gw)b;dp)Bkshfq|JJz?+=|q=E^m z42R~4E(yHs96!Ht|8)i`bYWnaxbUwK$cm6iWGgmrV3c44D!f~o!h8>?(2)_SPjE5%Iau_l`nY^CEoRMd8A*a~nzZ_aX zxk664$!?rljAcNUK2XO(PDREYK(_kiSDY41-siDn+i`O-y?_Y5Wf2q$@MdKLx{84Z2-h<+Fc^Y)0JoG?@&Et; From c374b93fa040dde158f1cf1e54a26acf37a5e6b0 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Thu, 7 Mar 2024 23:37:12 +0100 Subject: [PATCH 12/78] Spotless --- .../commons/util/ClasspathScannerTests.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java index 1ff431f578c8..167e8115b96b 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java @@ -147,11 +147,11 @@ void scanForResourcesInClasspathRootWhenGenericRuntimeExceptionOccurs(LogRecordL private void assertResourcesScannedWhenExceptionIsThrown(Predicate filter) { var resourceFilter = ResourceFilter.of(filter); - var resources = this.classpathScanner.scanForResourcesInClasspathRoot(getTestClasspathResourceRoot(), resourceFilter); + var resources = this.classpathScanner.scanForResourcesInClasspathRoot(getTestClasspathResourceRoot(), + resourceFilter); assertThat(resources).hasSizeGreaterThanOrEqualTo(150); } - private void assertDebugMessageLogged(LogRecordListener listener, String regex) { // @formatter:off assertThat(listener.stream(ClasspathScanner.class, Level.FINE) @@ -218,11 +218,10 @@ private void scanForResourcesInClasspathRootWithinJarFile(String resourceName) t var resources = classpathScanner.scanForResourcesInClasspathRoot(jarfile.toURI(), allResources); assertThat(resources).extracting(Resource::getName) // .containsExactlyInAnyOrder("org/junit/platform/jartest/notincluded/not-included.resource", - "org/junit/platform/jartest/included/included.resource", - "org/junit/platform/jartest/included/recursive/recursively-included.resource", - // TODO: This is interesting. Would we also scan classes in META-INF/versions? - "META-INF/MANIFEST.MF" - ); + "org/junit/platform/jartest/included/included.resource", + "org/junit/platform/jartest/included/recursive/recursively-included.resource", + // TODO: This is interesting. Would we also scan classes in META-INF/versions? + "META-INF/MANIFEST.MF"); } } @@ -535,6 +534,7 @@ private URI getTestClasspathRoot() throws Exception { var location = getClass().getProtectionDomain().getCodeSource().getLocation(); return location.toURI(); } + private URI getTestClasspathResourceRoot() { // Gradle puts classes and resources in different roots. var defaultPackageResource = "/default-package.resource"; From 6cca62adc841f4badc7b2b4d9e94ffedb57c6b14 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Thu, 7 Mar 2024 23:42:23 +0100 Subject: [PATCH 13/78] Update CHANGELOG --- .../src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc index 5068eec705e0..3aa300e682f3 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc @@ -34,6 +34,7 @@ repository on GitHub. * Error messages for type mismatches in `NamespacedHierarchicalStore` now include the actual type and value in addition to the required type. +* `ReflectionUtils` now supports scanning for classpath resources. [[release-notes-5.11.0-M1-junit-jupiter]] === JUnit Jupiter From 704e584c30a58c7577104510f997cc0672b70a09 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Thu, 7 Mar 2024 23:54:21 +0100 Subject: [PATCH 14/78] Update CHANGELOG --- .../docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc index 3aa300e682f3..86ace76aa737 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc @@ -34,7 +34,7 @@ repository on GitHub. * Error messages for type mismatches in `NamespacedHierarchicalStore` now include the actual type and value in addition to the required type. -* `ReflectionUtils` now supports scanning for classpath resources. +* `ReflectionSupport` now supports scanning for classpath resources. [[release-notes-5.11.0-M1-junit-jupiter]] === JUnit Jupiter From 9cbc960209c164f11eb1b206e60a2c453232905a Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Thu, 7 Mar 2024 21:23:24 +0100 Subject: [PATCH 15/78] Resolve resource container selectors As a follow up for #3630 and #3705 this adds a `addResourceContainerSelectorResolver()` method to `EngineDiscoveryRequestResolver.Builder` analogous to `addClassContainerSelectorResolver()`. Points of note: * As classpath resources can be selected from packages, the package filter should also be applied. To make this possible the base path of a resource is rewritten to a package name prior to being filtered. * The `ClasspathResourceSelector` now has a `getClasspathResource` method. This method will lazily try to load the resource if not was not already provided when discovering resources in a container. * `selectClasspathResource(Resource)` was added to short circuit the need to resolve resources twice. And to make it possible to use this method as part of the public API, `ReflectionSupport.tryToLoadResource` was also added. --- .../commons/support/ReflectionSupport.java | 20 +++ .../commons/util/ReflectionUtils.java | 24 +++ .../discovery/ClasspathResourceSelector.java | 31 ++++ .../engine/discovery/DiscoverySelectors.java | 25 +++ .../EngineDiscoveryRequestResolver.java | 45 ++++++ .../ResourceContainerSelectorResolver.java | 88 +++++++++++ .../support/ReflectionSupportTests.java | 12 ++ .../discovery/DiscoverySelectorsTests.java | 7 +- ...ResourceContainerSelectorResolverTest.java | 147 ++++++++++++++++++ 9 files changed, 398 insertions(+), 1 deletion(-) create mode 100644 junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java create mode 100644 platform-tests/src/test/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolverTest.java diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java index dcc8dcdb1fb5..4ebad4acfacb 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java @@ -113,6 +113,26 @@ public static Try> tryToLoadClass(String name, ClassLoader classLoader) return ReflectionUtils.tryToLoadClass(name, classLoader); } + /** + * Tries to load the {@link Resource} for the supplied classpath resource name. + * + *

The name of a classpath resource must follow the semantics + * for resource paths as defined in {@link ClassLoader#getResource(String)}. + * + *

If the supplied classpath resource name is prefixed with a slash + * ({@code /}), the slash will be removed. + * + * @param classpathResourceName the name of the resource to load; never {@code null} or blank + * @return a successful {@code Try} containing the loaded class or a failed + * {@code Try} containing the exception if no such resource could be loaded; + * never {@code null} + * @since 1.11 + */ + @API(status = EXPERIMENTAL, since = "1.11") + public static Try tryToLoadResource(String classpathResourceName) { + return ReflectionUtils.tryToLoadResource(classpathResourceName); + } + /** * Find all {@linkplain Class classes} in the supplied classpath {@code root} * that match the specified {@code classFilter} and {@code classNameFilter} diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java index 7832890004f0..74cd0ecdef20 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java @@ -35,6 +35,7 @@ import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.net.URI; +import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -56,6 +57,7 @@ import org.apiguardian.api.API; import org.junit.platform.commons.JUnitException; +import org.junit.platform.commons.PreconditionViolationException; import org.junit.platform.commons.function.Try; import org.junit.platform.commons.logging.Logger; import org.junit.platform.commons.logging.LoggerFactory; @@ -848,6 +850,28 @@ public static Try> tryToLoadClass(String name, ClassLoader classLoader) }); } + /** + * Tries to load the {@link Resource} for the supplied classpath resource name. + * + *

See {@link org.junit.platform.commons.support.ReflectionSupport#tryToLoadResource(String)} + * for details. + * + * @param classpathResourceName the name of the resource to load; never {@code null} or blank + * @since 1.11 + */ + @API(status = INTERNAL, since = "1.11") + public static Try tryToLoadResource(String classpathResourceName) { + Preconditions.notBlank(classpathResourceName, "Resource name must not be null or blank"); + ClassLoader classLoader = ClassLoaderUtils.getDefaultClassLoader(); + + boolean startsWithSlash = classpathResourceName.startsWith("/"); + URL resource = classLoader.getResource(startsWithSlash ? "/" + classpathResourceName : classpathResourceName); + if (resource == null) { + return Try.failure(new PreconditionViolationException("classLoader.getResource returned null")); + } + return Try.call(() -> new ClasspathResource(classpathResourceName, resource.toURI())); + } + private static Class loadArrayType(ClassLoader classLoader, String componentTypeName, int dimensions) throws ClassNotFoundException { diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java index 8f50e0f2284e..657894ae3aff 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java @@ -10,12 +10,17 @@ package org.junit.platform.engine.discovery; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; import static org.apiguardian.api.API.Status.STABLE; import java.util.Objects; import java.util.Optional; import org.apiguardian.api.API; +import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.commons.function.Try; +import org.junit.platform.commons.support.Resource; +import org.junit.platform.commons.util.ReflectionUtils; import org.junit.platform.commons.util.ToStringBuilder; import org.junit.platform.engine.DiscoverySelector; @@ -41,6 +46,7 @@ public class ClasspathResourceSelector implements DiscoverySelector { private final String classpathResourceName; private final FilePosition position; + private Resource classpathResource; ClasspathResourceSelector(String classpathResourceName, FilePosition position) { boolean startsWithSlash = classpathResourceName.startsWith("/"); @@ -48,6 +54,11 @@ public class ClasspathResourceSelector implements DiscoverySelector { this.position = position; } + ClasspathResourceSelector(Resource classpathResource) { + this(classpathResource.getName(), null); + this.classpathResource = classpathResource; + } + /** * Get the name of the selected classpath resource. * @@ -62,6 +73,26 @@ public String getClasspathResourceName() { return this.classpathResourceName; } + /** + * Get the selected {@link Resource}. + * + *

If the {@link Resource} was not provided, but only the name, this + * method attempts to lazily load the {@link Resource} based on its name and + * throws a {@link PreconditionViolationException} if the resource cannot + * be loaded. + */ + @API(status = EXPERIMENTAL, since = "1.11") + public Resource getClasspathResource() { + if (this.classpathResource == null) { + // @formatter:off + Try tryToLoadClass = ReflectionUtils.tryToLoadResource(this.classpathResourceName); + this.classpathResource = tryToLoadClass.getOrThrow(cause -> + new PreconditionViolationException("Could not load resource with name: " + this.classpathResourceName, cause)); + // @formatter:on + } + return this.classpathResource; + } + /** * Get the selected {@code FilePosition} within the classpath resource. */ diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java index 0f3d5aefd57f..839a72b7a48f 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java @@ -26,6 +26,7 @@ import org.apiguardian.api.API; import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.commons.support.Resource; import org.junit.platform.commons.util.Preconditions; import org.junit.platform.commons.util.ReflectionUtils; import org.junit.platform.engine.DiscoverySelector; @@ -276,6 +277,7 @@ public static List selectClasspathRoots(Set classpa * @param classpathResourceName the name of the classpath resource; never * {@code null} or blank * @see #selectClasspathResource(String, FilePosition) + * @see #selectClasspathResource(Resource) * @see ClasspathResourceSelector * @see ClassLoader#getResource(String) * @see ClassLoader#getResourceAsStream(String) @@ -305,6 +307,7 @@ public static ClasspathResourceSelector selectClasspathResource(String classpath * {@code null} or blank * @param position the position inside the classpath resource; may be {@code null} * @see #selectClasspathResource(String) + * @see #selectClasspathResource(Resource) * @see ClasspathResourceSelector * @see ClassLoader#getResource(String) * @see ClassLoader#getResourceAsStream(String) @@ -316,6 +319,28 @@ public static ClasspathResourceSelector selectClasspathResource(String classpath return new ClasspathResourceSelector(classpathResourceName, position); } + /** + * Create a {@code ClasspathResourceSelector} for the supplied classpath + * resource. + * + *

Since {@linkplain org.junit.platform.engine.TestEngine engines} are not + * expected to modify the classpath, the supplied resource must be on the + * classpath of the + * {@linkplain Thread#getContextClassLoader() context class loader} of the + * {@linkplain Thread thread} that uses the resulting selector. + * + * @param classpathResource the classpath resource; never {@code null} + * @see #selectClasspathResource(String, FilePosition) + * @see #selectClasspathResource(String) + * @see ClasspathResourceSelector + * @see org.junit.platform.commons.support.ReflectionSupport#tryToLoadResource(String) + */ + @API(status = EXPERIMENTAL, since = "1.11") + public static ClasspathResourceSelector selectClasspathResource(Resource classpathResource) { + Preconditions.notNull(classpathResource, "classpath resource must not be null or blank"); + return new ClasspathResourceSelector(classpathResource); + } + /** * Create a {@code ModuleSelector} for the supplied module name. * diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/EngineDiscoveryRequestResolver.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/EngineDiscoveryRequestResolver.java index df5611990a78..31adf7e6effb 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/EngineDiscoveryRequestResolver.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/EngineDiscoveryRequestResolver.java @@ -11,6 +11,7 @@ package org.junit.platform.engine.support.discovery; import static java.util.stream.Collectors.toCollection; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; import static org.apiguardian.api.API.Status.STABLE; import java.util.ArrayList; @@ -19,6 +20,7 @@ import java.util.function.Predicate; import org.apiguardian.api.API; +import org.junit.platform.commons.support.Resource; import org.junit.platform.commons.util.Preconditions; import org.junit.platform.engine.DiscoveryFilter; import org.junit.platform.engine.EngineDiscoveryRequest; @@ -26,6 +28,7 @@ import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.discovery.ClassNameFilter; import org.junit.platform.engine.discovery.ClassSelector; +import org.junit.platform.engine.discovery.ClasspathResourceSelector; import org.junit.platform.engine.discovery.ClasspathRootSelector; import org.junit.platform.engine.discovery.ModuleSelector; import org.junit.platform.engine.discovery.PackageNameFilter; @@ -160,6 +163,24 @@ public Builder addClassContainerSelectorResolver(Predicate> classFil context -> new ClassContainerSelectorResolver(classFilter, context.getClassNameFilter())); } + /** + * Add a predefined resolver that resolves {@link ClasspathRootSelector + * ClasspathRootSelectors}, {@link ModuleSelector ModuleSelectors}, and + * {@link PackageSelector PackageSelectors} into {@link ClasspathResourceSelector + * ClasspathResourceSelectors} by scanning for resources that satisfy the supplied + * predicate in the respective class containers to this builder. + * + * @param resourceFilter predicate the resolved classes must satisfy; never + * {@code null} + * @return this builder for method chaining + */ + @API(status = EXPERIMENTAL, since = "1.11") + public Builder addResourceContainerSelectorResolver(Predicate resourceFilter) { + Preconditions.notNull(resourceFilter, "resourceFilter must not be null"); + return addSelectorResolver( + context -> new ResourceContainerSelectorResolver(resourceFilter, context.getPackageFilter())); + } + /** * Add a context insensitive {@link SelectorResolver} to this builder. * @@ -247,6 +268,17 @@ public interface InitializationContext { */ Predicate getClassNameFilter(); + /** + * Get the class package filter built from the {@link PackageNameFilter + * PackageNameFilters} in the {@link EngineDiscoveryRequest} that is + * about to be resolved. + * + * @return the predicate for filtering the resolved resource names; never + * {@code null} + */ + @API(status = EXPERIMENTAL, since = "1.11") + Predicate getPackageFilter(); + } private static class DefaultInitializationContext implements InitializationContext { @@ -254,11 +286,13 @@ private static class DefaultInitializationContext impl private final EngineDiscoveryRequest request; private final T engineDescriptor; private final Predicate classNameFilter; + private final Predicate packageFilter; DefaultInitializationContext(EngineDiscoveryRequest request, T engineDescriptor) { this.request = request; this.engineDescriptor = engineDescriptor; this.classNameFilter = buildClassNamePredicate(request); + this.packageFilter = buildPackagePredicate(request); } /** @@ -274,6 +308,12 @@ private Predicate buildClassNamePredicate(EngineDiscoveryRequest request return Filter.composeFilters(filters).toPredicate(); } + private Predicate buildPackagePredicate(EngineDiscoveryRequest request) { + List> filters = new ArrayList<>(); + filters.addAll(request.getFiltersByType(PackageNameFilter.class)); + return Filter.composeFilters(filters).toPredicate(); + } + @Override public EngineDiscoveryRequest getDiscoveryRequest() { return request; @@ -288,6 +328,11 @@ public T getEngineDescriptor() { public Predicate getClassNameFilter() { return classNameFilter; } + + @Override + public Predicate getPackageFilter() { + return packageFilter; + } } } diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java new file mode 100644 index 000000000000..fe485e220758 --- /dev/null +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java @@ -0,0 +1,88 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.engine.support.discovery; + +import static java.util.stream.Collectors.toSet; +import static org.junit.platform.commons.support.ReflectionSupport.findAllResourcesInClasspathRoot; +import static org.junit.platform.commons.support.ReflectionSupport.findAllResourcesInPackage; +import static org.junit.platform.commons.util.ReflectionUtils.findAllResourcesInModule; +import static org.junit.platform.engine.support.discovery.SelectorResolver.Resolution.selectors; +import static org.junit.platform.engine.support.discovery.SelectorResolver.Resolution.unresolved; + +import java.util.List; +import java.util.function.Predicate; + +import org.junit.platform.commons.support.Resource; +import org.junit.platform.engine.discovery.ClasspathRootSelector; +import org.junit.platform.engine.discovery.DiscoverySelectors; +import org.junit.platform.engine.discovery.ModuleSelector; +import org.junit.platform.engine.discovery.PackageSelector; + +/** + * @since 1.11 + */ +class ResourceContainerSelectorResolver implements SelectorResolver { + private static final char CLASSPATH_RESOURCE_PATH_SEPARATOR = '/'; + private static final char PACKAGE_SEPARATOR_CHAR = '.'; + public static final String DEFAULT_PACKAGE_NAME = ""; + private final Predicate resourceFilter; + private final Predicate resourcePackageFilter; + + ResourceContainerSelectorResolver(Predicate resourceFilter, Predicate resourcePackageFilter) { + this.resourceFilter = resourceFilter; + this.resourcePackageFilter = adaptPackageFilter(resourcePackageFilter); + } + + /** + * A package filter is written to test {@code .} separated package names. + * Resources however have {@code /} separated paths. By rewriting the path + * of the resource into a package name, we can make the package filter work. + */ + private static Predicate adaptPackageFilter(Predicate packageFilter) { + return classpathResourceName -> packageFilter.test(packageName(classpathResourceName)); + } + + private static String packageName(String classpathResourceName) { + int lastIndexOf = classpathResourceName.lastIndexOf(CLASSPATH_RESOURCE_PATH_SEPARATOR); + if (lastIndexOf < 0) { + return DEFAULT_PACKAGE_NAME; + } + // classpath resource names do not start with / + String resourcePackagePath = classpathResourceName.substring(0, lastIndexOf); + return resourcePackagePath.replace(CLASSPATH_RESOURCE_PATH_SEPARATOR, PACKAGE_SEPARATOR_CHAR); + } + + @Override + public Resolution resolve(ClasspathRootSelector selector, Context context) { + return resourceSelectors( + findAllResourcesInClasspathRoot(selector.getClasspathRoot(), resourceFilter, resourcePackageFilter)); + } + + @Override + public Resolution resolve(ModuleSelector selector, Context context) { + return resourceSelectors( + findAllResourcesInModule(selector.getModuleName(), resourceFilter, resourcePackageFilter)); + } + + @Override + public Resolution resolve(PackageSelector selector, Context context) { + return resourceSelectors( + findAllResourcesInPackage(selector.getPackageName(), resourceFilter, resourcePackageFilter)); + } + + private Resolution resourceSelectors(List resources) { + if (resources.isEmpty()) { + return unresolved(); + } + return selectors(resources.stream().map(DiscoverySelectors::selectClasspathResource).collect(toSet())); + } + +} diff --git a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java index 94c883c81d73..da719e75afb1 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java @@ -122,6 +122,18 @@ List findAllClassesInClasspathRootDelegates() throws Throwable { return tests; } + @Test + void tryToLoadResourcePreconditions() { + assertPreconditionViolationExceptionForString("Resource name", () -> ReflectionSupport.tryToLoadResource(null)); + assertPreconditionViolationExceptionForString("Resource name", () -> ReflectionSupport.tryToLoadResource("")); + } + + @Test + void tryToLoadResourceDelegates() { + assertEquals(ReflectionUtils.tryToLoadResource("default-package.resource").toOptional(), + ReflectionSupport.tryToLoadResource("default-package.resource").toOptional()); + } + @Test void findAllClassesInClasspathRootPreconditions() { var path = Path.of(".").toUri(); diff --git a/platform-tests/src/test/java/org/junit/platform/engine/discovery/DiscoverySelectorsTests.java b/platform-tests/src/test/java/org/junit/platform/engine/discovery/DiscoverySelectorsTests.java index 2954fb3577e2..9c116525eb96 100644 --- a/platform-tests/src/test/java/org/junit/platform/engine/discovery/DiscoverySelectorsTests.java +++ b/platform-tests/src/test/java/org/junit/platform/engine/discovery/DiscoverySelectorsTests.java @@ -47,6 +47,7 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.commons.support.Resource; import org.junit.platform.commons.test.TestClassLoader; import org.junit.platform.commons.util.ReflectionUtils; @@ -191,10 +192,11 @@ class SelectClasspathResourceTests { @Test void selectClasspathResources() { - assertViolatesPrecondition(() -> selectClasspathResource(null)); + assertViolatesPrecondition(() -> selectClasspathResource((String) null)); assertViolatesPrecondition(() -> selectClasspathResource("")); assertViolatesPrecondition(() -> selectClasspathResource(" ")); assertViolatesPrecondition(() -> selectClasspathResource("\t")); + assertViolatesPrecondition(() -> selectClasspathResource((Resource) null)); // with unnecessary "/" prefix var selector = selectClasspathResource("/foo/bar/spec.xml"); @@ -203,6 +205,9 @@ void selectClasspathResources() { // standard use case selector = selectClasspathResource("A/B/C/spec.json"); assertEquals("A/B/C/spec.json", selector.getClasspathResourceName()); + + selector = selectClasspathResource("org/junit/platform/commons/example.resource"); + assertEquals("org/junit/platform/commons/example.resource", selector.getClasspathResource().getName()); } @Test diff --git a/platform-tests/src/test/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolverTest.java b/platform-tests/src/test/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolverTest.java new file mode 100644 index 000000000000..cb4682b02a8c --- /dev/null +++ b/platform-tests/src/test/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolverTest.java @@ -0,0 +1,147 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.engine.support.discovery; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClasspathRoots; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectPackage; +import static org.junit.platform.engine.discovery.PackageNameFilter.includePackageNames; +import static org.junit.platform.engine.support.discovery.SelectorResolver.Match.exact; +import static org.junit.platform.engine.support.discovery.SelectorResolver.Resolution.match; + +import java.net.URI; +import java.nio.file.Path; +import java.util.Collections; +import java.util.Optional; +import java.util.Set; +import java.util.function.Predicate; + +import org.junit.jupiter.api.Test; +import org.junit.platform.commons.support.Resource; +import org.junit.platform.engine.TestDescriptor; +import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.discovery.ClasspathResourceSelector; +import org.junit.platform.engine.support.descriptor.EngineDescriptor; +import org.junit.platform.fakes.TestDescriptorStub; +import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder; + +class ResourceContainerSelectorResolverTest { + + final TestDescriptor engineDescriptor = new EngineDescriptor(UniqueId.forEngine("resource-engine"), + "Resource Engine"); + final Predicate isResource = resource -> resource.getName().endsWith(".resource"); + // @formatter:off + final EngineDiscoveryRequestResolver resolver = EngineDiscoveryRequestResolver.builder() + .addResourceContainerSelectorResolver(isResource) + .addSelectorResolver(new ResourceSelectorResolver()) + .build(); + // @formatter:on + + @Test + void shouldDiscoverAllResourcesInPackage() { + var request = LauncherDiscoveryRequestBuilder.request() // + .selectors(selectPackage("org.junit.platform.commons")) // + .build(); + + resolver.resolve(request, engineDescriptor); + + // @formatter:off + assertThat(engineDescriptor.getChildren()) + .extracting(TestDescriptor::getDisplayName) + .containsExactlyInAnyOrder( + "org/junit/platform/commons/example.resource", + "org/junit/platform/commons/other-example.resource"); + // @formatter:on + + } + + @Test + void shouldDiscoverAllResourcesInRootPackage() { + var request = LauncherDiscoveryRequestBuilder.request() // + .selectors(selectPackage("")) // + .build(); + + resolver.resolve(request, engineDescriptor); + + // @formatter:off + assertThat(engineDescriptor.getChildren()) + .extracting(TestDescriptor::getDisplayName) + .containsExactlyInAnyOrder( + "default-package.resource", + "org/junit/platform/commons/example.resource", + "org/junit/platform/commons/other-example.resource"); + // @formatter:on + + } + + @Test + void shouldFilterPackages() { + var request = LauncherDiscoveryRequestBuilder.request() // + .selectors(selectPackage("")) // + .filters(includePackageNames("org.junit.platform")) // + .build(); + + resolver.resolve(request, engineDescriptor); + + // @formatter:off + assertThat(engineDescriptor.getChildren()) + .extracting(TestDescriptor::getDisplayName) + .containsExactlyInAnyOrder( + "org/junit/platform/commons/example.resource", + "org/junit/platform/commons/other-example.resource"); + // @formatter:on + + } + + @Test + void shouldDiscoverAllResourcesInClasspathRoot() { + var request = LauncherDiscoveryRequestBuilder.request() // + .selectors(selectClasspathRoots(getTestClasspathResourceRoot())) // + .build(); + + resolver.resolve(request, engineDescriptor); + + // @formatter:off + assertThat(engineDescriptor.getChildren()) + .extracting(TestDescriptor::getDisplayName) + .containsExactlyInAnyOrder( + "default-package.resource", + "org/junit/platform/commons/example.resource", + "org/junit/platform/commons/other-example.resource"); + // @formatter:on + } + + private Set getTestClasspathResourceRoot() { + // Gradle puts classes and resources in different roots. + var defaultPackageResource = "/default-package.resource"; + var resourceUri = getClass().getResource(defaultPackageResource).toString(); + var uri = URI.create(resourceUri.substring(0, resourceUri.length() - defaultPackageResource.length())); + return Collections.singleton(Path.of(uri)); + } + + private static class ResourceSelectorResolver implements SelectorResolver { + @Override + public Resolution resolve(ClasspathResourceSelector selector, Context context) { + // @formatter:off + return context.addToParent(parent -> createTestDescriptor(parent, selector.getClasspathResourceName())) + .map(testDescriptor -> match(exact(testDescriptor))) + .orElseGet(Resolution::unresolved); + // @formatter:on + } + + private static Optional createTestDescriptor(TestDescriptor parent, + String classpathResourceName) { + var uniqueId = parent.getUniqueId().append("resource", classpathResourceName); + var descriptor = new TestDescriptorStub(uniqueId, classpathResourceName); + return Optional.of(descriptor); + } + } +} From ee72ba65e5841df82024ece246a3d37ab42c6ea8 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Thu, 13 Jun 2024 18:55:13 +0200 Subject: [PATCH 16/78] Remove resource package filter predicate --- .../commons/support/ReflectionSupport.java | 66 +++++++------------ .../platform/commons/support/Resource.java | 12 ++-- .../commons/util/ClasspathScanner.java | 10 ++- .../commons/util/ReflectionUtils.java | 43 ++++++------ .../platform/commons/util/ResourceFilter.java | 30 ++------- .../platform/commons/util/ModuleUtils.java | 1 - .../ResourceContainerSelectorResolver.java | 18 ++--- .../support/ReflectionSupportTests.java | 32 ++++----- 8 files changed, 77 insertions(+), 135 deletions(-) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java index 4ebad4acfacb..c9e41ccc0f8c 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java @@ -167,17 +167,14 @@ public static List> findAllClassesInClasspathRoot(URI root, Predicate findAllResourcesInClasspathRoot(URI root, Predicate resourceFilter, - Predicate resourceNameFilter) { - - return ReflectionUtils.findAllResourcesInClasspathRoot(root, resourceFilter, resourceNameFilter); + public static List findAllResourcesInClasspathRoot(URI root, Predicate resourceFilter) { + return ReflectionUtils.findAllResourcesInClasspathRoot(root, resourceFilter); } /** @@ -216,18 +213,15 @@ public static Stream> streamAllClassesInClasspathRoot(URI root, Predica * @param root the URI for the classpath root in which to scan; never * {@code null} * @param resourceFilter the resource type filter; never {@code null} - * @param resourceNameFilter the resources name filter; never {@code null} * @return a stream of all such classes found; never {@code null} * but potentially empty * @since 1.10 - * @see #streamAllResourcesInPackage(String, Predicate, Predicate) - * @see #streamAllResourcesInModule(String, Predicate, Predicate) + * @see #streamAllResourcesInPackage(String, Predicate) + * @see #streamAllResourcesInModule(String, Predicate) */ @API(status = EXPERIMENTAL, since = "1.11") - public static Stream streamAllResourcesInClasspathRoot(URI root, Predicate resourceFilter, - Predicate resourceNameFilter) { - - return ReflectionUtils.streamAllResourcesInClasspathRoot(root, resourceFilter, resourceNameFilter); + public static Stream streamAllResourcesInClasspathRoot(URI root, Predicate resourceFilter) { + return ReflectionUtils.streamAllResourcesInClasspathRoot(root, resourceFilter); } /** @@ -250,7 +244,6 @@ public static Stream streamAllResourcesInClasspathRoot(URI root, Predi */ public static List> findAllClassesInPackage(String basePackageName, Predicate> classFilter, Predicate classNameFilter) { - return ReflectionUtils.findAllClassesInPackage(basePackageName, classFilter, classNameFilter); } @@ -266,17 +259,14 @@ public static List> findAllClassesInPackage(String basePackageName, Pre * scanning; must not be {@code null} and must be valid in terms of Java * syntax * @param resourceFilter the resource type filter; never {@code null} - * @param resourceNameFilter the resource name filter; never {@code null} * @return an immutable list of all such classes found; never {@code null} * but potentially empty - * @see #findAllResourcesInClasspathRoot(URI, Predicate, Predicate) - * @see #findAllResourcesInModule(String, Predicate, Predicate) + * @see #findAllResourcesInClasspathRoot(URI, Predicate) + * @see #findAllResourcesInModule(String, Predicate) */ @API(status = EXPERIMENTAL, since = "1.11") - public static List findAllResourcesInPackage(String basePackageName, Predicate resourceFilter, - Predicate resourceNameFilter) { - - return ReflectionUtils.findAllResourcesInPackage(basePackageName, resourceFilter, resourceNameFilter); + public static List findAllResourcesInPackage(String basePackageName, Predicate resourceFilter) { + return ReflectionUtils.findAllResourcesInPackage(basePackageName, resourceFilter); } /** @@ -317,18 +307,16 @@ public static Stream> streamAllClassesInPackage(String basePackageName, * scanning; must not be {@code null} and must be valid in terms of Java * syntax * @param resourceFilter the resource type filter; never {@code null} - * @param resourceNameFilter the resource name filter; never {@code null} * @return a stream of all such resources found; never {@code null} * but potentially empty * @since 1.10 - * @see #streamAllResourcesInClasspathRoot(URI, Predicate, Predicate) - * @see #streamAllResourcesInModule(String, Predicate, Predicate) + * @see #streamAllResourcesInClasspathRoot(URI, Predicate) + * @see #streamAllResourcesInModule(String, Predicate) */ @API(status = EXPERIMENTAL, since = "1.11") public static Stream streamAllResourcesInPackage(String basePackageName, - Predicate resourceFilter, Predicate resourceNameFilter) { - - return ReflectionUtils.streamAllResourcesInPackage(basePackageName, resourceFilter, resourceNameFilter); + Predicate resourceFilter) { + return ReflectionUtils.streamAllResourcesInPackage(basePackageName, resourceFilter); } /** @@ -366,18 +354,15 @@ public static List> findAllClassesInModule(String moduleName, Predicate * @param moduleName the name of the module to scan; never {@code null} or * empty * @param resourceFilter the resource type filter; never {@code null} - * @param resourceNameFilter the resource name filter; never {@code null} * @return an immutable list of all such resources found; never {@code null} * but potentially empty * @since 1.1.1 - * @see #findAllResourcesInClasspathRoot(URI, Predicate, Predicate) - * @see #findAllResourcesInPackage(String, Predicate, Predicate) + * @see #findAllResourcesInClasspathRoot(URI, Predicate) + * @see #findAllResourcesInPackage(String, Predicate) */ @API(status = EXPERIMENTAL, since = "1.11") - public static List findAllResourcesInModule(String moduleName, Predicate resourceFilter, - Predicate resourceNameFilter) { - - return ReflectionUtils.findAllResourcesInModule(moduleName, resourceFilter, resourceNameFilter); + public static List findAllResourcesInModule(String moduleName, Predicate resourceFilter) { + return ReflectionUtils.findAllResourcesInModule(moduleName, resourceFilter); } /** @@ -416,18 +401,15 @@ public static Stream> streamAllClassesInModule(String moduleName, Predi * @param moduleName the name of the module to scan; never {@code null} or * empty * @param resourceFilter the resource type filter; never {@code null} - * @param resourceNameFilter the resource name filter; never {@code null} * @return a stream of all such resources found; never {@code null} * but potentially empty * @since 1.10 - * @see #streamAllResourcesInClasspathRoot(URI, Predicate, Predicate) - * @see #streamAllResourcesInPackage(String, Predicate, Predicate) + * @see #streamAllResourcesInClasspathRoot(URI, Predicate) + * @see #streamAllResourcesInPackage(String, Predicate) */ @API(status = EXPERIMENTAL, since = "1.11") - public static Stream streamAllResourcesInModule(String moduleName, Predicate resourceFilter, - Predicate resourceNameFilter) { - - return ReflectionUtils.streamAllResourcesInModule(moduleName, resourceFilter, resourceNameFilter); + public static Stream streamAllResourcesInModule(String moduleName, Predicate resourceFilter) { + return ReflectionUtils.streamAllResourcesInModule(moduleName, resourceFilter); } /** diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/Resource.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/Resource.java index fc90e7427d6c..78c48e4cd608 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/Resource.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/Resource.java @@ -22,12 +22,12 @@ /** * Represents a resource on the classpath. * - * @see ReflectionSupport#findAllResourcesInClasspathRoot(URI, Predicate, Predicate) - * @see ReflectionSupport#findAllResourcesInPackage(String, Predicate, Predicate) - * @see ReflectionSupport#findAllResourcesInModule(String, Predicate, Predicate) - * @see ReflectionSupport#streamAllResourcesInClasspathRoot(URI, Predicate, Predicate) - * @see ReflectionSupport#streamAllResourcesInPackage(String, Predicate, Predicate) - * @see ReflectionSupport#streamAllResourcesInModule(String, Predicate, Predicate) + * @see ReflectionSupport#findAllResourcesInClasspathRoot(URI, Predicate) + * @see ReflectionSupport#findAllResourcesInPackage(String, Predicate) + * @see ReflectionSupport#findAllResourcesInModule(String, Predicate) + * @see ReflectionSupport#streamAllResourcesInClasspathRoot(URI, Predicate) + * @see ReflectionSupport#streamAllResourcesInPackage(String, Predicate) + * @see ReflectionSupport#streamAllResourcesInModule(String, Predicate) */ @API(status = EXPERIMENTAL, since = "1.11") public interface Resource { diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java index 24ae9ed6e59b..0940ca5f7d5f 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java @@ -207,12 +207,10 @@ private void processResourceFileSafely(Path baseDir, String basePackageName, Res try { String fullyQualifiedResourceName = determineFullyQualifiedResourceName(baseDir, basePackageName, resourceFile); - if (resourceFilter.match(fullyQualifiedResourceName)) { - Resource resource = new ClasspathResource(fullyQualifiedResourceName, resourceFile.toUri()); - // Always use "resourceFilter.test" to include future predicates. - if (resourceFilter.test(resource)) { - resourceConsumer.accept(resource); - } + Resource resource = new ClasspathResource(fullyQualifiedResourceName, resourceFile.toUri()); + // Always use "resourceFilter.test" to include future predicates. + if (resourceFilter.test(resource)) { + resourceConsumer.accept(resource); } } catch (Throwable throwable) { diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java index 74cd0ecdef20..d8b0d3453c7c 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java @@ -988,12 +988,11 @@ public static List> findAllClassesInClasspathRoot(URI root, Predicate findAllResourcesInClasspathRoot(URI root, Predicate resourceFilter, - Predicate resourceNameFilter) { + public static List findAllResourcesInClasspathRoot(URI root, Predicate resourceFilter) { // unmodifiable since returned by public, non-internal method(s) - return findAllResourcesInClasspathRoot(root, ResourceFilter.of(resourceNameFilter, resourceFilter)); + return findAllResourcesInClasspathRoot(root, ResourceFilter.of(resourceFilter)); } /** @@ -1007,11 +1006,10 @@ public static Stream> streamAllClassesInClasspathRoot(URI root, Predica /** * @since 1.11 - * @see org.junit.platform.commons.support.ReflectionSupport#streamAllResourcesInClasspathRoot(URI, Predicate, Predicate) + * @see #streamAllResourcesInClasspathRoot(URI, Predicate) */ - public static Stream streamAllResourcesInClasspathRoot(URI root, Predicate resourceFilter, - Predicate resourceNameFilter) { - return streamAllResourcesInClasspathRoot(root, ResourceFilter.of(resourceNameFilter, resourceFilter)); + public static Stream streamAllResourcesInClasspathRoot(URI root, Predicate resourceFilter) { + return streamAllResourcesInClasspathRoot(root, ResourceFilter.of(resourceFilter)); } /** @@ -1024,8 +1022,8 @@ public static List> findAllClassesInClasspathRoot(URI root, ClassFilter /** * @since 1.11 */ - public static List findAllResourcesInClasspathRoot(URI root, ResourceFilter classFilter) { - return Collections.unmodifiableList(classpathScanner.scanForResourcesInClasspathRoot(root, classFilter)); + public static List findAllResourcesInClasspathRoot(URI root, ResourceFilter resourceFilter) { + return Collections.unmodifiableList(classpathScanner.scanForResourcesInClasspathRoot(root, resourceFilter)); } /** @@ -1055,10 +1053,9 @@ public static List> findAllClassesInPackage(String basePackageName, Pre * @since 1.11 * @see org.junit.platform.commons.support.ReflectionSupport#findAllClassesInPackage(String, Predicate, Predicate) */ - public static List findAllResourcesInPackage(String basePackageName, Predicate resourceFilter, - Predicate resourceNameFilter) { + public static List findAllResourcesInPackage(String basePackageName, Predicate resourceFilter) { // unmodifiable since returned by public, non-internal method(s) - return findAllResourcesInPackage(basePackageName, ResourceFilter.of(resourceNameFilter, resourceFilter)); + return findAllResourcesInPackage(basePackageName, ResourceFilter.of(resourceFilter)); } /** @@ -1072,11 +1069,11 @@ public static Stream> streamAllClassesInPackage(String basePackageName, /** * since 1.11 - * @see org.junit.platform.commons.support.ReflectionSupport#streamAllResourcesInPackage(String, Predicate, Predicate) + * @see #streamAllResourcesInPackage(String, Predicate) */ public static Stream streamAllResourcesInPackage(String basePackageName, - Predicate resourceFilter, Predicate resourceNameFilter) { - return streamAllResourcesInPackage(basePackageName, ResourceFilter.of(resourceNameFilter, resourceFilter)); + Predicate resourceFilter) { + return streamAllResourcesInPackage(basePackageName, ResourceFilter.of(resourceFilter)); } /** @@ -1120,12 +1117,11 @@ public static List> findAllClassesInModule(String moduleName, Predicate /** * @since 1.11 - * @see org.junit.platform.commons.support.ReflectionSupport#findAllResourcesInModule(String, Predicate, Predicate) + * @see #findAllResourcesInModule(String, Predicate) */ - public static List findAllResourcesInModule(String moduleName, Predicate resourceFilter, - Predicate resourceNameFilter) { + public static List findAllResourcesInModule(String moduleName, Predicate resourceFilter) { // unmodifiable since returned by public, non-internal method(s) - return findAllResourcesInModule(moduleName, ResourceFilter.of(resourceNameFilter, resourceFilter)); + return findAllResourcesInModule(moduleName, ResourceFilter.of(resourceFilter)); } /** @@ -1139,11 +1135,10 @@ public static Stream> streamAllClassesInModule(String moduleName, Predi /** * @since 1.11 - * @see org.junit.platform.commons.support.ReflectionSupport#streamAllResourcesInModule(String, Predicate, Predicate) + * @see #streamAllResourcesInModule(String, Predicate) */ - public static Stream streamAllResourcesInModule(String moduleName, Predicate resourceFilter, - Predicate resourceNameFilter) { - return streamAllResourcesInModule(moduleName, ResourceFilter.of(resourceNameFilter, resourceFilter)); + public static Stream streamAllResourcesInModule(String moduleName, Predicate resourceFilter) { + return streamAllResourcesInModule(moduleName, ResourceFilter.of(resourceFilter)); } /** diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java index bde54890c85e..ac2775ff876f 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java @@ -32,42 +32,20 @@ public class ResourceFilter implements Predicate { /** - * Create a {@link ResourceFilter} instance that accepts all names but filters resources. + * Create a {@link ResourceFilter} instance that filters resources. */ public static ResourceFilter of(Predicate resourcePredicate) { - return of(name -> true, resourcePredicate); + return new ResourceFilter(resourcePredicate); } - /** - * Create a {@link ResourceFilter} instance that filters by resource names and resources. - */ - public static ResourceFilter of(Predicate namePredicate, Predicate resourcePredicate) { - return new ResourceFilter(namePredicate, resourcePredicate); - } - - private final Predicate namePredicate; private final Predicate resourcePredicate; - private ResourceFilter(Predicate namePredicate, Predicate resourcePredicate) { - this.namePredicate = Preconditions.notNull(namePredicate, "name predicate must not be null"); + private ResourceFilter(Predicate resourcePredicate) { this.resourcePredicate = Preconditions.notNull(resourcePredicate, "resource predicate must not be null"); } - public boolean match(String name) { - return namePredicate.test(name); - } - - public boolean match(Resource resource) { - return resourcePredicate.test(resource); - } - - /** - * @implNote This implementation combines all tests stored in the predicates - * of this instance. Any new predicate must be added to this test method as - * well. - */ @Override public boolean test(Resource resource) { - return match(resource.getName()) && match(resource); + return resourcePredicate.test(resource); } } diff --git a/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java b/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java index 137c76ec3ddc..fbbe0882165f 100644 --- a/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java +++ b/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java @@ -282,7 +282,6 @@ List scan(ModuleReference reference) { try (Stream names = reader.list()) { // @formatter:off return names.filter(name -> !name.endsWith(".class")) - .filter(resourceFilter::match) .map(this::loadResourceUnchecked) // Always use ".filter(resourceFilter)" to include future predicates. .filter(resourceFilter) diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java index fe485e220758..4b22280ae195 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java @@ -34,11 +34,10 @@ class ResourceContainerSelectorResolver implements SelectorResolver { private static final char PACKAGE_SEPARATOR_CHAR = '.'; public static final String DEFAULT_PACKAGE_NAME = ""; private final Predicate resourceFilter; - private final Predicate resourcePackageFilter; ResourceContainerSelectorResolver(Predicate resourceFilter, Predicate resourcePackageFilter) { - this.resourceFilter = resourceFilter; - this.resourcePackageFilter = adaptPackageFilter(resourcePackageFilter); + Predicate packageFilter = adaptPackageFilter(resourcePackageFilter); + this.resourceFilter = packageFilter.and(resourceFilter); } /** @@ -46,8 +45,8 @@ class ResourceContainerSelectorResolver implements SelectorResolver { * Resources however have {@code /} separated paths. By rewriting the path * of the resource into a package name, we can make the package filter work. */ - private static Predicate adaptPackageFilter(Predicate packageFilter) { - return classpathResourceName -> packageFilter.test(packageName(classpathResourceName)); + private static Predicate adaptPackageFilter(Predicate packageFilter) { + return resource -> packageFilter.test(packageName(resource.getName())); } private static String packageName(String classpathResourceName) { @@ -62,20 +61,17 @@ private static String packageName(String classpathResourceName) { @Override public Resolution resolve(ClasspathRootSelector selector, Context context) { - return resourceSelectors( - findAllResourcesInClasspathRoot(selector.getClasspathRoot(), resourceFilter, resourcePackageFilter)); + return resourceSelectors(findAllResourcesInClasspathRoot(selector.getClasspathRoot(), resourceFilter)); } @Override public Resolution resolve(ModuleSelector selector, Context context) { - return resourceSelectors( - findAllResourcesInModule(selector.getModuleName(), resourceFilter, resourcePackageFilter)); + return resourceSelectors(findAllResourcesInModule(selector.getModuleName(), resourceFilter)); } @Override public Resolution resolve(PackageSelector selector, Context context) { - return resourceSelectors( - findAllResourcesInPackage(selector.getPackageName(), resourceFilter, resourcePackageFilter)); + return resourceSelectors(findAllResourcesInPackage(selector.getPackageName(), resourceFilter)); } private Resolution resourceSelectors(List resources) { diff --git a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java index da719e75afb1..a8be97c4d596 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java @@ -158,8 +158,8 @@ List findAllResourcesInClasspathRootDelegates() throws Throwable { displayName = "..." + displayName.substring(displayName.length() - 42); } tests.add(DynamicTest.dynamicTest(displayName, - () -> assertEquals(ReflectionUtils.findAllResourcesInClasspathRoot(root, allResources, allNames), - ReflectionSupport.findAllResourcesInClasspathRoot(root, allResources, allNames)))); + () -> assertEquals(ReflectionUtils.findAllResourcesInClasspathRoot(root, allResources), + ReflectionSupport.findAllResourcesInClasspathRoot(root, allResources)))); } return tests; } @@ -168,11 +168,9 @@ List findAllResourcesInClasspathRootDelegates() throws Throwable { void findAllResourcesInClasspathRootPreconditions() { var path = Path.of(".").toUri(); assertPreconditionViolationException("root", - () -> ReflectionSupport.findAllResourcesInClasspathRoot(null, allResources, allNames)); + () -> ReflectionSupport.findAllResourcesInClasspathRoot(null, allResources)); assertPreconditionViolationException("resource predicate", - () -> ReflectionSupport.findAllResourcesInClasspathRoot(path, null, allNames)); - assertPreconditionViolationException("name predicate", - () -> ReflectionSupport.findAllResourcesInClasspathRoot(path, allResources, null)); + () -> ReflectionSupport.findAllResourcesInClasspathRoot(path, null)); } @Test @@ -194,20 +192,18 @@ void findAllClassesInPackagePreconditions() { @Test void findAllResourcesInPackageDelegates() { - assertNotEquals(0, ReflectionSupport.findAllResourcesInPackage("org.junit", allResources, allNames).size()); + assertNotEquals(0, ReflectionSupport.findAllResourcesInPackage("org.junit", allResources).size()); - assertEquals(ReflectionUtils.findAllResourcesInPackage("org.junit", allResources, allNames), - ReflectionSupport.findAllResourcesInPackage("org.junit", allResources, allNames)); + assertEquals(ReflectionUtils.findAllResourcesInPackage("org.junit", allResources), + ReflectionSupport.findAllResourcesInPackage("org.junit", allResources)); } @Test void findAllResourcesInPackagePreconditions() { assertPreconditionViolationExceptionForString("basePackageName", - () -> ReflectionSupport.findAllResourcesInPackage(null, allResources, allNames)); + () -> ReflectionSupport.findAllResourcesInPackage(null, allResources)); assertPreconditionViolationException("resource predicate", - () -> ReflectionSupport.findAllResourcesInPackage("org.junit", null, allNames)); - assertPreconditionViolationException("name predicate", - () -> ReflectionSupport.findAllResourcesInPackage("org.junit", allResources, null)); + () -> ReflectionSupport.findAllResourcesInPackage("org.junit", null)); } @Test @@ -229,19 +225,17 @@ void findAllClassesInModulePreconditions() { @Test void findAllResourcesInModuleDelegates() { - assertEquals(ReflectionUtils.findAllResourcesInModule("org.junit.platform.commons", allResources, allNames), - ReflectionSupport.findAllResourcesInModule("org.junit.platform.commons", allResources, allNames)); + assertEquals(ReflectionUtils.findAllResourcesInModule("org.junit.platform.commons", allResources), + ReflectionSupport.findAllResourcesInModule("org.junit.platform.commons", allResources)); } @Test void findAllResourcesInModulePreconditions() { var exception = assertThrows(PreconditionViolationException.class, - () -> ReflectionSupport.findAllResourcesInModule(null, allResources, allNames)); + () -> ReflectionSupport.findAllResourcesInModule(null, allResources)); assertEquals("Module name must not be null or empty", exception.getMessage()); assertPreconditionViolationException("resource predicate", - () -> ReflectionSupport.findAllResourcesInModule("org.junit.platform.commons", null, allNames)); - assertPreconditionViolationException("name predicate", - () -> ReflectionSupport.findAllResourcesInModule("org.junit.platform.commons", allResources, null)); + () -> ReflectionSupport.findAllResourcesInModule("org.junit.platform.commons", null)); } @Test From 9f99477c6ba8bda8a06edefb55492c405b34780d Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Thu, 13 Jun 2024 18:55:13 +0200 Subject: [PATCH 17/78] Remove resource name filter predicate --- .../commons/support/ReflectionSupport.java | 66 +++++++------------ .../platform/commons/support/Resource.java | 12 ++-- .../commons/util/ClasspathScanner.java | 10 ++- .../commons/util/ReflectionUtils.java | 43 ++++++------ .../platform/commons/util/ResourceFilter.java | 30 ++------- .../platform/commons/util/ModuleUtils.java | 1 - .../support/ReflectionSupportTests.java | 32 ++++----- 7 files changed, 70 insertions(+), 124 deletions(-) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java index dcc8dcdb1fb5..eafc080e7a9f 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java @@ -147,17 +147,14 @@ public static List> findAllClassesInClasspathRoot(URI root, Predicate findAllResourcesInClasspathRoot(URI root, Predicate resourceFilter, - Predicate resourceNameFilter) { - - return ReflectionUtils.findAllResourcesInClasspathRoot(root, resourceFilter, resourceNameFilter); + public static List findAllResourcesInClasspathRoot(URI root, Predicate resourceFilter) { + return ReflectionUtils.findAllResourcesInClasspathRoot(root, resourceFilter); } /** @@ -196,18 +193,15 @@ public static Stream> streamAllClassesInClasspathRoot(URI root, Predica * @param root the URI for the classpath root in which to scan; never * {@code null} * @param resourceFilter the resource type filter; never {@code null} - * @param resourceNameFilter the resources name filter; never {@code null} * @return a stream of all such classes found; never {@code null} * but potentially empty * @since 1.10 - * @see #streamAllResourcesInPackage(String, Predicate, Predicate) - * @see #streamAllResourcesInModule(String, Predicate, Predicate) + * @see #streamAllResourcesInPackage(String, Predicate) + * @see #streamAllResourcesInModule(String, Predicate) */ @API(status = EXPERIMENTAL, since = "1.11") - public static Stream streamAllResourcesInClasspathRoot(URI root, Predicate resourceFilter, - Predicate resourceNameFilter) { - - return ReflectionUtils.streamAllResourcesInClasspathRoot(root, resourceFilter, resourceNameFilter); + public static Stream streamAllResourcesInClasspathRoot(URI root, Predicate resourceFilter) { + return ReflectionUtils.streamAllResourcesInClasspathRoot(root, resourceFilter); } /** @@ -230,7 +224,6 @@ public static Stream streamAllResourcesInClasspathRoot(URI root, Predi */ public static List> findAllClassesInPackage(String basePackageName, Predicate> classFilter, Predicate classNameFilter) { - return ReflectionUtils.findAllClassesInPackage(basePackageName, classFilter, classNameFilter); } @@ -246,17 +239,14 @@ public static List> findAllClassesInPackage(String basePackageName, Pre * scanning; must not be {@code null} and must be valid in terms of Java * syntax * @param resourceFilter the resource type filter; never {@code null} - * @param resourceNameFilter the resource name filter; never {@code null} * @return an immutable list of all such classes found; never {@code null} * but potentially empty - * @see #findAllResourcesInClasspathRoot(URI, Predicate, Predicate) - * @see #findAllResourcesInModule(String, Predicate, Predicate) + * @see #findAllResourcesInClasspathRoot(URI, Predicate) + * @see #findAllResourcesInModule(String, Predicate) */ @API(status = EXPERIMENTAL, since = "1.11") - public static List findAllResourcesInPackage(String basePackageName, Predicate resourceFilter, - Predicate resourceNameFilter) { - - return ReflectionUtils.findAllResourcesInPackage(basePackageName, resourceFilter, resourceNameFilter); + public static List findAllResourcesInPackage(String basePackageName, Predicate resourceFilter) { + return ReflectionUtils.findAllResourcesInPackage(basePackageName, resourceFilter); } /** @@ -297,18 +287,16 @@ public static Stream> streamAllClassesInPackage(String basePackageName, * scanning; must not be {@code null} and must be valid in terms of Java * syntax * @param resourceFilter the resource type filter; never {@code null} - * @param resourceNameFilter the resource name filter; never {@code null} * @return a stream of all such resources found; never {@code null} * but potentially empty * @since 1.10 - * @see #streamAllResourcesInClasspathRoot(URI, Predicate, Predicate) - * @see #streamAllResourcesInModule(String, Predicate, Predicate) + * @see #streamAllResourcesInClasspathRoot(URI, Predicate) + * @see #streamAllResourcesInModule(String, Predicate) */ @API(status = EXPERIMENTAL, since = "1.11") public static Stream streamAllResourcesInPackage(String basePackageName, - Predicate resourceFilter, Predicate resourceNameFilter) { - - return ReflectionUtils.streamAllResourcesInPackage(basePackageName, resourceFilter, resourceNameFilter); + Predicate resourceFilter) { + return ReflectionUtils.streamAllResourcesInPackage(basePackageName, resourceFilter); } /** @@ -346,18 +334,15 @@ public static List> findAllClassesInModule(String moduleName, Predicate * @param moduleName the name of the module to scan; never {@code null} or * empty * @param resourceFilter the resource type filter; never {@code null} - * @param resourceNameFilter the resource name filter; never {@code null} * @return an immutable list of all such resources found; never {@code null} * but potentially empty * @since 1.1.1 - * @see #findAllResourcesInClasspathRoot(URI, Predicate, Predicate) - * @see #findAllResourcesInPackage(String, Predicate, Predicate) + * @see #findAllResourcesInClasspathRoot(URI, Predicate) + * @see #findAllResourcesInPackage(String, Predicate) */ @API(status = EXPERIMENTAL, since = "1.11") - public static List findAllResourcesInModule(String moduleName, Predicate resourceFilter, - Predicate resourceNameFilter) { - - return ReflectionUtils.findAllResourcesInModule(moduleName, resourceFilter, resourceNameFilter); + public static List findAllResourcesInModule(String moduleName, Predicate resourceFilter) { + return ReflectionUtils.findAllResourcesInModule(moduleName, resourceFilter); } /** @@ -396,18 +381,15 @@ public static Stream> streamAllClassesInModule(String moduleName, Predi * @param moduleName the name of the module to scan; never {@code null} or * empty * @param resourceFilter the resource type filter; never {@code null} - * @param resourceNameFilter the resource name filter; never {@code null} * @return a stream of all such resources found; never {@code null} * but potentially empty * @since 1.10 - * @see #streamAllResourcesInClasspathRoot(URI, Predicate, Predicate) - * @see #streamAllResourcesInPackage(String, Predicate, Predicate) + * @see #streamAllResourcesInClasspathRoot(URI, Predicate) + * @see #streamAllResourcesInPackage(String, Predicate) */ @API(status = EXPERIMENTAL, since = "1.11") - public static Stream streamAllResourcesInModule(String moduleName, Predicate resourceFilter, - Predicate resourceNameFilter) { - - return ReflectionUtils.streamAllResourcesInModule(moduleName, resourceFilter, resourceNameFilter); + public static Stream streamAllResourcesInModule(String moduleName, Predicate resourceFilter) { + return ReflectionUtils.streamAllResourcesInModule(moduleName, resourceFilter); } /** diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/Resource.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/Resource.java index fc90e7427d6c..78c48e4cd608 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/Resource.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/Resource.java @@ -22,12 +22,12 @@ /** * Represents a resource on the classpath. * - * @see ReflectionSupport#findAllResourcesInClasspathRoot(URI, Predicate, Predicate) - * @see ReflectionSupport#findAllResourcesInPackage(String, Predicate, Predicate) - * @see ReflectionSupport#findAllResourcesInModule(String, Predicate, Predicate) - * @see ReflectionSupport#streamAllResourcesInClasspathRoot(URI, Predicate, Predicate) - * @see ReflectionSupport#streamAllResourcesInPackage(String, Predicate, Predicate) - * @see ReflectionSupport#streamAllResourcesInModule(String, Predicate, Predicate) + * @see ReflectionSupport#findAllResourcesInClasspathRoot(URI, Predicate) + * @see ReflectionSupport#findAllResourcesInPackage(String, Predicate) + * @see ReflectionSupport#findAllResourcesInModule(String, Predicate) + * @see ReflectionSupport#streamAllResourcesInClasspathRoot(URI, Predicate) + * @see ReflectionSupport#streamAllResourcesInPackage(String, Predicate) + * @see ReflectionSupport#streamAllResourcesInModule(String, Predicate) */ @API(status = EXPERIMENTAL, since = "1.11") public interface Resource { diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java index 24ae9ed6e59b..0940ca5f7d5f 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java @@ -207,12 +207,10 @@ private void processResourceFileSafely(Path baseDir, String basePackageName, Res try { String fullyQualifiedResourceName = determineFullyQualifiedResourceName(baseDir, basePackageName, resourceFile); - if (resourceFilter.match(fullyQualifiedResourceName)) { - Resource resource = new ClasspathResource(fullyQualifiedResourceName, resourceFile.toUri()); - // Always use "resourceFilter.test" to include future predicates. - if (resourceFilter.test(resource)) { - resourceConsumer.accept(resource); - } + Resource resource = new ClasspathResource(fullyQualifiedResourceName, resourceFile.toUri()); + // Always use "resourceFilter.test" to include future predicates. + if (resourceFilter.test(resource)) { + resourceConsumer.accept(resource); } } catch (Throwable throwable) { diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java index 7832890004f0..0f3fbddf4644 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java @@ -964,12 +964,11 @@ public static List> findAllClassesInClasspathRoot(URI root, Predicate findAllResourcesInClasspathRoot(URI root, Predicate resourceFilter, - Predicate resourceNameFilter) { + public static List findAllResourcesInClasspathRoot(URI root, Predicate resourceFilter) { // unmodifiable since returned by public, non-internal method(s) - return findAllResourcesInClasspathRoot(root, ResourceFilter.of(resourceNameFilter, resourceFilter)); + return findAllResourcesInClasspathRoot(root, ResourceFilter.of(resourceFilter)); } /** @@ -983,11 +982,10 @@ public static Stream> streamAllClassesInClasspathRoot(URI root, Predica /** * @since 1.11 - * @see org.junit.platform.commons.support.ReflectionSupport#streamAllResourcesInClasspathRoot(URI, Predicate, Predicate) + * @see #streamAllResourcesInClasspathRoot(URI, Predicate) */ - public static Stream streamAllResourcesInClasspathRoot(URI root, Predicate resourceFilter, - Predicate resourceNameFilter) { - return streamAllResourcesInClasspathRoot(root, ResourceFilter.of(resourceNameFilter, resourceFilter)); + public static Stream streamAllResourcesInClasspathRoot(URI root, Predicate resourceFilter) { + return streamAllResourcesInClasspathRoot(root, ResourceFilter.of(resourceFilter)); } /** @@ -1000,8 +998,8 @@ public static List> findAllClassesInClasspathRoot(URI root, ClassFilter /** * @since 1.11 */ - public static List findAllResourcesInClasspathRoot(URI root, ResourceFilter classFilter) { - return Collections.unmodifiableList(classpathScanner.scanForResourcesInClasspathRoot(root, classFilter)); + public static List findAllResourcesInClasspathRoot(URI root, ResourceFilter resourceFilter) { + return Collections.unmodifiableList(classpathScanner.scanForResourcesInClasspathRoot(root, resourceFilter)); } /** @@ -1031,10 +1029,9 @@ public static List> findAllClassesInPackage(String basePackageName, Pre * @since 1.11 * @see org.junit.platform.commons.support.ReflectionSupport#findAllClassesInPackage(String, Predicate, Predicate) */ - public static List findAllResourcesInPackage(String basePackageName, Predicate resourceFilter, - Predicate resourceNameFilter) { + public static List findAllResourcesInPackage(String basePackageName, Predicate resourceFilter) { // unmodifiable since returned by public, non-internal method(s) - return findAllResourcesInPackage(basePackageName, ResourceFilter.of(resourceNameFilter, resourceFilter)); + return findAllResourcesInPackage(basePackageName, ResourceFilter.of(resourceFilter)); } /** @@ -1048,11 +1045,11 @@ public static Stream> streamAllClassesInPackage(String basePackageName, /** * since 1.11 - * @see org.junit.platform.commons.support.ReflectionSupport#streamAllResourcesInPackage(String, Predicate, Predicate) + * @see #streamAllResourcesInPackage(String, Predicate) */ public static Stream streamAllResourcesInPackage(String basePackageName, - Predicate resourceFilter, Predicate resourceNameFilter) { - return streamAllResourcesInPackage(basePackageName, ResourceFilter.of(resourceNameFilter, resourceFilter)); + Predicate resourceFilter) { + return streamAllResourcesInPackage(basePackageName, ResourceFilter.of(resourceFilter)); } /** @@ -1096,12 +1093,11 @@ public static List> findAllClassesInModule(String moduleName, Predicate /** * @since 1.11 - * @see org.junit.platform.commons.support.ReflectionSupport#findAllResourcesInModule(String, Predicate, Predicate) + * @see #findAllResourcesInModule(String, Predicate) */ - public static List findAllResourcesInModule(String moduleName, Predicate resourceFilter, - Predicate resourceNameFilter) { + public static List findAllResourcesInModule(String moduleName, Predicate resourceFilter) { // unmodifiable since returned by public, non-internal method(s) - return findAllResourcesInModule(moduleName, ResourceFilter.of(resourceNameFilter, resourceFilter)); + return findAllResourcesInModule(moduleName, ResourceFilter.of(resourceFilter)); } /** @@ -1115,11 +1111,10 @@ public static Stream> streamAllClassesInModule(String moduleName, Predi /** * @since 1.11 - * @see org.junit.platform.commons.support.ReflectionSupport#streamAllResourcesInModule(String, Predicate, Predicate) + * @see #streamAllResourcesInModule(String, Predicate) */ - public static Stream streamAllResourcesInModule(String moduleName, Predicate resourceFilter, - Predicate resourceNameFilter) { - return streamAllResourcesInModule(moduleName, ResourceFilter.of(resourceNameFilter, resourceFilter)); + public static Stream streamAllResourcesInModule(String moduleName, Predicate resourceFilter) { + return streamAllResourcesInModule(moduleName, ResourceFilter.of(resourceFilter)); } /** diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java index bde54890c85e..ac2775ff876f 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java @@ -32,42 +32,20 @@ public class ResourceFilter implements Predicate { /** - * Create a {@link ResourceFilter} instance that accepts all names but filters resources. + * Create a {@link ResourceFilter} instance that filters resources. */ public static ResourceFilter of(Predicate resourcePredicate) { - return of(name -> true, resourcePredicate); + return new ResourceFilter(resourcePredicate); } - /** - * Create a {@link ResourceFilter} instance that filters by resource names and resources. - */ - public static ResourceFilter of(Predicate namePredicate, Predicate resourcePredicate) { - return new ResourceFilter(namePredicate, resourcePredicate); - } - - private final Predicate namePredicate; private final Predicate resourcePredicate; - private ResourceFilter(Predicate namePredicate, Predicate resourcePredicate) { - this.namePredicate = Preconditions.notNull(namePredicate, "name predicate must not be null"); + private ResourceFilter(Predicate resourcePredicate) { this.resourcePredicate = Preconditions.notNull(resourcePredicate, "resource predicate must not be null"); } - public boolean match(String name) { - return namePredicate.test(name); - } - - public boolean match(Resource resource) { - return resourcePredicate.test(resource); - } - - /** - * @implNote This implementation combines all tests stored in the predicates - * of this instance. Any new predicate must be added to this test method as - * well. - */ @Override public boolean test(Resource resource) { - return match(resource.getName()) && match(resource); + return resourcePredicate.test(resource); } } diff --git a/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java b/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java index 137c76ec3ddc..fbbe0882165f 100644 --- a/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java +++ b/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java @@ -282,7 +282,6 @@ List scan(ModuleReference reference) { try (Stream names = reader.list()) { // @formatter:off return names.filter(name -> !name.endsWith(".class")) - .filter(resourceFilter::match) .map(this::loadResourceUnchecked) // Always use ".filter(resourceFilter)" to include future predicates. .filter(resourceFilter) diff --git a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java index 94c883c81d73..132c6b579a47 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java @@ -146,8 +146,8 @@ List findAllResourcesInClasspathRootDelegates() throws Throwable { displayName = "..." + displayName.substring(displayName.length() - 42); } tests.add(DynamicTest.dynamicTest(displayName, - () -> assertEquals(ReflectionUtils.findAllResourcesInClasspathRoot(root, allResources, allNames), - ReflectionSupport.findAllResourcesInClasspathRoot(root, allResources, allNames)))); + () -> assertEquals(ReflectionUtils.findAllResourcesInClasspathRoot(root, allResources), + ReflectionSupport.findAllResourcesInClasspathRoot(root, allResources)))); } return tests; } @@ -156,11 +156,9 @@ List findAllResourcesInClasspathRootDelegates() throws Throwable { void findAllResourcesInClasspathRootPreconditions() { var path = Path.of(".").toUri(); assertPreconditionViolationException("root", - () -> ReflectionSupport.findAllResourcesInClasspathRoot(null, allResources, allNames)); + () -> ReflectionSupport.findAllResourcesInClasspathRoot(null, allResources)); assertPreconditionViolationException("resource predicate", - () -> ReflectionSupport.findAllResourcesInClasspathRoot(path, null, allNames)); - assertPreconditionViolationException("name predicate", - () -> ReflectionSupport.findAllResourcesInClasspathRoot(path, allResources, null)); + () -> ReflectionSupport.findAllResourcesInClasspathRoot(path, null)); } @Test @@ -182,20 +180,18 @@ void findAllClassesInPackagePreconditions() { @Test void findAllResourcesInPackageDelegates() { - assertNotEquals(0, ReflectionSupport.findAllResourcesInPackage("org.junit", allResources, allNames).size()); + assertNotEquals(0, ReflectionSupport.findAllResourcesInPackage("org.junit", allResources).size()); - assertEquals(ReflectionUtils.findAllResourcesInPackage("org.junit", allResources, allNames), - ReflectionSupport.findAllResourcesInPackage("org.junit", allResources, allNames)); + assertEquals(ReflectionUtils.findAllResourcesInPackage("org.junit", allResources), + ReflectionSupport.findAllResourcesInPackage("org.junit", allResources)); } @Test void findAllResourcesInPackagePreconditions() { assertPreconditionViolationExceptionForString("basePackageName", - () -> ReflectionSupport.findAllResourcesInPackage(null, allResources, allNames)); + () -> ReflectionSupport.findAllResourcesInPackage(null, allResources)); assertPreconditionViolationException("resource predicate", - () -> ReflectionSupport.findAllResourcesInPackage("org.junit", null, allNames)); - assertPreconditionViolationException("name predicate", - () -> ReflectionSupport.findAllResourcesInPackage("org.junit", allResources, null)); + () -> ReflectionSupport.findAllResourcesInPackage("org.junit", null)); } @Test @@ -217,19 +213,17 @@ void findAllClassesInModulePreconditions() { @Test void findAllResourcesInModuleDelegates() { - assertEquals(ReflectionUtils.findAllResourcesInModule("org.junit.platform.commons", allResources, allNames), - ReflectionSupport.findAllResourcesInModule("org.junit.platform.commons", allResources, allNames)); + assertEquals(ReflectionUtils.findAllResourcesInModule("org.junit.platform.commons", allResources), + ReflectionSupport.findAllResourcesInModule("org.junit.platform.commons", allResources)); } @Test void findAllResourcesInModulePreconditions() { var exception = assertThrows(PreconditionViolationException.class, - () -> ReflectionSupport.findAllResourcesInModule(null, allResources, allNames)); + () -> ReflectionSupport.findAllResourcesInModule(null, allResources)); assertEquals("Module name must not be null or empty", exception.getMessage()); assertPreconditionViolationException("resource predicate", - () -> ReflectionSupport.findAllResourcesInModule("org.junit.platform.commons", null, allNames)); - assertPreconditionViolationException("name predicate", - () -> ReflectionSupport.findAllResourcesInModule("org.junit.platform.commons", allResources, null)); + () -> ReflectionSupport.findAllResourcesInModule("org.junit.platform.commons", null)); } @Test From 2df520181b275ecfda29517cff2708a547b6945d Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Thu, 13 Jun 2024 19:07:08 +0200 Subject: [PATCH 18/78] Clean up to do. --- .../org/junit/platform/commons/util/ClasspathScannerTests.java | 1 - 1 file changed, 1 deletion(-) diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java index 167e8115b96b..347ea2b5ddd5 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java @@ -220,7 +220,6 @@ private void scanForResourcesInClasspathRootWithinJarFile(String resourceName) t .containsExactlyInAnyOrder("org/junit/platform/jartest/notincluded/not-included.resource", "org/junit/platform/jartest/included/included.resource", "org/junit/platform/jartest/included/recursive/recursively-included.resource", - // TODO: This is interesting. Would we also scan classes in META-INF/versions? "META-INF/MANIFEST.MF"); } } From 5a39b83a27793c691ddbb255fa1c8d47eb2a9cb9 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Fri, 14 Jun 2024 11:24:57 +0200 Subject: [PATCH 19/78] Fix typo --- .../platform/engine/discovery/ClasspathResourceSelector.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java index 7d903bbf580c..2eeb41d4c0f0 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java @@ -88,8 +88,8 @@ public String getClasspathResourceName() { public Resource getClasspathResource() { if (this.classpathResource == null) { // @formatter:off - Try tryToLoadClass = ReflectionUtils.tryToLoadResource(this.classpathResourceName); - this.classpathResource = tryToLoadClass.getOrThrow(cause -> + Try tryToLoadResource = ReflectionUtils.tryToLoadResource(this.classpathResourceName); + this.classpathResource = tryToLoadResource.getOrThrow(cause -> new PreconditionViolationException("Could not load resource with name: " + this.classpathResourceName, cause)); // @formatter:on } From f5d892b78700d1d3f40c9ade59a5a53fe855faa3 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Fri, 14 Jun 2024 12:05:40 +0200 Subject: [PATCH 20/78] Replace resource filter with predicate --- .../commons/util/ClasspathScanner.java | 11 ++-- .../platform/commons/util/ModuleUtils.java | 3 +- .../commons/util/ReflectionUtils.java | 65 ++----------------- .../platform/commons/util/ResourceFilter.java | 51 --------------- .../platform/commons/util/ModuleUtils.java | 9 +-- .../support/ReflectionSupportTests.java | 6 +- .../commons/util/ClasspathScannerTests.java | 16 ++--- 7 files changed, 30 insertions(+), 131 deletions(-) delete mode 100644 junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java index 0940ca5f7d5f..81ddd2fe7f56 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java @@ -94,7 +94,7 @@ List> scanForClassesInClasspathRoot(URI root, ClassFilter classFilter) return findClassesForUri(root, PackageUtils.DEFAULT_PACKAGE_NAME, classFilter); } - List scanForResourcesInPackage(String basePackageName, ResourceFilter resourceFilter) { + List scanForResourcesInPackage(String basePackageName, Predicate resourceFilter) { Preconditions.condition( PackageUtils.DEFAULT_PACKAGE_NAME.equals(basePackageName) || isNotBlank(basePackageName), "basePackageName must not be null or blank"); @@ -105,7 +105,7 @@ List scanForResourcesInPackage(String basePackageName, ResourceFilter return findResourcesForUris(roots, basePackageName, resourceFilter); } - List scanForResourcesInClasspathRoot(URI root, ResourceFilter resourceFilter) { + List scanForResourcesInClasspathRoot(URI root, Predicate resourceFilter) { Preconditions.notNull(root, "root must not be null"); Preconditions.notNull(resourceFilter, "resourceFilter must not be null"); @@ -139,7 +139,7 @@ private List> findClassesForUri(URI baseUri, String basePackageName, Cl * Recursively scan for resources in all the supplied source directories. */ private List findResourcesForUris(List baseUris, String basePackageName, - ResourceFilter resourceFilter) { + Predicate resourceFilter) { // @formatter:off return baseUris.stream() .map(baseUri -> findResourcesForUri(baseUri, basePackageName, resourceFilter)) @@ -149,7 +149,8 @@ private List findResourcesForUris(List baseUris, String basePacka // @formatter:on } - private List findResourcesForUri(URI baseUri, String basePackageName, ResourceFilter resourceFilter) { + private List findResourcesForUri(URI baseUri, String basePackageName, + Predicate resourceFilter) { List resources = new ArrayList<>(); // @formatter:off walkFilesForUri(baseUri, ClasspathFilters.resourceFiles(), @@ -202,7 +203,7 @@ private void processClassFileSafely(Path baseDir, String basePackageName, ClassF } } - private void processResourceFileSafely(Path baseDir, String basePackageName, ResourceFilter resourceFilter, + private void processResourceFileSafely(Path baseDir, String basePackageName, Predicate resourceFilter, Path resourceFile, Consumer resourceConsumer) { try { String fullyQualifiedResourceName = determineFullyQualifiedResourceName(baseDir, basePackageName, diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ModuleUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ModuleUtils.java index bf083e63bed4..251375622aa5 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ModuleUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ModuleUtils.java @@ -17,6 +17,7 @@ import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.function.Predicate; import org.apiguardian.api.API; import org.junit.platform.commons.logging.Logger; @@ -108,7 +109,7 @@ public static List> findAllClassesInModule(String moduleName, ClassFilt * but potentially empty */ @API(status = INTERNAL, since = "1.11") - public static List findAllResourcesInModule(String moduleName, ResourceFilter filter) { + public static List findAllResourcesInModule(String moduleName, Predicate filter) { Preconditions.notBlank(moduleName, "Module name must not be null or empty"); Preconditions.notNull(filter, "Resource filter must not be null"); diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java index 72fe812f5cb0..517ee073f273 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java @@ -1052,15 +1052,6 @@ public static List> findAllClassesInClasspathRoot(URI root, Predicate findAllResourcesInClasspathRoot(URI root, Predicate resourceFilter) { - // unmodifiable since returned by public, non-internal method(s) - return findAllResourcesInClasspathRoot(root, ResourceFilter.of(resourceFilter)); - } - /** * @since 1.10 * @see org.junit.platform.commons.support.ReflectionSupport#streamAllClassesInClasspathRoot(URI, Predicate, Predicate) @@ -1070,14 +1061,6 @@ public static Stream> streamAllClassesInClasspathRoot(URI root, Predica return streamAllClassesInClasspathRoot(root, ClassFilter.of(classNameFilter, classFilter)); } - /** - * @since 1.11 - * @see #streamAllResourcesInClasspathRoot(URI, Predicate) - */ - public static Stream streamAllResourcesInClasspathRoot(URI root, Predicate resourceFilter) { - return streamAllResourcesInClasspathRoot(root, ResourceFilter.of(resourceFilter)); - } - /** * @since 1.1 */ @@ -1088,7 +1071,7 @@ public static List> findAllClassesInClasspathRoot(URI root, ClassFilter /** * @since 1.11 */ - public static List findAllResourcesInClasspathRoot(URI root, ResourceFilter resourceFilter) { + public static List findAllResourcesInClasspathRoot(URI root, Predicate resourceFilter) { return Collections.unmodifiableList(classpathScanner.scanForResourcesInClasspathRoot(root, resourceFilter)); } @@ -1102,7 +1085,7 @@ public static Stream> streamAllClassesInClasspathRoot(URI root, ClassFi /** * @since 1.11 */ - public static Stream streamAllResourcesInClasspathRoot(URI root, ResourceFilter resourceFilter) { + public static Stream streamAllResourcesInClasspathRoot(URI root, Predicate resourceFilter) { return findAllResourcesInClasspathRoot(root, resourceFilter).stream(); } @@ -1115,15 +1098,6 @@ public static List> findAllClassesInPackage(String basePackageName, Pre return findAllClassesInPackage(basePackageName, ClassFilter.of(classNameFilter, classFilter)); } - /** - * @since 1.11 - * @see org.junit.platform.commons.support.ReflectionSupport#findAllClassesInPackage(String, Predicate, Predicate) - */ - public static List findAllResourcesInPackage(String basePackageName, Predicate resourceFilter) { - // unmodifiable since returned by public, non-internal method(s) - return findAllResourcesInPackage(basePackageName, ResourceFilter.of(resourceFilter)); - } - /** * since 1.10 * @see org.junit.platform.commons.support.ReflectionSupport#streamAllClassesInPackage(String, Predicate, Predicate) @@ -1133,15 +1107,6 @@ public static Stream> streamAllClassesInPackage(String basePackageName, return streamAllClassesInPackage(basePackageName, ClassFilter.of(classNameFilter, classFilter)); } - /** - * since 1.11 - * @see #streamAllResourcesInPackage(String, Predicate) - */ - public static Stream streamAllResourcesInPackage(String basePackageName, - Predicate resourceFilter) { - return streamAllResourcesInPackage(basePackageName, ResourceFilter.of(resourceFilter)); - } - /** * @since 1.1 */ @@ -1152,7 +1117,7 @@ public static List> findAllClassesInPackage(String basePackageName, Cla /** * @since 1.11 */ - public static List findAllResourcesInPackage(String basePackageName, ResourceFilter resourceFilter) { + public static List findAllResourcesInPackage(String basePackageName, Predicate resourceFilter) { return Collections.unmodifiableList( classpathScanner.scanForResourcesInPackage(basePackageName, resourceFilter)); } @@ -1167,7 +1132,8 @@ public static Stream> streamAllClassesInPackage(String basePackageName, /** * @since 1.11 */ - public static Stream streamAllResourcesInPackage(String basePackageName, ResourceFilter resourceFilter) { + public static Stream streamAllResourcesInPackage(String basePackageName, + Predicate resourceFilter) { return findAllResourcesInPackage(basePackageName, resourceFilter).stream(); } @@ -1181,15 +1147,6 @@ public static List> findAllClassesInModule(String moduleName, Predicate return findAllClassesInModule(moduleName, ClassFilter.of(classNameFilter, classFilter)); } - /** - * @since 1.11 - * @see #findAllResourcesInModule(String, Predicate) - */ - public static List findAllResourcesInModule(String moduleName, Predicate resourceFilter) { - // unmodifiable since returned by public, non-internal method(s) - return findAllResourcesInModule(moduleName, ResourceFilter.of(resourceFilter)); - } - /** * @since 1.10 * @see org.junit.platform.commons.support.ReflectionSupport#streamAllClassesInModule(String, Predicate, Predicate) @@ -1199,14 +1156,6 @@ public static Stream> streamAllClassesInModule(String moduleName, Predi return streamAllClassesInModule(moduleName, ClassFilter.of(classNameFilter, classFilter)); } - /** - * @since 1.11 - * @see #streamAllResourcesInModule(String, Predicate) - */ - public static Stream streamAllResourcesInModule(String moduleName, Predicate resourceFilter) { - return streamAllResourcesInModule(moduleName, ResourceFilter.of(resourceFilter)); - } - /** * @since 1.1.1 */ @@ -1217,7 +1166,7 @@ public static List> findAllClassesInModule(String moduleName, ClassFilt /** * @since 1.11 */ - public static List findAllResourcesInModule(String moduleName, ResourceFilter resourceFilter) { + public static List findAllResourcesInModule(String moduleName, Predicate resourceFilter) { return Collections.unmodifiableList(ModuleUtils.findAllResourcesInModule(moduleName, resourceFilter)); } @@ -1231,7 +1180,7 @@ public static Stream> streamAllClassesInModule(String moduleName, Class /** * @since 1.11 */ - public static Stream streamAllResourcesInModule(String moduleName, ResourceFilter resourceFilter) { + public static Stream streamAllResourcesInModule(String moduleName, Predicate resourceFilter) { return findAllResourcesInModule(moduleName, resourceFilter).stream(); } diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java deleted file mode 100644 index ac2775ff876f..000000000000 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.commons.util; - -import static org.apiguardian.api.API.Status.INTERNAL; - -import java.util.function.Predicate; - -import org.apiguardian.api.API; -import org.junit.platform.commons.support.Resource; - -/** - * Resource-related predicate used by reflection utilities. - * - *

DISCLAIMER

- * - *

These utilities are intended solely for usage within the JUnit framework - * itself. Any usage by external parties is not supported. - * Use at your own risk! - * - * @since 1.11 - */ -@API(status = INTERNAL, since = "1.11") -public class ResourceFilter implements Predicate { - - /** - * Create a {@link ResourceFilter} instance that filters resources. - */ - public static ResourceFilter of(Predicate resourcePredicate) { - return new ResourceFilter(resourcePredicate); - } - - private final Predicate resourcePredicate; - - private ResourceFilter(Predicate resourcePredicate) { - this.resourcePredicate = Preconditions.notNull(resourcePredicate, "resource predicate must not be null"); - } - - @Override - public boolean test(Resource resource) { - return resourcePredicate.test(resource); - } -} diff --git a/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java b/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java index fbbe0882165f..f46f06010608 100644 --- a/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java +++ b/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java @@ -127,7 +127,7 @@ public static List> findAllClassesInModule(String moduleName, ClassFilt * but potentially empty */ @API(status = INTERNAL, since = "1.11") - public static List findAllResourcesInModule(String moduleName, ResourceFilter filter) { + public static List findAllResourcesInModule(String moduleName, Predicate filter) { Preconditions.notBlank(moduleName, "Module name must not be null or empty"); Preconditions.notNull(filter, "Resource filter must not be null"); @@ -185,7 +185,8 @@ private static List> scan(Set references, ClassFilter * Scan for classes using the supplied set of module references, class * filter, and loader. */ - private static List scan(Set references, ResourceFilter filter, ClassLoader loader) { + private static List scan(Set references, Predicate filter, + ClassLoader loader) { logger.debug(() -> "Scanning " + references.size() + " module references: " + references); ModuleReferenceResourceScanner scanner = new ModuleReferenceResourceScanner(filter, loader); List classes = new ArrayList<>(); @@ -266,10 +267,10 @@ private Class loadClassUnchecked(String binaryName) { */ static class ModuleReferenceResourceScanner { - private final ResourceFilter resourceFilter; + private final Predicate resourceFilter; private final ClassLoader classLoader; - ModuleReferenceResourceScanner(ResourceFilter resourceFilter, ClassLoader classLoader) { + ModuleReferenceResourceScanner(Predicate resourceFilter, ClassLoader classLoader) { this.resourceFilter = resourceFilter; this.classLoader = classLoader; } diff --git a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java index 132c6b579a47..02bfc11ddafe 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java @@ -157,7 +157,7 @@ void findAllResourcesInClasspathRootPreconditions() { var path = Path.of(".").toUri(); assertPreconditionViolationException("root", () -> ReflectionSupport.findAllResourcesInClasspathRoot(null, allResources)); - assertPreconditionViolationException("resource predicate", + assertPreconditionViolationException("resourceFilter", () -> ReflectionSupport.findAllResourcesInClasspathRoot(path, null)); } @@ -190,7 +190,7 @@ void findAllResourcesInPackageDelegates() { void findAllResourcesInPackagePreconditions() { assertPreconditionViolationExceptionForString("basePackageName", () -> ReflectionSupport.findAllResourcesInPackage(null, allResources)); - assertPreconditionViolationException("resource predicate", + assertPreconditionViolationException("resourceFilter", () -> ReflectionSupport.findAllResourcesInPackage("org.junit", null)); } @@ -222,7 +222,7 @@ void findAllResourcesInModulePreconditions() { var exception = assertThrows(PreconditionViolationException.class, () -> ReflectionSupport.findAllResourcesInModule(null, allResources)); assertEquals("Module name must not be null or empty", exception.getMessage()); - assertPreconditionViolationException("resource predicate", + assertPreconditionViolationException("Resource filter", () -> ReflectionSupport.findAllResourcesInModule("org.junit.platform.commons", null)); } diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java index 347ea2b5ddd5..b3808fca72ee 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java @@ -60,7 +60,7 @@ class ClasspathScannerTests { private static final ClassFilter allClasses = ClassFilter.of(type -> true); - private static final ResourceFilter allResources = ResourceFilter.of(type -> true); + private static final Predicate allResources = type -> true; private final List> loadedClasses = new ArrayList<>(); @@ -146,9 +146,7 @@ void scanForResourcesInClasspathRootWhenGenericRuntimeExceptionOccurs(LogRecordL } private void assertResourcesScannedWhenExceptionIsThrown(Predicate filter) { - var resourceFilter = ResourceFilter.of(filter); - var resources = this.classpathScanner.scanForResourcesInClasspathRoot(getTestClasspathResourceRoot(), - resourceFilter); + var resources = this.classpathScanner.scanForResourcesInClasspathRoot(getTestClasspathResourceRoot(), filter); assertThat(resources).hasSizeGreaterThanOrEqualTo(150); } @@ -345,7 +343,7 @@ void scanForClassesInDefaultPackage() { @Test void scanForResourcesInDefaultPackage() { - var resourceFilter = ResourceFilter.of(this::inDefaultPackage); + Predicate resourceFilter = this::inDefaultPackage; var resources = classpathScanner.scanForResourcesInPackage("", resourceFilter); assertThat(resources).as("number of resources found in default package").isNotEmpty(); @@ -362,8 +360,8 @@ void scanForClassesInPackageWithFilter() { @Test void scanForResourcesInPackageWithFilter() { - var thisResourceOnly = ResourceFilter.of( - resource -> "org/junit/platform/commons/example.resource".equals(resource.getName())); + Predicate thisResourceOnly = resource -> "org/junit/platform/commons/example.resource".equals( + resource.getName()); var resources = classpathScanner.scanForResourcesInPackage("org.junit.platform.commons", thisResourceOnly); assertThat(resources).extracting(Resource::getName).containsExactly( "org/junit/platform/commons/example.resource"); @@ -371,8 +369,8 @@ void scanForResourcesInPackageWithFilter() { @Test void resourcesCanBeRead() throws IOException { - var thisResourceOnly = ResourceFilter.of( - resource -> "org/junit/platform/commons/example.resource".equals(resource.getName())); + Predicate thisResourceOnly = resource -> "org/junit/platform/commons/example.resource".equals( + resource.getName()); var resources = classpathScanner.scanForResourcesInPackage("org.junit.platform.commons", thisResourceOnly); Resource resource = resources.get(0); From 6e95eeba1ab69aa32aba2177c84081b750ffa5f6 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Fri, 14 Jun 2024 12:23:33 +0200 Subject: [PATCH 21/78] Revert "Replace resource filter with predicate" This reverts commit f5d892b78700d1d3f40c9ade59a5a53fe855faa3. --- .../commons/util/ClasspathScanner.java | 11 ++-- .../platform/commons/util/ModuleUtils.java | 3 +- .../commons/util/ReflectionUtils.java | 65 +++++++++++++++++-- .../platform/commons/util/ResourceFilter.java | 51 +++++++++++++++ .../platform/commons/util/ModuleUtils.java | 9 ++- .../support/ReflectionSupportTests.java | 6 +- .../commons/util/ClasspathScannerTests.java | 16 +++-- 7 files changed, 131 insertions(+), 30 deletions(-) create mode 100644 junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java index 81ddd2fe7f56..0940ca5f7d5f 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java @@ -94,7 +94,7 @@ List> scanForClassesInClasspathRoot(URI root, ClassFilter classFilter) return findClassesForUri(root, PackageUtils.DEFAULT_PACKAGE_NAME, classFilter); } - List scanForResourcesInPackage(String basePackageName, Predicate resourceFilter) { + List scanForResourcesInPackage(String basePackageName, ResourceFilter resourceFilter) { Preconditions.condition( PackageUtils.DEFAULT_PACKAGE_NAME.equals(basePackageName) || isNotBlank(basePackageName), "basePackageName must not be null or blank"); @@ -105,7 +105,7 @@ List scanForResourcesInPackage(String basePackageName, Predicate scanForResourcesInClasspathRoot(URI root, Predicate resourceFilter) { + List scanForResourcesInClasspathRoot(URI root, ResourceFilter resourceFilter) { Preconditions.notNull(root, "root must not be null"); Preconditions.notNull(resourceFilter, "resourceFilter must not be null"); @@ -139,7 +139,7 @@ private List> findClassesForUri(URI baseUri, String basePackageName, Cl * Recursively scan for resources in all the supplied source directories. */ private List findResourcesForUris(List baseUris, String basePackageName, - Predicate resourceFilter) { + ResourceFilter resourceFilter) { // @formatter:off return baseUris.stream() .map(baseUri -> findResourcesForUri(baseUri, basePackageName, resourceFilter)) @@ -149,8 +149,7 @@ private List findResourcesForUris(List baseUris, String basePacka // @formatter:on } - private List findResourcesForUri(URI baseUri, String basePackageName, - Predicate resourceFilter) { + private List findResourcesForUri(URI baseUri, String basePackageName, ResourceFilter resourceFilter) { List resources = new ArrayList<>(); // @formatter:off walkFilesForUri(baseUri, ClasspathFilters.resourceFiles(), @@ -203,7 +202,7 @@ private void processClassFileSafely(Path baseDir, String basePackageName, ClassF } } - private void processResourceFileSafely(Path baseDir, String basePackageName, Predicate resourceFilter, + private void processResourceFileSafely(Path baseDir, String basePackageName, ResourceFilter resourceFilter, Path resourceFile, Consumer resourceConsumer) { try { String fullyQualifiedResourceName = determineFullyQualifiedResourceName(baseDir, basePackageName, diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ModuleUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ModuleUtils.java index 251375622aa5..bf083e63bed4 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ModuleUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ModuleUtils.java @@ -17,7 +17,6 @@ import java.util.List; import java.util.Optional; import java.util.Set; -import java.util.function.Predicate; import org.apiguardian.api.API; import org.junit.platform.commons.logging.Logger; @@ -109,7 +108,7 @@ public static List> findAllClassesInModule(String moduleName, ClassFilt * but potentially empty */ @API(status = INTERNAL, since = "1.11") - public static List findAllResourcesInModule(String moduleName, Predicate filter) { + public static List findAllResourcesInModule(String moduleName, ResourceFilter filter) { Preconditions.notBlank(moduleName, "Module name must not be null or empty"); Preconditions.notNull(filter, "Resource filter must not be null"); diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java index 517ee073f273..72fe812f5cb0 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java @@ -1052,6 +1052,15 @@ public static List> findAllClassesInClasspathRoot(URI root, Predicate findAllResourcesInClasspathRoot(URI root, Predicate resourceFilter) { + // unmodifiable since returned by public, non-internal method(s) + return findAllResourcesInClasspathRoot(root, ResourceFilter.of(resourceFilter)); + } + /** * @since 1.10 * @see org.junit.platform.commons.support.ReflectionSupport#streamAllClassesInClasspathRoot(URI, Predicate, Predicate) @@ -1061,6 +1070,14 @@ public static Stream> streamAllClassesInClasspathRoot(URI root, Predica return streamAllClassesInClasspathRoot(root, ClassFilter.of(classNameFilter, classFilter)); } + /** + * @since 1.11 + * @see #streamAllResourcesInClasspathRoot(URI, Predicate) + */ + public static Stream streamAllResourcesInClasspathRoot(URI root, Predicate resourceFilter) { + return streamAllResourcesInClasspathRoot(root, ResourceFilter.of(resourceFilter)); + } + /** * @since 1.1 */ @@ -1071,7 +1088,7 @@ public static List> findAllClassesInClasspathRoot(URI root, ClassFilter /** * @since 1.11 */ - public static List findAllResourcesInClasspathRoot(URI root, Predicate resourceFilter) { + public static List findAllResourcesInClasspathRoot(URI root, ResourceFilter resourceFilter) { return Collections.unmodifiableList(classpathScanner.scanForResourcesInClasspathRoot(root, resourceFilter)); } @@ -1085,7 +1102,7 @@ public static Stream> streamAllClassesInClasspathRoot(URI root, ClassFi /** * @since 1.11 */ - public static Stream streamAllResourcesInClasspathRoot(URI root, Predicate resourceFilter) { + public static Stream streamAllResourcesInClasspathRoot(URI root, ResourceFilter resourceFilter) { return findAllResourcesInClasspathRoot(root, resourceFilter).stream(); } @@ -1098,6 +1115,15 @@ public static List> findAllClassesInPackage(String basePackageName, Pre return findAllClassesInPackage(basePackageName, ClassFilter.of(classNameFilter, classFilter)); } + /** + * @since 1.11 + * @see org.junit.platform.commons.support.ReflectionSupport#findAllClassesInPackage(String, Predicate, Predicate) + */ + public static List findAllResourcesInPackage(String basePackageName, Predicate resourceFilter) { + // unmodifiable since returned by public, non-internal method(s) + return findAllResourcesInPackage(basePackageName, ResourceFilter.of(resourceFilter)); + } + /** * since 1.10 * @see org.junit.platform.commons.support.ReflectionSupport#streamAllClassesInPackage(String, Predicate, Predicate) @@ -1107,6 +1133,15 @@ public static Stream> streamAllClassesInPackage(String basePackageName, return streamAllClassesInPackage(basePackageName, ClassFilter.of(classNameFilter, classFilter)); } + /** + * since 1.11 + * @see #streamAllResourcesInPackage(String, Predicate) + */ + public static Stream streamAllResourcesInPackage(String basePackageName, + Predicate resourceFilter) { + return streamAllResourcesInPackage(basePackageName, ResourceFilter.of(resourceFilter)); + } + /** * @since 1.1 */ @@ -1117,7 +1152,7 @@ public static List> findAllClassesInPackage(String basePackageName, Cla /** * @since 1.11 */ - public static List findAllResourcesInPackage(String basePackageName, Predicate resourceFilter) { + public static List findAllResourcesInPackage(String basePackageName, ResourceFilter resourceFilter) { return Collections.unmodifiableList( classpathScanner.scanForResourcesInPackage(basePackageName, resourceFilter)); } @@ -1132,8 +1167,7 @@ public static Stream> streamAllClassesInPackage(String basePackageName, /** * @since 1.11 */ - public static Stream streamAllResourcesInPackage(String basePackageName, - Predicate resourceFilter) { + public static Stream streamAllResourcesInPackage(String basePackageName, ResourceFilter resourceFilter) { return findAllResourcesInPackage(basePackageName, resourceFilter).stream(); } @@ -1147,6 +1181,15 @@ public static List> findAllClassesInModule(String moduleName, Predicate return findAllClassesInModule(moduleName, ClassFilter.of(classNameFilter, classFilter)); } + /** + * @since 1.11 + * @see #findAllResourcesInModule(String, Predicate) + */ + public static List findAllResourcesInModule(String moduleName, Predicate resourceFilter) { + // unmodifiable since returned by public, non-internal method(s) + return findAllResourcesInModule(moduleName, ResourceFilter.of(resourceFilter)); + } + /** * @since 1.10 * @see org.junit.platform.commons.support.ReflectionSupport#streamAllClassesInModule(String, Predicate, Predicate) @@ -1156,6 +1199,14 @@ public static Stream> streamAllClassesInModule(String moduleName, Predi return streamAllClassesInModule(moduleName, ClassFilter.of(classNameFilter, classFilter)); } + /** + * @since 1.11 + * @see #streamAllResourcesInModule(String, Predicate) + */ + public static Stream streamAllResourcesInModule(String moduleName, Predicate resourceFilter) { + return streamAllResourcesInModule(moduleName, ResourceFilter.of(resourceFilter)); + } + /** * @since 1.1.1 */ @@ -1166,7 +1217,7 @@ public static List> findAllClassesInModule(String moduleName, ClassFilt /** * @since 1.11 */ - public static List findAllResourcesInModule(String moduleName, Predicate resourceFilter) { + public static List findAllResourcesInModule(String moduleName, ResourceFilter resourceFilter) { return Collections.unmodifiableList(ModuleUtils.findAllResourcesInModule(moduleName, resourceFilter)); } @@ -1180,7 +1231,7 @@ public static Stream> streamAllClassesInModule(String moduleName, Class /** * @since 1.11 */ - public static Stream streamAllResourcesInModule(String moduleName, Predicate resourceFilter) { + public static Stream streamAllResourcesInModule(String moduleName, ResourceFilter resourceFilter) { return findAllResourcesInModule(moduleName, resourceFilter).stream(); } diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java new file mode 100644 index 000000000000..ac2775ff876f --- /dev/null +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java @@ -0,0 +1,51 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.util; + +import static org.apiguardian.api.API.Status.INTERNAL; + +import java.util.function.Predicate; + +import org.apiguardian.api.API; +import org.junit.platform.commons.support.Resource; + +/** + * Resource-related predicate used by reflection utilities. + * + *

DISCLAIMER

+ * + *

These utilities are intended solely for usage within the JUnit framework + * itself. Any usage by external parties is not supported. + * Use at your own risk! + * + * @since 1.11 + */ +@API(status = INTERNAL, since = "1.11") +public class ResourceFilter implements Predicate { + + /** + * Create a {@link ResourceFilter} instance that filters resources. + */ + public static ResourceFilter of(Predicate resourcePredicate) { + return new ResourceFilter(resourcePredicate); + } + + private final Predicate resourcePredicate; + + private ResourceFilter(Predicate resourcePredicate) { + this.resourcePredicate = Preconditions.notNull(resourcePredicate, "resource predicate must not be null"); + } + + @Override + public boolean test(Resource resource) { + return resourcePredicate.test(resource); + } +} diff --git a/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java b/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java index f46f06010608..fbbe0882165f 100644 --- a/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java +++ b/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java @@ -127,7 +127,7 @@ public static List> findAllClassesInModule(String moduleName, ClassFilt * but potentially empty */ @API(status = INTERNAL, since = "1.11") - public static List findAllResourcesInModule(String moduleName, Predicate filter) { + public static List findAllResourcesInModule(String moduleName, ResourceFilter filter) { Preconditions.notBlank(moduleName, "Module name must not be null or empty"); Preconditions.notNull(filter, "Resource filter must not be null"); @@ -185,8 +185,7 @@ private static List> scan(Set references, ClassFilter * Scan for classes using the supplied set of module references, class * filter, and loader. */ - private static List scan(Set references, Predicate filter, - ClassLoader loader) { + private static List scan(Set references, ResourceFilter filter, ClassLoader loader) { logger.debug(() -> "Scanning " + references.size() + " module references: " + references); ModuleReferenceResourceScanner scanner = new ModuleReferenceResourceScanner(filter, loader); List classes = new ArrayList<>(); @@ -267,10 +266,10 @@ private Class loadClassUnchecked(String binaryName) { */ static class ModuleReferenceResourceScanner { - private final Predicate resourceFilter; + private final ResourceFilter resourceFilter; private final ClassLoader classLoader; - ModuleReferenceResourceScanner(Predicate resourceFilter, ClassLoader classLoader) { + ModuleReferenceResourceScanner(ResourceFilter resourceFilter, ClassLoader classLoader) { this.resourceFilter = resourceFilter; this.classLoader = classLoader; } diff --git a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java index 02bfc11ddafe..132c6b579a47 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java @@ -157,7 +157,7 @@ void findAllResourcesInClasspathRootPreconditions() { var path = Path.of(".").toUri(); assertPreconditionViolationException("root", () -> ReflectionSupport.findAllResourcesInClasspathRoot(null, allResources)); - assertPreconditionViolationException("resourceFilter", + assertPreconditionViolationException("resource predicate", () -> ReflectionSupport.findAllResourcesInClasspathRoot(path, null)); } @@ -190,7 +190,7 @@ void findAllResourcesInPackageDelegates() { void findAllResourcesInPackagePreconditions() { assertPreconditionViolationExceptionForString("basePackageName", () -> ReflectionSupport.findAllResourcesInPackage(null, allResources)); - assertPreconditionViolationException("resourceFilter", + assertPreconditionViolationException("resource predicate", () -> ReflectionSupport.findAllResourcesInPackage("org.junit", null)); } @@ -222,7 +222,7 @@ void findAllResourcesInModulePreconditions() { var exception = assertThrows(PreconditionViolationException.class, () -> ReflectionSupport.findAllResourcesInModule(null, allResources)); assertEquals("Module name must not be null or empty", exception.getMessage()); - assertPreconditionViolationException("Resource filter", + assertPreconditionViolationException("resource predicate", () -> ReflectionSupport.findAllResourcesInModule("org.junit.platform.commons", null)); } diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java index b3808fca72ee..347ea2b5ddd5 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java @@ -60,7 +60,7 @@ class ClasspathScannerTests { private static final ClassFilter allClasses = ClassFilter.of(type -> true); - private static final Predicate allResources = type -> true; + private static final ResourceFilter allResources = ResourceFilter.of(type -> true); private final List> loadedClasses = new ArrayList<>(); @@ -146,7 +146,9 @@ void scanForResourcesInClasspathRootWhenGenericRuntimeExceptionOccurs(LogRecordL } private void assertResourcesScannedWhenExceptionIsThrown(Predicate filter) { - var resources = this.classpathScanner.scanForResourcesInClasspathRoot(getTestClasspathResourceRoot(), filter); + var resourceFilter = ResourceFilter.of(filter); + var resources = this.classpathScanner.scanForResourcesInClasspathRoot(getTestClasspathResourceRoot(), + resourceFilter); assertThat(resources).hasSizeGreaterThanOrEqualTo(150); } @@ -343,7 +345,7 @@ void scanForClassesInDefaultPackage() { @Test void scanForResourcesInDefaultPackage() { - Predicate resourceFilter = this::inDefaultPackage; + var resourceFilter = ResourceFilter.of(this::inDefaultPackage); var resources = classpathScanner.scanForResourcesInPackage("", resourceFilter); assertThat(resources).as("number of resources found in default package").isNotEmpty(); @@ -360,8 +362,8 @@ void scanForClassesInPackageWithFilter() { @Test void scanForResourcesInPackageWithFilter() { - Predicate thisResourceOnly = resource -> "org/junit/platform/commons/example.resource".equals( - resource.getName()); + var thisResourceOnly = ResourceFilter.of( + resource -> "org/junit/platform/commons/example.resource".equals(resource.getName())); var resources = classpathScanner.scanForResourcesInPackage("org.junit.platform.commons", thisResourceOnly); assertThat(resources).extracting(Resource::getName).containsExactly( "org/junit/platform/commons/example.resource"); @@ -369,8 +371,8 @@ void scanForResourcesInPackageWithFilter() { @Test void resourcesCanBeRead() throws IOException { - Predicate thisResourceOnly = resource -> "org/junit/platform/commons/example.resource".equals( - resource.getName()); + var thisResourceOnly = ResourceFilter.of( + resource -> "org/junit/platform/commons/example.resource".equals(resource.getName())); var resources = classpathScanner.scanForResourcesInPackage("org.junit.platform.commons", thisResourceOnly); Resource resource = resources.get(0); From e59cc59561b316a0254d202f1f726aa783f9882e Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Fri, 14 Jun 2024 12:25:11 +0200 Subject: [PATCH 22/78] Revert "Remove resource name filter predicate" This reverts commit 9f99477c6ba8bda8a06edefb55492c405b34780d. --- .../commons/support/ReflectionSupport.java | 66 ++++++++++++------- .../platform/commons/support/Resource.java | 12 ++-- .../commons/util/ClasspathScanner.java | 10 +-- .../commons/util/ReflectionUtils.java | 43 ++++++------ .../platform/commons/util/ResourceFilter.java | 30 +++++++-- .../platform/commons/util/ModuleUtils.java | 1 + .../support/ReflectionSupportTests.java | 32 +++++---- 7 files changed, 124 insertions(+), 70 deletions(-) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java index d4c35725bd6f..ce72026caaf9 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java @@ -147,14 +147,17 @@ public static List> findAllClassesInClasspathRoot(URI root, Predicate findAllResourcesInClasspathRoot(URI root, Predicate resourceFilter) { - return ReflectionUtils.findAllResourcesInClasspathRoot(root, resourceFilter); + public static List findAllResourcesInClasspathRoot(URI root, Predicate resourceFilter, + Predicate resourceNameFilter) { + + return ReflectionUtils.findAllResourcesInClasspathRoot(root, resourceFilter, resourceNameFilter); } /** @@ -193,15 +196,18 @@ public static Stream> streamAllClassesInClasspathRoot(URI root, Predica * @param root the URI for the classpath root in which to scan; never * {@code null} * @param resourceFilter the resource type filter; never {@code null} + * @param resourceNameFilter the resources name filter; never {@code null} * @return a stream of all such classes found; never {@code null} * but potentially empty * @since 1.10 - * @see #streamAllResourcesInPackage(String, Predicate) - * @see #streamAllResourcesInModule(String, Predicate) + * @see #streamAllResourcesInPackage(String, Predicate, Predicate) + * @see #streamAllResourcesInModule(String, Predicate, Predicate) */ @API(status = EXPERIMENTAL, since = "1.11") - public static Stream streamAllResourcesInClasspathRoot(URI root, Predicate resourceFilter) { - return ReflectionUtils.streamAllResourcesInClasspathRoot(root, resourceFilter); + public static Stream streamAllResourcesInClasspathRoot(URI root, Predicate resourceFilter, + Predicate resourceNameFilter) { + + return ReflectionUtils.streamAllResourcesInClasspathRoot(root, resourceFilter, resourceNameFilter); } /** @@ -224,6 +230,7 @@ public static Stream streamAllResourcesInClasspathRoot(URI root, Predi */ public static List> findAllClassesInPackage(String basePackageName, Predicate> classFilter, Predicate classNameFilter) { + return ReflectionUtils.findAllClassesInPackage(basePackageName, classFilter, classNameFilter); } @@ -239,14 +246,17 @@ public static List> findAllClassesInPackage(String basePackageName, Pre * scanning; must not be {@code null} and must be valid in terms of Java * syntax * @param resourceFilter the resource type filter; never {@code null} + * @param resourceNameFilter the resource name filter; never {@code null} * @return an immutable list of all such classes found; never {@code null} * but potentially empty - * @see #findAllResourcesInClasspathRoot(URI, Predicate) - * @see #findAllResourcesInModule(String, Predicate) + * @see #findAllResourcesInClasspathRoot(URI, Predicate, Predicate) + * @see #findAllResourcesInModule(String, Predicate, Predicate) */ @API(status = EXPERIMENTAL, since = "1.11") - public static List findAllResourcesInPackage(String basePackageName, Predicate resourceFilter) { - return ReflectionUtils.findAllResourcesInPackage(basePackageName, resourceFilter); + public static List findAllResourcesInPackage(String basePackageName, Predicate resourceFilter, + Predicate resourceNameFilter) { + + return ReflectionUtils.findAllResourcesInPackage(basePackageName, resourceFilter, resourceNameFilter); } /** @@ -287,16 +297,18 @@ public static Stream> streamAllClassesInPackage(String basePackageName, * scanning; must not be {@code null} and must be valid in terms of Java * syntax * @param resourceFilter the resource type filter; never {@code null} + * @param resourceNameFilter the resource name filter; never {@code null} * @return a stream of all such resources found; never {@code null} * but potentially empty * @since 1.10 - * @see #streamAllResourcesInClasspathRoot(URI, Predicate) - * @see #streamAllResourcesInModule(String, Predicate) + * @see #streamAllResourcesInClasspathRoot(URI, Predicate, Predicate) + * @see #streamAllResourcesInModule(String, Predicate, Predicate) */ @API(status = EXPERIMENTAL, since = "1.11") public static Stream streamAllResourcesInPackage(String basePackageName, - Predicate resourceFilter) { - return ReflectionUtils.streamAllResourcesInPackage(basePackageName, resourceFilter); + Predicate resourceFilter, Predicate resourceNameFilter) { + + return ReflectionUtils.streamAllResourcesInPackage(basePackageName, resourceFilter, resourceNameFilter); } /** @@ -334,15 +346,18 @@ public static List> findAllClassesInModule(String moduleName, Predicate * @param moduleName the name of the module to scan; never {@code null} or * empty * @param resourceFilter the resource type filter; never {@code null} + * @param resourceNameFilter the resource name filter; never {@code null} * @return an immutable list of all such resources found; never {@code null} * but potentially empty * @since 1.1.1 - * @see #findAllResourcesInClasspathRoot(URI, Predicate) - * @see #findAllResourcesInPackage(String, Predicate) + * @see #findAllResourcesInClasspathRoot(URI, Predicate, Predicate) + * @see #findAllResourcesInPackage(String, Predicate, Predicate) */ @API(status = EXPERIMENTAL, since = "1.11") - public static List findAllResourcesInModule(String moduleName, Predicate resourceFilter) { - return ReflectionUtils.findAllResourcesInModule(moduleName, resourceFilter); + public static List findAllResourcesInModule(String moduleName, Predicate resourceFilter, + Predicate resourceNameFilter) { + + return ReflectionUtils.findAllResourcesInModule(moduleName, resourceFilter, resourceNameFilter); } /** @@ -381,15 +396,18 @@ public static Stream> streamAllClassesInModule(String moduleName, Predi * @param moduleName the name of the module to scan; never {@code null} or * empty * @param resourceFilter the resource type filter; never {@code null} + * @param resourceNameFilter the resource name filter; never {@code null} * @return a stream of all such resources found; never {@code null} * but potentially empty * @since 1.10 - * @see #streamAllResourcesInClasspathRoot(URI, Predicate) - * @see #streamAllResourcesInPackage(String, Predicate) + * @see #streamAllResourcesInClasspathRoot(URI, Predicate, Predicate) + * @see #streamAllResourcesInPackage(String, Predicate, Predicate) */ @API(status = EXPERIMENTAL, since = "1.11") - public static Stream streamAllResourcesInModule(String moduleName, Predicate resourceFilter) { - return ReflectionUtils.streamAllResourcesInModule(moduleName, resourceFilter); + public static Stream streamAllResourcesInModule(String moduleName, Predicate resourceFilter, + Predicate resourceNameFilter) { + + return ReflectionUtils.streamAllResourcesInModule(moduleName, resourceFilter, resourceNameFilter); } /** diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/Resource.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/Resource.java index 78c48e4cd608..fc90e7427d6c 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/Resource.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/Resource.java @@ -22,12 +22,12 @@ /** * Represents a resource on the classpath. * - * @see ReflectionSupport#findAllResourcesInClasspathRoot(URI, Predicate) - * @see ReflectionSupport#findAllResourcesInPackage(String, Predicate) - * @see ReflectionSupport#findAllResourcesInModule(String, Predicate) - * @see ReflectionSupport#streamAllResourcesInClasspathRoot(URI, Predicate) - * @see ReflectionSupport#streamAllResourcesInPackage(String, Predicate) - * @see ReflectionSupport#streamAllResourcesInModule(String, Predicate) + * @see ReflectionSupport#findAllResourcesInClasspathRoot(URI, Predicate, Predicate) + * @see ReflectionSupport#findAllResourcesInPackage(String, Predicate, Predicate) + * @see ReflectionSupport#findAllResourcesInModule(String, Predicate, Predicate) + * @see ReflectionSupport#streamAllResourcesInClasspathRoot(URI, Predicate, Predicate) + * @see ReflectionSupport#streamAllResourcesInPackage(String, Predicate, Predicate) + * @see ReflectionSupport#streamAllResourcesInModule(String, Predicate, Predicate) */ @API(status = EXPERIMENTAL, since = "1.11") public interface Resource { diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java index 0940ca5f7d5f..24ae9ed6e59b 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java @@ -207,10 +207,12 @@ private void processResourceFileSafely(Path baseDir, String basePackageName, Res try { String fullyQualifiedResourceName = determineFullyQualifiedResourceName(baseDir, basePackageName, resourceFile); - Resource resource = new ClasspathResource(fullyQualifiedResourceName, resourceFile.toUri()); - // Always use "resourceFilter.test" to include future predicates. - if (resourceFilter.test(resource)) { - resourceConsumer.accept(resource); + if (resourceFilter.match(fullyQualifiedResourceName)) { + Resource resource = new ClasspathResource(fullyQualifiedResourceName, resourceFile.toUri()); + // Always use "resourceFilter.test" to include future predicates. + if (resourceFilter.test(resource)) { + resourceConsumer.accept(resource); + } } } catch (Throwable throwable) { diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java index 72fe812f5cb0..f8f4d2996e58 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java @@ -1054,11 +1054,12 @@ public static List> findAllClassesInClasspathRoot(URI root, Predicate findAllResourcesInClasspathRoot(URI root, Predicate resourceFilter) { + public static List findAllResourcesInClasspathRoot(URI root, Predicate resourceFilter, + Predicate resourceNameFilter) { // unmodifiable since returned by public, non-internal method(s) - return findAllResourcesInClasspathRoot(root, ResourceFilter.of(resourceFilter)); + return findAllResourcesInClasspathRoot(root, ResourceFilter.of(resourceNameFilter, resourceFilter)); } /** @@ -1072,10 +1073,11 @@ public static Stream> streamAllClassesInClasspathRoot(URI root, Predica /** * @since 1.11 - * @see #streamAllResourcesInClasspathRoot(URI, Predicate) + * @see org.junit.platform.commons.support.ReflectionSupport#streamAllResourcesInClasspathRoot(URI, Predicate, Predicate) */ - public static Stream streamAllResourcesInClasspathRoot(URI root, Predicate resourceFilter) { - return streamAllResourcesInClasspathRoot(root, ResourceFilter.of(resourceFilter)); + public static Stream streamAllResourcesInClasspathRoot(URI root, Predicate resourceFilter, + Predicate resourceNameFilter) { + return streamAllResourcesInClasspathRoot(root, ResourceFilter.of(resourceNameFilter, resourceFilter)); } /** @@ -1088,8 +1090,8 @@ public static List> findAllClassesInClasspathRoot(URI root, ClassFilter /** * @since 1.11 */ - public static List findAllResourcesInClasspathRoot(URI root, ResourceFilter resourceFilter) { - return Collections.unmodifiableList(classpathScanner.scanForResourcesInClasspathRoot(root, resourceFilter)); + public static List findAllResourcesInClasspathRoot(URI root, ResourceFilter classFilter) { + return Collections.unmodifiableList(classpathScanner.scanForResourcesInClasspathRoot(root, classFilter)); } /** @@ -1119,9 +1121,10 @@ public static List> findAllClassesInPackage(String basePackageName, Pre * @since 1.11 * @see org.junit.platform.commons.support.ReflectionSupport#findAllClassesInPackage(String, Predicate, Predicate) */ - public static List findAllResourcesInPackage(String basePackageName, Predicate resourceFilter) { + public static List findAllResourcesInPackage(String basePackageName, Predicate resourceFilter, + Predicate resourceNameFilter) { // unmodifiable since returned by public, non-internal method(s) - return findAllResourcesInPackage(basePackageName, ResourceFilter.of(resourceFilter)); + return findAllResourcesInPackage(basePackageName, ResourceFilter.of(resourceNameFilter, resourceFilter)); } /** @@ -1135,11 +1138,11 @@ public static Stream> streamAllClassesInPackage(String basePackageName, /** * since 1.11 - * @see #streamAllResourcesInPackage(String, Predicate) + * @see org.junit.platform.commons.support.ReflectionSupport#streamAllResourcesInPackage(String, Predicate, Predicate) */ public static Stream streamAllResourcesInPackage(String basePackageName, - Predicate resourceFilter) { - return streamAllResourcesInPackage(basePackageName, ResourceFilter.of(resourceFilter)); + Predicate resourceFilter, Predicate resourceNameFilter) { + return streamAllResourcesInPackage(basePackageName, ResourceFilter.of(resourceNameFilter, resourceFilter)); } /** @@ -1183,11 +1186,12 @@ public static List> findAllClassesInModule(String moduleName, Predicate /** * @since 1.11 - * @see #findAllResourcesInModule(String, Predicate) + * @see org.junit.platform.commons.support.ReflectionSupport#findAllResourcesInModule(String, Predicate, Predicate) */ - public static List findAllResourcesInModule(String moduleName, Predicate resourceFilter) { + public static List findAllResourcesInModule(String moduleName, Predicate resourceFilter, + Predicate resourceNameFilter) { // unmodifiable since returned by public, non-internal method(s) - return findAllResourcesInModule(moduleName, ResourceFilter.of(resourceFilter)); + return findAllResourcesInModule(moduleName, ResourceFilter.of(resourceNameFilter, resourceFilter)); } /** @@ -1201,10 +1205,11 @@ public static Stream> streamAllClassesInModule(String moduleName, Predi /** * @since 1.11 - * @see #streamAllResourcesInModule(String, Predicate) + * @see org.junit.platform.commons.support.ReflectionSupport#streamAllResourcesInModule(String, Predicate, Predicate) */ - public static Stream streamAllResourcesInModule(String moduleName, Predicate resourceFilter) { - return streamAllResourcesInModule(moduleName, ResourceFilter.of(resourceFilter)); + public static Stream streamAllResourcesInModule(String moduleName, Predicate resourceFilter, + Predicate resourceNameFilter) { + return streamAllResourcesInModule(moduleName, ResourceFilter.of(resourceNameFilter, resourceFilter)); } /** diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java index ac2775ff876f..bde54890c85e 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java @@ -32,20 +32,42 @@ public class ResourceFilter implements Predicate { /** - * Create a {@link ResourceFilter} instance that filters resources. + * Create a {@link ResourceFilter} instance that accepts all names but filters resources. */ public static ResourceFilter of(Predicate resourcePredicate) { - return new ResourceFilter(resourcePredicate); + return of(name -> true, resourcePredicate); } + /** + * Create a {@link ResourceFilter} instance that filters by resource names and resources. + */ + public static ResourceFilter of(Predicate namePredicate, Predicate resourcePredicate) { + return new ResourceFilter(namePredicate, resourcePredicate); + } + + private final Predicate namePredicate; private final Predicate resourcePredicate; - private ResourceFilter(Predicate resourcePredicate) { + private ResourceFilter(Predicate namePredicate, Predicate resourcePredicate) { + this.namePredicate = Preconditions.notNull(namePredicate, "name predicate must not be null"); this.resourcePredicate = Preconditions.notNull(resourcePredicate, "resource predicate must not be null"); } + public boolean match(String name) { + return namePredicate.test(name); + } + + public boolean match(Resource resource) { + return resourcePredicate.test(resource); + } + + /** + * @implNote This implementation combines all tests stored in the predicates + * of this instance. Any new predicate must be added to this test method as + * well. + */ @Override public boolean test(Resource resource) { - return resourcePredicate.test(resource); + return match(resource.getName()) && match(resource); } } diff --git a/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java b/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java index fbbe0882165f..137c76ec3ddc 100644 --- a/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java +++ b/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java @@ -282,6 +282,7 @@ List scan(ModuleReference reference) { try (Stream names = reader.list()) { // @formatter:off return names.filter(name -> !name.endsWith(".class")) + .filter(resourceFilter::match) .map(this::loadResourceUnchecked) // Always use ".filter(resourceFilter)" to include future predicates. .filter(resourceFilter) diff --git a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java index 132c6b579a47..94c883c81d73 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java @@ -146,8 +146,8 @@ List findAllResourcesInClasspathRootDelegates() throws Throwable { displayName = "..." + displayName.substring(displayName.length() - 42); } tests.add(DynamicTest.dynamicTest(displayName, - () -> assertEquals(ReflectionUtils.findAllResourcesInClasspathRoot(root, allResources), - ReflectionSupport.findAllResourcesInClasspathRoot(root, allResources)))); + () -> assertEquals(ReflectionUtils.findAllResourcesInClasspathRoot(root, allResources, allNames), + ReflectionSupport.findAllResourcesInClasspathRoot(root, allResources, allNames)))); } return tests; } @@ -156,9 +156,11 @@ List findAllResourcesInClasspathRootDelegates() throws Throwable { void findAllResourcesInClasspathRootPreconditions() { var path = Path.of(".").toUri(); assertPreconditionViolationException("root", - () -> ReflectionSupport.findAllResourcesInClasspathRoot(null, allResources)); + () -> ReflectionSupport.findAllResourcesInClasspathRoot(null, allResources, allNames)); assertPreconditionViolationException("resource predicate", - () -> ReflectionSupport.findAllResourcesInClasspathRoot(path, null)); + () -> ReflectionSupport.findAllResourcesInClasspathRoot(path, null, allNames)); + assertPreconditionViolationException("name predicate", + () -> ReflectionSupport.findAllResourcesInClasspathRoot(path, allResources, null)); } @Test @@ -180,18 +182,20 @@ void findAllClassesInPackagePreconditions() { @Test void findAllResourcesInPackageDelegates() { - assertNotEquals(0, ReflectionSupport.findAllResourcesInPackage("org.junit", allResources).size()); + assertNotEquals(0, ReflectionSupport.findAllResourcesInPackage("org.junit", allResources, allNames).size()); - assertEquals(ReflectionUtils.findAllResourcesInPackage("org.junit", allResources), - ReflectionSupport.findAllResourcesInPackage("org.junit", allResources)); + assertEquals(ReflectionUtils.findAllResourcesInPackage("org.junit", allResources, allNames), + ReflectionSupport.findAllResourcesInPackage("org.junit", allResources, allNames)); } @Test void findAllResourcesInPackagePreconditions() { assertPreconditionViolationExceptionForString("basePackageName", - () -> ReflectionSupport.findAllResourcesInPackage(null, allResources)); + () -> ReflectionSupport.findAllResourcesInPackage(null, allResources, allNames)); assertPreconditionViolationException("resource predicate", - () -> ReflectionSupport.findAllResourcesInPackage("org.junit", null)); + () -> ReflectionSupport.findAllResourcesInPackage("org.junit", null, allNames)); + assertPreconditionViolationException("name predicate", + () -> ReflectionSupport.findAllResourcesInPackage("org.junit", allResources, null)); } @Test @@ -213,17 +217,19 @@ void findAllClassesInModulePreconditions() { @Test void findAllResourcesInModuleDelegates() { - assertEquals(ReflectionUtils.findAllResourcesInModule("org.junit.platform.commons", allResources), - ReflectionSupport.findAllResourcesInModule("org.junit.platform.commons", allResources)); + assertEquals(ReflectionUtils.findAllResourcesInModule("org.junit.platform.commons", allResources, allNames), + ReflectionSupport.findAllResourcesInModule("org.junit.platform.commons", allResources, allNames)); } @Test void findAllResourcesInModulePreconditions() { var exception = assertThrows(PreconditionViolationException.class, - () -> ReflectionSupport.findAllResourcesInModule(null, allResources)); + () -> ReflectionSupport.findAllResourcesInModule(null, allResources, allNames)); assertEquals("Module name must not be null or empty", exception.getMessage()); assertPreconditionViolationException("resource predicate", - () -> ReflectionSupport.findAllResourcesInModule("org.junit.platform.commons", null)); + () -> ReflectionSupport.findAllResourcesInModule("org.junit.platform.commons", null, allNames)); + assertPreconditionViolationException("name predicate", + () -> ReflectionSupport.findAllResourcesInModule("org.junit.platform.commons", allResources, null)); } @Test From 767dcf467011b5426327d04b4f6ace3bef690443 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Fri, 14 Jun 2024 12:53:41 +0200 Subject: [PATCH 23/78] Load canonical resources through classloader --- .../commons/support/ReflectionSupport.java | 21 ++++++++ .../commons/util/ClasspathScanner.java | 20 ++++++-- .../commons/util/ReflectionUtils.java | 25 +++++++++- .../commons/util/ClasspathScannerTests.java | 50 ++++++++++++++++--- 4 files changed, 102 insertions(+), 14 deletions(-) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java index ce72026caaf9..10198fd8f133 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java @@ -113,6 +113,27 @@ public static Try> tryToLoadClass(String name, ClassLoader classLoader) return ReflectionUtils.tryToLoadClass(name, classLoader); } + /** + * Tries to load the {@link Resource} for the supplied classpath resource name. + * + *

The name of a classpath resource must follow the semantics + * for resource paths as defined in {@link ClassLoader#getResource(String)}. + * + *

If the supplied classpath resource name is prefixed with a slash + * ({@code /}), the slash will be removed. + * + * @param classpathResourceName the name of the resource to load; never {@code null} or blank + * @param classLoader the {@code ClassLoader} to use; never {@code null} + * @return a successful {@code Try} containing the loaded class or a failed + * {@code Try} containing the exception if no such resource could be loaded; + * never {@code null} + * @since 1.11 + */ + @API(status = EXPERIMENTAL, since = "1.11") + public static Try tryToLoadResource(String classpathResourceName, ClassLoader classLoader) { + return ReflectionUtils.tryToLoadResource(classpathResourceName, classLoader); + } + /** * Find all {@linkplain Class classes} in the supplied classpath {@code root} * that match the specified {@code classFilter} and {@code classNameFilter} diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java index 24ae9ed6e59b..cf3672c162f3 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java @@ -68,12 +68,15 @@ class ClasspathScanner { private final Supplier classLoaderSupplier; private final BiFunction>> loadClass; + private final BiFunction> loadResource; ClasspathScanner(Supplier classLoaderSupplier, - BiFunction>> loadClass) { + BiFunction>> loadClass, + BiFunction> loadResource) { this.classLoaderSupplier = classLoaderSupplier; this.loadClass = loadClass; + this.loadResource = loadResource; } List> scanForClassesInPackage(String basePackageName, ClassFilter classFilter) { @@ -208,10 +211,17 @@ private void processResourceFileSafely(Path baseDir, String basePackageName, Res String fullyQualifiedResourceName = determineFullyQualifiedResourceName(baseDir, basePackageName, resourceFile); if (resourceFilter.match(fullyQualifiedResourceName)) { - Resource resource = new ClasspathResource(fullyQualifiedResourceName, resourceFile.toUri()); - // Always use "resourceFilter.test" to include future predicates. - if (resourceFilter.test(resource)) { - resourceConsumer.accept(resource); + try { + // @formatter:off + loadResource.apply(fullyQualifiedResourceName, getClassLoader()) + .toOptional() + // Always use ".filter(classFilter)" to include future predicates. + .filter(resourceFilter) + .ifPresent(resourceConsumer); + // @formatter:on + } + catch (InternalError internalError) { + handleInternalError(resourceFile, fullyQualifiedResourceName, internalError); } } } diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java index f8f4d2996e58..b0e9a92443ec 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java @@ -35,6 +35,7 @@ import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.net.URI; +import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -56,6 +57,7 @@ import org.apiguardian.api.API; import org.junit.platform.commons.JUnitException; +import org.junit.platform.commons.PreconditionViolationException; import org.junit.platform.commons.function.Try; import org.junit.platform.commons.logging.Logger; import org.junit.platform.commons.logging.LoggerFactory; @@ -146,7 +148,7 @@ public enum HierarchyTraversalMode { private static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; private static final ClasspathScanner classpathScanner = new ClasspathScanner( - ClassLoaderUtils::getDefaultClassLoader, ReflectionUtils::tryToLoadClass); + ClassLoaderUtils::getDefaultClassLoader, ReflectionUtils::tryToLoadClass, ReflectionUtils::tryToLoadResource); /** * Cache for equivalent methods on an interface implemented by the declaring class. @@ -890,6 +892,27 @@ public static Try> tryToLoadClass(String name, ClassLoader classLoader) }); } + /** + * Tries to load the {@link Resource} for the supplied classpath resource name. + * + *

See {@link org.junit.platform.commons.support.ReflectionSupport#tryToLoadResource(String, ClassLoader)} + * for details. + * + * @param classpathResourceName the name of the resource to load; never {@code null} or blank + * @param classLoader the {@code ClassLoader} to use; never {@code null} + * @since 1.11 + */ + @API(status = INTERNAL, since = "1.11") + public static Try tryToLoadResource(String classpathResourceName, ClassLoader classLoader) { + Preconditions.notBlank(classpathResourceName, "Resource name must not be null or blank"); + boolean startsWithSlash = classpathResourceName.startsWith("/"); + URL resource = classLoader.getResource(startsWithSlash ? "/" + classpathResourceName : classpathResourceName); + if (resource == null) { + return Try.failure(new PreconditionViolationException("classLoader.getResource returned null")); + } + return Try.call(() -> new ClasspathResource(classpathResourceName, resource.toURI())); + } + private static Class loadArrayType(ClassLoader classLoader, String componentTypeName, int dimensions) throws ClassNotFoundException { diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java index 347ea2b5ddd5..c50e69605e34 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java @@ -63,12 +63,16 @@ class ClasspathScannerTests { private static final ResourceFilter allResources = ResourceFilter.of(type -> true); private final List> loadedClasses = new ArrayList<>(); + private final List loadedResources = new ArrayList<>(); private final BiFunction>> trackingClassLoader = (name, classLoader) -> ReflectionUtils.tryToLoadClass(name, classLoader).ifSuccess(loadedClasses::add); + private final BiFunction> trackingResourceLoader = (name, + classLoader) -> ReflectionUtils.tryToLoadResource(name, classLoader).ifSuccess(loadedResources::add); + private final ClasspathScanner classpathScanner = new ClasspathScanner(ClassLoaderUtils::getDefaultClassLoader, - trackingClassLoader); + trackingClassLoader, trackingResourceLoader); @Test void scanForClassesInClasspathRootWhenMalformedClassnameInternalErrorOccursWithNullDetailedMessage( @@ -189,7 +193,8 @@ private void scanForClassesInClasspathRootWithinJarFile(String resourceName) thr var jarfile = getClass().getResource(resourceName); try (var classLoader = new URLClassLoader(new URL[] { jarfile })) { - var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass); + var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass, + ReflectionUtils::tryToLoadResource); var classes = classpathScanner.scanForClassesInClasspathRoot(jarfile.toURI(), allClasses); assertThat(classes).extracting(Class::getName) // @@ -213,7 +218,8 @@ private void scanForResourcesInClasspathRootWithinJarFile(String resourceName) t var jarfile = getClass().getResource(resourceName); try (var classLoader = new URLClassLoader(new URL[] { jarfile })) { - var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass); + var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass, + ReflectionUtils::tryToLoadResource); var resources = classpathScanner.scanForResourcesInClasspathRoot(jarfile.toURI(), allResources); assertThat(resources).extracting(Resource::getName) // @@ -270,7 +276,8 @@ private void checkModules2500(ModuleFinder finder) { var parent = ClassLoader.getPlatformClassLoader(); var layer = ModuleLayer.defineModulesWithOneLoader(configuration, List.of(boot), parent).layer(); - var classpathScanner = new ClasspathScanner(() -> layer.findLoader(root), ReflectionUtils::tryToLoadClass); + var classpathScanner = new ClasspathScanner(() -> layer.findLoader(root), ReflectionUtils::tryToLoadClass, + ReflectionUtils::tryToLoadResource); { var classes = classpathScanner.scanForClassesInPackage("foo", allClasses); var classNames = classes.stream().map(Class::getName).collect(Collectors.toList()); @@ -289,7 +296,8 @@ void findAllClassesInPackageWithinJarFileConcurrently() throws Exception { var jarUri = URI.create("jar:" + jarFile); try (var classLoader = new URLClassLoader(new URL[] { jarFile })) { - var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass); + var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass, + ReflectionUtils::tryToLoadResource); var results = executeConcurrently(10, () -> classpathScanner.scanForClassesInPackage("org.junit.platform.jartest.included", allClasses)); @@ -314,7 +322,8 @@ void findAllResourcesInPackageWithinJarFileConcurrently() throws Exception { var jarUri = URI.create("jar:" + jarFile); try (var classLoader = new URLClassLoader(new URL[] { jarFile })) { - var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass); + var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass, + ReflectionUtils::tryToLoadResource); var results = executeConcurrently(10, () -> classpathScanner.scanForResourcesInPackage("org.junit.platform.jartest.included", allResources)); @@ -416,14 +425,16 @@ void scanForClassesInPackageForNullClassFilter() { @Test void scanForClassesInPackageWhenIOExceptionOccurs() { - var scanner = new ClasspathScanner(ThrowingClassLoader::new, ReflectionUtils::tryToLoadClass); + var scanner = new ClasspathScanner(ThrowingClassLoader::new, ReflectionUtils::tryToLoadClass, + ReflectionUtils::tryToLoadResource); var classes = scanner.scanForClassesInPackage("org.junit.platform.commons", allClasses); assertThat(classes).isEmpty(); } @Test void scanForResourcesInPackageWhenIOExceptionOccurs() { - var scanner = new ClasspathScanner(ThrowingClassLoader::new, ReflectionUtils::tryToLoadClass); + var scanner = new ClasspathScanner(ThrowingClassLoader::new, ReflectionUtils::tryToLoadClass, + ReflectionUtils::tryToLoadResource); var classes = scanner.scanForResourcesInPackage("org.junit.platform.commons", allResources); assertThat(classes).isEmpty(); } @@ -438,6 +449,17 @@ void scanForClassesInPackageOnlyLoadsClassesThatAreIncludedByTheClassNameFilter( assertThat(loadedClasses).containsExactly(ClasspathScannerTests.class); } + @Test + void scanForResourcesInPackageOnlyLoadsResourcesThatAreIncludedByTheResourceNameFilter() { + Predicate resourceNameFilter = name -> name.endsWith("/example.resource"); + var resourceFilter = ResourceFilter.of(resourceNameFilter, type -> true); + + classpathScanner.scanForResourcesInPackage("org.junit.platform.commons", resourceFilter); + + assertThat(loadedResources).extracting(Resource::getName).containsExactly( + "org/junit/platform/commons/example.resource"); + } + @Test void findAllClassesInClasspathRoot() throws Exception { var thisClassOnly = ClassFilter.of(clazz -> clazz == ClasspathScannerTests.class); @@ -519,6 +541,18 @@ void onlyLoadsClassesInClasspathRootThatAreIncludedByTheClassNameFilter() throws assertThat(loadedClasses).containsExactly(ClasspathScannerTests.class); } + @Test + void onlyLoadsResourcesInClasspathRootThatAreIncludedByTheResourceNameFilter() { + Predicate resourceNameFilter = name -> name.endsWith("/example.resource"); + var resourceFilter = ResourceFilter.of(resourceNameFilter, type -> true); + var root = getTestClasspathResourceRoot(); + + classpathScanner.scanForResourcesInClasspathRoot(root, resourceFilter); + + assertThat(loadedResources).extracting(Resource::getName).containsExactly( + "org/junit/platform/commons/example.resource"); + } + private static URI uriOf(String name) { var resource = ClasspathScannerTests.class.getResource(name); try { From 5348738cdaf77a463fcc321d9642e2bd6afec139 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Fri, 14 Jun 2024 13:10:13 +0200 Subject: [PATCH 24/78] Touch up --- .../java/org/junit/platform/commons/util/ClasspathScanner.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java index cf3672c162f3..f2e8cc2c5458 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java @@ -215,7 +215,7 @@ private void processResourceFileSafely(Path baseDir, String basePackageName, Res // @formatter:off loadResource.apply(fullyQualifiedResourceName, getClassLoader()) .toOptional() - // Always use ".filter(classFilter)" to include future predicates. + // Always use ".filter(resourceFilter)" to include future predicates. .filter(resourceFilter) .ifPresent(resourceConsumer); // @formatter:on From 94215bce9a4590696fa381343ed5103635e381df Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Fri, 14 Jun 2024 13:11:46 +0200 Subject: [PATCH 25/78] Touch up --- .../java/org/junit/platform/commons/util/ClasspathScanner.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java index cf3672c162f3..f2e8cc2c5458 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java @@ -215,7 +215,7 @@ private void processResourceFileSafely(Path baseDir, String basePackageName, Res // @formatter:off loadResource.apply(fullyQualifiedResourceName, getClassLoader()) .toOptional() - // Always use ".filter(classFilter)" to include future predicates. + // Always use ".filter(resourceFilter)" to include future predicates. .filter(resourceFilter) .ifPresent(resourceConsumer); // @formatter:on From 794793a9f396f60acd5f451e8305deecbd71b062 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Fri, 14 Jun 2024 15:51:36 +0200 Subject: [PATCH 26/78] Correctly resolve shadowed resources --- .../commons/util/ClasspathScannerTests.java | 41 +++++++++++++++++- .../src/test/resources/jartest-shadowed.jar | Bin 0 -> 2103 bytes 2 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 platform-tests/src/test/resources/jartest-shadowed.jar diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java index c50e69605e34..b89c343bb300 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java @@ -192,7 +192,7 @@ void scanForClassesInClasspathRootWithinJarWithSpacesInPath() throws Exception { private void scanForClassesInClasspathRootWithinJarFile(String resourceName) throws Exception { var jarfile = getClass().getResource(resourceName); - try (var classLoader = new URLClassLoader(new URL[] { jarfile })) { + try (var classLoader = new URLClassLoader(new URL[] { jarfile }, null)) { var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass, ReflectionUtils::tryToLoadResource); @@ -217,7 +217,7 @@ void scanForResourcesInClasspathRootWithinJarWithSpacesInPath() throws Exception private void scanForResourcesInClasspathRootWithinJarFile(String resourceName) throws Exception { var jarfile = getClass().getResource(resourceName); - try (var classLoader = new URLClassLoader(new URL[] { jarfile })) { + try (var classLoader = new URLClassLoader(new URL[] { jarfile }, null)) { var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass, ReflectionUtils::tryToLoadResource); @@ -230,6 +230,43 @@ private void scanForResourcesInClasspathRootWithinJarFile(String resourceName) t } } + @Test + void scanForResourcesInShadowedClassPathRoot() throws Exception { + var jarFile = getClass().getResource("/jartest.jar"); + var shadowedJarFile = getClass().getResource("/jartest-shadowed.jar"); + + try (var classLoader = new URLClassLoader(new URL[] { jarFile, shadowedJarFile }, null)) { + var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass, + ReflectionUtils::tryToLoadResource); + + var resources = classpathScanner.scanForResourcesInClasspathRoot(shadowedJarFile.toURI(), allResources); + assertThat(resources).extracting(Resource::getName).containsExactlyInAnyOrder( + "org/junit/platform/jartest/included/unique.resource", + "org/junit/platform/jartest/included/included.resource", + "org/junit/platform/jartest/included/recursive/recursively-included.resource", "META-INF/MANIFEST.MF"); + + assertThat(resources).extracting(Resource::getUri) // + .map(ClasspathScannerTests::jarFileAndEntry) // + .containsExactlyInAnyOrder( + // This resource only exists in the shadowed jar file + "jartest-shadowed.jar!/org/junit/platform/jartest/included/unique.resource", + // These resources exist in both the jar and shadowed jar file. + // So they're discovered in the shadowed jar, but loaded from the regular jar. + "jartest.jar!/org/junit/platform/jartest/included/included.resource", + "jartest.jar!/org/junit/platform/jartest/included/recursive/recursively-included.resource", + "jartest.jar!/META-INF/MANIFEST.MF"); + } + } + + private static String jarFileAndEntry(URI uri) { + var uriString = uri.toString(); + int lastJarUriSeparator = uriString.lastIndexOf("!/"); + var jarUri = uriString.substring(0, lastJarUriSeparator); + var jarEntry = uriString.substring(lastJarUriSeparator + 1); + var fileName = jarUri.substring(jarUri.lastIndexOf("/") + 1); + return fileName + "!" + jarEntry; + } + @Test void scanForClassesInPackage() { var classes = classpathScanner.scanForClassesInPackage("org.junit.platform.commons", allClasses); diff --git a/platform-tests/src/test/resources/jartest-shadowed.jar b/platform-tests/src/test/resources/jartest-shadowed.jar new file mode 100644 index 0000000000000000000000000000000000000000..8a13258b5759924e09e0a4d7b552c2f634dbebaf GIT binary patch literal 2103 zcmWIWW@Zs#VBp|jV2k?T!2kqIAOZ+D8CV#6T|*poJ^kGD|D9rBU}gwFQT+28_g`nA zLKh$g8i7#k>*(j{<{BKL=j-;__snS@Z(Y5MyxzK6=gyqp9At3C_`%a6JuhD!Pv48B zt5`TAUPvB^meR`jA+D3UU%l((;RP@o137t|2S2s3f%*pG_+GHD=}| z=aikg+5)=o4Vwr;>zvf)Ti`pI)3n0%5h)o$} zkOCPVc(Aa5n*d|z6{QyEmlh?bhK6u5Fe|#}q=9g01vdjD%L`@(1~9>W@`O&9#<>&v zXFUTwyjV901qXdP9o#s_t94RONb902kN#X*^dzKp%c4Iqt!s`fnsnunkgdX5R#*}R zIx`#1nchS?6A^B3R!*fZcE?Kr9S*`&bUY}@0>hy4T*RA2X1<`v24Q0&9S=m% z93=(F(FlN2ZlG&LFE2*Ym>Ead`=0o;BAr7;AU zL8OWB41(8eP$7c=Pw<v literal 0 HcmV?d00001 From c0f1c3a48270bbb4ba6f81e031170b93f2e4cf01 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Fri, 14 Jun 2024 22:25:50 +0200 Subject: [PATCH 27/78] Fix formatting --- ...ResourceContainerSelectorResolverTest.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/platform-tests/src/test/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolverTest.java b/platform-tests/src/test/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolverTest.java index cb4682b02a8c..b629250214e8 100644 --- a/platform-tests/src/test/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolverTest.java +++ b/platform-tests/src/test/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolverTest.java @@ -17,7 +17,9 @@ import static org.junit.platform.engine.support.discovery.SelectorResolver.Match.exact; import static org.junit.platform.engine.support.discovery.SelectorResolver.Resolution.match; +import java.io.IOException; import java.net.URI; +import java.nio.file.Files; import java.nio.file.Path; import java.util.Collections; import java.util.Optional; @@ -29,6 +31,7 @@ import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.UniqueId; import org.junit.platform.engine.discovery.ClasspathResourceSelector; +import org.junit.platform.engine.discovery.PackageNameFilter; import org.junit.platform.engine.support.descriptor.EngineDescriptor; import org.junit.platform.fakes.TestDescriptorStub; import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder; @@ -38,12 +41,11 @@ class ResourceContainerSelectorResolverTest { final TestDescriptor engineDescriptor = new EngineDescriptor(UniqueId.forEngine("resource-engine"), "Resource Engine"); final Predicate isResource = resource -> resource.getName().endsWith(".resource"); - // @formatter:off - final EngineDiscoveryRequestResolver resolver = EngineDiscoveryRequestResolver.builder() - .addResourceContainerSelectorResolver(isResource) - .addSelectorResolver(new ResourceSelectorResolver()) - .build(); - // @formatter:on + + final EngineDiscoveryRequestResolver resolver = EngineDiscoveryRequestResolver.builder() // + .addResourceContainerSelectorResolver(isResource) // + .addSelectorResolver(new ResourceSelectorResolver()) // + .build(); @Test void shouldDiscoverAllResourcesInPackage() { @@ -130,11 +132,9 @@ private Set getTestClasspathResourceRoot() { private static class ResourceSelectorResolver implements SelectorResolver { @Override public Resolution resolve(ClasspathResourceSelector selector, Context context) { - // @formatter:off - return context.addToParent(parent -> createTestDescriptor(parent, selector.getClasspathResourceName())) - .map(testDescriptor -> match(exact(testDescriptor))) - .orElseGet(Resolution::unresolved); - // @formatter:on + return context.addToParent(parent -> createTestDescriptor(parent, selector.getClasspathResourceName())) // + .map(testDescriptor -> match(exact(testDescriptor))) // + .orElseGet(Resolution::unresolved); } private static Optional createTestDescriptor(TestDescriptor parent, From 6676283ab403f1ac18d9263c72235646c093b2b2 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Fri, 14 Jun 2024 22:35:00 +0200 Subject: [PATCH 28/78] Remove spurious whitespace changes --- .../junit/platform/commons/support/ReflectionSupport.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java index 896ed6170001..05e9f5cb5f15 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java @@ -197,6 +197,7 @@ public static List> findAllClassesInClasspathRoot(URI root, Predicate findAllResourcesInClasspathRoot(URI root, Predicate resourceFilter, Predicate resourceNameFilter) { + return ReflectionUtils.findAllResourcesInClasspathRoot(root, resourceFilter, resourceNameFilter); } @@ -246,6 +247,7 @@ public static Stream> streamAllClassesInClasspathRoot(URI root, Predica @API(status = EXPERIMENTAL, since = "1.11") public static Stream streamAllResourcesInClasspathRoot(URI root, Predicate resourceFilter, Predicate resourceNameFilter) { + return ReflectionUtils.streamAllResourcesInClasspathRoot(root, resourceFilter, resourceNameFilter); } @@ -269,6 +271,7 @@ public static Stream streamAllResourcesInClasspathRoot(URI root, Predi */ public static List> findAllClassesInPackage(String basePackageName, Predicate> classFilter, Predicate classNameFilter) { + return ReflectionUtils.findAllClassesInPackage(basePackageName, classFilter, classNameFilter); } @@ -293,6 +296,7 @@ public static List> findAllClassesInPackage(String basePackageName, Pre @API(status = EXPERIMENTAL, since = "1.11") public static List findAllResourcesInPackage(String basePackageName, Predicate resourceFilter, Predicate resourceNameFilter) { + return ReflectionUtils.findAllResourcesInPackage(basePackageName, resourceFilter, resourceNameFilter); } @@ -344,6 +348,7 @@ public static Stream> streamAllClassesInPackage(String basePackageName, @API(status = EXPERIMENTAL, since = "1.11") public static Stream streamAllResourcesInPackage(String basePackageName, Predicate resourceFilter, Predicate resourceNameFilter) { + return ReflectionUtils.streamAllResourcesInPackage(basePackageName, resourceFilter, resourceNameFilter); } @@ -392,6 +397,7 @@ public static List> findAllClassesInModule(String moduleName, Predicate @API(status = EXPERIMENTAL, since = "1.11") public static List findAllResourcesInModule(String moduleName, Predicate resourceFilter, Predicate resourceNameFilter) { + return ReflectionUtils.findAllResourcesInModule(moduleName, resourceFilter, resourceNameFilter); } @@ -441,6 +447,7 @@ public static Stream> streamAllClassesInModule(String moduleName, Predi @API(status = EXPERIMENTAL, since = "1.11") public static Stream streamAllResourcesInModule(String moduleName, Predicate resourceFilter, Predicate resourceNameFilter) { + return ReflectionUtils.streamAllResourcesInModule(moduleName, resourceFilter, resourceNameFilter); } From ac77e69d1aae3da121dfbf08e9bcc42d86943d32 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Fri, 14 Jun 2024 22:39:46 +0200 Subject: [PATCH 29/78] Fixup changelog --- .../docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc | 2 -- .../docs/asciidoc/release-notes/release-notes-5.11.0-M3.adoc | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc index 908a0551f5b1..7d6dc35b0602 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc @@ -60,8 +60,6 @@ page in the Wiki. actual type and value in addition to the required type. * Updated `open-test-reporting` dependency to `0.1.0-M2`. -* `ReflectionSupport` now supports scanning for classpath resources. - [[release-notes-5.11.0-M1-junit-jupiter]] === JUnit Jupiter diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M3.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M3.adoc index 11f17150547e..3d7feffb50c3 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M3.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M3.adoc @@ -29,6 +29,7 @@ repository on GitHub. * New `rootCause()` condition in `TestExecutionResultConditions` that matches if an exception's _root_ cause matches all supplied conditions, for use with the `EngineTestKit`. +* `ReflectionSupport` now supports scanning for classpath resources. [[release-notes-5.11.0-M3-junit-jupiter]] From 16edf0d43c2c58d2670a05339f43ff6939f2a656 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Fri, 14 Jun 2024 22:41:27 +0200 Subject: [PATCH 30/78] Fix imports --- .../docs/asciidoc/release-notes/release-notes-5.11.0-M3.adoc | 1 + .../discovery/ResourceContainerSelectorResolverTest.java | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M3.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M3.adoc index 3d7feffb50c3..1bc289877615 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M3.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M3.adoc @@ -30,6 +30,7 @@ repository on GitHub. exception's _root_ cause matches all supplied conditions, for use with the `EngineTestKit`. * `ReflectionSupport` now supports scanning for classpath resources. +* `ReflectionSupport` now supports scanning for classpath resources. [[release-notes-5.11.0-M3-junit-jupiter]] diff --git a/platform-tests/src/test/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolverTest.java b/platform-tests/src/test/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolverTest.java index b629250214e8..9a6b8881699e 100644 --- a/platform-tests/src/test/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolverTest.java +++ b/platform-tests/src/test/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolverTest.java @@ -17,9 +17,7 @@ import static org.junit.platform.engine.support.discovery.SelectorResolver.Match.exact; import static org.junit.platform.engine.support.discovery.SelectorResolver.Resolution.match; -import java.io.IOException; import java.net.URI; -import java.nio.file.Files; import java.nio.file.Path; import java.util.Collections; import java.util.Optional; @@ -31,7 +29,6 @@ import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.UniqueId; import org.junit.platform.engine.discovery.ClasspathResourceSelector; -import org.junit.platform.engine.discovery.PackageNameFilter; import org.junit.platform.engine.support.descriptor.EngineDescriptor; import org.junit.platform.fakes.TestDescriptorStub; import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder; From c18dfb979ab1d342d8228306db017b85952e8af1 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Fri, 14 Jun 2024 22:46:35 +0200 Subject: [PATCH 31/78] Update changelog --- .../docs/asciidoc/release-notes/release-notes-5.11.0-M3.adoc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M3.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M3.adoc index 1bc289877615..4c64388bf149 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M3.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M3.adoc @@ -30,7 +30,9 @@ repository on GitHub. exception's _root_ cause matches all supplied conditions, for use with the `EngineTestKit`. * `ReflectionSupport` now supports scanning for classpath resources. -* `ReflectionSupport` now supports scanning for classpath resources. +* New `addResourceContainerSelectorResolver()` in `EngineDiscoveryRequestResolver.Builder` to + support the discovery of class path resource based tests, analogous to the + `addClassContainerSelectorResolver()`. [[release-notes-5.11.0-M3-junit-jupiter]] From 0b59daff2fb97db52d7f04c64b1b9b6b58d2f394 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Sat, 15 Jun 2024 00:02:01 +0200 Subject: [PATCH 32/78] Touch up javadoc --- .../java/org/junit/platform/commons/util/ReflectionUtils.java | 2 +- .../platform/engine/discovery/ClasspathResourceSelector.java | 2 ++ .../org/junit/platform/engine/discovery/DiscoverySelectors.java | 1 + .../support/discovery/EngineDiscoveryRequestResolver.java | 2 ++ 4 files changed, 6 insertions(+), 1 deletion(-) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java index 6bfcf89a1d83..801b2c9fee40 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java @@ -899,7 +899,7 @@ public static Try> tryToLoadClass(String name, ClassLoader classLoader) * @since 1.11 * @see org.junit.platform.commons.support.ReflectionSupport#tryToLoadResource(String, ClassLoader) */ - @API(status = INTERNAL, since = "1.4") + @API(status = INTERNAL, since = "1.11") public static Try tryToLoadResource(String classpathResourceName) { return tryToLoadResource(classpathResourceName, ClassLoaderUtils.getDefaultClassLoader()); } diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java index 2eeb41d4c0f0..ee1f415d91df 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java @@ -83,6 +83,8 @@ public String getClasspathResourceName() { * method attempts to lazily load the {@link Resource} based on its name and * throws a {@link PreconditionViolationException} if the resource cannot * be loaded. + * + * @since 1.11 */ @API(status = EXPERIMENTAL, since = "1.11") public Resource getClasspathResource() { diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java index d75283446f8e..fe8d288942d6 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java @@ -339,6 +339,7 @@ public static ClasspathResourceSelector selectClasspathResource(String classpath * @see #selectClasspathResource(String) * @see ClasspathResourceSelector * @see org.junit.platform.commons.support.ReflectionSupport#tryToLoadResource(String) + * @since 1.11 */ @API(status = EXPERIMENTAL, since = "1.11") public static ClasspathResourceSelector selectClasspathResource(Resource classpathResource) { diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/EngineDiscoveryRequestResolver.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/EngineDiscoveryRequestResolver.java index 31adf7e6effb..0947f19ad675 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/EngineDiscoveryRequestResolver.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/EngineDiscoveryRequestResolver.java @@ -173,6 +173,7 @@ public Builder addClassContainerSelectorResolver(Predicate> classFil * @param resourceFilter predicate the resolved classes must satisfy; never * {@code null} * @return this builder for method chaining + * @since 1.11 */ @API(status = EXPERIMENTAL, since = "1.11") public Builder addResourceContainerSelectorResolver(Predicate resourceFilter) { @@ -275,6 +276,7 @@ public interface InitializationContext { * * @return the predicate for filtering the resolved resource names; never * {@code null} + * @since 1.11 */ @API(status = EXPERIMENTAL, since = "1.11") Predicate getPackageFilter(); From 79f13bfa7a168bef9552d63a133e21d5ed71c277 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Sat, 15 Jun 2024 00:12:44 +0200 Subject: [PATCH 33/78] Fix up java doc --- .../release-notes-5.11.0-M1.adoc | 1 + .../commons/support/ReflectionSupport.java | 10 ++++++---- .../platform/commons/support/Resource.java | 2 +- .../platform/commons/util/ModuleUtils.java | 1 + .../platform/commons/util/ModuleUtils.java | 1 + .../commons/util/ClasspathScannerTests.java | 19 ++++++++----------- 6 files changed, 18 insertions(+), 16 deletions(-) diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc index 7d6dc35b0602..332a1c2e8e81 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc @@ -60,6 +60,7 @@ page in the Wiki. actual type and value in addition to the required type. * Updated `open-test-reporting` dependency to `0.1.0-M2`. + [[release-notes-5.11.0-M1-junit-jupiter]] === JUnit Jupiter diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java index 10198fd8f133..67bdcc2aee9f 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java @@ -171,6 +171,7 @@ public static List> findAllClassesInClasspathRoot(URI root, Predicate> streamAllClassesInClasspathRoot(URI root, Predica * @param resourceNameFilter the resources name filter; never {@code null} * @return a stream of all such classes found; never {@code null} * but potentially empty - * @since 1.10 + * @since 1.11 * @see #streamAllResourcesInPackage(String, Predicate, Predicate) * @see #streamAllResourcesInModule(String, Predicate, Predicate) */ @@ -270,6 +271,7 @@ public static List> findAllClassesInPackage(String basePackageName, Pre * @param resourceNameFilter the resource name filter; never {@code null} * @return an immutable list of all such classes found; never {@code null} * but potentially empty + * @since 1.11 * @see #findAllResourcesInClasspathRoot(URI, Predicate, Predicate) * @see #findAllResourcesInModule(String, Predicate, Predicate) */ @@ -321,7 +323,7 @@ public static Stream> streamAllClassesInPackage(String basePackageName, * @param resourceNameFilter the resource name filter; never {@code null} * @return a stream of all such resources found; never {@code null} * but potentially empty - * @since 1.10 + * @since 1.11 * @see #streamAllResourcesInClasspathRoot(URI, Predicate, Predicate) * @see #streamAllResourcesInModule(String, Predicate, Predicate) */ @@ -370,7 +372,7 @@ public static List> findAllClassesInModule(String moduleName, Predicate * @param resourceNameFilter the resource name filter; never {@code null} * @return an immutable list of all such resources found; never {@code null} * but potentially empty - * @since 1.1.1 + * @since 1.11 * @see #findAllResourcesInClasspathRoot(URI, Predicate, Predicate) * @see #findAllResourcesInPackage(String, Predicate, Predicate) */ @@ -420,7 +422,7 @@ public static Stream> streamAllClassesInModule(String moduleName, Predi * @param resourceNameFilter the resource name filter; never {@code null} * @return a stream of all such resources found; never {@code null} * but potentially empty - * @since 1.10 + * @since 1.11 * @see #streamAllResourcesInClasspathRoot(URI, Predicate, Predicate) * @see #streamAllResourcesInPackage(String, Predicate, Predicate) */ diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/Resource.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/Resource.java index fc90e7427d6c..68ffec8d0559 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/Resource.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/Resource.java @@ -21,7 +21,7 @@ /** * Represents a resource on the classpath. - * + * @since 1.11 * @see ReflectionSupport#findAllResourcesInClasspathRoot(URI, Predicate, Predicate) * @see ReflectionSupport#findAllResourcesInPackage(String, Predicate, Predicate) * @see ReflectionSupport#findAllResourcesInModule(String, Predicate, Predicate) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ModuleUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ModuleUtils.java index bf083e63bed4..ae50731a0866 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ModuleUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ModuleUtils.java @@ -106,6 +106,7 @@ public static List> findAllClassesInModule(String moduleName, ClassFilt * @param filter the class filter to apply; never {@code null} * @return an immutable list of all such resources found; never {@code null} * but potentially empty + * @since 1.11 */ @API(status = INTERNAL, since = "1.11") public static List findAllResourcesInModule(String moduleName, ResourceFilter filter) { diff --git a/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java b/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java index 137c76ec3ddc..9a5a70fc725c 100644 --- a/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java +++ b/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java @@ -125,6 +125,7 @@ public static List> findAllClassesInModule(String moduleName, ClassFilt * @param filter the class filter to apply; never {@code null} * @return an immutable list of all such resources found; never {@code null} * but potentially empty + * @since 1.11 */ @API(status = INTERNAL, since = "1.11") public static List findAllResourcesInModule(String moduleName, ResourceFilter filter) { diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java index b89c343bb300..47ea5fa864f8 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java @@ -241,9 +241,10 @@ void scanForResourcesInShadowedClassPathRoot() throws Exception { var resources = classpathScanner.scanForResourcesInClasspathRoot(shadowedJarFile.toURI(), allResources); assertThat(resources).extracting(Resource::getName).containsExactlyInAnyOrder( - "org/junit/platform/jartest/included/unique.resource", - "org/junit/platform/jartest/included/included.resource", - "org/junit/platform/jartest/included/recursive/recursively-included.resource", "META-INF/MANIFEST.MF"); + "org/junit/platform/jartest/included/unique.resource", // + "org/junit/platform/jartest/included/included.resource", // + "org/junit/platform/jartest/included/recursive/recursively-included.resource", // + "META-INF/MANIFEST.MF"); assertThat(resources).extracting(Resource::getUri) // .map(ClasspathScannerTests::jarFileAndEntry) // @@ -342,14 +343,10 @@ void findAllClassesInPackageWithinJarFileConcurrently() throws Exception { assertThrows(FileSystemNotFoundException.class, () -> FileSystems.getFileSystem(jarUri), "FileSystem should be closed"); - // @formatter:off - results.forEach(classes -> assertThat(classes) - .hasSize(2) - .extracting(Class::getSimpleName).containsExactlyInAnyOrder( - "Included", - "RecursivelyIncluded" - )); - // @formatter:on + results.forEach(classes -> assertThat(classes) // + .hasSize(2) // + .extracting(Class::getSimpleName) // + .containsExactlyInAnyOrder("Included", "RecursivelyIncluded")); } } From 46659cd2b1c05d39aae352e4d05f8c5e41db66c5 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Sat, 15 Jun 2024 00:19:48 +0200 Subject: [PATCH 34/78] Fix formatting --- .../engine/discovery/ClasspathResourceSelector.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java index ee1f415d91df..b13431939385 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java @@ -90,10 +90,10 @@ public String getClasspathResourceName() { public Resource getClasspathResource() { if (this.classpathResource == null) { // @formatter:off - Try tryToLoadResource = ReflectionUtils.tryToLoadResource(this.classpathResourceName); - this.classpathResource = tryToLoadResource.getOrThrow(cause -> - new PreconditionViolationException("Could not load resource with name: " + this.classpathResourceName, cause)); - // @formatter:on + Try tryToLoadResource = ReflectionUtils.tryToLoadResource(this.classpathResourceName); + this.classpathResource = tryToLoadResource.getOrThrow(cause -> + new PreconditionViolationException("Could not load resource with name: " + this.classpathResourceName, cause)); + // @formatter:on } return this.classpathResource; } From 2355b7c112df1f0e492ebdea3f5dd29f840fa848 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Sat, 15 Jun 2024 00:22:04 +0200 Subject: [PATCH 35/78] Fix check style --- .../org/junit/platform/engine/discovery/DiscoverySelectors.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java index fe8d288942d6..d1ed0141cd60 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java @@ -335,11 +335,11 @@ public static ClasspathResourceSelector selectClasspathResource(String classpath * {@linkplain Thread thread} that uses the resulting selector. * * @param classpathResource the classpath resource; never {@code null} + * @since 1.11 * @see #selectClasspathResource(String, FilePosition) * @see #selectClasspathResource(String) * @see ClasspathResourceSelector * @see org.junit.platform.commons.support.ReflectionSupport#tryToLoadResource(String) - * @since 1.11 */ @API(status = EXPERIMENTAL, since = "1.11") public static ClasspathResourceSelector selectClasspathResource(Resource classpathResource) { From d200e234d4a1bedf681e4045bbde413e2c26f0dd Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Sat, 15 Jun 2024 00:44:00 +0200 Subject: [PATCH 36/78] Fix typo --- .../support/discovery/EngineDiscoveryRequestResolver.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/EngineDiscoveryRequestResolver.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/EngineDiscoveryRequestResolver.java index 0947f19ad675..9525cd76992f 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/EngineDiscoveryRequestResolver.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/EngineDiscoveryRequestResolver.java @@ -270,7 +270,7 @@ public interface InitializationContext { Predicate getClassNameFilter(); /** - * Get the class package filter built from the {@link PackageNameFilter + * Get the package name filter built from the {@link PackageNameFilter * PackageNameFilters} in the {@link EngineDiscoveryRequest} that is * about to be resolved. * From 966e21f6a17be529e2052c93ae32aed12a294334 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Sat, 15 Jun 2024 14:00:20 +0200 Subject: [PATCH 37/78] Fix tryToLoadResource --- .../commons/util/ReflectionUtils.java | 9 ++-- .../commons/util/ReflectionUtilsTests.java | 41 +++++++++++++++++++ 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java index b0e9a92443ec..1a2222518898 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java @@ -905,12 +905,15 @@ public static Try> tryToLoadClass(String name, ClassLoader classLoader) @API(status = INTERNAL, since = "1.11") public static Try tryToLoadResource(String classpathResourceName, ClassLoader classLoader) { Preconditions.notBlank(classpathResourceName, "Resource name must not be null or blank"); + Preconditions.notNull(classLoader, "ClassLoader must not be null"); boolean startsWithSlash = classpathResourceName.startsWith("/"); - URL resource = classLoader.getResource(startsWithSlash ? "/" + classpathResourceName : classpathResourceName); + String canonicalClasspathResourceName = (startsWithSlash ? classpathResourceName.substring(1) + : classpathResourceName); + URL resource = classLoader.getResource(canonicalClasspathResourceName); if (resource == null) { - return Try.failure(new PreconditionViolationException("classLoader.getResource returned null")); + return Try.failure(new NullPointerException("classLoader.getResource returned null")); } - return Try.call(() -> new ClasspathResource(classpathResourceName, resource.toURI())); + return Try.call(() -> new ClasspathResource(canonicalClasspathResourceName, resource.toURI())); } private static Class loadArrayType(ClassLoader classLoader, String componentTypeName, int dimensions) diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java index 394c7f73aaa9..7ab8aa5e893a 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java @@ -16,6 +16,7 @@ import static java.util.stream.Collectors.toList; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -709,6 +710,46 @@ private void privateMethod() { } + @Nested + class ResourceLoadingTests { + + @Test + void tryToLoadResourcePreconditions() { + assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.tryToLoadResource("", null)); + assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.tryToLoadResource(" ", null)); + + assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.tryToLoadResource(null, null)); + assertThrows(PreconditionViolationException.class, + () -> ReflectionUtils.tryToLoadResource("org/junit/platform/commons/example.resource", null)); + } + + @Test + void tryToLoadResource() { + var classLoader = ClassLoaderUtils.getDefaultClassLoader(); + var tryToLoadResource = ReflectionUtils.tryToLoadResource("org/junit/platform/commons/example.resource", + classLoader); + var resource = assertDoesNotThrow(tryToLoadResource::get); + assertThat(resource.getName()).isEqualTo("org/junit/platform/commons/example.resource"); + } + + @Test + void tryToLoadResourceWithPrefixedSlash() { + var classLoader = ClassLoaderUtils.getDefaultClassLoader(); + var tryToLoadResource = ReflectionUtils.tryToLoadResource("/org/junit/platform/commons/example.resource", + classLoader); + var resource = assertDoesNotThrow(tryToLoadResource::get); + assertThat(resource.getName()).isEqualTo("org/junit/platform/commons/example.resource"); + } + + @Test + void tryToLoadResourceWhenResourceNotFound() { + var classLoader = ClassLoaderUtils.getDefaultClassLoader(); + var tryToLoadResource = ReflectionUtils.tryToLoadResource("org/junit/platform/commons/no-such.resource", + classLoader); + assertThrows(NullPointerException.class, tryToLoadResource::get); + } + } + @Nested class ClassLoadingTests { From 358693f841ee61a94c900a4ad9a8aea9ff79fbb8 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Sat, 15 Jun 2024 14:18:16 +0200 Subject: [PATCH 38/78] Wrap class loader call in try --- .../platform/commons/util/ReflectionUtils.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java index 1a2222518898..f55718fae475 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java @@ -909,11 +909,14 @@ public static Try tryToLoadResource(String classpathResourceName, Clas boolean startsWithSlash = classpathResourceName.startsWith("/"); String canonicalClasspathResourceName = (startsWithSlash ? classpathResourceName.substring(1) : classpathResourceName); - URL resource = classLoader.getResource(canonicalClasspathResourceName); - if (resource == null) { - return Try.failure(new NullPointerException("classLoader.getResource returned null")); - } - return Try.call(() -> new ClasspathResource(canonicalClasspathResourceName, resource.toURI())); + + return Try.call(() -> { + URL resource = classLoader.getResource(canonicalClasspathResourceName); + if (resource == null) { + throw new NullPointerException("classLoader.getResource returned null"); + } + return new ClasspathResource(canonicalClasspathResourceName, resource.toURI()); + }); } private static Class loadArrayType(ClassLoader classLoader, String componentTypeName, int dimensions) From e1220bd1f0dcd1d82aaf6dde6bffda05fc6bbdd3 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Sat, 15 Jun 2024 14:22:53 +0200 Subject: [PATCH 39/78] Simplify tryToLoadResource tests --- .../commons/util/ReflectionUtilsTests.java | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java index 7ab8aa5e893a..dac5a53bf9d7 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java @@ -715,37 +715,31 @@ class ResourceLoadingTests { @Test void tryToLoadResourcePreconditions() { - assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.tryToLoadResource("", null)); - assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.tryToLoadResource(" ", null)); + assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.tryToLoadResource("")); + assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.tryToLoadResource(" ")); - assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.tryToLoadResource(null, null)); + assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.tryToLoadResource(null)); assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.tryToLoadResource("org/junit/platform/commons/example.resource", null)); } @Test void tryToLoadResource() { - var classLoader = ClassLoaderUtils.getDefaultClassLoader(); - var tryToLoadResource = ReflectionUtils.tryToLoadResource("org/junit/platform/commons/example.resource", - classLoader); + var tryToLoadResource = ReflectionUtils.tryToLoadResource("org/junit/platform/commons/example.resource"); var resource = assertDoesNotThrow(tryToLoadResource::get); assertThat(resource.getName()).isEqualTo("org/junit/platform/commons/example.resource"); } @Test void tryToLoadResourceWithPrefixedSlash() { - var classLoader = ClassLoaderUtils.getDefaultClassLoader(); - var tryToLoadResource = ReflectionUtils.tryToLoadResource("/org/junit/platform/commons/example.resource", - classLoader); + var tryToLoadResource = ReflectionUtils.tryToLoadResource("/org/junit/platform/commons/example.resource"); var resource = assertDoesNotThrow(tryToLoadResource::get); assertThat(resource.getName()).isEqualTo("org/junit/platform/commons/example.resource"); } @Test void tryToLoadResourceWhenResourceNotFound() { - var classLoader = ClassLoaderUtils.getDefaultClassLoader(); - var tryToLoadResource = ReflectionUtils.tryToLoadResource("org/junit/platform/commons/no-such.resource", - classLoader); + var tryToLoadResource = ReflectionUtils.tryToLoadResource("org/junit/platform/commons/no-such.resource"); assertThrows(NullPointerException.class, tryToLoadResource::get); } } From 917f004225646120dd62d50e9a3d0b21d85d4843 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Sat, 15 Jun 2024 14:33:12 +0200 Subject: [PATCH 40/78] Add more tryToLoadResource tests --- .../support/ReflectionSupportTests.java | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java index 94c883c81d73..661fb68c5d96 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java @@ -90,12 +90,23 @@ void tryToLoadClassWithExplicitClassLoaderDelegates() { ReflectionSupport.tryToLoadClass("java.nio.Bits", classLoader)); } + /** + * @since 1.11 + */ + @Test + void tryToLoadResourcesWithExplicitClassLoaderDelegates() { + var classLoader = getClass().getClassLoader(); + var resource = "org/junit/platform/commons/example.resource"; + assertEquals(ReflectionUtils.tryToLoadResource(resource, classLoader).toOptional(), + ReflectionSupport.tryToLoadResource(resource, classLoader).toOptional()); + } + /** * @since 1.10 */ @Test void tryToLoadClassWithExplicitClassLoaderPreconditions() { - ClassLoader cl = getClass().getClassLoader(); + var cl = getClass().getClassLoader(); assertPreconditionViolationExceptionForString("Class name", () -> ReflectionSupport.tryToLoadClass(null, cl)); assertPreconditionViolationExceptionForString("Class name", () -> ReflectionSupport.tryToLoadClass("", cl)); @@ -103,6 +114,21 @@ void tryToLoadClassWithExplicitClassLoaderPreconditions() { assertPreconditionViolationException("ClassLoader", () -> ReflectionSupport.tryToLoadClass("int", null)); } + /** + * @since 1.11 + */ + @Test + void tryToLoadResourceWithExplicitClassLoaderPreconditions() { + ClassLoader cl = getClass().getClassLoader(); + + assertPreconditionViolationExceptionForString("Resource name", + () -> ReflectionSupport.tryToLoadResource(null, cl)); + assertPreconditionViolationExceptionForString("Resource name", + () -> ReflectionSupport.tryToLoadResource("", cl)); + + assertPreconditionViolationException("ClassLoader", () -> ReflectionSupport.tryToLoadResource("int", null)); + } + @TestFactory List findAllClassesInClasspathRootDelegates() throws Throwable { List tests = new ArrayList<>(); From 4ab3cf80e1266a528ecd5b1ae4c117f44bafb416 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Sat, 15 Jun 2024 14:36:16 +0200 Subject: [PATCH 41/78] Touchups --- .../platform/commons/support/ReflectionSupportTests.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java index 6815079f761d..4570b00f286f 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java @@ -148,12 +148,18 @@ List findAllClassesInClasspathRootDelegates() throws Throwable { return tests; } + /** + * @since 1.11 + */ @Test void tryToLoadResourcePreconditions() { assertPreconditionViolationExceptionForString("Resource name", () -> ReflectionSupport.tryToLoadResource(null)); assertPreconditionViolationExceptionForString("Resource name", () -> ReflectionSupport.tryToLoadResource("")); } + /** + * @since 1.11 + */ @Test void tryToLoadResourceDelegates() { assertEquals(ReflectionUtils.tryToLoadResource("default-package.resource").toOptional(), From ca1f81b9499a5b423aa3bc4af1c501fcc0eef876 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Sat, 15 Jun 2024 14:38:18 +0200 Subject: [PATCH 42/78] Touchups --- .../java/org/junit/platform/commons/util/ReflectionUtils.java | 1 - 1 file changed, 1 deletion(-) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java index f55718fae475..ea0d36673866 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java @@ -57,7 +57,6 @@ import org.apiguardian.api.API; import org.junit.platform.commons.JUnitException; -import org.junit.platform.commons.PreconditionViolationException; import org.junit.platform.commons.function.Try; import org.junit.platform.commons.logging.Logger; import org.junit.platform.commons.logging.LoggerFactory; From 7ffff49492357083b3ba2d458d17f8b4621c603a Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Sun, 16 Jun 2024 00:45:25 +0200 Subject: [PATCH 43/78] Remove unnesesary try-catch --- .../commons/util/ClasspathScanner.java | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java index f2e8cc2c5458..35297912bf0b 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java @@ -211,18 +211,13 @@ private void processResourceFileSafely(Path baseDir, String basePackageName, Res String fullyQualifiedResourceName = determineFullyQualifiedResourceName(baseDir, basePackageName, resourceFile); if (resourceFilter.match(fullyQualifiedResourceName)) { - try { - // @formatter:off - loadResource.apply(fullyQualifiedResourceName, getClassLoader()) - .toOptional() - // Always use ".filter(resourceFilter)" to include future predicates. - .filter(resourceFilter) - .ifPresent(resourceConsumer); - // @formatter:on - } - catch (InternalError internalError) { - handleInternalError(resourceFile, fullyQualifiedResourceName, internalError); - } + // @formatter:off + loadResource.apply(fullyQualifiedResourceName, getClassLoader()) + .toOptional() + // Always use ".filter(resourceFilter)" to include future predicates. + .filter(resourceFilter) + .ifPresent(resourceConsumer); + // @formatter:on } } catch (Throwable throwable) { From 2144abefea2509593df3969675e4ba47f9f200d5 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Sun, 16 Jun 2024 01:09:17 +0200 Subject: [PATCH 44/78] Add more reflection support tests --- .../support/ReflectionSupportTests.java | 121 ++++++++++++++++-- 1 file changed, 111 insertions(+), 10 deletions(-) diff --git a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java index 661fb68c5d96..f9369610bf1b 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java @@ -19,6 +19,7 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.net.URI; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; @@ -137,11 +138,7 @@ List findAllClassesInClasspathRootDelegates() throws Throwable { paths.addAll(ReflectionUtils.getAllClasspathRootDirectories()); for (var path : paths) { var root = path.toUri(); - var displayName = root.getPath(); - if (displayName.length() > 42) { - displayName = "..." + displayName.substring(displayName.length() - 42); - } - tests.add(DynamicTest.dynamicTest(displayName, + tests.add(DynamicTest.dynamicTest(createDisplayName(root), () -> assertEquals(ReflectionUtils.findAllClassesInClasspathRoot(root, allTypes, allNames), ReflectionSupport.findAllClassesInClasspathRoot(root, allTypes, allNames)))); } @@ -159,6 +156,9 @@ void findAllClassesInClasspathRootPreconditions() { () -> ReflectionSupport.findAllClassesInClasspathRoot(path, allTypes, null)); } + /** + * @since 1.11 + */ @TestFactory List findAllResourcesInClasspathRootDelegates() throws Throwable { List tests = new ArrayList<>(); @@ -167,17 +167,16 @@ List findAllResourcesInClasspathRootDelegates() throws Throwable { paths.addAll(ReflectionUtils.getAllClasspathRootDirectories()); for (var path : paths) { var root = path.toUri(); - var displayName = root.getPath(); - if (displayName.length() > 42) { - displayName = "..." + displayName.substring(displayName.length() - 42); - } - tests.add(DynamicTest.dynamicTest(displayName, + tests.add(DynamicTest.dynamicTest(createDisplayName(root), () -> assertEquals(ReflectionUtils.findAllResourcesInClasspathRoot(root, allResources, allNames), ReflectionSupport.findAllResourcesInClasspathRoot(root, allResources, allNames)))); } return tests; } + /** + * @since 1.11 + */ @Test void findAllResourcesInClasspathRootPreconditions() { var path = Path.of(".").toUri(); @@ -189,6 +188,39 @@ void findAllResourcesInClasspathRootPreconditions() { () -> ReflectionSupport.findAllResourcesInClasspathRoot(path, allResources, null)); } + /** + * @since 1.11 + */ + @TestFactory + List streamAllResourcesInClasspathRootDelegates() throws Throwable { + List tests = new ArrayList<>(); + List paths = new ArrayList<>(); + paths.add(Path.of(".").toRealPath()); + paths.addAll(ReflectionUtils.getAllClasspathRootDirectories()); + for (var path : paths) { + var root = path.toUri(); + tests.add(DynamicTest.dynamicTest(createDisplayName(root), + () -> assertEquals( + ReflectionUtils.streamAllResourcesInClasspathRoot(root, allResources, allNames).toList(), + ReflectionSupport.streamAllResourcesInClasspathRoot(root, allResources, allNames).toList()))); + } + return tests; + } + + /** + * @since 1.11 + */ + @Test + void streamAllResourcesInClasspathRootPreconditions() { + var path = Path.of(".").toUri(); + assertPreconditionViolationException("root", + () -> ReflectionSupport.streamAllResourcesInClasspathRoot(null, allResources, allNames)); + assertPreconditionViolationException("resource predicate", + () -> ReflectionSupport.streamAllResourcesInClasspathRoot(path, null, allNames)); + assertPreconditionViolationException("name predicate", + () -> ReflectionSupport.streamAllResourcesInClasspathRoot(path, allResources, null)); + } + @Test void findAllClassesInPackageDelegates() { assertNotEquals(0, ReflectionSupport.findAllClassesInPackage("org.junit", allTypes, allNames).size()); @@ -206,6 +238,9 @@ void findAllClassesInPackagePreconditions() { () -> ReflectionSupport.findAllClassesInPackage("org.junit", allTypes, null)); } + /** + * @since 1.11 + */ @Test void findAllResourcesInPackageDelegates() { assertNotEquals(0, ReflectionSupport.findAllResourcesInPackage("org.junit", allResources, allNames).size()); @@ -214,6 +249,9 @@ void findAllResourcesInPackageDelegates() { ReflectionSupport.findAllResourcesInPackage("org.junit", allResources, allNames)); } + /** + * @since 1.11 + */ @Test void findAllResourcesInPackagePreconditions() { assertPreconditionViolationExceptionForString("basePackageName", @@ -224,6 +262,30 @@ void findAllResourcesInPackagePreconditions() { () -> ReflectionSupport.findAllResourcesInPackage("org.junit", allResources, null)); } + /** + * @since 1.11 + */ + @Test + void streamAllResourcesInPackageDelegates() { + assertNotEquals(0, ReflectionSupport.streamAllResourcesInPackage("org.junit", allResources, allNames).count()); + + assertEquals(ReflectionUtils.streamAllResourcesInPackage("org.junit", allResources, allNames).toList(), + ReflectionSupport.streamAllResourcesInPackage("org.junit", allResources, allNames).toList()); + } + + /** + * @since 1.11 + */ + @Test + void streamAllResourcesInPackagePreconditions() { + assertPreconditionViolationExceptionForString("basePackageName", + () -> ReflectionSupport.streamAllResourcesInPackage(null, allResources, allNames)); + assertPreconditionViolationException("resource predicate", + () -> ReflectionSupport.streamAllResourcesInPackage("org.junit", null, allNames)); + assertPreconditionViolationException("name predicate", + () -> ReflectionSupport.streamAllResourcesInPackage("org.junit", allResources, null)); + } + @Test void findAllClassesInModuleDelegates() { assertEquals(ReflectionUtils.findAllClassesInModule("org.junit.platform.commons", allTypes, allNames), @@ -241,12 +303,18 @@ void findAllClassesInModulePreconditions() { () -> ReflectionSupport.findAllClassesInModule("org.junit.platform.commons", allTypes, null)); } + /** + * @since 1.11 + */ @Test void findAllResourcesInModuleDelegates() { assertEquals(ReflectionUtils.findAllResourcesInModule("org.junit.platform.commons", allResources, allNames), ReflectionSupport.findAllResourcesInModule("org.junit.platform.commons", allResources, allNames)); } + /** + * @since 1.11 + */ @Test void findAllResourcesInModulePreconditions() { var exception = assertThrows(PreconditionViolationException.class, @@ -258,6 +326,31 @@ void findAllResourcesInModulePreconditions() { () -> ReflectionSupport.findAllResourcesInModule("org.junit.platform.commons", allResources, null)); } + /** + * @since 1.11 + */ + @Test + void streamAllResourcesInModuleDelegates() { + assertEquals( + ReflectionUtils.streamAllResourcesInModule("org.junit.platform.commons", allResources, allNames).toList(), + ReflectionSupport.streamAllResourcesInModule("org.junit.platform.commons", allResources, + allNames).toList()); + } + + /** + * @since 1.11 + */ + @Test + void streamAllResourcesInModulePreconditions() { + var exception = assertThrows(PreconditionViolationException.class, + () -> ReflectionSupport.streamAllResourcesInModule(null, allResources, allNames)); + assertEquals("Module name must not be null or empty", exception.getMessage()); + assertPreconditionViolationException("resource predicate", + () -> ReflectionSupport.streamAllResourcesInModule("org.junit.platform.commons", null, allNames)); + assertPreconditionViolationException("name predicate", + () -> ReflectionSupport.streamAllResourcesInModule("org.junit.platform.commons", allResources, null)); + } + @Test void newInstanceDelegates() { assertEquals(ReflectionUtils.newInstance(String.class, "foo"), @@ -410,6 +503,14 @@ void findNestedClassesPreconditions() { () -> ReflectionSupport.findNestedClasses(ClassWithNestedClasses.class, null)); } + private static String createDisplayName(URI root) { + var displayName = root.getPath(); + if (displayName.length() > 42) { + displayName = "..." + displayName.substring(displayName.length() - 42); + } + return displayName; + } + static class ClassWithNestedClasses { class Nested1 { From 6cbebf0ac09a134a92b303727444c5bb1ecc27b6 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Mon, 8 Jul 2024 20:47:13 +0200 Subject: [PATCH 45/78] Work in progress --- .../commons/support/ReflectionSupport.java | 72 +++++++------- .../platform/commons/support/Resource.java | 12 +-- .../commons/util/ClasspathScanner.java | 30 +++--- .../platform/commons/util/ModuleUtils.java | 3 +- .../commons/util/ReflectionUtils.java | 73 ++------------ .../platform/commons/util/ResourceFilter.java | 94 ++++++++++++------- .../platform/commons/util/ModuleUtils.java | 10 +- .../ResourceContainerSelectorResolver.java | 48 ++++------ .../support/ReflectionSupportTests.java | 77 +++++++-------- .../commons/util/ClasspathScannerTests.java | 77 ++++----------- 10 files changed, 198 insertions(+), 298 deletions(-) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java index 79a4c9dd2143..25887ff66608 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java @@ -19,6 +19,7 @@ import java.net.URI; import java.util.List; import java.util.Optional; +import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Stream; @@ -188,18 +189,16 @@ public static List> findAllClassesInClasspathRoot(URI root, Predicate findAllResourcesInClasspathRoot(URI root, Predicate resourceFilter, - Predicate resourceNameFilter) { + public static List findAllResourcesInClasspathRoot(URI root, Predicate resourceFilter) { - return ReflectionUtils.findAllResourcesInClasspathRoot(root, resourceFilter, resourceNameFilter); + return ReflectionUtils.findAllResourcesInClasspathRoot(root, resourceFilter); } /** @@ -238,18 +237,16 @@ public static Stream> streamAllClassesInClasspathRoot(URI root, Predica * @param root the URI for the classpath root in which to scan; never * {@code null} * @param resourceFilter the resource type filter; never {@code null} - * @param resourceNameFilter the resources name filter; never {@code null} * @return a stream of all such classes found; never {@code null} * but potentially empty * @since 1.11 - * @see #streamAllResourcesInPackage(String, Predicate, Predicate) - * @see #streamAllResourcesInModule(String, Predicate, Predicate) + * @see #streamAllResourcesInPackage(String, Predicate) + * @see #streamAllResourcesInModule(String, Predicate) */ @API(status = EXPERIMENTAL, since = "1.11") - public static Stream streamAllResourcesInClasspathRoot(URI root, Predicate resourceFilter, - Predicate resourceNameFilter) { + public static Stream streamAllResourcesInClasspathRoot(URI root, Predicate resourceFilter) { - return ReflectionUtils.streamAllResourcesInClasspathRoot(root, resourceFilter, resourceNameFilter); + return ReflectionUtils.streamAllResourcesInClasspathRoot(root, resourceFilter); } /** @@ -284,22 +281,24 @@ public static List> findAllClassesInPackage(String basePackageName, Pre *

The classpath scanning algorithm searches recursively in subpackages * beginning within the supplied base package. * + *

The resulting list may include identically named resources from different + * classpath roots. These can be filtered out using + * {@link org.junit.platform.commons.util.ResourceFilter#loadClasspathResource(Function)}. + * * @param basePackageName the name of the base package in which to start * scanning; must not be {@code null} and must be valid in terms of Java * syntax * @param resourceFilter the resource type filter; never {@code null} - * @param resourceNameFilter the resource name filter; never {@code null} * @return an immutable list of all such classes found; never {@code null} * but potentially empty * @since 1.11 - * @see #findAllResourcesInClasspathRoot(URI, Predicate, Predicate) - * @see #findAllResourcesInModule(String, Predicate, Predicate) + * @see #findAllResourcesInClasspathRoot(URI, Predicate) + * @see #findAllResourcesInModule(String, Predicate) */ @API(status = EXPERIMENTAL, since = "1.11") - public static List findAllResourcesInPackage(String basePackageName, Predicate resourceFilter, - Predicate resourceNameFilter) { + public static List findAllResourcesInPackage(String basePackageName, Predicate resourceFilter) { - return ReflectionUtils.findAllResourcesInPackage(basePackageName, resourceFilter, resourceNameFilter); + return ReflectionUtils.findAllResourcesInPackage(basePackageName, resourceFilter); } /** @@ -310,6 +309,10 @@ public static List findAllResourcesInPackage(String basePackageName, P *

The classpath scanning algorithm searches recursively in subpackages * beginning within the supplied base package. * + *

The resulting stream may include identically named resources from different + * classpath roots. These can be filtered out using + * {@link org.junit.platform.commons.util.ResourceFilter#loadClasspathResource(Function)}. + * * @param basePackageName the name of the base package in which to start * scanning; must not be {@code null} and must be valid in terms of Java * syntax @@ -336,22 +339,25 @@ public static Stream> streamAllClassesInPackage(String basePackageName, *

The classpath scanning algorithm searches recursively in subpackages * beginning within the supplied base package. * + *

The resulting stream may include identically named resources from different + * classpath roots. These can be filtered out using + * {@link org.junit.platform.commons.util.ResourceFilter#loadClasspathResource(Function)}. + * * @param basePackageName the name of the base package in which to start * scanning; must not be {@code null} and must be valid in terms of Java * syntax * @param resourceFilter the resource type filter; never {@code null} - * @param resourceNameFilter the resource name filter; never {@code null} * @return a stream of all such resources found; never {@code null} * but potentially empty * @since 1.11 - * @see #streamAllResourcesInClasspathRoot(URI, Predicate, Predicate) - * @see #streamAllResourcesInModule(String, Predicate, Predicate) + * @see #streamAllResourcesInClasspathRoot(URI, Predicate) + * @see #streamAllResourcesInModule(String, Predicate) */ @API(status = EXPERIMENTAL, since = "1.11") public static Stream streamAllResourcesInPackage(String basePackageName, - Predicate resourceFilter, Predicate resourceNameFilter) { + Predicate resourceFilter) { - return ReflectionUtils.streamAllResourcesInPackage(basePackageName, resourceFilter, resourceNameFilter); + return ReflectionUtils.streamAllResourcesInPackage(basePackageName, resourceFilter); } /** @@ -389,18 +395,16 @@ public static List> findAllClassesInModule(String moduleName, Predicate * @param moduleName the name of the module to scan; never {@code null} or * empty * @param resourceFilter the resource type filter; never {@code null} - * @param resourceNameFilter the resource name filter; never {@code null} * @return an immutable list of all such resources found; never {@code null} * but potentially empty * @since 1.11 - * @see #findAllResourcesInClasspathRoot(URI, Predicate, Predicate) - * @see #findAllResourcesInPackage(String, Predicate, Predicate) + * @see #findAllResourcesInClasspathRoot(URI, Predicate) + * @see #findAllResourcesInPackage(String, Predicate) */ @API(status = EXPERIMENTAL, since = "1.11") - public static List findAllResourcesInModule(String moduleName, Predicate resourceFilter, - Predicate resourceNameFilter) { + public static List findAllResourcesInModule(String moduleName, Predicate resourceFilter) { - return ReflectionUtils.findAllResourcesInModule(moduleName, resourceFilter, resourceNameFilter); + return ReflectionUtils.findAllResourcesInModule(moduleName, resourceFilter); } /** @@ -439,18 +443,16 @@ public static Stream> streamAllClassesInModule(String moduleName, Predi * @param moduleName the name of the module to scan; never {@code null} or * empty * @param resourceFilter the resource type filter; never {@code null} - * @param resourceNameFilter the resource name filter; never {@code null} * @return a stream of all such resources found; never {@code null} * but potentially empty * @since 1.11 - * @see #streamAllResourcesInClasspathRoot(URI, Predicate, Predicate) - * @see #streamAllResourcesInPackage(String, Predicate, Predicate) + * @see #streamAllResourcesInClasspathRoot(URI, Predicate) + * @see #streamAllResourcesInPackage(String, Predicate) */ @API(status = EXPERIMENTAL, since = "1.11") - public static Stream streamAllResourcesInModule(String moduleName, Predicate resourceFilter, - Predicate resourceNameFilter) { + public static Stream streamAllResourcesInModule(String moduleName, Predicate resourceFilter) { - return ReflectionUtils.streamAllResourcesInModule(moduleName, resourceFilter, resourceNameFilter); + return ReflectionUtils.streamAllResourcesInModule(moduleName, resourceFilter); } /** diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/Resource.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/Resource.java index 68ffec8d0559..c9587c3a5ca6 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/Resource.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/Resource.java @@ -22,12 +22,12 @@ /** * Represents a resource on the classpath. * @since 1.11 - * @see ReflectionSupport#findAllResourcesInClasspathRoot(URI, Predicate, Predicate) - * @see ReflectionSupport#findAllResourcesInPackage(String, Predicate, Predicate) - * @see ReflectionSupport#findAllResourcesInModule(String, Predicate, Predicate) - * @see ReflectionSupport#streamAllResourcesInClasspathRoot(URI, Predicate, Predicate) - * @see ReflectionSupport#streamAllResourcesInPackage(String, Predicate, Predicate) - * @see ReflectionSupport#streamAllResourcesInModule(String, Predicate, Predicate) + * @see ReflectionSupport#findAllResourcesInClasspathRoot(URI, Predicate) + * @see ReflectionSupport#findAllResourcesInPackage(String, Predicate) + * @see ReflectionSupport#findAllResourcesInModule(String, Predicate) + * @see ReflectionSupport#streamAllResourcesInClasspathRoot(URI, Predicate) + * @see ReflectionSupport#streamAllResourcesInPackage(String, Predicate) + * @see ReflectionSupport#streamAllResourcesInModule(String, Predicate) */ @API(status = EXPERIMENTAL, since = "1.11") public interface Resource { diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java index 35297912bf0b..77bf1ae829ed 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java @@ -68,15 +68,12 @@ class ClasspathScanner { private final Supplier classLoaderSupplier; private final BiFunction>> loadClass; - private final BiFunction> loadResource; ClasspathScanner(Supplier classLoaderSupplier, - BiFunction>> loadClass, - BiFunction> loadResource) { + BiFunction>> loadClass) { this.classLoaderSupplier = classLoaderSupplier; this.loadClass = loadClass; - this.loadResource = loadResource; } List> scanForClassesInPackage(String basePackageName, ClassFilter classFilter) { @@ -97,7 +94,7 @@ List> scanForClassesInClasspathRoot(URI root, ClassFilter classFilter) return findClassesForUri(root, PackageUtils.DEFAULT_PACKAGE_NAME, classFilter); } - List scanForResourcesInPackage(String basePackageName, ResourceFilter resourceFilter) { + List scanForResourcesInPackage(String basePackageName, Predicate resourceFilter) { Preconditions.condition( PackageUtils.DEFAULT_PACKAGE_NAME.equals(basePackageName) || isNotBlank(basePackageName), "basePackageName must not be null or blank"); @@ -108,7 +105,7 @@ List scanForResourcesInPackage(String basePackageName, ResourceFilter return findResourcesForUris(roots, basePackageName, resourceFilter); } - List scanForResourcesInClasspathRoot(URI root, ResourceFilter resourceFilter) { + List scanForResourcesInClasspathRoot(URI root, Predicate resourceFilter) { Preconditions.notNull(root, "root must not be null"); Preconditions.notNull(resourceFilter, "resourceFilter must not be null"); @@ -142,7 +139,7 @@ private List> findClassesForUri(URI baseUri, String basePackageName, Cl * Recursively scan for resources in all the supplied source directories. */ private List findResourcesForUris(List baseUris, String basePackageName, - ResourceFilter resourceFilter) { + Predicate resourceFilter) { // @formatter:off return baseUris.stream() .map(baseUri -> findResourcesForUri(baseUri, basePackageName, resourceFilter)) @@ -152,7 +149,7 @@ private List findResourcesForUris(List baseUris, String basePacka // @formatter:on } - private List findResourcesForUri(URI baseUri, String basePackageName, ResourceFilter resourceFilter) { + private List findResourcesForUri(URI baseUri, String basePackageName, Predicate resourceFilter) { List resources = new ArrayList<>(); // @formatter:off walkFilesForUri(baseUri, ClasspathFilters.resourceFiles(), @@ -205,20 +202,15 @@ private void processClassFileSafely(Path baseDir, String basePackageName, ClassF } } - private void processResourceFileSafely(Path baseDir, String basePackageName, ResourceFilter resourceFilter, + private void processResourceFileSafely(Path baseDir, String basePackageName, Predicate resourceFilter, Path resourceFile, Consumer resourceConsumer) { try { - String fullyQualifiedResourceName = determineFullyQualifiedResourceName(baseDir, basePackageName, - resourceFile); - if (resourceFilter.match(fullyQualifiedResourceName)) { - // @formatter:off - loadResource.apply(fullyQualifiedResourceName, getClassLoader()) - .toOptional() - // Always use ".filter(resourceFilter)" to include future predicates. - .filter(resourceFilter) - .ifPresent(resourceConsumer); - // @formatter:on + String fullyQualifiedResourceName = determineFullyQualifiedResourceName(baseDir, basePackageName, resourceFile); + Resource resource = new ClasspathResource(fullyQualifiedResourceName, resourceFile.toUri()); + if (resourceFilter.test(resource)) { + resourceConsumer.accept(resource); } + // @formatter:on } catch (Throwable throwable) { handleThrowable(resourceFile, throwable); diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ModuleUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ModuleUtils.java index ae50731a0866..d24b977d71eb 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ModuleUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ModuleUtils.java @@ -17,6 +17,7 @@ import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.function.Predicate; import org.apiguardian.api.API; import org.junit.platform.commons.logging.Logger; @@ -109,7 +110,7 @@ public static List> findAllClassesInModule(String moduleName, ClassFilt * @since 1.11 */ @API(status = INTERNAL, since = "1.11") - public static List findAllResourcesInModule(String moduleName, ResourceFilter filter) { + public static List findAllResourcesInModule(String moduleName, Predicate filter) { Preconditions.notBlank(moduleName, "Module name must not be null or empty"); Preconditions.notNull(filter, "Resource filter must not be null"); diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java index 5c12d6f3d83b..f514c4e3c990 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java @@ -147,7 +147,7 @@ public enum HierarchyTraversalMode { private static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; private static final ClasspathScanner classpathScanner = new ClasspathScanner( - ClassLoaderUtils::getDefaultClassLoader, ReflectionUtils::tryToLoadClass, ReflectionUtils::tryToLoadResource); + ClassLoaderUtils::getDefaultClassLoader, ReflectionUtils::tryToLoadClass); /** * Cache for equivalent methods on an interface implemented by the declaring class. @@ -1092,16 +1092,6 @@ public static List> findAllClassesInClasspathRoot(URI root, Predicate findAllResourcesInClasspathRoot(URI root, Predicate resourceFilter, - Predicate resourceNameFilter) { - // unmodifiable since returned by public, non-internal method(s) - return findAllResourcesInClasspathRoot(root, ResourceFilter.of(resourceNameFilter, resourceFilter)); - } - /** * @since 1.10 * @see org.junit.platform.commons.support.ReflectionSupport#streamAllClassesInClasspathRoot(URI, Predicate, Predicate) @@ -1111,15 +1101,6 @@ public static Stream> streamAllClassesInClasspathRoot(URI root, Predica return streamAllClassesInClasspathRoot(root, ClassFilter.of(classNameFilter, classFilter)); } - /** - * @since 1.11 - * @see org.junit.platform.commons.support.ReflectionSupport#streamAllResourcesInClasspathRoot(URI, Predicate, Predicate) - */ - public static Stream streamAllResourcesInClasspathRoot(URI root, Predicate resourceFilter, - Predicate resourceNameFilter) { - return streamAllResourcesInClasspathRoot(root, ResourceFilter.of(resourceNameFilter, resourceFilter)); - } - /** * @since 1.1 */ @@ -1130,8 +1111,8 @@ public static List> findAllClassesInClasspathRoot(URI root, ClassFilter /** * @since 1.11 */ - public static List findAllResourcesInClasspathRoot(URI root, ResourceFilter classFilter) { - return Collections.unmodifiableList(classpathScanner.scanForResourcesInClasspathRoot(root, classFilter)); + public static List findAllResourcesInClasspathRoot(URI root, Predicate resourceFilter) { + return Collections.unmodifiableList(classpathScanner.scanForResourcesInClasspathRoot(root, resourceFilter)); } /** @@ -1144,7 +1125,7 @@ public static Stream> streamAllClassesInClasspathRoot(URI root, ClassFi /** * @since 1.11 */ - public static Stream streamAllResourcesInClasspathRoot(URI root, ResourceFilter resourceFilter) { + public static Stream streamAllResourcesInClasspathRoot(URI root, Predicate resourceFilter) { return findAllResourcesInClasspathRoot(root, resourceFilter).stream(); } @@ -1157,16 +1138,6 @@ public static List> findAllClassesInPackage(String basePackageName, Pre return findAllClassesInPackage(basePackageName, ClassFilter.of(classNameFilter, classFilter)); } - /** - * @since 1.11 - * @see org.junit.platform.commons.support.ReflectionSupport#findAllClassesInPackage(String, Predicate, Predicate) - */ - public static List findAllResourcesInPackage(String basePackageName, Predicate resourceFilter, - Predicate resourceNameFilter) { - // unmodifiable since returned by public, non-internal method(s) - return findAllResourcesInPackage(basePackageName, ResourceFilter.of(resourceNameFilter, resourceFilter)); - } - /** * since 1.10 * @see org.junit.platform.commons.support.ReflectionSupport#streamAllClassesInPackage(String, Predicate, Predicate) @@ -1176,15 +1147,6 @@ public static Stream> streamAllClassesInPackage(String basePackageName, return streamAllClassesInPackage(basePackageName, ClassFilter.of(classNameFilter, classFilter)); } - /** - * since 1.11 - * @see org.junit.platform.commons.support.ReflectionSupport#streamAllResourcesInPackage(String, Predicate, Predicate) - */ - public static Stream streamAllResourcesInPackage(String basePackageName, - Predicate resourceFilter, Predicate resourceNameFilter) { - return streamAllResourcesInPackage(basePackageName, ResourceFilter.of(resourceNameFilter, resourceFilter)); - } - /** * @since 1.1 */ @@ -1195,7 +1157,7 @@ public static List> findAllClassesInPackage(String basePackageName, Cla /** * @since 1.11 */ - public static List findAllResourcesInPackage(String basePackageName, ResourceFilter resourceFilter) { + public static List findAllResourcesInPackage(String basePackageName, Predicate resourceFilter) { return Collections.unmodifiableList( classpathScanner.scanForResourcesInPackage(basePackageName, resourceFilter)); } @@ -1210,7 +1172,7 @@ public static Stream> streamAllClassesInPackage(String basePackageName, /** * @since 1.11 */ - public static Stream streamAllResourcesInPackage(String basePackageName, ResourceFilter resourceFilter) { + public static Stream streamAllResourcesInPackage(String basePackageName, Predicate resourceFilter) { return findAllResourcesInPackage(basePackageName, resourceFilter).stream(); } @@ -1224,16 +1186,6 @@ public static List> findAllClassesInModule(String moduleName, Predicate return findAllClassesInModule(moduleName, ClassFilter.of(classNameFilter, classFilter)); } - /** - * @since 1.11 - * @see org.junit.platform.commons.support.ReflectionSupport#findAllResourcesInModule(String, Predicate, Predicate) - */ - public static List findAllResourcesInModule(String moduleName, Predicate resourceFilter, - Predicate resourceNameFilter) { - // unmodifiable since returned by public, non-internal method(s) - return findAllResourcesInModule(moduleName, ResourceFilter.of(resourceNameFilter, resourceFilter)); - } - /** * @since 1.10 * @see org.junit.platform.commons.support.ReflectionSupport#streamAllClassesInModule(String, Predicate, Predicate) @@ -1243,15 +1195,6 @@ public static Stream> streamAllClassesInModule(String moduleName, Predi return streamAllClassesInModule(moduleName, ClassFilter.of(classNameFilter, classFilter)); } - /** - * @since 1.11 - * @see org.junit.platform.commons.support.ReflectionSupport#streamAllResourcesInModule(String, Predicate, Predicate) - */ - public static Stream streamAllResourcesInModule(String moduleName, Predicate resourceFilter, - Predicate resourceNameFilter) { - return streamAllResourcesInModule(moduleName, ResourceFilter.of(resourceNameFilter, resourceFilter)); - } - /** * @since 1.1.1 */ @@ -1262,7 +1205,7 @@ public static List> findAllClassesInModule(String moduleName, ClassFilt /** * @since 1.11 */ - public static List findAllResourcesInModule(String moduleName, ResourceFilter resourceFilter) { + public static List findAllResourcesInModule(String moduleName, Predicate resourceFilter) { return Collections.unmodifiableList(ModuleUtils.findAllResourcesInModule(moduleName, resourceFilter)); } @@ -1276,7 +1219,7 @@ public static Stream> streamAllClassesInModule(String moduleName, Class /** * @since 1.11 */ - public static Stream streamAllResourcesInModule(String moduleName, ResourceFilter resourceFilter) { + public static Stream streamAllResourcesInModule(String moduleName, Predicate resourceFilter) { return findAllResourcesInModule(moduleName, resourceFilter).stream(); } diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java index bde54890c85e..d5f796d8c6b0 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java @@ -10,64 +10,88 @@ package org.junit.platform.commons.util; -import static org.apiguardian.api.API.Status.INTERNAL; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import java.util.function.Function; import java.util.function.Predicate; import org.apiguardian.api.API; +import org.junit.platform.commons.function.Try; +import org.junit.platform.commons.support.ReflectionSupport; import org.junit.platform.commons.support.Resource; /** - * Resource-related predicate used by reflection utilities. - * - *

DISCLAIMER

- * - *

These utilities are intended solely for usage within the JUnit framework - * itself. Any usage by external parties is not supported. - * Use at your own risk! + * Resource-related predicates for use with {@link org.junit.platform.commons.support.ReflectionSupport}. * * @since 1.11 */ -@API(status = INTERNAL, since = "1.11") -public class ResourceFilter implements Predicate { +@API(status = EXPERIMENTAL, since = "1.11") +public class ResourceFilter { + + public static final String DEFAULT_PACKAGE_NAME = ""; + private static final char CLASSPATH_RESOURCE_PATH_SEPARATOR = '/'; + private static final char PACKAGE_SEPARATOR_CHAR = '.'; /** - * Create a {@link ResourceFilter} instance that accepts all names but filters resources. + * TODO: */ - public static ResourceFilter of(Predicate resourcePredicate) { - return of(name -> true, resourcePredicate); + public static Function loadClasspathResource() { + return loadClasspathResource(ReflectionSupport::tryToLoadResource); } - /** - * Create a {@link ResourceFilter} instance that filters by resource names and resources. + * TODO: Improve or reconsider. + * + * Include only resources that can be loaded by a class loader. + *

+ * Resources discovered by {@link org.junit.platform.commons.support.ReflectionSupport} + * may include identically named resources from different class + * path roots. To get + * + * @param loadResource function to load the resource, e.g. {@link org.junit.platform.commons.support.ReflectionSupport#tryToLoadResource(String)}. + * @return a function that for a given resource, returns the resource as it would bye loaded by {@link ClassLoader#getResource(String)} + * + * @see ReflectionUtils#tryToLoadResource(String) + * @see ReflectionUtils#tryToLoadResource(String, ClassLoader) */ - public static ResourceFilter of(Predicate namePredicate, Predicate resourcePredicate) { - return new ResourceFilter(namePredicate, resourcePredicate); - } - private final Predicate namePredicate; - private final Predicate resourcePredicate; + public static Function loadClasspathResource(Function> loadResource) { + return candidate -> loadResource.apply(candidate.getName()) // + .toOptional() // + .map(loaded -> { + if (!loaded.getUri().equals(candidate.getUri())) { + return new ClasspathResource(candidate.getName(), loaded.getUri()); + } + return candidate; - private ResourceFilter(Predicate namePredicate, Predicate resourcePredicate) { - this.namePredicate = Preconditions.notNull(namePredicate, "name predicate must not be null"); - this.resourcePredicate = Preconditions.notNull(resourcePredicate, "resource predicate must not be null"); + }) + .orElse(candidate); } - public boolean match(String name) { - return namePredicate.test(name); + /** + * TODO: Doc + * + * A package filter is written to test {@code .} separated package names. + * Resources however have {@code /} separated paths. By rewriting the path + * of the resource into a package name, we can make the package filter work. + */ + public static Predicate packageName(Predicate packageFilter) { + + // TODO: Filter out invalid package names? + return resource -> packageFilter.test(packageName(resource.getName())); } - public boolean match(Resource resource) { - return resourcePredicate.test(resource); + private static String packageName(String classpathResourceName) { + int lastIndexOf = classpathResourceName.lastIndexOf(CLASSPATH_RESOURCE_PATH_SEPARATOR); + if (lastIndexOf < 0) { + return DEFAULT_PACKAGE_NAME; + } + // classpath resource names do not start with / + String resourcePackagePath = classpathResourceName.substring(0, lastIndexOf); + return resourcePackagePath.replace(CLASSPATH_RESOURCE_PATH_SEPARATOR, PACKAGE_SEPARATOR_CHAR); } - /** - * @implNote This implementation combines all tests stored in the predicates - * of this instance. Any new predicate must be added to this test method as - * well. - */ - @Override - public boolean test(Resource resource) { - return match(resource.getName()) && match(resource); + private ResourceFilter() { + } + } diff --git a/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java b/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java index 9a5a70fc725c..e6659e3764f7 100644 --- a/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java +++ b/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java @@ -128,7 +128,7 @@ public static List> findAllClassesInModule(String moduleName, ClassFilt * @since 1.11 */ @API(status = INTERNAL, since = "1.11") - public static List findAllResourcesInModule(String moduleName, ResourceFilter filter) { + public static List findAllResourcesInModule(String moduleName, Predicate filter) { Preconditions.notBlank(moduleName, "Module name must not be null or empty"); Preconditions.notNull(filter, "Resource filter must not be null"); @@ -186,7 +186,7 @@ private static List> scan(Set references, ClassFilter * Scan for classes using the supplied set of module references, class * filter, and loader. */ - private static List scan(Set references, ResourceFilter filter, ClassLoader loader) { + private static List scan(Set references, Predicate filter, ClassLoader loader) { logger.debug(() -> "Scanning " + references.size() + " module references: " + references); ModuleReferenceResourceScanner scanner = new ModuleReferenceResourceScanner(filter, loader); List classes = new ArrayList<>(); @@ -267,10 +267,10 @@ private Class loadClassUnchecked(String binaryName) { */ static class ModuleReferenceResourceScanner { - private final ResourceFilter resourceFilter; + private final Predicate resourceFilter; private final ClassLoader classLoader; - ModuleReferenceResourceScanner(ResourceFilter resourceFilter, ClassLoader classLoader) { + ModuleReferenceResourceScanner(Predicate resourceFilter, ClassLoader classLoader) { this.resourceFilter = resourceFilter; this.classLoader = classLoader; } @@ -283,9 +283,7 @@ List scan(ModuleReference reference) { try (Stream names = reader.list()) { // @formatter:off return names.filter(name -> !name.endsWith(".class")) - .filter(resourceFilter::match) .map(this::loadResourceUnchecked) - // Always use ".filter(resourceFilter)" to include future predicates. .filter(resourceFilter) .collect(Collectors.toList()); // @formatter:on diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java index 3cf4c9c30b08..f29394b0a9c3 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java @@ -14,13 +14,18 @@ import static org.junit.platform.commons.support.ReflectionSupport.findAllResourcesInClasspathRoot; import static org.junit.platform.commons.support.ReflectionSupport.findAllResourcesInPackage; import static org.junit.platform.commons.util.ReflectionUtils.findAllResourcesInModule; +import static org.junit.platform.commons.util.ResourceFilter.packageName; +import static org.junit.platform.commons.util.ResourceFilter.loadClasspathResource; import static org.junit.platform.engine.support.discovery.SelectorResolver.Resolution.selectors; import static org.junit.platform.engine.support.discovery.SelectorResolver.Resolution.unresolved; import java.util.List; +import java.util.Set; +import java.util.function.Function; import java.util.function.Predicate; import org.junit.platform.commons.support.Resource; +import org.junit.platform.engine.discovery.ClasspathResourceSelector; import org.junit.platform.engine.discovery.ClasspathRootSelector; import org.junit.platform.engine.discovery.DiscoverySelectors; import org.junit.platform.engine.discovery.ModuleSelector; @@ -30,59 +35,44 @@ * @since 1.11 */ class ResourceContainerSelectorResolver implements SelectorResolver { - private static final char CLASSPATH_RESOURCE_PATH_SEPARATOR = '/'; - private static final char PACKAGE_SEPARATOR_CHAR = '.'; - public static final String DEFAULT_PACKAGE_NAME = ""; + private static final Function classpathResource = loadClasspathResource(); + private final Predicate packageFilter; private final Predicate resourceFilter; - private final Predicate resourceNameFilter; ResourceContainerSelectorResolver(Predicate resourceFilter, Predicate resourcePackageFilter) { + this.packageFilter = packageName(resourcePackageFilter); this.resourceFilter = resourceFilter; - this.resourceNameFilter = adaptPackageFilter(resourcePackageFilter); - } - - /** - * A package filter is written to test {@code .} separated package names. - * Resources however have {@code /} separated paths. By rewriting the path - * of the resource into a package name, we can make the package filter work. - */ - private static Predicate adaptPackageFilter(Predicate packageFilter) { - return resource -> packageFilter.test(packageName(resource)); - } - - private static String packageName(String classpathResourceName) { - int lastIndexOf = classpathResourceName.lastIndexOf(CLASSPATH_RESOURCE_PATH_SEPARATOR); - if (lastIndexOf < 0) { - return DEFAULT_PACKAGE_NAME; - } - // classpath resource names do not start with / - String resourcePackagePath = classpathResourceName.substring(0, lastIndexOf); - return resourcePackagePath.replace(CLASSPATH_RESOURCE_PATH_SEPARATOR, PACKAGE_SEPARATOR_CHAR); } @Override public Resolution resolve(ClasspathRootSelector selector, Context context) { return resourceSelectors( - findAllResourcesInClasspathRoot(selector.getClasspathRoot(), resourceFilter, resourceNameFilter)); + findAllResourcesInClasspathRoot(selector.getClasspathRoot(), packageFilter)); } @Override public Resolution resolve(ModuleSelector selector, Context context) { return resourceSelectors( - findAllResourcesInModule(selector.getModuleName(), resourceFilter, resourceNameFilter)); + findAllResourcesInModule(selector.getModuleName(), packageFilter)); } @Override public Resolution resolve(PackageSelector selector, Context context) { return resourceSelectors( - findAllResourcesInPackage(selector.getPackageName(), resourceFilter, resourceNameFilter)); + findAllResourcesInPackage(selector.getPackageName(), packageFilter)); } private Resolution resourceSelectors(List resources) { - if (resources.isEmpty()) { + Set classpathResources = resources.stream() // + .map(classpathResource) // + .filter(resourceFilter) // + .map(DiscoverySelectors::selectClasspathResource) // + .collect(toSet()); + + if (classpathResources.isEmpty()) { return unresolved(); } - return selectors(resources.stream().map(DiscoverySelectors::selectClasspathResource).collect(toSet())); + return selectors(classpathResources); } } diff --git a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java index 53da5b44610a..5a9ce7e6665c 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java @@ -186,8 +186,8 @@ List findAllResourcesInClasspathRootDelegates() throws Throwable { for (var path : paths) { var root = path.toUri(); tests.add(DynamicTest.dynamicTest(createDisplayName(root), - () -> assertEquals(ReflectionUtils.findAllResourcesInClasspathRoot(root, allResources, allNames), - ReflectionSupport.findAllResourcesInClasspathRoot(root, allResources, allNames)))); + () -> assertEquals(ReflectionUtils.findAllResourcesInClasspathRoot(root, allResources), + ReflectionSupport.findAllResourcesInClasspathRoot(root, allResources)))); } return tests; } @@ -199,11 +199,9 @@ List findAllResourcesInClasspathRootDelegates() throws Throwable { void findAllResourcesInClasspathRootPreconditions() { var path = Path.of(".").toUri(); assertPreconditionViolationException("root", - () -> ReflectionSupport.findAllResourcesInClasspathRoot(null, allResources, allNames)); - assertPreconditionViolationException("resource predicate", - () -> ReflectionSupport.findAllResourcesInClasspathRoot(path, null, allNames)); - assertPreconditionViolationException("name predicate", - () -> ReflectionSupport.findAllResourcesInClasspathRoot(path, allResources, null)); + () -> ReflectionSupport.findAllResourcesInClasspathRoot(null, allResources)); + assertPreconditionViolationException("resourceFilter", + () -> ReflectionSupport.findAllResourcesInClasspathRoot(path, null)); } /** @@ -219,8 +217,8 @@ List streamAllResourcesInClasspathRootDelegates() throws Throwable var root = path.toUri(); tests.add(DynamicTest.dynamicTest(createDisplayName(root), () -> assertEquals( - ReflectionUtils.streamAllResourcesInClasspathRoot(root, allResources, allNames).toList(), - ReflectionSupport.streamAllResourcesInClasspathRoot(root, allResources, allNames).toList()))); + ReflectionUtils.streamAllResourcesInClasspathRoot(root, allResources).toList(), + ReflectionSupport.streamAllResourcesInClasspathRoot(root, allResources).toList()))); } return tests; } @@ -232,11 +230,9 @@ List streamAllResourcesInClasspathRootDelegates() throws Throwable void streamAllResourcesInClasspathRootPreconditions() { var path = Path.of(".").toUri(); assertPreconditionViolationException("root", - () -> ReflectionSupport.streamAllResourcesInClasspathRoot(null, allResources, allNames)); - assertPreconditionViolationException("resource predicate", - () -> ReflectionSupport.streamAllResourcesInClasspathRoot(path, null, allNames)); - assertPreconditionViolationException("name predicate", - () -> ReflectionSupport.streamAllResourcesInClasspathRoot(path, allResources, null)); + () -> ReflectionSupport.streamAllResourcesInClasspathRoot(null, allResources)); + assertPreconditionViolationException("resourceFilter", + () -> ReflectionSupport.streamAllResourcesInClasspathRoot(path, null)); } @Test @@ -261,10 +257,10 @@ void findAllClassesInPackagePreconditions() { */ @Test void findAllResourcesInPackageDelegates() { - assertNotEquals(0, ReflectionSupport.findAllResourcesInPackage("org.junit", allResources, allNames).size()); + assertNotEquals(0, ReflectionSupport.findAllResourcesInPackage("org.junit", allResources).size()); - assertEquals(ReflectionUtils.findAllResourcesInPackage("org.junit", allResources, allNames), - ReflectionSupport.findAllResourcesInPackage("org.junit", allResources, allNames)); + assertEquals(ReflectionUtils.findAllResourcesInPackage("org.junit", allResources), + ReflectionSupport.findAllResourcesInPackage("org.junit", allResources)); } /** @@ -273,11 +269,9 @@ void findAllResourcesInPackageDelegates() { @Test void findAllResourcesInPackagePreconditions() { assertPreconditionViolationExceptionForString("basePackageName", - () -> ReflectionSupport.findAllResourcesInPackage(null, allResources, allNames)); - assertPreconditionViolationException("resource predicate", - () -> ReflectionSupport.findAllResourcesInPackage("org.junit", null, allNames)); - assertPreconditionViolationException("name predicate", - () -> ReflectionSupport.findAllResourcesInPackage("org.junit", allResources, null)); + () -> ReflectionSupport.findAllResourcesInPackage(null, allResources)); + assertPreconditionViolationException("resourceFilter", + () -> ReflectionSupport.findAllResourcesInPackage("org.junit", null)); } /** @@ -285,10 +279,10 @@ void findAllResourcesInPackagePreconditions() { */ @Test void streamAllResourcesInPackageDelegates() { - assertNotEquals(0, ReflectionSupport.streamAllResourcesInPackage("org.junit", allResources, allNames).count()); + assertNotEquals(0, ReflectionSupport.streamAllResourcesInPackage("org.junit", allResources).count()); - assertEquals(ReflectionUtils.streamAllResourcesInPackage("org.junit", allResources, allNames).toList(), - ReflectionSupport.streamAllResourcesInPackage("org.junit", allResources, allNames).toList()); + assertEquals(ReflectionUtils.streamAllResourcesInPackage("org.junit", allResources).toList(), + ReflectionSupport.streamAllResourcesInPackage("org.junit", allResources).toList()); } /** @@ -297,11 +291,9 @@ void streamAllResourcesInPackageDelegates() { @Test void streamAllResourcesInPackagePreconditions() { assertPreconditionViolationExceptionForString("basePackageName", - () -> ReflectionSupport.streamAllResourcesInPackage(null, allResources, allNames)); - assertPreconditionViolationException("resource predicate", - () -> ReflectionSupport.streamAllResourcesInPackage("org.junit", null, allNames)); - assertPreconditionViolationException("name predicate", - () -> ReflectionSupport.streamAllResourcesInPackage("org.junit", allResources, null)); + () -> ReflectionSupport.streamAllResourcesInPackage(null, allResources)); + assertPreconditionViolationException("resourceFilter", + () -> ReflectionSupport.streamAllResourcesInPackage("org.junit", null)); } @Test @@ -326,8 +318,8 @@ void findAllClassesInModulePreconditions() { */ @Test void findAllResourcesInModuleDelegates() { - assertEquals(ReflectionUtils.findAllResourcesInModule("org.junit.platform.commons", allResources, allNames), - ReflectionSupport.findAllResourcesInModule("org.junit.platform.commons", allResources, allNames)); + assertEquals(ReflectionUtils.findAllResourcesInModule("org.junit.platform.commons", allResources), + ReflectionSupport.findAllResourcesInModule("org.junit.platform.commons", allResources)); } /** @@ -336,12 +328,10 @@ void findAllResourcesInModuleDelegates() { @Test void findAllResourcesInModulePreconditions() { var exception = assertThrows(PreconditionViolationException.class, - () -> ReflectionSupport.findAllResourcesInModule(null, allResources, allNames)); + () -> ReflectionSupport.findAllResourcesInModule(null, allResources)); assertEquals("Module name must not be null or empty", exception.getMessage()); - assertPreconditionViolationException("resource predicate", - () -> ReflectionSupport.findAllResourcesInModule("org.junit.platform.commons", null, allNames)); - assertPreconditionViolationException("name predicate", - () -> ReflectionSupport.findAllResourcesInModule("org.junit.platform.commons", allResources, null)); + assertPreconditionViolationException("Resource filter", + () -> ReflectionSupport.findAllResourcesInModule("org.junit.platform.commons", null)); } /** @@ -350,9 +340,8 @@ void findAllResourcesInModulePreconditions() { @Test void streamAllResourcesInModuleDelegates() { assertEquals( - ReflectionUtils.streamAllResourcesInModule("org.junit.platform.commons", allResources, allNames).toList(), - ReflectionSupport.streamAllResourcesInModule("org.junit.platform.commons", allResources, - allNames).toList()); + ReflectionUtils.streamAllResourcesInModule("org.junit.platform.commons", allResources).toList(), + ReflectionSupport.streamAllResourcesInModule("org.junit.platform.commons", allResources).toList()); } /** @@ -361,12 +350,10 @@ void streamAllResourcesInModuleDelegates() { @Test void streamAllResourcesInModulePreconditions() { var exception = assertThrows(PreconditionViolationException.class, - () -> ReflectionSupport.streamAllResourcesInModule(null, allResources, allNames)); + () -> ReflectionSupport.streamAllResourcesInModule(null, allResources)); assertEquals("Module name must not be null or empty", exception.getMessage()); - assertPreconditionViolationException("resource predicate", - () -> ReflectionSupport.streamAllResourcesInModule("org.junit.platform.commons", null, allNames)); - assertPreconditionViolationException("name predicate", - () -> ReflectionSupport.streamAllResourcesInModule("org.junit.platform.commons", allResources, null)); + assertPreconditionViolationException("Resource filter", + () -> ReflectionSupport.streamAllResourcesInModule("org.junit.platform.commons", null)); } @Test diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java index 47ea5fa864f8..94d3817e8e01 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java @@ -60,19 +60,15 @@ class ClasspathScannerTests { private static final ClassFilter allClasses = ClassFilter.of(type -> true); - private static final ResourceFilter allResources = ResourceFilter.of(type -> true); + private static final Predicate allResources = type -> true; private final List> loadedClasses = new ArrayList<>(); - private final List loadedResources = new ArrayList<>(); private final BiFunction>> trackingClassLoader = (name, classLoader) -> ReflectionUtils.tryToLoadClass(name, classLoader).ifSuccess(loadedClasses::add); - private final BiFunction> trackingResourceLoader = (name, - classLoader) -> ReflectionUtils.tryToLoadResource(name, classLoader).ifSuccess(loadedResources::add); - private final ClasspathScanner classpathScanner = new ClasspathScanner(ClassLoaderUtils::getDefaultClassLoader, - trackingClassLoader, trackingResourceLoader); + trackingClassLoader); @Test void scanForClassesInClasspathRootWhenMalformedClassnameInternalErrorOccursWithNullDetailedMessage( @@ -150,9 +146,7 @@ void scanForResourcesInClasspathRootWhenGenericRuntimeExceptionOccurs(LogRecordL } private void assertResourcesScannedWhenExceptionIsThrown(Predicate filter) { - var resourceFilter = ResourceFilter.of(filter); - var resources = this.classpathScanner.scanForResourcesInClasspathRoot(getTestClasspathResourceRoot(), - resourceFilter); + var resources = this.classpathScanner.scanForResourcesInClasspathRoot(getTestClasspathResourceRoot(), filter); assertThat(resources).hasSizeGreaterThanOrEqualTo(150); } @@ -193,8 +187,7 @@ private void scanForClassesInClasspathRootWithinJarFile(String resourceName) thr var jarfile = getClass().getResource(resourceName); try (var classLoader = new URLClassLoader(new URL[] { jarfile }, null)) { - var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass, - ReflectionUtils::tryToLoadResource); + var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass); var classes = classpathScanner.scanForClassesInClasspathRoot(jarfile.toURI(), allClasses); assertThat(classes).extracting(Class::getName) // @@ -218,8 +211,7 @@ private void scanForResourcesInClasspathRootWithinJarFile(String resourceName) t var jarfile = getClass().getResource(resourceName); try (var classLoader = new URLClassLoader(new URL[] { jarfile }, null)) { - var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass, - ReflectionUtils::tryToLoadResource); + var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass); var resources = classpathScanner.scanForResourcesInClasspathRoot(jarfile.toURI(), allResources); assertThat(resources).extracting(Resource::getName) // @@ -236,8 +228,7 @@ void scanForResourcesInShadowedClassPathRoot() throws Exception { var shadowedJarFile = getClass().getResource("/jartest-shadowed.jar"); try (var classLoader = new URLClassLoader(new URL[] { jarFile, shadowedJarFile }, null)) { - var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass, - ReflectionUtils::tryToLoadResource); + var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass); var resources = classpathScanner.scanForResourcesInClasspathRoot(shadowedJarFile.toURI(), allResources); assertThat(resources).extracting(Resource::getName).containsExactlyInAnyOrder( @@ -252,10 +243,10 @@ void scanForResourcesInShadowedClassPathRoot() throws Exception { // This resource only exists in the shadowed jar file "jartest-shadowed.jar!/org/junit/platform/jartest/included/unique.resource", // These resources exist in both the jar and shadowed jar file. - // So they're discovered in the shadowed jar, but loaded from the regular jar. - "jartest.jar!/org/junit/platform/jartest/included/included.resource", - "jartest.jar!/org/junit/platform/jartest/included/recursive/recursively-included.resource", - "jartest.jar!/META-INF/MANIFEST.MF"); + // They must be discovered in the shadowed jar as we're searching in that classpath root. + "jartest-shadowed.jar!/org/junit/platform/jartest/included/included.resource", + "jartest-shadowed.jar!/org/junit/platform/jartest/included/recursive/recursively-included.resource", + "jartest-shadowed.jar!/META-INF/MANIFEST.MF"); } } @@ -314,8 +305,7 @@ private void checkModules2500(ModuleFinder finder) { var parent = ClassLoader.getPlatformClassLoader(); var layer = ModuleLayer.defineModulesWithOneLoader(configuration, List.of(boot), parent).layer(); - var classpathScanner = new ClasspathScanner(() -> layer.findLoader(root), ReflectionUtils::tryToLoadClass, - ReflectionUtils::tryToLoadResource); + var classpathScanner = new ClasspathScanner(() -> layer.findLoader(root), ReflectionUtils::tryToLoadClass); { var classes = classpathScanner.scanForClassesInPackage("foo", allClasses); var classNames = classes.stream().map(Class::getName).collect(Collectors.toList()); @@ -334,8 +324,7 @@ void findAllClassesInPackageWithinJarFileConcurrently() throws Exception { var jarUri = URI.create("jar:" + jarFile); try (var classLoader = new URLClassLoader(new URL[] { jarFile })) { - var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass, - ReflectionUtils::tryToLoadResource); + var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass); var results = executeConcurrently(10, () -> classpathScanner.scanForClassesInPackage("org.junit.platform.jartest.included", allClasses)); @@ -356,8 +345,7 @@ void findAllResourcesInPackageWithinJarFileConcurrently() throws Exception { var jarUri = URI.create("jar:" + jarFile); try (var classLoader = new URLClassLoader(new URL[] { jarFile })) { - var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass, - ReflectionUtils::tryToLoadResource); + var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass); var results = executeConcurrently(10, () -> classpathScanner.scanForResourcesInPackage("org.junit.platform.jartest.included", allResources)); @@ -388,7 +376,7 @@ void scanForClassesInDefaultPackage() { @Test void scanForResourcesInDefaultPackage() { - var resourceFilter = ResourceFilter.of(this::inDefaultPackage); + Predicate resourceFilter = this::inDefaultPackage; var resources = classpathScanner.scanForResourcesInPackage("", resourceFilter); assertThat(resources).as("number of resources found in default package").isNotEmpty(); @@ -405,8 +393,8 @@ void scanForClassesInPackageWithFilter() { @Test void scanForResourcesInPackageWithFilter() { - var thisResourceOnly = ResourceFilter.of( - resource -> "org/junit/platform/commons/example.resource".equals(resource.getName())); + Predicate thisResourceOnly = resource -> "org/junit/platform/commons/example.resource" + .equals(resource.getName()); var resources = classpathScanner.scanForResourcesInPackage("org.junit.platform.commons", thisResourceOnly); assertThat(resources).extracting(Resource::getName).containsExactly( "org/junit/platform/commons/example.resource"); @@ -414,8 +402,8 @@ void scanForResourcesInPackageWithFilter() { @Test void resourcesCanBeRead() throws IOException { - var thisResourceOnly = ResourceFilter.of( - resource -> "org/junit/platform/commons/example.resource".equals(resource.getName())); + Predicate thisResourceOnly = resource -> "org/junit/platform/commons/example.resource".equals( + resource.getName()); var resources = classpathScanner.scanForResourcesInPackage("org.junit.platform.commons", thisResourceOnly); Resource resource = resources.get(0); @@ -459,16 +447,14 @@ void scanForClassesInPackageForNullClassFilter() { @Test void scanForClassesInPackageWhenIOExceptionOccurs() { - var scanner = new ClasspathScanner(ThrowingClassLoader::new, ReflectionUtils::tryToLoadClass, - ReflectionUtils::tryToLoadResource); + var scanner = new ClasspathScanner(ThrowingClassLoader::new, ReflectionUtils::tryToLoadClass); var classes = scanner.scanForClassesInPackage("org.junit.platform.commons", allClasses); assertThat(classes).isEmpty(); } @Test void scanForResourcesInPackageWhenIOExceptionOccurs() { - var scanner = new ClasspathScanner(ThrowingClassLoader::new, ReflectionUtils::tryToLoadClass, - ReflectionUtils::tryToLoadResource); + var scanner = new ClasspathScanner(ThrowingClassLoader::new, ReflectionUtils::tryToLoadClass); var classes = scanner.scanForResourcesInPackage("org.junit.platform.commons", allResources); assertThat(classes).isEmpty(); } @@ -483,17 +469,6 @@ void scanForClassesInPackageOnlyLoadsClassesThatAreIncludedByTheClassNameFilter( assertThat(loadedClasses).containsExactly(ClasspathScannerTests.class); } - @Test - void scanForResourcesInPackageOnlyLoadsResourcesThatAreIncludedByTheResourceNameFilter() { - Predicate resourceNameFilter = name -> name.endsWith("/example.resource"); - var resourceFilter = ResourceFilter.of(resourceNameFilter, type -> true); - - classpathScanner.scanForResourcesInPackage("org.junit.platform.commons", resourceFilter); - - assertThat(loadedResources).extracting(Resource::getName).containsExactly( - "org/junit/platform/commons/example.resource"); - } - @Test void findAllClassesInClasspathRoot() throws Exception { var thisClassOnly = ClassFilter.of(clazz -> clazz == ClasspathScannerTests.class); @@ -575,18 +550,6 @@ void onlyLoadsClassesInClasspathRootThatAreIncludedByTheClassNameFilter() throws assertThat(loadedClasses).containsExactly(ClasspathScannerTests.class); } - @Test - void onlyLoadsResourcesInClasspathRootThatAreIncludedByTheResourceNameFilter() { - Predicate resourceNameFilter = name -> name.endsWith("/example.resource"); - var resourceFilter = ResourceFilter.of(resourceNameFilter, type -> true); - var root = getTestClasspathResourceRoot(); - - classpathScanner.scanForResourcesInClasspathRoot(root, resourceFilter); - - assertThat(loadedResources).extracting(Resource::getName).containsExactly( - "org/junit/platform/commons/example.resource"); - } - private static URI uriOf(String name) { var resource = ClasspathScannerTests.class.getResource(name); try { From 4802bb5200ab4b06f1f41f2352efaeed04169704 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Mon, 8 Jul 2024 20:47:51 +0200 Subject: [PATCH 46/78] Work in progressg --- .../junit/platform/commons/util/ClasspathScanner.java | 6 ++++-- .../junit/platform/commons/util/ReflectionUtils.java | 3 ++- .../junit/platform/commons/util/ResourceFilter.java | 4 ++-- .../org/junit/platform/commons/util/ModuleUtils.java | 3 ++- .../discovery/ResourceContainerSelectorResolver.java | 11 ++++------- .../commons/support/ReflectionSupportTests.java | 6 ++---- .../platform/commons/util/ClasspathScannerTests.java | 4 ++-- 7 files changed, 18 insertions(+), 19 deletions(-) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java index 77bf1ae829ed..19bec125b93c 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java @@ -149,7 +149,8 @@ private List findResourcesForUris(List baseUris, String basePacka // @formatter:on } - private List findResourcesForUri(URI baseUri, String basePackageName, Predicate resourceFilter) { + private List findResourcesForUri(URI baseUri, String basePackageName, + Predicate resourceFilter) { List resources = new ArrayList<>(); // @formatter:off walkFilesForUri(baseUri, ClasspathFilters.resourceFiles(), @@ -205,7 +206,8 @@ private void processClassFileSafely(Path baseDir, String basePackageName, ClassF private void processResourceFileSafely(Path baseDir, String basePackageName, Predicate resourceFilter, Path resourceFile, Consumer resourceConsumer) { try { - String fullyQualifiedResourceName = determineFullyQualifiedResourceName(baseDir, basePackageName, resourceFile); + String fullyQualifiedResourceName = determineFullyQualifiedResourceName(baseDir, basePackageName, + resourceFile); Resource resource = new ClasspathResource(fullyQualifiedResourceName, resourceFile.toUri()); if (resourceFilter.test(resource)) { resourceConsumer.accept(resource); diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java index f514c4e3c990..3a80098eb048 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java @@ -1172,7 +1172,8 @@ public static Stream> streamAllClassesInPackage(String basePackageName, /** * @since 1.11 */ - public static Stream streamAllResourcesInPackage(String basePackageName, Predicate resourceFilter) { + public static Stream streamAllResourcesInPackage(String basePackageName, + Predicate resourceFilter) { return findAllResourcesInPackage(basePackageName, resourceFilter).stream(); } diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java index d5f796d8c6b0..8dc7f5b2ce03 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java @@ -38,6 +38,7 @@ public class ResourceFilter { public static Function loadClasspathResource() { return loadClasspathResource(ReflectionSupport::tryToLoadResource); } + /** * TODO: Improve or reconsider. * @@ -63,8 +64,7 @@ public static Function loadClasspathResource(Function> scan(Set references, ClassFilter * Scan for classes using the supplied set of module references, class * filter, and loader. */ - private static List scan(Set references, Predicate filter, ClassLoader loader) { + private static List scan(Set references, Predicate filter, + ClassLoader loader) { logger.debug(() -> "Scanning " + references.size() + " module references: " + references); ModuleReferenceResourceScanner scanner = new ModuleReferenceResourceScanner(filter, loader); List classes = new ArrayList<>(); diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java index f29394b0a9c3..c625c1e6024f 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java @@ -14,8 +14,8 @@ import static org.junit.platform.commons.support.ReflectionSupport.findAllResourcesInClasspathRoot; import static org.junit.platform.commons.support.ReflectionSupport.findAllResourcesInPackage; import static org.junit.platform.commons.util.ReflectionUtils.findAllResourcesInModule; -import static org.junit.platform.commons.util.ResourceFilter.packageName; import static org.junit.platform.commons.util.ResourceFilter.loadClasspathResource; +import static org.junit.platform.commons.util.ResourceFilter.packageName; import static org.junit.platform.engine.support.discovery.SelectorResolver.Resolution.selectors; import static org.junit.platform.engine.support.discovery.SelectorResolver.Resolution.unresolved; @@ -46,20 +46,17 @@ class ResourceContainerSelectorResolver implements SelectorResolver { @Override public Resolution resolve(ClasspathRootSelector selector, Context context) { - return resourceSelectors( - findAllResourcesInClasspathRoot(selector.getClasspathRoot(), packageFilter)); + return resourceSelectors(findAllResourcesInClasspathRoot(selector.getClasspathRoot(), packageFilter)); } @Override public Resolution resolve(ModuleSelector selector, Context context) { - return resourceSelectors( - findAllResourcesInModule(selector.getModuleName(), packageFilter)); + return resourceSelectors(findAllResourcesInModule(selector.getModuleName(), packageFilter)); } @Override public Resolution resolve(PackageSelector selector, Context context) { - return resourceSelectors( - findAllResourcesInPackage(selector.getPackageName(), packageFilter)); + return resourceSelectors(findAllResourcesInPackage(selector.getPackageName(), packageFilter)); } private Resolution resourceSelectors(List resources) { diff --git a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java index 5a9ce7e6665c..7d924d8e582c 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java @@ -216,8 +216,7 @@ List streamAllResourcesInClasspathRootDelegates() throws Throwable for (var path : paths) { var root = path.toUri(); tests.add(DynamicTest.dynamicTest(createDisplayName(root), - () -> assertEquals( - ReflectionUtils.streamAllResourcesInClasspathRoot(root, allResources).toList(), + () -> assertEquals(ReflectionUtils.streamAllResourcesInClasspathRoot(root, allResources).toList(), ReflectionSupport.streamAllResourcesInClasspathRoot(root, allResources).toList()))); } return tests; @@ -339,8 +338,7 @@ void findAllResourcesInModulePreconditions() { */ @Test void streamAllResourcesInModuleDelegates() { - assertEquals( - ReflectionUtils.streamAllResourcesInModule("org.junit.platform.commons", allResources).toList(), + assertEquals(ReflectionUtils.streamAllResourcesInModule("org.junit.platform.commons", allResources).toList(), ReflectionSupport.streamAllResourcesInModule("org.junit.platform.commons", allResources).toList()); } diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java index 94d3817e8e01..2fad77ba92d5 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java @@ -393,8 +393,8 @@ void scanForClassesInPackageWithFilter() { @Test void scanForResourcesInPackageWithFilter() { - Predicate thisResourceOnly = resource -> "org/junit/platform/commons/example.resource" - .equals(resource.getName()); + Predicate thisResourceOnly = resource -> "org/junit/platform/commons/example.resource".equals( + resource.getName()); var resources = classpathScanner.scanForResourcesInPackage("org.junit.platform.commons", thisResourceOnly); assertThat(resources).extracting(Resource::getName).containsExactly( "org/junit/platform/commons/example.resource"); From 7df46a33200514bdfcfc0bf5d943abbc3610d247 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Mon, 8 Jul 2024 20:52:15 +0200 Subject: [PATCH 47/78] Find all available resources, including duplicates --- .../commons/support/ReflectionSupport.java | 60 ++++++-------- .../platform/commons/support/Resource.java | 12 +-- .../commons/util/ClasspathScanner.java | 28 +++---- .../platform/commons/util/ModuleUtils.java | 3 +- .../commons/util/ReflectionUtils.java | 74 +++-------------- .../platform/commons/util/ResourceFilter.java | 73 ----------------- .../platform/commons/util/ModuleUtils.java | 11 ++- .../support/ReflectionSupportTests.java | 79 ++++++++----------- .../commons/util/ClasspathScannerTests.java | 77 +++++------------- 9 files changed, 110 insertions(+), 307 deletions(-) delete mode 100644 junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java index 67bdcc2aee9f..aceeeef12951 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java @@ -19,6 +19,7 @@ import java.net.URI; import java.util.List; import java.util.Optional; +import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Stream; @@ -168,18 +169,16 @@ public static List> findAllClassesInClasspathRoot(URI root, Predicate findAllResourcesInClasspathRoot(URI root, Predicate resourceFilter, - Predicate resourceNameFilter) { + public static List findAllResourcesInClasspathRoot(URI root, Predicate resourceFilter) { - return ReflectionUtils.findAllResourcesInClasspathRoot(root, resourceFilter, resourceNameFilter); + return ReflectionUtils.findAllResourcesInClasspathRoot(root, resourceFilter); } /** @@ -218,18 +217,16 @@ public static Stream> streamAllClassesInClasspathRoot(URI root, Predica * @param root the URI for the classpath root in which to scan; never * {@code null} * @param resourceFilter the resource type filter; never {@code null} - * @param resourceNameFilter the resources name filter; never {@code null} * @return a stream of all such classes found; never {@code null} * but potentially empty * @since 1.11 - * @see #streamAllResourcesInPackage(String, Predicate, Predicate) - * @see #streamAllResourcesInModule(String, Predicate, Predicate) + * @see #streamAllResourcesInPackage(String, Predicate) + * @see #streamAllResourcesInModule(String, Predicate) */ @API(status = EXPERIMENTAL, since = "1.11") - public static Stream streamAllResourcesInClasspathRoot(URI root, Predicate resourceFilter, - Predicate resourceNameFilter) { + public static Stream streamAllResourcesInClasspathRoot(URI root, Predicate resourceFilter) { - return ReflectionUtils.streamAllResourcesInClasspathRoot(root, resourceFilter, resourceNameFilter); + return ReflectionUtils.streamAllResourcesInClasspathRoot(root, resourceFilter); } /** @@ -268,18 +265,16 @@ public static List> findAllClassesInPackage(String basePackageName, Pre * scanning; must not be {@code null} and must be valid in terms of Java * syntax * @param resourceFilter the resource type filter; never {@code null} - * @param resourceNameFilter the resource name filter; never {@code null} * @return an immutable list of all such classes found; never {@code null} * but potentially empty * @since 1.11 - * @see #findAllResourcesInClasspathRoot(URI, Predicate, Predicate) - * @see #findAllResourcesInModule(String, Predicate, Predicate) + * @see #findAllResourcesInClasspathRoot(URI, Predicate) + * @see #findAllResourcesInModule(String, Predicate) */ @API(status = EXPERIMENTAL, since = "1.11") - public static List findAllResourcesInPackage(String basePackageName, Predicate resourceFilter, - Predicate resourceNameFilter) { + public static List findAllResourcesInPackage(String basePackageName, Predicate resourceFilter) { - return ReflectionUtils.findAllResourcesInPackage(basePackageName, resourceFilter, resourceNameFilter); + return ReflectionUtils.findAllResourcesInPackage(basePackageName, resourceFilter); } /** @@ -320,18 +315,17 @@ public static Stream> streamAllClassesInPackage(String basePackageName, * scanning; must not be {@code null} and must be valid in terms of Java * syntax * @param resourceFilter the resource type filter; never {@code null} - * @param resourceNameFilter the resource name filter; never {@code null} * @return a stream of all such resources found; never {@code null} * but potentially empty * @since 1.11 - * @see #streamAllResourcesInClasspathRoot(URI, Predicate, Predicate) - * @see #streamAllResourcesInModule(String, Predicate, Predicate) + * @see #streamAllResourcesInClasspathRoot(URI, Predicate) + * @see #streamAllResourcesInModule(String, Predicate) */ @API(status = EXPERIMENTAL, since = "1.11") public static Stream streamAllResourcesInPackage(String basePackageName, - Predicate resourceFilter, Predicate resourceNameFilter) { + Predicate resourceFilter) { - return ReflectionUtils.streamAllResourcesInPackage(basePackageName, resourceFilter, resourceNameFilter); + return ReflectionUtils.streamAllResourcesInPackage(basePackageName, resourceFilter); } /** @@ -369,18 +363,16 @@ public static List> findAllClassesInModule(String moduleName, Predicate * @param moduleName the name of the module to scan; never {@code null} or * empty * @param resourceFilter the resource type filter; never {@code null} - * @param resourceNameFilter the resource name filter; never {@code null} * @return an immutable list of all such resources found; never {@code null} * but potentially empty * @since 1.11 - * @see #findAllResourcesInClasspathRoot(URI, Predicate, Predicate) - * @see #findAllResourcesInPackage(String, Predicate, Predicate) + * @see #findAllResourcesInClasspathRoot(URI, Predicate) + * @see #findAllResourcesInPackage(String, Predicate) */ @API(status = EXPERIMENTAL, since = "1.11") - public static List findAllResourcesInModule(String moduleName, Predicate resourceFilter, - Predicate resourceNameFilter) { + public static List findAllResourcesInModule(String moduleName, Predicate resourceFilter) { - return ReflectionUtils.findAllResourcesInModule(moduleName, resourceFilter, resourceNameFilter); + return ReflectionUtils.findAllResourcesInModule(moduleName, resourceFilter); } /** @@ -419,18 +411,16 @@ public static Stream> streamAllClassesInModule(String moduleName, Predi * @param moduleName the name of the module to scan; never {@code null} or * empty * @param resourceFilter the resource type filter; never {@code null} - * @param resourceNameFilter the resource name filter; never {@code null} * @return a stream of all such resources found; never {@code null} * but potentially empty * @since 1.11 - * @see #streamAllResourcesInClasspathRoot(URI, Predicate, Predicate) - * @see #streamAllResourcesInPackage(String, Predicate, Predicate) + * @see #streamAllResourcesInClasspathRoot(URI, Predicate) + * @see #streamAllResourcesInPackage(String, Predicate) */ @API(status = EXPERIMENTAL, since = "1.11") - public static Stream streamAllResourcesInModule(String moduleName, Predicate resourceFilter, - Predicate resourceNameFilter) { + public static Stream streamAllResourcesInModule(String moduleName, Predicate resourceFilter) { - return ReflectionUtils.streamAllResourcesInModule(moduleName, resourceFilter, resourceNameFilter); + return ReflectionUtils.streamAllResourcesInModule(moduleName, resourceFilter); } /** diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/Resource.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/Resource.java index 68ffec8d0559..c9587c3a5ca6 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/Resource.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/Resource.java @@ -22,12 +22,12 @@ /** * Represents a resource on the classpath. * @since 1.11 - * @see ReflectionSupport#findAllResourcesInClasspathRoot(URI, Predicate, Predicate) - * @see ReflectionSupport#findAllResourcesInPackage(String, Predicate, Predicate) - * @see ReflectionSupport#findAllResourcesInModule(String, Predicate, Predicate) - * @see ReflectionSupport#streamAllResourcesInClasspathRoot(URI, Predicate, Predicate) - * @see ReflectionSupport#streamAllResourcesInPackage(String, Predicate, Predicate) - * @see ReflectionSupport#streamAllResourcesInModule(String, Predicate, Predicate) + * @see ReflectionSupport#findAllResourcesInClasspathRoot(URI, Predicate) + * @see ReflectionSupport#findAllResourcesInPackage(String, Predicate) + * @see ReflectionSupport#findAllResourcesInModule(String, Predicate) + * @see ReflectionSupport#streamAllResourcesInClasspathRoot(URI, Predicate) + * @see ReflectionSupport#streamAllResourcesInPackage(String, Predicate) + * @see ReflectionSupport#streamAllResourcesInModule(String, Predicate) */ @API(status = EXPERIMENTAL, since = "1.11") public interface Resource { diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java index 35297912bf0b..19bec125b93c 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathScanner.java @@ -68,15 +68,12 @@ class ClasspathScanner { private final Supplier classLoaderSupplier; private final BiFunction>> loadClass; - private final BiFunction> loadResource; ClasspathScanner(Supplier classLoaderSupplier, - BiFunction>> loadClass, - BiFunction> loadResource) { + BiFunction>> loadClass) { this.classLoaderSupplier = classLoaderSupplier; this.loadClass = loadClass; - this.loadResource = loadResource; } List> scanForClassesInPackage(String basePackageName, ClassFilter classFilter) { @@ -97,7 +94,7 @@ List> scanForClassesInClasspathRoot(URI root, ClassFilter classFilter) return findClassesForUri(root, PackageUtils.DEFAULT_PACKAGE_NAME, classFilter); } - List scanForResourcesInPackage(String basePackageName, ResourceFilter resourceFilter) { + List scanForResourcesInPackage(String basePackageName, Predicate resourceFilter) { Preconditions.condition( PackageUtils.DEFAULT_PACKAGE_NAME.equals(basePackageName) || isNotBlank(basePackageName), "basePackageName must not be null or blank"); @@ -108,7 +105,7 @@ List scanForResourcesInPackage(String basePackageName, ResourceFilter return findResourcesForUris(roots, basePackageName, resourceFilter); } - List scanForResourcesInClasspathRoot(URI root, ResourceFilter resourceFilter) { + List scanForResourcesInClasspathRoot(URI root, Predicate resourceFilter) { Preconditions.notNull(root, "root must not be null"); Preconditions.notNull(resourceFilter, "resourceFilter must not be null"); @@ -142,7 +139,7 @@ private List> findClassesForUri(URI baseUri, String basePackageName, Cl * Recursively scan for resources in all the supplied source directories. */ private List findResourcesForUris(List baseUris, String basePackageName, - ResourceFilter resourceFilter) { + Predicate resourceFilter) { // @formatter:off return baseUris.stream() .map(baseUri -> findResourcesForUri(baseUri, basePackageName, resourceFilter)) @@ -152,7 +149,8 @@ private List findResourcesForUris(List baseUris, String basePacka // @formatter:on } - private List findResourcesForUri(URI baseUri, String basePackageName, ResourceFilter resourceFilter) { + private List findResourcesForUri(URI baseUri, String basePackageName, + Predicate resourceFilter) { List resources = new ArrayList<>(); // @formatter:off walkFilesForUri(baseUri, ClasspathFilters.resourceFiles(), @@ -205,20 +203,16 @@ private void processClassFileSafely(Path baseDir, String basePackageName, ClassF } } - private void processResourceFileSafely(Path baseDir, String basePackageName, ResourceFilter resourceFilter, + private void processResourceFileSafely(Path baseDir, String basePackageName, Predicate resourceFilter, Path resourceFile, Consumer resourceConsumer) { try { String fullyQualifiedResourceName = determineFullyQualifiedResourceName(baseDir, basePackageName, resourceFile); - if (resourceFilter.match(fullyQualifiedResourceName)) { - // @formatter:off - loadResource.apply(fullyQualifiedResourceName, getClassLoader()) - .toOptional() - // Always use ".filter(resourceFilter)" to include future predicates. - .filter(resourceFilter) - .ifPresent(resourceConsumer); - // @formatter:on + Resource resource = new ClasspathResource(fullyQualifiedResourceName, resourceFile.toUri()); + if (resourceFilter.test(resource)) { + resourceConsumer.accept(resource); } + // @formatter:on } catch (Throwable throwable) { handleThrowable(resourceFile, throwable); diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ModuleUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ModuleUtils.java index ae50731a0866..d24b977d71eb 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ModuleUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ModuleUtils.java @@ -17,6 +17,7 @@ import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.function.Predicate; import org.apiguardian.api.API; import org.junit.platform.commons.logging.Logger; @@ -109,7 +110,7 @@ public static List> findAllClassesInModule(String moduleName, ClassFilt * @since 1.11 */ @API(status = INTERNAL, since = "1.11") - public static List findAllResourcesInModule(String moduleName, ResourceFilter filter) { + public static List findAllResourcesInModule(String moduleName, Predicate filter) { Preconditions.notBlank(moduleName, "Module name must not be null or empty"); Preconditions.notNull(filter, "Resource filter must not be null"); diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java index ea0d36673866..451c92f63bb3 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java @@ -147,7 +147,7 @@ public enum HierarchyTraversalMode { private static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; private static final ClasspathScanner classpathScanner = new ClasspathScanner( - ClassLoaderUtils::getDefaultClassLoader, ReflectionUtils::tryToLoadClass, ReflectionUtils::tryToLoadResource); + ClassLoaderUtils::getDefaultClassLoader, ReflectionUtils::tryToLoadClass); /** * Cache for equivalent methods on an interface implemented by the declaring class. @@ -1080,16 +1080,6 @@ public static List> findAllClassesInClasspathRoot(URI root, Predicate findAllResourcesInClasspathRoot(URI root, Predicate resourceFilter, - Predicate resourceNameFilter) { - // unmodifiable since returned by public, non-internal method(s) - return findAllResourcesInClasspathRoot(root, ResourceFilter.of(resourceNameFilter, resourceFilter)); - } - /** * @since 1.10 * @see org.junit.platform.commons.support.ReflectionSupport#streamAllClassesInClasspathRoot(URI, Predicate, Predicate) @@ -1099,15 +1089,6 @@ public static Stream> streamAllClassesInClasspathRoot(URI root, Predica return streamAllClassesInClasspathRoot(root, ClassFilter.of(classNameFilter, classFilter)); } - /** - * @since 1.11 - * @see org.junit.platform.commons.support.ReflectionSupport#streamAllResourcesInClasspathRoot(URI, Predicate, Predicate) - */ - public static Stream streamAllResourcesInClasspathRoot(URI root, Predicate resourceFilter, - Predicate resourceNameFilter) { - return streamAllResourcesInClasspathRoot(root, ResourceFilter.of(resourceNameFilter, resourceFilter)); - } - /** * @since 1.1 */ @@ -1118,8 +1099,8 @@ public static List> findAllClassesInClasspathRoot(URI root, ClassFilter /** * @since 1.11 */ - public static List findAllResourcesInClasspathRoot(URI root, ResourceFilter classFilter) { - return Collections.unmodifiableList(classpathScanner.scanForResourcesInClasspathRoot(root, classFilter)); + public static List findAllResourcesInClasspathRoot(URI root, Predicate resourceFilter) { + return Collections.unmodifiableList(classpathScanner.scanForResourcesInClasspathRoot(root, resourceFilter)); } /** @@ -1132,7 +1113,7 @@ public static Stream> streamAllClassesInClasspathRoot(URI root, ClassFi /** * @since 1.11 */ - public static Stream streamAllResourcesInClasspathRoot(URI root, ResourceFilter resourceFilter) { + public static Stream streamAllResourcesInClasspathRoot(URI root, Predicate resourceFilter) { return findAllResourcesInClasspathRoot(root, resourceFilter).stream(); } @@ -1145,16 +1126,6 @@ public static List> findAllClassesInPackage(String basePackageName, Pre return findAllClassesInPackage(basePackageName, ClassFilter.of(classNameFilter, classFilter)); } - /** - * @since 1.11 - * @see org.junit.platform.commons.support.ReflectionSupport#findAllClassesInPackage(String, Predicate, Predicate) - */ - public static List findAllResourcesInPackage(String basePackageName, Predicate resourceFilter, - Predicate resourceNameFilter) { - // unmodifiable since returned by public, non-internal method(s) - return findAllResourcesInPackage(basePackageName, ResourceFilter.of(resourceNameFilter, resourceFilter)); - } - /** * since 1.10 * @see org.junit.platform.commons.support.ReflectionSupport#streamAllClassesInPackage(String, Predicate, Predicate) @@ -1164,15 +1135,6 @@ public static Stream> streamAllClassesInPackage(String basePackageName, return streamAllClassesInPackage(basePackageName, ClassFilter.of(classNameFilter, classFilter)); } - /** - * since 1.11 - * @see org.junit.platform.commons.support.ReflectionSupport#streamAllResourcesInPackage(String, Predicate, Predicate) - */ - public static Stream streamAllResourcesInPackage(String basePackageName, - Predicate resourceFilter, Predicate resourceNameFilter) { - return streamAllResourcesInPackage(basePackageName, ResourceFilter.of(resourceNameFilter, resourceFilter)); - } - /** * @since 1.1 */ @@ -1183,7 +1145,7 @@ public static List> findAllClassesInPackage(String basePackageName, Cla /** * @since 1.11 */ - public static List findAllResourcesInPackage(String basePackageName, ResourceFilter resourceFilter) { + public static List findAllResourcesInPackage(String basePackageName, Predicate resourceFilter) { return Collections.unmodifiableList( classpathScanner.scanForResourcesInPackage(basePackageName, resourceFilter)); } @@ -1198,7 +1160,8 @@ public static Stream> streamAllClassesInPackage(String basePackageName, /** * @since 1.11 */ - public static Stream streamAllResourcesInPackage(String basePackageName, ResourceFilter resourceFilter) { + public static Stream streamAllResourcesInPackage(String basePackageName, + Predicate resourceFilter) { return findAllResourcesInPackage(basePackageName, resourceFilter).stream(); } @@ -1212,16 +1175,6 @@ public static List> findAllClassesInModule(String moduleName, Predicate return findAllClassesInModule(moduleName, ClassFilter.of(classNameFilter, classFilter)); } - /** - * @since 1.11 - * @see org.junit.platform.commons.support.ReflectionSupport#findAllResourcesInModule(String, Predicate, Predicate) - */ - public static List findAllResourcesInModule(String moduleName, Predicate resourceFilter, - Predicate resourceNameFilter) { - // unmodifiable since returned by public, non-internal method(s) - return findAllResourcesInModule(moduleName, ResourceFilter.of(resourceNameFilter, resourceFilter)); - } - /** * @since 1.10 * @see org.junit.platform.commons.support.ReflectionSupport#streamAllClassesInModule(String, Predicate, Predicate) @@ -1231,15 +1184,6 @@ public static Stream> streamAllClassesInModule(String moduleName, Predi return streamAllClassesInModule(moduleName, ClassFilter.of(classNameFilter, classFilter)); } - /** - * @since 1.11 - * @see org.junit.platform.commons.support.ReflectionSupport#streamAllResourcesInModule(String, Predicate, Predicate) - */ - public static Stream streamAllResourcesInModule(String moduleName, Predicate resourceFilter, - Predicate resourceNameFilter) { - return streamAllResourcesInModule(moduleName, ResourceFilter.of(resourceNameFilter, resourceFilter)); - } - /** * @since 1.1.1 */ @@ -1250,7 +1194,7 @@ public static List> findAllClassesInModule(String moduleName, ClassFilt /** * @since 1.11 */ - public static List findAllResourcesInModule(String moduleName, ResourceFilter resourceFilter) { + public static List findAllResourcesInModule(String moduleName, Predicate resourceFilter) { return Collections.unmodifiableList(ModuleUtils.findAllResourcesInModule(moduleName, resourceFilter)); } @@ -1264,7 +1208,7 @@ public static Stream> streamAllClassesInModule(String moduleName, Class /** * @since 1.11 */ - public static Stream streamAllResourcesInModule(String moduleName, ResourceFilter resourceFilter) { + public static Stream streamAllResourcesInModule(String moduleName, Predicate resourceFilter) { return findAllResourcesInModule(moduleName, resourceFilter).stream(); } diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java deleted file mode 100644 index bde54890c85e..000000000000 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.commons.util; - -import static org.apiguardian.api.API.Status.INTERNAL; - -import java.util.function.Predicate; - -import org.apiguardian.api.API; -import org.junit.platform.commons.support.Resource; - -/** - * Resource-related predicate used by reflection utilities. - * - *

DISCLAIMER

- * - *

These utilities are intended solely for usage within the JUnit framework - * itself. Any usage by external parties is not supported. - * Use at your own risk! - * - * @since 1.11 - */ -@API(status = INTERNAL, since = "1.11") -public class ResourceFilter implements Predicate { - - /** - * Create a {@link ResourceFilter} instance that accepts all names but filters resources. - */ - public static ResourceFilter of(Predicate resourcePredicate) { - return of(name -> true, resourcePredicate); - } - - /** - * Create a {@link ResourceFilter} instance that filters by resource names and resources. - */ - public static ResourceFilter of(Predicate namePredicate, Predicate resourcePredicate) { - return new ResourceFilter(namePredicate, resourcePredicate); - } - - private final Predicate namePredicate; - private final Predicate resourcePredicate; - - private ResourceFilter(Predicate namePredicate, Predicate resourcePredicate) { - this.namePredicate = Preconditions.notNull(namePredicate, "name predicate must not be null"); - this.resourcePredicate = Preconditions.notNull(resourcePredicate, "resource predicate must not be null"); - } - - public boolean match(String name) { - return namePredicate.test(name); - } - - public boolean match(Resource resource) { - return resourcePredicate.test(resource); - } - - /** - * @implNote This implementation combines all tests stored in the predicates - * of this instance. Any new predicate must be added to this test method as - * well. - */ - @Override - public boolean test(Resource resource) { - return match(resource.getName()) && match(resource); - } -} diff --git a/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java b/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java index 9a5a70fc725c..f3a6bd1a5f33 100644 --- a/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java +++ b/junit-platform-commons/src/main/java9/org/junit/platform/commons/util/ModuleUtils.java @@ -128,7 +128,7 @@ public static List> findAllClassesInModule(String moduleName, ClassFilt * @since 1.11 */ @API(status = INTERNAL, since = "1.11") - public static List findAllResourcesInModule(String moduleName, ResourceFilter filter) { + public static List findAllResourcesInModule(String moduleName, Predicate filter) { Preconditions.notBlank(moduleName, "Module name must not be null or empty"); Preconditions.notNull(filter, "Resource filter must not be null"); @@ -186,7 +186,8 @@ private static List> scan(Set references, ClassFilter * Scan for classes using the supplied set of module references, class * filter, and loader. */ - private static List scan(Set references, ResourceFilter filter, ClassLoader loader) { + private static List scan(Set references, Predicate filter, + ClassLoader loader) { logger.debug(() -> "Scanning " + references.size() + " module references: " + references); ModuleReferenceResourceScanner scanner = new ModuleReferenceResourceScanner(filter, loader); List classes = new ArrayList<>(); @@ -267,10 +268,10 @@ private Class loadClassUnchecked(String binaryName) { */ static class ModuleReferenceResourceScanner { - private final ResourceFilter resourceFilter; + private final Predicate resourceFilter; private final ClassLoader classLoader; - ModuleReferenceResourceScanner(ResourceFilter resourceFilter, ClassLoader classLoader) { + ModuleReferenceResourceScanner(Predicate resourceFilter, ClassLoader classLoader) { this.resourceFilter = resourceFilter; this.classLoader = classLoader; } @@ -283,9 +284,7 @@ List scan(ModuleReference reference) { try (Stream names = reader.list()) { // @formatter:off return names.filter(name -> !name.endsWith(".class")) - .filter(resourceFilter::match) .map(this::loadResourceUnchecked) - // Always use ".filter(resourceFilter)" to include future predicates. .filter(resourceFilter) .collect(Collectors.toList()); // @formatter:on diff --git a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java index f9369610bf1b..5215fb17e4c5 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java @@ -168,8 +168,8 @@ List findAllResourcesInClasspathRootDelegates() throws Throwable { for (var path : paths) { var root = path.toUri(); tests.add(DynamicTest.dynamicTest(createDisplayName(root), - () -> assertEquals(ReflectionUtils.findAllResourcesInClasspathRoot(root, allResources, allNames), - ReflectionSupport.findAllResourcesInClasspathRoot(root, allResources, allNames)))); + () -> assertEquals(ReflectionUtils.findAllResourcesInClasspathRoot(root, allResources), + ReflectionSupport.findAllResourcesInClasspathRoot(root, allResources)))); } return tests; } @@ -181,11 +181,9 @@ List findAllResourcesInClasspathRootDelegates() throws Throwable { void findAllResourcesInClasspathRootPreconditions() { var path = Path.of(".").toUri(); assertPreconditionViolationException("root", - () -> ReflectionSupport.findAllResourcesInClasspathRoot(null, allResources, allNames)); - assertPreconditionViolationException("resource predicate", - () -> ReflectionSupport.findAllResourcesInClasspathRoot(path, null, allNames)); - assertPreconditionViolationException("name predicate", - () -> ReflectionSupport.findAllResourcesInClasspathRoot(path, allResources, null)); + () -> ReflectionSupport.findAllResourcesInClasspathRoot(null, allResources)); + assertPreconditionViolationException("resourceFilter", + () -> ReflectionSupport.findAllResourcesInClasspathRoot(path, null)); } /** @@ -200,9 +198,8 @@ List streamAllResourcesInClasspathRootDelegates() throws Throwable for (var path : paths) { var root = path.toUri(); tests.add(DynamicTest.dynamicTest(createDisplayName(root), - () -> assertEquals( - ReflectionUtils.streamAllResourcesInClasspathRoot(root, allResources, allNames).toList(), - ReflectionSupport.streamAllResourcesInClasspathRoot(root, allResources, allNames).toList()))); + () -> assertEquals(ReflectionUtils.streamAllResourcesInClasspathRoot(root, allResources).toList(), + ReflectionSupport.streamAllResourcesInClasspathRoot(root, allResources).toList()))); } return tests; } @@ -214,11 +211,9 @@ List streamAllResourcesInClasspathRootDelegates() throws Throwable void streamAllResourcesInClasspathRootPreconditions() { var path = Path.of(".").toUri(); assertPreconditionViolationException("root", - () -> ReflectionSupport.streamAllResourcesInClasspathRoot(null, allResources, allNames)); - assertPreconditionViolationException("resource predicate", - () -> ReflectionSupport.streamAllResourcesInClasspathRoot(path, null, allNames)); - assertPreconditionViolationException("name predicate", - () -> ReflectionSupport.streamAllResourcesInClasspathRoot(path, allResources, null)); + () -> ReflectionSupport.streamAllResourcesInClasspathRoot(null, allResources)); + assertPreconditionViolationException("resourceFilter", + () -> ReflectionSupport.streamAllResourcesInClasspathRoot(path, null)); } @Test @@ -243,10 +238,10 @@ void findAllClassesInPackagePreconditions() { */ @Test void findAllResourcesInPackageDelegates() { - assertNotEquals(0, ReflectionSupport.findAllResourcesInPackage("org.junit", allResources, allNames).size()); + assertNotEquals(0, ReflectionSupport.findAllResourcesInPackage("org.junit", allResources).size()); - assertEquals(ReflectionUtils.findAllResourcesInPackage("org.junit", allResources, allNames), - ReflectionSupport.findAllResourcesInPackage("org.junit", allResources, allNames)); + assertEquals(ReflectionUtils.findAllResourcesInPackage("org.junit", allResources), + ReflectionSupport.findAllResourcesInPackage("org.junit", allResources)); } /** @@ -255,11 +250,9 @@ void findAllResourcesInPackageDelegates() { @Test void findAllResourcesInPackagePreconditions() { assertPreconditionViolationExceptionForString("basePackageName", - () -> ReflectionSupport.findAllResourcesInPackage(null, allResources, allNames)); - assertPreconditionViolationException("resource predicate", - () -> ReflectionSupport.findAllResourcesInPackage("org.junit", null, allNames)); - assertPreconditionViolationException("name predicate", - () -> ReflectionSupport.findAllResourcesInPackage("org.junit", allResources, null)); + () -> ReflectionSupport.findAllResourcesInPackage(null, allResources)); + assertPreconditionViolationException("resourceFilter", + () -> ReflectionSupport.findAllResourcesInPackage("org.junit", null)); } /** @@ -267,10 +260,10 @@ void findAllResourcesInPackagePreconditions() { */ @Test void streamAllResourcesInPackageDelegates() { - assertNotEquals(0, ReflectionSupport.streamAllResourcesInPackage("org.junit", allResources, allNames).count()); + assertNotEquals(0, ReflectionSupport.streamAllResourcesInPackage("org.junit", allResources).count()); - assertEquals(ReflectionUtils.streamAllResourcesInPackage("org.junit", allResources, allNames).toList(), - ReflectionSupport.streamAllResourcesInPackage("org.junit", allResources, allNames).toList()); + assertEquals(ReflectionUtils.streamAllResourcesInPackage("org.junit", allResources).toList(), + ReflectionSupport.streamAllResourcesInPackage("org.junit", allResources).toList()); } /** @@ -279,11 +272,9 @@ void streamAllResourcesInPackageDelegates() { @Test void streamAllResourcesInPackagePreconditions() { assertPreconditionViolationExceptionForString("basePackageName", - () -> ReflectionSupport.streamAllResourcesInPackage(null, allResources, allNames)); - assertPreconditionViolationException("resource predicate", - () -> ReflectionSupport.streamAllResourcesInPackage("org.junit", null, allNames)); - assertPreconditionViolationException("name predicate", - () -> ReflectionSupport.streamAllResourcesInPackage("org.junit", allResources, null)); + () -> ReflectionSupport.streamAllResourcesInPackage(null, allResources)); + assertPreconditionViolationException("resourceFilter", + () -> ReflectionSupport.streamAllResourcesInPackage("org.junit", null)); } @Test @@ -308,8 +299,8 @@ void findAllClassesInModulePreconditions() { */ @Test void findAllResourcesInModuleDelegates() { - assertEquals(ReflectionUtils.findAllResourcesInModule("org.junit.platform.commons", allResources, allNames), - ReflectionSupport.findAllResourcesInModule("org.junit.platform.commons", allResources, allNames)); + assertEquals(ReflectionUtils.findAllResourcesInModule("org.junit.platform.commons", allResources), + ReflectionSupport.findAllResourcesInModule("org.junit.platform.commons", allResources)); } /** @@ -318,12 +309,10 @@ void findAllResourcesInModuleDelegates() { @Test void findAllResourcesInModulePreconditions() { var exception = assertThrows(PreconditionViolationException.class, - () -> ReflectionSupport.findAllResourcesInModule(null, allResources, allNames)); + () -> ReflectionSupport.findAllResourcesInModule(null, allResources)); assertEquals("Module name must not be null or empty", exception.getMessage()); - assertPreconditionViolationException("resource predicate", - () -> ReflectionSupport.findAllResourcesInModule("org.junit.platform.commons", null, allNames)); - assertPreconditionViolationException("name predicate", - () -> ReflectionSupport.findAllResourcesInModule("org.junit.platform.commons", allResources, null)); + assertPreconditionViolationException("Resource filter", + () -> ReflectionSupport.findAllResourcesInModule("org.junit.platform.commons", null)); } /** @@ -331,10 +320,8 @@ void findAllResourcesInModulePreconditions() { */ @Test void streamAllResourcesInModuleDelegates() { - assertEquals( - ReflectionUtils.streamAllResourcesInModule("org.junit.platform.commons", allResources, allNames).toList(), - ReflectionSupport.streamAllResourcesInModule("org.junit.platform.commons", allResources, - allNames).toList()); + assertEquals(ReflectionUtils.streamAllResourcesInModule("org.junit.platform.commons", allResources).toList(), + ReflectionSupport.streamAllResourcesInModule("org.junit.platform.commons", allResources).toList()); } /** @@ -343,12 +330,10 @@ void streamAllResourcesInModuleDelegates() { @Test void streamAllResourcesInModulePreconditions() { var exception = assertThrows(PreconditionViolationException.class, - () -> ReflectionSupport.streamAllResourcesInModule(null, allResources, allNames)); + () -> ReflectionSupport.streamAllResourcesInModule(null, allResources)); assertEquals("Module name must not be null or empty", exception.getMessage()); - assertPreconditionViolationException("resource predicate", - () -> ReflectionSupport.streamAllResourcesInModule("org.junit.platform.commons", null, allNames)); - assertPreconditionViolationException("name predicate", - () -> ReflectionSupport.streamAllResourcesInModule("org.junit.platform.commons", allResources, null)); + assertPreconditionViolationException("Resource filter", + () -> ReflectionSupport.streamAllResourcesInModule("org.junit.platform.commons", null)); } @Test diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java index 47ea5fa864f8..2fad77ba92d5 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java @@ -60,19 +60,15 @@ class ClasspathScannerTests { private static final ClassFilter allClasses = ClassFilter.of(type -> true); - private static final ResourceFilter allResources = ResourceFilter.of(type -> true); + private static final Predicate allResources = type -> true; private final List> loadedClasses = new ArrayList<>(); - private final List loadedResources = new ArrayList<>(); private final BiFunction>> trackingClassLoader = (name, classLoader) -> ReflectionUtils.tryToLoadClass(name, classLoader).ifSuccess(loadedClasses::add); - private final BiFunction> trackingResourceLoader = (name, - classLoader) -> ReflectionUtils.tryToLoadResource(name, classLoader).ifSuccess(loadedResources::add); - private final ClasspathScanner classpathScanner = new ClasspathScanner(ClassLoaderUtils::getDefaultClassLoader, - trackingClassLoader, trackingResourceLoader); + trackingClassLoader); @Test void scanForClassesInClasspathRootWhenMalformedClassnameInternalErrorOccursWithNullDetailedMessage( @@ -150,9 +146,7 @@ void scanForResourcesInClasspathRootWhenGenericRuntimeExceptionOccurs(LogRecordL } private void assertResourcesScannedWhenExceptionIsThrown(Predicate filter) { - var resourceFilter = ResourceFilter.of(filter); - var resources = this.classpathScanner.scanForResourcesInClasspathRoot(getTestClasspathResourceRoot(), - resourceFilter); + var resources = this.classpathScanner.scanForResourcesInClasspathRoot(getTestClasspathResourceRoot(), filter); assertThat(resources).hasSizeGreaterThanOrEqualTo(150); } @@ -193,8 +187,7 @@ private void scanForClassesInClasspathRootWithinJarFile(String resourceName) thr var jarfile = getClass().getResource(resourceName); try (var classLoader = new URLClassLoader(new URL[] { jarfile }, null)) { - var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass, - ReflectionUtils::tryToLoadResource); + var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass); var classes = classpathScanner.scanForClassesInClasspathRoot(jarfile.toURI(), allClasses); assertThat(classes).extracting(Class::getName) // @@ -218,8 +211,7 @@ private void scanForResourcesInClasspathRootWithinJarFile(String resourceName) t var jarfile = getClass().getResource(resourceName); try (var classLoader = new URLClassLoader(new URL[] { jarfile }, null)) { - var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass, - ReflectionUtils::tryToLoadResource); + var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass); var resources = classpathScanner.scanForResourcesInClasspathRoot(jarfile.toURI(), allResources); assertThat(resources).extracting(Resource::getName) // @@ -236,8 +228,7 @@ void scanForResourcesInShadowedClassPathRoot() throws Exception { var shadowedJarFile = getClass().getResource("/jartest-shadowed.jar"); try (var classLoader = new URLClassLoader(new URL[] { jarFile, shadowedJarFile }, null)) { - var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass, - ReflectionUtils::tryToLoadResource); + var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass); var resources = classpathScanner.scanForResourcesInClasspathRoot(shadowedJarFile.toURI(), allResources); assertThat(resources).extracting(Resource::getName).containsExactlyInAnyOrder( @@ -252,10 +243,10 @@ void scanForResourcesInShadowedClassPathRoot() throws Exception { // This resource only exists in the shadowed jar file "jartest-shadowed.jar!/org/junit/platform/jartest/included/unique.resource", // These resources exist in both the jar and shadowed jar file. - // So they're discovered in the shadowed jar, but loaded from the regular jar. - "jartest.jar!/org/junit/platform/jartest/included/included.resource", - "jartest.jar!/org/junit/platform/jartest/included/recursive/recursively-included.resource", - "jartest.jar!/META-INF/MANIFEST.MF"); + // They must be discovered in the shadowed jar as we're searching in that classpath root. + "jartest-shadowed.jar!/org/junit/platform/jartest/included/included.resource", + "jartest-shadowed.jar!/org/junit/platform/jartest/included/recursive/recursively-included.resource", + "jartest-shadowed.jar!/META-INF/MANIFEST.MF"); } } @@ -314,8 +305,7 @@ private void checkModules2500(ModuleFinder finder) { var parent = ClassLoader.getPlatformClassLoader(); var layer = ModuleLayer.defineModulesWithOneLoader(configuration, List.of(boot), parent).layer(); - var classpathScanner = new ClasspathScanner(() -> layer.findLoader(root), ReflectionUtils::tryToLoadClass, - ReflectionUtils::tryToLoadResource); + var classpathScanner = new ClasspathScanner(() -> layer.findLoader(root), ReflectionUtils::tryToLoadClass); { var classes = classpathScanner.scanForClassesInPackage("foo", allClasses); var classNames = classes.stream().map(Class::getName).collect(Collectors.toList()); @@ -334,8 +324,7 @@ void findAllClassesInPackageWithinJarFileConcurrently() throws Exception { var jarUri = URI.create("jar:" + jarFile); try (var classLoader = new URLClassLoader(new URL[] { jarFile })) { - var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass, - ReflectionUtils::tryToLoadResource); + var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass); var results = executeConcurrently(10, () -> classpathScanner.scanForClassesInPackage("org.junit.platform.jartest.included", allClasses)); @@ -356,8 +345,7 @@ void findAllResourcesInPackageWithinJarFileConcurrently() throws Exception { var jarUri = URI.create("jar:" + jarFile); try (var classLoader = new URLClassLoader(new URL[] { jarFile })) { - var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass, - ReflectionUtils::tryToLoadResource); + var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass); var results = executeConcurrently(10, () -> classpathScanner.scanForResourcesInPackage("org.junit.platform.jartest.included", allResources)); @@ -388,7 +376,7 @@ void scanForClassesInDefaultPackage() { @Test void scanForResourcesInDefaultPackage() { - var resourceFilter = ResourceFilter.of(this::inDefaultPackage); + Predicate resourceFilter = this::inDefaultPackage; var resources = classpathScanner.scanForResourcesInPackage("", resourceFilter); assertThat(resources).as("number of resources found in default package").isNotEmpty(); @@ -405,8 +393,8 @@ void scanForClassesInPackageWithFilter() { @Test void scanForResourcesInPackageWithFilter() { - var thisResourceOnly = ResourceFilter.of( - resource -> "org/junit/platform/commons/example.resource".equals(resource.getName())); + Predicate thisResourceOnly = resource -> "org/junit/platform/commons/example.resource".equals( + resource.getName()); var resources = classpathScanner.scanForResourcesInPackage("org.junit.platform.commons", thisResourceOnly); assertThat(resources).extracting(Resource::getName).containsExactly( "org/junit/platform/commons/example.resource"); @@ -414,8 +402,8 @@ void scanForResourcesInPackageWithFilter() { @Test void resourcesCanBeRead() throws IOException { - var thisResourceOnly = ResourceFilter.of( - resource -> "org/junit/platform/commons/example.resource".equals(resource.getName())); + Predicate thisResourceOnly = resource -> "org/junit/platform/commons/example.resource".equals( + resource.getName()); var resources = classpathScanner.scanForResourcesInPackage("org.junit.platform.commons", thisResourceOnly); Resource resource = resources.get(0); @@ -459,16 +447,14 @@ void scanForClassesInPackageForNullClassFilter() { @Test void scanForClassesInPackageWhenIOExceptionOccurs() { - var scanner = new ClasspathScanner(ThrowingClassLoader::new, ReflectionUtils::tryToLoadClass, - ReflectionUtils::tryToLoadResource); + var scanner = new ClasspathScanner(ThrowingClassLoader::new, ReflectionUtils::tryToLoadClass); var classes = scanner.scanForClassesInPackage("org.junit.platform.commons", allClasses); assertThat(classes).isEmpty(); } @Test void scanForResourcesInPackageWhenIOExceptionOccurs() { - var scanner = new ClasspathScanner(ThrowingClassLoader::new, ReflectionUtils::tryToLoadClass, - ReflectionUtils::tryToLoadResource); + var scanner = new ClasspathScanner(ThrowingClassLoader::new, ReflectionUtils::tryToLoadClass); var classes = scanner.scanForResourcesInPackage("org.junit.platform.commons", allResources); assertThat(classes).isEmpty(); } @@ -483,17 +469,6 @@ void scanForClassesInPackageOnlyLoadsClassesThatAreIncludedByTheClassNameFilter( assertThat(loadedClasses).containsExactly(ClasspathScannerTests.class); } - @Test - void scanForResourcesInPackageOnlyLoadsResourcesThatAreIncludedByTheResourceNameFilter() { - Predicate resourceNameFilter = name -> name.endsWith("/example.resource"); - var resourceFilter = ResourceFilter.of(resourceNameFilter, type -> true); - - classpathScanner.scanForResourcesInPackage("org.junit.platform.commons", resourceFilter); - - assertThat(loadedResources).extracting(Resource::getName).containsExactly( - "org/junit/platform/commons/example.resource"); - } - @Test void findAllClassesInClasspathRoot() throws Exception { var thisClassOnly = ClassFilter.of(clazz -> clazz == ClasspathScannerTests.class); @@ -575,18 +550,6 @@ void onlyLoadsClassesInClasspathRootThatAreIncludedByTheClassNameFilter() throws assertThat(loadedClasses).containsExactly(ClasspathScannerTests.class); } - @Test - void onlyLoadsResourcesInClasspathRootThatAreIncludedByTheResourceNameFilter() { - Predicate resourceNameFilter = name -> name.endsWith("/example.resource"); - var resourceFilter = ResourceFilter.of(resourceNameFilter, type -> true); - var root = getTestClasspathResourceRoot(); - - classpathScanner.scanForResourcesInClasspathRoot(root, resourceFilter); - - assertThat(loadedResources).extracting(Resource::getName).containsExactly( - "org/junit/platform/commons/example.resource"); - } - private static URI uriOf(String name) { var resource = ClasspathScannerTests.class.getResource(name); try { From ee7b42a54876aef2a89bf3f5ac35d4f04e5a81d2 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Mon, 8 Jul 2024 21:00:20 +0200 Subject: [PATCH 48/78] Remove unused tryToLoadResource --- .../commons/support/ReflectionSupport.java | 22 ---------- .../commons/util/ReflectionUtils.java | 28 ------------- .../support/ReflectionSupportTests.java | 26 ------------ .../commons/util/ReflectionUtilsTests.java | 40 ------------------- 4 files changed, 116 deletions(-) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java index aceeeef12951..2c297d23e07f 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java @@ -19,7 +19,6 @@ import java.net.URI; import java.util.List; import java.util.Optional; -import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Stream; @@ -114,27 +113,6 @@ public static Try> tryToLoadClass(String name, ClassLoader classLoader) return ReflectionUtils.tryToLoadClass(name, classLoader); } - /** - * Tries to load the {@link Resource} for the supplied classpath resource name. - * - *

The name of a classpath resource must follow the semantics - * for resource paths as defined in {@link ClassLoader#getResource(String)}. - * - *

If the supplied classpath resource name is prefixed with a slash - * ({@code /}), the slash will be removed. - * - * @param classpathResourceName the name of the resource to load; never {@code null} or blank - * @param classLoader the {@code ClassLoader} to use; never {@code null} - * @return a successful {@code Try} containing the loaded class or a failed - * {@code Try} containing the exception if no such resource could be loaded; - * never {@code null} - * @since 1.11 - */ - @API(status = EXPERIMENTAL, since = "1.11") - public static Try tryToLoadResource(String classpathResourceName, ClassLoader classLoader) { - return ReflectionUtils.tryToLoadResource(classpathResourceName, classLoader); - } - /** * Find all {@linkplain Class classes} in the supplied classpath {@code root} * that match the specified {@code classFilter} and {@code classNameFilter} diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java index 451c92f63bb3..517ee073f273 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java @@ -35,7 +35,6 @@ import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.net.URI; -import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -891,33 +890,6 @@ public static Try> tryToLoadClass(String name, ClassLoader classLoader) }); } - /** - * Tries to load the {@link Resource} for the supplied classpath resource name. - * - *

See {@link org.junit.platform.commons.support.ReflectionSupport#tryToLoadResource(String, ClassLoader)} - * for details. - * - * @param classpathResourceName the name of the resource to load; never {@code null} or blank - * @param classLoader the {@code ClassLoader} to use; never {@code null} - * @since 1.11 - */ - @API(status = INTERNAL, since = "1.11") - public static Try tryToLoadResource(String classpathResourceName, ClassLoader classLoader) { - Preconditions.notBlank(classpathResourceName, "Resource name must not be null or blank"); - Preconditions.notNull(classLoader, "ClassLoader must not be null"); - boolean startsWithSlash = classpathResourceName.startsWith("/"); - String canonicalClasspathResourceName = (startsWithSlash ? classpathResourceName.substring(1) - : classpathResourceName); - - return Try.call(() -> { - URL resource = classLoader.getResource(canonicalClasspathResourceName); - if (resource == null) { - throw new NullPointerException("classLoader.getResource returned null"); - } - return new ClasspathResource(canonicalClasspathResourceName, resource.toURI()); - }); - } - private static Class loadArrayType(ClassLoader classLoader, String componentTypeName, int dimensions) throws ClassNotFoundException { diff --git a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java index 5215fb17e4c5..2673b6747c60 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java @@ -91,17 +91,6 @@ void tryToLoadClassWithExplicitClassLoaderDelegates() { ReflectionSupport.tryToLoadClass("java.nio.Bits", classLoader)); } - /** - * @since 1.11 - */ - @Test - void tryToLoadResourcesWithExplicitClassLoaderDelegates() { - var classLoader = getClass().getClassLoader(); - var resource = "org/junit/platform/commons/example.resource"; - assertEquals(ReflectionUtils.tryToLoadResource(resource, classLoader).toOptional(), - ReflectionSupport.tryToLoadResource(resource, classLoader).toOptional()); - } - /** * @since 1.10 */ @@ -115,21 +104,6 @@ void tryToLoadClassWithExplicitClassLoaderPreconditions() { assertPreconditionViolationException("ClassLoader", () -> ReflectionSupport.tryToLoadClass("int", null)); } - /** - * @since 1.11 - */ - @Test - void tryToLoadResourceWithExplicitClassLoaderPreconditions() { - ClassLoader cl = getClass().getClassLoader(); - - assertPreconditionViolationExceptionForString("Resource name", - () -> ReflectionSupport.tryToLoadResource(null, cl)); - assertPreconditionViolationExceptionForString("Resource name", - () -> ReflectionSupport.tryToLoadResource("", cl)); - - assertPreconditionViolationException("ClassLoader", () -> ReflectionSupport.tryToLoadResource("int", null)); - } - @TestFactory List findAllClassesInClasspathRootDelegates() throws Throwable { List tests = new ArrayList<>(); diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java index 7ab8aa5e893a..1def4526fbe4 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java @@ -710,46 +710,6 @@ private void privateMethod() { } - @Nested - class ResourceLoadingTests { - - @Test - void tryToLoadResourcePreconditions() { - assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.tryToLoadResource("", null)); - assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.tryToLoadResource(" ", null)); - - assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.tryToLoadResource(null, null)); - assertThrows(PreconditionViolationException.class, - () -> ReflectionUtils.tryToLoadResource("org/junit/platform/commons/example.resource", null)); - } - - @Test - void tryToLoadResource() { - var classLoader = ClassLoaderUtils.getDefaultClassLoader(); - var tryToLoadResource = ReflectionUtils.tryToLoadResource("org/junit/platform/commons/example.resource", - classLoader); - var resource = assertDoesNotThrow(tryToLoadResource::get); - assertThat(resource.getName()).isEqualTo("org/junit/platform/commons/example.resource"); - } - - @Test - void tryToLoadResourceWithPrefixedSlash() { - var classLoader = ClassLoaderUtils.getDefaultClassLoader(); - var tryToLoadResource = ReflectionUtils.tryToLoadResource("/org/junit/platform/commons/example.resource", - classLoader); - var resource = assertDoesNotThrow(tryToLoadResource::get); - assertThat(resource.getName()).isEqualTo("org/junit/platform/commons/example.resource"); - } - - @Test - void tryToLoadResourceWhenResourceNotFound() { - var classLoader = ClassLoaderUtils.getDefaultClassLoader(); - var tryToLoadResource = ReflectionUtils.tryToLoadResource("org/junit/platform/commons/no-such.resource", - classLoader); - assertThrows(NullPointerException.class, tryToLoadResource::get); - } - } - @Nested class ClassLoadingTests { From c0c9ee6c922e98e05470deeb9f7b4b19ebc2a09b Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Mon, 8 Jul 2024 21:05:14 +0200 Subject: [PATCH 49/78] Suppress warnings --- .../junit/platform/commons/support/ReflectionSupportTests.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java index 2673b6747c60..adb986154b79 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java @@ -472,9 +472,11 @@ private static String createDisplayName(URI root) { static class ClassWithNestedClasses { + @SuppressWarnings({ "InnerClassMayBeStatic", "unused" }) class Nested1 { } + @SuppressWarnings("unused") static class Nested2 { } From 8621935fe22753334450d13ff7f14bd74c094af2 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Tue, 9 Jul 2024 15:55:50 +0200 Subject: [PATCH 50/78] Remove resourceNameFilter predicate from Javadoc --- .../commons/support/ReflectionSupport.java | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java index 2c297d23e07f..6d63e015fccc 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java @@ -138,8 +138,7 @@ public static List> findAllClassesInClasspathRoot(URI root, PredicateThe classpath scanning algorithm searches recursively in subpackages * beginning with the root of the classpath. @@ -186,8 +185,7 @@ public static Stream> streamAllClassesInClasspathRoot(URI root, Predica /** * Find all {@linkplain Resource resources} in the supplied classpath {@code root} - * that match the specified {@code resourceFilter} and {@code resourceNameFilter} - * predicates. + * that match the specified {@code resourceFilter} predicate. * *

The classpath scanning algorithm searches recursively in subpackages * beginning with the root of the classpath. @@ -233,8 +231,7 @@ public static List> findAllClassesInPackage(String basePackageName, Pre /** * Find all {@linkplain Resource resources} in the supplied {@code basePackageName} - * that match the specified {@code resourceFilter} and {@code resourceNameFilter} - * predicates. + * that match the specified {@code resourceFilter} predicate. * *

The classpath scanning algorithm searches recursively in subpackages * beginning within the supplied base package. @@ -283,8 +280,7 @@ public static Stream> streamAllClassesInPackage(String basePackageName, /** * Find all {@linkplain Resource resources} in the supplied {@code basePackageName} - * that match the specified {@code resourceFilter} and {@code resourceNameFilter} - * predicates. + * that match the specified {@code resourceFilter} predicate. * *

The classpath scanning algorithm searches recursively in subpackages * beginning within the supplied base package. @@ -332,8 +328,7 @@ public static List> findAllClassesInModule(String moduleName, Predicate /** * Find all {@linkplain Resource resources} in the supplied {@code moduleName} - * that match the specified {@code resourceFilter} and {@code resourceNameFilter} - * predicates. + * that match the specified {@code resourceFilter} predicate. * *

The module-path scanning algorithm searches recursively in all * packages contained in the module. @@ -380,8 +375,7 @@ public static Stream> streamAllClassesInModule(String moduleName, Predi /** * Find all {@linkplain Resource resources} in the supplied {@code moduleName} - * that match the specified {@code resourceFilter} and {@code resourceNameFilter} - * predicates. + * that match the specified {@code resourceFilter} predicate. * *

The module-path scanning algorithm searches recursively in all * packages contained in the module. From 3a146963d2a98613bc34fb5f239a60f2a059d414 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Tue, 9 Jul 2024 15:56:33 +0200 Subject: [PATCH 51/78] Add test for finding duplicate resources --- .../commons/util/ClasspathScannerTests.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java index 2fad77ba92d5..7cd2f31456b4 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/ClasspathScannerTests.java @@ -250,6 +250,30 @@ void scanForResourcesInShadowedClassPathRoot() throws Exception { } } + @Test + void scanForResourcesInPackageWithDuplicateResources() throws Exception { + var jarFile = getClass().getResource("/jartest.jar"); + var shadowedJarFile = getClass().getResource("/jartest-shadowed.jar"); + + try (var classLoader = new URLClassLoader(new URL[] { jarFile, shadowedJarFile }, null)) { + var classpathScanner = new ClasspathScanner(() -> classLoader, ReflectionUtils::tryToLoadClass); + + var resources = classpathScanner.scanForResourcesInPackage("org.junit.platform.jartest.included", + allResources); + + assertThat(resources).extracting(Resource::getUri) // + .map(ClasspathScannerTests::jarFileAndEntry) // + .containsExactlyInAnyOrder( + // This resource only exists in the shadowed jar file + "jartest-shadowed.jar!/org/junit/platform/jartest/included/unique.resource", + // These resources exist in both the jar and shadowed jar file. + "jartest.jar!/org/junit/platform/jartest/included/included.resource", + "jartest-shadowed.jar!/org/junit/platform/jartest/included/included.resource", + "jartest.jar!/org/junit/platform/jartest/included/recursive/recursively-included.resource", + "jartest-shadowed.jar!/org/junit/platform/jartest/included/recursive/recursively-included.resource"); + } + } + private static String jarFileAndEntry(URI uri) { var uriString = uri.toString(); int lastJarUriSeparator = uriString.lastIndexOf("!/"); From e8ef19aeaf8f70e18ee045b83ff80016089304a4 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Fri, 12 Jul 2024 13:43:11 +0200 Subject: [PATCH 52/78] Rename tryToLoadResource to tryToGetResource Classes are loaded, resources are gotten --- .../commons/support/ReflectionSupport.java | 14 +++++----- .../commons/util/ReflectionUtils.java | 10 +++---- .../platform/commons/util/ResourceFilter.java | 16 +++++------ .../discovery/ClasspathResourceSelector.java | 4 +-- .../engine/discovery/DiscoverySelectors.java | 3 +- .../ResourceContainerSelectorResolver.java | 5 ++-- .../support/ReflectionSupportTests.java | 12 ++++---- .../commons/util/ReflectionUtilsTests.java | 28 +++++++++---------- 8 files changed, 47 insertions(+), 45 deletions(-) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java index 9aca927b8e89..6565a51a7915 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java @@ -130,8 +130,8 @@ public static Try> tryToLoadClass(String name, ClassLoader classLoader) * @since 1.11 */ @API(status = EXPERIMENTAL, since = "1.11") - public static Try tryToLoadResource(String classpathResourceName) { - return ReflectionUtils.tryToLoadResource(classpathResourceName); + public static Try tryToGetResource(String classpathResourceName) { + return ReflectionUtils.tryToGetResource(classpathResourceName); } /** @@ -151,8 +151,8 @@ public static Try tryToLoadResource(String classpathResourceName) { * @since 1.11 */ @API(status = EXPERIMENTAL, since = "1.11") - public static Try tryToLoadResource(String classpathResourceName, ClassLoader classLoader) { - return ReflectionUtils.tryToLoadResource(classpathResourceName, classLoader); + public static Try tryToGetResource(String classpathResourceName, ClassLoader classLoader) { + return ReflectionUtils.tryToGetResource(classpathResourceName, classLoader); } /** @@ -280,7 +280,7 @@ public static List> findAllClassesInPackage(String basePackageName, Pre * *

The resulting list may include identically named resources from different * classpath roots. These can be filtered out using - * {@link org.junit.platform.commons.util.ResourceFilter#loadClasspathResource(Function)}. + * {@link org.junit.platform.commons.util.ResourceFilter#getClasspathResource(Function)}. * * @param basePackageName the name of the base package in which to start * scanning; must not be {@code null} and must be valid in terms of Java @@ -308,7 +308,7 @@ public static List findAllResourcesInPackage(String basePackageName, P * *

The resulting stream may include identically named resources from different * classpath roots. These can be filtered out using - * {@link org.junit.platform.commons.util.ResourceFilter#loadClasspathResource(Function)}. + * {@link org.junit.platform.commons.util.ResourceFilter#getClasspathResource(Function)}. * * @param basePackageName the name of the base package in which to start * scanning; must not be {@code null} and must be valid in terms of Java @@ -337,7 +337,7 @@ public static Stream> streamAllClassesInPackage(String basePackageName, * *

The resulting stream may include identically named resources from different * classpath roots. These can be filtered out using - * {@link org.junit.platform.commons.util.ResourceFilter#loadClasspathResource(Function)}. + * {@link org.junit.platform.commons.util.ResourceFilter#getClasspathResource(Function)}. * * @param basePackageName the name of the base package in which to start * scanning; must not be {@code null} and must be valid in terms of Java diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java index 3a80098eb048..a6e25dc74d19 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java @@ -896,17 +896,17 @@ public static Try> tryToLoadClass(String name, ClassLoader classLoader) * * @param classpathResourceName the name of the resource to load; never {@code null} or blank * @since 1.11 - * @see org.junit.platform.commons.support.ReflectionSupport#tryToLoadResource(String, ClassLoader) + * @see org.junit.platform.commons.support.ReflectionSupport#tryToGetResource(String, ClassLoader) */ @API(status = INTERNAL, since = "1.11") - public static Try tryToLoadResource(String classpathResourceName) { - return tryToLoadResource(classpathResourceName, ClassLoaderUtils.getDefaultClassLoader()); + public static Try tryToGetResource(String classpathResourceName) { + return tryToGetResource(classpathResourceName, ClassLoaderUtils.getDefaultClassLoader()); } /** * Tries to load the {@link Resource} for the supplied classpath resource name. * - *

See {@link org.junit.platform.commons.support.ReflectionSupport#tryToLoadResource(String, ClassLoader)} + *

See {@link org.junit.platform.commons.support.ReflectionSupport#tryToGetResource(String, ClassLoader)} * for details. * * @param classpathResourceName the name of the resource to load; never {@code null} or blank @@ -914,7 +914,7 @@ public static Try tryToLoadResource(String classpathResourceName) { * @since 1.11 */ @API(status = INTERNAL, since = "1.11") - public static Try tryToLoadResource(String classpathResourceName, ClassLoader classLoader) { + public static Try tryToGetResource(String classpathResourceName, ClassLoader classLoader) { Preconditions.notBlank(classpathResourceName, "Resource name must not be null or blank"); Preconditions.notNull(classLoader, "ClassLoader must not be null"); boolean startsWithSlash = classpathResourceName.startsWith("/"); diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java index 8dc7f5b2ce03..e8ed83b014a3 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java @@ -21,7 +21,7 @@ import org.junit.platform.commons.support.Resource; /** - * Resource-related predicates for use with {@link org.junit.platform.commons.support.ReflectionSupport}. + * Resource-related predicates for use with {@link ReflectionSupport}. * * @since 1.11 */ @@ -35,8 +35,8 @@ public class ResourceFilter { /** * TODO: */ - public static Function loadClasspathResource() { - return loadClasspathResource(ReflectionSupport::tryToLoadResource); + public static Function getClasspathResource() { + return getClasspathResource(ReflectionSupport::tryToGetResource); } /** @@ -44,18 +44,18 @@ public static Function loadClasspathResource() { * * Include only resources that can be loaded by a class loader. *

- * Resources discovered by {@link org.junit.platform.commons.support.ReflectionSupport} + * Resources discovered by {@link ReflectionSupport} * may include identically named resources from different class * path roots. To get * - * @param loadResource function to load the resource, e.g. {@link org.junit.platform.commons.support.ReflectionSupport#tryToLoadResource(String)}. + * @param loadResource function to load the resource, e.g. {@link ReflectionSupport#tryToGetResource(String)}. * @return a function that for a given resource, returns the resource as it would bye loaded by {@link ClassLoader#getResource(String)} * - * @see ReflectionUtils#tryToLoadResource(String) - * @see ReflectionUtils#tryToLoadResource(String, ClassLoader) + * @see ReflectionUtils#tryToGetResource(String) + * @see ReflectionUtils#tryToGetResource(String, ClassLoader) */ - public static Function loadClasspathResource(Function> loadResource) { + public static Function getClasspathResource(Function> loadResource) { return candidate -> loadResource.apply(candidate.getName()) // .toOptional() // .map(loaded -> { diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java index b13431939385..596b69dd00d8 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java @@ -90,8 +90,8 @@ public String getClasspathResourceName() { public Resource getClasspathResource() { if (this.classpathResource == null) { // @formatter:off - Try tryToLoadResource = ReflectionUtils.tryToLoadResource(this.classpathResourceName); - this.classpathResource = tryToLoadResource.getOrThrow(cause -> + Try tryToGetResource = ReflectionUtils.tryToGetResource(this.classpathResourceName); + this.classpathResource = tryToGetResource.getOrThrow(cause -> new PreconditionViolationException("Could not load resource with name: " + this.classpathResourceName, cause)); // @formatter:on } diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java index d1ed0141cd60..f20af2f5dde3 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java @@ -29,6 +29,7 @@ import org.apiguardian.api.API; import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.commons.support.ReflectionSupport; import org.junit.platform.commons.support.Resource; import org.junit.platform.commons.util.Preconditions; import org.junit.platform.commons.util.ReflectionUtils; @@ -339,7 +340,7 @@ public static ClasspathResourceSelector selectClasspathResource(String classpath * @see #selectClasspathResource(String, FilePosition) * @see #selectClasspathResource(String) * @see ClasspathResourceSelector - * @see org.junit.platform.commons.support.ReflectionSupport#tryToLoadResource(String) + * @see ReflectionSupport#tryToGetResource(String) */ @API(status = EXPERIMENTAL, since = "1.11") public static ClasspathResourceSelector selectClasspathResource(Resource classpathResource) { diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java index c625c1e6024f..5e25c09aba6e 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java @@ -14,7 +14,7 @@ import static org.junit.platform.commons.support.ReflectionSupport.findAllResourcesInClasspathRoot; import static org.junit.platform.commons.support.ReflectionSupport.findAllResourcesInPackage; import static org.junit.platform.commons.util.ReflectionUtils.findAllResourcesInModule; -import static org.junit.platform.commons.util.ResourceFilter.loadClasspathResource; +import static org.junit.platform.commons.util.ResourceFilter.getClasspathResource; import static org.junit.platform.commons.util.ResourceFilter.packageName; import static org.junit.platform.engine.support.discovery.SelectorResolver.Resolution.selectors; import static org.junit.platform.engine.support.discovery.SelectorResolver.Resolution.unresolved; @@ -25,6 +25,7 @@ import java.util.function.Predicate; import org.junit.platform.commons.support.Resource; +import org.junit.platform.commons.util.ResourceFilter; import org.junit.platform.engine.discovery.ClasspathResourceSelector; import org.junit.platform.engine.discovery.ClasspathRootSelector; import org.junit.platform.engine.discovery.DiscoverySelectors; @@ -35,7 +36,7 @@ * @since 1.11 */ class ResourceContainerSelectorResolver implements SelectorResolver { - private static final Function classpathResource = loadClasspathResource(); + private static final Function classpathResource = ResourceFilter.getClasspathResource(); private final Predicate packageFilter; private final Predicate resourceFilter; diff --git a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java index 7e341c43e957..a9a564f6a35c 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java @@ -123,18 +123,18 @@ List findAllClassesInClasspathRootDelegates() throws Throwable { * @since 1.11 */ @Test - void tryToLoadResourcePreconditions() { - assertPreconditionViolationExceptionForString("Resource name", () -> ReflectionSupport.tryToLoadResource(null)); - assertPreconditionViolationExceptionForString("Resource name", () -> ReflectionSupport.tryToLoadResource("")); + void tryToGetResourcePreconditions() { + assertPreconditionViolationExceptionForString("Resource name", () -> ReflectionSupport.tryToGetResource(null)); + assertPreconditionViolationExceptionForString("Resource name", () -> ReflectionSupport.tryToGetResource("")); } /** * @since 1.11 */ @Test - void tryToLoadResourceDelegates() { - assertEquals(ReflectionUtils.tryToLoadResource("default-package.resource").toOptional(), - ReflectionSupport.tryToLoadResource("default-package.resource").toOptional()); + void tryToGetResource() { + assertEquals(ReflectionUtils.tryToGetResource("default-package.resource").toOptional(), + ReflectionSupport.tryToGetResource("default-package.resource").toOptional()); } @Test diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java index dac5a53bf9d7..ce1a7ea56cce 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java @@ -714,33 +714,33 @@ private void privateMethod() { class ResourceLoadingTests { @Test - void tryToLoadResourcePreconditions() { - assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.tryToLoadResource("")); - assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.tryToLoadResource(" ")); + void tryToGetResourcePreconditions() { + assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.tryToGetResource("")); + assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.tryToGetResource(" ")); - assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.tryToLoadResource(null)); + assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.tryToGetResource(null)); assertThrows(PreconditionViolationException.class, - () -> ReflectionUtils.tryToLoadResource("org/junit/platform/commons/example.resource", null)); + () -> ReflectionUtils.tryToGetResource("org/junit/platform/commons/example.resource", null)); } @Test - void tryToLoadResource() { - var tryToLoadResource = ReflectionUtils.tryToLoadResource("org/junit/platform/commons/example.resource"); - var resource = assertDoesNotThrow(tryToLoadResource::get); + void tryToGetResource() { + var tryToGetResource = ReflectionUtils.tryToGetResource("org/junit/platform/commons/example.resource"); + var resource = assertDoesNotThrow(tryToGetResource::get); assertThat(resource.getName()).isEqualTo("org/junit/platform/commons/example.resource"); } @Test - void tryToLoadResourceWithPrefixedSlash() { - var tryToLoadResource = ReflectionUtils.tryToLoadResource("/org/junit/platform/commons/example.resource"); - var resource = assertDoesNotThrow(tryToLoadResource::get); + void tryToGetResourceWithPrefixedSlash() { + var tryToGetResource = ReflectionUtils.tryToGetResource("/org/junit/platform/commons/example.resource"); + var resource = assertDoesNotThrow(tryToGetResource::get); assertThat(resource.getName()).isEqualTo("org/junit/platform/commons/example.resource"); } @Test - void tryToLoadResourceWhenResourceNotFound() { - var tryToLoadResource = ReflectionUtils.tryToLoadResource("org/junit/platform/commons/no-such.resource"); - assertThrows(NullPointerException.class, tryToLoadResource::get); + void tryToGetResourceWhenResourceNotFound() { + var tryToGetResource = ReflectionUtils.tryToGetResource("org/junit/platform/commons/no-such.resource"); + assertThrows(NullPointerException.class, tryToGetResource::get); } } From 3ffeb59cd26cf4115a74736afb9defc104c44a44 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Fri, 12 Jul 2024 13:53:56 +0200 Subject: [PATCH 53/78] Polish docs for tryToGetResource --- .../junit/platform/commons/support/ReflectionSupport.java | 5 +++-- .../org/junit/platform/commons/util/ReflectionUtils.java | 7 +++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java index 6565a51a7915..7233f7effd24 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java @@ -115,7 +115,7 @@ public static Try> tryToLoadClass(String name, ClassLoader classLoader) } /** - * Tries to load the {@link Resource} for the supplied classpath resource name. + * Tries to get the {@link Resource} for the supplied classpath resource name. * *

The name of a classpath resource must follow the semantics * for resource paths as defined in {@link ClassLoader#getResource(String)}. @@ -135,7 +135,8 @@ public static Try tryToGetResource(String classpathResourceName) { } /** - * Tries to load the {@link Resource} for the supplied classpath resource name. + * Tries to load the {@link Resource} for the supplied classpath resource name, + * using the supplied {@link ClassLoader}. * *

The name of a classpath resource must follow the semantics * for resource paths as defined in {@link ClassLoader#getResource(String)}. diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java index a6e25dc74d19..3c94d91cb1a2 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java @@ -892,7 +892,10 @@ public static Try> tryToLoadClass(String name, ClassLoader classLoader) } /** - * Tries to load the {@link Resource} for the supplied classpath resource name. + * Try to get a {@link Resource} by its name, using the {@link ClassLoaderUtils#getDefaultClassLoader()}. + * + *

See {@link org.junit.platform.commons.support.ReflectionSupport#tryToGetResource(String)} + * for details. * * @param classpathResourceName the name of the resource to load; never {@code null} or blank * @since 1.11 @@ -904,7 +907,7 @@ public static Try tryToGetResource(String classpathResourceName) { } /** - * Tries to load the {@link Resource} for the supplied classpath resource name. + * Try to get a {@link Resource} by its name, using the supplied {@link ClassLoader}. * *

See {@link org.junit.platform.commons.support.ReflectionSupport#tryToGetResource(String, ClassLoader)} * for details. From ba7cd1e11d74d573b7d8953242cfb92eb7739b4f Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Fri, 12 Jul 2024 14:15:07 +0200 Subject: [PATCH 54/78] Rename ResourceFilter to ResourceUtils and add docs --- .../commons/support/ReflectionSupport.java | 7 +-- ...ResourceFilter.java => ResourceUtils.java} | 45 ++++++++++--------- .../ResourceContainerSelectorResolver.java | 9 ++-- 3 files changed, 34 insertions(+), 27 deletions(-) rename junit-platform-commons/src/main/java/org/junit/platform/commons/util/{ResourceFilter.java => ResourceUtils.java} (66%) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java index 7233f7effd24..bd8b720f7d2b 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java @@ -29,6 +29,7 @@ import org.junit.platform.commons.util.ExceptionUtils; import org.junit.platform.commons.util.Preconditions; import org.junit.platform.commons.util.ReflectionUtils; +import org.junit.platform.commons.util.ResourceUtils; /** * {@code ReflectionSupport} provides static utility methods for common @@ -281,7 +282,7 @@ public static List> findAllClassesInPackage(String basePackageName, Pre * *

The resulting list may include identically named resources from different * classpath roots. These can be filtered out using - * {@link org.junit.platform.commons.util.ResourceFilter#getClasspathResource(Function)}. + * {@link ResourceUtils#getClasspathResource(Function)}. * * @param basePackageName the name of the base package in which to start * scanning; must not be {@code null} and must be valid in terms of Java @@ -309,7 +310,7 @@ public static List findAllResourcesInPackage(String basePackageName, P * *

The resulting stream may include identically named resources from different * classpath roots. These can be filtered out using - * {@link org.junit.platform.commons.util.ResourceFilter#getClasspathResource(Function)}. + * {@link ResourceUtils#getClasspathResource(Function)}. * * @param basePackageName the name of the base package in which to start * scanning; must not be {@code null} and must be valid in terms of Java @@ -338,7 +339,7 @@ public static Stream> streamAllClassesInPackage(String basePackageName, * *

The resulting stream may include identically named resources from different * classpath roots. These can be filtered out using - * {@link org.junit.platform.commons.util.ResourceFilter#getClasspathResource(Function)}. + * {@link ResourceUtils#getClasspathResource(Function)}. * * @param basePackageName the name of the base package in which to start * scanning; must not be {@code null} and must be valid in terms of Java diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceUtils.java similarity index 66% rename from junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java rename to junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceUtils.java index e8ed83b014a3..0654f7178ac2 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceFilter.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceUtils.java @@ -21,40 +21,46 @@ import org.junit.platform.commons.support.Resource; /** - * Resource-related predicates for use with {@link ReflectionSupport}. + * Resource-related utilities to be used in conjunction with {@link ReflectionSupport}. * * @since 1.11 */ @API(status = EXPERIMENTAL, since = "1.11") -public class ResourceFilter { +public class ResourceUtils { public static final String DEFAULT_PACKAGE_NAME = ""; private static final char CLASSPATH_RESOURCE_PATH_SEPARATOR = '/'; private static final char PACKAGE_SEPARATOR_CHAR = '.'; /** - * TODO: + * Maps a resource to its "canonical" version. + * + *

Resources discovered by {@link ReflectionSupport} + * may include identically named resources from different class + * path roots. + * + *

The canonical version of a resource has the uri that + * would be produced by calling {@link ClassLoader#getResource(String)}. + * + * @return a function that for a given resource, returns the "canonical" resource. */ public static Function getClasspathResource() { return getClasspathResource(ReflectionSupport::tryToGetResource); } /** - * TODO: Improve or reconsider. + * Maps a resource to its "canonical" version. * - * Include only resources that can be loaded by a class loader. - *

- * Resources discovered by {@link ReflectionSupport} + *

Resources discovered by {@link ReflectionSupport} * may include identically named resources from different class - * path roots. To get + * path roots. * - * @param loadResource function to load the resource, e.g. {@link ReflectionSupport#tryToGetResource(String)}. - * @return a function that for a given resource, returns the resource as it would bye loaded by {@link ClassLoader#getResource(String)} + *

The canonical version of a resource has the uri that + * would be produced by calling {@link ClassLoader#getResource(String)}. * - * @see ReflectionUtils#tryToGetResource(String) - * @see ReflectionUtils#tryToGetResource(String, ClassLoader) + * @param loadResource function to load the resource, e.g. {@link ReflectionSupport#tryToGetResource(String)}. + * @return a function that for a given resource, returns the "canonical" resource. */ - public static Function getClasspathResource(Function> loadResource) { return candidate -> loadResource.apply(candidate.getName()) // .toOptional() // @@ -68,15 +74,14 @@ public static Function getClasspathResource(FunctionThe {@code /} separated path of a resource is rewritten to a + * {@code .} separated package names. The package filter is applied to that + * package name. */ public static Predicate packageName(Predicate packageFilter) { - - // TODO: Filter out invalid package names? + // TODO: Filter out invalid package names? META-INF and such? return resource -> packageFilter.test(packageName(resource.getName())); } @@ -90,7 +95,7 @@ private static String packageName(String classpathResourceName) { return resourcePackagePath.replace(CLASSPATH_RESOURCE_PATH_SEPARATOR, PACKAGE_SEPARATOR_CHAR); } - private ResourceFilter() { + private ResourceUtils() { } diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java index 5e25c09aba6e..2288949bddbf 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java @@ -14,8 +14,8 @@ import static org.junit.platform.commons.support.ReflectionSupport.findAllResourcesInClasspathRoot; import static org.junit.platform.commons.support.ReflectionSupport.findAllResourcesInPackage; import static org.junit.platform.commons.util.ReflectionUtils.findAllResourcesInModule; -import static org.junit.platform.commons.util.ResourceFilter.getClasspathResource; -import static org.junit.platform.commons.util.ResourceFilter.packageName; +import static org.junit.platform.commons.util.ResourceUtils.getClasspathResource; +import static org.junit.platform.commons.util.ResourceUtils.packageName; import static org.junit.platform.engine.support.discovery.SelectorResolver.Resolution.selectors; import static org.junit.platform.engine.support.discovery.SelectorResolver.Resolution.unresolved; @@ -25,7 +25,7 @@ import java.util.function.Predicate; import org.junit.platform.commons.support.Resource; -import org.junit.platform.commons.util.ResourceFilter; +import org.junit.platform.commons.util.ResourceUtils; import org.junit.platform.engine.discovery.ClasspathResourceSelector; import org.junit.platform.engine.discovery.ClasspathRootSelector; import org.junit.platform.engine.discovery.DiscoverySelectors; @@ -36,7 +36,7 @@ * @since 1.11 */ class ResourceContainerSelectorResolver implements SelectorResolver { - private static final Function classpathResource = ResourceFilter.getClasspathResource(); + private static final Function classpathResource = ResourceUtils.getClasspathResource(); private final Predicate packageFilter; private final Predicate resourceFilter; @@ -63,6 +63,7 @@ public Resolution resolve(PackageSelector selector, Context context) { private Resolution resourceSelectors(List resources) { Set classpathResources = resources.stream() // .map(classpathResource) // + .distinct() // Ensure the resourceFilter only sees unique resources .filter(resourceFilter) // .map(DiscoverySelectors::selectClasspathResource) // .collect(toSet()); From 6817ec9917ec06c3007d2908f849fe55c4adfcea Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Fri, 12 Jul 2024 14:24:33 +0200 Subject: [PATCH 55/78] Docs and naming --- .../commons/support/ReflectionSupport.java | 6 ++--- .../platform/commons/util/ResourceUtils.java | 26 ++++++++++--------- .../ResourceContainerSelectorResolver.java | 7 +++-- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java index bd8b720f7d2b..973b94df708e 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java @@ -282,7 +282,7 @@ public static List> findAllClassesInPackage(String basePackageName, Pre * *

The resulting list may include identically named resources from different * classpath roots. These can be filtered out using - * {@link ResourceUtils#getClasspathResource(Function)}. + * {@link ResourceUtils#getClassLoaderResource(Function)}. * * @param basePackageName the name of the base package in which to start * scanning; must not be {@code null} and must be valid in terms of Java @@ -310,7 +310,7 @@ public static List findAllResourcesInPackage(String basePackageName, P * *

The resulting stream may include identically named resources from different * classpath roots. These can be filtered out using - * {@link ResourceUtils#getClasspathResource(Function)}. + * {@link ResourceUtils#getClassLoaderResource(Function)}. * * @param basePackageName the name of the base package in which to start * scanning; must not be {@code null} and must be valid in terms of Java @@ -339,7 +339,7 @@ public static Stream> streamAllClassesInPackage(String basePackageName, * *

The resulting stream may include identically named resources from different * classpath roots. These can be filtered out using - * {@link ResourceUtils#getClasspathResource(Function)}. + * {@link ResourceUtils#getClassLoaderResource(Function)}. * * @param basePackageName the name of the base package in which to start * scanning; must not be {@code null} and must be valid in terms of Java diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceUtils.java index 0654f7178ac2..34c6d8ede621 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceUtils.java @@ -33,35 +33,37 @@ public class ResourceUtils { private static final char PACKAGE_SEPARATOR_CHAR = '.'; /** - * Maps a resource to its "canonical" version. + * Maps a resource to its class loader version. + * + *

The class loader version of a resource has the uri that + * would be produced by calling {@link ClassLoader#getResource(String)}. * *

Resources discovered by {@link ReflectionSupport} * may include identically named resources from different class - * path roots. - * - *

The canonical version of a resource has the uri that - * would be produced by calling {@link ClassLoader#getResource(String)}. + * path roots. After mapping these to their class loader version + * these can be deduplicated. * * @return a function that for a given resource, returns the "canonical" resource. */ - public static Function getClasspathResource() { - return getClasspathResource(ReflectionSupport::tryToGetResource); + public static Function getClassLoaderResource() { + return getClassLoaderResource(ReflectionSupport::tryToGetResource); } /** * Maps a resource to its "canonical" version. * + *

The class loader version of a resource has the uri that + * would be produced by calling {@link ClassLoader#getResource(String)}. + * *

Resources discovered by {@link ReflectionSupport} * may include identically named resources from different class - * path roots. - * - *

The canonical version of a resource has the uri that - * would be produced by calling {@link ClassLoader#getResource(String)}. + * path roots. After mapping these to their class loader version + * these can be deduplicated. * * @param loadResource function to load the resource, e.g. {@link ReflectionSupport#tryToGetResource(String)}. * @return a function that for a given resource, returns the "canonical" resource. */ - public static Function getClasspathResource(Function> loadResource) { + public static Function getClassLoaderResource(Function> loadResource) { return candidate -> loadResource.apply(candidate.getName()) // .toOptional() // .map(loaded -> { diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java index 2288949bddbf..02b6561e37f4 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java @@ -14,7 +14,7 @@ import static org.junit.platform.commons.support.ReflectionSupport.findAllResourcesInClasspathRoot; import static org.junit.platform.commons.support.ReflectionSupport.findAllResourcesInPackage; import static org.junit.platform.commons.util.ReflectionUtils.findAllResourcesInModule; -import static org.junit.platform.commons.util.ResourceUtils.getClasspathResource; +import static org.junit.platform.commons.util.ResourceUtils.getClassLoaderResource; import static org.junit.platform.commons.util.ResourceUtils.packageName; import static org.junit.platform.engine.support.discovery.SelectorResolver.Resolution.selectors; import static org.junit.platform.engine.support.discovery.SelectorResolver.Resolution.unresolved; @@ -25,7 +25,6 @@ import java.util.function.Predicate; import org.junit.platform.commons.support.Resource; -import org.junit.platform.commons.util.ResourceUtils; import org.junit.platform.engine.discovery.ClasspathResourceSelector; import org.junit.platform.engine.discovery.ClasspathRootSelector; import org.junit.platform.engine.discovery.DiscoverySelectors; @@ -36,7 +35,7 @@ * @since 1.11 */ class ResourceContainerSelectorResolver implements SelectorResolver { - private static final Function classpathResource = ResourceUtils.getClasspathResource(); + private final Function classLoaderResource = getClassLoaderResource(); private final Predicate packageFilter; private final Predicate resourceFilter; @@ -62,7 +61,7 @@ public Resolution resolve(PackageSelector selector, Context context) { private Resolution resourceSelectors(List resources) { Set classpathResources = resources.stream() // - .map(classpathResource) // + .map(classLoaderResource) // .distinct() // Ensure the resourceFilter only sees unique resources .filter(resourceFilter) // .map(DiscoverySelectors::selectClasspathResource) // From 27c367113cfb96b7663c737120f8e9aad3b9fdad Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Fri, 12 Jul 2024 14:40:03 +0200 Subject: [PATCH 56/78] Add note about resources on the module path --- .../platform/engine/discovery/ClasspathResourceSelector.java | 4 ++++ .../junit/platform/engine/discovery/DiscoverySelectors.java | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java index 596b69dd00d8..641cdcdadb2b 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java @@ -39,6 +39,10 @@ * {@linkplain Thread#getContextClassLoader() context class loader} of the * {@linkplain Thread thread} that uses it. * + *

Note: Since Java 9, all resources are on the module path. Either in + * named or unnamed modules. These resources are also considered to be + * classpath resources. + * * @since 1.0 * @see DiscoverySelectors#selectClasspathResource(String) * @see ClasspathRootSelector diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java index f20af2f5dde3..cc408743cc8a 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java @@ -335,6 +335,10 @@ public static ClasspathResourceSelector selectClasspathResource(String classpath * {@linkplain Thread#getContextClassLoader() context class loader} of the * {@linkplain Thread thread} that uses the resulting selector. * + *

Note: Since Java 9, all resources are on the module path. Either in + * named or unnamed modules. These resources are also considered to be + * classpath resources. + * * @param classpathResource the classpath resource; never {@code null} * @since 1.11 * @see #selectClasspathResource(String, FilePosition) From c72537d711c66679c9a70d1cbd28f107d356251d Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Fri, 12 Jul 2024 15:45:42 +0200 Subject: [PATCH 57/78] Log and ignore failures to get resource --- .../platform/commons/util/ResourceUtils.java | 29 ++++++++++++------- .../ResourceContainerSelectorResolver.java | 5 +++- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceUtils.java index 34c6d8ede621..317c6a55cf67 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceUtils.java @@ -10,13 +10,17 @@ package org.junit.platform.commons.util; +import static java.lang.String.format; import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import java.util.Optional; import java.util.function.Function; import java.util.function.Predicate; import org.apiguardian.api.API; import org.junit.platform.commons.function.Try; +import org.junit.platform.commons.logging.Logger; +import org.junit.platform.commons.logging.LoggerFactory; import org.junit.platform.commons.support.ReflectionSupport; import org.junit.platform.commons.support.Resource; @@ -27,6 +31,7 @@ */ @API(status = EXPERIMENTAL, since = "1.11") public class ResourceUtils { + private static final Logger logger = LoggerFactory.getLogger(ResourceUtils.class); public static final String DEFAULT_PACKAGE_NAME = ""; private static final char CLASSPATH_RESOURCE_PATH_SEPARATOR = '/'; @@ -45,7 +50,7 @@ public class ResourceUtils { * * @return a function that for a given resource, returns the "canonical" resource. */ - public static Function getClassLoaderResource() { + public static Function> getClassLoaderResource() { return getClassLoaderResource(ReflectionSupport::tryToGetResource); } @@ -60,19 +65,21 @@ public static Function getClassLoaderResource() { * path roots. After mapping these to their class loader version * these can be deduplicated. * - * @param loadResource function to load the resource, e.g. {@link ReflectionSupport#tryToGetResource(String)}. + * @param getResource function to get the resource, e.g. {@link ReflectionSupport#tryToGetResource(String)}. * @return a function that for a given resource, returns the "canonical" resource. */ - public static Function getClassLoaderResource(Function> loadResource) { - return candidate -> loadResource.apply(candidate.getName()) // - .toOptional() // - .map(loaded -> { - if (!loaded.getUri().equals(candidate.getUri())) { - return new ClasspathResource(candidate.getName(), loaded.getUri()); + public static Function> getClassLoaderResource( + Function> getResource) { + return candidate -> getResource.apply(candidate.getName()) // + .andThenTry(loaded -> { + if (loaded.getUri().equals(candidate.getUri())) { + return candidate; } - return candidate; - - }).orElse(candidate); + return new ClasspathResource(candidate.getName(), loaded.getUri()); + }) // + .ifFailure( + throwable -> logger.debug(throwable, () -> format("Failed to load [%s].", candidate.getName()))) // + .toOptional(); } /** diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java index 02b6561e37f4..9a7b09744522 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java @@ -20,6 +20,7 @@ import static org.junit.platform.engine.support.discovery.SelectorResolver.Resolution.unresolved; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.function.Function; import java.util.function.Predicate; @@ -35,7 +36,7 @@ * @since 1.11 */ class ResourceContainerSelectorResolver implements SelectorResolver { - private final Function classLoaderResource = getClassLoaderResource(); + private final Function> classLoaderResource = getClassLoaderResource(); private final Predicate packageFilter; private final Predicate resourceFilter; @@ -62,6 +63,8 @@ public Resolution resolve(PackageSelector selector, Context context) { private Resolution resourceSelectors(List resources) { Set classpathResources = resources.stream() // .map(classLoaderResource) // + .filter(Optional::isPresent) // + .map(Optional::get) // .distinct() // Ensure the resourceFilter only sees unique resources .filter(resourceFilter) // .map(DiscoverySelectors::selectClasspathResource) // From b826b3283a4e37cccdf5f59722e39307264ed85b Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Fri, 12 Jul 2024 22:54:18 +0200 Subject: [PATCH 58/78] Clean up unused import --- .../org/junit/platform/commons/util/ReflectionUtilsTests.java | 1 - 1 file changed, 1 deletion(-) diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java index 1def4526fbe4..394c7f73aaa9 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java @@ -16,7 +16,6 @@ import static java.util.stream.Collectors.toList; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; From cb75366ee9fa1c13790fcfaf2b944e6fbfb86c65 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Tue, 27 Aug 2024 19:40:14 +0200 Subject: [PATCH 59/78] Update since version numbers to 1.12 --- .../junit/platform/commons/support/ReflectionSupport.java | 4 ++-- .../org/junit/platform/commons/util/ReflectionUtils.java | 8 ++++---- .../org/junit/platform/commons/util/ResourceUtils.java | 4 ++-- .../engine/discovery/ClasspathResourceSelector.java | 4 ++-- .../platform/engine/discovery/DiscoverySelectors.java | 4 ++-- .../support/discovery/EngineDiscoveryRequestResolver.java | 8 ++++---- .../discovery/ResourceContainerSelectorResolver.java | 2 +- .../platform/commons/support/ReflectionSupportTests.java | 4 ++-- 8 files changed, 19 insertions(+), 19 deletions(-) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java index 6ec75c82ca37..6a28e517dd29 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java @@ -130,7 +130,7 @@ public static Try> tryToLoadClass(String name, ClassLoader classLoader) * never {@code null} * @since 1.11 */ - @API(status = EXPERIMENTAL, since = "1.11") + @API(status = EXPERIMENTAL, since = "1.12") public static Try tryToGetResource(String classpathResourceName) { return ReflectionUtils.tryToGetResource(classpathResourceName); } @@ -152,7 +152,7 @@ public static Try tryToGetResource(String classpathResourceName) { * never {@code null} * @since 1.11 */ - @API(status = EXPERIMENTAL, since = "1.11") + @API(status = EXPERIMENTAL, since = "1.12") public static Try tryToGetResource(String classpathResourceName, ClassLoader classLoader) { return ReflectionUtils.tryToGetResource(classpathResourceName, classLoader); } diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java index 3c94d91cb1a2..19d54776959b 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java @@ -898,10 +898,10 @@ public static Try> tryToLoadClass(String name, ClassLoader classLoader) * for details. * * @param classpathResourceName the name of the resource to load; never {@code null} or blank - * @since 1.11 + * @since 1.12 * @see org.junit.platform.commons.support.ReflectionSupport#tryToGetResource(String, ClassLoader) */ - @API(status = INTERNAL, since = "1.11") + @API(status = INTERNAL, since = "1.12") public static Try tryToGetResource(String classpathResourceName) { return tryToGetResource(classpathResourceName, ClassLoaderUtils.getDefaultClassLoader()); } @@ -914,9 +914,9 @@ public static Try tryToGetResource(String classpathResourceName) { * * @param classpathResourceName the name of the resource to load; never {@code null} or blank * @param classLoader the {@code ClassLoader} to use; never {@code null} - * @since 1.11 + * @since 1.12 */ - @API(status = INTERNAL, since = "1.11") + @API(status = INTERNAL, since = "1.12") public static Try tryToGetResource(String classpathResourceName, ClassLoader classLoader) { Preconditions.notBlank(classpathResourceName, "Resource name must not be null or blank"); Preconditions.notNull(classLoader, "ClassLoader must not be null"); diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceUtils.java index 317c6a55cf67..47dd46a0177c 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceUtils.java @@ -27,9 +27,9 @@ /** * Resource-related utilities to be used in conjunction with {@link ReflectionSupport}. * - * @since 1.11 + * @since 1.12 */ -@API(status = EXPERIMENTAL, since = "1.11") +@API(status = EXPERIMENTAL, since = "1.12") public class ResourceUtils { private static final Logger logger = LoggerFactory.getLogger(ResourceUtils.class); diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java index 641cdcdadb2b..9f939441d8e7 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java @@ -88,9 +88,9 @@ public String getClasspathResourceName() { * throws a {@link PreconditionViolationException} if the resource cannot * be loaded. * - * @since 1.11 + * @since 1.12 */ - @API(status = EXPERIMENTAL, since = "1.11") + @API(status = EXPERIMENTAL, since = "1.12") public Resource getClasspathResource() { if (this.classpathResource == null) { // @formatter:off diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java index cc408743cc8a..d3ba876333d9 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java @@ -340,13 +340,13 @@ public static ClasspathResourceSelector selectClasspathResource(String classpath * classpath resources. * * @param classpathResource the classpath resource; never {@code null} - * @since 1.11 + * @since 1.12 * @see #selectClasspathResource(String, FilePosition) * @see #selectClasspathResource(String) * @see ClasspathResourceSelector * @see ReflectionSupport#tryToGetResource(String) */ - @API(status = EXPERIMENTAL, since = "1.11") + @API(status = EXPERIMENTAL, since = "1.12") public static ClasspathResourceSelector selectClasspathResource(Resource classpathResource) { Preconditions.notNull(classpathResource, "classpath resource must not be null or blank"); return new ClasspathResourceSelector(classpathResource); diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/EngineDiscoveryRequestResolver.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/EngineDiscoveryRequestResolver.java index 9525cd76992f..277bd119cb24 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/EngineDiscoveryRequestResolver.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/EngineDiscoveryRequestResolver.java @@ -173,9 +173,9 @@ public Builder addClassContainerSelectorResolver(Predicate> classFil * @param resourceFilter predicate the resolved classes must satisfy; never * {@code null} * @return this builder for method chaining - * @since 1.11 + * @since 1.12 */ - @API(status = EXPERIMENTAL, since = "1.11") + @API(status = EXPERIMENTAL, since = "1.12") public Builder addResourceContainerSelectorResolver(Predicate resourceFilter) { Preconditions.notNull(resourceFilter, "resourceFilter must not be null"); return addSelectorResolver( @@ -276,9 +276,9 @@ public interface InitializationContext { * * @return the predicate for filtering the resolved resource names; never * {@code null} - * @since 1.11 + * @since 1.12 */ - @API(status = EXPERIMENTAL, since = "1.11") + @API(status = EXPERIMENTAL, since = "1.12") Predicate getPackageFilter(); } diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java index 9a7b09744522..20757605badd 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java @@ -33,7 +33,7 @@ import org.junit.platform.engine.discovery.PackageSelector; /** - * @since 1.11 + * @since 1.12 */ class ResourceContainerSelectorResolver implements SelectorResolver { private final Function> classLoaderResource = getClassLoaderResource(); diff --git a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java index a9a564f6a35c..56c6af2f0758 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java @@ -120,7 +120,7 @@ List findAllClassesInClasspathRootDelegates() throws Throwable { } /** - * @since 1.11 + * @since 1.12 */ @Test void tryToGetResourcePreconditions() { @@ -129,7 +129,7 @@ void tryToGetResourcePreconditions() { } /** - * @since 1.11 + * @since 1.12 */ @Test void tryToGetResource() { From 9d9e1fb6833f90529493d5792410238b2b119965 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Tue, 27 Aug 2024 20:27:08 +0200 Subject: [PATCH 60/78] Support multiple resources per selector --- .../commons/support/ReflectionSupport.java | 43 +++---- .../commons/util/ReflectionUtils.java | 30 +++-- .../platform/commons/util/ResourceUtils.java | 111 ------------------ .../discovery/ClasspathResourceSelector.java | 37 ++++-- .../ResourceContainerSelectorResolver.java | 10 +- .../support/discovery/ResourceUtils.java | 49 ++++++++ .../support/ReflectionSupportTests.java | 2 +- .../commons/util/ReflectionUtilsTests.java | 22 ++-- .../discovery/DiscoverySelectorsTests.java | 6 +- 9 files changed, 129 insertions(+), 181 deletions(-) delete mode 100644 junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceUtils.java create mode 100644 junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceUtils.java diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java index 6a28e517dd29..266ba0c717b0 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java @@ -19,7 +19,6 @@ import java.net.URI; import java.util.List; import java.util.Optional; -import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Stream; @@ -29,7 +28,6 @@ import org.junit.platform.commons.util.ExceptionUtils; import org.junit.platform.commons.util.Preconditions; import org.junit.platform.commons.util.ReflectionUtils; -import org.junit.platform.commons.util.ResourceUtils; /** * {@code ReflectionSupport} provides static utility methods for common @@ -116,7 +114,7 @@ public static Try> tryToLoadClass(String name, ClassLoader classLoader) } /** - * Tries to get the {@link Resource} for the supplied classpath resource name. + * Tries to get the {@linkplain Resource resources} for the supplied classpath resource name. * *

The name of a classpath resource must follow the semantics * for resource paths as defined in {@link ClassLoader#getResource(String)}. @@ -125,18 +123,18 @@ public static Try> tryToLoadClass(String name, ClassLoader classLoader) * ({@code /}), the slash will be removed. * * @param classpathResourceName the name of the resource to load; never {@code null} or blank - * @return a successful {@code Try} containing the loaded class or a failed - * {@code Try} containing the exception if no such resource could be loaded; + * @return a successful {@code Try} containing the loaded resources or a failed + * {@code Try} containing the exception if no such resources could be loaded; * never {@code null} * @since 1.11 */ @API(status = EXPERIMENTAL, since = "1.12") - public static Try tryToGetResource(String classpathResourceName) { - return ReflectionUtils.tryToGetResource(classpathResourceName); + public static Try> tryToGetResource(String classpathResourceName) { + return ReflectionUtils.tryToGetResources(classpathResourceName); } /** - * Tries to load the {@link Resource} for the supplied classpath resource name, + * Tries to load the {@linkplain Resource resources} for the supplied classpath resource name, * using the supplied {@link ClassLoader}. * *

The name of a classpath resource must follow the semantics @@ -147,14 +145,14 @@ public static Try tryToGetResource(String classpathResourceName) { * * @param classpathResourceName the name of the resource to load; never {@code null} or blank * @param classLoader the {@code ClassLoader} to use; never {@code null} - * @return a successful {@code Try} containing the loaded class or a failed - * {@code Try} containing the exception if no such resource could be loaded; + * @return a successful {@code Try} containing the loaded resources or a failed + * {@code Try} containing the exception if no such resources could be loaded; * never {@code null} * @since 1.11 */ @API(status = EXPERIMENTAL, since = "1.12") - public static Try tryToGetResource(String classpathResourceName, ClassLoader classLoader) { - return ReflectionUtils.tryToGetResource(classpathResourceName, classLoader); + public static Try> tryToGetResource(String classpathResourceName, ClassLoader classLoader) { + return ReflectionUtils.tryToGetResources(classpathResourceName, classLoader); } /** @@ -278,11 +276,8 @@ public static List> findAllClassesInPackage(String basePackageName, Pre * that match the specified {@code resourceFilter} predicate. * *

The classpath scanning algorithm searches recursively in subpackages - * beginning within the supplied base package. - * - *

The resulting list may include identically named resources from different - * classpath roots. These can be filtered out using - * {@link ResourceUtils#getClassLoaderResource(Function)}. + * beginning within the supplied base package. The resulting list may include identically + * named resources from different classpath roots. * * @param basePackageName the name of the base package in which to start * scanning; must not be {@code null} and must be valid in terms of Java @@ -306,11 +301,8 @@ public static List findAllResourcesInPackage(String basePackageName, P * predicates. * *

The classpath scanning algorithm searches recursively in subpackages - * beginning within the supplied base package. - * - *

The resulting stream may include identically named resources from different - * classpath roots. These can be filtered out using - * {@link ResourceUtils#getClassLoaderResource(Function)}. + * beginning within the supplied base package. The resulting stream may include + * identically named resources from different classpath roots. * * @param basePackageName the name of the base package in which to start * scanning; must not be {@code null} and must be valid in terms of Java @@ -335,11 +327,8 @@ public static Stream> streamAllClassesInPackage(String basePackageName, * that match the specified {@code resourceFilter} predicate. * *

The classpath scanning algorithm searches recursively in subpackages - * beginning within the supplied base package. - * - *

The resulting stream may include identically named resources from different - * classpath roots. These can be filtered out using - * {@link ResourceUtils#getClassLoaderResource(Function)}. + * beginning within the supplied base package. The resulting stream may include + * identically named resources from different classpath roots. * * @param basePackageName the name of the base package in which to start * scanning; must not be {@code null} and must be valid in terms of Java diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java index 19d54776959b..55af9526df06 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java @@ -35,6 +35,7 @@ import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; @@ -892,32 +893,32 @@ public static Try> tryToLoadClass(String name, ClassLoader classLoader) } /** - * Try to get a {@link Resource} by its name, using the {@link ClassLoaderUtils#getDefaultClassLoader()}. + * Try to get {@linkplain Resource resources} by their name, using the {@link ClassLoaderUtils#getDefaultClassLoader()}. * *

See {@link org.junit.platform.commons.support.ReflectionSupport#tryToGetResource(String)} * for details. * - * @param classpathResourceName the name of the resource to load; never {@code null} or blank + * @param classpathResourceName the name of the resources to load; never {@code null} or blank * @since 1.12 * @see org.junit.platform.commons.support.ReflectionSupport#tryToGetResource(String, ClassLoader) */ @API(status = INTERNAL, since = "1.12") - public static Try tryToGetResource(String classpathResourceName) { - return tryToGetResource(classpathResourceName, ClassLoaderUtils.getDefaultClassLoader()); + public static Try> tryToGetResources(String classpathResourceName) { + return tryToGetResources(classpathResourceName, ClassLoaderUtils.getDefaultClassLoader()); } /** - * Try to get a {@link Resource} by its name, using the supplied {@link ClassLoader}. + * Try to get {@linkplain Resource resources} by their name, using the supplied {@link ClassLoader}. * *

See {@link org.junit.platform.commons.support.ReflectionSupport#tryToGetResource(String, ClassLoader)} * for details. * - * @param classpathResourceName the name of the resource to load; never {@code null} or blank + * @param classpathResourceName the name of the resources to load; never {@code null} or blank * @param classLoader the {@code ClassLoader} to use; never {@code null} * @since 1.12 */ @API(status = INTERNAL, since = "1.12") - public static Try tryToGetResource(String classpathResourceName, ClassLoader classLoader) { + public static Try> tryToGetResources(String classpathResourceName, ClassLoader classLoader) { Preconditions.notBlank(classpathResourceName, "Resource name must not be null or blank"); Preconditions.notNull(classLoader, "ClassLoader must not be null"); boolean startsWithSlash = classpathResourceName.startsWith("/"); @@ -925,11 +926,18 @@ public static Try tryToGetResource(String classpathResourceName, Class : classpathResourceName); return Try.call(() -> { - URL resource = classLoader.getResource(canonicalClasspathResourceName); - if (resource == null) { - throw new NullPointerException("classLoader.getResource returned null"); + List resources = Collections.list(classLoader.getResources(canonicalClasspathResourceName)); + if (resources.isEmpty()) { + throw new NullPointerException("classLoader.getResource returned no resources"); } - return new ClasspathResource(canonicalClasspathResourceName, resource.toURI()); + return resources.stream().map(url -> { + try { + return new ClasspathResource(canonicalClasspathResourceName, url.toURI()); + } + catch (URISyntaxException e) { + throw ExceptionUtils.throwAsUncheckedException(e); + } + }).collect(toList()); }); } diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceUtils.java deleted file mode 100644 index 47dd46a0177c..000000000000 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ResourceUtils.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2015-2024 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.platform.commons.util; - -import static java.lang.String.format; -import static org.apiguardian.api.API.Status.EXPERIMENTAL; - -import java.util.Optional; -import java.util.function.Function; -import java.util.function.Predicate; - -import org.apiguardian.api.API; -import org.junit.platform.commons.function.Try; -import org.junit.platform.commons.logging.Logger; -import org.junit.platform.commons.logging.LoggerFactory; -import org.junit.platform.commons.support.ReflectionSupport; -import org.junit.platform.commons.support.Resource; - -/** - * Resource-related utilities to be used in conjunction with {@link ReflectionSupport}. - * - * @since 1.12 - */ -@API(status = EXPERIMENTAL, since = "1.12") -public class ResourceUtils { - private static final Logger logger = LoggerFactory.getLogger(ResourceUtils.class); - - public static final String DEFAULT_PACKAGE_NAME = ""; - private static final char CLASSPATH_RESOURCE_PATH_SEPARATOR = '/'; - private static final char PACKAGE_SEPARATOR_CHAR = '.'; - - /** - * Maps a resource to its class loader version. - * - *

The class loader version of a resource has the uri that - * would be produced by calling {@link ClassLoader#getResource(String)}. - * - *

Resources discovered by {@link ReflectionSupport} - * may include identically named resources from different class - * path roots. After mapping these to their class loader version - * these can be deduplicated. - * - * @return a function that for a given resource, returns the "canonical" resource. - */ - public static Function> getClassLoaderResource() { - return getClassLoaderResource(ReflectionSupport::tryToGetResource); - } - - /** - * Maps a resource to its "canonical" version. - * - *

The class loader version of a resource has the uri that - * would be produced by calling {@link ClassLoader#getResource(String)}. - * - *

Resources discovered by {@link ReflectionSupport} - * may include identically named resources from different class - * path roots. After mapping these to their class loader version - * these can be deduplicated. - * - * @param getResource function to get the resource, e.g. {@link ReflectionSupport#tryToGetResource(String)}. - * @return a function that for a given resource, returns the "canonical" resource. - */ - public static Function> getClassLoaderResource( - Function> getResource) { - return candidate -> getResource.apply(candidate.getName()) // - .andThenTry(loaded -> { - if (loaded.getUri().equals(candidate.getUri())) { - return candidate; - } - return new ClasspathResource(candidate.getName(), loaded.getUri()); - }) // - .ifFailure( - throwable -> logger.debug(throwable, () -> format("Failed to load [%s].", candidate.getName()))) // - .toOptional(); - } - - /** - * Match resources against a package filter. - * - *

The {@code /} separated path of a resource is rewritten to a - * {@code .} separated package names. The package filter is applied to that - * package name. - */ - public static Predicate packageName(Predicate packageFilter) { - // TODO: Filter out invalid package names? META-INF and such? - return resource -> packageFilter.test(packageName(resource.getName())); - } - - private static String packageName(String classpathResourceName) { - int lastIndexOf = classpathResourceName.lastIndexOf(CLASSPATH_RESOURCE_PATH_SEPARATOR); - if (lastIndexOf < 0) { - return DEFAULT_PACKAGE_NAME; - } - // classpath resource names do not start with / - String resourcePackagePath = classpathResourceName.substring(0, lastIndexOf); - return resourcePackagePath.replace(CLASSPATH_RESOURCE_PATH_SEPARATOR, PACKAGE_SEPARATOR_CHAR); - } - - private ResourceUtils() { - - } - -} diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java index 9f939441d8e7..accd0218d750 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java @@ -10,10 +10,13 @@ package org.junit.platform.engine.discovery; +import static java.util.stream.Collectors.toList; import static org.apiguardian.api.API.Status.EXPERIMENTAL; import static org.apiguardian.api.API.Status.INTERNAL; import static org.apiguardian.api.API.Status.STABLE; +import java.util.Arrays; +import java.util.List; import java.util.Objects; import java.util.Optional; @@ -21,6 +24,7 @@ import org.junit.platform.commons.PreconditionViolationException; import org.junit.platform.commons.function.Try; import org.junit.platform.commons.support.Resource; +import org.junit.platform.commons.util.Preconditions; import org.junit.platform.commons.util.ReflectionUtils; import org.junit.platform.commons.util.StringUtils; import org.junit.platform.commons.util.ToStringBuilder; @@ -53,7 +57,7 @@ public class ClasspathResourceSelector implements DiscoverySelector { private final String classpathResourceName; private final FilePosition position; - private Resource classpathResource; + private List classpathResources; ClasspathResourceSelector(String classpathResourceName, FilePosition position) { boolean startsWithSlash = classpathResourceName.startsWith("/"); @@ -61,9 +65,17 @@ public class ClasspathResourceSelector implements DiscoverySelector { this.position = position; } - ClasspathResourceSelector(Resource classpathResource) { - this(classpathResource.getName(), null); - this.classpathResource = classpathResource; + ClasspathResourceSelector(Resource... classpathResources) { + this(getClasspathResourceName(classpathResources), null); + this.classpathResources = Arrays.asList(classpathResources); + } + + private static String getClasspathResourceName(Resource[] classpathResources) { + Preconditions.notEmpty(classpathResources, "classpathResources array must not be null or empty"); + Preconditions.containsNoNullElements(classpathResources, "individual classpathResources must not be null"); + List names = Arrays.stream(classpathResources).map(Resource::getName).distinct().collect(toList()); + Preconditions.condition(names.size() == 1, "all classpathResources must have the same name"); + return names.get(0); } /** @@ -81,7 +93,7 @@ public String getClasspathResourceName() { } /** - * Get the selected {@link Resource}. + * Get the selected {@link Resource Resources}. * *

If the {@link Resource} was not provided, but only the name, this * method attempts to lazily load the {@link Resource} based on its name and @@ -91,15 +103,15 @@ public String getClasspathResourceName() { * @since 1.12 */ @API(status = EXPERIMENTAL, since = "1.12") - public Resource getClasspathResource() { - if (this.classpathResource == null) { + public List getClasspathResources() { + if (this.classpathResources == null) { // @formatter:off - Try tryToGetResource = ReflectionUtils.tryToGetResource(this.classpathResourceName); - this.classpathResource = tryToGetResource.getOrThrow(cause -> + Try> tryToGetResource = ReflectionUtils.tryToGetResources(this.classpathResourceName); + this.classpathResources = tryToGetResource.getOrThrow(cause -> new PreconditionViolationException("Could not load resource with name: " + this.classpathResourceName, cause)); // @formatter:on } - return this.classpathResource; + return this.classpathResources; } /** @@ -123,7 +135,8 @@ public boolean equals(Object o) { } ClasspathResourceSelector that = (ClasspathResourceSelector) o; return Objects.equals(this.classpathResourceName, that.classpathResourceName) - && Objects.equals(this.position, that.position); + && Objects.equals(this.position, that.position) + && Objects.equals(this.classpathResources, that.classpathResources); } /** @@ -132,7 +145,7 @@ public boolean equals(Object o) { @API(status = STABLE, since = "1.3") @Override public int hashCode() { - return Objects.hash(this.classpathResourceName, this.position); + return Objects.hash(this.classpathResourceName, this.position, this.classpathResources); } @Override diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java index 20757605badd..72c2bc032ab6 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java @@ -14,15 +14,12 @@ import static org.junit.platform.commons.support.ReflectionSupport.findAllResourcesInClasspathRoot; import static org.junit.platform.commons.support.ReflectionSupport.findAllResourcesInPackage; import static org.junit.platform.commons.util.ReflectionUtils.findAllResourcesInModule; -import static org.junit.platform.commons.util.ResourceUtils.getClassLoaderResource; -import static org.junit.platform.commons.util.ResourceUtils.packageName; +import static org.junit.platform.engine.support.discovery.ResourceUtils.packageName; import static org.junit.platform.engine.support.discovery.SelectorResolver.Resolution.selectors; import static org.junit.platform.engine.support.discovery.SelectorResolver.Resolution.unresolved; import java.util.List; -import java.util.Optional; import java.util.Set; -import java.util.function.Function; import java.util.function.Predicate; import org.junit.platform.commons.support.Resource; @@ -36,7 +33,6 @@ * @since 1.12 */ class ResourceContainerSelectorResolver implements SelectorResolver { - private final Function> classLoaderResource = getClassLoaderResource(); private final Predicate packageFilter; private final Predicate resourceFilter; @@ -62,10 +58,6 @@ public Resolution resolve(PackageSelector selector, Context context) { private Resolution resourceSelectors(List resources) { Set classpathResources = resources.stream() // - .map(classLoaderResource) // - .filter(Optional::isPresent) // - .map(Optional::get) // - .distinct() // Ensure the resourceFilter only sees unique resources .filter(resourceFilter) // .map(DiscoverySelectors::selectClasspathResource) // .collect(toSet()); diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceUtils.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceUtils.java new file mode 100644 index 000000000000..6649000184ad --- /dev/null +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceUtils.java @@ -0,0 +1,49 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.engine.support.discovery; + +import java.util.function.Predicate; + +import org.junit.platform.commons.support.ReflectionSupport; +import org.junit.platform.commons.support.Resource; + +/** + * Resource-related utilities to be used in conjunction with {@link ReflectionSupport}. + * + * @since 1.12 + */ +class ResourceUtils { + public static final String DEFAULT_PACKAGE_NAME = ""; + private static final char CLASSPATH_RESOURCE_PATH_SEPARATOR = '/'; + private static final char PACKAGE_SEPARATOR_CHAR = '.'; + + /** + * Match resources against a package filter. + * + *

The {@code /} separated path of a resource is rewritten to a + * {@code .} separated package names. The package filter is applied to that + * package name. + */ + static Predicate packageName(Predicate packageFilter) { + // TODO: Filter out invalid package names? META-INF and such? + return resource -> packageFilter.test(packageName(resource.getName())); + } + + private static String packageName(String classpathResourceName) { + int lastIndexOf = classpathResourceName.lastIndexOf(CLASSPATH_RESOURCE_PATH_SEPARATOR); + if (lastIndexOf < 0) { + return DEFAULT_PACKAGE_NAME; + } + // classpath resource names do not start with / + String resourcePackagePath = classpathResourceName.substring(0, lastIndexOf); + return resourcePackagePath.replace(CLASSPATH_RESOURCE_PATH_SEPARATOR, PACKAGE_SEPARATOR_CHAR); + } +} diff --git a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java index 56c6af2f0758..feed97cc1162 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java @@ -133,7 +133,7 @@ void tryToGetResourcePreconditions() { */ @Test void tryToGetResource() { - assertEquals(ReflectionUtils.tryToGetResource("default-package.resource").toOptional(), + assertEquals(ReflectionUtils.tryToGetResources("default-package.resource").toOptional(), ReflectionSupport.tryToGetResource("default-package.resource").toOptional()); } diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java index ce1a7ea56cce..579fb07cbbb9 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java @@ -16,6 +16,7 @@ import static java.util.stream.Collectors.toList; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -715,31 +716,34 @@ class ResourceLoadingTests { @Test void tryToGetResourcePreconditions() { - assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.tryToGetResource("")); - assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.tryToGetResource(" ")); + assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.tryToGetResources("")); + assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.tryToGetResources(" ")); - assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.tryToGetResource(null)); + assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.tryToGetResources(null)); assertThrows(PreconditionViolationException.class, - () -> ReflectionUtils.tryToGetResource("org/junit/platform/commons/example.resource", null)); + () -> ReflectionUtils.tryToGetResources("org/junit/platform/commons/example.resource", null)); } @Test void tryToGetResource() { - var tryToGetResource = ReflectionUtils.tryToGetResource("org/junit/platform/commons/example.resource"); + var tryToGetResource = ReflectionUtils.tryToGetResources("org/junit/platform/commons/example.resource"); var resource = assertDoesNotThrow(tryToGetResource::get); - assertThat(resource.getName()).isEqualTo("org/junit/platform/commons/example.resource"); + assertAll(() -> assertThat(resource).hasSize(1), + () -> assertThat(resource.get(0).getName()).isEqualTo("org/junit/platform/commons/example.resource")); + } @Test void tryToGetResourceWithPrefixedSlash() { - var tryToGetResource = ReflectionUtils.tryToGetResource("/org/junit/platform/commons/example.resource"); + var tryToGetResource = ReflectionUtils.tryToGetResources("/org/junit/platform/commons/example.resource"); var resource = assertDoesNotThrow(tryToGetResource::get); - assertThat(resource.getName()).isEqualTo("org/junit/platform/commons/example.resource"); + assertAll(() -> assertThat(resource).hasSize(1), + () -> assertThat(resource.get(0).getName()).isEqualTo("org/junit/platform/commons/example.resource")); } @Test void tryToGetResourceWhenResourceNotFound() { - var tryToGetResource = ReflectionUtils.tryToGetResource("org/junit/platform/commons/no-such.resource"); + var tryToGetResource = ReflectionUtils.tryToGetResources("org/junit/platform/commons/no-such.resource"); assertThrows(NullPointerException.class, tryToGetResource::get); } } diff --git a/platform-tests/src/test/java/org/junit/platform/engine/discovery/DiscoverySelectorsTests.java b/platform-tests/src/test/java/org/junit/platform/engine/discovery/DiscoverySelectorsTests.java index 5dc5977fbe76..fbfac7c91a10 100644 --- a/platform-tests/src/test/java/org/junit/platform/engine/discovery/DiscoverySelectorsTests.java +++ b/platform-tests/src/test/java/org/junit/platform/engine/discovery/DiscoverySelectorsTests.java @@ -14,6 +14,7 @@ import static java.util.Objects.requireNonNull; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.InstanceOfAssertFactories.type; +import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.engine.discovery.JupiterUniqueIdBuilder.uniqueIdForMethod; @@ -303,7 +304,10 @@ void selectClasspathResources() { assertEquals("A/B/C/spec.json", selector.getClasspathResourceName()); selector = selectClasspathResource("org/junit/platform/commons/example.resource"); - assertEquals("org/junit/platform/commons/example.resource", selector.getClasspathResource().getName()); + var classpathResources = selector.getClasspathResources(); + assertAll(() -> assertThat(classpathResources).hasSize(1), () -> assertThat(classpathResources) // + .extracting(Resource::getName) // + .containsExactly("org/junit/platform/commons/example.resource")); } @Test From 9e536be4cf341eea0469506081cdb33b1d93a4c5 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Tue, 27 Aug 2024 20:44:19 +0200 Subject: [PATCH 61/78] Fix pluralization --- .../commons/support/ReflectionSupport.java | 4 +-- .../commons/util/ReflectionUtils.java | 6 ++-- .../discovery/ClasspathResourceSelector.java | 28 ++++++++++++------- .../engine/discovery/DiscoverySelectors.java | 14 +++++----- .../ResourceContainerSelectorResolver.java | 10 +++++-- .../support/ReflectionSupportTests.java | 10 +++---- .../discovery/DiscoverySelectorsTests.java | 6 +++- 7 files changed, 47 insertions(+), 31 deletions(-) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java index 266ba0c717b0..f62b1269af98 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java @@ -129,7 +129,7 @@ public static Try> tryToLoadClass(String name, ClassLoader classLoader) * @since 1.11 */ @API(status = EXPERIMENTAL, since = "1.12") - public static Try> tryToGetResource(String classpathResourceName) { + public static Try> tryToGetResources(String classpathResourceName) { return ReflectionUtils.tryToGetResources(classpathResourceName); } @@ -151,7 +151,7 @@ public static Try> tryToGetResource(String classpathResourceName) * @since 1.11 */ @API(status = EXPERIMENTAL, since = "1.12") - public static Try> tryToGetResource(String classpathResourceName, ClassLoader classLoader) { + public static Try> tryToGetResources(String classpathResourceName, ClassLoader classLoader) { return ReflectionUtils.tryToGetResources(classpathResourceName, classLoader); } diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java index 55af9526df06..609d114f0396 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java @@ -895,12 +895,12 @@ public static Try> tryToLoadClass(String name, ClassLoader classLoader) /** * Try to get {@linkplain Resource resources} by their name, using the {@link ClassLoaderUtils#getDefaultClassLoader()}. * - *

See {@link org.junit.platform.commons.support.ReflectionSupport#tryToGetResource(String)} + *

See {@link org.junit.platform.commons.support.ReflectionSupport#tryToGetResources(String)} * for details. * * @param classpathResourceName the name of the resources to load; never {@code null} or blank * @since 1.12 - * @see org.junit.platform.commons.support.ReflectionSupport#tryToGetResource(String, ClassLoader) + * @see org.junit.platform.commons.support.ReflectionSupport#tryToGetResources(String, ClassLoader) */ @API(status = INTERNAL, since = "1.12") public static Try> tryToGetResources(String classpathResourceName) { @@ -910,7 +910,7 @@ public static Try> tryToGetResources(String classpathResourceName /** * Try to get {@linkplain Resource resources} by their name, using the supplied {@link ClassLoader}. * - *

See {@link org.junit.platform.commons.support.ReflectionSupport#tryToGetResource(String, ClassLoader)} + *

See {@link org.junit.platform.commons.support.ReflectionSupport#tryToGetResources(String, ClassLoader)} * for details. * * @param classpathResourceName the name of the resources to load; never {@code null} or blank diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java index accd0218d750..9faf7ab885cc 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java @@ -10,12 +10,13 @@ package org.junit.platform.engine.discovery; +import static java.util.Collections.unmodifiableList; +import static java.util.Comparator.comparing; import static java.util.stream.Collectors.toList; import static org.apiguardian.api.API.Status.EXPERIMENTAL; import static org.apiguardian.api.API.Status.INTERNAL; import static org.apiguardian.api.API.Status.STABLE; -import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -65,15 +66,21 @@ public class ClasspathResourceSelector implements DiscoverySelector { this.position = position; } - ClasspathResourceSelector(Resource... classpathResources) { + ClasspathResourceSelector(List classpathResources) { this(getClasspathResourceName(classpathResources), null); - this.classpathResources = Arrays.asList(classpathResources); + this.classpathResources = unmodifiableList(copyAndSort(classpathResources)); } - private static String getClasspathResourceName(Resource[] classpathResources) { + private static List copyAndSort(List classpathResources) { + return classpathResources.stream() // + .sorted(comparing(Resource::getUri)) // + .collect(toList()); + } + + private static String getClasspathResourceName(List classpathResources) { Preconditions.notEmpty(classpathResources, "classpathResources array must not be null or empty"); Preconditions.containsNoNullElements(classpathResources, "individual classpathResources must not be null"); - List names = Arrays.stream(classpathResources).map(Resource::getName).distinct().collect(toList()); + List names = classpathResources.stream().map(Resource::getName).distinct().collect(toList()); Preconditions.condition(names.size() == 1, "all classpathResources must have the same name"); return names.get(0); } @@ -93,11 +100,11 @@ public String getClasspathResourceName() { } /** - * Get the selected {@link Resource Resources}. + * Get the selected {@link Resource resources}. * - *

If the {@link Resource} was not provided, but only the name, this - * method attempts to lazily load the {@link Resource} based on its name and - * throws a {@link PreconditionViolationException} if the resource cannot + *

If the {@link Resource resources} were not provided, but only their name, + * this method attempts to lazily load the {@link Resource} based on its name + * and throws a {@link PreconditionViolationException} if the resource cannot * be loaded. * * @since 1.12 @@ -107,9 +114,10 @@ public List getClasspathResources() { if (this.classpathResources == null) { // @formatter:off Try> tryToGetResource = ReflectionUtils.tryToGetResources(this.classpathResourceName); - this.classpathResources = tryToGetResource.getOrThrow(cause -> + List classpathResources = tryToGetResource.getOrThrow(cause -> new PreconditionViolationException("Could not load resource with name: " + this.classpathResourceName, cause)); // @formatter:on + this.classpathResources = unmodifiableList(classpathResources); } return this.classpathResources; } diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java index d3ba876333d9..b16b08295ffa 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java @@ -313,7 +313,7 @@ public static ClasspathResourceSelector selectClasspathResource(String classpath * {@code null} or blank * @param position the position inside the classpath resource; may be {@code null} * @see #selectClasspathResource(String) - * @see #selectClasspathResource(Resource) + * @see #selectClasspathResource(List) * @see ClasspathResourceSelector * @see ClassLoader#getResource(String) * @see ClassLoader#getResourceAsStream(String) @@ -327,7 +327,7 @@ public static ClasspathResourceSelector selectClasspathResource(String classpath /** * Create a {@code ClasspathResourceSelector} for the supplied classpath - * resource. + * resources. * *

Since {@linkplain org.junit.platform.engine.TestEngine engines} are not * expected to modify the classpath, the supplied resource must be on the @@ -339,17 +339,17 @@ public static ClasspathResourceSelector selectClasspathResource(String classpath * named or unnamed modules. These resources are also considered to be * classpath resources. * - * @param classpathResource the classpath resource; never {@code null} + * @param classpathResources the classpath resource; never {@code null} * @since 1.12 * @see #selectClasspathResource(String, FilePosition) * @see #selectClasspathResource(String) * @see ClasspathResourceSelector - * @see ReflectionSupport#tryToGetResource(String) + * @see ReflectionSupport#tryToGetResources(String) */ @API(status = EXPERIMENTAL, since = "1.12") - public static ClasspathResourceSelector selectClasspathResource(Resource classpathResource) { - Preconditions.notNull(classpathResource, "classpath resource must not be null or blank"); - return new ClasspathResourceSelector(classpathResource); + public static ClasspathResourceSelector selectClasspathResource(List classpathResources) { + Preconditions.notNull(classpathResources, "classpath resource must not be null or blank"); + return new ClasspathResourceSelector(classpathResources); } /** diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java index 72c2bc032ab6..94542fe31846 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java @@ -10,6 +10,7 @@ package org.junit.platform.engine.support.discovery; +import static java.util.stream.Collectors.groupingBy; import static java.util.stream.Collectors.toSet; import static org.junit.platform.commons.support.ReflectionSupport.findAllResourcesInClasspathRoot; import static org.junit.platform.commons.support.ReflectionSupport.findAllResourcesInPackage; @@ -57,15 +58,18 @@ public Resolution resolve(PackageSelector selector, Context context) { } private Resolution resourceSelectors(List resources) { - Set classpathResources = resources.stream() // + Set selectors = resources.stream() // .filter(resourceFilter) // + .collect(groupingBy(Resource::getName)) // + .values() // + .stream() // .map(DiscoverySelectors::selectClasspathResource) // .collect(toSet()); - if (classpathResources.isEmpty()) { + if (selectors.isEmpty()) { return unresolved(); } - return selectors(classpathResources); + return selectors(selectors); } } diff --git a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java index feed97cc1162..d87559609550 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java @@ -123,18 +123,18 @@ List findAllClassesInClasspathRootDelegates() throws Throwable { * @since 1.12 */ @Test - void tryToGetResourcePreconditions() { - assertPreconditionViolationExceptionForString("Resource name", () -> ReflectionSupport.tryToGetResource(null)); - assertPreconditionViolationExceptionForString("Resource name", () -> ReflectionSupport.tryToGetResource("")); + void tryToGetResourcesPreconditions() { + assertPreconditionViolationExceptionForString("Resource name", () -> ReflectionSupport.tryToGetResources(null)); + assertPreconditionViolationExceptionForString("Resource name", () -> ReflectionSupport.tryToGetResources("")); } /** * @since 1.12 */ @Test - void tryToGetResource() { + void tryToGetResources() { assertEquals(ReflectionUtils.tryToGetResources("default-package.resource").toOptional(), - ReflectionSupport.tryToGetResource("default-package.resource").toOptional()); + ReflectionSupport.tryToGetResources("default-package.resource").toOptional()); } @Test diff --git a/platform-tests/src/test/java/org/junit/platform/engine/discovery/DiscoverySelectorsTests.java b/platform-tests/src/test/java/org/junit/platform/engine/discovery/DiscoverySelectorsTests.java index fbfac7c91a10..92daaa8cea35 100644 --- a/platform-tests/src/test/java/org/junit/platform/engine/discovery/DiscoverySelectorsTests.java +++ b/platform-tests/src/test/java/org/junit/platform/engine/discovery/DiscoverySelectorsTests.java @@ -39,6 +39,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.Set; @@ -293,7 +294,10 @@ void selectClasspathResources() { assertViolatesPrecondition(() -> selectClasspathResource("")); assertViolatesPrecondition(() -> selectClasspathResource(" ")); assertViolatesPrecondition(() -> selectClasspathResource("\t")); - assertViolatesPrecondition(() -> selectClasspathResource((Resource) null)); + assertViolatesPrecondition(() -> selectClasspathResource((List) null)); + assertViolatesPrecondition(() -> selectClasspathResource(Collections.emptyList())); + assertViolatesPrecondition(() -> selectClasspathResource(Collections.singletonList(null))); + assertViolatesPrecondition(() -> selectClasspathResource(Collections.singletonList(null))); // with unnecessary "/" prefix var selector = selectClasspathResource("/foo/bar/spec.xml"); From d507767144e3c3eb555f13e2026fe85d4220073a Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Tue, 27 Aug 2024 21:03:51 +0200 Subject: [PATCH 62/78] Ensure resource selectors can be equaled --- .../commons/support/ReflectionSupport.java | 26 +++++++++--------- .../commons/util/ClasspathResource.java | 8 ++++++ .../commons/util/ReflectionUtils.java | 12 +++++---- .../discovery/ClasspathResourceSelector.java | 27 ++++++++----------- .../engine/discovery/DiscoverySelectors.java | 2 +- .../ResourceContainerSelectorResolver.java | 2 ++ 6 files changed, 43 insertions(+), 34 deletions(-) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java index f62b1269af98..9bddfdf3ac7a 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java @@ -19,6 +19,7 @@ import java.net.URI; import java.util.List; import java.util.Optional; +import java.util.Set; import java.util.function.Predicate; import java.util.stream.Stream; @@ -114,7 +115,8 @@ public static Try> tryToLoadClass(String name, ClassLoader classLoader) } /** - * Tries to get the {@linkplain Resource resources} for the supplied classpath resource name. + * Tries to get the {@linkplain Resource resources} for the supplied classpath + * resource name. * *

The name of a classpath resource must follow the semantics * for resource paths as defined in {@link ClassLoader#getResource(String)}. @@ -129,13 +131,13 @@ public static Try> tryToLoadClass(String name, ClassLoader classLoader) * @since 1.11 */ @API(status = EXPERIMENTAL, since = "1.12") - public static Try> tryToGetResources(String classpathResourceName) { + public static Try> tryToGetResources(String classpathResourceName) { return ReflectionUtils.tryToGetResources(classpathResourceName); } /** - * Tries to load the {@linkplain Resource resources} for the supplied classpath resource name, - * using the supplied {@link ClassLoader}. + * Tries to load the {@linkplain Resource resources} for the supplied classpath + * resource name, using the supplied {@link ClassLoader}. * *

The name of a classpath resource must follow the semantics * for resource paths as defined in {@link ClassLoader#getResource(String)}. @@ -143,7 +145,7 @@ public static Try> tryToGetResources(String classpathResourceName *

If the supplied classpath resource name is prefixed with a slash * ({@code /}), the slash will be removed. * - * @param classpathResourceName the name of the resource to load; never {@code null} or blank + * @param classpathResourceName the name of the resource to load; never {@code null}or blank * @param classLoader the {@code ClassLoader} to use; never {@code null} * @return a successful {@code Try} containing the loaded resources or a failed * {@code Try} containing the exception if no such resources could be loaded; @@ -151,7 +153,7 @@ public static Try> tryToGetResources(String classpathResourceName * @since 1.11 */ @API(status = EXPERIMENTAL, since = "1.12") - public static Try> tryToGetResources(String classpathResourceName, ClassLoader classLoader) { + public static Try> tryToGetResources(String classpathResourceName, ClassLoader classLoader) { return ReflectionUtils.tryToGetResources(classpathResourceName, classLoader); } @@ -276,8 +278,8 @@ public static List> findAllClassesInPackage(String basePackageName, Pre * that match the specified {@code resourceFilter} predicate. * *

The classpath scanning algorithm searches recursively in subpackages - * beginning within the supplied base package. The resulting list may include identically - * named resources from different classpath roots. + * beginning within the supplied base package. The resulting list may include + * identically named resources from different classpath roots. * * @param basePackageName the name of the base package in which to start * scanning; must not be {@code null} and must be valid in terms of Java @@ -301,8 +303,8 @@ public static List findAllResourcesInPackage(String basePackageName, P * predicates. * *

The classpath scanning algorithm searches recursively in subpackages - * beginning within the supplied base package. The resulting stream may include - * identically named resources from different classpath roots. + * beginning within the supplied base package. The resulting stream may + * include identically named resources from different classpath roots. * * @param basePackageName the name of the base package in which to start * scanning; must not be {@code null} and must be valid in terms of Java @@ -327,8 +329,8 @@ public static Stream> streamAllClassesInPackage(String basePackageName, * that match the specified {@code resourceFilter} predicate. * *

The classpath scanning algorithm searches recursively in subpackages - * beginning within the supplied base package. The resulting stream may include - * identically named resources from different classpath roots. + * beginning within the supplied base package. The resulting stream may + * include identically named resources from different classpath roots. * * @param basePackageName the name of the base package in which to start * scanning; must not be {@code null} and must be valid in terms of Java diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathResource.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathResource.java index 720c5166c297..459beceb652c 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathResource.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ClasspathResource.java @@ -52,4 +52,12 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(name, uri); } + + @Override + public String toString() { + return new ToStringBuilder(this) // + .append("name", this.name) // + .append("uri", this.uri) // + .toString(); + } } diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java index 609d114f0396..fcf8978a1e2e 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java @@ -893,7 +893,8 @@ public static Try> tryToLoadClass(String name, ClassLoader classLoader) } /** - * Try to get {@linkplain Resource resources} by their name, using the {@link ClassLoaderUtils#getDefaultClassLoader()}. + * Try to get {@linkplain Resource resources} by their name, using the + * {@link ClassLoaderUtils#getDefaultClassLoader()}. * *

See {@link org.junit.platform.commons.support.ReflectionSupport#tryToGetResources(String)} * for details. @@ -903,12 +904,13 @@ public static Try> tryToLoadClass(String name, ClassLoader classLoader) * @see org.junit.platform.commons.support.ReflectionSupport#tryToGetResources(String, ClassLoader) */ @API(status = INTERNAL, since = "1.12") - public static Try> tryToGetResources(String classpathResourceName) { + public static Try> tryToGetResources(String classpathResourceName) { return tryToGetResources(classpathResourceName, ClassLoaderUtils.getDefaultClassLoader()); } /** - * Try to get {@linkplain Resource resources} by their name, using the supplied {@link ClassLoader}. + * Try to get {@linkplain Resource resources} by their name, using the + * supplied {@link ClassLoader}. * *

See {@link org.junit.platform.commons.support.ReflectionSupport#tryToGetResources(String, ClassLoader)} * for details. @@ -918,7 +920,7 @@ public static Try> tryToGetResources(String classpathResourceName * @since 1.12 */ @API(status = INTERNAL, since = "1.12") - public static Try> tryToGetResources(String classpathResourceName, ClassLoader classLoader) { + public static Try> tryToGetResources(String classpathResourceName, ClassLoader classLoader) { Preconditions.notBlank(classpathResourceName, "Resource name must not be null or blank"); Preconditions.notNull(classLoader, "ClassLoader must not be null"); boolean startsWithSlash = classpathResourceName.startsWith("/"); @@ -937,7 +939,7 @@ public static Try> tryToGetResources(String classpathResourceName catch (URISyntaxException e) { throw ExceptionUtils.throwAsUncheckedException(e); } - }).collect(toList()); + }).collect(toCollection(LinkedHashSet::new)); }); } diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java index 9faf7ab885cc..a976f00707b5 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java @@ -10,16 +10,17 @@ package org.junit.platform.engine.discovery; -import static java.util.Collections.unmodifiableList; -import static java.util.Comparator.comparing; +import static java.util.Collections.unmodifiableSet; import static java.util.stream.Collectors.toList; import static org.apiguardian.api.API.Status.EXPERIMENTAL; import static org.apiguardian.api.API.Status.INTERNAL; import static org.apiguardian.api.API.Status.STABLE; +import java.util.LinkedHashSet; import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.Set; import org.apiguardian.api.API; import org.junit.platform.commons.PreconditionViolationException; @@ -58,7 +59,7 @@ public class ClasspathResourceSelector implements DiscoverySelector { private final String classpathResourceName; private final FilePosition position; - private List classpathResources; + private Set classpathResources; ClasspathResourceSelector(String classpathResourceName, FilePosition position) { boolean startsWithSlash = classpathResourceName.startsWith("/"); @@ -66,18 +67,12 @@ public class ClasspathResourceSelector implements DiscoverySelector { this.position = position; } - ClasspathResourceSelector(List classpathResources) { + ClasspathResourceSelector(Set classpathResources) { this(getClasspathResourceName(classpathResources), null); - this.classpathResources = unmodifiableList(copyAndSort(classpathResources)); + this.classpathResources = unmodifiableSet(new LinkedHashSet<>(classpathResources)); } - private static List copyAndSort(List classpathResources) { - return classpathResources.stream() // - .sorted(comparing(Resource::getUri)) // - .collect(toList()); - } - - private static String getClasspathResourceName(List classpathResources) { + private static String getClasspathResourceName(Set classpathResources) { Preconditions.notEmpty(classpathResources, "classpathResources array must not be null or empty"); Preconditions.containsNoNullElements(classpathResources, "individual classpathResources must not be null"); List names = classpathResources.stream().map(Resource::getName).distinct().collect(toList()); @@ -110,14 +105,14 @@ public String getClasspathResourceName() { * @since 1.12 */ @API(status = EXPERIMENTAL, since = "1.12") - public List getClasspathResources() { + public Set getClasspathResources() { if (this.classpathResources == null) { // @formatter:off - Try> tryToGetResource = ReflectionUtils.tryToGetResources(this.classpathResourceName); - List classpathResources = tryToGetResource.getOrThrow(cause -> + Try> tryToGetResource = ReflectionUtils.tryToGetResources(this.classpathResourceName); + Set classpathResources = tryToGetResource.getOrThrow(cause -> new PreconditionViolationException("Could not load resource with name: " + this.classpathResourceName, cause)); // @formatter:on - this.classpathResources = unmodifiableList(classpathResources); + this.classpathResources = unmodifiableSet(classpathResources); } return this.classpathResources; } diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java index b16b08295ffa..6b88a1c2de59 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java @@ -347,7 +347,7 @@ public static ClasspathResourceSelector selectClasspathResource(String classpath * @see ReflectionSupport#tryToGetResources(String) */ @API(status = EXPERIMENTAL, since = "1.12") - public static ClasspathResourceSelector selectClasspathResource(List classpathResources) { + public static ClasspathResourceSelector selectClasspathResource(Set classpathResources) { Preconditions.notNull(classpathResources, "classpath resource must not be null or blank"); return new ClasspathResourceSelector(classpathResources); } diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java index 94542fe31846..eda919ba4552 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java @@ -19,6 +19,7 @@ import static org.junit.platform.engine.support.discovery.SelectorResolver.Resolution.selectors; import static org.junit.platform.engine.support.discovery.SelectorResolver.Resolution.unresolved; +import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import java.util.function.Predicate; @@ -63,6 +64,7 @@ private Resolution resourceSelectors(List resources) { .collect(groupingBy(Resource::getName)) // .values() // .stream() // + .map(LinkedHashSet::new) // .map(DiscoverySelectors::selectClasspathResource) // .collect(toSet()); From 753a891e4476ee5e4ccdaacd077641d974f766d6 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Tue, 27 Aug 2024 21:05:33 +0200 Subject: [PATCH 63/78] Fix doc reference --- .../org/junit/platform/engine/discovery/DiscoverySelectors.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java index 6b88a1c2de59..f50793805090 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java @@ -283,7 +283,7 @@ public static List selectClasspathRoots(Set classpa * @param classpathResourceName the name of the classpath resource; never * {@code null} or blank * @see #selectClasspathResource(String, FilePosition) - * @see #selectClasspathResource(Resource) + * @see #selectClasspathResource(Set) * @see ClasspathResourceSelector * @see ClassLoader#getResource(String) * @see ClassLoader#getResourceAsStream(String) From d5ec2c50ba1310cb720178350da25d1576fbdc9f Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Tue, 27 Aug 2024 21:07:59 +0200 Subject: [PATCH 64/78] Fix doc reference --- .../engine/discovery/ClasspathResourceSelector.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java index a976f00707b5..cb60f74be78d 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java @@ -98,9 +98,9 @@ public String getClasspathResourceName() { * Get the selected {@link Resource resources}. * *

If the {@link Resource resources} were not provided, but only their name, - * this method attempts to lazily load the {@link Resource} based on its name - * and throws a {@link PreconditionViolationException} if the resource cannot - * be loaded. + * this method attempts to lazily load the {@link Resource resources} based on + * their name and throws a {@link PreconditionViolationException} if the + * resource cannot be loaded. * * @since 1.12 */ From 85b368b2594c9c605b579049461abbe93a8745aa Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Tue, 27 Aug 2024 21:17:22 +0200 Subject: [PATCH 65/78] Fix compile --- .../commons/util/ReflectionUtilsTests.java | 14 +++++++++----- .../engine/discovery/DiscoverySelectorsTests.java | 7 +++---- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java index 579fb07cbbb9..b4674a8c1256 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java @@ -69,6 +69,7 @@ import org.junit.platform.commons.JUnitException; import org.junit.platform.commons.PreconditionViolationException; import org.junit.platform.commons.logging.LogRecordListener; +import org.junit.platform.commons.support.Resource; import org.junit.platform.commons.test.TestClassLoader; import org.junit.platform.commons.util.ReflectionUtilsTests.NestedClassTests.ClassWithNestedClasses.Nested1; import org.junit.platform.commons.util.ReflectionUtilsTests.NestedClassTests.ClassWithNestedClasses.Nested2; @@ -728,17 +729,20 @@ void tryToGetResourcePreconditions() { void tryToGetResource() { var tryToGetResource = ReflectionUtils.tryToGetResources("org/junit/platform/commons/example.resource"); var resource = assertDoesNotThrow(tryToGetResource::get); - assertAll(() -> assertThat(resource).hasSize(1), - () -> assertThat(resource.get(0).getName()).isEqualTo("org/junit/platform/commons/example.resource")); - + assertAll( // + () -> assertThat(resource).hasSize(1), // + () -> assertThat(resource).extracting(Resource::getName) // + .containsExactly("org/junit/platform/commons/example.resource")); } @Test void tryToGetResourceWithPrefixedSlash() { var tryToGetResource = ReflectionUtils.tryToGetResources("/org/junit/platform/commons/example.resource"); var resource = assertDoesNotThrow(tryToGetResource::get); - assertAll(() -> assertThat(resource).hasSize(1), - () -> assertThat(resource.get(0).getName()).isEqualTo("org/junit/platform/commons/example.resource")); + assertAll( // + () -> assertThat(resource).hasSize(1), // + () -> assertThat(resource).extracting(Resource::getName) // + .containsExactly("org/junit/platform/commons/example.resource")); } @Test diff --git a/platform-tests/src/test/java/org/junit/platform/engine/discovery/DiscoverySelectorsTests.java b/platform-tests/src/test/java/org/junit/platform/engine/discovery/DiscoverySelectorsTests.java index 92daaa8cea35..7f010ed2ca86 100644 --- a/platform-tests/src/test/java/org/junit/platform/engine/discovery/DiscoverySelectorsTests.java +++ b/platform-tests/src/test/java/org/junit/platform/engine/discovery/DiscoverySelectorsTests.java @@ -294,10 +294,9 @@ void selectClasspathResources() { assertViolatesPrecondition(() -> selectClasspathResource("")); assertViolatesPrecondition(() -> selectClasspathResource(" ")); assertViolatesPrecondition(() -> selectClasspathResource("\t")); - assertViolatesPrecondition(() -> selectClasspathResource((List) null)); - assertViolatesPrecondition(() -> selectClasspathResource(Collections.emptyList())); - assertViolatesPrecondition(() -> selectClasspathResource(Collections.singletonList(null))); - assertViolatesPrecondition(() -> selectClasspathResource(Collections.singletonList(null))); + assertViolatesPrecondition(() -> selectClasspathResource((Set) null)); + assertViolatesPrecondition(() -> selectClasspathResource(Collections.emptySet())); + assertViolatesPrecondition(() -> selectClasspathResource(Collections.singleton(null))); // with unnecessary "/" prefix var selector = selectClasspathResource("/foo/bar/spec.xml"); From 9b32549e7fcfd214cb13ddac7d1b82a1d4fc6205 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Tue, 27 Aug 2024 21:26:11 +0200 Subject: [PATCH 66/78] Fix coverage --- .../org/junit/platform/commons/util/ReflectionUtils.java | 2 +- .../platform/commons/support/ReflectionSupportTests.java | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java index fcf8978a1e2e..c6699dd874c0 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java @@ -922,7 +922,7 @@ public static Try> tryToGetResources(String classpathResourceName) @API(status = INTERNAL, since = "1.12") public static Try> tryToGetResources(String classpathResourceName, ClassLoader classLoader) { Preconditions.notBlank(classpathResourceName, "Resource name must not be null or blank"); - Preconditions.notNull(classLoader, "ClassLoader must not be null"); + Preconditions.notNull(classLoader, "Class loader must not be null"); boolean startsWithSlash = classpathResourceName.startsWith("/"); String canonicalClasspathResourceName = (startsWithSlash ? classpathResourceName.substring(1) : classpathResourceName); diff --git a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java index d87559609550..d03d3c17c7d6 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java @@ -16,6 +16,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.platform.commons.support.PreconditionAssertions.assertPreconditionViolationException; import static org.junit.platform.commons.support.PreconditionAssertions.assertPreconditionViolationExceptionForString; +import static org.junit.platform.commons.util.ClassLoaderUtils.getDefaultClassLoader; import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -126,6 +127,8 @@ List findAllClassesInClasspathRootDelegates() throws Throwable { void tryToGetResourcesPreconditions() { assertPreconditionViolationExceptionForString("Resource name", () -> ReflectionSupport.tryToGetResources(null)); assertPreconditionViolationExceptionForString("Resource name", () -> ReflectionSupport.tryToGetResources("")); + assertPreconditionViolationExceptionForString("Class loader", () -> ReflectionSupport.tryToGetResources("default-package.resource", null)); + assertPreconditionViolationExceptionForString("Class loader", () -> ReflectionSupport.tryToGetResources("default-package.resource", null)); } /** @@ -135,6 +138,9 @@ void tryToGetResourcesPreconditions() { void tryToGetResources() { assertEquals(ReflectionUtils.tryToGetResources("default-package.resource").toOptional(), ReflectionSupport.tryToGetResources("default-package.resource").toOptional()); + assertEquals( + ReflectionUtils.tryToGetResources("default-package.resource", getDefaultClassLoader()).toOptional(), // + ReflectionSupport.tryToGetResources("default-package.resource", getDefaultClassLoader()).toOptional()); } @Test From 6762e0621bf9b6727d0574bd19da6b3c0df074e0 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Tue, 27 Aug 2024 21:31:29 +0200 Subject: [PATCH 67/78] Fix doc --- .../org/junit/platform/engine/discovery/DiscoverySelectors.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java index f50793805090..ef043cc4bdf3 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java @@ -313,7 +313,7 @@ public static ClasspathResourceSelector selectClasspathResource(String classpath * {@code null} or blank * @param position the position inside the classpath resource; may be {@code null} * @see #selectClasspathResource(String) - * @see #selectClasspathResource(List) + * @see #selectClasspathResource(Set) * @see ClasspathResourceSelector * @see ClassLoader#getResource(String) * @see ClassLoader#getResourceAsStream(String) From f4f7acf04c4e49bfb291fb3237f7299552a40e55 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Tue, 27 Aug 2024 21:32:23 +0200 Subject: [PATCH 68/78] Fix spotless --- .../platform/commons/support/ReflectionSupportTests.java | 6 ++++-- .../junit/platform/commons/util/ReflectionUtilsTests.java | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java index d03d3c17c7d6..e3d54309ae3f 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java @@ -127,8 +127,10 @@ List findAllClassesInClasspathRootDelegates() throws Throwable { void tryToGetResourcesPreconditions() { assertPreconditionViolationExceptionForString("Resource name", () -> ReflectionSupport.tryToGetResources(null)); assertPreconditionViolationExceptionForString("Resource name", () -> ReflectionSupport.tryToGetResources("")); - assertPreconditionViolationExceptionForString("Class loader", () -> ReflectionSupport.tryToGetResources("default-package.resource", null)); - assertPreconditionViolationExceptionForString("Class loader", () -> ReflectionSupport.tryToGetResources("default-package.resource", null)); + assertPreconditionViolationExceptionForString("Class loader", + () -> ReflectionSupport.tryToGetResources("default-package.resource", null)); + assertPreconditionViolationExceptionForString("Class loader", + () -> ReflectionSupport.tryToGetResources("default-package.resource", null)); } /** diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java index b4674a8c1256..2c72bfe2a50d 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java @@ -740,9 +740,9 @@ void tryToGetResourceWithPrefixedSlash() { var tryToGetResource = ReflectionUtils.tryToGetResources("/org/junit/platform/commons/example.resource"); var resource = assertDoesNotThrow(tryToGetResource::get); assertAll( // - () -> assertThat(resource).hasSize(1), // - () -> assertThat(resource).extracting(Resource::getName) // - .containsExactly("org/junit/platform/commons/example.resource")); + () -> assertThat(resource).hasSize(1), // + () -> assertThat(resource).extracting(Resource::getName) // + .containsExactly("org/junit/platform/commons/example.resource")); } @Test From 527672ac86dc174a80a38bd4efe6c970a114b93b Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Tue, 27 Aug 2024 21:44:34 +0200 Subject: [PATCH 69/78] Fix tests --- .../platform/commons/support/ReflectionSupportTests.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java index e3d54309ae3f..2067775d2ed7 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java @@ -127,9 +127,9 @@ List findAllClassesInClasspathRootDelegates() throws Throwable { void tryToGetResourcesPreconditions() { assertPreconditionViolationExceptionForString("Resource name", () -> ReflectionSupport.tryToGetResources(null)); assertPreconditionViolationExceptionForString("Resource name", () -> ReflectionSupport.tryToGetResources("")); - assertPreconditionViolationExceptionForString("Class loader", + assertPreconditionViolationException("Class loader", () -> ReflectionSupport.tryToGetResources("default-package.resource", null)); - assertPreconditionViolationExceptionForString("Class loader", + assertPreconditionViolationException("Class loader", () -> ReflectionSupport.tryToGetResources("default-package.resource", null)); } From b65e680da84615a2c66bdf8da4e21fe8eb760b56 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Tue, 27 Aug 2024 21:49:54 +0200 Subject: [PATCH 70/78] Drop TODO --- .../junit/platform/engine/support/discovery/ResourceUtils.java | 1 - 1 file changed, 1 deletion(-) diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceUtils.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceUtils.java index 6649000184ad..02bcd3656c2a 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceUtils.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceUtils.java @@ -33,7 +33,6 @@ class ResourceUtils { * package name. */ static Predicate packageName(Predicate packageFilter) { - // TODO: Filter out invalid package names? META-INF and such? return resource -> packageFilter.test(packageName(resource.getName())); } From f990a838c5b88ea8b660c038d5ec4c9af20e5186 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Tue, 27 Aug 2024 21:52:09 +0200 Subject: [PATCH 71/78] Update release notes --- .../docs/asciidoc/release-notes/release-notes-5.12.0-M1.adoc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.12.0-M1.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.12.0-M1.adoc index 89a1753a5280..28bc3000fde2 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.12.0-M1.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.12.0-M1.adoc @@ -26,8 +26,9 @@ JUnit repository on GitHub. [[release-notes-5.12.0-M1-junit-platform-new-features-and-improvements]] ==== New Features and Improvements -* ❓ - +* New `addResourceContainerSelectorResolver()` in `EngineDiscoveryRequestResolver.Builder` to +support the discovery of class path resource based tests, analogous to the +`addClassContainerSelectorResolver()`. [[release-notes-5.12.0-M1-junit-jupiter]] === JUnit Jupiter From 9a5b68b397a460710c77bdbbe2f8a4ed149591c0 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Sun, 1 Sep 2024 20:06:05 +0200 Subject: [PATCH 72/78] Polishing --- .../commons/support/ReflectionSupport.java | 6 ++++-- .../discovery/ClasspathResourceSelector.java | 13 +----------- .../engine/discovery/DiscoverySelectors.java | 13 +++++++++--- .../discovery/DiscoverySelectorsTests.java | 21 +++++++++++++++++++ 4 files changed, 36 insertions(+), 17 deletions(-) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java index 9bddfdf3ac7a..e880bd97a2c8 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/ReflectionSupport.java @@ -124,7 +124,8 @@ public static Try> tryToLoadClass(String name, ClassLoader classLoader) *

If the supplied classpath resource name is prefixed with a slash * ({@code /}), the slash will be removed. * - * @param classpathResourceName the name of the resource to load; never {@code null} or blank + * @param classpathResourceName the name of the resource to load; never + * {@code null} or blank * @return a successful {@code Try} containing the loaded resources or a failed * {@code Try} containing the exception if no such resources could be loaded; * never {@code null} @@ -145,7 +146,8 @@ public static Try> tryToGetResources(String classpathResourceName) *

If the supplied classpath resource name is prefixed with a slash * ({@code /}), the slash will be removed. * - * @param classpathResourceName the name of the resource to load; never {@code null}or blank + * @param classpathResourceName the name of the resource to load; never + * {@code null} or blank * @param classLoader the {@code ClassLoader} to use; never {@code null} * @return a successful {@code Try} containing the loaded resources or a failed * {@code Try} containing the exception if no such resources could be loaded; diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java index cb60f74be78d..89cb1ab0c14e 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java @@ -11,13 +11,11 @@ package org.junit.platform.engine.discovery; import static java.util.Collections.unmodifiableSet; -import static java.util.stream.Collectors.toList; import static org.apiguardian.api.API.Status.EXPERIMENTAL; import static org.apiguardian.api.API.Status.INTERNAL; import static org.apiguardian.api.API.Status.STABLE; import java.util.LinkedHashSet; -import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.Set; @@ -26,7 +24,6 @@ import org.junit.platform.commons.PreconditionViolationException; import org.junit.platform.commons.function.Try; import org.junit.platform.commons.support.Resource; -import org.junit.platform.commons.util.Preconditions; import org.junit.platform.commons.util.ReflectionUtils; import org.junit.platform.commons.util.StringUtils; import org.junit.platform.commons.util.ToStringBuilder; @@ -68,18 +65,10 @@ public class ClasspathResourceSelector implements DiscoverySelector { } ClasspathResourceSelector(Set classpathResources) { - this(getClasspathResourceName(classpathResources), null); + this(classpathResources.iterator().next().getName(), null); this.classpathResources = unmodifiableSet(new LinkedHashSet<>(classpathResources)); } - private static String getClasspathResourceName(Set classpathResources) { - Preconditions.notEmpty(classpathResources, "classpathResources array must not be null or empty"); - Preconditions.containsNoNullElements(classpathResources, "individual classpathResources must not be null"); - List names = classpathResources.stream().map(Resource::getName).distinct().collect(toList()); - Preconditions.condition(names.size() == 1, "all classpathResources must have the same name"); - return names.get(0); - } - /** * Get the name of the selected classpath resource. * diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java index ef043cc4bdf3..55cb13224447 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java @@ -10,6 +10,7 @@ package org.junit.platform.engine.discovery; +import static java.util.stream.Collectors.toList; import static org.apiguardian.api.API.Status.EXPERIMENTAL; import static org.apiguardian.api.API.Status.STABLE; import static org.junit.platform.commons.util.CollectionUtils.toUnmodifiableList; @@ -321,7 +322,7 @@ public static ClasspathResourceSelector selectClasspathResource(String classpath */ public static ClasspathResourceSelector selectClasspathResource(String classpathResourceName, FilePosition position) { - Preconditions.notBlank(classpathResourceName, "Classpath resource name must not be null or blank"); + Preconditions.notBlank(classpathResourceName, "classpath resource name must not be null or blank"); return new ClasspathResourceSelector(classpathResourceName, position); } @@ -339,7 +340,9 @@ public static ClasspathResourceSelector selectClasspathResource(String classpath * named or unnamed modules. These resources are also considered to be * classpath resources. * - * @param classpathResources the classpath resource; never {@code null} + * @param classpathResources a set of classpath resources; never + * {@code null} or empty. All resources must have the same name, may not + * be {@code null} or blank. * @since 1.12 * @see #selectClasspathResource(String, FilePosition) * @see #selectClasspathResource(String) @@ -348,7 +351,11 @@ public static ClasspathResourceSelector selectClasspathResource(String classpath */ @API(status = EXPERIMENTAL, since = "1.12") public static ClasspathResourceSelector selectClasspathResource(Set classpathResources) { - Preconditions.notNull(classpathResources, "classpath resource must not be null or blank"); + Preconditions.notEmpty(classpathResources, "classpath resources must not be null or empty"); + Preconditions.containsNoNullElements(classpathResources, "individual classpath resources must not be null"); + List resourceNames = classpathResources.stream().map(Resource::getName).distinct().collect(toList()); + Preconditions.condition(resourceNames.size() == 1, "all classpath resources must have the same name"); + Preconditions.notBlank(resourceNames.get(0), "classpath resource names must not be null or blank"); return new ClasspathResourceSelector(classpathResources); } diff --git a/platform-tests/src/test/java/org/junit/platform/engine/discovery/DiscoverySelectorsTests.java b/platform-tests/src/test/java/org/junit/platform/engine/discovery/DiscoverySelectorsTests.java index 7f010ed2ca86..f71b113a8d59 100644 --- a/platform-tests/src/test/java/org/junit/platform/engine/discovery/DiscoverySelectorsTests.java +++ b/platform-tests/src/test/java/org/junit/platform/engine/discovery/DiscoverySelectorsTests.java @@ -297,6 +297,10 @@ void selectClasspathResources() { assertViolatesPrecondition(() -> selectClasspathResource((Set) null)); assertViolatesPrecondition(() -> selectClasspathResource(Collections.emptySet())); assertViolatesPrecondition(() -> selectClasspathResource(Collections.singleton(null))); + assertViolatesPrecondition(() -> selectClasspathResource(Set.of(new StubResource(null)))); + assertViolatesPrecondition(() -> selectClasspathResource(Set.of(new StubResource("")))); + assertViolatesPrecondition( + () -> selectClasspathResource(Set.of(new StubResource("a"), new StubResource("b")))); // with unnecessary "/" prefix var selector = selectClasspathResource("/foo/bar/spec.xml"); @@ -371,6 +375,23 @@ void parseClasspathResourcesWithFilePosition() { .containsExactly("A/B/C/spec.json", Optional.of(filePosition)); } + private class StubResource implements Resource { + private final String name; + + private StubResource(String name) { + this.name = name; + } + + @Override + public String getName() { + return name; + } + + @Override + public URI getUri() { + return null; + } + } } @Nested From baf861c0b25ab41ce91da29271e129b6c3a5f72c Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Sun, 1 Sep 2024 20:37:46 +0200 Subject: [PATCH 73/78] Polishing --- .../platform/engine/discovery/DiscoverySelectorsTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform-tests/src/test/java/org/junit/platform/engine/discovery/DiscoverySelectorsTests.java b/platform-tests/src/test/java/org/junit/platform/engine/discovery/DiscoverySelectorsTests.java index f71b113a8d59..52ad017e8524 100644 --- a/platform-tests/src/test/java/org/junit/platform/engine/discovery/DiscoverySelectorsTests.java +++ b/platform-tests/src/test/java/org/junit/platform/engine/discovery/DiscoverySelectorsTests.java @@ -375,7 +375,7 @@ void parseClasspathResourcesWithFilePosition() { .containsExactly("A/B/C/spec.json", Optional.of(filePosition)); } - private class StubResource implements Resource { + private static class StubResource implements Resource { private final String name; private StubResource(String name) { From 2c49146bca72d2768a9b740539a73987b5524c63 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Thu, 17 Oct 2024 18:33:52 +0200 Subject: [PATCH 74/78] Pull up could not load resource(s) exception --- .../commons/util/ReflectionUtils.java | 3 --- .../discovery/ClasspathResourceSelector.java | 11 +++++---- .../commons/util/ReflectionUtilsTests.java | 3 ++- .../discovery/DiscoverySelectorsTests.java | 24 +++++++++++++++---- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java index 5d8a20417f5c..2dafd46d5344 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java @@ -933,9 +933,6 @@ public static Try> tryToGetResources(String classpathResourceName, return Try.call(() -> { List resources = Collections.list(classLoader.getResources(canonicalClasspathResourceName)); - if (resources.isEmpty()) { - throw new NullPointerException("classLoader.getResource returned no resources"); - } return resources.stream().map(url -> { try { return new ClasspathResource(canonicalClasspathResourceName, url.toURI()); diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java index 5fc57b84cc11..af37e1f8512b 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java @@ -96,11 +96,14 @@ public String getClasspathResourceName() { @API(status = EXPERIMENTAL, since = "1.12") public Set getClasspathResources() { if (this.classpathResources == null) { - // @formatter:off Try> tryToGetResource = ReflectionUtils.tryToGetResources(this.classpathResourceName); - Set classpathResources = tryToGetResource.getOrThrow(cause -> - new PreconditionViolationException("Could not load resource with name: " + this.classpathResourceName, cause)); - // @formatter:on + Set classpathResources = tryToGetResource.getOrThrow( // + cause -> new PreconditionViolationException( // + "Could not load resource(s) with name: " + this.classpathResourceName, cause)); + if (classpathResources.isEmpty()) { + throw new PreconditionViolationException( + "Could not load resource(s) with name: " + this.classpathResourceName); + } this.classpathResources = unmodifiableSet(classpathResources); } return this.classpathResources; diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java index a31d0cae9b8f..c8d6e694ec0b 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java @@ -748,7 +748,8 @@ void tryToGetResourceWithPrefixedSlash() { @Test void tryToGetResourceWhenResourceNotFound() { var tryToGetResource = ReflectionUtils.tryToGetResources("org/junit/platform/commons/no-such.resource"); - assertThrows(NullPointerException.class, tryToGetResource::get); + var resource = assertDoesNotThrow(tryToGetResource::get); + assertThat(resource).isEmpty(); } } diff --git a/platform-tests/src/test/java/org/junit/platform/engine/discovery/DiscoverySelectorsTests.java b/platform-tests/src/test/java/org/junit/platform/engine/discovery/DiscoverySelectorsTests.java index 52ad017e8524..c37ce9e8286b 100644 --- a/platform-tests/src/test/java/org/junit/platform/engine/discovery/DiscoverySelectorsTests.java +++ b/platform-tests/src/test/java/org/junit/platform/engine/discovery/DiscoverySelectorsTests.java @@ -289,7 +289,7 @@ void parseDirectorySelectorWithAbsolutePath() { } @Test - void selectClasspathResources() { + void selectClasspathResourcesPreconditions() { assertViolatesPrecondition(() -> selectClasspathResource((String) null)); assertViolatesPrecondition(() -> selectClasspathResource("")); assertViolatesPrecondition(() -> selectClasspathResource(" ")); @@ -301,7 +301,10 @@ void selectClasspathResources() { assertViolatesPrecondition(() -> selectClasspathResource(Set.of(new StubResource("")))); assertViolatesPrecondition( () -> selectClasspathResource(Set.of(new StubResource("a"), new StubResource("b")))); + } + @Test + void selectClasspathResources() { // with unnecessary "/" prefix var selector = selectClasspathResource("/foo/bar/spec.xml"); assertEquals("foo/bar/spec.xml", selector.getClasspathResourceName()); @@ -309,12 +312,23 @@ void selectClasspathResources() { // standard use case selector = selectClasspathResource("A/B/C/spec.json"); assertEquals("A/B/C/spec.json", selector.getClasspathResourceName()); + } - selector = selectClasspathResource("org/junit/platform/commons/example.resource"); + @Test + void getSelectedClasspathResources() { + var selector = selectClasspathResource("org/junit/platform/commons/example.resource"); var classpathResources = selector.getClasspathResources(); - assertAll(() -> assertThat(classpathResources).hasSize(1), () -> assertThat(classpathResources) // - .extracting(Resource::getName) // - .containsExactly("org/junit/platform/commons/example.resource")); + assertAll(() -> assertThat(classpathResources).hasSize(1), // + () -> assertThat(classpathResources) // + .extracting(Resource::getName) // + .containsExactly("org/junit/platform/commons/example.resource") // + ); + } + + @Test + void getMissingClasspathResources() { + var selector = selectClasspathResource("org/junit/platform/commons/no-such-example.resource"); + assertViolatesPrecondition(selector::getClasspathResources); } @Test From e9e1ade1b70f64cd91a11648b16bb855ffe326c9 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Thu, 17 Oct 2024 18:44:54 +0200 Subject: [PATCH 75/78] Do not included cached values in hashcode and equals --- .../engine/discovery/ClasspathResourceSelector.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java index af37e1f8512b..ecb934b84e42 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java @@ -130,8 +130,7 @@ public boolean equals(Object o) { } ClasspathResourceSelector that = (ClasspathResourceSelector) o; return Objects.equals(this.classpathResourceName, that.classpathResourceName) - && Objects.equals(this.position, that.position) - && Objects.equals(this.classpathResources, that.classpathResources); + && Objects.equals(this.position, that.position); } /** @@ -140,13 +139,17 @@ public boolean equals(Object o) { @API(status = STABLE, since = "1.3") @Override public int hashCode() { - return Objects.hash(this.classpathResourceName, this.position, this.classpathResources); + return Objects.hash(this.classpathResourceName, this.position); } @Override public String toString() { - return new ToStringBuilder(this).append("classpathResourceName", this.classpathResourceName).append("position", - this.position).toString(); + // @formatter:off + return new ToStringBuilder(this) + .append("classpathResourceName", this.classpathResourceName) + .append("position", this.position) + .toString(); + // @formatter:on } @Override From 23871b45fb3a0d040725fbc0fb443e9d36057461 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Mon, 28 Oct 2024 16:54:03 +0100 Subject: [PATCH 76/78] Update junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java Co-authored-by: Marc Philipp --- .../platform/engine/discovery/ClasspathResourceSelector.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java index ecb934b84e42..4b591a38684e 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/ClasspathResourceSelector.java @@ -102,7 +102,7 @@ public Set getClasspathResources() { "Could not load resource(s) with name: " + this.classpathResourceName, cause)); if (classpathResources.isEmpty()) { throw new PreconditionViolationException( - "Could not load resource(s) with name: " + this.classpathResourceName); + "Could not find any resource(s) with name: " + this.classpathResourceName); } this.classpathResources = unmodifiableSet(classpathResources); } From 75506f19d82e5fb904a1f4460542985e6976dc81 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Mon, 28 Oct 2024 16:54:23 +0100 Subject: [PATCH 77/78] Update documentation/src/docs/asciidoc/release-notes/release-notes-5.12.0-M1.adoc Co-authored-by: Marc Philipp --- .../docs/asciidoc/release-notes/release-notes-5.12.0-M1.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.12.0-M1.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.12.0-M1.adoc index afbe3cd8e892..b1e92534c8dd 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.12.0-M1.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.12.0-M1.adoc @@ -28,8 +28,8 @@ JUnit repository on GitHub. ==== New Features and Improvements * New `addResourceContainerSelectorResolver()` in `EngineDiscoveryRequestResolver.Builder` to -support the discovery of class path resource based tests, analogous to the -`addClassContainerSelectorResolver()`. + support the discovery of class path resource based tests, analogous to the + `addClassContainerSelectorResolver()`. * Introduce `ReflectionSupport.makeAccessible(Field)` for third-party use rather than calling the internal `ReflectionUtils.makeAccessible(Field)` method directly. * Support both the primitive type `void` and the wrapper type `Void` in the internal From 1d13082aa6eac12388feb7284d0ca2db7afb885c Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Mon, 28 Oct 2024 17:21:38 +0100 Subject: [PATCH 78/78] Merge resource predicates --- .../ResourceContainerSelectorResolver.java | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java index eda919ba4552..e5c41492b999 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/discovery/ResourceContainerSelectorResolver.java @@ -35,32 +35,29 @@ * @since 1.12 */ class ResourceContainerSelectorResolver implements SelectorResolver { - private final Predicate packageFilter; private final Predicate resourceFilter; - ResourceContainerSelectorResolver(Predicate resourceFilter, Predicate resourcePackageFilter) { - this.packageFilter = packageName(resourcePackageFilter); - this.resourceFilter = resourceFilter; + ResourceContainerSelectorResolver(Predicate resourceFilter, Predicate packageFilter) { + this.resourceFilter = packageName(packageFilter).and(resourceFilter); } @Override public Resolution resolve(ClasspathRootSelector selector, Context context) { - return resourceSelectors(findAllResourcesInClasspathRoot(selector.getClasspathRoot(), packageFilter)); + return resourceSelectors(findAllResourcesInClasspathRoot(selector.getClasspathRoot(), resourceFilter)); } @Override public Resolution resolve(ModuleSelector selector, Context context) { - return resourceSelectors(findAllResourcesInModule(selector.getModuleName(), packageFilter)); + return resourceSelectors(findAllResourcesInModule(selector.getModuleName(), resourceFilter)); } @Override public Resolution resolve(PackageSelector selector, Context context) { - return resourceSelectors(findAllResourcesInPackage(selector.getPackageName(), packageFilter)); + return resourceSelectors(findAllResourcesInPackage(selector.getPackageName(), resourceFilter)); } private Resolution resourceSelectors(List resources) { Set selectors = resources.stream() // - .filter(resourceFilter) // .collect(groupingBy(Resource::getName)) // .values() // .stream() //