package com.hubspot.jinjava.interpret; import static org.assertj.core.api.Assertions.assertThat; import java.time.ZonedDateTime; import java.util.HashMap; import org.junit.Before; import org.junit.Test; import com.google.common.collect.Lists; import com.hubspot.jinjava.Jinjava; import com.hubspot.jinjava.JinjavaConfig; import com.hubspot.jinjava.interpret.JinjavaInterpreter.InterpreterScopeClosable; import com.hubspot.jinjava.interpret.TemplateError.ErrorReason; import com.hubspot.jinjava.tree.TextNode; import com.hubspot.jinjava.tree.parse.TextToken; public class JinjavaInterpreterTest { Jinjava jinjava; JinjavaInterpreter interpreter; @Before public void setup() { jinjava = new Jinjava(); interpreter = jinjava.newInterpreter(); } @Test public void resolveBlockStubsWithNoStubs() { assertThat(interpreter.render("foo")).isEqualTo("foo"); } @Test public void resolveBlockStubsWithMissingNamedBlock() { String content = "this is {% block foobar %}{% endblock %}!"; assertThat(interpreter.render(content)).isEqualTo("this is !"); } @Test public void resolveBlockStubs() throws Exception { interpreter.addBlock("foobar", Lists.newLinkedList(Lists.newArrayList((new TextNode(new TextToken("sparta", -1)))))); String content = "this is {% block foobar %}foobar{% endblock %}!"; assertThat(interpreter.render(content)).isEqualTo("this is sparta!"); } @Test public void resolveBlockStubsWithSpecialChars() throws Exception { interpreter.addBlock("foobar", Lists.newLinkedList(Lists.newArrayList(new TextNode(new TextToken("$150.00", -1))))); String content = "this is {% block foobar %}foobar{% endblock %}!"; assertThat(interpreter.render(content)).isEqualTo("this is $150.00!"); } @Test public void resolveBlockStubsWithCycle() throws Exception { String content = interpreter.render("{% block foo %}{% block foo %}{% endblock %}{% endblock %}"); assertThat(content).isEmpty(); } // Ex VariableChain stuff static class Foo { private String bar; public Foo(String bar) { this.bar = bar; } public String getBar() { return bar; } public String getBarFoo() { return bar; } public String getBarFoo1() { return bar; } } @Test public void singleWordProperty() { assertThat(interpreter.resolveProperty(new Foo("a"), "bar")).isEqualTo("a"); } @Test public void multiWordCamelCase() { assertThat(interpreter.resolveProperty(new Foo("a"), "barFoo")).isEqualTo("a"); } @Test public void multiWordSnakeCase() { assertThat(interpreter.resolveProperty(new Foo("a"), "bar_foo")).isEqualTo("a"); } @Test public void multiWordNumberSnakeCase() { assertThat(interpreter.resolveProperty(new Foo("a"), "bar_foo_1")).isEqualTo("a"); } @Test public void triesBeanMethodFirst() { assertThat(interpreter.resolveProperty(ZonedDateTime.parse("2013-09-19T12:12:12+00:00"), "year") .toString()).isEqualTo("2013"); } @Test public void enterScopeTryFinally() { interpreter.getContext().put("foo", "parent"); interpreter.enterScope(); try { interpreter.getContext().put("foo", "child"); assertThat(interpreter.resolveELExpression("foo", 1)).isEqualTo("child"); } finally { interpreter.leaveScope(); } assertThat(interpreter.resolveELExpression("foo", 1)).isEqualTo("parent"); } @Test public void enterScopeTryWithResources() { interpreter.getContext().put("foo", "parent"); try (InterpreterScopeClosable c = interpreter.enterScope()) { interpreter.getContext().put("foo", "child"); assertThat(interpreter.resolveELExpression("foo", 1)).isEqualTo("child"); } assertThat(interpreter.resolveELExpression("foo", 1)).isEqualTo("parent"); } @Test public void bubbleUpDependenciesFromLowerScope() { String dependencyType = "foo"; String dependencyIdentifier = "123"; interpreter.enterScope(); interpreter.getContext().addDependency(dependencyType, dependencyIdentifier); assertThat(interpreter.getContext().getDependencies().get(dependencyType)).contains(dependencyIdentifier); interpreter.leaveScope(); assertThat(interpreter.getContext().getDependencies().get(dependencyType)).contains(dependencyIdentifier); } @Test public void parseWithSyntaxError() { RenderResult result = new Jinjava().renderForResult("{%}", new HashMap<>()); assertThat(result.getErrors()).isNotEmpty(); assertThat(result.getErrors().get(0).getReason()).isEqualTo(ErrorReason.SYNTAX_ERROR); } @Test public void itLimitsOutputSize() throws Exception { JinjavaConfig outputSizeLimitedConfig = JinjavaConfig.newBuilder().withMaxOutputSize(20).build(); String output = "123456789012345678901234567890"; RenderResult renderResult = new Jinjava().renderForResult(output, new HashMap<>()); assertThat(renderResult.getOutput()).isEqualTo(output); assertThat(renderResult.hasErrors()).isFalse(); renderResult = new Jinjava(outputSizeLimitedConfig).renderForResult(output, new HashMap<>()); assertThat(renderResult.getErrors().get(0).getMessage()).contains("OutputTooBigException"); } @Test public void itLimitsOutputSizeWhenSumOfNodeSizesExceedsMax() throws Exception { JinjavaConfig outputSizeLimitedConfig = JinjavaConfig.newBuilder().withMaxOutputSize(19).build(); String input = "1234567890{% block testchild %}1234567890{% endblock %}"; String output = "12345678901234567890"; // Note that this exceeds the max size RenderResult renderResult = new Jinjava().renderForResult(input, new HashMap<>()); assertThat(renderResult.getOutput()).isEqualTo(output); assertThat(renderResult.hasErrors()).isFalse(); renderResult = new Jinjava(outputSizeLimitedConfig).renderForResult(input, new HashMap<>()); assertThat(renderResult.hasErrors()).isTrue(); assertThat(renderResult.getErrors().get(0).getMessage()).contains("OutputTooBigException"); } }