Merge branch '2.1.x'

pull/16278/head
Stephane Nicoll 6 years ago
commit 465053c11e

@ -22,7 +22,6 @@ import java.util.Locale;
import nz.net.ultraq.thymeleaf.LayoutDialect; import nz.net.ultraq.thymeleaf.LayoutDialect;
import nz.net.ultraq.thymeleaf.decorators.strategies.GroupingStrategy; import nz.net.ultraq.thymeleaf.decorators.strategies.GroupingStrategy;
import org.junit.After;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.thymeleaf.TemplateEngine; import org.thymeleaf.TemplateEngine;
@ -36,15 +35,12 @@ import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring5.view.reactive.ThymeleafReactiveViewResolver; import org.thymeleaf.spring5.view.reactive.ThymeleafReactiveViewResolver;
import org.thymeleaf.templateresolver.ITemplateResolver; import org.thymeleaf.templateresolver.ITemplateResolver;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
import org.springframework.boot.test.util.TestPropertyValues; import org.springframework.boot.test.rule.OutputCapture;
import org.springframework.boot.testsupport.BuildOutput; import org.springframework.boot.testsupport.BuildOutput;
import org.springframework.boot.testsupport.rule.OutputCapture;
import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.mock.http.server.reactive.MockServerHttpRequest; import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
import org.springframework.mock.web.server.MockServerWebExchange; import org.springframework.mock.web.server.MockServerWebExchange;
@ -59,166 +55,182 @@ import static org.assertj.core.api.Assertions.assertThat;
* *
* @author Brian Clozel * @author Brian Clozel
* @author Kazuki Shimizu * @author Kazuki Shimizu
* @author Stephane Nicoll
*/ */
public class ThymeleafReactiveAutoConfigurationTests { public class ThymeleafReactiveAutoConfigurationTests {
private final BuildOutput buildOutput = new BuildOutput(getClass());
@Rule @Rule
public final OutputCapture output = new OutputCapture(); public final OutputCapture output = new OutputCapture();
private AnnotationConfigReactiveWebApplicationContext context; private final BuildOutput buildOutput = new BuildOutput(getClass());
@After private ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()
public void close() { .withConfiguration(AutoConfigurations.of(ThymeleafAutoConfiguration.class));
if (this.context != null) {
this.context.close();
}
}
@Test @Test
public void createFromConfigClass() { public void createFromConfigClass() {
load(BaseConfiguration.class, "spring.thymeleaf.suffix:.html"); this.contextRunner.withPropertyValues("spring.thymeleaf.suffix:.html")
TemplateEngine engine = this.context.getBean(TemplateEngine.class); .run((context) -> {
Context attrs = new Context(Locale.UK, Collections.singletonMap("foo", "bar")); TemplateEngine engine = context.getBean(TemplateEngine.class);
Context attrs = new Context(Locale.UK,
Collections.singletonMap("foo", "bar"));
String result = engine.process("template", attrs); String result = engine.process("template", attrs);
assertThat(result).isEqualTo("<html>bar</html>"); assertThat(result).isEqualTo("<html>bar</html>");
});
} }
@Test @Test
public void overrideCharacterEncoding() { public void overrideCharacterEncoding() {
load(BaseConfiguration.class, "spring.thymeleaf.encoding:UTF-16"); this.contextRunner.withPropertyValues("spring.thymeleaf.encoding:UTF-16")
ITemplateResolver resolver = this.context.getBean(ITemplateResolver.class); .run((context) -> {
assertThat(resolver instanceof SpringResourceTemplateResolver).isTrue(); ITemplateResolver resolver = context.getBean(ITemplateResolver.class);
assertThat(((SpringResourceTemplateResolver) resolver).getCharacterEncoding()) assertThat(resolver)
.isEqualTo("UTF-16"); .isInstanceOf(SpringResourceTemplateResolver.class);
ThymeleafReactiveViewResolver views = this.context assertThat(((SpringResourceTemplateResolver) resolver)
.getCharacterEncoding()).isEqualTo("UTF-16");
ThymeleafReactiveViewResolver views = context
.getBean(ThymeleafReactiveViewResolver.class); .getBean(ThymeleafReactiveViewResolver.class);
assertThat(views.getDefaultCharset().name()).isEqualTo("UTF-16"); assertThat(views.getDefaultCharset().name()).isEqualTo("UTF-16");
});
} }
@Test @Test
public void overrideMediaTypes() { public void overrideMediaTypes() {
load(BaseConfiguration.class, this.contextRunner
"spring.thymeleaf.reactive.media-types:text/html,text/plain"); .withPropertyValues(
ThymeleafReactiveViewResolver views = this.context "spring.thymeleaf.reactive.media-types:text/html,text/plain")
.getBean(ThymeleafReactiveViewResolver.class); .run((context) -> assertThat(
assertThat(views.getSupportedMediaTypes()).contains(MediaType.TEXT_HTML, context.getBean(ThymeleafReactiveViewResolver.class)
MediaType.TEXT_PLAIN); .getSupportedMediaTypes()).contains(MediaType.TEXT_HTML,
MediaType.TEXT_PLAIN));
} }
@Test @Test
public void overrideTemplateResolverOrder() { public void overrideTemplateResolverOrder() {
load(BaseConfiguration.class, "spring.thymeleaf.templateResolverOrder:25"); this.contextRunner.withPropertyValues("spring.thymeleaf.templateResolverOrder:25")
ITemplateResolver resolver = this.context.getBean(ITemplateResolver.class); .run((context) -> assertThat(
assertThat(resolver.getOrder()).isEqualTo(Integer.valueOf(25)); context.getBean(ITemplateResolver.class).getOrder())
.isEqualTo(Integer.valueOf(25)));
} }
@Test @Test
public void overrideViewNames() { public void overrideViewNames() {
load(BaseConfiguration.class, "spring.thymeleaf.viewNames:foo,bar"); this.contextRunner.withPropertyValues("spring.thymeleaf.viewNames:foo,bar")
ThymeleafReactiveViewResolver views = this.context .run((context) -> assertThat(context
.getBean(ThymeleafReactiveViewResolver.class); .getBean(ThymeleafReactiveViewResolver.class).getViewNames())
assertThat(views.getViewNames()).isEqualTo(new String[] { "foo", "bar" }); .isEqualTo(new String[] { "foo", "bar" }));
} }
@Test @Test
public void overrideMaxChunkSize() { public void overrideMaxChunkSize() {
load(BaseConfiguration.class, "spring.thymeleaf.reactive.maxChunkSize:8KB"); this.contextRunner
ThymeleafReactiveViewResolver views = this.context .withPropertyValues("spring.thymeleaf.reactive.maxChunkSize:8KB")
.getBean(ThymeleafReactiveViewResolver.class); .run((context) -> assertThat(
assertThat(views.getResponseMaxChunkSizeBytes()).isEqualTo(Integer.valueOf(8192)); context.getBean(ThymeleafReactiveViewResolver.class)
.getResponseMaxChunkSizeBytes())
.isEqualTo(Integer.valueOf(8192)));
} }
@Test @Test
public void overrideFullModeViewNames() { public void overrideFullModeViewNames() {
load(BaseConfiguration.class, this.contextRunner
"spring.thymeleaf.reactive.fullModeViewNames:foo,bar"); .withPropertyValues("spring.thymeleaf.reactive.fullModeViewNames:foo,bar")
ThymeleafReactiveViewResolver views = this.context .run((context) -> assertThat(
.getBean(ThymeleafReactiveViewResolver.class); context.getBean(ThymeleafReactiveViewResolver.class)
assertThat(views.getFullModeViewNames()).isEqualTo(new String[] { "foo", "bar" }); .getFullModeViewNames())
.isEqualTo(new String[] { "foo", "bar" }));
} }
@Test @Test
public void overrideChunkedModeViewNames() { public void overrideChunkedModeViewNames() {
load(BaseConfiguration.class, this.contextRunner
"spring.thymeleaf.reactive.chunkedModeViewNames:foo,bar"); .withPropertyValues(
ThymeleafReactiveViewResolver views = this.context "spring.thymeleaf.reactive.chunkedModeViewNames:foo,bar")
.getBean(ThymeleafReactiveViewResolver.class); .run((context) -> assertThat(
assertThat(views.getChunkedModeViewNames()) context.getBean(ThymeleafReactiveViewResolver.class)
.isEqualTo(new String[] { "foo", "bar" }); .getChunkedModeViewNames())
.isEqualTo(new String[] { "foo", "bar" }));
} }
@Test @Test
public void overrideEnableSpringElCompiler() { public void overrideEnableSpringElCompiler() {
load(BaseConfiguration.class, "spring.thymeleaf.enable-spring-el-compiler:true"); this.contextRunner
assertThat(this.context.getBean(SpringWebFluxTemplateEngine.class) .withPropertyValues("spring.thymeleaf.enable-spring-el-compiler:true")
.getEnableSpringELCompiler()).isTrue(); .run((context) -> assertThat(
context.getBean(SpringWebFluxTemplateEngine.class)
.getEnableSpringELCompiler()).isTrue());
} }
@Test @Test
public void enableSpringElCompilerIsDisabledByDefault() { public void enableSpringElCompilerIsDisabledByDefault() {
load(BaseConfiguration.class); this.contextRunner.run(
assertThat(this.context.getBean(SpringWebFluxTemplateEngine.class) (context) -> assertThat(context.getBean(SpringWebFluxTemplateEngine.class)
.getEnableSpringELCompiler()).isFalse(); .getEnableSpringELCompiler()).isFalse());
} }
@Test @Test
public void overrideRenderHiddenMarkersBeforeCheckboxes() { public void overrideRenderHiddenMarkersBeforeCheckboxes() {
load(BaseConfiguration.class, this.contextRunner
"spring.thymeleaf.render-hidden-markers-before-checkboxes:true"); .withPropertyValues(
assertThat(this.context.getBean(SpringWebFluxTemplateEngine.class) "spring.thymeleaf.render-hidden-markers-before-checkboxes:true")
.getRenderHiddenMarkersBeforeCheckboxes()).isTrue(); .run((context) -> assertThat(
context.getBean(SpringWebFluxTemplateEngine.class)
.getRenderHiddenMarkersBeforeCheckboxes()).isTrue());
} }
@Test @Test
public void enableRenderHiddenMarkersBeforeCheckboxesIsDisabledByDefault() { public void enableRenderHiddenMarkersBeforeCheckboxesIsDisabledByDefault() {
load(BaseConfiguration.class); this.contextRunner.run(
assertThat(this.context.getBean(SpringWebFluxTemplateEngine.class) (context) -> assertThat(context.getBean(SpringWebFluxTemplateEngine.class)
.getRenderHiddenMarkersBeforeCheckboxes()).isFalse(); .getRenderHiddenMarkersBeforeCheckboxes()).isFalse());
} }
@Test @Test
public void templateLocationDoesNotExist() { public void templateLocationDoesNotExist() {
load(BaseConfiguration.class, this.contextRunner
"spring.thymeleaf.prefix:classpath:/no-such-directory/"); .withPropertyValues(
assertThat(this.output.toString()).contains("Cannot find template location"); "spring.thymeleaf.prefix:classpath:/no-such-directory/")
.run((context) -> assertThat(this.output.toString())
.contains("Cannot find template location"));
} }
@Test @Test
public void templateLocationEmpty() { public void templateLocationEmpty() {
new File(this.buildOutput.getTestResourcesLocation(), new File(this.buildOutput.getTestResourcesLocation(),
"empty-templates/empty-directory").mkdirs(); "empty-templates/empty-directory").mkdirs();
load(BaseConfiguration.class, this.contextRunner.withPropertyValues(
"spring.thymeleaf.prefix:classpath:/empty-templates/empty-directory/"); "spring.thymeleaf.prefix:classpath:/empty-templates/empty-directory/")
assertThat(this.output.toString()) .run((context) -> assertThat(this.output.toString())
.doesNotContain("Cannot find template location"); .doesNotContain("Cannot find template location"));
} }
@Test @Test
public void useDataDialect() { public void useDataDialect() {
load(BaseConfiguration.class); this.contextRunner.run((context) -> {
ISpringWebFluxTemplateEngine engine = this.context ISpringWebFluxTemplateEngine engine = context
.getBean(ISpringWebFluxTemplateEngine.class); .getBean(ISpringWebFluxTemplateEngine.class);
Context attrs = new Context(Locale.UK, Collections.singletonMap("foo", "bar")); Context attrs = new Context(Locale.UK,
Collections.singletonMap("foo", "bar"));
String result = engine.process("data-dialect", attrs); String result = engine.process("data-dialect", attrs);
assertThat(result).isEqualTo("<html><body data-foo=\"bar\"></body></html>"); assertThat(result).isEqualTo("<html><body data-foo=\"bar\"></body></html>");
});
} }
@Test @Test
public void useJava8TimeDialect() { public void useJava8TimeDialect() {
load(BaseConfiguration.class); this.contextRunner.run((context) -> {
ISpringWebFluxTemplateEngine engine = this.context ISpringWebFluxTemplateEngine engine = context
.getBean(ISpringWebFluxTemplateEngine.class); .getBean(ISpringWebFluxTemplateEngine.class);
Context attrs = new Context(Locale.UK); Context attrs = new Context(Locale.UK);
String result = engine.process("java8time-dialect", attrs); String result = engine.process("java8time-dialect", attrs);
assertThat(result).isEqualTo("<html><body>2015-11-24</body></html>"); assertThat(result).isEqualTo("<html><body>2015-11-24</body></html>");
});
} }
@Test @Test
public void useSecurityDialect() { public void useSecurityDialect() {
load(BaseConfiguration.class); this.contextRunner.run((context) -> {
ISpringWebFluxTemplateEngine engine = this.context ISpringWebFluxTemplateEngine engine = context
.getBean(ISpringWebFluxTemplateEngine.class); .getBean(ISpringWebFluxTemplateEngine.class);
MockServerWebExchange exchange = MockServerWebExchange MockServerWebExchange exchange = MockServerWebExchange
.from(MockServerHttpRequest.get("/test").build()); .from(MockServerHttpRequest.get("/test").build());
@ -228,47 +240,32 @@ public class ThymeleafReactiveAutoConfigurationTests {
new TestingAuthenticationToken("alice", "admin"))); new TestingAuthenticationToken("alice", "admin")));
IContext attrs = new SpringWebFluxContext(exchange); IContext attrs = new SpringWebFluxContext(exchange);
String result = engine.process("security-dialect", attrs); String result = engine.process("security-dialect", attrs);
assertThat(result).isEqualTo( assertThat(result).isEqualTo("<html><body><div>alice</div></body></html>"
"<html><body><div>alice</div></body></html>" + System.lineSeparator()); + System.lineSeparator());
});
} }
@Test @Test
public void renderTemplate() { public void renderTemplate() {
load(BaseConfiguration.class); this.contextRunner.run((context) -> {
ISpringWebFluxTemplateEngine engine = this.context ISpringWebFluxTemplateEngine engine = context
.getBean(ISpringWebFluxTemplateEngine.class); .getBean(ISpringWebFluxTemplateEngine.class);
Context attrs = new Context(Locale.UK, Collections.singletonMap("foo", "bar")); Context attrs = new Context(Locale.UK,
Collections.singletonMap("foo", "bar"));
String result = engine.process("home", attrs); String result = engine.process("home", attrs);
assertThat(result).isEqualTo("<html><body>bar</body></html>"); assertThat(result).isEqualTo("<html><body>bar</body></html>");
});
} }
@Test @Test
public void layoutDialectCanBeCustomized() { public void layoutDialectCanBeCustomized() {
load(LayoutDialectConfiguration.class); this.contextRunner.withUserConfiguration(LayoutDialectConfiguration.class)
LayoutDialect layoutDialect = this.context.getBean(LayoutDialect.class); .run((context) -> assertThat(ReflectionTestUtils.getField(
assertThat(ReflectionTestUtils.getField(layoutDialect, "sortingStrategy")) context.getBean(LayoutDialect.class), "sortingStrategy"))
.isInstanceOf(GroupingStrategy.class); .isInstanceOf(GroupingStrategy.class));
}
private void load(Class<?> config, String... envVariables) {
this.context = new AnnotationConfigReactiveWebApplicationContext();
TestPropertyValues.of(envVariables).applyTo(this.context);
if (config != null) {
this.context.register(config);
}
this.context.register(config);
this.context.refresh();
}
@Configuration(proxyBeanMethods = false)
@ImportAutoConfiguration({ ThymeleafAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
protected static class BaseConfiguration {
} }
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@Import(BaseConfiguration.class)
static class LayoutDialectConfiguration { static class LayoutDialectConfiguration {
@Bean @Bean

@ -26,7 +26,6 @@ import javax.servlet.DispatcherType;
import nz.net.ultraq.thymeleaf.LayoutDialect; import nz.net.ultraq.thymeleaf.LayoutDialect;
import nz.net.ultraq.thymeleaf.decorators.strategies.GroupingStrategy; import nz.net.ultraq.thymeleaf.decorators.strategies.GroupingStrategy;
import org.junit.After;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.thymeleaf.TemplateEngine; import org.thymeleaf.TemplateEngine;
@ -38,17 +37,16 @@ import org.thymeleaf.spring5.view.ThymeleafView;
import org.thymeleaf.spring5.view.ThymeleafViewResolver; import org.thymeleaf.spring5.view.ThymeleafViewResolver;
import org.thymeleaf.templateresolver.ITemplateResolver; import org.thymeleaf.templateresolver.ITemplateResolver;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.test.rule.OutputCapture; import org.springframework.boot.test.rule.OutputCapture;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.boot.testsupport.BuildOutput; import org.springframework.boot.testsupport.BuildOutput;
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.filter.OrderedCharacterEncodingFilter; import org.springframework.boot.web.servlet.filter.OrderedCharacterEncodingFilter;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockServletContext; import org.springframework.mock.web.MockServletContext;
@ -56,13 +54,13 @@ import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextImpl; import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.test.util.ReflectionTestUtils; import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.resource.ResourceUrlEncodingFilter; import org.springframework.web.servlet.resource.ResourceUrlEncodingFilter;
import org.springframework.web.servlet.support.RequestContext; import org.springframework.web.servlet.support.RequestContext;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not;
/** /**
* Tests for {@link ThymeleafAutoConfiguration} in Servlet-based applications. * Tests for {@link ThymeleafAutoConfiguration} in Servlet-based applications.
@ -76,157 +74,176 @@ import static org.hamcrest.Matchers.containsString;
*/ */
public class ThymeleafServletAutoConfigurationTests { public class ThymeleafServletAutoConfigurationTests {
private final BuildOutput buildOutput = new BuildOutput(getClass());
@Rule @Rule
public OutputCapture output = new OutputCapture(); public OutputCapture output = new OutputCapture();
private AnnotationConfigWebApplicationContext context; private final BuildOutput buildOutput = new BuildOutput(getClass());
@After private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
public void close() { .withConfiguration(AutoConfigurations.of(ThymeleafAutoConfiguration.class));
if (this.context != null) {
this.context.close(); @Test
} public void autoConfigurationBackOffWithoutThymeleafSpring() {
this.contextRunner
.withClassLoader(new FilteredClassLoader("org.thymeleaf.spring5"))
.run((context) -> assertThat(context)
.doesNotHaveBean(TemplateEngine.class));
} }
@Test @Test
public void createFromConfigClass() { public void createFromConfigClass() {
load(BaseConfiguration.class, "spring.thymeleaf.mode:HTML", this.contextRunner.withPropertyValues("spring.thymeleaf.mode:HTML",
"spring.thymeleaf.suffix:"); "spring.thymeleaf.suffix:").run((context) -> {
TemplateEngine engine = this.context.getBean(TemplateEngine.class); assertThat(context).hasSingleBean(TemplateEngine.class);
Context attrs = new Context(Locale.UK, Collections.singletonMap("foo", "bar")); TemplateEngine engine = context.getBean(TemplateEngine.class);
Context attrs = new Context(Locale.UK,
Collections.singletonMap("foo", "bar"));
String result = engine.process("template.html", attrs); String result = engine.process("template.html", attrs);
assertThat(result).isEqualTo("<html>bar</html>"); assertThat(result).isEqualTo("<html>bar</html>");
});
} }
@Test @Test
public void overrideCharacterEncoding() { public void overrideCharacterEncoding() {
load(BaseConfiguration.class, "spring.thymeleaf.encoding:UTF-16"); this.contextRunner.withPropertyValues("spring.thymeleaf.encoding:UTF-16")
ITemplateResolver resolver = this.context.getBean(ITemplateResolver.class); .run((context) -> {
assertThat(resolver instanceof SpringResourceTemplateResolver).isTrue(); ITemplateResolver resolver = context.getBean(ITemplateResolver.class);
assertThat(((SpringResourceTemplateResolver) resolver).getCharacterEncoding()) assertThat(resolver)
.isEqualTo("UTF-16"); .isInstanceOf(SpringResourceTemplateResolver.class);
ThymeleafViewResolver views = this.context.getBean(ThymeleafViewResolver.class); assertThat(((SpringResourceTemplateResolver) resolver)
.getCharacterEncoding()).isEqualTo("UTF-16");
ThymeleafViewResolver views = context
.getBean(ThymeleafViewResolver.class);
assertThat(views.getCharacterEncoding()).isEqualTo("UTF-16"); assertThat(views.getCharacterEncoding()).isEqualTo("UTF-16");
assertThat(views.getContentType()).isEqualTo("text/html;charset=UTF-16"); assertThat(views.getContentType())
.isEqualTo("text/html;charset=UTF-16");
});
} }
@Test @Test
public void overrideDisableProducePartialOutputWhileProcessing() { public void overrideDisableProducePartialOutputWhileProcessing() {
load(BaseConfiguration.class, this.contextRunner.withPropertyValues(
"spring.thymeleaf.servlet.produce-partial-output-while-processing:false"); "spring.thymeleaf.servlet.produce-partial-output-while-processing:false")
assertThat(this.context.getBean(ThymeleafViewResolver.class) .run((context) -> assertThat(context.getBean(ThymeleafViewResolver.class)
.getProducePartialOutputWhileProcessing()).isFalse(); .getProducePartialOutputWhileProcessing()).isFalse());
} }
@Test @Test
public void disableProducePartialOutputWhileProcessingIsEnabledByDefault() { public void disableProducePartialOutputWhileProcessingIsEnabledByDefault() {
load(BaseConfiguration.class); this.contextRunner
assertThat(this.context.getBean(ThymeleafViewResolver.class) .run((context) -> assertThat(context.getBean(ThymeleafViewResolver.class)
.getProducePartialOutputWhileProcessing()).isTrue(); .getProducePartialOutputWhileProcessing()).isTrue());
} }
@Test @Test
public void overrideTemplateResolverOrder() { public void overrideTemplateResolverOrder() {
load(BaseConfiguration.class, "spring.thymeleaf.templateResolverOrder:25"); this.contextRunner.withPropertyValues("spring.thymeleaf.templateResolverOrder:25")
ITemplateResolver resolver = this.context.getBean(ITemplateResolver.class); .run((context) -> assertThat(
assertThat(resolver.getOrder()).isEqualTo(Integer.valueOf(25)); context.getBean(ITemplateResolver.class).getOrder())
.isEqualTo(Integer.valueOf(25)));
} }
@Test @Test
public void overrideViewNames() { public void overrideViewNames() {
load(BaseConfiguration.class, "spring.thymeleaf.viewNames:foo,bar"); this.contextRunner.withPropertyValues("spring.thymeleaf.viewNames:foo,bar")
ThymeleafViewResolver views = this.context.getBean(ThymeleafViewResolver.class); .run((context) -> assertThat(
assertThat(views.getViewNames()).isEqualTo(new String[] { "foo", "bar" }); context.getBean(ThymeleafViewResolver.class).getViewNames())
.isEqualTo(new String[] { "foo", "bar" }));
} }
@Test @Test
public void overrideEnableSpringElCompiler() { public void overrideEnableSpringElCompiler() {
load(BaseConfiguration.class, "spring.thymeleaf.enable-spring-el-compiler:true"); this.contextRunner
assertThat(this.context.getBean(SpringTemplateEngine.class) .withPropertyValues("spring.thymeleaf.enable-spring-el-compiler:true")
.getEnableSpringELCompiler()).isTrue(); .run((context) -> assertThat(context.getBean(SpringTemplateEngine.class)
.getEnableSpringELCompiler()).isTrue());
} }
@Test @Test
public void enableSpringElCompilerIsDisabledByDefault() { public void enableSpringElCompilerIsDisabledByDefault() {
load(BaseConfiguration.class); this.contextRunner.run((context) -> assertThat(
assertThat(this.context.getBean(SpringTemplateEngine.class) context.getBean(SpringTemplateEngine.class).getEnableSpringELCompiler())
.getEnableSpringELCompiler()).isFalse(); .isFalse());
} }
@Test @Test
public void overrideRenderHiddenMarkersBeforeCheckboxes() { public void overrideRenderHiddenMarkersBeforeCheckboxes() {
load(BaseConfiguration.class, this.contextRunner
"spring.thymeleaf.render-hidden-markers-before-checkboxes:true"); .withPropertyValues(
assertThat(this.context.getBean(SpringTemplateEngine.class) "spring.thymeleaf.render-hidden-markers-before-checkboxes:true")
.getRenderHiddenMarkersBeforeCheckboxes()).isTrue(); .run((context) -> assertThat(context.getBean(SpringTemplateEngine.class)
.getRenderHiddenMarkersBeforeCheckboxes()).isTrue());
} }
@Test @Test
public void enableRenderHiddenMarkersBeforeCheckboxesIsDisabledByDefault() { public void enableRenderHiddenMarkersBeforeCheckboxesIsDisabledByDefault() {
load(BaseConfiguration.class); this.contextRunner
assertThat(this.context.getBean(SpringTemplateEngine.class) .run((context) -> assertThat(context.getBean(SpringTemplateEngine.class)
.getRenderHiddenMarkersBeforeCheckboxes()).isFalse(); .getRenderHiddenMarkersBeforeCheckboxes()).isFalse());
} }
@Test @Test
public void templateLocationDoesNotExist() { public void templateLocationDoesNotExist() {
load(BaseConfiguration.class, this.contextRunner
"spring.thymeleaf.prefix:classpath:/no-such-directory/"); .withPropertyValues(
this.output.expect(containsString("Cannot find template location")); "spring.thymeleaf.prefix:classpath:/no-such-directory/")
.run((context) -> this.output
.expect(containsString("Cannot find template location")));
} }
@Test @Test
public void templateLocationEmpty() { public void templateLocationEmpty() {
new File(this.buildOutput.getTestResourcesLocation(), new File(this.buildOutput.getTestResourcesLocation(),
"empty-templates/empty-directory").mkdirs(); "empty-templates/empty-directory").mkdirs();
load(BaseConfiguration.class, this.contextRunner.withPropertyValues(
"spring.thymeleaf.prefix:classpath:/empty-templates/empty-directory/"); "spring.thymeleaf.prefix:classpath:/empty-templates/empty-directory/")
.run((context) -> this.output
.expect(not(containsString("Cannot find template location"))));
} }
@Test @Test
public void createLayoutFromConfigClass() throws Exception { public void createLayoutFromConfigClass() {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); this.contextRunner.run((context) -> {
context.register(ThymeleafAutoConfiguration.class, ThymeleafView view = (ThymeleafView) context
PropertyPlaceholderAutoConfiguration.class); .getBean(ThymeleafViewResolver.class)
MockServletContext servletContext = new MockServletContext();
context.setServletContext(servletContext);
context.refresh();
ThymeleafView view = (ThymeleafView) context.getBean(ThymeleafViewResolver.class)
.resolveViewName("view", Locale.UK); .resolveViewName("view", Locale.UK);
MockHttpServletResponse response = new MockHttpServletResponse(); MockHttpServletResponse response = new MockHttpServletResponse();
MockHttpServletRequest request = new MockHttpServletRequest(); MockHttpServletRequest request = new MockHttpServletRequest();
request.setAttribute(RequestContext.WEB_APPLICATION_CONTEXT_ATTRIBUTE, context); request.setAttribute(RequestContext.WEB_APPLICATION_CONTEXT_ATTRIBUTE,
context);
view.render(Collections.singletonMap("foo", "bar"), request, response); view.render(Collections.singletonMap("foo", "bar"), request, response);
String result = response.getContentAsString(); String result = response.getContentAsString();
assertThat(result).contains("<title>Content</title>"); assertThat(result).contains("<title>Content</title>");
assertThat(result).contains("<span>bar</span>"); assertThat(result).contains("<span>bar</span>");
context.close(); context.close();
});
} }
@Test @Test
public void useDataDialect() { public void useDataDialect() {
load(BaseConfiguration.class); this.contextRunner.run((context) -> {
TemplateEngine engine = this.context.getBean(TemplateEngine.class); TemplateEngine engine = context.getBean(TemplateEngine.class);
Context attrs = new Context(Locale.UK, Collections.singletonMap("foo", "bar")); Context attrs = new Context(Locale.UK,
Collections.singletonMap("foo", "bar"));
String result = engine.process("data-dialect", attrs); String result = engine.process("data-dialect", attrs);
assertThat(result).isEqualTo("<html><body data-foo=\"bar\"></body></html>"); assertThat(result).isEqualTo("<html><body data-foo=\"bar\"></body></html>");
});
} }
@Test @Test
public void useJava8TimeDialect() { public void useJava8TimeDialect() {
load(BaseConfiguration.class); this.contextRunner.run((context) -> {
TemplateEngine engine = this.context.getBean(TemplateEngine.class); TemplateEngine engine = context.getBean(TemplateEngine.class);
Context attrs = new Context(Locale.UK); Context attrs = new Context(Locale.UK);
String result = engine.process("java8time-dialect", attrs); String result = engine.process("java8time-dialect", attrs);
assertThat(result).isEqualTo("<html><body>2015-11-24</body></html>"); assertThat(result).isEqualTo("<html><body>2015-11-24</body></html>");
});
} }
@Test @Test
public void useSecurityDialect() { public void useSecurityDialect() {
load(BaseConfiguration.class); this.contextRunner.run((context) -> {
TemplateEngine engine = this.context.getBean(TemplateEngine.class); TemplateEngine engine = context.getBean(TemplateEngine.class);
WebContext attrs = new WebContext(new MockHttpServletRequest(), WebContext attrs = new WebContext(new MockHttpServletRequest(),
new MockHttpServletResponse(), new MockServletContext()); new MockHttpServletResponse(), new MockServletContext());
try { try {
@ -239,114 +256,115 @@ public class ThymeleafServletAutoConfigurationTests {
finally { finally {
SecurityContextHolder.clearContext(); SecurityContextHolder.clearContext();
} }
});
} }
@Test @Test
public void renderTemplate() { public void renderTemplate() {
load(BaseConfiguration.class); this.contextRunner.run((context) -> {
TemplateEngine engine = this.context.getBean(TemplateEngine.class); TemplateEngine engine = context.getBean(TemplateEngine.class);
Context attrs = new Context(Locale.UK, Collections.singletonMap("foo", "bar")); Context attrs = new Context(Locale.UK,
Collections.singletonMap("foo", "bar"));
String result = engine.process("home", attrs); String result = engine.process("home", attrs);
assertThat(result).isEqualTo("<html><body>bar</body></html>"); assertThat(result).isEqualTo("<html><body>bar</body></html>");
});
} }
@Test @Test
public void renderNonWebAppTemplate() { public void renderNonWebAppTemplate() {
try (AnnotationConfigApplicationContext customContext = new AnnotationConfigApplicationContext( new ApplicationContextRunner()
ThymeleafAutoConfiguration.class, .withConfiguration(
PropertyPlaceholderAutoConfiguration.class)) { AutoConfigurations.of(ThymeleafAutoConfiguration.class))
assertThat(customContext.getBeanNamesForType(ViewResolver.class).length) .run((context) -> {
.isEqualTo(0); assertThat(context).doesNotHaveBean(ViewResolver.class);
TemplateEngine engine = customContext.getBean(TemplateEngine.class); TemplateEngine engine = context.getBean(TemplateEngine.class);
Context attrs = new Context(Locale.UK, Context attrs = new Context(Locale.UK,
Collections.singletonMap("greeting", "Hello World")); Collections.singletonMap("greeting", "Hello World"));
String result = engine.process("message", attrs); String result = engine.process("message", attrs);
assertThat(result).contains("Hello World"); assertThat(result).contains("Hello World");
} });
} }
@Test @Test
public void registerResourceHandlingFilterDisabledByDefault() { public void registerResourceHandlingFilterDisabledByDefault() {
load(BaseConfiguration.class); this.contextRunner.run((context) -> assertThat(context)
assertThat(this.context.getBeansOfType(FilterRegistrationBean.class)).isEmpty(); .doesNotHaveBean(FilterRegistrationBean.class));
} }
@Test @Test
public void registerResourceHandlingFilterOnlyIfResourceChainIsEnabled() { public void registerResourceHandlingFilterOnlyIfResourceChainIsEnabled() {
load(BaseConfiguration.class, "spring.resources.chain.enabled:true"); this.contextRunner.withPropertyValues("spring.resources.chain.enabled:true")
FilterRegistrationBean<?> registration = this.context .run((context) -> {
FilterRegistrationBean<?> registration = context
.getBean(FilterRegistrationBean.class); .getBean(FilterRegistrationBean.class);
assertThat(registration.getFilter()) assertThat(registration.getFilter())
.isInstanceOf(ResourceUrlEncodingFilter.class); .isInstanceOf(ResourceUrlEncodingFilter.class);
assertThat(registration).hasFieldOrPropertyWithValue("dispatcherTypes", assertThat(registration).hasFieldOrPropertyWithValue(
"dispatcherTypes",
EnumSet.of(DispatcherType.REQUEST, DispatcherType.ERROR)); EnumSet.of(DispatcherType.REQUEST, DispatcherType.ERROR));
});
} }
@Test @Test
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
public void registerResourceHandlingFilterWithOtherRegistrationBean() { public void registerResourceHandlingFilterWithOtherRegistrationBean() {
// gh-14897 // gh-14897
load(FilterRegistrationOtherConfiguration.class, this.contextRunner
"spring.resources.chain.enabled:true"); .withUserConfiguration(FilterRegistrationOtherConfiguration.class)
Map<String, FilterRegistrationBean> beans = this.context .withPropertyValues("spring.resources.chain.enabled:true")
.run((context) -> {
Map<String, FilterRegistrationBean> beans = context
.getBeansOfType(FilterRegistrationBean.class); .getBeansOfType(FilterRegistrationBean.class);
assertThat(beans).hasSize(2); assertThat(beans).hasSize(2);
FilterRegistrationBean registration = beans.values().stream() FilterRegistrationBean registration = beans.values().stream().filter(
.filter((r) -> r.getFilter() instanceof ResourceUrlEncodingFilter) (r) -> r.getFilter() instanceof ResourceUrlEncodingFilter)
.findFirst().get(); .findFirst().get();
assertThat(registration).hasFieldOrPropertyWithValue("dispatcherTypes", assertThat(registration).hasFieldOrPropertyWithValue(
"dispatcherTypes",
EnumSet.of(DispatcherType.REQUEST, DispatcherType.ERROR)); EnumSet.of(DispatcherType.REQUEST, DispatcherType.ERROR));
});
} }
@Test @Test
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
public void registerResourceHandlingFilterWithResourceRegistrationBean() { public void registerResourceHandlingFilterWithResourceRegistrationBean() {
// gh-14926 // gh-14926
load(FilterRegistrationResourceConfiguration.class, this.contextRunner
"spring.resources.chain.enabled:true"); .withUserConfiguration(FilterRegistrationResourceConfiguration.class)
Map<String, FilterRegistrationBean> beans = this.context .withPropertyValues("spring.resources.chain.enabled:true")
.run((context) -> {
Map<String, FilterRegistrationBean> beans = context
.getBeansOfType(FilterRegistrationBean.class); .getBeansOfType(FilterRegistrationBean.class);
assertThat(beans).hasSize(1); assertThat(beans).hasSize(1);
FilterRegistrationBean registration = beans.values().stream() FilterRegistrationBean registration = beans.values().stream().filter(
.filter((r) -> r.getFilter() instanceof ResourceUrlEncodingFilter) (r) -> r.getFilter() instanceof ResourceUrlEncodingFilter)
.findFirst().get(); .findFirst().get();
assertThat(registration).hasFieldOrPropertyWithValue("dispatcherTypes", assertThat(registration).hasFieldOrPropertyWithValue(
EnumSet.of(DispatcherType.INCLUDE)); "dispatcherTypes", EnumSet.of(DispatcherType.INCLUDE));
});
} }
@Test @Test
public void layoutDialectCanBeCustomized() { public void layoutDialectCanBeCustomized() {
load(LayoutDialectConfiguration.class); this.contextRunner.withUserConfiguration(LayoutDialectConfiguration.class)
LayoutDialect layoutDialect = this.context.getBean(LayoutDialect.class); .run((context) -> assertThat(ReflectionTestUtils.getField(
assertThat(ReflectionTestUtils.getField(layoutDialect, "sortingStrategy")) context.getBean(LayoutDialect.class), "sortingStrategy"))
.isInstanceOf(GroupingStrategy.class); .isInstanceOf(GroupingStrategy.class));
} }
@Test @Test
public void cachingCanBeDisabled() { public void cachingCanBeDisabled() {
load(BaseConfiguration.class, "spring.thymeleaf.cache:false"); this.contextRunner.withPropertyValues("spring.thymeleaf.cache:false")
assertThat(this.context.getBean(ThymeleafViewResolver.class).isCache()).isFalse(); .run((context) -> {
SpringResourceTemplateResolver templateResolver = this.context assertThat(context.getBean(ThymeleafViewResolver.class).isCache())
.isFalse();
SpringResourceTemplateResolver templateResolver = context
.getBean(SpringResourceTemplateResolver.class); .getBean(SpringResourceTemplateResolver.class);
assertThat(templateResolver.isCacheable()).isFalse(); assertThat(templateResolver.isCacheable()).isFalse();
} });
private void load(Class<?> config, String... envVariables) {
this.context = new AnnotationConfigWebApplicationContext();
TestPropertyValues.of(envVariables).applyTo(this.context);
this.context.register(config);
this.context.refresh();
}
@Configuration(proxyBeanMethods = false)
@ImportAutoConfiguration({ ThymeleafAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
static class BaseConfiguration {
} }
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@Import(BaseConfiguration.class)
static class LayoutDialectConfiguration { static class LayoutDialectConfiguration {
@Bean @Bean
@ -357,7 +375,6 @@ public class ThymeleafServletAutoConfigurationTests {
} }
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@Import(BaseConfiguration.class)
static class FilterRegistrationResourceConfiguration { static class FilterRegistrationResourceConfiguration {
@Bean @Bean
@ -371,7 +388,6 @@ public class ThymeleafServletAutoConfigurationTests {
} }
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@Import(BaseConfiguration.class)
static class FilterRegistrationOtherConfiguration { static class FilterRegistrationOtherConfiguration {
@Bean @Bean

Loading…
Cancel
Save