25 changed files with 1397 additions and 0 deletions
@ -0,0 +1,44 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -0,0 +1 @@
|
||||
one |
||||
Loading…
Reference in new issue