/** * Parse the given string into a root Node, and then renders it processing extend parents. * * @param template * string to parse * @return rendered result */ public String render(String template) { ENGINE_LOG.debug(template); return render(parse(template), true); }
@Test public void itResolvesAllForExpressionsInValidationMode() { validatingInterpreter.render( "{{ badCode( }}" + "{% for i in [1, 2, 3] %}" + " {{ badCode( }}" + "{% endfor %}"); assertThat(validatingInterpreter.getErrors().size()).isEqualTo(4); }
@Override public String interpret(TagNode tagNode, JinjavaInterpreter interpreter) { String macroExpr = "{{" + tagNode.getHelpers().trim() + "}}"; try (InterpreterScopeClosable c = interpreter.enterScope()) { LinkedHashMap<String, Object> args = new LinkedHashMap<>(); MacroFunction caller = new MacroFunction(tagNode.getChildren(), "caller", args, false, false, true, interpreter.getContext()); interpreter.getContext().addGlobalMacro(caller); return interpreter.render(macroExpr); } }
@Test public void itBlocksDisabledTags() { Map<Context.Library, Set<String>> disabled = ImmutableMap.of(Context.Library.TAG, ImmutableSet.of("raw")); assertThat(interpreter.render("{% raw %}foo{% endraw %}")).isEqualTo("foo"); try (JinjavaInterpreter.InterpreterScopeClosable c = interpreter.enterScope(disabled)) { interpreter.render("{% raw %} foo {% endraw %}"); } TemplateError e = interpreter.getErrorsCopy().get(0); assertThat(e.getItem()).isEqualTo(ErrorItem.TAG); assertThat(e.getReason()).isEqualTo(ErrorReason.DISABLED); assertThat(e.getMessage()).contains("'raw' is disabled in this context"); }
@Test public void testSimpleFn() { Document dom = Jsoup.parseBodyFragment(interpreter.render(fixture("simple"))); assertThat(dom.select("div h2").text().trim()).isEqualTo("Hello World"); assertThat(dom.select("div.contents").text().trim()).isEqualTo("This is a simple dialog rendered by using a macro and a call block."); }
@Test public void itAllowsMacrosCallingMacrosUsingCall() throws IOException { String template = fixtureText("macros-calling-macros"); String out = interpreter.render(template); assertThat(interpreter.getErrorsCopy()).isEmpty(); assertThat(out).contains("Hello World One"); assertThat(out).contains("Hello World Two"); }
@Test public void itPreservesInnerWhiteSpace() throws Exception { String expression = "{% for foo in [1,2,3] -%}\nL{% if true %}\n{{ foo }}\n{% endif %}R\n{%- endfor %}"; final Node tree = new TreeParser(interpreter, expression).buildTree(); assertThat(interpreter.render(tree)).isEqualTo("L\n1\nRL\n2\nRL\n3\nR"); }
@Test public void itStripsLeftWhiteSpaceBeforeTag() throws Exception { String expression = ".\n {%- for foo in [1,2,3] %} {{ foo }} {% endfor %} \n."; final Node tree = new TreeParser(interpreter, expression).buildTree(); assertThat(interpreter.render(tree)).isEqualTo(". 1 2 3 \n."); }
@Test public void itStripsAllOuterWhiteSpace() throws Exception { String expression = ".\n {%- for foo in [1,2,3] -%} {{ foo }} {%- endfor -%} \n."; final Node tree = new TreeParser(interpreter, expression).buildTree(); assertThat(interpreter.render(tree)).isEqualTo(".123."); }
@Test public void itStripsLeftAndRightWhiteSpace() throws Exception { String expression = "{% for foo in [1,2,3] -%} \n .{{ foo }}. \n {%- endfor %}"; final Node tree = new TreeParser(interpreter, expression).buildTree(); assertThat(interpreter.render(tree)).isEqualTo(".1..2..3."); }
@Test public void itStripsLeftWhiteSpace() throws Exception { String expression = "{% for foo in [1,2,3] %}\n{{ foo }}. \n {%- endfor %}"; final Node tree = new TreeParser(interpreter, expression).buildTree(); assertThat(interpreter.render(tree)).isEqualTo("\n1.\n2.\n3."); }
@Test public void itPreventsIndirectMacroRecursion() throws IOException { String template = fixtureText("recursion_indirect"); interpreter.render(template); assertThat(interpreter.getErrorsCopy().get(0).getMessage()).contains("Cycle detected for macro 'goodbye'"); }
@Test public void itPreventsDirectMacroRecursion() throws IOException { String template = fixtureText("recursion"); interpreter.render(template); assertThat(interpreter.getErrorsCopy().get(0).getMessage()).contains("Cycle detected for macro 'hello'"); }
@Test public void itAvoidsNestedImportCycle() throws IOException { Jinjava jinjava = new Jinjava(); interpreter = new JinjavaInterpreter(jinjava, context, jinjava.getGlobalConfig()); interpreter.render(Resources.toString(Resources.getResource("tags/importtag/a-imports-b.jinja"), StandardCharsets.UTF_8)); assertThat(context.get("a")).isEqualTo("foo"); assertThat(context.get("b")).isEqualTo("bar"); assertThat(interpreter.getErrorsCopy().get(0).getMessage()).contains("Rendering cycle detected:", "b-imports-a.jinja"); }
@Test public void itAvoidsSimpleImportCycle() throws IOException { Jinjava jinjava = new Jinjava(); interpreter = new JinjavaInterpreter(jinjava, context, jinjava.getGlobalConfig()); interpreter.render(Resources.toString(Resources.getResource("tags/importtag/imports-self.jinja"), StandardCharsets.UTF_8)); assertThat(context.get("c")).isEqualTo("hello"); assertThat(interpreter.getErrorsCopy().get(0).getMessage()).contains("Rendering cycle detected:", "imports-self.jinja"); }
@Test public void resolveBlockStubsWithSpecialChars() { interpreter.addBlock("foobar", Lists.newLinkedList(Lists.newArrayList(new TextNode(new TextToken("$150.00", -1, -1))))); String content = "this is {% block foobar %}foobar{% endblock %}!"; assertThat(interpreter.render(content)).isEqualTo("this is $150.00!"); }
@Test public void resolveBlockStubsWithSpecialChars() { interpreter.addBlock("foobar", Lists.newLinkedList(Lists.newArrayList(new TextNode(new TextToken("$150.00", -1, -1))))); String content = "this is {% block foobar %}foobar{% endblock %}!"; assertThat(interpreter.render(content)).isEqualTo("this is $150.00!"); }
@Test public void itFailsOnUnknownTokensVariables() throws Exception { final JinjavaConfig config = JinjavaConfig.newBuilder().withFailOnUnknownTokens(true).build(); JinjavaInterpreter jinjavaInterpreter = new Jinjava(config).newInterpreter(); String jinja = "{{ UnknownToken }}"; Node node = new TreeParser(jinjavaInterpreter, jinja).buildTree(); assertThatThrownBy(() -> jinjavaInterpreter.render(node)) .isInstanceOf(UnknownTokenException.class) .hasMessage("Unknown token found: UnknownToken"); }
@Test public void itFailsOnUnknownTokensWithFilter() throws Exception { final JinjavaConfig config = JinjavaConfig.newBuilder().withFailOnUnknownTokens(true).build(); JinjavaInterpreter jinjavaInterpreter = new Jinjava(config).newInterpreter(); String jinja = "{{ UnknownToken | default('abc') }}"; Node node = new TreeParser(jinjavaInterpreter, jinja).buildTree(); assertThatThrownBy(() -> jinjavaInterpreter.render(node)) .isInstanceOf(UnknownTokenException.class) .hasMessage("Unknown token found: UnknownToken"); }
@Test public void trimAndLstripBlocks() { interpreter = new Jinjava(JinjavaConfig.newBuilder().withLstripBlocks(true).withTrimBlocks(true).build()).newInterpreter(); assertThat(interpreter.render(parse("parse/tokenizer/whitespace-tags.jinja"))) .isEqualTo("<div>\n" + " yay\n" + "</div>\n"); }