Skip to content

Commit c0d9fd3

Browse files
committed
Add selectClasspathResources(String...) to discovery selectors
Adds the array and list based equivalent of the singular `selectClasspathResource`. Additionally: 1. Replace `List.of` with `Arrays.asList` to prevent premature NPEs instead of failing preconditions. 2. Add and use `Preconditions.containsNoBlankElements` to catch collections with blank strings.
1 parent 80bf2fd commit c0d9fd3

File tree

4 files changed

+179
-8
lines changed

4 files changed

+179
-8
lines changed

junit-platform-commons/src/main/java/org/junit/platform/commons/util/Preconditions.java

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,56 @@ public static <T extends Collection<?>> T notEmpty(@Nullable T collection, Suppl
270270
return collection;
271271
}
272272

273+
/**
274+
* Assert that the supplied collection contains no blank elements.
275+
*
276+
* <p><strong>WARNING</strong>: this method does NOT check if the supplied
277+
* collection is {@code null} or <em>empty</em>.
278+
*
279+
* @param collection the collection to check
280+
* @param message precondition violation message
281+
* @return the supplied collection as a convenience
282+
* @throws PreconditionViolationException if the supplied collection contains
283+
* any blank elements
284+
* @since 6.1
285+
* @see #notBlank(String, String)
286+
*/
287+
@API(status = INTERNAL, since = "6.1")
288+
@Contract("null, _ -> null")
289+
public static <T extends Collection<String>> @Nullable T containsNoBlankElements(@Nullable T collection,
290+
String message) throws PreconditionViolationException {
291+
292+
if (collection != null) {
293+
collection.forEach(object -> notBlank(object, message));
294+
}
295+
return collection;
296+
}
297+
298+
/**
299+
* Assert that the supplied collection contains no blank elements.
300+
*
301+
* <p><strong>WARNING</strong>: this method does NOT check if the supplied
302+
* collection is {@code null} or <em>empty</em>.
303+
*
304+
* @param collection the collection to check
305+
* @param messageSupplier precondition violation message supplier
306+
* @return the supplied collection as a convenience
307+
* @throws PreconditionViolationException if the supplied collection contains
308+
* any blank elements
309+
* @since 6.1
310+
* @see #notBlank(String, String)
311+
*/
312+
@API(status = INTERNAL, since = "6.1")
313+
@Contract("null, _ -> null")
314+
public static <T extends Collection<String>> @Nullable T containsNoBlankElements(@Nullable T collection,
315+
Supplier<String> messageSupplier) throws PreconditionViolationException {
316+
317+
if (collection != null) {
318+
collection.forEach(object -> notBlank(object, messageSupplier));
319+
}
320+
return collection;
321+
}
322+
273323
/**
274324
* Assert that the supplied {@link String} is not blank.
275325
*

junit-platform-engine/src/main/java/org/junit/platform/engine/discovery/DiscoverySelectors.java

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.net.URISyntaxException;
2323
import java.nio.file.Files;
2424
import java.nio.file.Path;
25+
import java.util.Arrays;
2526
import java.util.Collection;
2627
import java.util.List;
2728
import java.util.Optional;
@@ -292,6 +293,7 @@ public static List<ClasspathRootSelector> selectClasspathRoots(Set<Path> classpa
292293
* @param classpathResourceName the name of the classpath resource; never
293294
* {@code null} or blank
294295
* @see #selectClasspathResource(String, FilePosition)
296+
* @see #selectClasspathResources(String...)
295297
* @see #selectClasspathResourceByName(Set)
296298
* @see ClasspathResourceSelector
297299
* @see ClassLoader#getResource(String)
@@ -322,6 +324,7 @@ public static ClasspathResourceSelector selectClasspathResource(String classpath
322324
* {@code null} or blank
323325
* @param position the position inside the classpath resource; may be {@code null}
324326
* @see #selectClasspathResource(String)
327+
* @see #selectClasspathResources(String...)
325328
* @see #selectClasspathResourceByName(Set)
326329
* @see ClasspathResourceSelector
327330
* @see ClassLoader#getResource(String)
@@ -413,6 +416,45 @@ public static ClasspathResourceSelector selectClasspathResourceByName(Set<? exte
413416
return new ClasspathResourceSelector(classpathResources);
414417
}
415418

419+
/**
420+
* Create a {@code ClasspathResourceSelector} for each supplied classpath
421+
* resource name.
422+
*
423+
* @param classpathResourceNames the names of the classpath resource; never
424+
* {@code null} and never containing {@code null} or blank references.
425+
* @since 6.1
426+
* @see #selectClasspathResource(String)
427+
* @see #selectClasspathResources(String...)
428+
* @see ClasspathResourceSelector
429+
*/
430+
@API(status = EXPERIMENTAL, since = "6.1")
431+
public static List<ClasspathResourceSelector> selectClasspathResources(String... classpathResourceNames) {
432+
Preconditions.notNull(classpathResourceNames, "classpathResourceNames must not be null");
433+
return selectClasspathResources(Arrays.asList(classpathResourceNames));
434+
}
435+
436+
/**
437+
* Create a {@code ClasspathResourceSelector} for each supplied classpath
438+
* resource name.
439+
*
440+
* @param classpathResourceNames the names of the classpath resource; never
441+
* {@code null} and never containing {@code null} or blank references.
442+
* @since 6.1
443+
* @see #selectClasspathResource(String)
444+
* @see #selectClasspathResources(String...)
445+
* @see ClasspathResourceSelector
446+
*/
447+
@API(status = EXPERIMENTAL, since = "6.1")
448+
public static List<ClasspathResourceSelector> selectClasspathResources(List<String> classpathResourceNames) {
449+
Preconditions.notNull(classpathResourceNames, "classpathResourceNames must not be null");
450+
Preconditions.containsNoBlankElements(classpathResourceNames,
451+
"Individual classpathResourceNames must not be null or blank");
452+
return classpathResourceNames.stream() //
453+
.distinct() //
454+
.map(DiscoverySelectors::selectClasspathResource) //
455+
.toList();
456+
}
457+
416458
/**
417459
* Create a {@code ModuleSelector} for the supplied module name.
418460
*
@@ -540,7 +582,8 @@ public static ClassSelector selectClass(@Nullable ClassLoader classLoader, Strin
540582
*/
541583
@API(status = EXPERIMENTAL, since = "6.0")
542584
public static List<ClassSelector> selectClasses(Class<?>... classes) {
543-
return selectClasses(List.of(classes));
585+
Preconditions.notNull(classes, "classes must not be null");
586+
return selectClasses(Arrays.asList(classes));
544587
}
545588

