You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@freemarker.apache.org by dd...@apache.org on 2017/05/14 10:52:45 UTC
[02/51] [partial] incubator-freemarker git commit: Migrated from Ant
to Gradle, and modularized the project. This is an incomplete migration;
there are some TODO-s in the build scripts, and release related tasks are
still missing. What works: Building th
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3fd56062/freemarker-core/src/test/java/org/apache/freemarker/core/IncludeAndImportTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/IncludeAndImportTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/IncludeAndImportTest.java
new file mode 100644
index 0000000..fa767ff
--- /dev/null
+++ b/freemarker-core/src/test/java/org/apache/freemarker/core/IncludeAndImportTest.java
@@ -0,0 +1,270 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.freemarker.core;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+import org.apache.freemarker.core.Environment.LazilyInitializedNamespace;
+import org.apache.freemarker.core.Environment.Namespace;
+import org.apache.freemarker.core.model.WrappingTemplateModel;
+import org.apache.freemarker.test.TemplateTest;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+@SuppressWarnings("boxing")
+public class IncludeAndImportTest extends TemplateTest {
+
+ @Override
+ protected void addCommonTemplates() {
+ addTemplate("inc1.ftl", "[inc1]<#global inc1Cnt = (inc1Cnt!0) + 1><#global history = (history!) + 'I'>");
+ addTemplate("inc2.ftl", "[inc2]");
+ addTemplate("inc3.ftl", "[inc3]");
+ addTemplate("lib1.ftl", "<#global lib1Cnt = (lib1Cnt!0) + 1><#global history = (history!) + 'L1'>"
+ + "<#macro m>In lib1</#macro>");
+ addTemplate("lib2.ftl", "<#global history = (history!) + 'L2'>"
+ + "<#macro m>In lib2</#macro>");
+ addTemplate("lib3.ftl", "<#global history = (history!) + 'L3'>"
+ + "<#macro m>In lib3</#macro>");
+
+ addTemplate("lib2CallsLib1.ftl", "<#global history = (history!) + 'L2'>"
+ + "<#macro m>In lib2 (<@lib1.m/>)</#macro>");
+ addTemplate("lib3ImportsLib1.ftl", "<#import 'lib1.ftl' as lib1><#global history = (history!) + 'L3'>"
+ + "<#macro m>In lib3 (<@lib1.m/>)</#macro>");
+
+ addTemplate("lib_de.ftl", "<#global history = (history!) + 'LDe'><#assign initLocale=.locale>"
+ + "<#macro m>de</#macro>");
+ addTemplate("lib_en.ftl", "<#global history = (history!) + 'LEn'><#assign initLocale=.locale>"
+ + "<#macro m>en</#macro>");
+ }
+
+ @Test
+ public void includeSameTwice() throws IOException, TemplateException {
+ assertOutput("<#include 'inc1.ftl'>${inc1Cnt}<#include 'inc1.ftl'>${inc1Cnt}", "[inc1]1[inc1]2");
+ }
+
+ @Test
+ public void importSameTwice() throws IOException, TemplateException {
+ assertOutput("<#import 'lib1.ftl' as i1>${lib1Cnt} <#import 'lib1.ftl' as i2>${lib1Cnt}", "1 1");
+ }
+
+ @Test
+ public void importInMainCreatesGlobal() throws IOException, TemplateException {
+ String ftl = "${.main.lib1???c} ${.globals.lib1???c}"
+ + "<#import 'lib1.ftl' as lib1> ${.main.lib1???c} ${.globals.lib1???c}";
+ String expectedOut = "false false true true";
+ assertOutput(ftl, expectedOut);
+ }
+
+ @Test
+ public void importInMainCreatesGlobalBugfix() throws IOException, TemplateException {
+ // An import in the main namespace should invoke a global variable, even if the imported library was already
+ // initialized elsewhere.
+ String ftl = "<#import 'lib3ImportsLib1.ftl' as lib3>${lib1Cnt} ${.main.lib1???c} ${.globals.lib1???c}, "
+ + "<#import 'lib1.ftl' as lib1>${lib1Cnt} ${.main.lib1???c} ${.globals.lib1???c}";
+ assertOutput(ftl, "1 false false, 1 true true");
+ }
+
+ /**
+ * Tests the order of auto-includes and auto-imports, also that they only effect the main template directly.
+ */
+ @Test
+ public void autoIncludeAndAutoImport() throws IOException, TemplateException {
+ setConfiguration(new TestConfigurationBuilder()
+ .autoImports(ImmutableMap.of(
+ "lib1", "lib1.ftl",
+ "lib2", "lib2CallsLib1.ftl"
+ ))
+ .autoIncludes(ImmutableList.of(
+ "inc1.ftl",
+ "inc2.ftl"))
+ .build());
+ assertOutput(
+ "<#include 'inc3.ftl'>[main] ${inc1Cnt}, ${history}, <@lib1.m/>, <@lib2.m/>",
+ "[inc1][inc2][inc3][main] 1, L1L2I, In lib1, In lib2 (In lib1)");
+ }
+
+ /**
+ * Demonstrates design issue in FreeMarker 2.3.x where the lookupStrategy is not factored in when identifying
+ * already existing namespaces.
+ */
+ @Test
+ public void lookupSrategiesAreNotConsideredProperly() throws IOException, TemplateException {
+ // As only the name of the template is used for the finding the already existing namespace, the settings that
+ // influence the lookup are erroneously ignored.
+ assertOutput(
+ "<#setting locale='en_US'><#import 'lib.ftl' as ns1>"
+ + "<#setting locale='de_DE'><#import 'lib.ftl' as ns2>"
+ + "<@ns1.m/> <@ns2.m/> ${history}",
+ "en en LEn");
+
+ // The opposite of the prevous, where differn names refer to the same template after a lookup:
+ assertOutput(
+ "<#setting locale='en_US'>"
+ + "<#import '*/lib.ftl' as ns1>"
+ + "<#import 'lib.ftl' as ns2>"
+ + "<@ns1.m/> <@ns2.m/> ${history}",
+ "en en LEnLEn");
+ }
+
+ @Test
+ public void lazyImportBasics() throws IOException, TemplateException {
+ String ftlImports = "<#import 'lib1.ftl' as l1><#import 'lib2.ftl' as l2><#import 'lib3ImportsLib1.ftl' as l3>";
+ String ftlCalls = "<@l2.m/>, <@l1.m/>; ${history}";
+ String ftl = ftlImports + ftlCalls;
+
+ assertOutput(ftl, "In lib2, In lib1; L1L2L3");
+
+ setConfiguration(new TestConfigurationBuilder().lazyImports(true).build());
+ assertOutput(ftl, "In lib2, In lib1; L2L1");
+
+ assertOutput(ftlImports + "<@l3.m/>, " + ftlCalls, "In lib3 (In lib1), In lib2, In lib1; L3L1L2");
+ }
+
+ @Test
+ public void lazyImportAndLocale() throws IOException, TemplateException {
+ setConfiguration(new TestConfigurationBuilder().lazyImports(true).build());
+ assertOutput("<#setting locale = 'de_DE'><#import 'lib.ftl' as lib>"
+ + "[${history!}] "
+ + "<#setting locale = 'en'>"
+ + "<@lib.m/> ${lib.initLocale} [${history}]",
+ "[] de de_DE [LDe]");
+ }
+
+ @Test
+ public void lazyAutoImportSettings() throws IOException, TemplateException {
+ TestConfigurationBuilder cfgB = new TestConfigurationBuilder()
+ .autoImports(ImmutableMap.of(
+ "l1", "lib1.ftl",
+ "l2", "lib2.ftl",
+ "l3", "lib3.ftl"
+ ));
+
+ String ftl = "<@l2.m/>, <@l1.m/>; ${history}";
+ String expectedEagerOutput = "In lib2, In lib1; L1L2L3";
+ String expecedLazyOutput = "In lib2, In lib1; L2L1";
+
+ setConfiguration(cfgB.build());
+ assertOutput(ftl, expectedEagerOutput);
+ cfgB.setLazyImports(true);
+ setConfiguration(cfgB.build());
+ assertOutput(ftl, expecedLazyOutput);
+ cfgB.setLazyImports(false);
+ setConfiguration(cfgB.build());
+ assertOutput(ftl, expectedEagerOutput);
+ cfgB.setLazyAutoImports(true);
+ setConfiguration(cfgB.build());
+ assertOutput(ftl, expecedLazyOutput);
+ cfgB.setLazyAutoImports(null);
+ setConfiguration(cfgB.build());
+ assertOutput(ftl, expectedEagerOutput);
+ cfgB.setLazyImports(true);
+ cfgB.setLazyAutoImports(false);
+ setConfiguration(cfgB.build());
+ assertOutput(ftl, expectedEagerOutput);
+ }
+
+ @Test
+ public void lazyAutoImportMixedWithManualImport() throws IOException, TemplateException {
+ TestConfigurationBuilder cfgB = new TestConfigurationBuilder()
+ .autoImports(ImmutableMap.of(
+ "l1", "lib1.ftl",
+ "l2", "/./lib2.ftl",
+ "l3", "lib3.ftl"))
+ .lazyAutoImports(true);
+
+ String ftl = "<@l2.m/>, <@l1.m/>; ${history}";
+ String expectOutputWithoutHistory = "In lib2, In lib1; ";
+ String expecedOutput = expectOutputWithoutHistory + "L2L1";
+
+ setConfiguration(cfgB.build());
+ assertOutput(ftl, expecedOutput);
+ assertOutput("<#import 'lib1.ftl' as l1>" + ftl, expectOutputWithoutHistory + "L1L2");
+ assertOutput("<#import './x/../lib1.ftl' as l1>" + ftl, expectOutputWithoutHistory + "L1L2");
+ assertOutput("<#import 'lib2.ftl' as l2>" + ftl, expecedOutput);
+ assertOutput("<#import 'lib3.ftl' as l3>" + ftl, expectOutputWithoutHistory + "L3L2L1");
+
+ cfgB.setLazyImports(true);
+ setConfiguration(cfgB.build());
+ assertOutput("<#import 'lib1.ftl' as l1>" + ftl, expecedOutput);
+ assertOutput("<#import './x/../lib1.ftl' as l1>" + ftl, expecedOutput);
+ assertOutput("<#import 'lib2.ftl' as l2>" + ftl, expecedOutput);
+ assertOutput("<#import 'lib3.ftl' as l3>" + ftl, expecedOutput);
+ }
+
+ @Test
+ public void lazyImportErrors() throws IOException, TemplateException {
+ TestConfigurationBuilder cfgB = new TestConfigurationBuilder();
+ cfgB.setLazyImports(true);
+
+ setConfiguration(cfgB.build());
+ assertOutput("<#import 'noSuchTemplate.ftl' as wrong>x", "x");
+
+ cfgB.addAutoImport("wrong", "noSuchTemplate.ftl");
+ setConfiguration(cfgB.build());
+ assertOutput("x", "x");
+
+ try {
+ assertOutput("${wrong.x}", "");
+ fail();
+ } catch (TemplateException e) {
+ assertThat(e.getMessage(),
+ allOf(containsString("Lazy initialization"), containsString("noSuchTemplate.ftl")));
+ assertThat(e.getCause(), instanceOf(TemplateNotFoundException.class));
+ }
+
+ addTemplate("containsError.ftl", "${noSuchVar}");
+ try {
+ assertOutput("<#import 'containsError.ftl' as lib>${lib.x}", "");
+ fail();
+ } catch (TemplateException e) {
+ assertThat(e.getMessage(),
+ allOf(containsString("Lazy initialization"), containsString("containsError.ftl")));
+ assertThat(e.getCause(), instanceOf(InvalidReferenceException.class));
+ assertThat(e.getCause().getMessage(), containsString("noSuchVar"));
+ }
+ }
+
+ /**
+ * Ensures that all methods are overridden so that they will do the lazy initialization.
+ */
+ @Test
+ public void lazilyInitializingNamespaceOverridesAll() throws SecurityException, NoSuchMethodException {
+ for (Method m : Namespace.class.getMethods()) {
+ Class<?> declClass = m.getDeclaringClass();
+ if (declClass == Object.class || declClass == WrappingTemplateModel.class
+ || (m.getModifiers() & Modifier.STATIC) != 0
+ || m.getName().equals("synchronizedWrapper")) {
+ continue;
+ }
+ Method lazyM = LazilyInitializedNamespace.class.getMethod(m.getName(), m.getParameterTypes());
+ if (lazyM.getDeclaringClass() != LazilyInitializedNamespace.class) {
+ fail("The " + lazyM + " method wasn't overidden in " + LazilyInitializedNamespace.class.getName());
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3fd56062/freemarker-core/src/test/java/org/apache/freemarker/core/IncudeFromNamelessTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/IncudeFromNamelessTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/IncudeFromNamelessTest.java
new file mode 100644
index 0000000..f4908b8
--- /dev/null
+++ b/freemarker-core/src/test/java/org/apache/freemarker/core/IncudeFromNamelessTest.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.freemarker.core;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+import org.apache.freemarker.core.templateresolver.impl.StringTemplateLoader;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+
+import junit.framework.TestCase;
+
+public class IncudeFromNamelessTest extends TestCase {
+
+ public IncudeFromNamelessTest(String name) {
+ super(name);
+ }
+
+ public void test() throws IOException, TemplateException {
+ StringTemplateLoader loader = new StringTemplateLoader();
+ loader.putTemplate("i.ftl", "[i]");
+ loader.putTemplate("sub/i.ftl", "[sub/i]");
+ loader.putTemplate("import.ftl", "<#assign x = 1>");
+
+ Configuration cfg = new TestConfigurationBuilder().templateLoader(loader).build();
+
+ Template t = new Template(null, new StringReader(
+ "<#include 'i.ftl'>\n"
+ + "<#include '/i.ftl'>\n"
+ + "<#include 'sub/i.ftl'>\n"
+ + "<#include '/sub/i.ftl'>"
+ + "<#import 'import.ftl' as i>${i.x}"
+ ),
+ cfg);
+ StringWriter out = new StringWriter();
+ t.process(null, out);
+ assertEquals("[i][i][sub/i][sub/i]1", out.toString());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3fd56062/freemarker-core/src/test/java/org/apache/freemarker/core/InterpretAndEvalTemplateNameTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/InterpretAndEvalTemplateNameTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/InterpretAndEvalTemplateNameTest.java
new file mode 100644
index 0000000..ff5897f
--- /dev/null
+++ b/freemarker-core/src/test/java/org/apache/freemarker/core/InterpretAndEvalTemplateNameTest.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.freemarker.core;
+
+import java.io.IOException;
+
+import org.apache.freemarker.core.templateresolver.impl.StringTemplateLoader;
+import org.apache.freemarker.test.TemplateTest;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+import org.junit.Test;
+
+/**
+ * Test template names returned by special variables and relative path resolution in {@code ?interpret}-ed and
+ * {@code ?eval}-ed parts.
+ */
+public class InterpretAndEvalTemplateNameTest extends TemplateTest {
+
+ @Test
+ public void testInterpret() throws IOException, TemplateException {
+ for (String getTemplateNames : new String[] {
+ "c=${.current_template_name}, m=${.main_template_name}",
+ "c=${\".current_template_name\"?eval}, m=${\".main_template_name\"?eval}"
+ }) {
+ StringTemplateLoader tl = new StringTemplateLoader();
+ tl.putTemplate(
+ "main.ftl",
+ getTemplateNames + " "
+ + "{<#include 'sub/t.ftl'>}");
+ tl.putTemplate(
+ "sub/t.ftl",
+ getTemplateNames + " "
+ + "i{<@r'" + getTemplateNames + " {<#include \"a.ftl\">'?interpret />}} "
+ + "i{<@[r'" + getTemplateNames + " {<#include \"a.ftl\">','named_interpreted']?interpret />}}");
+ tl.putTemplate("sub/a.ftl", "In sub/a.ftl, " + getTemplateNames);
+ tl.putTemplate("a.ftl", "In a.ftl");
+
+ setConfiguration(new TestConfigurationBuilder().templateLoader(tl).build());
+
+ assertOutputForNamed("main.ftl",
+ "c=main.ftl, m=main.ftl "
+ + "{"
+ + "c=sub/t.ftl, m=main.ftl "
+ + "i{c=sub/t.ftl->anonymous_interpreted, m=main.ftl {In sub/a.ftl, c=sub/a.ftl, m=main.ftl}} "
+ + "i{c=sub/t.ftl->named_interpreted, m=main.ftl {In sub/a.ftl, c=sub/a.ftl, m=main.ftl}}"
+ + "}");
+
+ assertOutputForNamed("sub/t.ftl",
+ "c=sub/t.ftl, m=sub/t.ftl "
+ + "i{c=sub/t.ftl->anonymous_interpreted, m=sub/t.ftl {In sub/a.ftl, c=sub/a.ftl, m=sub/t.ftl}} "
+ + "i{c=sub/t.ftl->named_interpreted, m=sub/t.ftl {In sub/a.ftl, c=sub/a.ftl, m=sub/t.ftl}}");
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3fd56062/freemarker-core/src/test/java/org/apache/freemarker/core/InterpretSettingInheritanceTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/InterpretSettingInheritanceTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/InterpretSettingInheritanceTest.java
new file mode 100644
index 0000000..2d061d7
--- /dev/null
+++ b/freemarker-core/src/test/java/org/apache/freemarker/core/InterpretSettingInheritanceTest.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.freemarker.core;
+
+import java.io.IOException;
+
+import org.apache.freemarker.test.TemplateTest;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+import org.junit.Test;
+
+/**
+ * The {@code interpret} built-in must not consider the settings or established auto-detected syntax of the surrounding
+ * template. It can only depend on the {@link Configuration}.
+ */
+public class InterpretSettingInheritanceTest extends TemplateTest {
+
+ private static final String FTL_A_S_A = "<#ftl><@'[#if true]s[/#if]<#if true>a</#if>'?interpret />";
+ private static final String FTL_A_A_S = "<#ftl><@'<#if true>a</#if>[#if true]s[/#if]'?interpret />";
+ private static final String FTL_S_S_A = "[#ftl][@'[#if true]s[/#if]<#if true>a</#if>'?interpret /]";
+ private static final String FTL_S_A_S = "[#ftl][@'<#if true>a</#if>[#if true]s[/#if]'?interpret /]";
+ private static final String OUT_S_A_WHEN_SYNTAX_IS_S = "s<#if true>a</#if>";
+ private static final String OUT_S_A_WHEN_SYNTAX_IS_A = "[#if true]s[/#if]a";
+ private static final String OUT_A_S_WHEN_SYNTAX_IS_A = "a[#if true]s[/#if]";
+ private static final String OUT_A_S_WHEN_SYNTAX_IS_S = "<#if true>a</#if>s";
+
+ @Test
+ public void tagSyntaxTest() throws IOException, TemplateException {
+ setConfiguration(new TestConfigurationBuilder()
+ .tagSyntax(ParsingConfiguration.ANGLE_BRACKET_TAG_SYNTAX)
+ .build());
+ assertOutput(FTL_S_A_S, OUT_A_S_WHEN_SYNTAX_IS_A);
+ assertOutput(FTL_S_S_A, OUT_S_A_WHEN_SYNTAX_IS_A);
+ assertOutput(FTL_A_A_S, OUT_A_S_WHEN_SYNTAX_IS_A);
+ assertOutput(FTL_A_S_A, OUT_S_A_WHEN_SYNTAX_IS_A);
+
+ setConfiguration(new TestConfigurationBuilder()
+ .tagSyntax(ParsingConfiguration.SQUARE_BRACKET_TAG_SYNTAX)
+ .build());
+ assertOutput(FTL_S_A_S, OUT_A_S_WHEN_SYNTAX_IS_S);
+ assertOutput(FTL_S_S_A, OUT_S_A_WHEN_SYNTAX_IS_S);
+ assertOutput(FTL_A_A_S, OUT_A_S_WHEN_SYNTAX_IS_S);
+ assertOutput(FTL_A_S_A, OUT_S_A_WHEN_SYNTAX_IS_S);
+
+ setConfiguration(new TestConfigurationBuilder()
+ .tagSyntax(ParsingConfiguration.AUTO_DETECT_TAG_SYNTAX)
+ .build());
+ assertOutput(FTL_S_A_S, OUT_A_S_WHEN_SYNTAX_IS_A);
+ assertOutput(FTL_S_S_A, OUT_S_A_WHEN_SYNTAX_IS_S);
+ assertOutput(FTL_A_A_S, OUT_A_S_WHEN_SYNTAX_IS_A);
+ assertOutput(FTL_A_S_A, OUT_S_A_WHEN_SYNTAX_IS_S);
+ assertOutput("<@'[#ftl]x'?interpret />[#if true]y[/#if]", "x[#if true]y[/#if]");
+ }
+
+ @Test
+ public void whitespaceStrippingTest() throws IOException, TemplateException {
+ Configuration cfg = getConfiguration();
+
+ setConfiguration(new TestConfigurationBuilder()
+ .whitespaceStripping(true)
+ .build());
+ assertOutput("<#assign x = 1>\nX<@'<#assign x = 1>\\nY'?interpret />", "XY");
+ assertOutput("<#ftl stripWhitespace=false><#assign x = 1>\nX<@'<#assign x = 1>\\nY'?interpret />", "\nXY");
+ assertOutput("<#assign x = 1>\nX<@'<#ftl stripWhitespace=false><#assign x = 1>\\nY'?interpret />", "X\nY");
+
+ setConfiguration(new TestConfigurationBuilder()
+ .whitespaceStripping(false)
+ .build());
+ assertOutput("<#assign x = 1>\nX<@'<#assign x = 1>\\nY'?interpret />", "\nX\nY");
+ assertOutput("<#ftl stripWhitespace=true><#assign x = 1>\nX<@'<#assign x = 1>\\nY'?interpret />", "X\nY");
+ assertOutput("<#assign x = 1>\nX<@'<#ftl stripWhitespace=true><#assign x = 1>\\nY'?interpret />", "\nXY");
+ }
+
+ @Test
+ public void evalTest() throws IOException, TemplateException {
+ setConfiguration(new TestConfigurationBuilder()
+ .tagSyntax(ParsingConfiguration.ANGLE_BRACKET_TAG_SYNTAX)
+ .build());
+ assertOutput("<@'\"[#if true]s[/#if]<#if true>a</#if>\"?interpret'?eval />", OUT_S_A_WHEN_SYNTAX_IS_A);
+ assertOutput("[#ftl][@'\"[#if true]s[/#if]<#if true>a</#if>\"?interpret'?eval /]", OUT_S_A_WHEN_SYNTAX_IS_A);
+
+ setConfiguration(new TestConfigurationBuilder()
+ .tagSyntax(ParsingConfiguration.SQUARE_BRACKET_TAG_SYNTAX)
+ .build());
+ assertOutput("[@'\"[#if true]s[/#if]<#if true>a</#if>\"?interpret'?eval /]", OUT_S_A_WHEN_SYNTAX_IS_S);
+ assertOutput("<#ftl><@'\"[#if true]s[/#if]<#if true>a</#if>\"?interpret'?eval />", OUT_S_A_WHEN_SYNTAX_IS_S);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3fd56062/freemarker-core/src/test/java/org/apache/freemarker/core/IteratorIssuesTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/IteratorIssuesTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/IteratorIssuesTest.java
new file mode 100644
index 0000000..08fcee2
--- /dev/null
+++ b/freemarker-core/src/test/java/org/apache/freemarker/core/IteratorIssuesTest.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.freemarker.core;
+
+import java.util.Arrays;
+import java.util.Iterator;
+
+import org.apache.freemarker.core.model.impl.DefaultObjectWrapper;
+import org.apache.freemarker.test.TemplateTest;
+import org.junit.Test;
+
+public class IteratorIssuesTest extends TemplateTest {
+
+ private static final DefaultObjectWrapper OW = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
+
+ private static final String FTL_HAS_CONTENT_AND_LIST
+ = "<#if it?hasContent><#list it as i>${i}</#list><#else>empty</#if>";
+ private static final String OUT_HAS_CONTENT_AND_LIST_ABC = "abc";
+ private static final String OUT_HAS_CONTENT_AND_LIST_EMPTY = "empty";
+
+ private static final String FTL_LIST_AND_HAS_CONTENT
+ = "<#list it as i>${i}${it?hasContent?then('+', '-')}</#list>";
+ private static final String OUT_LIST_AND_HAS_CONTENT_BW_GOOD = "a+b+c-";
+
+ @Test
+ public void testHasContentAndList() throws Exception {
+ addToDataModel("it", OW.wrap(getAbcIt()));
+ assertOutput(FTL_HAS_CONTENT_AND_LIST, OUT_HAS_CONTENT_AND_LIST_ABC);
+
+ addToDataModel("it", OW.wrap(getEmptyIt()));
+ assertOutput(FTL_HAS_CONTENT_AND_LIST, OUT_HAS_CONTENT_AND_LIST_EMPTY);
+ }
+
+ @Test
+ public void testListAndHasContent() throws Exception {
+ addToDataModel("it", OW.wrap(getAbcIt()));
+ assertErrorContains(FTL_LIST_AND_HAS_CONTENT, "can be listed only once");
+ }
+
+ private Iterator getAbcIt() {
+ return Arrays.asList(new String[] { "a", "b", "c" }).iterator();
+ }
+
+ private Iterator getEmptyIt() {
+ return Arrays.asList(new String[] { }).iterator();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3fd56062/freemarker-core/src/test/java/org/apache/freemarker/core/JavaCCExceptionAsEOFFixTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/JavaCCExceptionAsEOFFixTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/JavaCCExceptionAsEOFFixTest.java
new file mode 100644
index 0000000..0fa3f79
--- /dev/null
+++ b/freemarker-core/src/test/java/org/apache/freemarker/core/JavaCCExceptionAsEOFFixTest.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.freemarker.core;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.io.Reader;
+
+import org.apache.freemarker.test.TestConfigurationBuilder;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * JavaCC suppresses exceptions thrown by the Reader, silently treating them as EOF. To be precise, JavaCC 3.2 only does
+ * that with {@link IOException}-s, while JavaCC 6 does that for all {@link Exception}-s. This tests FreeMarker's
+ * workaround for this problem.
+ */
+public class JavaCCExceptionAsEOFFixTest {
+
+ public static class FailingReader extends Reader {
+
+ private static final String CONTENT = "abc";
+
+ private final Throwable exceptionToThrow;
+ private int readSoFar;
+
+ protected FailingReader(Throwable exceptionToThrow) {
+ this.exceptionToThrow = exceptionToThrow;
+ }
+
+ @Override
+ public int read() throws IOException {
+ if (readSoFar == CONTENT.length()) {
+ if (exceptionToThrow != null) {
+ throwException();
+ } else {
+ return -1;
+ }
+ }
+ return CONTENT.charAt(readSoFar++);
+ }
+
+ private void throwException() throws IOException {
+ if (exceptionToThrow instanceof IOException) {
+ throw (IOException) exceptionToThrow;
+ }
+ if (exceptionToThrow instanceof RuntimeException) {
+ throw (RuntimeException) exceptionToThrow;
+ }
+ if (exceptionToThrow instanceof Error) {
+ throw (Error) exceptionToThrow;
+ }
+ Assert.fail();
+ }
+
+ @Override
+ public void close() throws IOException {
+ // nop
+ }
+
+ @Override
+ public int read(char[] cbuf, int off, int len) throws IOException {
+ for (int i = 0; i < len; i++) {
+ int c = read();
+ if (c == -1) return i == 0 ? -1 : i;
+ cbuf[off + i] = (char) c;
+ }
+ return len;
+ }
+
+ }
+
+ @Test
+ public void testIOException() throws IOException {
+ try {
+ new Template(null, new FailingReader(new IOException("test")), new TestConfigurationBuilder().build());
+ fail();
+ } catch (IOException e) {
+ assertEquals("test", e.getMessage());
+ }
+ }
+
+ @Test
+ public void testRuntimeException() throws IOException {
+ try {
+ new Template(null, new FailingReader(new NullPointerException("test")), new TestConfigurationBuilder().build());
+ fail();
+ } catch (NullPointerException e) {
+ assertEquals("test", e.getMessage());
+ }
+ }
+
+ @Test
+ public void testError() throws IOException {
+ try {
+ new Template(null, new FailingReader(new OutOfMemoryError("test")), new TestConfigurationBuilder().build());
+ fail();
+ } catch (OutOfMemoryError e) {
+ assertEquals("test", e.getMessage());
+ }
+ }
+
+ @Test
+ public void testNoException() throws IOException {
+ Template t = new Template(null, new FailingReader(null), new TestConfigurationBuilder().build());
+ assertEquals("abc", t.toString());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3fd56062/freemarker-core/src/test/java/org/apache/freemarker/core/ListErrorsTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/ListErrorsTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/ListErrorsTest.java
new file mode 100644
index 0000000..05bac4f
--- /dev/null
+++ b/freemarker-core/src/test/java/org/apache/freemarker/core/ListErrorsTest.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.freemarker.core;
+
+import java.io.IOException;
+
+import org.apache.freemarker.core.model.impl.DefaultObjectWrapper;
+import org.apache.freemarker.test.TemplateTest;
+import org.apache.freemarker.test.templatesuite.models.Listables;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableMap;
+
+public class ListErrorsTest extends TemplateTest {
+
+ @Test
+ public void testValid() throws IOException, TemplateException {
+ assertOutput("<#list 1..2 as x><#list 3..4>${x}:<#items as x>${x}</#items></#list>;</#list>", "1:34;2:34;");
+ assertOutput("<#list [] as x>${x}<#else><#list 1..2 as x>${x}<#sep>, </#list></#list>", "1, 2");
+ assertOutput("<#macro m>[<#nested 3>]</#macro>"
+ + "<#list 1..2 as x>"
+ + "${x}@${x?index}"
+ + "<@m ; x>"
+ + "${x},"
+ + "<#list 4..4 as x>${x}@${x?index}</#list>"
+ + "</@>"
+ + "${x}@${x?index}; "
+ + "</#list>",
+ "1@0[3,4@0]1@0; 2@1[3,4@0]2@1; ");
+ }
+
+ @Test
+ public void testInvalidItemsParseTime() throws IOException, TemplateException {
+ assertErrorContains("<#items as x>${x}</#items>",
+ "#items", "must be inside", "#list");
+ assertErrorContains("<#list xs><#macro m><#items as x></#items></#macro></#list>",
+ "#items", "must be inside", "#list");
+ assertErrorContains("<#list xs as x><#items as x>${x}</#items></#list>",
+ "#list", "must not have", "#items", "as loopVar");
+ assertErrorContains("<#list xs><#list xs as x><#items as x>${x}</#items></#list></#list>",
+ "#list", "must not have", "#items", "as loopVar");
+ assertErrorContains("<#list xs></#list>",
+ "#list", "must have", "#items", "as loopVar");
+ }
+
+ @Test
+ public void testInvalidSepParseTime() throws IOException, TemplateException {
+ assertErrorContains("<#sep>, </#sep>",
+ "#sep", "must be inside", "#list");
+ assertErrorContains("<#sep>, ",
+ "#sep", "must be inside", "#list");
+ assertErrorContains("<#list xs as x><#else><#sep>, </#list>",
+ "#sep", "must be inside", "#list");
+ assertErrorContains("<#list xs as x><#macro m><#sep>, </#macro></#list>",
+ "#sep", "must be inside", "#list");
+ }
+
+ @Test
+ public void testInvalidItemsRuntime() throws IOException, TemplateException {
+ assertErrorContains("<#list 1..1><#items as x></#items><#items as x></#items></#list>",
+ "#items", "already entered earlier");
+ assertErrorContains("<#list 1..1><#items as x><#items as y>${x}/${y}</#items></#items></#list>",
+ "#items", "Can't nest #items into each other");
+ }
+
+ @Test
+ public void testInvalidLoopVarBuiltinLHO() {
+ assertErrorContains("<#list foos>${foo?index}</#list>",
+ "?index", "foo", "no loop variable");
+ assertErrorContains("<#list foos as foo></#list>${foo?index}",
+ "?index", "foo" , "no loop variable");
+ assertErrorContains("<#list foos as foo><#macro m>${foo?index}</#macro></#list>",
+ "?index", "foo" , "no loop variable");
+ assertErrorContains("<#list foos as foo><#function f>${foo?index}</#function></#list>",
+ "?index", "foo" , "no loop variable");
+ assertErrorContains("<#list xs as x>${foo?index}</#list>",
+ "?index", "foo" , "no loop variable");
+ assertErrorContains("<#list foos as foo><@m; foo>${foo?index}</@></#list>",
+ "?index", "foo" , "user defined directive");
+ assertErrorContains(
+ "<#list foos as foo><@m; foo><@m; foo>${foo?index}</@></@></#list>",
+ "?index", "foo" , "user defined directive");
+ assertErrorContains(
+ "<#list foos as foo><@m; foo>"
+ + "<#list foos as foo><@m; foo>${foo?index}</@></#list>"
+ + "</@></#list>",
+ "?index", "foo" , "user defined directive");
+ }
+
+ @Test
+ public void testKeyValueSameName() {
+ assertErrorContains("<#list {} as foo, foo></#list>",
+ "key", "value", "both" , "foo");
+ }
+
+ @Test
+ public void testCollectionVersusHash() {
+ assertErrorContains("<#list {} as i></#list>",
+ "as k, v");
+ assertErrorContains("<#list [] as k, v></#list>",
+ "only one loop variable");
+ }
+
+ @Test
+ public void testNonEx2NonStringKey() throws IOException, TemplateException {
+ addToDataModel("m", new Listables.NonEx2MapAdapter(ImmutableMap.of("k1", "v1", 2, "v2"),
+ new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build()));
+ assertOutput("<#list m?keys as k>${k};</#list>", "k1;2;");
+ assertErrorContains("<#list m as k, v></#list>",
+ "string", "number", ".TemplateHashModelEx2");
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3fd56062/freemarker-core/src/test/java/org/apache/freemarker/core/MiscErrorMessagesTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/MiscErrorMessagesTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/MiscErrorMessagesTest.java
new file mode 100644
index 0000000..1903e05
--- /dev/null
+++ b/freemarker-core/src/test/java/org/apache/freemarker/core/MiscErrorMessagesTest.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.freemarker.core;
+
+import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormat;
+import org.apache.freemarker.test.TemplateTest;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+import org.junit.Test;
+
+public class MiscErrorMessagesTest extends TemplateTest {
+
+ @Test
+ public void stringIndexOutOfBounds() {
+ assertErrorContains("${'foo'[10]}", "length", "3", "10", "String index out of");
+ }
+
+ @Test
+ public void wrongTemplateNameFormat() {
+ setConfiguration(new TestConfigurationBuilder().templateNameFormat(DefaultTemplateNameFormat.INSTANCE).build());
+
+ assertErrorContains("<#include 'foo:/bar:baaz'>", "Malformed template name", "':'");
+ assertErrorContains("<#include '../baaz'>", "Malformed template name", "root");
+ assertErrorContains("<#include '\u0000'>", "Malformed template name", "\\u0000");
+ }
+
+ @Test
+ public void numericalKeyHint() {
+ assertErrorContains("${{}[10]}", "[]", "?api");
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3fd56062/freemarker-core/src/test/java/org/apache/freemarker/core/MistakenlyPublicImportAPIsTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/MistakenlyPublicImportAPIsTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/MistakenlyPublicImportAPIsTest.java
new file mode 100644
index 0000000..5fcee97
--- /dev/null
+++ b/freemarker-core/src/test/java/org/apache/freemarker/core/MistakenlyPublicImportAPIsTest.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.freemarker.core;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.List;
+
+import org.apache.freemarker.core.Environment.Namespace;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.templateresolver.impl.StringTemplateLoader;
+import org.apache.freemarker.core.util._NullWriter;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+import org.junit.Test;
+
+/**
+ * These are things that users shouldn't do, but we shouldn't break backward compatibility without knowing about it.
+ */
+public class MistakenlyPublicImportAPIsTest {
+
+ @Test
+ public void testImportCopying() throws IOException, TemplateException {
+ StringTemplateLoader tl = new StringTemplateLoader();
+ tl.putTemplate("imp1", "<#macro m>1</#macro>");
+ tl.putTemplate("imp2", "<#assign x = 2><#macro m>${x}</#macro>");
+
+ Configuration cfg = new TestConfigurationBuilder().templateLoader(tl).build();
+
+ Template t1 = new Template(null, "<#import 'imp1' as i1><#import 'imp2' as i2>", cfg);
+ List<ASTDirImport> imports = t1.getImports();
+ assertEquals(2, imports.size());
+
+ {
+ Template t2 = new Template(null, "<@i1.m/><@i2.m/>", cfg);
+ for (ASTDirImport libLoad : imports) {
+ t2.addImport(libLoad);
+ }
+
+ try {
+ t2.process(null, _NullWriter.INSTANCE);
+ fail();
+ } catch (InvalidReferenceException e) {
+ // Apparenly, it has never worked like this...
+ assertEquals("i1", e.getBlamedExpressionString());
+ }
+ }
+
+ // It works this way, though it has nothing to do with the problematic API-s:
+ Environment env = t1.createProcessingEnvironment(null, _NullWriter.INSTANCE);
+ env.process();
+ TemplateModel i1 = env.getVariable("i1");
+ assertThat(i1, instanceOf(Namespace.class));
+ TemplateModel i2 = env.getVariable("i2");
+ assertThat(i2, instanceOf(Namespace.class));
+
+ {
+ Template t2 = new Template(null, "<@i1.m/>", cfg);
+
+ StringWriter sw = new StringWriter();
+ env = t2.createProcessingEnvironment(null, sw);
+ env.setVariable("i1", i1);
+
+ env.process();
+ assertEquals("1", sw.toString());
+ }
+
+ {
+ Template t2 = new Template(null, "<@i2.m/>", cfg);
+
+ StringWriter sw = new StringWriter();
+ env = t2.createProcessingEnvironment(null, sw);
+ env.setVariable("i2", i2);
+
+ try {
+ env.process();
+ assertEquals("2", sw.toString());
+ } catch (NullPointerException e) {
+ // Expected on 2.3.x, because it won't find the namespace for the macro
+ // [2.4] Fix this "bug"
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3fd56062/freemarker-core/src/test/java/org/apache/freemarker/core/MistakenlyPublicMacroAPIsTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/MistakenlyPublicMacroAPIsTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/MistakenlyPublicMacroAPIsTest.java
new file mode 100644
index 0000000..9c87e61
--- /dev/null
+++ b/freemarker-core/src/test/java/org/apache/freemarker/core/MistakenlyPublicMacroAPIsTest.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.freemarker.core;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.Map;
+
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.util._NullWriter;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+import org.junit.Test;
+
+/**
+ * These are things that users shouldn't do, but we shouldn't break backward compatibility without knowing about it.
+ */
+public class MistakenlyPublicMacroAPIsTest {
+
+ private final Configuration cfg = new TestConfigurationBuilder().build();
+
+ /**
+ * Getting the macros from one template, and adding them to another.
+ */
+ @Test
+ public void testMacroCopyingExploit() throws IOException, TemplateException {
+ Template tMacros = new Template(null, "<#macro m1>1</#macro><#macro m2>2</#macro>", cfg);
+ Map<String, ASTDirMacro> macros = tMacros.getMacros();
+
+ Template t = new Template(null,
+ "<@m1/><@m2/><@m3/>"
+ + "<#macro m1>1b</#macro><#macro m3>3b</#macro> "
+ + "<@m1/><@m2/><@m3/>", cfg);
+ t.addMacro(macros.get("m1"));
+ t.addMacro(macros.get("m2"));
+
+ assertEquals("123b 1b23b", getTemplateOutput(t));
+ }
+
+ @Test
+ public void testMacroCopyingExploitAndNamespaces() throws IOException, TemplateException {
+ Template tMacros = new Template(null, "<#assign x = 0><#macro m1>${x}</#macro>", cfg);
+ Template t = new Template(null, "<#assign x = 1><@m1/>", cfg);
+ t.addMacro((ASTDirMacro) tMacros.getMacros().get("m1"));
+
+ assertEquals("1", getTemplateOutput(t));
+ }
+
+ @Test
+ public void testMacroCopyingFromFTLVariable() throws IOException, TemplateException {
+ Template tMacros = new Template(null, "<#assign x = 0><#macro m1>${x}</#macro>", cfg);
+ Environment env = tMacros.createProcessingEnvironment(null, _NullWriter.INSTANCE);
+ env.process();
+ TemplateModel m1 = env.getVariable("m1");
+ assertThat(m1, instanceOf(ASTDirMacro.class));
+
+ Template t = new Template(null, "<#assign x = 1><@m1/>", cfg);
+ t.addMacro((ASTDirMacro) m1);
+
+ assertEquals("1", getTemplateOutput(t));
+ }
+
+ private String getTemplateOutput(Template t) throws TemplateException, IOException {
+ StringWriter sw = new StringWriter();
+ t.process(null, sw);
+ return sw.toString();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3fd56062/freemarker-core/src/test/java/org/apache/freemarker/core/NewBiObjectWrapperRestrictionTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/NewBiObjectWrapperRestrictionTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/NewBiObjectWrapperRestrictionTest.java
new file mode 100644
index 0000000..d865deb
--- /dev/null
+++ b/freemarker-core/src/test/java/org/apache/freemarker/core/NewBiObjectWrapperRestrictionTest.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.freemarker.core;
+
+import java.io.IOException;
+
+import org.apache.freemarker.test.TemplateTest;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+import org.apache.freemarker.test.util.EntirelyCustomObjectWrapper;
+import org.junit.Test;
+
+public class NewBiObjectWrapperRestrictionTest extends TemplateTest {
+
+ @Override
+ protected Configuration createDefaultConfiguration() throws Exception {
+ return new TestConfigurationBuilder().objectWrapper(new EntirelyCustomObjectWrapper()).build();
+ }
+
+ @Test
+ public void testPositive() throws IOException, TemplateException {
+ assertOutput(
+ "${'org.apache.freemarker.test.templatesuite.models.NewTestModel'?new()}",
+ "default constructor");
+ }
+
+ @Test
+ public void testNegative() {
+ assertErrorContains(
+ "${'org.apache.freemarker.test.templatesuite.models.NewTestModel'?new('s')}",
+ "only supports 0 argument");
+ }
+
+}