Tidy up tests in spring-boot-autoconfigure-all

This commit is contained in:
Andy Wilkinson
2025-05-08 10:36:48 +01:00
committed by Phillip Webb
parent 6e04fc0910
commit 5b4791fdc6
17 changed files with 56 additions and 63 deletions

View File

@@ -0,0 +1,151 @@
/*
* 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.autoconfigure.admin;
import java.lang.management.ManagementFactory;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.admin.SpringApplicationAdminMXBeanRegistrar;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jmx.export.MBeanExporter;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.fail;
/**
* Tests for {@link SpringApplicationAdminJmxAutoConfiguration}.
*
* @author Stephane Nicoll
* @author Andy Wilkinson
* @author Nguyen Bao Sach
*/
class SpringApplicationAdminJmxAutoConfigurationTests {
private static final String ENABLE_ADMIN_PROP = "spring.application.admin.enabled=true";
private static final String DEFAULT_JMX_NAME = "org.springframework.boot:type=Admin,name=SpringApplication";
private final MBeanServer server = ManagementFactory.getPlatformMBeanServer();
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(SpringApplicationAdminJmxAutoConfiguration.class));
@Test
void notRegisteredWhenThereAreNoMBeanExporter() {
this.contextRunner.withPropertyValues(ENABLE_ADMIN_PROP).run((context) -> {
ObjectName objectName = createDefaultObjectName();
ObjectInstance objectInstance = this.server.getObjectInstance(objectName);
assertThat(objectInstance).as("Lifecycle bean should have been registered").isNotNull();
});
}
@Test
void notRegisteredByDefaultWhenThereAreMultipleMBeanExporters() {
this.contextRunner.withUserConfiguration(MultipleMBeanExportersConfiguration.class)
.run((context) -> assertThatExceptionOfType(InstanceNotFoundException.class)
.isThrownBy(() -> this.server.getObjectInstance(createDefaultObjectName())));
}
@Test
void registeredWithPropertyWhenThereAreMultipleMBeanExporters() {
this.contextRunner.withUserConfiguration(MultipleMBeanExportersConfiguration.class)
.withPropertyValues(ENABLE_ADMIN_PROP)
.run((context) -> {
ObjectName objectName = createDefaultObjectName();
ObjectInstance objectInstance = this.server.getObjectInstance(objectName);
assertThat(objectInstance).as("Lifecycle bean should have been registered").isNotNull();
});
}
@Test
void registerWithCustomJmxNameWhenThereAreMultipleMBeanExporters() {
String customJmxName = "org.acme:name=FooBar";
this.contextRunner.withUserConfiguration(MultipleMBeanExportersConfiguration.class)
.withSystemProperties("spring.application.admin.jmx-name=" + customJmxName)
.withPropertyValues(ENABLE_ADMIN_PROP)
.run((context) -> {
try {
this.server.getObjectInstance(createObjectName(customJmxName));
}
catch (InstanceNotFoundException ex) {
fail("Admin MBean should have been exposed with custom name");
}
assertThatExceptionOfType(InstanceNotFoundException.class)
.isThrownBy(() -> this.server.getObjectInstance(createDefaultObjectName()));
});
}
@Test
void onlyRegisteredOnceWhenThereIsAChildContext() {
SpringApplicationBuilder parentBuilder = new SpringApplicationBuilder().web(WebApplicationType.NONE)
.sources(MultipleMBeanExportersConfiguration.class, SpringApplicationAdminJmxAutoConfiguration.class);
SpringApplicationBuilder childBuilder = parentBuilder
.child(MultipleMBeanExportersConfiguration.class, SpringApplicationAdminJmxAutoConfiguration.class)
.web(WebApplicationType.NONE);
try (ConfigurableApplicationContext parent = parentBuilder.run("--" + ENABLE_ADMIN_PROP);
ConfigurableApplicationContext child = childBuilder.run("--" + ENABLE_ADMIN_PROP)) {
BeanFactoryUtils.beanOfType(parent.getBeanFactory(), SpringApplicationAdminMXBeanRegistrar.class);
assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> BeanFactoryUtils
.beanOfType(child.getBeanFactory(), SpringApplicationAdminMXBeanRegistrar.class));
}
}
private ObjectName createDefaultObjectName() {
return createObjectName(DEFAULT_JMX_NAME);
}
private ObjectName createObjectName(String jmxName) {
try {
return new ObjectName(jmxName);
}
catch (MalformedObjectNameException ex) {
throw new IllegalStateException("Invalid jmx name " + jmxName, ex);
}
}
@Configuration(proxyBeanMethods = false)
static class MultipleMBeanExportersConfiguration {
@Bean
MBeanExporter firstMBeanExporter() {
return new MBeanExporter();
}
@Bean
MBeanExporter secondMBeanExporter() {
return new MBeanExporter();
}
}
}