546589
/**
@@ -579,7 +622,8 @@ public static List<ClassSelector> selectClasses(List<Class<?>> classes) {
579622
*/
580623
@API(status = EXPERIMENTAL, since = "6.0")
581624
public static List<ClassSelector> selectClassesByName(String... classNames) {
582-
return selectClassesByName(List.of(classNames));
625+
Preconditions.notNull(classNames, "classNames must not be null");
626+
return selectClassesByName(Arrays.asList(classNames));
583627
}
584628

585629
/**
@@ -595,6 +639,7 @@ public static List<ClassSelector> selectClassesByName(String... classNames) {
595639
*/
596640
@API(status = EXPERIMENTAL, since = "6.0")
597641
public static List<ClassSelector> selectClassesByName(List<String> classNames) {
642+
Preconditions.notNull(classNames, "classNames must not be null");
598643
return selectClassesByName(null, classNames);
599644
}
600645

@@ -613,7 +658,8 @@ public static List<ClassSelector> selectClassesByName(List<String> classNames) {
613658
*/
614659
@API(status = EXPERIMENTAL, since = "6.0")
615660
public static List<ClassSelector> selectClassesByName(@Nullable ClassLoader classLoader, String... classNames) {
616-
return selectClassesByName(classLoader, List.of(classNames));
661+
Preconditions.notNull(classNames, "classNames must not be null");
662+
return selectClassesByName(classLoader, Arrays.asList(classNames));
617663
}
618664

619665
/**
@@ -631,7 +677,7 @@ public static List<ClassSelector> selectClassesByName(@Nullable ClassLoader clas
631677
@API(status = EXPERIMENTAL, since = "6.0")
632678
public static List<ClassSelector> selectClassesByName(@Nullable ClassLoader classLoader, List<String> classNames) {
633679
Preconditions.notNull(classNames, "classNames must not be null");
634-
Preconditions.containsNoNullElements(classNames, "Individual class names must not be null");
680+
Preconditions.containsNoBlankElements(classNames, "Individual class names must not be null or blank");
635681

636682
// @formatter:off
637683
return classNames.stream()

platform-tests/src/test/java/org/junit/platform/commons/util/PreconditionsTests.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import static org.junit.jupiter.api.Assertions.assertSame;
1515
import static org.junit.platform.commons.test.PreconditionAssertions.assertPreconditionViolationFor;
1616
import static org.junit.platform.commons.util.Preconditions.condition;
17+
import static org.junit.platform.commons.util.Preconditions.containsNoBlankElements;
1718
import static org.junit.platform.commons.util.Preconditions.containsNoNullElements;
1819
import static org.junit.platform.commons.util.Preconditions.notBlank;
1920
import static org.junit.platform.commons.util.Preconditions.notEmpty;
@@ -106,6 +107,32 @@ void notEmptyThrowsForEmptyCollection() {
106107
assertPreconditionViolationFor(() -> notEmpty(List.of(), message)).withMessage(message);
107108
}
108109

110+
@Test
111+
void containsNoBlankElementsPassesForCollectionThatIsNullOrEmpty() {
112+
containsNoBlankElements((List<String>) null, "collection is null");
113+
containsNoBlankElements(List.of(), "collection is empty");
114+
115+
containsNoBlankElements((List<String>) null, () -> "collection is null");
116+
containsNoBlankElements(List.of(), () -> "collection is empty");
117+
}
118+
119+
@Test
120+
void containsNoBlankElementsPassesForCollectionContainingNonBlankElements() {
121+
var input = List.of("a", "b", "c");
122+
var output = containsNoBlankElements(input, "message");
123+
assertSame(input, output);
124+
}
125+
126+
@Test
127+
void containsNoBlankElementsThrowsForCollectionContainingNullElements() {
128+
var message = "collection contains blank elements";
129+
130+
assertPreconditionViolationFor(() -> containsNoBlankElements(singletonList(""), message)) //
131+
.withMessage(message);
132+
assertPreconditionViolationFor(() -> containsNoBlankElements(singletonList((String) null), message)) //
133+
.withMessage(message);
134+
}
135+
109136
@Test
110137
void containsNoNullElementsPassesForArrayThatIsNullOrEmpty() {
111138
containsNoNullElements((Object[]) null, "array is null");

platform-tests/src/test/java/org/junit/platform/engine/discovery/DiscoverySelectorsTests.java

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
package org.junit.platform.engine.discovery;
1212

1313
import static java.lang.String.join;
14+
import static java.util.Collections.singletonList;
1415
import static java.util.Objects.requireNonNull;
1516
import static org.assertj.core.api.Assertions.assertThat;
1617
import static org.assertj.core.api.InstanceOfAssertFactories.type;
@@ -25,6 +26,7 @@
2526
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClassesByName;
2627
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClasspathResource;
2728
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClasspathResourceByName;
29+
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClasspathResources;
2830
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClasspathRoots;
2931
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectDirectory;
3032
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectFile;
@@ -298,7 +300,7 @@ class SelectClasspathResourceTests {
298300

299301
@SuppressWarnings("DataFlowIssue")
300302
@Test
301-
void selectClasspathResourcesPreconditions() {
303+
void selectClasspathResourcePreconditions() {
302304
// @formatter:off
303305
assertPreconditionViolationFor(() -> selectClasspathResource((String) null));
304306
assertPreconditionViolationFor(() -> selectClasspathResource(""));
@@ -317,7 +319,7 @@ void selectClasspathResourcesPreconditions() {
317319
}
318320

319321
@Test
320-
void selectIndividualClasspathResources() {
322+
void selectIndividualClasspathResource() {
321323
// with unnecessary "/" prefix
322324
var selector = selectClasspathResource("/foo/bar/spec.xml");
323325
assertEquals("foo/bar/spec.xml", selector.getClasspathResourceName());
@@ -328,7 +330,7 @@ void selectIndividualClasspathResources() {
328330
}
329331

330332
@Test
331-
void getSelectedClasspathResources() {
333+
void getSelectedClasspathResource() {
332334
var selector = selectClasspathResource("org/junit/platform/commons/example.resource");
333335
var classpathResources = selector.getResources();
334336
assertAll(() -> assertThat(classpathResources).hasSize(1), //
@@ -339,7 +341,7 @@ void getSelectedClasspathResources() {
339341
}
340342

341343
@Test
342-
void getMissingClasspathResources() {
344+
void getMissingClasspathResource() {
343345
var selector = selectClasspathResource("org/junit/platform/commons/no-such-example.resource");
344346
assertPreconditionViolationFor(selector::getResources);
345347
}
@@ -417,6 +419,52 @@ public URI getUri() {
417419
}
418420
}
419421

422+
/**
423+
* @since 6.1
424+
*/
425+
@Nested
426+
class SelectClasspathResourcesTests {
427+
428+
@SuppressWarnings("DataFlowIssue")
429+
@Test
430+
void selectClasspathResourcesPreconditions() {
431+
assertPreconditionViolationFor(() -> selectClasspathResources((String) null));
432+
assertPreconditionViolationFor(() -> selectClasspathResources((String[]) null));
433+
assertPreconditionViolationFor(() -> selectClasspathResources(""));
434+
assertPreconditionViolationFor(() -> selectClasspathResources(singletonList(null)));
435+
assertPreconditionViolationFor(() -> selectClasspathResources(singletonList("")));
436+
}
437+
438+
@Test
439+
void selectMultipleClasspathResources() {
440+
var selectors = selectClasspathResources( //
441+
"org/junit/platform/example-a.resource", //
442+
"org/junit/platform/example-b.resource" //
443+
);
444+
assertThat(selectors).extracting(ClasspathResourceSelector::getClasspathResourceName) //
445+
.containsExactly( //
446+
"org/junit/platform/example-a.resource", //
447+
"org/junit/platform/example-b.resource" //
448+
);
449+
}
450+
451+
@Test
452+
void selectDistinctClasspathResources() {
453+
var selectors = selectClasspathResources( //
454+
"org/junit/platform/example-a.resource", //
455+
"org/junit/platform/example-b.resource", //
456+
"org/junit/platform/example-a.resource", //
457+
"org/junit/platform/example-c.resource" //
458+
);
459+
assertThat(selectors).extracting(ClasspathResourceSelector::getClasspathResourceName) //
460+
.containsExactly( //
461+
"org/junit/platform/example-a.resource", //
462+
"org/junit/platform/example-b.resource", //
463+
"org/junit/platform/example-c.resource" //
464+
);
465+
}
466+
}
467+
420468
@Nested
421469
class SelectModuleTests {
422470

0 commit comments

Comments
 (0)