Repository: PebbleTemplates/pebble
Pull request #514 (2020-05-21 00:18:27)

#506: Add unit test


Patch:
diff --git a/docs/src/orchid/resources/changelog/v3_1_4.md b/docs/src/orchid/resources/changelog/v3_1_4.md
deleted file mode 100644
index 4249b17e..00000000
--- a/docs/src/orchid/resources/changelog/v3_1_4.md
+++ /dev/null
@@ -1,9 +0,0 @@
----
-version: '3.1.4'
----
-
-- Slice filter: Use collection size when toIndex is greater than collection size  (#504)
-- Adjust spring boot doc (#509) 
-- Build with jdk14 (#508)
-- Set proxyBeanMethods to false (#507)
-- Add access to Spring Beans/request/session and response when using Pebble with WebFlux (#512)
\ No newline at end of file
diff --git a/pebble-spring/pebble-spring-boot-starter/src/main/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleAutoConfiguration.java b/pebble-spring/pebble-spring-boot-starter/src/main/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleAutoConfiguration.java
index 076271af..3e874f7c 100644
--- a/pebble-spring/pebble-spring-boot-starter/src/main/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleAutoConfiguration.java
+++ b/pebble-spring/pebble-spring-boot-starter/src/main/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleAutoConfiguration.java
@@ -9,7 +9,6 @@ import java.util.List;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.context.MessageSource;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Import;
@@ -34,8 +33,8 @@ public class PebbleAutoConfiguration extends AbstractPebbleConfiguration {
 
   @Bean
   @ConditionalOnMissingBean
-  public SpringExtension pebbleSpringExtension(MessageSource messageSource) {
-    return new SpringExtension(messageSource);
+  public SpringExtension pebbleSpringExtension() {
+    return new SpringExtension();
   }
 
   @Bean
diff --git a/pebble-spring/pebble-spring-boot-starter/src/main/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleServletWebConfiguration.java b/pebble-spring/pebble-spring-boot-starter/src/main/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleServletWebConfiguration.java
index 122cdb68..9cf61957 100644
--- a/pebble-spring/pebble-spring-boot-starter/src/main/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleServletWebConfiguration.java
+++ b/pebble-spring/pebble-spring-boot-starter/src/main/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleServletWebConfiguration.java
@@ -17,8 +17,10 @@ class PebbleServletWebConfiguration extends AbstractPebbleConfiguration {
   @ConditionalOnMissingBean(name = "pebbleViewResolver")
   PebbleViewResolver pebbleViewResolver(PebbleProperties properties,
       PebbleEngine pebbleEngine) {
-    PebbleViewResolver pvr = new PebbleViewResolver(pebbleEngine);
+    PebbleViewResolver pvr = new PebbleViewResolver();
     properties.applyToMvcViewResolver(pvr);
+
+    pvr.setPebbleEngine(pebbleEngine);
     if (pebbleEngine.getLoader() instanceof ClasspathLoader) {
       // classpathloader doesn't like leading slashes in paths
       pvr.setPrefix(this.stripLeadingSlash(properties.getPrefix()));
diff --git a/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/extension/SpringExtension.java b/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/extension/SpringExtension.java
index 888be297..14f0e09e 100644
--- a/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/extension/SpringExtension.java
+++ b/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/extension/SpringExtension.java
@@ -18,6 +18,7 @@ import com.mitchellbosecke.pebble.spring.extension.function.bindingresult.HasFie
 import com.mitchellbosecke.pebble.spring.extension.function.bindingresult.HasGlobalErrorsFunction;
 import java.util.HashMap;
 import java.util.Map;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.MessageSource;
 
 /**
@@ -29,11 +30,8 @@ import org.springframework.context.MessageSource;
  */
 public class SpringExtension extends AbstractExtension {
 
-  private final MessageSource messageSource;
-
-  public SpringExtension(MessageSource messageSource) {
-    this.messageSource = messageSource;
-  }
+  @Autowired
+  private MessageSource messageSource;
 
   @Override
   public Map<String, Function> getFunctions() {
diff --git a/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/reactive/PebbleReactiveView.java b/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/reactive/PebbleReactiveView.java
index 48c2c51d..c0809e71 100644
--- a/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/reactive/PebbleReactiveView.java
+++ b/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/reactive/PebbleReactiveView.java
@@ -1,17 +1,9 @@
 package com.mitchellbosecke.pebble.spring.reactive;
 
-import static java.util.Optional.ofNullable;
-
 import com.mitchellbosecke.pebble.PebbleEngine;
 import com.mitchellbosecke.pebble.error.PebbleException;
-import com.mitchellbosecke.pebble.spring.context.Beans;
 import com.mitchellbosecke.pebble.template.PebbleTemplate;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
-import java.nio.charset.Charset;
-import java.util.Locale;
-import java.util.Map;
+
 import org.springframework.context.i18n.LocaleContextHolder;
 import org.springframework.core.io.buffer.DataBuffer;
 import org.springframework.core.io.buffer.DataBufferUtils;
@@ -20,16 +12,20 @@ import org.springframework.lang.Nullable;
 import org.springframework.util.MimeType;
 import org.springframework.web.reactive.result.view.AbstractUrlBasedView;
 import org.springframework.web.server.ServerWebExchange;
+
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.nio.charset.Charset;
+import java.util.Locale;
+import java.util.Map;
+
+import static java.util.Optional.ofNullable;
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
 public class PebbleReactiveView extends AbstractUrlBasedView {
 
-  private static final String BEANS_VARIABLE_NAME = "beans";
-  private static final String REQUEST_VARIABLE_NAME = "request";
-  private static final String RESPONSE_VARIABLE_NAME = "response";
-  private static final String SESSION_VARIABLE_NAME = "session";
-
   private PebbleEngine pebbleEngine;
   private String templateName;
 
@@ -51,7 +47,6 @@ public class PebbleReactiveView extends AbstractUrlBasedView {
     try {
       Charset charset = this.getCharset(contentType);
       Writer writer = new OutputStreamWriter(dataBuffer.asOutputStream(), charset);
-      this.addVariablesToModel(renderAttributes, exchange);
       this.evaluateTemplate(renderAttributes, locale, writer);
     } catch (Exception ex) {
       DataBufferUtils.release(dataBuffer);
@@ -60,13 +55,6 @@ public class PebbleReactiveView extends AbstractUrlBasedView {
     return exchange.getResponse().writeWith(Flux.just(dataBuffer));
   }
 
-  private void addVariablesToModel(Map<String, Object> model, ServerWebExchange exchange) {
-    model.put(BEANS_VARIABLE_NAME, new Beans(this.getApplicationContext()));
-    model.put(REQUEST_VARIABLE_NAME, exchange.getRequest());
-    model.put(RESPONSE_VARIABLE_NAME, exchange.getResponse());
-    model.put(SESSION_VARIABLE_NAME, exchange.getSession());
-  }
-
   private Charset getCharset(@Nullable MediaType mediaType) {
     return ofNullable(mediaType)
         .map(MimeType::getCharset)
diff --git a/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/reactive/PebbleReactiveViewResolver.java b/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/reactive/PebbleReactiveViewResolver.java
index 3f4a4734..138e7ae7 100644
--- a/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/reactive/PebbleReactiveViewResolver.java
+++ b/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/reactive/PebbleReactiveViewResolver.java
@@ -1,6 +1,7 @@
 package com.mitchellbosecke.pebble.spring.reactive;
 
 import com.mitchellbosecke.pebble.PebbleEngine;
+
 import org.springframework.web.reactive.result.view.AbstractUrlBasedView;
 import org.springframework.web.reactive.result.view.UrlBasedViewResolver;
 
@@ -26,4 +27,8 @@ public class PebbleReactiveViewResolver extends UrlBasedViewResolver {
   protected Class<?> requiredViewClass() {
     return PebbleReactiveView.class;
   }
+
+  public PebbleEngine getPebbleEngine() {
+    return this.pebbleEngine;
+  }
 }
diff --git a/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/servlet/PebbleViewResolver.java b/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/servlet/PebbleViewResolver.java
index 01271123..0b7a66f4 100644
--- a/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/servlet/PebbleViewResolver.java
+++ b/pebble-spring/pebble-spring5/src/main/java/com/mitchellbosecke/pebble/spring/servlet/PebbleViewResolver.java
@@ -8,17 +8,18 @@ package com.mitchellbosecke.pebble.spring.servlet;
 
 import com.mitchellbosecke.pebble.PebbleEngine;
 import com.mitchellbosecke.pebble.loader.Loader;
+
 import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Required;
 import org.springframework.web.servlet.view.AbstractTemplateViewResolver;
 import org.springframework.web.servlet.view.AbstractUrlBasedView;
 
 public class PebbleViewResolver extends AbstractTemplateViewResolver implements InitializingBean {
 
   private String characterEncoding = "UTF-8";
-  private final PebbleEngine pebbleEngine;
+  private PebbleEngine pebbleEngine;
 
-  public PebbleViewResolver(PebbleEngine pebbleEngine) {
-    this.pebbleEngine = pebbleEngine;
+  public PebbleViewResolver() {
     this.setViewClass(this.requiredViewClass());
   }
 
@@ -33,6 +34,11 @@ public class PebbleViewResolver extends AbstractTemplateViewResolver implements
     this.characterEncoding = characterEncoding;
   }
 
+  @Required
+  public void setPebbleEngine(PebbleEngine pebbleEngine) {
+    this.pebbleEngine = pebbleEngine;
+  }
+
   @Override
   protected AbstractUrlBasedView buildView(String viewName) throws Exception {
     PebbleView view = (PebbleView) super.buildView(viewName);


Test patch:
diff --git a/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/Controllers.java b/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/Controllers.java
index 795b843d..52eb0afa 100644
--- a/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/Controllers.java
+++ b/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/Controllers.java
@@ -26,14 +26,4 @@ public class Controllers {
     return "extensions";
   }
 
-  @RequestMapping("/beans.action")
-  public String beans() {
-    return "beans";
-  }
-
-  @RequestMapping("/response.action")
-  public String response() {
-    return "responseObject";
-  }
-
 }
\ No newline at end of file
diff --git a/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/Foo.java b/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/Foo.java
deleted file mode 100644
index f4531508..00000000
--- a/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/Foo.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.mitchellbosecke.pebble.boot;
-
-import org.springframework.stereotype.Component;
-
-@Component
-public class Foo {
-
-  public String value = "bar";
-}
diff --git a/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleAutoConfigurationTest.java b/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleAutoConfigurationTest.java
index 0938cc03..2cc79ca7 100644
--- a/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleAutoConfigurationTest.java
+++ b/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/autoconfigure/PebbleAutoConfigurationTest.java
@@ -13,7 +13,6 @@ import org.junit.jupiter.api.Test;
 import org.springframework.boot.test.util.TestPropertyValues;
 import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebApplicationContext;
 import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebApplicationContext;
-import org.springframework.context.MessageSource;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Import;
@@ -102,8 +101,8 @@ class PebbleAutoConfigurationTest {
     }
 
     @Bean
-    public SpringExtension customSpringExtension(MessageSource messageSource) {
-      return new SpringExtension(messageSource);
+    public SpringExtension customSpringExtension() {
+      return new SpringExtension();
     }
   }
 
diff --git a/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/autoconfigure/ReactiveAppTest.java b/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/autoconfigure/ReactiveAppTest.java
index 60d6a8b2..210b4624 100644
--- a/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/autoconfigure/ReactiveAppTest.java
+++ b/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/autoconfigure/ReactiveAppTest.java
@@ -36,7 +36,7 @@ class ReactiveAppTest {
         .expectBody(String.class)
         .returnResult().getResponseBody();
 
-    assertThat(result).isEqualTo("ctx path:/contextPath.action");
+    assertThat(result).isEqualTo("ctx path:");
   }
 
   @Test
@@ -74,27 +74,5 @@ class ReactiveAppTest {
 
     assertThat(result).isEqualTo("Hola Boot! Tested!");
   }
-
-  @Test
-  void testBeansAccess() throws Exception {
-    String result = this.client.get().uri("/beans.action").exchange()
-        .expectStatus().isOk()
-        .expectHeader().contentTypeCompatibleWith(MediaType.TEXT_HTML)
-        .expectBody(String.class)
-        .returnResult().getResponseBody();
-
-    assertThat(result).isEqualTo("beans:bar");
-  }
-
-  @Test
-  void testResponseAccess() throws Exception {
-    String result = this.client.get().uri("/response.action").exchange()
-        .expectStatus().isOk()
-        .expectHeader().contentTypeCompatibleWith(MediaType.TEXT_HTML)
-        .expectBody(String.class)
-        .returnResult().getResponseBody();
-
-    assertThat(result).isEqualTo("response:200 OK");
-  }
 }
 
diff --git a/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/autoconfigure/ServletAppTest.java b/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/autoconfigure/ServletAppTest.java
index b4bdeb58..431142b2 100644
--- a/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/autoconfigure/ServletAppTest.java
+++ b/pebble-spring/pebble-spring-boot-starter/src/test/java/com/mitchellbosecke/pebble/boot/autoconfigure/ServletAppTest.java
@@ -70,19 +70,4 @@ class ServletAppTest {
         .andExpect(content().string("Hola Boot! Tested!"));
   }
 
-  @Test
-  void testBeansAccess() throws Exception {
-    this.mockMvc.perform(get("/beans.action"))
-        .andExpect(status().isOk())
-        .andExpect(content().contentTypeCompatibleWith(MediaType.TEXT_HTML))
-        .andExpect(content().string("beans:bar"));
-  }
-
-  @Test
-  void testResponseAccess() throws Exception {
-    this.mockMvc.perform(get("/response.action"))
-        .andExpect(status().isOk())
-        .andExpect(content().contentTypeCompatibleWith(MediaType.TEXT_HTML))
-        .andExpect(content().string("response:200"));
-  }
 }
diff --git a/pebble-spring/pebble-spring-boot-starter/src/test/resources/templates/beans.pebble b/pebble-spring/pebble-spring-boot-starter/src/test/resources/templates/beans.pebble
deleted file mode 100644
index c0a95852..00000000
--- a/pebble-spring/pebble-spring-boot-starter/src/test/resources/templates/beans.pebble
+++ /dev/null
@@ -1,1 +0,0 @@
-beans:{{beans.foo.value}}
\ No newline at end of file
diff --git a/pebble-spring/pebble-spring-boot-starter/src/test/resources/templates/contextPath.pebble b/pebble-spring/pebble-spring-boot-starter/src/test/resources/templates/contextPath.pebble
index bf5fc36c..6b2af787 100644
--- a/pebble-spring/pebble-spring-boot-starter/src/test/resources/templates/contextPath.pebble
+++ b/pebble-spring/pebble-spring-boot-starter/src/test/resources/templates/contextPath.pebble
@@ -1,1 +1,1 @@
-ctx path:{{request.contextPath}}{{request.path}}
\ No newline at end of file
+ctx path:{{request.contextPath}}
\ No newline at end of file
diff --git a/pebble-spring/pebble-spring-boot-starter/src/test/resources/templates/responseObject.pebble b/pebble-spring/pebble-spring-boot-starter/src/test/resources/templates/responseObject.pebble
deleted file mode 100644
index 1b11aa7d..00000000
--- a/pebble-spring/pebble-spring-boot-starter/src/test/resources/templates/responseObject.pebble
+++ /dev/null
@@ -1,1 +0,0 @@
-response:{{response.status}}{{response.statusCode}}
\ No newline at end of file
diff --git a/pebble-spring/pebble-spring5/src/test/java/com/mitchellbosecke/pebble/spring/config/MVCConfig.java b/pebble-spring/pebble-spring5/src/test/java/com/mitchellbosecke/pebble/spring/config/MVCConfig.java
index 10122412..2170d1c7 100644
--- a/pebble-spring/pebble-spring5/src/test/java/com/mitchellbosecke/pebble/spring/config/MVCConfig.java
+++ b/pebble-spring/pebble-spring5/src/test/java/com/mitchellbosecke/pebble/spring/config/MVCConfig.java
@@ -12,6 +12,7 @@ import com.mitchellbosecke.pebble.loader.Loader;
 import com.mitchellbosecke.pebble.spring.bean.SomeBean;
 import com.mitchellbosecke.pebble.spring.extension.SpringExtension;
 import com.mitchellbosecke.pebble.spring.servlet.PebbleViewResolver;
+
 import org.springframework.context.MessageSource;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -50,8 +51,8 @@ public class MVCConfig {
   }
 
   @Bean
-  public SpringExtension springExtension(MessageSource messageSource) {
-    return new SpringExtension(messageSource);
+  public SpringExtension springExtension() {
+    return new SpringExtension();
   }
 
   @Bean
@@ -61,9 +62,10 @@ public class MVCConfig {
 
   @Bean
   public ViewResolver viewResolver(PebbleEngine pebbleEngine) {
-    PebbleViewResolver viewResolver = new PebbleViewResolver(pebbleEngine);
+    PebbleViewResolver viewResolver = new PebbleViewResolver();
     viewResolver.setPrefix("com/mitchellbosecke/pebble/spring/template/");
     viewResolver.setSuffix(".html");
+    viewResolver.setPebbleEngine(pebbleEngine);
     viewResolver.setContentType("text/html");
     return viewResolver;
   }
diff --git a/pebble/src/test/java/com/mitchellbosecke/pebble/IncludeWithParameterTest.java b/pebble/src/test/java/com/mitchellbosecke/pebble/IncludeWithParameterTest.java
index 1e8c6d3c..eff1c657 100644
--- a/pebble/src/test/java/com/mitchellbosecke/pebble/IncludeWithParameterTest.java
+++ b/pebble/src/test/java/com/mitchellbosecke/pebble/IncludeWithParameterTest.java
@@ -1,17 +1,15 @@
 package com.mitchellbosecke.pebble;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
 import com.mitchellbosecke.pebble.error.PebbleException;
 import com.mitchellbosecke.pebble.template.PebbleTemplate;
-
-import org.junit.jupiter.api.Test;
-
 import java.io.IOException;
 import java.io.StringWriter;
 import java.io.Writer;
 import java.util.HashMap;
 import java.util.Map;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
+import org.junit.jupiter.api.Test;
 
 /**
  * This class tests if includes with parameters work.
@@ -59,4 +57,23 @@ class IncludeWithParameterTest {
 
   }
 
+  @Test
+  void testIncludeWithParameterObject() throws PebbleException, IOException {
+
+    PebbleEngine pebble = new PebbleEngine.Builder().strictVariables(false).build();
+    PebbleTemplate template = pebble
+        .getTemplate("templates/template.includeWithParameterObject1.peb");
+    Map<String, Object> context = new HashMap<>();
+    context.put("object", new TestObject());
+
+    Writer writer = new StringWriter();
+    template.evaluate(writer, context);
+
+    assertEquals("Hello title", writer.toString());
+  }
+
+  public static class TestObject {
+
+    public String title = "title";
+  }
 }
diff --git a/pebble/src/test/resources/templates/template.includeWithParameterObject1.peb b/pebble/src/test/resources/templates/template.includeWithParameterObject1.peb
new file mode 100644
index 00000000..5fd7e33e
--- /dev/null
+++ b/pebble/src/test/resources/templates/template.includeWithParameterObject1.peb
@@ -0,0 +1,2 @@
+{# used by IncludeWithParameterTest.testIncludeWithParameterObject #}
+{% include './template.includeWithParameterObject2.peb' with { 'sub' : object } %}
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/template.includeWithParameterObject2.peb b/pebble/src/test/resources/templates/template.includeWithParameterObject2.peb
new file mode 100644
index 00000000..03f7c5f9
--- /dev/null
+++ b/pebble/src/test/resources/templates/template.includeWithParameterObject2.peb
@@ -0,0 +1,1 @@
+Hello {{ sub.title }}
\ No newline at end of file