View File

@@ -0,0 +1,199 @@
/*
* 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.autoconfigure.condition;
import java.io.IOException;
import java.util.function.Consumer;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link ConditionalOnMissingFilterBean @ConditionalOnMissingFilterBean}.
*
* @author Phillip Webb
*/
class ConditionalOnMissingFilterBeanTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner();
@Test
void outcomeWhenValueIsOfMissingBeanReturnsMatch() {
this.contextRunner.withUserConfiguration(WithoutTestFilterConfig.class, OnMissingWithValueConfig.class)
.run((context) -> assertThat(context).satisfies(filterBeanRequirement("myOtherFilter", "testFilter")));
}
@Test
void outcomeWhenValueIsOfExistingBeanReturnsNoMatch() {
this.contextRunner.withUserConfiguration(WithTestFilterConfig.class, OnMissingWithValueConfig.class)
.run((context) -> assertThat(context).satisfies(filterBeanRequirement("myTestFilter")));
}
@Test
void outcomeWhenValueIsOfMissingBeanRegistrationReturnsMatch() {
this.contextRunner
.withUserConfiguration(WithoutTestFilterRegistrationConfig.class, OnMissingWithValueConfig.class)
.run((context) -> assertThat(context).satisfies(filterBeanRequirement("myOtherFilter", "testFilter")));
}
@Test
void outcomeWhenValueIsOfExistingBeanRegistrationReturnsNoMatch() {
this.contextRunner.withUserConfiguration(WithTestFilterRegistrationConfig.class, OnMissingWithValueConfig.class)
.run((context) -> assertThat(context).satisfies(filterBeanRequirement("myTestFilter")));
}
@Test
void outcomeWhenReturnTypeIsOfExistingBeanReturnsNoMatch() {
this.contextRunner.withUserConfiguration(WithTestFilterConfig.class, OnMissingWithReturnTypeConfig.class)
.run((context) -> assertThat(context).satisfies(filterBeanRequirement("myTestFilter")));
}
@Test
void outcomeWhenReturnTypeIsOfExistingBeanRegistrationReturnsNoMatch() {
this.contextRunner
.withUserConfiguration(WithTestFilterRegistrationConfig.class, OnMissingWithReturnTypeConfig.class)
.run((context) -> assertThat(context).satisfies(filterBeanRequirement("myTestFilter")));
}
@Test
void outcomeWhenReturnRegistrationTypeIsOfExistingBeanReturnsNoMatch() {
this.contextRunner
.withUserConfiguration(WithTestFilterConfig.class, OnMissingWithReturnRegistrationTypeConfig.class)
.run((context) -> assertThat(context).satisfies(filterBeanRequirement("myTestFilter")));
}
@Test
void outcomeWhenReturnRegistrationTypeIsOfExistingBeanRegistrationReturnsNoMatch() {
this.contextRunner
.withUserConfiguration(WithTestFilterRegistrationConfig.class,
OnMissingWithReturnRegistrationTypeConfig.class)
.run((context) -> assertThat(context).satisfies(filterBeanRequirement("myTestFilter")));
}
private Consumer<ConfigurableApplicationContext> filterBeanRequirement(String... names) {
return (context) -> {
String[] filters = context.getBeanNamesForType(Filter.class);
String[] registrations = context.getBeanNamesForType(FilterRegistrationBean.class);
assertThat(StringUtils.concatenateStringArrays(filters, registrations)).containsOnly(names);
};
}
@Configuration(proxyBeanMethods = false)
static class WithTestFilterConfig {
@Bean
TestFilter myTestFilter() {
return new TestFilter();
}
}
@Configuration(proxyBeanMethods = false)
static class WithoutTestFilterConfig {
@Bean
OtherFilter myOtherFilter() {
return new OtherFilter();
}
}
@Configuration(proxyBeanMethods = false)
static class WithoutTestFilterRegistrationConfig {
@Bean
FilterRegistrationBean<OtherFilter> myOtherFilter() {
return new FilterRegistrationBean<>(new OtherFilter());
}
}
@Configuration(proxyBeanMethods = false)
static class WithTestFilterRegistrationConfig {
@Bean
FilterRegistrationBean<TestFilter> myTestFilter() {
return new FilterRegistrationBean<>(new TestFilter());
}
}
@Configuration(proxyBeanMethods = false)
static class OnMissingWithValueConfig {
@Bean
@ConditionalOnMissingFilterBean(TestFilter.class)
TestFilter testFilter() {
return new TestFilter();
}
}
@Configuration(proxyBeanMethods = false)
static class OnMissingWithReturnTypeConfig {
@Bean
@ConditionalOnMissingFilterBean
TestFilter testFilter() {
return new TestFilter();
}
}
@Configuration(proxyBeanMethods = false)
static class OnMissingWithReturnRegistrationTypeConfig {
@Bean
@ConditionalOnMissingFilterBean
FilterRegistrationBean<TestFilter> testFilter() {
return new FilterRegistrationBean<>(new TestFilter());
}
}
static class TestFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
}
}
static class OtherFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
}
}
}

