blob: 5aa735d5f7ee2076732f7b30ea7545f1fbc856ab [file] [log] [blame]
/*
* 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 freemarker.core;
import java.io.IOException;
import org.junit.Before;
import org.junit.Test;
import freemarker.cache.StringTemplateLoader;
import freemarker.cache.TemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.Version;
import freemarker.template.utility.StringUtil;
import freemarker.test.TemplateTest;
public class TemplateNameSpecialVariablesTest extends TemplateTest {
private static final Version[] BREAK_POINT_VERSIONS = new Version[] {
Configuration.VERSION_2_3_0, Configuration.VERSION_2_3_22, Configuration.VERSION_2_3_23 };
private static TemplateLoader createTemplateLoader(String specVar) {
StringTemplateLoader tl = new StringTemplateLoader();
tl.putTemplate("main.ftl",
"In main: ${" + specVar + "}\n"
+ "<#import 'imp.ftl' as i>"
+ "In imp: ${inImp}\n"
+ "In main: ${" + specVar + "}\n"
+ "<@i.impM>${" + specVar + "}</@>\n"
+ "<@i.impM2 />\n"
+ "In main: ${" + specVar + "}\n"
+ "<#include 'inc.ftl'>"
+ "In main: ${" + specVar + "}\n"
+ "<@incM>${" + specVar + "}</@>\n"
+ "<@incM2 />\n"
+ "In main: ${" + specVar + "}\n"
);
tl.putTemplate("imp.ftl",
"<#global inImp = " + specVar + ">"
+ "<#macro impM>"
+ "${" + specVar + "}\n"
+ "{<#nested>}"
+ "</#macro>"
+ "<#macro impM2>"
+ "In imp call imp:\n"
+ "<@impM>${" + specVar + "}</@>\n"
+ "After: ${" + specVar + "}"
+ "</#macro>"
);
tl.putTemplate("inc.ftl",
"In inc: ${" + specVar + "}\n"
+ "In inc call imp:\n"
+ "<@i.impM>${" + specVar + "}</@>\n"
+ "<#macro incM>"
+ "${" + specVar + "}\n"
+ "{<#nested>}"
+ "</#macro>"
+ "<#macro incM2>"
+ "In inc call imp:\n"
+ "<@i.impM>${" + specVar + "}</@>"
+ "</#macro>"
);
return tl;
}
private static final String PRINT_ALL_FTL
= "t=${.templateName}, ct=${.currentTemplateName!'-'}, mt=${.mainTemplateName!'-'}";
@Test
public void testTemplateName230() throws IOException, TemplateException {
getConfiguration().setTemplateLoader(createTemplateLoader(".templateName"));
getConfiguration().setIncompatibleImprovements(Configuration.VERSION_2_3_0);
assertMainFtlOutput(false);
}
/** This IcI version was buggy. */
@Test
public void testTemplateName2322() throws IOException, TemplateException {
getConfiguration().setTemplateLoader(createTemplateLoader(".templateName"));
getConfiguration().setIncompatibleImprovements(Configuration.VERSION_2_3_22);
assertMainFtlOutput(true);
}
@Test
public void testTemplateName2323() throws IOException, TemplateException {
getConfiguration().setTemplateLoader(createTemplateLoader(".templateName"));
getConfiguration().setIncompatibleImprovements(Configuration.VERSION_2_3_23);
assertMainFtlOutput(false);
}
@Test
public void testMainTemplateName() throws IOException, TemplateException {
getConfiguration().setTemplateLoader(createTemplateLoader(".mainTemplateName"));
for (Version ici : BREAK_POINT_VERSIONS) {
getConfiguration().setIncompatibleImprovements(ici);
assertMainFtlOutput(true);
}
}
@Test
public void testCurrentTemplateName() throws IOException, TemplateException {
getConfiguration().setTemplateLoader(createTemplateLoader(".currentTemplateName"));
for (Version ici : BREAK_POINT_VERSIONS) {
getConfiguration().setIncompatibleImprovements(ici);
assertOutputForNamed("main.ftl",
"In main: main.ftl\n"
+ "In imp: imp.ftl\n"
+ "In main: main.ftl\n"
+ "imp.ftl\n"
+ "{main.ftl}\n"
+ "In imp call imp:\n"
+ "imp.ftl\n"
+ "{imp.ftl}\n"
+ "After: imp.ftl\n"
+ "In main: main.ftl\n"
+ "In inc: inc.ftl\n"
+ "In inc call imp:\n"
+ "imp.ftl\n"
+ "{inc.ftl}\n"
+ "In main: main.ftl\n"
+ "inc.ftl\n"
+ "{main.ftl}\n"
+ "In inc call imp:\n"
+ "imp.ftl\n"
+ "{inc.ftl}\n"
+ "In main: main.ftl\n");
}
}
protected void assertMainFtlOutput(boolean allMain) throws IOException, TemplateException {
String expected
= "In main: main.ftl\n"
+ "In imp: imp.ftl\n"
+ "In main: main.ftl\n"
+ "main.ftl\n"
+ "{main.ftl}\n"
+ "In imp call imp:\n"
+ "main.ftl\n"
+ "{imp.ftl}\n"
+ "After: main.ftl\n"
+ "In main: main.ftl\n"
+ "In inc: inc.ftl\n"
+ "In inc call imp:\n"
+ "inc.ftl\n"
+ "{main.ftl}\n"
+ "In main: main.ftl\n"
+ "main.ftl\n"
+ "{main.ftl}\n"
+ "In inc call imp:\n"
+ "main.ftl\n"
+ "{main.ftl}\n"
+ "In main: main.ftl\n";
if (allMain) {
expected = StringUtil.replace(expected, "imp.ftl", "main.ftl");
expected = StringUtil.replace(expected, "inc.ftl", "main.ftl");
}
assertOutputForNamed("main.ftl", expected);
}
@Before
public void setup() {
Configuration cfg = getConfiguration();
cfg.setWhitespaceStripping(false);
}
@Test
public void testInAdhocTemplate() throws TemplateException, IOException {
StringTemplateLoader tl = new StringTemplateLoader();
tl.putTemplate("inc.ftl", "Inc: " + PRINT_ALL_FTL);
getConfiguration().setTemplateLoader(tl);
// In nameless templates, the deprecated .templateName is "", but the new variables are missing values.
assertOutput(new Template(null, PRINT_ALL_FTL + "; <#include 'inc.ftl'>", getConfiguration()),
"t=, ct=-, mt=-; Inc: t=inc.ftl, ct=inc.ftl, mt=-");
assertOutput(new Template("foo.ftl", PRINT_ALL_FTL + "; <#include 'inc.ftl'>", getConfiguration()),
"t=foo.ftl, ct=foo.ftl, mt=foo.ftl; Inc: t=inc.ftl, ct=inc.ftl, mt=foo.ftl");
}
@Test
public void testInInterpretTemplate() throws TemplateException, IOException {
getConfiguration().setSharedVariable("t", PRINT_ALL_FTL);
assertOutput(new Template("foo.ftl", PRINT_ALL_FTL + "; <@t?interpret />", getConfiguration()),
"t=foo.ftl, ct=foo.ftl, mt=foo.ftl; "
+ "t=foo.ftl->anonymous_interpreted, ct=foo.ftl->anonymous_interpreted, mt=foo.ftl");
assertOutput(new Template(null, PRINT_ALL_FTL + "; <@t?interpret />", getConfiguration()),
"t=, ct=-, mt=-; "
+ "t=nameless_template->anonymous_interpreted, ct=nameless_template->anonymous_interpreted, mt=-");
assertOutput(new Template("foo.ftl", PRINT_ALL_FTL + "; <@[t,'bar']?interpret />", getConfiguration()),
"t=foo.ftl, ct=foo.ftl, mt=foo.ftl; "
+ "t=foo.ftl->bar, ct=foo.ftl->bar, mt=foo.ftl");
}
@Test
public void testArgumentBugWithMacro() throws TemplateException, IOException {
StringTemplateLoader tl = new StringTemplateLoader();
tl.putTemplate("main.ftl", ""
+ "<#include 'inc.ftl'>"
+ "Before: ${.currentTemplateName}\n"
+ "<@m p1=.currentTemplateName; x>"
+ "Loop var: ${x}\n"
+ "In nested: ${.currentTemplateName}\n"
+ "</@>"
+ "After: ${.currentTemplateName}");
tl.putTemplate("inc.ftl", ""
+ "<#macro m p1 p2=.currentTemplateName>"
+ "p1: ${p1}\n"
+ "p2: ${p2}\n"
+ "Inside: ${.currentTemplateName}\n"
+ "<#nested .currentTemplateName>"
+ "</#macro>");
Configuration cfg = getConfiguration();
cfg.setTemplateLoader(tl);
for (boolean fixed : new boolean[] { false, true }) {
cfg.setIncompatibleImprovements(fixed ? Configuration.VERSION_2_3_28 : Configuration.VERSION_2_3_27);
assertOutputForNamed("main.ftl", ""
+ "Before: main.ftl\n"
+ "p1: " + (fixed ? "main.ftl" : "inc.ftl") + "\n"
+ "p2: inc.ftl\n"
+ "Inside: inc.ftl\n"
+ "Loop var: inc.ftl\n"
+ "In nested: main.ftl\n"
+ "After: main.ftl");
}
}
@Test
public void testArgumentBugWithFunction() throws TemplateException, IOException {
StringTemplateLoader tl = new StringTemplateLoader();
tl.putTemplate("main.ftl", ""
+ "<#include 'inc.ftl'>"
+ "${f(.currentTemplateName)}");
tl.putTemplate("inc.ftl", ""
+ "<#function f(p1, p2=.currentTemplateName)>"
+ "<#return 'p1=${p1}, p2=${p2}, inside=${.currentTemplateName}'>"
+ "</#function>");
Configuration cfg = getConfiguration();
cfg.setTemplateLoader(tl);
for (boolean fixed : new boolean[] { false, true }) {
cfg.setIncompatibleImprovements(fixed ? Configuration.VERSION_2_3_28 : Configuration.VERSION_2_3_27);
assertOutputForNamed("main.ftl", ""
+ "p1=" + (fixed ? "main.ftl" : "inc.ftl")
+ ", p2=inc.ftl, inside=inc.ftl");
}
}
}