From 29442d4b7a92244399a4ce72e525d8ce71d405c0 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Sun, 25 Sep 2022 16:12:46 +0200 Subject: [PATCH] Revamp PathMatchingResourcePatternResolverTests In preparation for gh-29163, this commit revamps PathMatchingResourcePatternResolverTests as follows. - organizes tests into @Nested test classes - reintroduces the @Disabled classpathStarWithPatternOnFileSystem() test - stops asserting the protocol of Resource URLs, since the protocol is dependent on the environment -- for example, file: and jar: URLs are actually resource: URLs within a GraalVM native image - simplifies implementation of test methods and assertFilenames() --- ...hMatchingResourcePatternResolverTests.java | 201 ++++++++---------- 1 file changed, 94 insertions(+), 107 deletions(-) diff --git a/spring-core/src/test/java/org/springframework/core/io/support/PathMatchingResourcePatternResolverTests.java b/spring-core/src/test/java/org/springframework/core/io/support/PathMatchingResourcePatternResolverTests.java index 41db4dcff5..0410d11e92 100644 --- a/spring-core/src/test/java/org/springframework/core/io/support/PathMatchingResourcePatternResolverTests.java +++ b/spring-core/src/test/java/org/springframework/core/io/support/PathMatchingResourcePatternResolverTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,25 +16,27 @@ package org.springframework.core.io.support; -import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; -import java.util.ArrayList; +import java.net.URLDecoder; import java.util.Arrays; import java.util.List; -import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledInNativeImage; import org.springframework.core.io.Resource; import org.springframework.util.StringUtils; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; /** - * If this test case fails, uncomment diagnostics in the - * {@link #assertProtocolAndFilenames} method. + * Tests for {@link PathMatchingResourcePatternResolver}. + * + *

If tests fail, uncomment the diagnostics in {@link #assertFilenames}. * * @author Oliver Hutchison * @author Juergen Hoeller @@ -44,124 +46,109 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType; */ class PathMatchingResourcePatternResolverTests { - private static final String[] CLASSES_IN_CORE_IO_SUPPORT = - new String[] {"EncodedResource.class", "LocalizedResourceHelper.class", - "PathMatchingResourcePatternResolver.class", "PropertiesLoaderSupport.class", - "PropertiesLoaderUtils.class", "ResourceArrayPropertyEditor.class", - "ResourcePatternResolver.class", "ResourcePatternUtils.class"}; + private static final String[] CLASSES_IN_CORE_IO_SUPPORT = { "EncodedResource.class", + "LocalizedResourceHelper.class", "PathMatchingResourcePatternResolver.class", "PropertiesLoaderSupport.class", + "PropertiesLoaderUtils.class", "ResourceArrayPropertyEditor.class", "ResourcePatternResolver.class", + "ResourcePatternUtils.class", "SpringFactoriesLoader.class" }; - private static final String[] TEST_CLASSES_IN_CORE_IO_SUPPORT = - new String[] {"PathMatchingResourcePatternResolverTests.class"}; + private static final String[] TEST_CLASSES_IN_CORE_IO_SUPPORT = { "PathMatchingResourcePatternResolverTests.class" }; - private static final String[] CLASSES_IN_REACTOR_UTIL_ANNOTATIONS = - new String[] {"NonNull.class", "NonNullApi.class", "Nullable.class"}; - - private PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); + private static final String[] CLASSES_IN_REACTOR_UTIL_ANNOTATION = { "NonNull.class", "NonNullApi.class", "Nullable.class" }; - @Test - void invalidPrefixWithPatternElementInIt() throws IOException { - assertThatExceptionOfType(FileNotFoundException.class).isThrownBy(() -> - resolver.getResources("xx**:**/*.xy")); - } + private final PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); - @Test - void singleResourceOnFileSystem() throws IOException { - Resource[] resources = - resolver.getResources("org/springframework/core/io/support/PathMatchingResourcePatternResolverTests.class"); - assertThat(resources.length).isEqualTo(1); - assertProtocolAndFilenames(resources, "file", "PathMatchingResourcePatternResolverTests.class"); - } - @Test - void singleResourceInJar() throws IOException { - Resource[] resources = resolver.getResources("org/reactivestreams/Publisher.class"); - assertThat(resources.length).isEqualTo(1); - assertProtocolAndFilenames(resources, "jar", "Publisher.class"); - } + @Nested + class InvalidPatterns { - @Disabled - @Test - void classpathStarWithPatternOnFileSystem() throws IOException { - Resource[] resources = resolver.getResources("classpath*:org/springframework/core/io/sup*/*.class"); - // Have to exclude Clover-generated class files here, - // as we might be running as part of a Clover test run. - List noCloverResources = new ArrayList<>(); - for (Resource resource : resources) { - if (!resource.getFilename().contains("$__CLOVER_")) { - noCloverResources.add(resource); - } + @Test + void invalidPrefixWithPatternElementInItThrowsException() throws IOException { + assertThatExceptionOfType(FileNotFoundException.class).isThrownBy(() -> resolver.getResources("xx**:**/*.xy")); } - resources = noCloverResources.toArray(new Resource[0]); - assertProtocolAndFilenames(resources, "file", - StringUtils.concatenateStringArrays(CLASSES_IN_CORE_IO_SUPPORT, TEST_CLASSES_IN_CORE_IO_SUPPORT)); + } - @Test - void getResourcesOnFileSystemContainingHashtagsInTheirFileNames() throws IOException { - Resource[] resources = resolver.getResources("classpath*:org/springframework/core/io/**/resource#test*.txt"); - assertThat(resources).extracting(Resource::getFile).extracting(File::getName) - .containsExactlyInAnyOrder("resource#test1.txt", "resource#test2.txt"); - } - @Test - void classpathWithPatternInJar() throws IOException { - Resource[] resources = resolver.getResources("classpath:reactor/util/annotation/*.class"); - assertProtocolAndFilenames(resources, "jar", CLASSES_IN_REACTOR_UTIL_ANNOTATIONS); - } + @Nested + class FileSystemResources { - @Test - void classpathStarWithPatternInJar() throws IOException { - Resource[] resources = resolver.getResources("classpath*:reactor/util/annotation/*.class"); - assertProtocolAndFilenames(resources, "jar", CLASSES_IN_REACTOR_UTIL_ANNOTATIONS); - } - - @Test - void rootPatternRetrievalInJarFiles() throws IOException { - Resource[] resources = resolver.getResources("classpath*:*.dtd"); - boolean found = false; - for (Resource resource : resources) { - if (resource.getFilename().equals("aspectj_1_5_0.dtd")) { - found = true; - break; - } + @Test + void singleResourceOnFileSystem() throws IOException { + String pattern = "org/springframework/core/io/support/PathMatchingResourcePatternResolverTests.class"; + assertFilenames(pattern, "PathMatchingResourcePatternResolverTests.class"); } - assertThat(found).as("Could not find aspectj_1_5_0.dtd in the root of the aspectjweaver jar").isTrue(); - } - - private void assertProtocolAndFilenames(Resource[] resources, String protocol, String... filenames) - throws IOException { - - // Uncomment the following if you encounter problems with matching against the file system - // It shows file locations. -// String[] actualNames = new String[resources.length]; -// for (int i = 0; i < resources.length; i++) { -// actualNames[i] = resources[i].getFilename(); -// } -// List sortedActualNames = new LinkedList(Arrays.asList(actualNames)); -// List expectedNames = new LinkedList(Arrays.asList(fileNames)); -// Collections.sort(sortedActualNames); -// Collections.sort(expectedNames); -// -// System.out.println("-----------"); -// System.out.println("Expected: " + StringUtils.collectionToCommaDelimitedString(expectedNames)); -// System.out.println("Actual: " + StringUtils.collectionToCommaDelimitedString(sortedActualNames)); -// for (int i = 0; i < resources.length; i++) { -// System.out.println(resources[i]); -// } - - assertThat(resources.length).as("Correct number of files found").isEqualTo(filenames.length); - for (Resource resource : resources) { - String actualProtocol = resource.getURL().getProtocol(); - assertThat(actualProtocol).isEqualTo(protocol); - assertFilenameIn(resource, filenames); + @Test + void classpathStarWithPatternOnFileSystem() throws IOException { + String pattern = "classpath*:org/springframework/core/io/sup*/*.class"; + String[] expectedFilenames = StringUtils.concatenateStringArrays(CLASSES_IN_CORE_IO_SUPPORT, TEST_CLASSES_IN_CORE_IO_SUPPORT); + assertFilenames(pattern, expectedFilenames); } + + @Test + void getResourcesOnFileSystemContainingHashtagsInTheirFileNames() throws IOException { + String pattern = "classpath*:org/springframework/core/io/**/resource#test*.txt"; + assertFilenames(pattern, "resource#test1.txt", "resource#test2.txt"); + } + } - private void assertFilenameIn(Resource resource, String... filenames) { - String filename = resource.getFilename(); - assertThat(Arrays.stream(filenames).anyMatch(filename::endsWith)).as(resource + " does not have a filename that matches any of the specified names").isTrue(); + + @Nested + class JarResources { + + @Test + void singleResourceInJar() throws IOException { + String pattern = "org/reactivestreams/Publisher.class"; + assertFilenames(pattern, "Publisher.class"); + } + + @Test + void singleResourceInRootOfJar() throws IOException { + String pattern = "aspectj_1_5_0.dtd"; + assertFilenames(pattern, "aspectj_1_5_0.dtd"); + } + + @Test + void classpathWithPatternInJar() throws IOException { + String pattern = "classpath:reactor/util/annotation/*.class"; + assertFilenames(pattern, CLASSES_IN_REACTOR_UTIL_ANNOTATION); + } + + @Test + void classpathStarWithPatternInJar() throws IOException { + String pattern = "classpath*:reactor/util/annotation/*.class"; + assertFilenames(pattern, CLASSES_IN_REACTOR_UTIL_ANNOTATION); + } + + @DisabledInNativeImage // https://github.com/oracle/graal/issues/5020 + @Test + void rootPatternRetrievalInJarFiles() throws IOException { + assertThat(resolver.getResources("classpath*:*.dtd")).extracting(Resource::getFilename) + .as("Could not find aspectj_1_5_0.dtd in the root of the aspectjweaver jar") + .contains("aspectj_1_5_0.dtd"); + } + + } + + + private void assertFilenames(String pattern, String... filenames) throws IOException { + Resource[] resources = resolver.getResources(pattern); + List actualNames = Arrays.stream(resources) + .map(Resource::getFilename) + .map(filename -> URLDecoder.decode(filename, UTF_8)) + .sorted() + .toList(); + + // Uncomment the following if you encounter problems with matching against the file system. + // List expectedNames = Arrays.stream(filenames).sorted().toList(); + // System.out.println("----------------------------------------------------------------------"); + // System.out.println("Expected: " + expectedNames); + // System.out.println("Actual: " + actualNames); + // Arrays.stream(resources).forEach(System.out::println); + + assertThat(actualNames).as("subset of files found").contains(filenames); } }