Skip to content

Commit

Permalink
Ensure @ContextConfiguration & @TestPropertySource locations are cleaned
Browse files Browse the repository at this point in the history
This commit ensures that locations to resources configured via
@ContextConfiguration & @TestPropertySource are consistently cleaned
using StringUtils.clean().

See gh-23544
  • Loading branch information
sbrannen committed Aug 30, 2019
1 parent ff1f8aa commit 22494ba
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2019 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.
Expand Down Expand Up @@ -54,33 +54,41 @@ public abstract class TestContextResourceUtils {
* <ul>
* <li>A plain path &mdash; for example, {@code "context.xml"} &mdash; will
* be treated as a classpath resource that is relative to the package in
* which the specified class is defined.
* which the specified class is defined. Such a path will be prepended with
* the {@code classpath:} prefix and the path to the package for the class.
* <li>A path starting with a slash will be treated as an absolute path
* within the classpath, for example: {@code "/org/example/schema.sql"}.
* <li>A path which is prefixed with a URL protocol (e.g.,
* {@link ResourceUtils#CLASSPATH_URL_PREFIX classpath:},
* {@link ResourceUtils#FILE_URL_PREFIX file:}, {@code http:}, etc.) will be
* {@link StringUtils#cleanPath cleaned} but otherwise unmodified.
* Such a path will be prepended with the {@code classpath:} prefix.
* <li>A path which is already prefixed with a URL protocol (e.g.,
* {@code classpath:}, {@code file:}, {@code http:}, etc.) will not have its
* protocol modified.
* </ul>
* <p>Each path will then be {@linkplain StringUtils#cleanPath cleaned}.
* @param clazz the class with which the paths are associated
* @param paths the paths to be converted
* @return a new array of converted resource paths
* @see #convertToResources
* @see ResourceUtils#CLASSPATH_URL_PREFIX
* @see ResourceUtils#FILE_URL_PREFIX
*/
public static String[] convertToClasspathResourcePaths(Class<?> clazz, String... paths) {
String[] convertedPaths = new String[paths.length];
for (int i = 0; i < paths.length; i++) {
String path = paths[i];
// Absolute path
if (path.startsWith(SLASH)) {
convertedPaths[i] = ResourceUtils.CLASSPATH_URL_PREFIX + path;
}
// Relative path
else if (!ResourcePatternUtils.isUrl(path)) {
convertedPaths[i] = ResourceUtils.CLASSPATH_URL_PREFIX + SLASH +
StringUtils.cleanPath(ClassUtils.classPackageAsResourcePath(clazz) + SLASH + path);
ClassUtils.classPackageAsResourcePath(clazz) + SLASH + path;
}
// URL
else {
convertedPaths[i] = StringUtils.cleanPath(path);
convertedPaths[i] = path;
}
convertedPaths[i] = StringUtils.cleanPath(convertedPaths[i]);
}
return convertedPaths;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.ContextLoader;
import org.springframework.test.context.MergedContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.web.WebDelegatingSmartContextLoader;
import org.springframework.test.context.web.WebMergedContextConfiguration;

Expand Down Expand Up @@ -194,6 +195,29 @@ void buildMergedConfigWithAnnotationsAndOverriddenClasses() {
AnnotationConfigContextLoader.class);
}

@Test
void buildMergedConfigAndVerifyLocationPathsAreCleanedEquivalently() {
assertMergedConfigForLocationPaths(AbsoluteFooXmlLocationWithoutClasspathPrefix.class);
assertMergedConfigForLocationPaths(AbsoluteFooXmlLocationWithInnerRelativePathWithoutClasspathPrefix.class);
assertMergedConfigForLocationPaths(AbsoluteFooXmlLocationWithClasspathPrefix.class);
assertMergedConfigForLocationPaths(RelativeFooXmlLocation.class);
}

private void assertMergedConfigForLocationPaths(Class<?> testClass) {
MergedContextConfiguration mergedConfig = buildMergedContextConfiguration(testClass);

assertThat(mergedConfig).isNotNull();
assertThat(mergedConfig.getTestClass()).isEqualTo(testClass);
assertThat(mergedConfig.getContextLoader()).isInstanceOf(DelegatingSmartContextLoader.class);
assertThat(mergedConfig.getLocations()).containsExactly("classpath:/example/foo.xml");
assertThat(mergedConfig.getPropertySourceLocations()).containsExactly("classpath:/example/foo.properties");

assertThat(mergedConfig.getClasses()).isEmpty();
assertThat(mergedConfig.getActiveProfiles()).isEmpty();
assertThat(mergedConfig.getContextInitializerClasses()).isEmpty();
assertThat(mergedConfig.getPropertySourceProperties()).isEmpty();
}


@ContextConfiguration
@Retention(RetentionPolicy.RUNTIME)
Expand All @@ -217,4 +241,25 @@ public static class GermanShepherd extends WorkingDog {
static class MissingContextAttributesTestCase {
}

@ContextConfiguration(locations = "/example/foo.xml")
@TestPropertySource("/example/foo.properties")
static class AbsoluteFooXmlLocationWithoutClasspathPrefix {
}

@ContextConfiguration(locations = "/example/../org/../example/foo.xml")
@TestPropertySource("/example/../org/../example/foo.properties")
static class AbsoluteFooXmlLocationWithInnerRelativePathWithoutClasspathPrefix {
}

@ContextConfiguration(locations = "classpath:/example/foo.xml")
@TestPropertySource("classpath:/example/foo.properties")
static class AbsoluteFooXmlLocationWithClasspathPrefix {
}

// org.springframework.test.context.support --> 5 levels up to the root of the classpath
@ContextConfiguration(locations = "../../../../../example/foo.xml")
@TestPropertySource("../../../../../example/foo.properties")
static class RelativeFooXmlLocation {
}

}

0 comments on commit 22494ba

Please sign in to comment.