View File

@@ -0,0 +1,82 @@
/*
* 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.autoconfigure.container;
import org.junit.jupiter.api.Test;
import org.springframework.core.AttributeAccessor;
import org.springframework.core.AttributeAccessorSupport;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link ContainerImageMetadata}.
*
* @author Phillip Webb
*/
class ContainerImageMetadataTests {
private ContainerImageMetadata metadata = new ContainerImageMetadata("test");
private AttributeAccessor attributes = new AttributeAccessorSupport() {
};
@Test
void addToWhenAttributesIsNullDoesNothing() {
this.metadata.addTo(null);
}
@Test
void addToAddsMetadata() {
this.metadata.addTo(this.attributes);
assertThat(this.attributes.getAttribute(ContainerImageMetadata.NAME)).isSameAs(this.metadata);
}
@Test
void isPresentWhenPresentReturnsTrue() {
this.metadata.addTo(this.attributes);
assertThat(ContainerImageMetadata.isPresent(this.attributes)).isTrue();
}
@Test
void isPresentWhenNotPresentReturnsFalse() {
assertThat(ContainerImageMetadata.isPresent(this.attributes)).isFalse();
}
@Test
void isPresentWhenNullAttributesReturnsFalse() {
assertThat(ContainerImageMetadata.isPresent(null)).isFalse();
}
@Test
void getFromWhenPresentReturnsMetadata() {
this.metadata.addTo(this.attributes);
assertThat(ContainerImageMetadata.getFrom(this.attributes)).isSameAs(this.metadata);
}
@Test
void getFromWhenNotPresentReturnsNull() {
assertThat(ContainerImageMetadata.getFrom(this.attributes)).isNull();
}
@Test
void getFromWhenNullAttributesReturnsNull() {
assertThat(ContainerImageMetadata.getFrom(null)).isNull();
}
}

View File

