Add support for working with resources in tests
Closes gh-44444
This commit is contained in:
parent
abf320d273
commit
3acea583ad
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.testsupport.classpath.resources;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation that indicates that the content of a resource should be injected. Supported
|
||||
* on parameters of type:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link String}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.PARAMETER)
|
||||
public @interface ResourceContent {
|
||||
|
||||
/**
|
||||
* The name of the resource whose content should be injected.
|
||||
* @return the resource name
|
||||
*/
|
||||
String value();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.testsupport.classpath.resources;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.nio.file.Path;
|
||||
|
||||
/**
|
||||
* Annotation that indicates that the path of a resource should be injected. Supported on
|
||||
* parameters of type:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link File}</li>
|
||||
* <li>{@link Path}</li>
|
||||
* <li>{@link String}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.PARAMETER)
|
||||
public @interface ResourcePath {
|
||||
|
||||
/**
|
||||
* The name of the resource whose path should be injected.
|
||||
* @return the resource name
|
||||
*/
|
||||
String value();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.testsupport.classpath.resources;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.FileSystemUtils;
|
||||
|
||||
/**
|
||||
* A collection of resources.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class Resources {
|
||||
|
||||
private final Path root;
|
||||
|
||||
Resources(Path root) {
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
Resources addPackage(Package root, String[] resourceNames) {
|
||||
Set<String> unmatchedNames = new HashSet<>(Arrays.asList(resourceNames));
|
||||
try {
|
||||
Enumeration<URL> sources = getClass().getClassLoader().getResources(root.getName().replace(".", "/"));
|
||||
for (URL source : Collections.list(sources)) {
|
||||
Path sourceRoot = Paths.get(source.toURI());
|
||||
for (String resourceName : resourceNames) {
|
||||
Path resource = sourceRoot.resolve(resourceName);
|
||||
if (Files.isRegularFile(resource)) {
|
||||
Path target = this.root.resolve(resourceName);
|
||||
Path targetDirectory = target.getParent();
|
||||
if (!Files.isDirectory(targetDirectory)) {
|
||||
Files.createDirectories(targetDirectory);
|
||||
}
|
||||
Files.copy(resource, target);
|
||||
unmatchedNames.remove(resourceName);
|
||||
}
|
||||
}
|
||||
}
|
||||
Assert.isTrue(unmatchedNames.isEmpty(),
|
||||
"Package '" + root.getName() + "' did not contain resources: " + unmatchedNames);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new UncheckedIOException(ex);
|
||||
}
|
||||
catch (URISyntaxException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
Resources addResource(String name, String content) {
|
||||
Path resourcePath = this.root.resolve(name);
|
||||
if (Files.isDirectory(resourcePath)) {
|
||||
throw new IllegalStateException(
|
||||
"Cannot create resource '" + name + "' as a directory already exists at that location");
|
||||
}
|
||||
Path parent = resourcePath.getParent();
|
||||
try {
|
||||
if (!Files.isDirectory(resourcePath)) {
|
||||
Files.createDirectories(parent);
|
||||
}
|
||||
Files.writeString(resourcePath, processContent(content));
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new UncheckedIOException(ex);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private String processContent(String content) {
|
||||
return content.replace("${resourceRoot}", this.root.toString());
|
||||
}
|
||||
|
||||
Resources addDirectory(String name) {
|
||||
Path directoryPath = this.root.resolve(name);
|
||||
if (Files.isRegularFile(directoryPath)) {
|
||||
throw new IllegalStateException(
|
||||
"Cannot create directory '" + name + " as a file already exists at that location");
|
||||
}
|
||||
try {
|
||||
Files.createDirectories(directoryPath);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new UncheckedIOException(ex);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
void delete() {
|
||||
try {
|
||||
FileSystemUtils.deleteRecursively(this.root);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new UncheckedIOException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
Path getRoot() {
|
||||
return this.root;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.testsupport.classpath.resources;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A {@link ClassLoader} that provides access to {@link Resources resources}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class ResourcesClassLoader extends ClassLoader {
|
||||
|
||||
private final Resources resources;
|
||||
|
||||
ResourcesClassLoader(ClassLoader parent, Resources resources) {
|
||||
super(parent);
|
||||
this.resources = resources;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected URL findResource(String name) {
|
||||
Path resource = this.resources.getRoot().resolve(name);
|
||||
if (Files.exists(resource)) {
|
||||
try {
|
||||
return resource.toUri().toURL();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new UncheckedIOException(ex);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Enumeration<URL> findResources(String name) throws IOException {
|
||||
URL resourceUrl = findResource(name);
|
||||
return (resourceUrl != null) ? Collections.enumeration(List.of(resourceUrl)) : Collections.emptyEnumeration();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,189 @@
|
|||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.testsupport.classpath.resources;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.extension.AfterEachCallback;
|
||||
import org.junit.jupiter.api.extension.BeforeEachCallback;
|
||||
import org.junit.jupiter.api.extension.Extension;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext.Store;
|
||||
import org.junit.jupiter.api.extension.ParameterContext;
|
||||
import org.junit.jupiter.api.extension.ParameterResolutionException;
|
||||
import org.junit.jupiter.api.extension.ParameterResolver;
|
||||
import org.junit.platform.commons.support.AnnotationSupport;
|
||||
import org.junit.platform.commons.support.SearchOption;
|
||||
|
||||
import org.springframework.util.StreamUtils;
|
||||
|
||||
/**
|
||||
* {@link Extension} for managing resources in tests. Resources are made available through
|
||||
* {@link Thread#getContextClassLoader() thread context class loader}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @see WithPackageResources
|
||||
* @see WithResource
|
||||
* @see WithResourceDirectory
|
||||
*/
|
||||
class ResourcesExtension implements BeforeEachCallback, AfterEachCallback, ParameterResolver {
|
||||
|
||||
private static final String RESOURCES_KEY = ResourcesExtension.class.getName() + ".resources";
|
||||
|
||||
private static final String TCCL_KEY = ResourcesExtension.class.getName() + ".tccl";
|
||||
|
||||
@Override
|
||||
public void beforeEach(ExtensionContext context) throws Exception {
|
||||
Store store = context.getStore(Namespace.create(ResourcesExtension.class));
|
||||
Resources resources = new Resources(Files.createTempDirectory("resources"));
|
||||
store.put(RESOURCES_KEY, resources);
|
||||
Method testMethod = context.getRequiredTestMethod();
|
||||
resourcesOf(testMethod).forEach((resource) -> resources.addResource(resource.name(), resource.content()));
|
||||
resourceDirectoriesOf(testMethod).forEach((directory) -> resources.addDirectory(directory.value()));
|
||||
packageResourcesOf(testMethod).forEach((withPackageResources) -> resources
|
||||
.addPackage(testMethod.getDeclaringClass().getPackage(), withPackageResources.value()));
|
||||
ResourcesClassLoader classLoader = new ResourcesClassLoader(context.getRequiredTestClass().getClassLoader(),
|
||||
resources);
|
||||
store.put(TCCL_KEY, Thread.currentThread().getContextClassLoader());
|
||||
Thread.currentThread().setContextClassLoader(classLoader);
|
||||
}
|
||||
|
||||
private List<WithResource> resourcesOf(Method method) {
|
||||
return withAnnotationsOf(method, WithResource.class);
|
||||
}
|
||||
|
||||
private List<WithResourceDirectory> resourceDirectoriesOf(Method method) {
|
||||
return withAnnotationsOf(method, WithResourceDirectory.class);
|
||||
}
|
||||
|
||||
private <A extends Annotation> List<A> withAnnotationsOf(Method method, Class<A> annotationType) {
|
||||
List<A> annotations = new ArrayList<>();
|
||||
AnnotationSupport.findRepeatableAnnotations(method, annotationType).forEach(annotations::add);
|
||||
Class<?> type = method.getDeclaringClass();
|
||||
while (type != null) {
|
||||
AnnotationSupport.findRepeatableAnnotations(type, annotationType).forEach(annotations::add);
|
||||
type = type.getEnclosingClass();
|
||||
}
|
||||
return annotations;
|
||||
}
|
||||
|
||||
private List<WithPackageResources> packageResourcesOf(Method method) {
|
||||
List<WithPackageResources> annotations = new ArrayList<>();
|
||||
AnnotationSupport.findAnnotation(method, WithPackageResources.class).ifPresent(annotations::add);
|
||||
AnnotationSupport
|
||||
.findAnnotation(method.getDeclaringClass(), WithPackageResources.class,
|
||||
SearchOption.INCLUDE_ENCLOSING_CLASSES)
|
||||
.ifPresent(annotations::add);
|
||||
return annotations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterEach(ExtensionContext context) throws Exception {
|
||||
Store store = context.getStore(Namespace.create(ResourcesExtension.class));
|
||||
store.get(RESOURCES_KEY, Resources.class).delete();
|
||||
Thread.currentThread().setContextClassLoader(store.get(TCCL_KEY, ClassLoader.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext)
|
||||
throws ParameterResolutionException {
|
||||
return parameterContext.isAnnotated(ResourcesRoot.class) || parameterContext.isAnnotated(ResourcePath.class)
|
||||
|| parameterContext.isAnnotated(ResourceContent.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext)
|
||||
throws ParameterResolutionException {
|
||||
if (parameterContext.isAnnotated(ResourcesRoot.class)) {
|
||||
return resolveResourcesRoot(parameterContext, extensionContext);
|
||||
}
|
||||
if (parameterContext.isAnnotated(ResourcePath.class)) {
|
||||
return resolveResourcePath(parameterContext, extensionContext);
|
||||
}
|
||||
if (parameterContext.isAnnotated(ResourceContent.class)) {
|
||||
return resolveResourceContent(parameterContext, extensionContext);
|
||||
}
|
||||
throw new ParameterResolutionException(
|
||||
"Parameter is not annotated with @ResourcesRoot, @ResourceContent, or @ResourcePath");
|
||||
}
|
||||
|
||||
private Object resolveResourcesRoot(ParameterContext parameterContext, ExtensionContext extensionContext) {
|
||||
Resources resources = getResources(extensionContext);
|
||||
Class<?> parameterType = parameterContext.getParameter().getType();
|
||||
if (parameterType.isAssignableFrom(Path.class)) {
|
||||
return resources.getRoot();
|
||||
}
|
||||
else if (parameterType.isAssignableFrom(File.class)) {
|
||||
return resources.getRoot().toFile();
|
||||
}
|
||||
throw new IllegalStateException(
|
||||
"@ResourcesRoot is not supported with parameter type '" + parameterType.getName() + "'");
|
||||
}
|
||||
|
||||
private Object resolveResourcePath(ParameterContext parameterContext, ExtensionContext extensionContext) {
|
||||
Resources resources = getResources(extensionContext);
|
||||
Class<?> parameterType = parameterContext.getParameter().getType();
|
||||
Path resourcePath = resources.getRoot()
|
||||
.resolve(parameterContext.findAnnotation(ResourcePath.class).get().value());
|
||||
if (parameterType.isAssignableFrom(Path.class)) {
|
||||
return resourcePath;
|
||||
}
|
||||
else if (parameterType.isAssignableFrom(File.class)) {
|
||||
return resourcePath.toFile();
|
||||
}
|
||||
else if (parameterType.isAssignableFrom(String.class)) {
|
||||
return resourcePath.toString();
|
||||
}
|
||||
throw new IllegalStateException(
|
||||
"@ResourcePath is not supported with parameter type '" + parameterType.getName() + "'");
|
||||
}
|
||||
|
||||
private Object resolveResourceContent(ParameterContext parameterContext, ExtensionContext extensionContext) {
|
||||
Resources resources = getResources(extensionContext);
|
||||
Class<?> parameterType = parameterContext.getParameter().getType();
|
||||
Path resourcePath = resources.getRoot()
|
||||
.resolve(parameterContext.findAnnotation(ResourceContent.class).get().value());
|
||||
if (parameterType.isAssignableFrom(String.class)) {
|
||||
try (InputStream in = Files.newInputStream(resourcePath)) {
|
||||
return StreamUtils.copyToString(in, StandardCharsets.UTF_8);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new UncheckedIOException(ex);
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException(
|
||||
"@ResourceContent is not supported with parameter type '" + parameterType.getName() + "'");
|
||||
}
|
||||
|
||||
private Resources getResources(ExtensionContext extensionContext) {
|
||||
Store store = extensionContext.getStore(Namespace.create(ResourcesExtension.class));
|
||||
Resources resources = store.get(RESOURCES_KEY, Resources.class);
|
||||
return resources;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.testsupport.classpath.resources;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.nio.file.Path;
|
||||
|
||||
/**
|
||||
* Annotation that indicates that the resources root should be injected. Supported on
|
||||
* parameters of type:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link File}</li>
|
||||
* <li>{@link Path}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.PARAMETER)
|
||||
public @interface ResourcesRoot {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.testsupport.classpath.resources;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
/**
|
||||
* Makes resources in the package of the annotated class available from the root of the
|
||||
* classpath.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@Inherited
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@ExtendWith(ResourcesExtension.class)
|
||||
public @interface WithPackageResources {
|
||||
|
||||
/**
|
||||
* The resources to make available from the root.
|
||||
* @return the resources
|
||||
*/
|
||||
String[] value();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.testsupport.classpath.resources;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
/**
|
||||
* Makes a resource directory available from the thread context class loader.
|
||||
* <p>
|
||||
* For cases where one resource needs to refer to another, the resource's content may
|
||||
* contain the placeholder <code>${resourceRoot}</code>. It will be replaced with the path
|
||||
* to the root of the resources. For example, a resource with the {@link #name}
|
||||
* {@code example.txt} can be referenced using <code>${resourceRoot}/example.txt</code>.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@Inherited
|
||||
@Repeatable(WithResources.class)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@ExtendWith(ResourcesExtension.class)
|
||||
public @interface WithResource {
|
||||
|
||||
/**
|
||||
* The name of the resource.
|
||||
* @return the name
|
||||
*/
|
||||
String name();
|
||||
|
||||
/**
|
||||
* The content of the resource. When omitted an empty resource will be created.
|
||||
* @return the content
|
||||
*/
|
||||
String content() default "";
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.testsupport.classpath.resources;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Container annotation for {@link WithResourceDirectory}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@Inherited
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
public @interface WithResourceDirectories {
|
||||
|
||||
WithResourceDirectory[] value();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.testsupport.classpath.resources;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
/**
|
||||
* Makes a resource available from the thread context class loader. Typically used when a
|
||||
* test requires an empty directory to exist.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@Inherited
|
||||
@Repeatable(WithResourceDirectories.class)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@ExtendWith(ResourcesExtension.class)
|
||||
public @interface WithResourceDirectory {
|
||||
|
||||
/**
|
||||
* The name of the directory.
|
||||
* @return the name
|
||||
*/
|
||||
String value();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.testsupport.classpath.resources;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Container annotation for {@link WithResource}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@Inherited
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
public @interface WithResources {
|
||||
|
||||
WithResource[] value();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Custom JUnit extension for testing with resources.
|
||||
*/
|
||||
package org.springframework.boot.testsupport.classpath.resources;
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.testsupport.classpath.resources;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link WithPackageResources} on a class.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@WithPackageResources({ "resource-1.txt", "resource-2.txt", "sub/resource-3.txt" })
|
||||
class OnClassWithPackageResourcesTests {
|
||||
|
||||
@Test
|
||||
void whenWithPackageResourcesIsUsedOnAClassThenResourcesAreAvailable() throws IOException {
|
||||
assertThat(new ClassPathResource("resource-1.txt").getContentAsString(StandardCharsets.UTF_8)).isEqualTo("one");
|
||||
assertThat(new ClassPathResource("resource-2.txt").getContentAsString(StandardCharsets.UTF_8)).isEqualTo("two");
|
||||
assertThat(new ClassPathResource("sub/resource-3.txt").getContentAsString(StandardCharsets.UTF_8))
|
||||
.isEqualTo("three");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.testsupport.classpath.resources;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link WithResource} when used on a class.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@WithResource(name = "on-class", content = "class content")
|
||||
class OnClassWithResourceTests {
|
||||
|
||||
@Test
|
||||
void whenWithResourceIsUsedOnAClassThenResourceIsAvailable() throws IOException {
|
||||
assertThat(new ClassPathResource("on-class").getContentAsString(StandardCharsets.UTF_8))
|
||||
.isEqualTo("class content");
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithResource(name = "method-resource", content = "method")
|
||||
void whenWithResourceIsUsedOnClassAndMethodThenBothResourcesAreAvailable() throws IOException {
|
||||
assertThat(new ClassPathResource("on-class").getContentAsString(StandardCharsets.UTF_8))
|
||||
.isEqualTo("class content");
|
||||
assertThat(new ClassPathResource("method-resource").getContentAsString(StandardCharsets.UTF_8))
|
||||
.isEqualTo("method");
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithResource(name = "method-resource-1", content = "method-1")
|
||||
@WithResource(name = "method-resource-2", content = "method-2")
|
||||
void whenWithResourceIsUsedOnClassAndRepeatedOnMethodThenAllResourcesAreAvailable() throws IOException {
|
||||
assertThat(new ClassPathResource("on-class").getContentAsString(StandardCharsets.UTF_8))
|
||||
.isEqualTo("class content");
|
||||
assertThat(new ClassPathResource("method-resource-1").getContentAsString(StandardCharsets.UTF_8))
|
||||
.isEqualTo("method-1");
|
||||
assertThat(new ClassPathResource("method-resource-2").getContentAsString(StandardCharsets.UTF_8))
|
||||
.isEqualTo("method-2");
|
||||
}
|
||||
|
||||
@Nested
|
||||
class NestedTests {
|
||||
|
||||
@Test
|
||||
void whenWithResourceIsUsedOnEnclosingClassThenResourceIsAvailable() throws IOException {
|
||||
assertThat(new ClassPathResource("on-class").getContentAsString(StandardCharsets.UTF_8))
|
||||
.isEqualTo("class content");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Nested
|
||||
@WithResource(name = "on-nested-class", content = "nested class content")
|
||||
class WithResourceNestedTests {
|
||||
|
||||
@Test
|
||||
void whenWithResourceIsUsedOnEnclosingClassAndClassThenBothResourcesAreAvailable() throws IOException {
|
||||
assertThat(new ClassPathResource("on-class").getContentAsString(StandardCharsets.UTF_8))
|
||||
.isEqualTo("class content");
|
||||
assertThat(new ClassPathResource("on-nested-class").getContentAsString(StandardCharsets.UTF_8))
|
||||
.isEqualTo("nested class content");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.testsupport.classpath.resources;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link WithPackageResources} when used on a super-class.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class OnSuperClassWithPackageResourcesTests extends WithPackageResourcesClass {
|
||||
|
||||
@Test
|
||||
void whenWithPackageResourcesIsUsedOnASuperClassThenResourcesAreAvailable() throws IOException {
|
||||
assertThat(new ClassPathResource("resource-1.txt").getContentAsString(StandardCharsets.UTF_8)).isEqualTo("one");
|
||||
assertThat(new ClassPathResource("resource-2.txt").getContentAsString(StandardCharsets.UTF_8)).isEqualTo("two");
|
||||
assertThat(new ClassPathResource("sub/resource-3.txt").getContentAsString(StandardCharsets.UTF_8))
|
||||
.isEqualTo("three");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.testsupport.classpath.resources;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link WithResource} when used on a super-class.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class OnSuperClassWithResourceTests extends WithResourceClass {
|
||||
|
||||
@Test
|
||||
void whenWithResourceIsUsedOnASuperClassThenResourceIsAvailable() throws IOException {
|
||||
assertThat(new ClassPathResource("on-super-class").getContentAsString(StandardCharsets.UTF_8))
|
||||
.isEqualTo("super-class content");
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithResource(name = "method-resource", content = "method")
|
||||
void whenWithResourceIsUsedOnASuperClassAndMethodThenBothResourcesAreAvailable() throws IOException {
|
||||
assertThat(new ClassPathResource("on-super-class").getContentAsString(StandardCharsets.UTF_8))
|
||||
.isEqualTo("super-class content");
|
||||
assertThat(new ClassPathResource("method-resource").getContentAsString(StandardCharsets.UTF_8))
|
||||
.isEqualTo("method");
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithResource(name = "method-resource-1", content = "method-1")
|
||||
@WithResource(name = "method-resource-2", content = "method-2")
|
||||
void whenWithResourceIsUsedOnASuperClassAndRepeatedOnMethodThenAllResourcesAreAvailable() throws IOException {
|
||||
assertThat(new ClassPathResource("on-super-class").getContentAsString(StandardCharsets.UTF_8))
|
||||
.isEqualTo("super-class content");
|
||||
assertThat(new ClassPathResource("method-resource-1").getContentAsString(StandardCharsets.UTF_8))
|
||||
.isEqualTo("method-1");
|
||||
assertThat(new ClassPathResource("method-resource-2").getContentAsString(StandardCharsets.UTF_8))
|
||||
.isEqualTo("method-2");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.testsupport.classpath.resources;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
|
||||
/**
|
||||
* Tests for {@link Resources}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class ResourcesTests {
|
||||
|
||||
@TempDir
|
||||
private Path root;
|
||||
|
||||
@Test
|
||||
void whenAddResourceThenResourceIsCreated() {
|
||||
new Resources(this.root).addResource("test", "test-content");
|
||||
assertThat(this.root.resolve("test")).hasContent("test-content");
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenAddResourceHasContentReferencingResourceRootThenResourceIsCreatedWithReferenceToRoot() {
|
||||
new Resources(this.root).addResource("test", "*** ${resourceRoot} ***");
|
||||
assertThat(this.root.resolve("test")).hasContent("*** " + this.root + " ***");
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenAddResourceWithPathThenResourceIsCreated() {
|
||||
new Resources(this.root).addResource("a/b/c/test", "test-content");
|
||||
assertThat(this.root.resolve("a/b/c/test")).hasContent("test-content");
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenAddResourceAndResourceAlreadyExistsThenResourcesIsOverwritten() {
|
||||
Resources resources = new Resources(this.root);
|
||||
resources.addResource("a/b/c/test", "original-content");
|
||||
resources.addResource("a/b/c/test", "new-content");
|
||||
assertThat(this.root.resolve("a/b/c/test")).hasContent("new-content");
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenAddPackageThenNamedResourcesFromPackageAreCreated() {
|
||||
new Resources(this.root).addPackage(getClass().getPackage(),
|
||||
new String[] { "resource-1.txt", "sub/resource-3.txt" });
|
||||
assertThat(this.root.resolve("resource-1.txt")).hasContent("one");
|
||||
assertThat(this.root.resolve("resource-2.txt")).doesNotExist();
|
||||
assertThat(this.root.resolve("sub/resource-3.txt")).hasContent("three");
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenAddResourceAndDeleteThenResourceDoesNotExist() {
|
||||
Resources resources = new Resources(this.root);
|
||||
resources.addResource("test", "test-content");
|
||||
assertThat(this.root.resolve("test")).hasContent("test-content");
|
||||
resources.delete();
|
||||
assertThat(this.root.resolve("test")).doesNotExist();
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenAddPackageAndDeleteThenResourcesDoNotExist() {
|
||||
Resources resources = new Resources(this.root);
|
||||
resources.addPackage(getClass().getPackage(),
|
||||
new String[] { "resource-1.txt", "resource-2.txt", "sub/resource-3.txt" });
|
||||
assertThat(this.root.resolve("resource-1.txt")).hasContent("one");
|
||||
assertThat(this.root.resolve("resource-2.txt")).hasContent("two");
|
||||
assertThat(this.root.resolve("sub/resource-3.txt")).hasContent("three");
|
||||
resources.delete();
|
||||
assertThat(this.root.resolve("resource-1.txt")).doesNotExist();
|
||||
assertThat(this.root.resolve("resource-2.txt")).doesNotExist();
|
||||
assertThat(this.root.resolve("sub/resource-3.txt")).doesNotExist();
|
||||
assertThat(this.root.resolve("sub")).doesNotExist();
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenAddDirectoryThenDirectoryIsCreated() {
|
||||
Resources resources = new Resources(this.root);
|
||||
resources.addDirectory("dir");
|
||||
assertThat(this.root.resolve("dir")).isDirectory();
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenAddDirectoryWithPathThenDirectoryIsCreated() {
|
||||
Resources resources = new Resources(this.root);
|
||||
resources.addDirectory("one/two/three/dir");
|
||||
assertThat(this.root.resolve("one/two/three/dir")).isDirectory();
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenAddDirectoryAndDirectoryAlreadyExistsThenDoesNotThrow() {
|
||||
Resources resources = new Resources(this.root);
|
||||
resources.addDirectory("one/two/three/dir");
|
||||
resources.addDirectory("one/two/three/dir");
|
||||
assertThat(this.root.resolve("one/two/three/dir")).isDirectory();
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenAddDirectoryAndResourceAlreadyExistsThenIllegalStateExceptionIsThrown() {
|
||||
Resources resources = new Resources(this.root);
|
||||
resources.addResource("one/two/three/", "content");
|
||||
assertThatIllegalStateException().isThrownBy(() -> resources.addDirectory("one/two/three"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenAddResourceAndDirectoryAlreadyExistsThenIllegalStateExceptionIsThrown() {
|
||||
Resources resources = new Resources(this.root);
|
||||
resources.addDirectory("one/two/three");
|
||||
assertThatIllegalStateException().isThrownBy(() -> resources.addResource("one/two/three", "content"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.testsupport.classpath.resources;
|
||||
|
||||
/**
|
||||
* Class to test the use of {@link WithPackageResources} on a super-class.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@WithPackageResources({ "resource-1.txt", "resource-2.txt", "sub/resource-3.txt" })
|
||||
class WithPackageResourcesClass {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.testsupport.classpath.resources;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link WithPackageResources}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class WithPackageResourcesTests {
|
||||
|
||||
@Test
|
||||
@WithPackageResources({ "resource-1.txt", "resource-2.txt", "sub/resource-3.txt" })
|
||||
void whenWithPackageResourcesIsUsedOnAMethodThenResourcesAreAvailable() throws IOException {
|
||||
assertThat(new ClassPathResource("resource-1.txt").getContentAsString(StandardCharsets.UTF_8)).isEqualTo("one");
|
||||
assertThat(new ClassPathResource("resource-2.txt").getContentAsString(StandardCharsets.UTF_8)).isEqualTo("two");
|
||||
assertThat(new ClassPathResource("sub/resource-3.txt").getContentAsString(StandardCharsets.UTF_8))
|
||||
.isEqualTo("three");
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithPackageResources("sub/resource-3.txt")
|
||||
void whenWithPackageResourcesOnlyIncludesSomeResourcesThenOnlyIncludedResourcesAreAvailable() throws IOException {
|
||||
assertThat(new ClassPathResource("resource-1.txt").exists()).isFalse();
|
||||
assertThat(new ClassPathResource("resource-2.txt").exists()).isFalse();
|
||||
assertThat(new ClassPathResource("sub/resource-3.txt").getContentAsString(StandardCharsets.UTF_8))
|
||||
.isEqualTo("three");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.testsupport.classpath.resources;
|
||||
|
||||
/**
|
||||
* Class to test the use of {@link WithResource} on a super-class
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@WithResource(name = "on-super-class", content = "super-class content")
|
||||
class WithResourceClass {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.testsupport.classpath.resources;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link WithResourceDirectory}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class WithResourceDirectoryTests {
|
||||
|
||||
@Test
|
||||
@WithResourceDirectory("test")
|
||||
void whenWithResourceDirectoryIsUsedOnAMethodThenDirectoryIsCreated() throws IOException {
|
||||
assertThat(new ClassPathResource("test").getFile()).isDirectory();
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithResourceDirectory("com/example/nested")
|
||||
void whenWithResourceDirectoryNamesANestedDirectoryThenDirectoryIsCreated() throws IOException {
|
||||
assertThat(new ClassPathResource("com/example/nested").getFile()).isDirectory();
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithResourceDirectory("1")
|
||||
@WithResourceDirectory("2")
|
||||
@WithResourceDirectory("3")
|
||||
void whenWithResourceDirectoryIsRepeatedOnAMethodThenAllResourceDirectoriesAreCreated() throws IOException {
|
||||
assertThat(new ClassPathResource("1").getFile()).isDirectory();
|
||||
assertThat(new ClassPathResource("2").getFile()).isDirectory();
|
||||
assertThat(new ClassPathResource("3").getFile()).isDirectory();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.testsupport.classpath.resources;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link WithResource}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class WithResourceTests {
|
||||
|
||||
@Test
|
||||
@WithResource(name = "test", content = "content")
|
||||
void whenWithResourceIsUsedOnAMethodThenResourceIsAvailable() throws IOException {
|
||||
assertThat(new ClassPathResource("test").getContentAsString(StandardCharsets.UTF_8)).isEqualTo("content");
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithResource(name = "test", content = "content")
|
||||
void whenWithResourceIsUsedOnAMethodThenResourceIsAvailableFromFileResourcesRoot(@ResourcesRoot File root) {
|
||||
assertThat(new File(root, "test")).hasContent("content");
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithResource(name = "test", content = "content")
|
||||
void whenWithResourceIsUsedOnAMethodThenResourceIsAvailableFromPathResourcesRoot(@ResourcesRoot Path root) {
|
||||
assertThat(root.resolve("test")).hasContent("content");
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithResource(name = "test", content = "content")
|
||||
void whenWithResourceIsUsedOnAMethodThenResourceIsAvailableFromPathResourcePath(
|
||||
@ResourcePath("test") Path resource) {
|
||||
assertThat(resource).hasContent("content");
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithResource(name = "test", content = "content")
|
||||
void whenWithResourceIsUsedOnAMethodThenResourceIsAvailableFromFileResourcePath(
|
||||
@ResourcePath("test") File resource) {
|
||||
assertThat(resource).hasContent("content");
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithResource(name = "test", content = "content")
|
||||
void whenWithResourceIsUsedOnAMethodThenResourceIsAvailableFromStringResourcePath(
|
||||
@ResourcePath("test") String resource) {
|
||||
assertThat(new File(resource)).hasContent("content");
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithResource(name = "test", content = "content")
|
||||
void whenWithResourceIsUsedOnAMethodThenResourceContentIsAvailableAsAString(
|
||||
@ResourceContent("test") String content) {
|
||||
assertThat(content).isEqualTo("content");
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithResource(name = "com/example/test-resource", content = "content")
|
||||
void whenWithResourceNameIncludesADirectoryThenResourceIsAvailable() throws IOException {
|
||||
assertThat(new ClassPathResource("com/example/test-resource").getContentAsString(StandardCharsets.UTF_8))
|
||||
.isEqualTo("content");
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithResource(name = "1", content = "one")
|
||||
@WithResource(name = "2", content = "two")
|
||||
@WithResource(name = "3", content = "three")
|
||||
void whenWithResourceIsRepeatedOnAMethodThenAllResourcesAreAvailable() throws IOException {
|
||||
assertThat(new ClassPathResource("1").getContentAsString(StandardCharsets.UTF_8)).isEqualTo("one");
|
||||
assertThat(new ClassPathResource("2").getContentAsString(StandardCharsets.UTF_8)).isEqualTo("two");
|
||||
assertThat(new ClassPathResource("3").getContentAsString(StandardCharsets.UTF_8)).isEqualTo("three");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
one
|
||||
|
|
@ -0,0 +1 @@
|
|||
two
|
||||
Loading…
Reference in New Issue