Repository: incubator-freemarker Updated Branches: refs/heads/3 612c42d80 -> 983ad9bd1
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/7d784b2b/src/test/java/org/apache/freemarker/core/ast/OutputFormatTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/freemarker/core/ast/OutputFormatTest.java b/src/test/java/org/apache/freemarker/core/ast/OutputFormatTest.java deleted file mode 100644 index 18d3ca0..0000000 --- a/src/test/java/org/apache/freemarker/core/ast/OutputFormatTest.java +++ /dev/null @@ -1,1022 +0,0 @@ -/* - * 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.ast; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; - -import java.io.IOException; -import java.io.StringWriter; -import java.io.Writer; -import java.util.Collections; - -import org.apache.freemarker.core.Configuration; -import org.apache.freemarker.core.Template; -import org.apache.freemarker.core.TemplateException; -import org.apache.freemarker.core.model.TemplateModelException; -import org.apache.freemarker.core.templateresolver.ConditionalTemplateConfigurationFactory; -import org.apache.freemarker.core.templateresolver.FileNameGlobMatcher; -import org.apache.freemarker.core.templateresolver.OrMatcher; -import org.apache.freemarker.test.TemplateTest; -import org.junit.Test; - -import com.google.common.collect.ImmutableList; - -public class OutputFormatTest extends TemplateTest { - - @Test - public void testOutputFormatSettingLayers() throws Exception { - addTemplate("t", "${.outputFormat}"); - addTemplate("t.xml", "${.outputFormat}"); - addTemplate("tWithHeader", "<#ftl outputFormat='HTML'>${.outputFormat}"); - - Configuration cfg = getConfiguration(); - for (OutputFormat cfgOutputFormat - : new OutputFormat[] { UndefinedOutputFormat.INSTANCE, RTFOutputFormat.INSTANCE } ) { - if (!cfgOutputFormat.equals(UndefinedOutputFormat.INSTANCE)) { - cfg.setOutputFormat(cfgOutputFormat); - } - - assertEquals(cfgOutputFormat, cfg.getOutputFormat()); - - { - Template t = cfg.getTemplate("t"); - assertEquals(cfgOutputFormat, t.getOutputFormat()); - assertOutput(t, t.getOutputFormat().getName()); - } - - { - Template t = cfg.getTemplate("t.xml"); - assertEquals(XMLOutputFormat.INSTANCE, t.getOutputFormat()); - assertOutput(t, t.getOutputFormat().getName()); - } - - { - Template t = cfg.getTemplate("tWithHeader"); - assertEquals(HTMLOutputFormat.INSTANCE, t.getOutputFormat()); - assertOutput(t, t.getOutputFormat().getName()); - } - - cfg.clearTemplateCache(); - } - } - - @Test - public void testStandardFileExtensions() throws Exception { - String commonContent = "${.outputFormat}"; - addTemplate("t", commonContent); - addTemplate("t.ftl", commonContent); - addTemplate("t.ftlh", commonContent); - addTemplate("t.FTLH", commonContent); - addTemplate("t.fTlH", commonContent); - addTemplate("t.ftlx", commonContent); - addTemplate("t.FTLX", commonContent); - addTemplate("t.fTlX", commonContent); - addTemplate("tWithHeader.ftlx", "<#ftl outputFormat='HTML'>" + commonContent); - - Configuration cfg = getConfiguration(); - for (int setupNumber = 1; setupNumber <= 3; setupNumber++) { - final OutputFormat cfgOutputFormat; - final OutputFormat ftlhOutputFormat; - final OutputFormat ftlxOutputFormat; - switch (setupNumber) { - case 1: - cfgOutputFormat = UndefinedOutputFormat.INSTANCE; - ftlhOutputFormat = HTMLOutputFormat.INSTANCE; - ftlxOutputFormat = XMLOutputFormat.INSTANCE; - break; - case 2: - cfgOutputFormat = RTFOutputFormat.INSTANCE; - cfg.setOutputFormat(cfgOutputFormat); - ftlhOutputFormat = HTMLOutputFormat.INSTANCE; - ftlxOutputFormat = XMLOutputFormat.INSTANCE; - break; - case 3: - cfgOutputFormat = UndefinedOutputFormat.INSTANCE; - cfg.unsetOutputFormat(); - TemplateConfiguration tcXml = new TemplateConfiguration(); - tcXml.setOutputFormat(XMLOutputFormat.INSTANCE); - cfg.setTemplateConfigurations( - new ConditionalTemplateConfigurationFactory( - new OrMatcher( - new FileNameGlobMatcher("*.ftlh"), - new FileNameGlobMatcher("*.FTLH"), - new FileNameGlobMatcher("*.fTlH")), - tcXml)); - ftlhOutputFormat = HTMLOutputFormat.INSTANCE; // can't be overidden - ftlxOutputFormat = XMLOutputFormat.INSTANCE; - break; - default: - throw new AssertionError(); - } - - assertEquals(cfgOutputFormat, cfg.getOutputFormat()); - - { - Template t = cfg.getTemplate("t"); - assertEquals(cfgOutputFormat, t.getOutputFormat()); - assertOutput(t, t.getOutputFormat().getName()); - } - - { - Template t = cfg.getTemplate("t.ftl"); - assertEquals(cfgOutputFormat, t.getOutputFormat()); - assertOutput(t, t.getOutputFormat().getName()); - } - - for (String name : new String[] { "t.ftlh", "t.FTLH", "t.fTlH" }) { - Template t = cfg.getTemplate(name); - assertEquals(ftlhOutputFormat, t.getOutputFormat()); - assertOutput(t, t.getOutputFormat().getName()); - } - - for (String name : new String[] { "t.ftlx", "t.FTLX", "t.fTlX" }) { - Template t = cfg.getTemplate(name); - assertEquals(ftlxOutputFormat, t.getOutputFormat()); - assertOutput(t, t.getOutputFormat().getName()); - } - - { - Template t = cfg.getTemplate("tWithHeader.ftlx"); - assertEquals(HTMLOutputFormat.INSTANCE, t.getOutputFormat()); - assertOutput(t, t.getOutputFormat().getName()); - } - - cfg.clearTemplateCache(); - } - } - - @Test - public void testStandardFileExtensionsSettingOverriding() throws Exception { - addTemplate("t.ftlx", - "${\"'\"} ${\"'\"?esc} ${\"'\"?noEsc}"); - addTemplate("t.ftl", - "${'{}'} ${'{}'?esc} ${'{}'?noEsc}"); - - TemplateConfiguration tcHTML = new TemplateConfiguration(); - tcHTML.setOutputFormat(HTMLOutputFormat.INSTANCE); - ConditionalTemplateConfigurationFactory tcfHTML = new ConditionalTemplateConfigurationFactory( - new FileNameGlobMatcher("t.*"), tcHTML); - - TemplateConfiguration tcNoAutoEsc = new TemplateConfiguration(); - tcNoAutoEsc.setAutoEscapingPolicy(Configuration.DISABLE_AUTO_ESCAPING_POLICY); - ConditionalTemplateConfigurationFactory tcfNoAutoEsc = new ConditionalTemplateConfigurationFactory( - new FileNameGlobMatcher("t.*"), tcNoAutoEsc); - - Configuration cfg = getConfiguration(); - cfg.setOutputFormat(HTMLOutputFormat.INSTANCE); - assertOutputForNamed("t.ftlx", "' ' '"); // Can't override it - cfg.setTemplateConfigurations(tcfHTML); - assertOutputForNamed("t.ftlx", "' ' '"); // Can't override it - cfg.setTemplateConfigurations(tcfNoAutoEsc); - assertOutputForNamed("t.ftlx", "' ' '"); // Can't override it - - cfg.setTemplateConfigurations(null); - cfg.unsetOutputFormat(); - cfg.setRecognizeStandardFileExtensions(false); - assertErrorContainsForNamed("t.ftlx", UndefinedOutputFormat.INSTANCE.getName()); - cfg.setOutputFormat(HTMLOutputFormat.INSTANCE); - assertOutputForNamed("t.ftlx", "' ' '"); - cfg.setOutputFormat(XMLOutputFormat.INSTANCE); - assertOutputForNamed("t.ftlx", "' ' '"); - cfg.setTemplateConfigurations(tcfHTML); - assertOutputForNamed("t.ftlx", "' ' '"); - cfg.setTemplateConfigurations(tcfNoAutoEsc); - assertOutputForNamed("t.ftlx", "' ' '"); - - cfg.setRecognizeStandardFileExtensions(true); - cfg.setTemplateConfigurations(tcfHTML); - assertOutputForNamed("t.ftlx", "' ' '"); // Can't override it - cfg.setTemplateConfigurations(tcfNoAutoEsc); - assertOutputForNamed("t.ftlx", "' ' '"); // Can't override it - - cfg.setTemplateConfigurations(null); - cfg.unsetOutputFormat(); - cfg.setTemplateConfigurations(tcfHTML); - assertOutputForNamed("t.ftlx", "' ' '"); // Can't override it - cfg.setRecognizeStandardFileExtensions(false); - assertOutputForNamed("t.ftlx", "' ' '"); - } - - @Test - public void testStandardFileExtensionsWithConstructor() throws Exception { - Configuration cfg = getConfiguration(); - String commonFTL = "${'\\''}"; - { - Template t = new Template("foo.ftl", commonFTL, cfg); - assertSame(UndefinedOutputFormat.INSTANCE, t.getOutputFormat()); - StringWriter out = new StringWriter(); - t.process(null, out); - assertEquals("'", out.toString()); - } - { - Template t = new Template("foo.ftlx", commonFTL, cfg); - assertSame(XMLOutputFormat.INSTANCE, t.getOutputFormat()); - StringWriter out = new StringWriter(); - t.process(null, out); - assertEquals("'", out.toString()); - } - { - Template t = new Template("foo.ftlh", commonFTL, cfg); - assertSame(HTMLOutputFormat.INSTANCE, t.getOutputFormat()); - StringWriter out = new StringWriter(); - t.process(null, out); - assertEquals("'", out.toString()); - } - } - - @Test - public void testStandardFileExtensionsFormatterImplOverriding() throws Exception { - addTemplate("t.ftlh", "${'a&x'}"); - assertOutputForNamed("t.ftlh", "a&x"); - getConfiguration().setRegisteredCustomOutputFormats(Collections.singleton(CustomHTMLOutputFormat.INSTANCE)); - assertOutputForNamed("t.ftlh", "a&X"); - getConfiguration().setRegisteredCustomOutputFormats(Collections.<OutputFormat>emptyList()); - assertOutputForNamed("t.ftlh", "a&x"); - } - - @Test - public void testAutoEscapingSettingLayers() throws Exception { - addTemplate("t", "${'a&b'}"); - addTemplate("tWithHeaderFalse", "<#ftl autoEsc=false>${'a&b'}"); - addTemplate("tWithHeaderTrue", "<#ftl autoEsc=true>${'a&b'}"); - - Configuration cfg = getConfiguration(); - - assertEquals(Configuration.ENABLE_IF_DEFAULT_AUTO_ESCAPING_POLICY, cfg.getAutoEscapingPolicy()); - - cfg.setOutputFormat(XMLOutputFormat.INSTANCE); - - for (boolean cfgAutoEscaping : new boolean[] { true, false }) { - if (!cfgAutoEscaping) { - cfg.setAutoEscapingPolicy(Configuration.DISABLE_AUTO_ESCAPING_POLICY); - } - - { - Template t = cfg.getTemplate("t"); - if (cfgAutoEscaping) { - assertTrue(t.getAutoEscaping()); - assertOutput(t, "a&b"); - } else { - assertFalse(t.getAutoEscaping()); - assertOutput(t, "a&b"); - } - } - - { - Template t = cfg.getTemplate("tWithHeaderFalse"); - assertFalse(t.getAutoEscaping()); - assertOutput(t, "a&b"); - } - - { - Template t = cfg.getTemplate("tWithHeaderTrue"); - assertTrue(t.getAutoEscaping()); - assertOutput(t, "a&b"); - } - - cfg.clearTemplateCache(); - } - } - - @Test - public void testNumericalInterpolation() throws IOException, TemplateException { - getConfiguration().setRegisteredCustomOutputFormats(Collections.singleton(DummyOutputFormat.INSTANCE)); - assertOutput( - "<#ftl outputFormat='dummy'>#{1.5}; #{1.5; m3}; ${'a.b'}", - "1\\.5; 1\\.500; a\\.b"); - assertOutput( - "<#ftl outputFormat='dummy' autoEsc=false>#{1.5}; #{1.5; m3}; ${'a.b'}; ${'a.b'?esc}", - "1.5; 1.500; a.b; a\\.b"); - assertOutput("<#ftl outputFormat='plainText'>#{1.5}", "1.5"); - assertOutput("<#ftl outputFormat='HTML'>#{1.5}", "1.5"); - assertOutput("#{1.5}", "1.5"); - } - - @Test - public void testUndefinedOutputFormat() throws IOException, TemplateException { - assertOutput("${'a < b'}; ${htmlPlain}; ${htmlMarkup}", "a < b; a < {h'}; <p>c"); - assertErrorContains("${'x'?esc}", "undefined", "escaping", "?esc"); - assertErrorContains("${'x'?noEsc}", "undefined", "escaping", "?noEsc"); - } - - @Test - public void testPlainTextOutputFormat() throws IOException, TemplateException { - assertOutput("<#ftl outputFormat='plainText'>${'a < b'}; ${htmlPlain}", "a < b; a < {h'}"); - assertErrorContains("<#ftl outputFormat='plainText'>${htmlMarkup}", "plainText", "HTML", "conversion"); - assertErrorContains("<#ftl outputFormat='plainText'>${'x'?esc}", "plainText", "escaping", "?esc"); - assertErrorContains("<#ftl outputFormat='plainText'>${'x'?noEsc}", "plainText", "escaping", "?noEsc"); - } - - @Test - public void testAutoEscapingOnMOs() throws IOException, TemplateException { - for (int autoEsc = 0; autoEsc < 2; autoEsc++) { - String commonAutoEscFtl = "<#ftl outputFormat='HTML'>${'&'}"; - if (autoEsc == 0) { - // Cfg default is autoEscaping true - assertOutput(commonAutoEscFtl, "&"); - } else { - getConfiguration().setAutoEscapingPolicy(Configuration.DISABLE_AUTO_ESCAPING_POLICY); - assertOutput(commonAutoEscFtl, "&"); - } - - assertOutput( - "<#ftl outputFormat='RTF'>" - + "${rtfPlain} ${rtfMarkup} " - + "${htmlPlain} " - + "${xmlPlain}", - "\\\\par a & b \\par c " - + "a < \\{h'\\} " - + "a < \\{x'\\}"); - assertOutput( - "<#ftl outputFormat='HTML'>" - + "${htmlPlain} ${htmlMarkup} " - + "${xmlPlain} " - + "${rtfPlain}", - "a < {h'} <p>c " - + "a < {x'} " - + "\\par a & b"); - assertOutput( - "<#ftl outputFormat='XML'>" - + "${xmlPlain} ${xmlMarkup} " - + "${htmlPlain} " - + "${rtfPlain}", - "a < {x'} <p>c</p> " - + "a < {h'} " - + "\\par a & b"); - assertErrorContains("<#ftl outputFormat='RTF'>${htmlMarkup}", "output format", "RTF", "HTML"); - assertErrorContains("<#ftl outputFormat='RTF'>${xmlMarkup}", "output format", "RTF", "XML"); - assertErrorContains("<#ftl outputFormat='HTML'>${rtfMarkup}", "output format", "HTML", "RTF"); - assertErrorContains("<#ftl outputFormat='HTML'>${xmlMarkup}", "output format", "HTML", "XML"); - assertErrorContains("<#ftl outputFormat='XML'>${rtfMarkup}", "output format", "XML", "RTF"); - assertErrorContains("<#ftl outputFormat='XML'>${htmlMarkup}", "output format", "XML", "HTML"); - - for (int hasHeader = 0; hasHeader < 2; hasHeader++) { - assertOutput( - (hasHeader == 1 ? "<#ftl outputFormat='undefined'>" : "") - + "${xmlPlain} ${xmlMarkup} " - + "${htmlPlain} ${htmlMarkup} " - + "${rtfPlain} ${rtfMarkup}", - "a < {x'} <p>c</p> " - + "a < {h'} <p>c " - + "\\\\par a & b \\par c"); - } - } - } - - @Test - public void testStringLiteralsUseUndefinedOF() throws IOException, TemplateException { - String expectedOut = "& (&) &"; - String ftl = "<#ftl outputFormat='XML'>${'&'} ${\"(${'&'})\"?noEsc} ${'&'}"; - - assertOutput(ftl, expectedOut); - - addTemplate("t.xml", ftl); - assertOutputForNamed("t.xml", expectedOut); - } - - @Test - public void testUnparsedTemplate() throws IOException, TemplateException { - String content = "<#ftl>a<#foo>b${x}"; - { - Template t = Template.getPlainTextTemplate("x", content, getConfiguration()); - Writer sw = new StringWriter(); - t.process(null, sw); - assertEquals(content, sw.toString()); - assertEquals(UndefinedOutputFormat.INSTANCE, t.getOutputFormat()); - } - - { - getConfiguration().setOutputFormat(HTMLOutputFormat.INSTANCE); - Template t = Template.getPlainTextTemplate("x", content, getConfiguration()); - Writer sw = new StringWriter(); - t.process(null, sw); - assertEquals(content, sw.toString()); - assertEquals(HTMLOutputFormat.INSTANCE, t.getOutputFormat()); - } - } - - @Test - public void testStringLiteralInterpolation() throws IOException, TemplateException { - Template t = new Template(null, "<#ftl outputFormat='XML'>${'&'} ${\"(${'&'})\"?noEsc}", getConfiguration()); - assertEquals(XMLOutputFormat.INSTANCE, t.getOutputFormat()); - - assertOutput("${.outputFormat} ${'${.outputFormat}'} ${.outputFormat}", - "undefined undefined undefined"); - assertOutput("<#ftl outputFormat='HTML'>${.outputFormat} ${'${.outputFormat}'} ${.outputFormat}", - "HTML HTML HTML"); - assertOutput("${.outputFormat} <#outputFormat 'XML'>${'${.outputFormat}'}</#outputFormat> ${.outputFormat}", - "undefined XML undefined"); - assertOutput("${'foo ${xmlPlain}'}", "foo a < {x'}"); - assertOutput("${'${xmlMarkup}'}", "<p>c</p>"); - assertErrorContains("${'${\"x\"?esc}'}", "?esc", "undefined"); - assertOutput("<#ftl outputFormat='XML'>${'${xmlMarkup?esc} ${\"<\"?esc} ${\">\"} ${\"&\"?noEsc}'}", - "<p>c</p> < > &"); - } - - @Test - public void testStringBIsFail() { - assertErrorContains("<#ftl outputFormat='HTML'>${'<b>foo</b>'?esc?upperCase}", "string", "markup_output"); - } - - @Test - public void testConcatWithMOs() throws IOException, TemplateException { - assertOutput( - "${'\\'' + htmlMarkup} ${htmlMarkup + '\\''} ${htmlMarkup + htmlMarkup}", - "'<p>c <p>c' <p>c<p>c"); - assertOutput( - "${'\\'' + htmlPlain} ${htmlPlain + '\\''} ${htmlPlain + htmlPlain}", - "'a < {h'} a < {h'}' a < {h'}a < {h'}"); - assertErrorContains( - "<#ftl outputFormat='XML'>${'\\'' + htmlMarkup}", - "HTML", "XML", "conversion"); - assertErrorContains( - "${xmlMarkup + htmlMarkup}", - "HTML", "XML", "Conversion", "common"); - assertOutput( - "${xmlMarkup + htmlPlain}", - "<p>c</p>a < {h'}"); - assertOutput( - "${xmlPlain + htmlMarkup}", - "a < {x'}<p>c"); - assertOutput( - "${xmlPlain + htmlPlain}", - "a < {x'}a < {h'}"); - assertOutput( - "${xmlPlain + htmlPlain + '\\''}", - "a < {x'}a < {h'}'"); - assertOutput( - "${htmlPlain + xmlPlain + '\\''}", - "a < {h'}a < {x'}'"); - assertOutput( - "${xmlPlain + htmlPlain + '\\''}", - "a < {x'}a < {h'}'"); - assertOutput( - "<#ftl outputFormat='XML'>${htmlPlain + xmlPlain + '\\''}", - "a < {h'}a < {x'}'"); - assertOutput( - "<#ftl outputFormat='RTF'>${htmlPlain + xmlPlain + '\\''}", - "a < \\{h'\\}a < \\{x'\\}'"); - assertOutput( - "<#ftl outputFormat='XML'>${'\\'' + htmlPlain}", - "'a < {h'}"); - assertOutput( - "<#ftl outputFormat='HTML'>${'\\'' + htmlPlain}", - "'a < {h'}"); - assertOutput( - "<#ftl outputFormat='HTML'>${'\\'' + xmlPlain}", - "'a < {x'}"); - assertOutput( - "<#ftl outputFormat='RTF'>${'\\'' + xmlPlain}", - "'a < \\{x'\\}"); - - assertOutput( - "<#assign x = '\\''><#assign x += xmlMarkup>${x}", - "'<p>c</p>"); - assertOutput( - "<#assign x = xmlMarkup><#assign x += '\\''>${x}", - "<p>c</p>'"); - assertOutput( - "<#assign x = xmlMarkup><#assign x += htmlPlain>${x}", - "<p>c</p>a < {h'}"); - assertErrorContains( - "<#assign x = xmlMarkup><#assign x += htmlMarkup>${x}", - "HTML", "XML", "Conversion", "common"); - } - - @Test - public void testBlockAssignment() throws Exception { - for (String d : new String[] { "assign", "global", "local" }) { - String commonFTL = - "<#macro m>" - + "<#" + d + " x><p>${'&'}</#" + d + ">${x?isString?c} ${x} ${'&'} " - + "<#" + d + " x></#" + d + ">${x?isString?c}" - + "</#macro><@m />"; - assertOutput( - commonFTL, - "true <p>& & true"); - assertOutput( - "<#ftl outputFormat='HTML'>" + commonFTL, - "false <p>& & false"); - } - } - - @Test - public void testSpecialVariables() throws Exception { - String commonFTL = "${.outputFormat} ${.autoEsc?c}"; - - addTemplate("t.ftlx", commonFTL); - assertOutputForNamed("t.ftlx", "XML true"); - - addTemplate("t.ftlh", commonFTL); - assertOutputForNamed("t.ftlh", "HTML true"); - - addTemplate("t.ftl", commonFTL); - assertOutputForNamed("t.ftl", "undefined false"); - - addTemplate("tX.ftl", "<#ftl outputFormat='XML'>" + commonFTL); - addTemplate("tX.ftlx", commonFTL); - assertOutputForNamed("t.ftlx", "XML true"); - - addTemplate("tN.ftl", "<#ftl outputFormat='RTF' autoEsc=false>" + commonFTL); - assertOutputForNamed("tN.ftl", "RTF false"); - - assertOutput("${.output_format} ${.auto_esc?c}", "undefined false"); - } - - @Test - public void testEscAndNoEscBIBasics() throws IOException, TemplateException { - String commonFTL = "${'<x>'} ${'<x>'?esc} ${'<x>'?noEsc}"; - addTemplate("t.ftlh", commonFTL); - addTemplate("t-noAuto.ftlh", "<#ftl autoEsc=false>" + commonFTL); - addTemplate("t.ftl", commonFTL); - assertOutputForNamed("t.ftlh", "<x> <x> <x>"); - assertOutputForNamed("t-noAuto.ftlh", "<x> <x> <x>"); - assertErrorContainsForNamed("t.ftl", "output format", "undefined"); - } - - @Test - public void testEscAndNoEscBIsOnMOs() throws IOException, TemplateException { - String xmlHdr = "<#ftl outputFormat='XML'>"; - - assertOutput( - xmlHdr + "${'&'?esc?esc} ${'&'?esc?noEsc} ${'&'?noEsc?esc} ${'&'?noEsc?noEsc}", - "& & & &"); - - for (String bi : new String[] { "esc", "noEsc" } ) { - assertOutput( - xmlHdr + "${rtfPlain?" + bi + "}", - "\\par a & b"); - assertOutput( - xmlHdr + "<#setting numberFormat='0.0'>${1?" + bi + "}", - "1.0"); - assertOutput( - xmlHdr + "<#setting booleanFormat='&y,&n'>${true?" + bi + "}", - bi.equals("esc") ? "&y" : "&y"); - assertErrorContains( - xmlHdr + "${rtfMarkup?" + bi + "}", - "?" + bi, "output format", "RTF", "XML"); - assertErrorContains( - xmlHdr + "${noSuchVar?" + bi + "}", - "noSuchVar", "null or missing"); - assertErrorContains( - xmlHdr + "${[]?" + bi + "}", - "?" + bi, "xpected", "string", "sequence"); - } - } - - @Test - public void testMarkupStringBI() throws Exception { - assertOutput( - "${htmlPlain?markupString} ${htmlMarkup?markupString}", - "a < {h'} <p>c"); - assertErrorContains( - "${noSuchVar?markupString}", - "noSuchVar", "null or missing"); - assertErrorContains( - "${'x'?markupString}", - "xpected", "markup output", "string"); - } - - @Test - public void testOutputFormatDirective() throws Exception { - assertOutput( - "${.outputFormat}${'\\''} " - + "<#outputFormat 'HTML'>" - + "${.outputFormat}${'\\''} " - + "<#outputFormat 'XML'>${.outputFormat}${'\\''}</#outputFormat> " - + "${.outputFormat}${'\\''} " - + "</#outputFormat>" - + "${.outputFormat}${'\\''}", - "undefined' HTML' XML' HTML' undefined'"); - assertOutput( - "<#ftl output_format='XML'>" - + "${.output_format}${'\\''} " - + "<#outputformat 'HTML'>${.output_format}${'\\''}</#outputformat> " - + "${.output_format}${'\\''}", - "XML' HTML' XML'"); - - // Custom format: - assertErrorContains( - "<#outputFormat 'dummy'></#outputFormat>", - "dummy", "nregistered"); - getConfiguration().setRegisteredCustomOutputFormats(Collections.singleton(DummyOutputFormat.INSTANCE)); - assertOutput( - "<#outputFormat 'dummy'>${.outputFormat}</#outputFormat>", - "dummy"); - - // Parse-time param expression: - assertOutput( - "<#outputFormat 'plain' + 'Text'>${.outputFormat}</#outputFormat>", - "plainText"); - assertErrorContains( - "<#outputFormat 'plain' + someVar + 'Text'></#outputFormat>", - "someVar", "parse-time"); - assertErrorContains( - "<#outputFormat 'plainText'?upperCase></#outputFormat>", - "?upperCase", "parse-time"); - assertErrorContains( - "<#outputFormat true></#outputFormat>", - "string", "boolean"); - - // Naming convention: - assertErrorContains( - "<#outputFormat 'HTML'></#outputformat>", - "convention", "#outputFormat", "#outputformat"); - assertErrorContains( - "<#outputformat 'HTML'></#outputFormat>", - "convention", "#outputFormat", "#outputformat"); - - // Empty block: - assertOutput( - "${.output_format} " - + "<#outputformat 'HTML'></#outputformat>" - + "${.output_format}", - "undefined undefined"); - - // WS stripping: - assertOutput( - "${.output_format}\n" - + "<#outputformat 'HTML'>\n" - + " x\n" - + "</#outputformat>\n" - + "${.output_format}", - "undefined\n x\nundefined"); - } - - @Test - public void testAutoEscAndNoAutoEscDirectives() throws Exception { - assertOutput( - "<#ftl outputFormat='XML'>" - + "${.autoEsc?c}${'&'} " - + "<#noAutoEsc>" - + "${.autoEsc?c}${'&'} " - + "<#autoEsc>${.autoEsc?c}${'&'}</#autoEsc> " - + "${.autoEsc?c}${'&'} " - + "</#noAutoEsc>" - + "${.autoEsc?c}${'&'}", - "true& false& true& false& true&"); - assertOutput( - "<#ftl auto_esc=false output_format='XML'>" - + "${.auto_esc?c}${'&'} " - + "<#autoesc>${.auto_esc?c}${'&'}</#autoesc> " - + "${.auto_esc?c}${'&'}", - "false& true& false&"); - - // Bad came case: - assertErrorContains( - "<#noAutoesc></#noAutoesc>", - "Unknown directive"); - assertErrorContains( - "<#noautoEsc></#noautoEsc>", - "Unknown directive"); - - getConfiguration().setOutputFormat(XMLOutputFormat.INSTANCE); - - // Empty block: - assertOutput( - "${.auto_esc?c} " - + "<#noautoesc></#noautoesc>" - + "${.auto_esc?c}", - "true true"); - - // WS stripping: - assertOutput( - "${.auto_esc?c}\n" - + "<#noautoesc>\n" - + " x\n" - + "</#noautoesc>\n" - + "${.auto_esc?c}", - "true\n x\ntrue"); - - - // Naming convention: - assertErrorContains( - "<#autoEsc></#autoesc>", - "convention", "#autoEsc", "#autoesc"); - assertErrorContains( - "<#autoesc></#autoEsc>", - "convention", "#autoEsc", "#autoesc"); - assertErrorContains( - "<#noAutoEsc></#noautoesc>", - "convention", "#noAutoEsc", "#noautoesc"); - assertErrorContains( - "<#noautoesc></#noAutoEsc>", - "convention", "#noAutoEsc", "#noautoesc"); - } - - @Test - public void testExplicitAutoEscBannedForNonMarkup() throws Exception { - // While this restriction is technically unnecessary, we can catch a dangerous and probably common user - // misunderstanding. - assertErrorContains("<#ftl autoEsc=true>", "can't do escaping", "undefined"); - assertErrorContains("<#ftl outputFormat='plainText' autoEsc=true>", "can't do escaping", "plainText"); - assertErrorContains("<#ftl autoEsc=true outputFormat='plainText'>", "can't do escaping", "plainText"); - assertOutput("<#ftl autoEsc=true outputFormat='HTML'>", ""); - assertOutput("<#ftl outputFormat='HTML' autoEsc=true>", ""); - assertOutput("<#ftl autoEsc=false>", ""); - - assertErrorContains("<#autoEsc></#autoEsc>", "can't do escaping", "undefined"); - assertErrorContains("<#ftl outputFormat='plainText'><#autoEsc></#autoEsc>", "can't do escaping", "plainText"); - assertOutput("<#ftl outputFormat='plainText'><#outputFormat 'XML'><#autoEsc></#autoEsc></#outputFormat>", ""); - assertOutput("<#ftl outputFormat='HTML'><#autoEsc></#autoEsc>", ""); - assertOutput("<#noAutoEsc></#noAutoEsc>", ""); - } - - @Test - public void testAutoEscPolicy() throws Exception { - Configuration cfg = getConfiguration(); - cfg.setRegisteredCustomOutputFormats(ImmutableList.of( - SeldomEscapedOutputFormat.INSTANCE, DummyOutputFormat.INSTANCE)); - assertEquals(Configuration.ENABLE_IF_DEFAULT_AUTO_ESCAPING_POLICY, cfg.getAutoEscapingPolicy()); - - String commonFTL = "${'.'} ${.autoEsc?c}"; - String notEsced = ". false"; - String esced = "\\. true"; - - for (int autoEscPolicy : new int[] { - Configuration.ENABLE_IF_DEFAULT_AUTO_ESCAPING_POLICY, - Configuration.ENABLE_IF_SUPPORTED_AUTO_ESCAPING_POLICY, - Configuration.DISABLE_AUTO_ESCAPING_POLICY }) { - cfg.setAutoEscapingPolicy(autoEscPolicy); - - String sExpted = autoEscPolicy == Configuration.ENABLE_IF_SUPPORTED_AUTO_ESCAPING_POLICY ? esced : notEsced; - cfg.setOutputFormat(SeldomEscapedOutputFormat.INSTANCE); - assertOutput(commonFTL, sExpted); - cfg.setOutputFormat(UndefinedOutputFormat.INSTANCE); - assertOutput("<#ftl outputFormat='seldomEscaped'>" + commonFTL, sExpted); - assertOutput("<#outputFormat 'seldomEscaped'>" + commonFTL + "</#outputFormat>", sExpted); - - String dExpted = autoEscPolicy == Configuration.DISABLE_AUTO_ESCAPING_POLICY ? notEsced : esced; - cfg.setOutputFormat(DummyOutputFormat.INSTANCE); - assertOutput(commonFTL, dExpted); - cfg.setOutputFormat(UndefinedOutputFormat.INSTANCE); - assertOutput("<#ftl outputFormat='dummy'>" + commonFTL, dExpted); - assertOutput("<#outputFormat 'dummy'>" + commonFTL + "</#outputFormat>", dExpted); - - cfg.setOutputFormat(DummyOutputFormat.INSTANCE); - assertOutput( - commonFTL - + "<#outputFormat 'seldomEscaped'>" - + commonFTL - + "<#outputFormat 'dummy'>" - + commonFTL - + "</#outputFormat>" - + commonFTL - + "<#outputFormat 'plainText'>" - + commonFTL - + "</#outputFormat>" - + commonFTL - + "<#noAutoEsc>" - + commonFTL - + "</#noAutoEsc>" - + commonFTL - + "<#autoEsc>" - + commonFTL - + "</#autoEsc>" - + commonFTL - + "</#outputFormat>" - + commonFTL - + "<#noAutoEsc>" - + commonFTL - + "</#noAutoEsc>" - + commonFTL - + "<#autoEsc>" - + commonFTL - + "</#autoEsc>" - + commonFTL - , - dExpted - + sExpted - + dExpted - + sExpted - + notEsced - + sExpted - + notEsced - + sExpted - + esced - + sExpted - + dExpted - + notEsced - + dExpted - + esced - + dExpted); - } - } - - @Test - public void testDynamicParsingBIsInherticContextOutputFormat() throws Exception { - // Dynamic parser BI-s are supposed to use the parserConfiguration of the calling template, and ignore anything - // inside the calling template itself. Except, the outputFormat has to come from the calling lexical context. - - String commonFTL - = "Eval: ${'.outputFormat'?eval}; " - + "Interpret: <#assign ipd = r\"${.outputFormat} ${'{&}'}\"?interpret><@ipd/>"; - addTemplate("t.ftlh", commonFTL); - addTemplate("t2.ftlh", "<#outputFormat 'RTF'>" + commonFTL + "</#outputFormat>"); - - assertOutputForNamed( - "t.ftlh", - "Eval: HTML; Interpret: HTML {&}"); - assertOutputForNamed( - "t2.ftlh", - "Eval: RTF; Interpret: RTF \\{&\\}"); - assertOutput( - commonFTL, - "Eval: undefined; Interpret: undefined {&}"); - assertOutput( - "<#ftl outputFormat='RTF'>" + commonFTL + "\n" - + "<#outputFormat 'XML'>" + commonFTL + "</#outputFormat>", - "Eval: RTF; Interpret: RTF \\{&\\}\n" - + "Eval: XML; Interpret: XML {&}"); - - // parser.autoEscapingPolicy is inherited too: - assertOutput( - "<#ftl autoEsc=false outputFormat='XML'>" - + commonFTL + " ${'.autoEsc'?eval?c}", - "Eval: XML; Interpret: XML {&} false"); - assertOutput( - "<#ftl outputFormat='XML'>" - + "<#noAutoEsc>" + commonFTL + " ${'.autoEsc'?eval?c}</#noAutoEsc>", - "Eval: XML; Interpret: XML {&} false"); - assertOutput( - "<#ftl autoEsc=false outputFormat='XML'>" - + "<#noAutoEsc>" + commonFTL + " ${'.autoEsc'?eval?c}</#noAutoEsc>", - "Eval: XML; Interpret: XML {&} false"); - assertOutput( - "<#ftl autoEsc=false outputFormat='XML'>" - + "<#autoEsc>" + commonFTL + " ${'.autoEsc'?eval?c}</#autoEsc>", - "Eval: XML; Interpret: XML {&} true"); - assertOutput( - "${.outputFormat}<#assign ftl='<#ftl outputFormat=\\'RTF\\'>$\\{.outputFormat}'> <@ftl?interpret/>", - "undefined RTF"); - assertOutput( - "${.outputFormat}<#outputFormat 'RTF'>" - + "<#assign ftl='$\\{.outputFormat}'> <@ftl?interpret/> ${'.outputFormat'?eval}" - + "</#outputFormat>", - "undefined RTF RTF"); - } - - @Test - public void testBannedBIsWhenAutoEscaping() throws Exception { - for (String biName : new String[] { "html", "xhtml", "rtf", "xml" }) { - getConfiguration().setIncompatibleImprovements(Configuration.VERSION_3_0_0); - - String commonFTL = "${'x'?" + biName + "}"; - assertOutput(commonFTL, "x"); - assertErrorContains("<#ftl outputFormat='HTML'>" + commonFTL, - "?" + biName, "HTML", "double-escaping"); - assertErrorContains("<#ftl outputFormat='HTML'>${'${\"x\"?" + biName + "}'}", - "?" + biName, "HTML", "double-escaping"); - assertOutput("<#ftl outputFormat='plainText'>" + commonFTL, "x"); - assertOutput("<#ftl outputFormat='HTML' autoEsc=false>" + commonFTL, "x"); - assertOutput("<#ftl outputFormat='HTML'><#noAutoEsc>" + commonFTL + "</#noAutoEsc>", "x"); - assertOutput("<#ftl outputFormat='HTML'><#outputFormat 'plainText'>" + commonFTL + "</#outputFormat>", - "x"); - } - } - - @Test - public void testLegacyEscaperBIsBypassMOs() throws Exception { - assertOutput("${htmlPlain?html} ${htmlMarkup?html}", "a < {h'} <p>c"); - assertErrorContains("${xmlPlain?html}", "?html", "string", "markup_output", "XML"); - assertErrorContains("${xmlMarkup?html}", "?html", "string", "markup_output", "XML"); - assertErrorContains("${rtfPlain?html}", "?html", "string", "markup_output", "RTF"); - assertErrorContains("${rtfMarkup?html}", "?html", "string", "markup_output", "RTF"); - - assertOutput("${htmlPlain?xhtml} ${htmlMarkup?xhtml}", "a < {h'} <p>c"); - assertErrorContains("${xmlPlain?xhtml}", "?xhtml", "string", "markup_output", "XML"); - assertErrorContains("${xmlMarkup?xhtml}", "?xhtml", "string", "markup_output", "XML"); - assertErrorContains("${rtfPlain?xhtml}", "?xhtml", "string", "markup_output", "RTF"); - assertErrorContains("${rtfMarkup?xhtml}", "?xhtml", "string", "markup_output", "RTF"); - - assertOutput("${xmlPlain?xml} ${xmlMarkup?xml}", "a < {x'} <p>c</p>"); - assertOutput("${htmlPlain?xml} ${htmlMarkup?xml}", "a < {h'} <p>c"); - assertErrorContains("${rtfPlain?xml}", "?xml", "string", "markup_output", "RTF"); - assertErrorContains("${rtfMarkup?xml}", "?xml", "string", "markup_output", "RTF"); - - assertOutput("${rtfPlain?rtf} ${rtfMarkup?rtf}", "\\\\par a & b \\par c"); - assertErrorContains("${xmlPlain?rtf}", "?rtf", "string", "markup_output", "XML"); - assertErrorContains("${xmlMarkup?rtf}", "?rtf", "string", "markup_output", "XML"); - assertErrorContains("${htmlPlain?rtf}", "?rtf", "string", "markup_output", "HTML"); - assertErrorContains("${htmlMarkup?rtf}", "?rtf", "string", "markup_output", "HTML"); - } - - @Test - public void testBannedDirectivesWhenAutoEscaping() throws Exception { - String commonFTL = "<#escape x as x?html>x</#escape>"; - assertOutput(commonFTL, "x"); - assertErrorContains("<#ftl outputFormat='HTML'>" + commonFTL, "escape", "HTML", "double-escaping"); - assertOutput("<#ftl outputFormat='plainText'>" + commonFTL, "x"); - assertOutput("<#ftl outputFormat='HTML' autoEsc=false>" + commonFTL, "x"); - assertOutput("<#ftl outputFormat='HTML'><#noAutoEsc>" + commonFTL + "</#noAutoEsc>", "x"); - assertOutput("<#ftl outputFormat='HTML'><#outputFormat 'plainText'>" + commonFTL + "</#outputFormat>", "x"); - } - - @Test - public void testCombinedOutputFormats() throws Exception { - assertOutput( - "<#outputFormat 'XML{HTML}'>${'\\''}</#outputFormat>", - "&#39;"); - assertOutput( - "<#outputFormat 'HTML{RTF{XML}}'>${'<a=\\'{}\\' />'}</#outputFormat>", - "&lt;a=&apos;\\{\\}&apos; /&gt;"); - - String commonFtl = "${'\\''} <#outputFormat '{HTML}'>${'\\''}</#outputFormat>"; - String commonOutput = "' &#39;"; - assertOutput( - "<#outputFormat 'XML'>" + commonFtl + "</#outputFormat>", - commonOutput); - assertOutput( - "<#ftl outputFormat='XML'>" + commonFtl, - commonOutput); - addTemplate("t.ftlx", commonFtl); - assertOutputForNamed( - "t.ftlx", - commonOutput); - - assertErrorContains( - commonFtl, - ParseException.class, "{...}", "markup", UndefinedOutputFormat.INSTANCE.getName()); - assertErrorContains( - "<#ftl outputFormat='plainText'>" + commonFtl, - ParseException.class, "{...}", "markup", PlainTextOutputFormat.INSTANCE.getName()); - assertErrorContains( - "<#ftl outputFormat='RTF'><#outputFormat '{plainText}'></#outputFormat>", - ParseException.class, "{...}", "markup", PlainTextOutputFormat.INSTANCE.getName()); - assertErrorContains( - "<#ftl outputFormat='RTF'><#outputFormat '{noSuchFormat}'></#outputFormat>", - ParseException.class, "noSuchFormat", "registered"); - assertErrorContains( - "<#outputFormat 'noSuchFormat{HTML}'></#outputFormat>", - ParseException.class, "noSuchFormat", "registered"); - assertErrorContains( - "<#outputFormat 'HTML{noSuchFormat}'></#outputFormat>", - ParseException.class, "noSuchFormat", "registered"); - } - - @Test - public void testHasContentBI() throws Exception { - assertOutput("${htmlMarkup?hasContent?c} ${htmlPlain?hasContent?c}", "true true"); - assertOutput("<#ftl outputFormat='HTML'>${''?esc?hasContent?c} ${''?noEsc?hasContent?c}", "false false"); - } - - @Test - public void testMissingVariables() throws Exception { - for (String ftl : new String[] { - "${noSuchVar}", - "<#ftl outputFormat='XML'>${noSuchVar}", - "<#ftl outputFormat='XML'>${noSuchVar?esc}", - "<#ftl outputFormat='XML'>${'x'?esc + noSuchVar}" - }) { - assertErrorContains(ftl, InvalidReferenceException.class, "noSuchVar", "null or missing"); - } - } - - @Test - public void testIsMarkupOutputBI() throws Exception { - addToDataModel("m1", HTMLOutputFormat.INSTANCE.fromPlainTextByEscaping("x")); - addToDataModel("m2", HTMLOutputFormat.INSTANCE.fromMarkup("x")); - addToDataModel("s", "x"); - assertOutput("${m1?isMarkupOutput?c} ${m2?isMarkupOutput?c} ${s?isMarkupOutput?c}", "true true false"); - assertOutput("${m1?is_markup_output?c}", "true"); - } - - @Override - protected Configuration createConfiguration() throws TemplateModelException { - Configuration cfg = new Configuration(Configuration.VERSION_3_0_0); - - TemplateConfiguration xmlTC = new TemplateConfiguration(); - xmlTC.setOutputFormat(XMLOutputFormat.INSTANCE); - cfg.setTemplateConfigurations( - new ConditionalTemplateConfigurationFactory(new FileNameGlobMatcher("*.xml"), xmlTC)); - - cfg.setSharedVariable("rtfPlain", RTFOutputFormat.INSTANCE.fromPlainTextByEscaping("\\par a & b")); - cfg.setSharedVariable("rtfMarkup", RTFOutputFormat.INSTANCE.fromMarkup("\\par c")); - cfg.setSharedVariable("htmlPlain", HTMLOutputFormat.INSTANCE.fromPlainTextByEscaping("a < {h'}")); - cfg.setSharedVariable("htmlMarkup", HTMLOutputFormat.INSTANCE.fromMarkup("<p>c")); - cfg.setSharedVariable("xmlPlain", XMLOutputFormat.INSTANCE.fromPlainTextByEscaping("a < {x'}")); - cfg.setSharedVariable("xmlMarkup", XMLOutputFormat.INSTANCE.fromMarkup("<p>c</p>")); - - return cfg; - } - -}