@@ -0,0 +1,220 @@
/*
* 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.autoconfigure.template;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Collection;
import java.util.Collections;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.mock.env.MockEnvironment;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
/**
* Tests for {@link TemplateAvailabilityProviders}.
*
* @author Phillip Webb
*/
@ExtendWith(MockitoExtension.class)
class TemplateAvailabilityProvidersTests {
private TemplateAvailabilityProviders providers;
@Mock
private TemplateAvailabilityProvider provider;
private final String view = "view";
private final ClassLoader classLoader = getClass().getClassLoader();
private final MockEnvironment environment = new MockEnvironment();
@Mock
private ResourceLoader resourceLoader;
@BeforeEach
void setup() {
this.providers = new TemplateAvailabilityProviders(Collections.singleton(this.provider));
}
@Test
void createWhenApplicationContextIsNullShouldThrowException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> new TemplateAvailabilityProviders((ApplicationContext) null))
.withMessageContaining("'classLoader' must not be null");
}
@Test
@SuppressWarnings("rawtypes")
@WithTestTemplateAvailabilityProvider
void createWhenUsingApplicationContextShouldLoadProviders() {
ApplicationContext applicationContext = mock(ApplicationContext.class);
given(applicationContext.getClassLoader()).willReturn(Thread.currentThread().getContextClassLoader());
TemplateAvailabilityProviders providers = new TemplateAvailabilityProviders(applicationContext);
assertThat(providers.getProviders()).extracting((provider) -> (Class) provider.getClass())
.containsExactly(TestTemplateAvailabilityProvider.class);
then(applicationContext).should().getClassLoader();
}
@Test
void createWhenClassLoaderIsNullShouldThrowException() {
assertThatIllegalArgumentException().isThrownBy(() -> new TemplateAvailabilityProviders((ClassLoader) null))
.withMessageContaining("'classLoader' must not be null");
}
@Test
@WithTestTemplateAvailabilityProvider
void createWhenUsingClassLoaderShouldLoadProviders() {
TemplateAvailabilityProviders providers = new TemplateAvailabilityProviders(
Thread.currentThread().getContextClassLoader());
assertThat(providers.getProviders()).isNotEmpty();
}
@Test
void createWhenProvidersIsNullShouldThrowException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> new TemplateAvailabilityProviders((Collection<TemplateAvailabilityProvider>) null))
.withMessageContaining("'providers' must not be null");
}
@Test
void createWhenUsingProvidersShouldUseProviders() {
TemplateAvailabilityProviders providers = new TemplateAvailabilityProviders(
Collections.singleton(this.provider));
assertThat(providers.getProviders()).containsOnly(this.provider);
}
@Test
void getProviderWhenApplicationContextIsNullShouldThrowException() {
assertThatIllegalArgumentException().isThrownBy(() -> this.providers.getProvider(this.view, null))
.withMessageContaining("'applicationContext' must not be null");
}
@Test
void getProviderWhenViewIsNullShouldThrowException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> this.providers.getProvider(null, this.environment, this.classLoader, this.resourceLoader))
.withMessageContaining("'view' must not be null");
}
@Test
void getProviderWhenEnvironmentIsNullShouldThrowException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> this.providers.getProvider(this.view, null, this.classLoader, this.resourceLoader))
.withMessageContaining("'environment' must not be null");
}
@Test
void getProviderWhenClassLoaderIsNullShouldThrowException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> this.providers.getProvider(this.view, this.environment, null, this.resourceLoader))
.withMessageContaining("'classLoader' must not be null");
}
@Test
void getProviderWhenResourceLoaderIsNullShouldThrowException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> this.providers.getProvider(this.view, this.environment, this.classLoader, null))
.withMessageContaining("'resourceLoader' must not be null");
}
@Test
void getProviderWhenNoneMatchShouldReturnNull() {
TemplateAvailabilityProvider found = this.providers.getProvider(this.view, this.environment, this.classLoader,
this.resourceLoader);
assertThat(found).isNull();
then(this.provider).should()
.isTemplateAvailable(this.view, this.environment, this.classLoader, this.resourceLoader);
}
@Test
void getProviderWhenMatchShouldReturnProvider() {
given(this.provider.isTemplateAvailable(this.view, this.environment, this.classLoader, this.resourceLoader))
.willReturn(true);
TemplateAvailabilityProvider found = this.providers.getProvider(this.view, this.environment, this.classLoader,
this.resourceLoader);
assertThat(found).isSameAs(this.provider);
}
@Test
void getProviderShouldCacheMatchResult() {
given(this.provider.isTemplateAvailable(this.view, this.environment, this.classLoader, this.resourceLoader))
.willReturn(true);
this.providers.getProvider(this.view, this.environment, this.classLoader, this.resourceLoader);
this.providers.getProvider(this.view, this.environment, this.classLoader, this.resourceLoader);
then(this.provider).should()
.isTemplateAvailable(this.view, this.environment, this.classLoader, this.resourceLoader);
}
@Test
void getProviderShouldCacheNoMatchResult() {
this.providers.getProvider(this.view, this.environment, this.classLoader, this.resourceLoader);
this.providers.getProvider(this.view, this.environment, this.classLoader, this.resourceLoader);
then(this.provider).should()
.isTemplateAvailable(this.view, this.environment, this.classLoader, this.resourceLoader);
}
@Test
void getProviderWhenCacheDisabledShouldNotUseCache() {
given(this.provider.isTemplateAvailable(this.view, this.environment, this.classLoader, this.resourceLoader))
.willReturn(true);
this.environment.setProperty("spring.template.provider.cache", "false");
this.providers.getProvider(this.view, this.environment, this.classLoader, this.resourceLoader);
this.providers.getProvider(this.view, this.environment, this.classLoader, this.resourceLoader);
then(this.provider).should(times(2))
.isTemplateAvailable(this.view, this.environment, this.classLoader, this.resourceLoader);
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@WithResource(name = "META-INF/spring.factories",
content = "org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider="
+ "org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvidersTests$TestTemplateAvailabilityProvider")
@interface WithTestTemplateAvailabilityProvider {
}
static class TestTemplateAvailabilityProvider implements TemplateAvailabilityProvider {
@Override
public boolean isTemplateAvailable(String view, Environment environment, ClassLoader classLoader,
ResourceLoader resourceLoader) {
return false;
}
}
}

