Merge branch '2.1.x'
This commit is contained in:
commit
465053c11e
|
@ -22,7 +22,6 @@ import java.util.Locale;
|
|||
|
||||
import nz.net.ultraq.thymeleaf.LayoutDialect;
|
||||
import nz.net.ultraq.thymeleaf.decorators.strategies.GroupingStrategy;
|
||||
import org.junit.After;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.thymeleaf.TemplateEngine;
|
||||
|
@ -36,15 +35,12 @@ import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
|
|||
import org.thymeleaf.spring5.view.reactive.ThymeleafReactiveViewResolver;
|
||||
import org.thymeleaf.templateresolver.ITemplateResolver;
|
||||
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.test.util.TestPropertyValues;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
|
||||
import org.springframework.boot.test.rule.OutputCapture;
|
||||
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.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
|
||||
import org.springframework.mock.web.server.MockServerWebExchange;
|
||||
|
@ -59,216 +55,217 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
*
|
||||
* @author Brian Clozel
|
||||
* @author Kazuki Shimizu
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class ThymeleafReactiveAutoConfigurationTests {
|
||||
|
||||
private final BuildOutput buildOutput = new BuildOutput(getClass());
|
||||
|
||||
@Rule
|
||||
public final OutputCapture output = new OutputCapture();
|
||||
|
||||
private AnnotationConfigReactiveWebApplicationContext context;
|
||||
private final BuildOutput buildOutput = new BuildOutput(getClass());
|
||||
|
||||
@After
|
||||
public void close() {
|
||||
if (this.context != null) {
|
||||
this.context.close();
|
||||
}
|
||||
}
|
||||
private ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(ThymeleafAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
public void createFromConfigClass() {
|
||||
load(BaseConfiguration.class, "spring.thymeleaf.suffix:.html");
|
||||
TemplateEngine engine = this.context.getBean(TemplateEngine.class);
|
||||
Context attrs = new Context(Locale.UK, Collections.singletonMap("foo", "bar"));
|
||||
String result = engine.process("template", attrs);
|
||||
assertThat(result).isEqualTo("<html>bar</html>");
|
||||
this.contextRunner.withPropertyValues("spring.thymeleaf.suffix:.html")
|
||||
.run((context) -> {
|
||||
TemplateEngine engine = context.getBean(TemplateEngine.class);
|
||||
Context attrs = new Context(Locale.UK,
|
||||
Collections.singletonMap("foo", "bar"));
|
||||
String result = engine.process("template", attrs);
|
||||
assertThat(result).isEqualTo("<html>bar</html>");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void overrideCharacterEncoding() {
|
||||
load(BaseConfiguration.class, "spring.thymeleaf.encoding:UTF-16");
|
||||
ITemplateResolver resolver = this.context.getBean(ITemplateResolver.class);
|
||||
assertThat(resolver instanceof SpringResourceTemplateResolver).isTrue();
|
||||
assertThat(((SpringResourceTemplateResolver) resolver).getCharacterEncoding())
|
||||
.isEqualTo("UTF-16");
|
||||
ThymeleafReactiveViewResolver views = this.context
|
||||
.getBean(ThymeleafReactiveViewResolver.class);
|
||||
assertThat(views.getDefaultCharset().name()).isEqualTo("UTF-16");
|
||||
this.contextRunner.withPropertyValues("spring.thymeleaf.encoding:UTF-16")
|
||||
.run((context) -> {
|
||||
ITemplateResolver resolver = context.getBean(ITemplateResolver.class);
|
||||
assertThat(resolver)
|
||||
.isInstanceOf(SpringResourceTemplateResolver.class);
|
||||
assertThat(((SpringResourceTemplateResolver) resolver)
|
||||
.getCharacterEncoding()).isEqualTo("UTF-16");
|
||||
ThymeleafReactiveViewResolver views = context
|
||||
.getBean(ThymeleafReactiveViewResolver.class);
|
||||
assertThat(views.getDefaultCharset().name()).isEqualTo("UTF-16");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void overrideMediaTypes() {
|
||||
load(BaseConfiguration.class,
|
||||
"spring.thymeleaf.reactive.media-types:text/html,text/plain");
|
||||
ThymeleafReactiveViewResolver views = this.context
|
||||
.getBean(ThymeleafReactiveViewResolver.class);
|
||||
assertThat(views.getSupportedMediaTypes()).contains(MediaType.TEXT_HTML,
|
||||
MediaType.TEXT_PLAIN);
|
||||
this.contextRunner
|
||||
.withPropertyValues(
|
||||
"spring.thymeleaf.reactive.media-types:text/html,text/plain")
|
||||
.run((context) -> assertThat(
|
||||
context.getBean(ThymeleafReactiveViewResolver.class)
|
||||
.getSupportedMediaTypes()).contains(MediaType.TEXT_HTML,
|
||||
MediaType.TEXT_PLAIN));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void overrideTemplateResolverOrder() {
|
||||
load(BaseConfiguration.class, "spring.thymeleaf.templateResolverOrder:25");
|
||||
ITemplateResolver resolver = this.context.getBean(ITemplateResolver.class);
|
||||
assertThat(resolver.getOrder()).isEqualTo(Integer.valueOf(25));
|
||||
this.contextRunner.withPropertyValues("spring.thymeleaf.templateResolverOrder:25")
|
||||
.run((context) -> assertThat(
|
||||
context.getBean(ITemplateResolver.class).getOrder())
|
||||
.isEqualTo(Integer.valueOf(25)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void overrideViewNames() {
|
||||
load(BaseConfiguration.class, "spring.thymeleaf.viewNames:foo,bar");
|
||||
ThymeleafReactiveViewResolver views = this.context
|
||||
.getBean(ThymeleafReactiveViewResolver.class);
|
||||
assertThat(views.getViewNames()).isEqualTo(new String[] { "foo", "bar" });
|
||||
this.contextRunner.withPropertyValues("spring.thymeleaf.viewNames:foo,bar")
|
||||
.run((context) -> assertThat(context
|
||||
.getBean(ThymeleafReactiveViewResolver.class).getViewNames())
|
||||
.isEqualTo(new String[] { "foo", "bar" }));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void overrideMaxChunkSize() {
|
||||
load(BaseConfiguration.class, "spring.thymeleaf.reactive.maxChunkSize:8KB");
|
||||
ThymeleafReactiveViewResolver views = this.context
|
||||
.getBean(ThymeleafReactiveViewResolver.class);
|
||||
assertThat(views.getResponseMaxChunkSizeBytes()).isEqualTo(Integer.valueOf(8192));
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.thymeleaf.reactive.maxChunkSize:8KB")
|
||||
.run((context) -> assertThat(
|
||||
context.getBean(ThymeleafReactiveViewResolver.class)
|
||||
.getResponseMaxChunkSizeBytes())
|
||||
.isEqualTo(Integer.valueOf(8192)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void overrideFullModeViewNames() {
|
||||
load(BaseConfiguration.class,
|
||||
"spring.thymeleaf.reactive.fullModeViewNames:foo,bar");
|
||||
ThymeleafReactiveViewResolver views = this.context
|
||||
.getBean(ThymeleafReactiveViewResolver.class);
|
||||
assertThat(views.getFullModeViewNames()).isEqualTo(new String[] { "foo", "bar" });
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.thymeleaf.reactive.fullModeViewNames:foo,bar")
|
||||
.run((context) -> assertThat(
|
||||
context.getBean(ThymeleafReactiveViewResolver.class)
|
||||
.getFullModeViewNames())
|
||||
.isEqualTo(new String[] { "foo", "bar" }));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void overrideChunkedModeViewNames() {
|
||||
load(BaseConfiguration.class,
|
||||
"spring.thymeleaf.reactive.chunkedModeViewNames:foo,bar");
|
||||
ThymeleafReactiveViewResolver views = this.context
|
||||
.getBean(ThymeleafReactiveViewResolver.class);
|
||||
assertThat(views.getChunkedModeViewNames())
|
||||
.isEqualTo(new String[] { "foo", "bar" });
|
||||
this.contextRunner
|
||||
.withPropertyValues(
|
||||
"spring.thymeleaf.reactive.chunkedModeViewNames:foo,bar")
|
||||
.run((context) -> assertThat(
|
||||
context.getBean(ThymeleafReactiveViewResolver.class)
|
||||
.getChunkedModeViewNames())
|
||||
.isEqualTo(new String[] { "foo", "bar" }));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void overrideEnableSpringElCompiler() {
|
||||
load(BaseConfiguration.class, "spring.thymeleaf.enable-spring-el-compiler:true");
|
||||
assertThat(this.context.getBean(SpringWebFluxTemplateEngine.class)
|
||||
.getEnableSpringELCompiler()).isTrue();
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.thymeleaf.enable-spring-el-compiler:true")
|
||||
.run((context) -> assertThat(
|
||||
context.getBean(SpringWebFluxTemplateEngine.class)
|
||||
.getEnableSpringELCompiler()).isTrue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enableSpringElCompilerIsDisabledByDefault() {
|
||||
load(BaseConfiguration.class);
|
||||
assertThat(this.context.getBean(SpringWebFluxTemplateEngine.class)
|
||||
.getEnableSpringELCompiler()).isFalse();
|
||||
this.contextRunner.run(
|
||||
(context) -> assertThat(context.getBean(SpringWebFluxTemplateEngine.class)
|
||||
.getEnableSpringELCompiler()).isFalse());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void overrideRenderHiddenMarkersBeforeCheckboxes() {
|
||||
load(BaseConfiguration.class,
|
||||
"spring.thymeleaf.render-hidden-markers-before-checkboxes:true");
|
||||
assertThat(this.context.getBean(SpringWebFluxTemplateEngine.class)
|
||||
.getRenderHiddenMarkersBeforeCheckboxes()).isTrue();
|
||||
this.contextRunner
|
||||
.withPropertyValues(
|
||||
"spring.thymeleaf.render-hidden-markers-before-checkboxes:true")
|
||||
.run((context) -> assertThat(
|
||||
context.getBean(SpringWebFluxTemplateEngine.class)
|
||||
.getRenderHiddenMarkersBeforeCheckboxes()).isTrue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enableRenderHiddenMarkersBeforeCheckboxesIsDisabledByDefault() {
|
||||
load(BaseConfiguration.class);
|
||||
assertThat(this.context.getBean(SpringWebFluxTemplateEngine.class)
|
||||
.getRenderHiddenMarkersBeforeCheckboxes()).isFalse();
|
||||
this.contextRunner.run(
|
||||
(context) -> assertThat(context.getBean(SpringWebFluxTemplateEngine.class)
|
||||
.getRenderHiddenMarkersBeforeCheckboxes()).isFalse());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void templateLocationDoesNotExist() {
|
||||
load(BaseConfiguration.class,
|
||||
"spring.thymeleaf.prefix:classpath:/no-such-directory/");
|
||||
assertThat(this.output.toString()).contains("Cannot find template location");
|
||||
this.contextRunner
|
||||
.withPropertyValues(
|
||||
"spring.thymeleaf.prefix:classpath:/no-such-directory/")
|
||||
.run((context) -> assertThat(this.output.toString())
|
||||
.contains("Cannot find template location"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void templateLocationEmpty() {
|
||||
new File(this.buildOutput.getTestResourcesLocation(),
|
||||
"empty-templates/empty-directory").mkdirs();
|
||||
load(BaseConfiguration.class,
|
||||
"spring.thymeleaf.prefix:classpath:/empty-templates/empty-directory/");
|
||||
assertThat(this.output.toString())
|
||||
.doesNotContain("Cannot find template location");
|
||||
this.contextRunner.withPropertyValues(
|
||||
"spring.thymeleaf.prefix:classpath:/empty-templates/empty-directory/")
|
||||
.run((context) -> assertThat(this.output.toString())
|
||||
.doesNotContain("Cannot find template location"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void useDataDialect() {
|
||||
load(BaseConfiguration.class);
|
||||
ISpringWebFluxTemplateEngine engine = this.context
|
||||
.getBean(ISpringWebFluxTemplateEngine.class);
|
||||
Context attrs = new Context(Locale.UK, Collections.singletonMap("foo", "bar"));
|
||||
String result = engine.process("data-dialect", attrs);
|
||||
assertThat(result).isEqualTo("<html><body data-foo=\"bar\"></body></html>");
|
||||
this.contextRunner.run((context) -> {
|
||||
ISpringWebFluxTemplateEngine engine = context
|
||||
.getBean(ISpringWebFluxTemplateEngine.class);
|
||||
Context attrs = new Context(Locale.UK,
|
||||
Collections.singletonMap("foo", "bar"));
|
||||
String result = engine.process("data-dialect", attrs);
|
||||
assertThat(result).isEqualTo("<html><body data-foo=\"bar\"></body></html>");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void useJava8TimeDialect() {
|
||||
load(BaseConfiguration.class);
|
||||
ISpringWebFluxTemplateEngine engine = this.context
|
||||
.getBean(ISpringWebFluxTemplateEngine.class);
|
||||
Context attrs = new Context(Locale.UK);
|
||||
String result = engine.process("java8time-dialect", attrs);
|
||||
assertThat(result).isEqualTo("<html><body>2015-11-24</body></html>");
|
||||
this.contextRunner.run((context) -> {
|
||||
ISpringWebFluxTemplateEngine engine = context
|
||||
.getBean(ISpringWebFluxTemplateEngine.class);
|
||||
Context attrs = new Context(Locale.UK);
|
||||
String result = engine.process("java8time-dialect", attrs);
|
||||
assertThat(result).isEqualTo("<html><body>2015-11-24</body></html>");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void useSecurityDialect() {
|
||||
load(BaseConfiguration.class);
|
||||
ISpringWebFluxTemplateEngine engine = this.context
|
||||
.getBean(ISpringWebFluxTemplateEngine.class);
|
||||
MockServerWebExchange exchange = MockServerWebExchange
|
||||
.from(MockServerHttpRequest.get("/test").build());
|
||||
exchange.getAttributes().put(
|
||||
SpringSecurityContextUtils.SECURITY_CONTEXT_MODEL_ATTRIBUTE_NAME,
|
||||
new SecurityContextImpl(
|
||||
new TestingAuthenticationToken("alice", "admin")));
|
||||
IContext attrs = new SpringWebFluxContext(exchange);
|
||||
String result = engine.process("security-dialect", attrs);
|
||||
assertThat(result).isEqualTo(
|
||||
"<html><body><div>alice</div></body></html>" + System.lineSeparator());
|
||||
this.contextRunner.run((context) -> {
|
||||
ISpringWebFluxTemplateEngine engine = context
|
||||
.getBean(ISpringWebFluxTemplateEngine.class);
|
||||
MockServerWebExchange exchange = MockServerWebExchange
|
||||
.from(MockServerHttpRequest.get("/test").build());
|
||||
exchange.getAttributes().put(
|
||||
SpringSecurityContextUtils.SECURITY_CONTEXT_MODEL_ATTRIBUTE_NAME,
|
||||
new SecurityContextImpl(
|
||||
new TestingAuthenticationToken("alice", "admin")));
|
||||
IContext attrs = new SpringWebFluxContext(exchange);
|
||||
String result = engine.process("security-dialect", attrs);
|
||||
assertThat(result).isEqualTo("<html><body><div>alice</div></body></html>"
|
||||
+ System.lineSeparator());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void renderTemplate() {
|
||||
load(BaseConfiguration.class);
|
||||
ISpringWebFluxTemplateEngine engine = this.context
|
||||
.getBean(ISpringWebFluxTemplateEngine.class);
|
||||
Context attrs = new Context(Locale.UK, Collections.singletonMap("foo", "bar"));
|
||||
String result = engine.process("home", attrs);
|
||||
assertThat(result).isEqualTo("<html><body>bar</body></html>");
|
||||
this.contextRunner.run((context) -> {
|
||||
ISpringWebFluxTemplateEngine engine = context
|
||||
.getBean(ISpringWebFluxTemplateEngine.class);
|
||||
Context attrs = new Context(Locale.UK,
|
||||
Collections.singletonMap("foo", "bar"));
|
||||
String result = engine.process("home", attrs);
|
||||
assertThat(result).isEqualTo("<html><body>bar</body></html>");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void layoutDialectCanBeCustomized() {
|
||||
load(LayoutDialectConfiguration.class);
|
||||
LayoutDialect layoutDialect = this.context.getBean(LayoutDialect.class);
|
||||
assertThat(ReflectionTestUtils.getField(layoutDialect, "sortingStrategy"))
|
||||
.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();
|
||||
this.contextRunner.withUserConfiguration(LayoutDialectConfiguration.class)
|
||||
.run((context) -> assertThat(ReflectionTestUtils.getField(
|
||||
context.getBean(LayoutDialect.class), "sortingStrategy"))
|
||||
.isInstanceOf(GroupingStrategy.class));
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ImportAutoConfiguration({ ThymeleafAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class })
|
||||
protected static class BaseConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(BaseConfiguration.class)
|
||||
static class LayoutDialectConfiguration {
|
||||
|
||||
@Bean
|
||||
|
|
|
@ -26,7 +26,6 @@ import javax.servlet.DispatcherType;
|
|||
|
||||
import nz.net.ultraq.thymeleaf.LayoutDialect;
|
||||
import nz.net.ultraq.thymeleaf.decorators.strategies.GroupingStrategy;
|
||||
import org.junit.After;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.thymeleaf.TemplateEngine;
|
||||
|
@ -38,17 +37,16 @@ import org.thymeleaf.spring5.view.ThymeleafView;
|
|||
import org.thymeleaf.spring5.view.ThymeleafViewResolver;
|
||||
import org.thymeleaf.templateresolver.ITemplateResolver;
|
||||
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
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.util.TestPropertyValues;
|
||||
import org.springframework.boot.testsupport.BuildOutput;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
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.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
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.SecurityContextImpl;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
import org.springframework.web.servlet.ViewResolver;
|
||||
import org.springframework.web.servlet.resource.ResourceUrlEncodingFilter;
|
||||
import org.springframework.web.servlet.support.RequestContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
|
||||
/**
|
||||
* Tests for {@link ThymeleafAutoConfiguration} in Servlet-based applications.
|
||||
|
@ -76,277 +74,297 @@ import static org.hamcrest.Matchers.containsString;
|
|||
*/
|
||||
public class ThymeleafServletAutoConfigurationTests {
|
||||
|
||||
private final BuildOutput buildOutput = new BuildOutput(getClass());
|
||||
|
||||
@Rule
|
||||
public OutputCapture output = new OutputCapture();
|
||||
|
||||
private AnnotationConfigWebApplicationContext context;
|
||||
private final BuildOutput buildOutput = new BuildOutput(getClass());
|
||||
|
||||
@After
|
||||
public void close() {
|
||||
if (this.context != null) {
|
||||
this.context.close();
|
||||
}
|
||||
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(ThymeleafAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
public void autoConfigurationBackOffWithoutThymeleafSpring() {
|
||||
this.contextRunner
|
||||
.withClassLoader(new FilteredClassLoader("org.thymeleaf.spring5"))
|
||||
.run((context) -> assertThat(context)
|
||||
.doesNotHaveBean(TemplateEngine.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createFromConfigClass() {
|
||||
load(BaseConfiguration.class, "spring.thymeleaf.mode:HTML",
|
||||
"spring.thymeleaf.suffix:");
|
||||
TemplateEngine engine = this.context.getBean(TemplateEngine.class);
|
||||
Context attrs = new Context(Locale.UK, Collections.singletonMap("foo", "bar"));
|
||||
String result = engine.process("template.html", attrs);
|
||||
assertThat(result).isEqualTo("<html>bar</html>");
|
||||
this.contextRunner.withPropertyValues("spring.thymeleaf.mode:HTML",
|
||||
"spring.thymeleaf.suffix:").run((context) -> {
|
||||
assertThat(context).hasSingleBean(TemplateEngine.class);
|
||||
TemplateEngine engine = context.getBean(TemplateEngine.class);
|
||||
Context attrs = new Context(Locale.UK,
|
||||
Collections.singletonMap("foo", "bar"));
|
||||
String result = engine.process("template.html", attrs);
|
||||
assertThat(result).isEqualTo("<html>bar</html>");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void overrideCharacterEncoding() {
|
||||
load(BaseConfiguration.class, "spring.thymeleaf.encoding:UTF-16");
|
||||
ITemplateResolver resolver = this.context.getBean(ITemplateResolver.class);
|
||||
assertThat(resolver instanceof SpringResourceTemplateResolver).isTrue();
|
||||
assertThat(((SpringResourceTemplateResolver) resolver).getCharacterEncoding())
|
||||
.isEqualTo("UTF-16");
|
||||
ThymeleafViewResolver views = this.context.getBean(ThymeleafViewResolver.class);
|
||||
assertThat(views.getCharacterEncoding()).isEqualTo("UTF-16");
|
||||
assertThat(views.getContentType()).isEqualTo("text/html;charset=UTF-16");
|
||||
this.contextRunner.withPropertyValues("spring.thymeleaf.encoding:UTF-16")
|
||||
.run((context) -> {
|
||||
ITemplateResolver resolver = context.getBean(ITemplateResolver.class);
|
||||
assertThat(resolver)
|
||||
.isInstanceOf(SpringResourceTemplateResolver.class);
|
||||
assertThat(((SpringResourceTemplateResolver) resolver)
|
||||
.getCharacterEncoding()).isEqualTo("UTF-16");
|
||||
ThymeleafViewResolver views = context
|
||||
.getBean(ThymeleafViewResolver.class);
|
||||
assertThat(views.getCharacterEncoding()).isEqualTo("UTF-16");
|
||||
assertThat(views.getContentType())
|
||||
.isEqualTo("text/html;charset=UTF-16");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void overrideDisableProducePartialOutputWhileProcessing() {
|
||||
load(BaseConfiguration.class,
|
||||
"spring.thymeleaf.servlet.produce-partial-output-while-processing:false");
|
||||
assertThat(this.context.getBean(ThymeleafViewResolver.class)
|
||||
.getProducePartialOutputWhileProcessing()).isFalse();
|
||||
this.contextRunner.withPropertyValues(
|
||||
"spring.thymeleaf.servlet.produce-partial-output-while-processing:false")
|
||||
.run((context) -> assertThat(context.getBean(ThymeleafViewResolver.class)
|
||||
.getProducePartialOutputWhileProcessing()).isFalse());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void disableProducePartialOutputWhileProcessingIsEnabledByDefault() {
|
||||
load(BaseConfiguration.class);
|
||||
assertThat(this.context.getBean(ThymeleafViewResolver.class)
|
||||
.getProducePartialOutputWhileProcessing()).isTrue();
|
||||
this.contextRunner
|
||||
.run((context) -> assertThat(context.getBean(ThymeleafViewResolver.class)
|
||||
.getProducePartialOutputWhileProcessing()).isTrue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void overrideTemplateResolverOrder() {
|
||||
load(BaseConfiguration.class, "spring.thymeleaf.templateResolverOrder:25");
|
||||
ITemplateResolver resolver = this.context.getBean(ITemplateResolver.class);
|
||||
assertThat(resolver.getOrder()).isEqualTo(Integer.valueOf(25));
|
||||
this.contextRunner.withPropertyValues("spring.thymeleaf.templateResolverOrder:25")
|
||||
.run((context) -> assertThat(
|
||||
context.getBean(ITemplateResolver.class).getOrder())
|
||||
.isEqualTo(Integer.valueOf(25)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void overrideViewNames() {
|
||||
load(BaseConfiguration.class, "spring.thymeleaf.viewNames:foo,bar");
|
||||
ThymeleafViewResolver views = this.context.getBean(ThymeleafViewResolver.class);
|
||||
assertThat(views.getViewNames()).isEqualTo(new String[] { "foo", "bar" });
|
||||
this.contextRunner.withPropertyValues("spring.thymeleaf.viewNames:foo,bar")
|
||||
.run((context) -> assertThat(
|
||||
context.getBean(ThymeleafViewResolver.class).getViewNames())
|
||||
.isEqualTo(new String[] { "foo", "bar" }));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void overrideEnableSpringElCompiler() {
|
||||
load(BaseConfiguration.class, "spring.thymeleaf.enable-spring-el-compiler:true");
|
||||
assertThat(this.context.getBean(SpringTemplateEngine.class)
|
||||
.getEnableSpringELCompiler()).isTrue();
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.thymeleaf.enable-spring-el-compiler:true")
|
||||
.run((context) -> assertThat(context.getBean(SpringTemplateEngine.class)
|
||||
.getEnableSpringELCompiler()).isTrue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enableSpringElCompilerIsDisabledByDefault() {
|
||||
load(BaseConfiguration.class);
|
||||
assertThat(this.context.getBean(SpringTemplateEngine.class)
|
||||
.getEnableSpringELCompiler()).isFalse();
|
||||
this.contextRunner.run((context) -> assertThat(
|
||||
context.getBean(SpringTemplateEngine.class).getEnableSpringELCompiler())
|
||||
.isFalse());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void overrideRenderHiddenMarkersBeforeCheckboxes() {
|
||||
load(BaseConfiguration.class,
|
||||
"spring.thymeleaf.render-hidden-markers-before-checkboxes:true");
|
||||
assertThat(this.context.getBean(SpringTemplateEngine.class)
|
||||
.getRenderHiddenMarkersBeforeCheckboxes()).isTrue();
|
||||
this.contextRunner
|
||||
.withPropertyValues(
|
||||
"spring.thymeleaf.render-hidden-markers-before-checkboxes:true")
|
||||
.run((context) -> assertThat(context.getBean(SpringTemplateEngine.class)
|
||||
.getRenderHiddenMarkersBeforeCheckboxes()).isTrue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enableRenderHiddenMarkersBeforeCheckboxesIsDisabledByDefault() {
|
||||
load(BaseConfiguration.class);
|
||||
assertThat(this.context.getBean(SpringTemplateEngine.class)
|
||||
.getRenderHiddenMarkersBeforeCheckboxes()).isFalse();
|
||||
this.contextRunner
|
||||
.run((context) -> assertThat(context.getBean(SpringTemplateEngine.class)
|
||||
.getRenderHiddenMarkersBeforeCheckboxes()).isFalse());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void templateLocationDoesNotExist() {
|
||||
load(BaseConfiguration.class,
|
||||
"spring.thymeleaf.prefix:classpath:/no-such-directory/");
|
||||
this.output.expect(containsString("Cannot find template location"));
|
||||
this.contextRunner
|
||||
.withPropertyValues(
|
||||
"spring.thymeleaf.prefix:classpath:/no-such-directory/")
|
||||
.run((context) -> this.output
|
||||
.expect(containsString("Cannot find template location")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void templateLocationEmpty() {
|
||||
new File(this.buildOutput.getTestResourcesLocation(),
|
||||
"empty-templates/empty-directory").mkdirs();
|
||||
load(BaseConfiguration.class,
|
||||
"spring.thymeleaf.prefix:classpath:/empty-templates/empty-directory/");
|
||||
this.contextRunner.withPropertyValues(
|
||||
"spring.thymeleaf.prefix:classpath:/empty-templates/empty-directory/")
|
||||
.run((context) -> this.output
|
||||
.expect(not(containsString("Cannot find template location"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createLayoutFromConfigClass() throws Exception {
|
||||
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
|
||||
context.register(ThymeleafAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class);
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
context.setServletContext(servletContext);
|
||||
context.refresh();
|
||||
ThymeleafView view = (ThymeleafView) context.getBean(ThymeleafViewResolver.class)
|
||||
.resolveViewName("view", Locale.UK);
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setAttribute(RequestContext.WEB_APPLICATION_CONTEXT_ATTRIBUTE, context);
|
||||
view.render(Collections.singletonMap("foo", "bar"), request, response);
|
||||
String result = response.getContentAsString();
|
||||
assertThat(result).contains("<title>Content</title>");
|
||||
assertThat(result).contains("<span>bar</span>");
|
||||
context.close();
|
||||
public void createLayoutFromConfigClass() {
|
||||
this.contextRunner.run((context) -> {
|
||||
ThymeleafView view = (ThymeleafView) context
|
||||
.getBean(ThymeleafViewResolver.class)
|
||||
.resolveViewName("view", Locale.UK);
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setAttribute(RequestContext.WEB_APPLICATION_CONTEXT_ATTRIBUTE,
|
||||
context);
|
||||
view.render(Collections.singletonMap("foo", "bar"), request, response);
|
||||
String result = response.getContentAsString();
|
||||
assertThat(result).contains("<title>Content</title>");
|
||||
assertThat(result).contains("<span>bar</span>");
|
||||
context.close();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void useDataDialect() {
|
||||
load(BaseConfiguration.class);
|
||||
TemplateEngine engine = this.context.getBean(TemplateEngine.class);
|
||||
Context attrs = new Context(Locale.UK, Collections.singletonMap("foo", "bar"));
|
||||
String result = engine.process("data-dialect", attrs);
|
||||
assertThat(result).isEqualTo("<html><body data-foo=\"bar\"></body></html>");
|
||||
this.contextRunner.run((context) -> {
|
||||
TemplateEngine engine = context.getBean(TemplateEngine.class);
|
||||
Context attrs = new Context(Locale.UK,
|
||||
Collections.singletonMap("foo", "bar"));
|
||||
String result = engine.process("data-dialect", attrs);
|
||||
assertThat(result).isEqualTo("<html><body data-foo=\"bar\"></body></html>");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void useJava8TimeDialect() {
|
||||
load(BaseConfiguration.class);
|
||||
TemplateEngine engine = this.context.getBean(TemplateEngine.class);
|
||||
Context attrs = new Context(Locale.UK);
|
||||
String result = engine.process("java8time-dialect", attrs);
|
||||
assertThat(result).isEqualTo("<html><body>2015-11-24</body></html>");
|
||||
this.contextRunner.run((context) -> {
|
||||
TemplateEngine engine = context.getBean(TemplateEngine.class);
|
||||
Context attrs = new Context(Locale.UK);
|
||||
String result = engine.process("java8time-dialect", attrs);
|
||||
assertThat(result).isEqualTo("<html><body>2015-11-24</body></html>");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void useSecurityDialect() {
|
||||
load(BaseConfiguration.class);
|
||||
TemplateEngine engine = this.context.getBean(TemplateEngine.class);
|
||||
WebContext attrs = new WebContext(new MockHttpServletRequest(),
|
||||
new MockHttpServletResponse(), new MockServletContext());
|
||||
try {
|
||||
SecurityContextHolder.setContext(new SecurityContextImpl(
|
||||
new TestingAuthenticationToken("alice", "admin")));
|
||||
String result = engine.process("security-dialect", attrs);
|
||||
assertThat(result).isEqualTo("<html><body><div>alice</div></body></html>"
|
||||
+ System.lineSeparator());
|
||||
}
|
||||
finally {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
this.contextRunner.run((context) -> {
|
||||
TemplateEngine engine = context.getBean(TemplateEngine.class);
|
||||
WebContext attrs = new WebContext(new MockHttpServletRequest(),
|
||||
new MockHttpServletResponse(), new MockServletContext());
|
||||
try {
|
||||
SecurityContextHolder.setContext(new SecurityContextImpl(
|
||||
new TestingAuthenticationToken("alice", "admin")));
|
||||
String result = engine.process("security-dialect", attrs);
|
||||
assertThat(result).isEqualTo("<html><body><div>alice</div></body></html>"
|
||||
+ System.lineSeparator());
|
||||
}
|
||||
finally {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void renderTemplate() {
|
||||
load(BaseConfiguration.class);
|
||||
TemplateEngine engine = this.context.getBean(TemplateEngine.class);
|
||||
Context attrs = new Context(Locale.UK, Collections.singletonMap("foo", "bar"));
|
||||
String result = engine.process("home", attrs);
|
||||
assertThat(result).isEqualTo("<html><body>bar</body></html>");
|
||||
this.contextRunner.run((context) -> {
|
||||
TemplateEngine engine = context.getBean(TemplateEngine.class);
|
||||
Context attrs = new Context(Locale.UK,
|
||||
Collections.singletonMap("foo", "bar"));
|
||||
String result = engine.process("home", attrs);
|
||||
assertThat(result).isEqualTo("<html><body>bar</body></html>");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void renderNonWebAppTemplate() {
|
||||
try (AnnotationConfigApplicationContext customContext = new AnnotationConfigApplicationContext(
|
||||
ThymeleafAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class)) {
|
||||
assertThat(customContext.getBeanNamesForType(ViewResolver.class).length)
|
||||
.isEqualTo(0);
|
||||
TemplateEngine engine = customContext.getBean(TemplateEngine.class);
|
||||
Context attrs = new Context(Locale.UK,
|
||||
Collections.singletonMap("greeting", "Hello World"));
|
||||
String result = engine.process("message", attrs);
|
||||
assertThat(result).contains("Hello World");
|
||||
}
|
||||
new ApplicationContextRunner()
|
||||
.withConfiguration(
|
||||
AutoConfigurations.of(ThymeleafAutoConfiguration.class))
|
||||
.run((context) -> {
|
||||
assertThat(context).doesNotHaveBean(ViewResolver.class);
|
||||
TemplateEngine engine = context.getBean(TemplateEngine.class);
|
||||
Context attrs = new Context(Locale.UK,
|
||||
Collections.singletonMap("greeting", "Hello World"));
|
||||
String result = engine.process("message", attrs);
|
||||
assertThat(result).contains("Hello World");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void registerResourceHandlingFilterDisabledByDefault() {
|
||||
load(BaseConfiguration.class);
|
||||
assertThat(this.context.getBeansOfType(FilterRegistrationBean.class)).isEmpty();
|
||||
this.contextRunner.run((context) -> assertThat(context)
|
||||
.doesNotHaveBean(FilterRegistrationBean.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void registerResourceHandlingFilterOnlyIfResourceChainIsEnabled() {
|
||||
load(BaseConfiguration.class, "spring.resources.chain.enabled:true");
|
||||
FilterRegistrationBean<?> registration = this.context
|
||||
.getBean(FilterRegistrationBean.class);
|
||||
assertThat(registration.getFilter())
|
||||
.isInstanceOf(ResourceUrlEncodingFilter.class);
|
||||
assertThat(registration).hasFieldOrPropertyWithValue("dispatcherTypes",
|
||||
EnumSet.of(DispatcherType.REQUEST, DispatcherType.ERROR));
|
||||
this.contextRunner.withPropertyValues("spring.resources.chain.enabled:true")
|
||||
.run((context) -> {
|
||||
FilterRegistrationBean<?> registration = context
|
||||
.getBean(FilterRegistrationBean.class);
|
||||
assertThat(registration.getFilter())
|
||||
.isInstanceOf(ResourceUrlEncodingFilter.class);
|
||||
assertThat(registration).hasFieldOrPropertyWithValue(
|
||||
"dispatcherTypes",
|
||||
EnumSet.of(DispatcherType.REQUEST, DispatcherType.ERROR));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void registerResourceHandlingFilterWithOtherRegistrationBean() {
|
||||
// gh-14897
|
||||
load(FilterRegistrationOtherConfiguration.class,
|
||||
"spring.resources.chain.enabled:true");
|
||||
Map<String, FilterRegistrationBean> beans = this.context
|
||||
.getBeansOfType(FilterRegistrationBean.class);
|
||||
assertThat(beans).hasSize(2);
|
||||
FilterRegistrationBean registration = beans.values().stream()
|
||||
.filter((r) -> r.getFilter() instanceof ResourceUrlEncodingFilter)
|
||||
.findFirst().get();
|
||||
assertThat(registration).hasFieldOrPropertyWithValue("dispatcherTypes",
|
||||
EnumSet.of(DispatcherType.REQUEST, DispatcherType.ERROR));
|
||||
this.contextRunner
|
||||
.withUserConfiguration(FilterRegistrationOtherConfiguration.class)
|
||||
.withPropertyValues("spring.resources.chain.enabled:true")
|
||||
.run((context) -> {
|
||||
Map<String, FilterRegistrationBean> beans = context
|
||||
.getBeansOfType(FilterRegistrationBean.class);
|
||||
assertThat(beans).hasSize(2);
|
||||
FilterRegistrationBean registration = beans.values().stream().filter(
|
||||
(r) -> r.getFilter() instanceof ResourceUrlEncodingFilter)
|
||||
.findFirst().get();
|
||||
assertThat(registration).hasFieldOrPropertyWithValue(
|
||||
"dispatcherTypes",
|
||||
EnumSet.of(DispatcherType.REQUEST, DispatcherType.ERROR));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void registerResourceHandlingFilterWithResourceRegistrationBean() {
|
||||
// gh-14926
|
||||
load(FilterRegistrationResourceConfiguration.class,
|
||||
"spring.resources.chain.enabled:true");
|
||||
Map<String, FilterRegistrationBean> beans = this.context
|
||||
.getBeansOfType(FilterRegistrationBean.class);
|
||||
assertThat(beans).hasSize(1);
|
||||
FilterRegistrationBean registration = beans.values().stream()
|
||||
.filter((r) -> r.getFilter() instanceof ResourceUrlEncodingFilter)
|
||||
.findFirst().get();
|
||||
assertThat(registration).hasFieldOrPropertyWithValue("dispatcherTypes",
|
||||
EnumSet.of(DispatcherType.INCLUDE));
|
||||
this.contextRunner
|
||||
.withUserConfiguration(FilterRegistrationResourceConfiguration.class)
|
||||
.withPropertyValues("spring.resources.chain.enabled:true")
|
||||
.run((context) -> {
|
||||
Map<String, FilterRegistrationBean> beans = context
|
||||
.getBeansOfType(FilterRegistrationBean.class);
|
||||
assertThat(beans).hasSize(1);
|
||||
FilterRegistrationBean registration = beans.values().stream().filter(
|
||||
(r) -> r.getFilter() instanceof ResourceUrlEncodingFilter)
|
||||
.findFirst().get();
|
||||
assertThat(registration).hasFieldOrPropertyWithValue(
|
||||
"dispatcherTypes", EnumSet.of(DispatcherType.INCLUDE));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void layoutDialectCanBeCustomized() {
|
||||
load(LayoutDialectConfiguration.class);
|
||||
LayoutDialect layoutDialect = this.context.getBean(LayoutDialect.class);
|
||||
assertThat(ReflectionTestUtils.getField(layoutDialect, "sortingStrategy"))
|
||||
.isInstanceOf(GroupingStrategy.class);
|
||||
this.contextRunner.withUserConfiguration(LayoutDialectConfiguration.class)
|
||||
.run((context) -> assertThat(ReflectionTestUtils.getField(
|
||||
context.getBean(LayoutDialect.class), "sortingStrategy"))
|
||||
.isInstanceOf(GroupingStrategy.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cachingCanBeDisabled() {
|
||||
load(BaseConfiguration.class, "spring.thymeleaf.cache:false");
|
||||
assertThat(this.context.getBean(ThymeleafViewResolver.class).isCache()).isFalse();
|
||||
SpringResourceTemplateResolver templateResolver = this.context
|
||||
.getBean(SpringResourceTemplateResolver.class);
|
||||
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();
|
||||
this.contextRunner.withPropertyValues("spring.thymeleaf.cache:false")
|
||||
.run((context) -> {
|
||||
assertThat(context.getBean(ThymeleafViewResolver.class).isCache())
|
||||
.isFalse();
|
||||
SpringResourceTemplateResolver templateResolver = context
|
||||
.getBean(SpringResourceTemplateResolver.class);
|
||||
assertThat(templateResolver.isCacheable()).isFalse();
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ImportAutoConfiguration({ ThymeleafAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class })
|
||||
static class BaseConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(BaseConfiguration.class)
|
||||
static class LayoutDialectConfiguration {
|
||||
|
||||
@Bean
|
||||
|
@ -357,7 +375,6 @@ public class ThymeleafServletAutoConfigurationTests {
|
|||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(BaseConfiguration.class)
|
||||
static class FilterRegistrationResourceConfiguration {
|
||||
|
||||
@Bean
|
||||
|
@ -371,7 +388,6 @@ public class ThymeleafServletAutoConfigurationTests {
|
|||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(BaseConfiguration.class)
|
||||
static class FilterRegistrationOtherConfiguration {
|
||||
|
||||
@Bean
|
||||
|
|
Loading…
Reference in New Issue