blob: 51d02310158562fa27745f4eb85db0fda7e3540a [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.ext.jsp;
import static org.junit.Assert.*;
import java.io.IOException;
import java.util.AbstractList;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.regex.Pattern;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.junit.Ignore;
import org.junit.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import freemarker.cache.ClassTemplateLoader;
import freemarker.cache.TemplateLoader;
import freemarker.cache.WebappTemplateLoader;
import freemarker.ext.beans.BeansWrapper;
import freemarker.ext.beans.BeansWrapperBuilder;
import freemarker.ext.servlet.FreemarkerServlet;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.ObjectWrapper;
import freemarker.template.SimpleObjectWrapper;
import freemarker.template.TemplateExceptionHandler;
import freemarker.test.servlet.DefaultModel2TesterAction;
import freemarker.test.servlet.WebAppTestCase;
/**
* Tests {@link FreemarkerServlet} on a real (embedded) Servlet container.
*/
@SuppressWarnings("boxing")
public class RealServletContainertTest extends WebAppTestCase {
private static final String WEBAPP_BASIC = "basic";
private static final String WEBAPP_TLD_DISCOVERY = "tldDiscovery";
private static final String WEBAPP_ERRORS = "errors";
private static final String WEBAPP_CONFIG = "config";
private static final String WEBAPP_MULTIPLE_LOADERS = "multipleLoaders";
@Test
public void basicTrivial() throws Exception {
assertJSPAndFTLOutputEquals(WEBAPP_BASIC, "tester?view=trivial");
}
@Test
@Ignore // c:forEach fails because of EL context issues
public void basicTrivialJSTL() throws Exception {
assertOutputsEqual(WEBAPP_BASIC, "tester?view=trivial.jsp", "tester?view=trivial-jstl-@Ignore.ftl");
}
@Test
public void basicCustomTags1() throws Exception {
assertExpectedEqualsOutput(WEBAPP_BASIC, "customTags1.txt", "tester?view=customTags1.ftl", false);
}
@Test
public void basicCustomAttributes() throws Exception {
restartWebAppIfStarted(WEBAPP_BASIC); // To clear the application scope attributes
assertExpectedEqualsOutput(WEBAPP_BASIC, "attributes.txt", "tester"
+ "?action=" + AllKindOfContainersModel2Action.class.getName()
+ "&view=attributes.ftl");
restartWebAppIfStarted(WEBAPP_BASIC); // To clear the application scope attributes
assertExpectedEqualsOutput(WEBAPP_BASIC, "attributes-2.3.22-future.txt", "tester"
+ "?action=" + AllKindOfContainersModel2Action.class.getName()
+ "&view=attributes.ftl&viewServlet=freemarker-2.3.22-future");
restartWebAppIfStarted(WEBAPP_BASIC); // To clear the application scope attributes
assertExpectedEqualsOutput(WEBAPP_BASIC, "attributes-2.3.0.txt", "tester"
+ "?action=" + AllKindOfContainersModel2Action.class.getName()
+ "&view=attributes.ftl&viewServlet=freemarker-2.3.0",
true,
ImmutableList.<Pattern>of(
Pattern.compile("(?<=^Date-time: ).*", Pattern.MULTILINE), // Uses Date.toString, so plat. dep.
Pattern.compile("(?<=^MyMap: ).*", Pattern.MULTILINE) // Uses HashMap, so order unknown
));
}
@Test
public void basicELFunctions() throws Exception {
//System.out.println(getResponseContent(WEBAPP_EL_FUNCTIONS, "tester?view=1.jsp"));
//System.out.println(getResponseContent(WEBAPP_EL_FUNCTIONS, "tester?view=1.ftl"));
assertJSPAndFTLOutputEquals(WEBAPP_BASIC, "tester?view=customELFunctions1");
}
@Test
public void tldDiscoveryBasic() throws Exception {
try {
restartWebAppIfStarted(WEBAPP_TLD_DISCOVERY);
assertExpectedEqualsOutput(WEBAPP_TLD_DISCOVERY, "test1.txt", "tester?view=test1.ftl");
} finally {
JspTestFreemarkerServlet.resetToDefaults();
}
}
@Test
public void tldDiscoveryBasicDefultOverride() throws Exception {
try {
restartWebAppIfStarted(WEBAPP_TLD_DISCOVERY);
assertExpectedEqualsOutput(WEBAPP_TLD_DISCOVERY, "test1.txt",
"tester?view=test1.ftl&viewServlet=freemarker-defaultOverride");
} finally {
JspTestFreemarkerServlet.resetToDefaults();
}
}
@Test
public void tldDiscoveryEmulatedProblems1() throws Exception {
try {
JspTestFreemarkerServlet.emulateNoJarURLConnections = true;
restartWebAppIfStarted(WEBAPP_TLD_DISCOVERY);
assertExpectedEqualsOutput(WEBAPP_TLD_DISCOVERY, "test1.txt", "tester?view=test1.ftl");
} finally {
JspTestFreemarkerServlet.resetToDefaults();
}
}
@Test
public void tldDiscoveryEmulatedProblems2() throws Exception {
try {
JspTestFreemarkerServlet.emulateNoJarURLConnections = true;
JspTestFreemarkerServlet.emulateNoUrlToFileConversions = true;
// Because of emulateNoUrlToFileConversions = true it won't be able to list the directories, so:
System.setProperty(
FreemarkerServlet.SYSTEM_PROPERTY_CLASSPATH_TLDS,
"META-INF/tldDiscovery MetaInfTldSources-1.tld");
restartWebAppIfStarted(WEBAPP_TLD_DISCOVERY);
assertExpectedEqualsOutput(WEBAPP_TLD_DISCOVERY, "test1.txt", "tester?view=test1.ftl");
} finally {
JspTestFreemarkerServlet.resetToDefaults();
System.clearProperty(FreemarkerServlet.SYSTEM_PROPERTY_CLASSPATH_TLDS);
}
}
@Test
public void tldDiscoveryClasspathOnly() throws Exception {
try {
System.setProperty(FreemarkerServlet.SYSTEM_PROPERTY_META_INF_TLD_SOURCES, "clear, classpath");
restartWebAppIfStarted(WEBAPP_TLD_DISCOVERY);
assertExpectedEqualsOutput(WEBAPP_TLD_DISCOVERY, "test1.txt", "tester?view=test1.ftl");
} finally {
JspTestFreemarkerServlet.resetToDefaults();
System.clearProperty(FreemarkerServlet.SYSTEM_PROPERTY_META_INF_TLD_SOURCES);
}
}
/**
* Tests that (1) webInfPerLibJars still loads from WEB-INF/lib/*.jar, and (2) that
* {@link FreemarkerServlet#SYSTEM_PROPERTY_META_INF_TLD_SOURCES} indeed overrides the init-param, and that the
* Jetty container's JSTL jar-s will still be discovered.
*/
@Test
public void tldDiscoveryNoClasspath() throws Exception {
try {
System.setProperty(FreemarkerServlet.SYSTEM_PROPERTY_META_INF_TLD_SOURCES, "clear, webInfPerLibJars");
restartWebAppIfStarted(WEBAPP_TLD_DISCOVERY);
assertExpectedEqualsOutput(WEBAPP_TLD_DISCOVERY,
"test-noClasspath.txt", "tester?view=test-noClasspath.ftl");
} finally {
JspTestFreemarkerServlet.resetToDefaults();
System.clearProperty(FreemarkerServlet.SYSTEM_PROPERTY_META_INF_TLD_SOURCES);
}
}
@Test
public void tldDiscoveryRelative() throws Exception {
assertExpectedEqualsOutput(WEBAPP_TLD_DISCOVERY, "subdir/test-rel.txt", "tester?view=subdir/test-rel.ftl");
}
@Test
public void errorStatusCodes() throws Exception {
assertEquals(404, getResponseStatusCode(WEBAPP_ERRORS, "missing.jsp"));
assertEquals(500, getResponseStatusCode(WEBAPP_ERRORS, "failing-runtime.jsp"));
assertEquals(500, getResponseStatusCode(WEBAPP_ERRORS, "failing-parsetime.jsp"));
assertEquals(200, getResponseStatusCode(WEBAPP_ERRORS,
"tester?view=not-failing.ftl&viewServlet=freemarker-default-dev"));
assertEquals(404, getResponseStatusCode(WEBAPP_ERRORS,
"tester?view=missing.ftl&viewServlet=freemarker-default-dev"));
assertEquals(200, getResponseStatusCode(WEBAPP_ERRORS,
"tester?view=failing-runtime.ftl&viewServlet=freemarker-default-dev"));
assertEquals(500, getResponseStatusCode(WEBAPP_ERRORS,
"tester?view=failing-parsetime.ftlnv&viewServlet=freemarker-default-dev"));
assertEquals(200, getResponseStatusCode(WEBAPP_ERRORS,
"tester?view=not-failing.ftl&viewServlet=freemarker-default-prod"));
assertEquals(404, getResponseStatusCode(WEBAPP_ERRORS,
"tester?view=missing.ftl&viewServlet=freemarker-default-prod"));
assertEquals(500, getResponseStatusCode(WEBAPP_ERRORS,
"tester?view=failing-runtime.ftl&viewServlet=freemarker-default-prod"));
assertEquals(500, getResponseStatusCode(WEBAPP_ERRORS,
"tester?view=failing-parsetime.ftlnv&viewServlet=freemarker-default-prod"));
assertEquals(200, getResponseStatusCode(WEBAPP_ERRORS,
"tester?view=not-failing.ftl&viewServlet=freemarker-future-prod"));
assertEquals(500, getResponseStatusCode(WEBAPP_ERRORS,
"tester?view=missing.ftl&viewServlet=freemarker-future-prod"));
assertEquals(500, getResponseStatusCode(WEBAPP_ERRORS,
"tester?view=failing-runtime.ftl&viewServlet=freemarker-future-prod"));
assertEquals(500, getResponseStatusCode(WEBAPP_ERRORS,
"tester?view=failing-parsetime.ftlnv&viewServlet=freemarker-future-prod"));
}
@Test
public void testTemplateLoaderConfig() throws Exception {
assertEquals("from /WEB-INF/classes", getResponseContent(WEBAPP_CONFIG,
"tester?view=test.ftl&viewServlet=freemarker-class-root"));
assertEquals("from WEB-INF/lib/templates.jar/sub", getResponseContent(WEBAPP_CONFIG,
"tester?view=sub/test2.ftl&viewServlet=freemarker-class-root"));
assertEquals("from /WEB-INF/classes/sub", getResponseContent(WEBAPP_CONFIG,
"tester?view=test.ftl&viewServlet=freemarker-class-sub"));
assertEquals("from WEB-INF/lib/templates.jar/sub", getResponseContent(WEBAPP_CONFIG,
"tester?view=test2.ftl&viewServlet=freemarker-class-sub"));
assertEquals("from /WEB-INF/classes", getResponseContent(WEBAPP_CONFIG,
"tester?view=test.ftl&viewServlet=freemarker-classpath-root"));
assertEquals("from WEB-INF/lib/templates.jar/sub", getResponseContent(WEBAPP_CONFIG,
"tester?view=sub/test2.ftl&viewServlet=freemarker-classpath-root"));
assertEquals("from /WEB-INF/classes/sub", getResponseContent(WEBAPP_CONFIG,
"tester?view=test.ftl&viewServlet=freemarker-classpath-sub"));
assertEquals("from WEB-INF/lib/templates.jar/sub", getResponseContent(WEBAPP_CONFIG,
"tester?view=test2.ftl&viewServlet=freemarker-classpath-sub"));
assertEquals("from /WEB-INF/templates", getResponseContent(WEBAPP_CONFIG,
"tester?view=test.ftl&viewServlet=freemarker-webinfPerTemplates"));
assertEquals("from /", getResponseContent(WEBAPP_CONFIG,
"tester?view=test.ftl&viewServlet=freemarker-contentRoot"));
}
@Test
public void testConfigurationDefaults() throws Exception {
assertEquals(200, getResponseStatusCode(WEBAPP_CONFIG,
"tester?view=test.ftl&viewServlet=freemarker-assertDefaultsFreemarkerServlet"));
assertEquals(200, getResponseStatusCode(WEBAPP_CONFIG,
"tester?view=test.ftl&viewServlet=freemarker-assertDefaultsIcI2322FreemarkerServlet"));
assertEquals(200, getResponseStatusCode(WEBAPP_CONFIG,
"tester?view=test.ftl&viewServlet=freemarker-assertCustomizedDefaultsFreemarkerServlet"));
assertEquals(200, getResponseStatusCode(WEBAPP_CONFIG,
"tester?view=test.ftl&viewServlet=freemarker-assertObjectWrapperDefaults1FreemarkerServlet"));
assertEquals(200, getResponseStatusCode(WEBAPP_CONFIG,
"tester?view=test.ftl&viewServlet=freemarker-assertObjectWrapperDefaults2FreemarkerServlet"));
}
@Test
public void testMultipleLoaders() throws Exception {
assertEquals("In test.ftl",
getResponseContent(WEBAPP_MULTIPLE_LOADERS, "tester?view=test.ftl"));
assertEquals("In classpath-test.ftl",
getResponseContent(WEBAPP_MULTIPLE_LOADERS, "tester?view=classpath-test.ftl"));
}
public static class AllKindOfContainersModel2Action extends DefaultModel2TesterAction {
@Override
public String execute(HttpServletRequest req, HttpServletResponse resp) throws Exception {
req.setAttribute("linkedList", initTestCollection(new LinkedList<Integer>()));
req.setAttribute("arrayList", initTestCollection(new ArrayList<Integer>()));
req.setAttribute("myList", new MyList());
req.setAttribute("linkedHashMap", initTestMap(new LinkedHashMap()));
req.setAttribute("treeMap", initTestMap(new TreeMap()));
req.setAttribute("myMap", new MyMap());
req.setAttribute("treeSet", initTestCollection(new TreeSet()));
return super.execute(req, resp);
}
private Collection<Integer> initTestCollection(Collection<Integer> list) {
for (int i = 0; i < 3; i++) list.add(i + 1);
return list;
}
private Map<String, Integer> initTestMap(Map<String, Integer> map) {
for (int i = 0; i < 3; i++) map.put(String.valueOf((char) ('a' + i)), i + 1);
return map;
}
}
public static class MyMap extends AbstractMap<String, Integer> {
@Override
public Set<Map.Entry<String, Integer>> entrySet() {
return ImmutableSet.<Map.Entry<String, Integer>>of(
new MyEntry("a", 1), new MyEntry("b", 2), new MyEntry("c", 3));
}
private static class MyEntry implements Map.Entry<String, Integer> {
private final String key;
private final Integer value;
public MyEntry(String key, Integer value) {
this.key = key;
this.value = value;
}
public String getKey() {
return key;
}
public Integer getValue() {
return value;
}
public Integer setValue(Integer value) {
throw new UnsupportedOperationException();
}
}
}
public static class MyList extends AbstractList<Integer> {
@SuppressWarnings("boxing")
@Override
public Integer get(int index) {
return index + 1;
}
@Override
public int size() {
return 3;
}
}
public static abstract class AssertingFreemarkerServlet extends FreemarkerServlet {
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
Configuration cfg = getConfiguration();
try {
doAssertions(cfg);
} catch (Exception e) {
throw new ServletException("Test failed", e);
}
response.setStatus(200);
response.getWriter().write("OK");
}
protected abstract void doAssertions(Configuration cfg) throws Exception;
}
public static class AssertDefaultsFreemarkerServlet extends AssertingFreemarkerServlet {
@Override
protected void doAssertions(Configuration cfg) {
assertEquals(Configuration.VERSION_2_3_22, cfg.getIncompatibleImprovements());
assertSame(cfg.getTemplateExceptionHandler(), TemplateExceptionHandler.HTML_DEBUG_HANDLER);
assertFalse(cfg.getLogTemplateExceptions());
{
ObjectWrapper ow = cfg.getObjectWrapper();
assertTrue(ow instanceof DefaultObjectWrapper);
assertEquals(Configuration.VERSION_2_3_22, ((DefaultObjectWrapper) ow).getIncompatibleImprovements());
}
{
TemplateLoader tl = cfg.getTemplateLoader();
assertTrue(tl instanceof ClassTemplateLoader);
assertEquals("/", ((ClassTemplateLoader) tl).getBasePackagePath());
}
}
}
public static class AssertDefaultsIcI2322FreemarkerServlet extends AssertDefaultsFreemarkerServlet {
@Override
protected Configuration createConfiguration() {
Configuration cfg = new Configuration(Configuration.VERSION_2_3_22);
return cfg;
}
}
public static class AssertCustomizedDefaultsFreemarkerServlet extends AssertingFreemarkerServlet {
@Override
protected Configuration createConfiguration() {
Configuration cfg = new Configuration(Configuration.VERSION_2_3_20);
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
cfg.setLogTemplateExceptions(true);
cfg.setObjectWrapper(new BeansWrapperBuilder(Configuration.VERSION_2_3_21).build());
cfg.setTemplateLoader(new WebappTemplateLoader(getServletContext()));
return cfg;
}
@Override
protected void doAssertions(Configuration cfg) {
assertEquals(Configuration.VERSION_2_3_20, cfg.getIncompatibleImprovements());
assertSame(cfg.getTemplateExceptionHandler(), TemplateExceptionHandler.RETHROW_HANDLER);
assertTrue(cfg.getLogTemplateExceptions());
{
ObjectWrapper ow = cfg.getObjectWrapper();
assertSame(BeansWrapper.class, ow.getClass());
assertEquals(Configuration.VERSION_2_3_21, ((BeansWrapper) ow).getIncompatibleImprovements());
}
{
TemplateLoader tl = cfg.getTemplateLoader();
assertTrue(tl instanceof WebappTemplateLoader);
}
}
}
public static class AssertObjectWrapperDefaults1FreemarkerServlet extends AssertingFreemarkerServlet {
@Override
protected void doAssertions(Configuration cfg) throws Exception {
ObjectWrapper ow = cfg.getObjectWrapper();
assertSame(BeansWrapper.class, ow.getClass());
assertEquals(Configuration.VERSION_2_3_21, ((BeansWrapper) ow).getIncompatibleImprovements());
}
@Override
protected ObjectWrapper createDefaultObjectWrapper() {
return new BeansWrapperBuilder(Configuration.VERSION_2_3_21).build();
}
}
public static class AssertObjectWrapperDefaults2FreemarkerServlet extends
AssertObjectWrapperDefaults1FreemarkerServlet {
@Override
protected Configuration createConfiguration() {
Configuration cfg = new Configuration(Configuration.VERSION_2_3_20);
cfg.setObjectWrapper(new SimpleObjectWrapper(Configuration.VERSION_2_3_22));
return cfg;
}
@Override
protected void doAssertions(Configuration cfg) throws Exception {
ObjectWrapper ow = cfg.getObjectWrapper();
assertSame(SimpleObjectWrapper.class, ow.getClass());
assertEquals(Configuration.VERSION_2_3_22, ((BeansWrapper) ow).getIncompatibleImprovements());
}
}
}