View File

@@ -0,0 +1,69 @@
/*
* 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.autoconfigure.template;
import java.util.function.Predicate;
import org.junit.jupiter.api.Test;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
import org.springframework.beans.factory.aot.AotServices;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.core.io.ClassPathResource;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link TemplateRuntimeHints}.
*
* @author Stephane Nicoll
*/
class TemplateRuntimeHintsTests {
private static final Predicate<RuntimeHints> TEST_PREDICATE = RuntimeHintsPredicates.resource()
.forResource("templates/something/hello.html");
@Test
void templateRuntimeHintsIsRegistered() {
Iterable<RuntimeHintsRegistrar> registrar = AotServices.factories().load(RuntimeHintsRegistrar.class);
assertThat(registrar).anyMatch(TemplateRuntimeHints.class::isInstance);
}
@Test
@WithResource(name = "templates/test.html")
void contributeWhenTemplateLocationExists() {
RuntimeHints runtimeHints = contribute(Thread.currentThread().getContextClassLoader());
assertThat(TEST_PREDICATE.test(runtimeHints)).isTrue();
}
@Test
void contributeWhenTemplateLocationDoesNotExist() {
FilteredClassLoader classLoader = new FilteredClassLoader(new ClassPathResource("templates"));
RuntimeHints runtimeHints = contribute(classLoader);
assertThat(TEST_PREDICATE.test(runtimeHints)).isFalse();
}
private RuntimeHints contribute(ClassLoader classLoader) {
RuntimeHints runtimeHints = new RuntimeHints();
new TemplateRuntimeHints().registerHints(runtimeHints, classLoader);
return runtimeHints;
}
}

View File

@@ -0,0 +1,187 @@
/*
* 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.autoconfigure.web.format;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.OffsetTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Calendar;
import java.util.Date;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link WebConversionService}.
*
* @author Brian Clozel
* @author Madhura Bhave
* @author Gaurav Pareek
*/
class WebConversionServiceTests {
@Test
void defaultDateFormat() {
WebConversionService conversionService = new WebConversionService(new DateTimeFormatters());
LocalDate date = LocalDate.of(2020, 4, 26);
assertThat(conversionService.convert(date, String.class))
.isEqualTo(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).format(date));
}
@Test
void isoDateFormat() {
WebConversionService conversionService = new WebConversionService(new DateTimeFormatters().dateFormat("iso"));
LocalDate date = LocalDate.of(2020, 4, 26);
assertThat(conversionService.convert(date, String.class))
.isEqualTo(DateTimeFormatter.ISO_LOCAL_DATE.format(date));
}
@Test
void customDateFormatWithJavaUtilDate() {
customDateFormat(Date.from(ZonedDateTime.of(2018, 1, 1, 20, 30, 0, 0, ZoneId.systemDefault()).toInstant()));
}
@Test
void customDateFormatWithJavaTime() {
customDateFormat(java.time.LocalDate.of(2018, 1, 1));
}
@Test
void defaultTimeFormat() {
WebConversionService conversionService = new WebConversionService(new DateTimeFormatters());
LocalTime time = LocalTime.of(12, 45, 23);
assertThat(conversionService.convert(time, String.class))
.isEqualTo(DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT).format(time));
}
@Test
void isoTimeFormat() {
WebConversionService conversionService = new WebConversionService(new DateTimeFormatters().timeFormat("iso"));
LocalTime time = LocalTime.of(12, 45, 23);
assertThat(conversionService.convert(time, String.class))
.isEqualTo(DateTimeFormatter.ISO_LOCAL_TIME.format(time));
}
@Test
void isoOffsetTimeFormat() {
isoOffsetTimeFormat(new DateTimeFormatters().timeFormat("isooffset"));
}
@Test
void hyphenatedIsoOffsetTimeFormat() {
isoOffsetTimeFormat(new DateTimeFormatters().timeFormat("iso-offset"));
}
private void isoOffsetTimeFormat(DateTimeFormatters formatters) {
WebConversionService conversionService = new WebConversionService(formatters);
OffsetTime offsetTime = OffsetTime.of(LocalTime.of(12, 45, 23), ZoneOffset.ofHoursMinutes(1, 30));
assertThat(conversionService.convert(offsetTime, String.class))
.isEqualTo(DateTimeFormatter.ISO_OFFSET_TIME.format(offsetTime));
}
@Test
void customTimeFormat() {
WebConversionService conversionService = new WebConversionService(
new DateTimeFormatters().timeFormat("HH*mm*ss"));
LocalTime time = LocalTime.of(12, 45, 23);
assertThat(conversionService.convert(time, String.class)).isEqualTo("12*45*23");
}
@Test
void defaultDateTimeFormat() {
WebConversionService conversionService = new WebConversionService(new DateTimeFormatters());
LocalDateTime dateTime = LocalDateTime.of(2020, 4, 26, 12, 45, 23);
assertThat(conversionService.convert(dateTime, String.class))
.isEqualTo(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT).format(dateTime));
}
@Test
void isoDateTimeFormat() {
WebConversionService conversionService = new WebConversionService(
new DateTimeFormatters().dateTimeFormat("iso"));
LocalDateTime dateTime = LocalDateTime.of(2020, 4, 26, 12, 45, 23);
assertThat(conversionService.convert(dateTime, String.class))
.isEqualTo(DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(dateTime));
}
@Test
void isoOffsetDateTimeFormat() {
isoOffsetDateTimeFormat(new DateTimeFormatters().dateTimeFormat("isooffset"));
}
@Test
void hyphenatedIsoOffsetDateTimeFormat() {
isoOffsetDateTimeFormat(new DateTimeFormatters().dateTimeFormat("iso-offset"));
}
private void isoOffsetDateTimeFormat(DateTimeFormatters formatters) {
WebConversionService conversionService = new WebConversionService(formatters);
OffsetDateTime offsetDateTime = OffsetDateTime.of(LocalDate.of(2020, 4, 26), LocalTime.of(12, 45, 23),
ZoneOffset.ofHoursMinutes(1, 30));
assertThat(conversionService.convert(offsetDateTime, String.class))
.isEqualTo(DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(offsetDateTime));
}
@Test
void customDateTimeFormat() {
WebConversionService conversionService = new WebConversionService(
new DateTimeFormatters().dateTimeFormat("dd*MM*yyyy HH*mm*ss"));
LocalDateTime dateTime = LocalDateTime.of(2020, 4, 26, 12, 45, 23);
assertThat(conversionService.convert(dateTime, String.class)).isEqualTo("26*04*2020 12*45*23");
}
@Test
void convertFromStringToLocalDate() {
WebConversionService conversionService = new WebConversionService(
new DateTimeFormatters().dateFormat("yyyy-MM-dd"));
LocalDate date = conversionService.convert("2018-01-01", LocalDate.class);
assertThat(date).isEqualTo(java.time.LocalDate.of(2018, 1, 1));
}
@Test
void convertFromStringToLocalDateWithIsoFormatting() {
WebConversionService conversionService = new WebConversionService(new DateTimeFormatters().dateFormat("iso"));
LocalDate date = conversionService.convert("2018-01-01", LocalDate.class);
assertThat(date).isEqualTo(java.time.LocalDate.of(2018, 1, 1));
}
@Test
void convertFromStringToDateWithIsoFormatting() {
WebConversionService conversionService = new WebConversionService(new DateTimeFormatters().dateFormat("iso"));
Date date = conversionService.convert("2018-01-01", Date.class);
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
assertThat(calendar.get(Calendar.YEAR)).isEqualTo(2018);
assertThat(calendar.get(Calendar.MONTH)).isZero();
assertThat(calendar.get(Calendar.DAY_OF_MONTH)).isOne();
}
private void customDateFormat(Object input) {
WebConversionService conversionService = new WebConversionService(
new DateTimeFormatters().dateFormat("dd*MM*yyyy"));
assertThat(conversionService.convert(input, String.class)).isEqualTo("01*01*2018");
}
}