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/15 21:23:17 UTC

[01/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Repository: incubator-freemarker
Updated Branches:
  refs/heads/3 3fd560629 -> 28a276c80


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/transforms.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/transforms.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/transforms.txt
deleted file mode 100644
index 6b7f986..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/transforms.txt
+++ /dev/null
@@ -1,68 +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.
- */
-<html>
-<head>
-<title>FreeMarker: Transformation Test</title>
-</head>
-<body>
-
-<p>A simple test follows:</p>
-
-<p>Hello, world!</p>
-
-&lt;p&gt;Hello, world!&lt;/p&gt;
-
-<P>Now try the Utility package:</p>
-<p>Utility transformations</p>
-
-&lt;p&gt;Utility transformations&lt;/p&gt;
-
-<p>Now some nested transforms:</p>
-<p >This tests the compress transformation</p >&lt;p &gt;This tests the compress transformation&lt;/p &gt;&lt;p &gt;This tests the compress transformation&lt;/p &gt;
-<p>Now try method and transform interactions:</p>
-&lt;p&gt;This isn&apos;t a valid XML string.&lt;/p&gt;
-&lt;p&gt;This isn't a valid HTML string.&lt;/p&gt;
-
-<p>A more advanced interaction involves getting a TemplateMethodModel
-to initialise a TemplateTransformModel, as follow:</p>
-
-Comment: This is a comment
-
-A test string containing quotes: "This isn't a test".
-A test string containing amps: Fish & Chips.
-A test string containing tags: <p>Fish &amp; Chips.</p>
-
-Comment: This is a second comment
-
-A test string containing quotes: &quot;This isn&apos;t a test&quot;.
-A test string containing amps: Fish & Chips.
-A test string containing tags: <p>Fish &amp; Chips.</p>
-Comment: This is a third comment
-
-A test string containing quotes: &quot;This isn&apos;t a test&quot;.
-A test string containing amps: Fish &amp; Chips.
-A test string containing tags: <p>Fish &amp;amp; Chips.</p>
-Comment: Utility transformations
-
-A test string containing quotes: "This isn't a test".
-A test string containing amps: Fish & Chips.
-A test string containing tags: &lt;p&gt;Fish &amp; Chips.&lt;/p&gt;
-
-</body>
-</html>


[22/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/ConfigurationTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/ConfigurationTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/ConfigurationTest.java
deleted file mode 100644
index dcefa3f..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/ConfigurationTest.java
+++ /dev/null
@@ -1,1486 +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;
-
-import static org.apache.freemarker.test.hamcerst.Matchers.*;
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.io.Serializable;
-import java.io.StringWriter;
-import java.lang.reflect.Field;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-import java.util.TimeZone;
-
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateScalarModel;
-import org.apache.freemarker.core.model.impl.DefaultObjectWrapper;
-import org.apache.freemarker.core.model.impl.RestrictedObjectWrapper;
-import org.apache.freemarker.core.model.impl.SimpleScalar;
-import org.apache.freemarker.core.outputformat.MarkupOutputFormat;
-import org.apache.freemarker.core.outputformat.OutputFormat;
-import org.apache.freemarker.core.outputformat.UnregisteredOutputFormatException;
-import org.apache.freemarker.core.outputformat.impl.CombinedMarkupOutputFormat;
-import org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat;
-import org.apache.freemarker.core.outputformat.impl.RTFOutputFormat;
-import org.apache.freemarker.core.outputformat.impl.UndefinedOutputFormat;
-import org.apache.freemarker.core.outputformat.impl.XMLOutputFormat;
-import org.apache.freemarker.core.templateresolver.CacheStorageWithGetSize;
-import org.apache.freemarker.core.templateresolver.ConditionalTemplateConfigurationFactory;
-import org.apache.freemarker.core.templateresolver.FileNameGlobMatcher;
-import org.apache.freemarker.core.templateresolver.TemplateLookupContext;
-import org.apache.freemarker.core.templateresolver.TemplateLookupResult;
-import org.apache.freemarker.core.templateresolver.TemplateLookupStrategy;
-import org.apache.freemarker.core.templateresolver.impl.ByteArrayTemplateLoader;
-import org.apache.freemarker.core.templateresolver.impl.ClassTemplateLoader;
-import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateLookupStrategy;
-import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormat;
-import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormatFM2;
-import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateResolver;
-import org.apache.freemarker.core.templateresolver.impl.NullCacheStorage;
-import org.apache.freemarker.core.templateresolver.impl.SoftCacheStorage;
-import org.apache.freemarker.core.templateresolver.impl.StringTemplateLoader;
-import org.apache.freemarker.core.templateresolver.impl.StrongCacheStorage;
-import org.apache.freemarker.core.userpkg.BaseNTemplateNumberFormatFactory;
-import org.apache.freemarker.core.userpkg.CustomHTMLOutputFormat;
-import org.apache.freemarker.core.userpkg.DummyOutputFormat;
-import org.apache.freemarker.core.userpkg.EpochMillisDivTemplateDateFormatFactory;
-import org.apache.freemarker.core.userpkg.EpochMillisTemplateDateFormatFactory;
-import org.apache.freemarker.core.userpkg.HexTemplateNumberFormatFactory;
-import org.apache.freemarker.core.util._DateUtil;
-import org.apache.freemarker.core.util._NullArgumentException;
-import org.apache.freemarker.core.util._NullWriter;
-import org.apache.freemarker.core.util._StringUtil;
-import org.apache.freemarker.core.valueformat.TemplateDateFormatFactory;
-import org.apache.freemarker.core.valueformat.TemplateNumberFormatFactory;
-import org.junit.Test;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import junit.framework.TestCase;
-
-public class ConfigurationTest extends TestCase {
-
-    private static final Charset ISO_8859_2 = Charset.forName("ISO-8859-2");
-
-    public ConfigurationTest(String name) {
-        super(name);
-    }
-
-    public void testUnsetAndIsSet() throws Exception {
-        Configuration.ExtendableBuilder<?> cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
-        
-        assertFalse(cfgB.isLogTemplateExceptionsSet());
-        assertFalse(cfgB.getLogTemplateExceptions());
-        //
-        cfgB.setLogTemplateExceptions(true);
-        {
-            Configuration cfg = cfgB.build();
-            assertTrue(cfgB.isLogTemplateExceptionsSet());
-            assertTrue(cfg.isLogTemplateExceptionsSet());
-            assertTrue(cfgB.getLogTemplateExceptions());
-            assertTrue(cfg.getLogTemplateExceptions());
-        }
-        //
-        for (int i = 0; i < 2; i++) {
-            cfgB.unsetLogTemplateExceptions();
-            Configuration cfg = cfgB.build();
-            assertFalse(cfgB.isLogTemplateExceptionsSet());
-            assertTrue(cfg.isLogTemplateExceptionsSet());
-            assertFalse(cfgB.getLogTemplateExceptions());
-            assertFalse(cfg.getLogTemplateExceptions());
-        }
-
-        DefaultObjectWrapper dow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
-        assertFalse(cfgB.isObjectWrapperSet());
-        assertSame(dow, cfgB.getObjectWrapper());
-        //
-        RestrictedObjectWrapper ow = new RestrictedObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
-        cfgB.setObjectWrapper(ow);
-        assertTrue(cfgB.isObjectWrapperSet());
-        assertSame(ow, cfgB.getObjectWrapper());
-        //
-        for (int i = 0; i < 2; i++) {
-            cfgB.unsetObjectWrapper();
-            assertFalse(cfgB.isObjectWrapperSet());
-            assertSame(dow, cfgB.getObjectWrapper());
-        }
-        
-        assertFalse(cfgB.isTemplateExceptionHandlerSet());
-        assertSame(TemplateExceptionHandler.DEBUG_HANDLER, cfgB.getTemplateExceptionHandler());
-        //
-        cfgB.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
-        assertTrue(cfgB.isTemplateExceptionHandlerSet());
-        assertSame(TemplateExceptionHandler.RETHROW_HANDLER, cfgB.getTemplateExceptionHandler());
-        //
-        for (int i = 0; i < 2; i++) {
-            cfgB.unsetTemplateExceptionHandler();
-            assertFalse(cfgB.isTemplateExceptionHandlerSet());
-            assertSame(TemplateExceptionHandler.DEBUG_HANDLER, cfgB.getTemplateExceptionHandler());
-        }
-        
-        assertFalse(cfgB.isTemplateLoaderSet());
-        assertNull(cfgB.getTemplateLoader());
-        //
-        cfgB.setTemplateLoader(null);
-        assertTrue(cfgB.isTemplateLoaderSet());
-        assertNull(cfgB.getTemplateLoader());
-        //
-        for (int i = 0; i < 3; i++) {
-            if (i == 2) {
-                cfgB.setTemplateLoader(new StringTemplateLoader());
-            }
-            cfgB.unsetTemplateLoader();
-            assertFalse(cfgB.isTemplateLoaderSet());
-            assertNull(cfgB.getTemplateLoader());
-        }
-        
-        assertFalse(cfgB.isTemplateLookupStrategySet());
-        assertSame(DefaultTemplateLookupStrategy.INSTANCE, cfgB.getTemplateLookupStrategy());
-        //
-        cfgB.setTemplateLookupStrategy(DefaultTemplateLookupStrategy.INSTANCE);
-        assertTrue(cfgB.isTemplateLookupStrategySet());
-        //
-        for (int i = 0; i < 2; i++) {
-            cfgB.unsetTemplateLookupStrategy();
-            assertFalse(cfgB.isTemplateLookupStrategySet());
-        }
-        
-        assertFalse(cfgB.isTemplateNameFormatSet());
-        assertSame(DefaultTemplateNameFormatFM2.INSTANCE, cfgB.getTemplateNameFormat());
-        //
-        cfgB.setTemplateNameFormat(DefaultTemplateNameFormat.INSTANCE);
-        assertTrue(cfgB.isTemplateNameFormatSet());
-        assertSame(DefaultTemplateNameFormat.INSTANCE, cfgB.getTemplateNameFormat());
-        //
-        for (int i = 0; i < 2; i++) {
-            cfgB.unsetTemplateNameFormat();
-            assertFalse(cfgB.isTemplateNameFormatSet());
-            assertSame(DefaultTemplateNameFormatFM2.INSTANCE, cfgB.getTemplateNameFormat());
-        }
-        
-        assertFalse(cfgB.isCacheStorageSet());
-        assertTrue(cfgB.getCacheStorage() instanceof SoftCacheStorage);
-        //
-        cfgB.setCacheStorage(NullCacheStorage.INSTANCE);
-        assertTrue(cfgB.isCacheStorageSet());
-        assertSame(NullCacheStorage.INSTANCE, cfgB.getCacheStorage());
-        //
-        for (int i = 0; i < 3; i++) {
-            if (i == 2) {
-                cfgB.setCacheStorage(cfgB.getCacheStorage());
-            }
-            cfgB.unsetCacheStorage();
-            assertFalse(cfgB.isCacheStorageSet());
-            assertTrue(cfgB.getCacheStorage() instanceof SoftCacheStorage);
-        }
-    }
-    
-    public void testTemplateLoadingErrors() throws Exception {
-        Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0)
-                .templateLoader(new ClassTemplateLoader(getClass(), "nosuchpackage"))
-                .build();
-        try {
-            cfg.getTemplate("missing.ftl");
-            fail();
-        } catch (TemplateNotFoundException e) {
-            assertThat(e.getMessage(), not(containsString("wasn't set")));
-        }
-    }
-    
-    public void testVersion() {
-        Version v = Configuration.getVersion();
-        assertTrue(v.intValue() >= _CoreAPI.VERSION_INT_3_0_0);
-        
-        try {
-            new Configuration.Builder(new Version(999, 1, 2));
-        } catch (IllegalArgumentException e) {
-            assertThat(e.getMessage(), containsString("upgrade"));
-        }
-        
-        try {
-            new Configuration.Builder(new Version(2, 3, 0));
-        } catch (IllegalArgumentException e) {
-            assertThat(e.getMessage(), containsString("3.0.0"));
-        }
-    }
-    
-    public void testShowErrorTips() throws Exception {
-        try {
-            Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0).build();
-            new Template(null, "${x}", cfg).process(null, _NullWriter.INSTANCE);
-            fail();
-        } catch (TemplateException e) {
-            assertThat(e.getMessage(), containsString("Tip:"));
-        }
-
-        try {
-            Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0).showErrorTips(false).build();
-            new Template(null, "${x}", cfg).process(null, _NullWriter.INSTANCE);
-            fail();
-        } catch (TemplateException e) {
-            assertThat(e.getMessage(), not(containsString("Tip:")));
-        }
-    }
-    
-    @Test
-    @SuppressWarnings("boxing")
-    public void testGetTemplateOverloads() throws Exception {
-        final Locale hu = new Locale("hu", "HU");
-        final String tFtl = "t.ftl";
-        final String tHuFtl = "t_hu.ftl";
-        final String tEnFtl = "t_en.ftl";
-        final String tUtf8Ftl = "utf8.ftl";
-        final Serializable custLookupCond = 12345;
-
-        ByteArrayTemplateLoader tl = new ByteArrayTemplateLoader();
-        tl.putTemplate(tFtl, "${1}".getBytes(StandardCharsets.UTF_8));
-        tl.putTemplate(tEnFtl, "${1}".getBytes(StandardCharsets.UTF_8));
-        tl.putTemplate(tHuFtl, "${1}".getBytes(StandardCharsets.UTF_8));
-        tl.putTemplate(tUtf8Ftl, "<#ftl encoding='utf-8'>".getBytes(StandardCharsets.UTF_8));
-
-        Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0)
-                .locale(Locale.GERMAN)
-                .sourceEncoding(StandardCharsets.ISO_8859_1)
-                .templateLoader(tl)
-                .templateConfigurations(
-                        new ConditionalTemplateConfigurationFactory(
-                                new FileNameGlobMatcher("*_hu.*"),
-                                new TemplateConfiguration.Builder().sourceEncoding(ISO_8859_2).build()))
-                .build();
-
-        // 1 args:
-        {
-            Template t = cfg.getTemplate(tFtl);
-            assertEquals(tFtl, t.getLookupName());
-            assertEquals(tFtl, t.getSourceName());
-            assertEquals(Locale.GERMAN, t.getLocale());
-            assertNull(t.getCustomLookupCondition());
-            assertEquals(StandardCharsets.ISO_8859_1, t.getActualSourceEncoding());
-        }
-        {
-            Template t = cfg.getTemplate(tUtf8Ftl);
-            assertEquals(tUtf8Ftl, t.getLookupName());
-            assertEquals(tUtf8Ftl, t.getSourceName());
-            assertEquals(Locale.GERMAN, t.getLocale());
-            assertNull(t.getCustomLookupCondition());
-            assertEquals(StandardCharsets.UTF_8, t.getActualSourceEncoding());
-        }
-        
-        // 2 args:
-        {
-            Template t = cfg.getTemplate(tFtl, Locale.GERMAN);
-            assertEquals(tFtl, t.getLookupName());
-            assertEquals(tFtl, t.getSourceName());
-            assertEquals(Locale.GERMAN, t.getLocale());
-            assertNull(t.getCustomLookupCondition());
-            assertEquals(StandardCharsets.ISO_8859_1, t.getActualSourceEncoding());
-        }
-        {
-            Template t = cfg.getTemplate(tFtl, (Locale) null);
-            assertEquals(tFtl, t.getLookupName());
-            assertEquals(tFtl, t.getSourceName());
-            assertEquals(Locale.GERMAN, t.getLocale());
-            assertNull(t.getCustomLookupCondition());
-            assertEquals(StandardCharsets.ISO_8859_1, t.getActualSourceEncoding());
-        }
-        {
-            Template t = cfg.getTemplate(tFtl, Locale.US);
-            assertEquals(tFtl, t.getLookupName());
-            assertEquals(tEnFtl, t.getSourceName());
-            assertEquals(Locale.US, t.getLocale());
-            assertNull(t.getCustomLookupCondition());
-            assertEquals(StandardCharsets.ISO_8859_1, t.getActualSourceEncoding());
-        }
-        {
-            Template t = cfg.getTemplate(tUtf8Ftl, Locale.US);
-            assertEquals(tUtf8Ftl, t.getLookupName());
-            assertEquals(tUtf8Ftl, t.getSourceName());
-            assertEquals(Locale.US, t.getLocale());
-            assertNull(t.getCustomLookupCondition());
-            assertEquals(StandardCharsets.UTF_8, t.getActualSourceEncoding());
-        }
-        {
-            Template t = cfg.getTemplate(tFtl, hu);
-            assertEquals(tFtl, t.getLookupName());
-            assertEquals(tHuFtl, t.getSourceName());
-            assertEquals(hu, t.getLocale());
-            assertNull(t.getCustomLookupCondition());
-            assertEquals(ISO_8859_2, t.getActualSourceEncoding());
-        }
-        {
-            Template t = cfg.getTemplate(tUtf8Ftl, hu);
-            assertEquals(tUtf8Ftl, t.getLookupName());
-            assertEquals(tUtf8Ftl, t.getSourceName());
-            assertEquals(hu, t.getLocale());
-            assertNull(t.getCustomLookupCondition());
-            assertEquals(StandardCharsets.UTF_8, t.getActualSourceEncoding());
-        }
-
-        // 4 args:
-        try {
-            cfg.getTemplate("missing.ftl", hu, custLookupCond, false);
-            fail();
-        } catch (TemplateNotFoundException e) {
-            // Expected
-        }
-        assertNull(cfg.getTemplate("missing.ftl", hu, custLookupCond, true));
-        {
-            Template t = cfg.getTemplate(tFtl, hu, custLookupCond, false);
-            assertEquals(tFtl, t.getLookupName());
-            assertEquals(tHuFtl, t.getSourceName());
-            assertEquals(hu, t.getLocale());
-            assertEquals(custLookupCond, t.getCustomLookupCondition());
-            assertEquals(ISO_8859_2, t.getActualSourceEncoding());
-            assertOutputEquals("1", t);
-        }
-        {
-            Template t = cfg.getTemplate(tFtl, null, custLookupCond, false);
-            assertEquals(tFtl, t.getLookupName());
-            assertEquals(tFtl, t.getSourceName());
-            assertEquals(Locale.GERMAN, t.getLocale());
-            assertEquals(custLookupCond, t.getCustomLookupCondition());
-            assertEquals(StandardCharsets.ISO_8859_1, t.getActualSourceEncoding());
-            assertOutputEquals("1", t);
-        }
-    }
-
-    private void assertOutputEquals(final String expectedContent, final Template t) throws ConfigurationException,
-            IOException, TemplateException {
-        StringWriter sw = new StringWriter();
-        t.process(null, sw);
-        assertEquals(expectedContent, sw.toString());
-    }
-    
-    public void testTemplateResolverCache() throws Exception {
-        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
-        
-        CacheStorageWithGetSize cache = (CacheStorageWithGetSize) cfgB.getCacheStorage();
-        assertEquals(0, cache.getSize());
-        cfgB.setCacheStorage(new StrongCacheStorage());
-        cache = (CacheStorageWithGetSize) cfgB.getCacheStorage();
-        assertEquals(0, cache.getSize());
-        cfgB.setTemplateLoader(new ClassTemplateLoader(ConfigurationTest.class, ""));
-        Configuration cfg = cfgB.build();
-        assertEquals(0, cache.getSize());
-        cfg.getTemplate("toCache1.ftl");
-        assertEquals(1, cache.getSize());
-        cfg.getTemplate("toCache2.ftl");
-        assertEquals(2, cache.getSize());
-        cfg.clearTemplateCache();
-        assertEquals(0, cache.getSize());
-        cfg.getTemplate("toCache1.ftl");
-        assertEquals(1, cache.getSize());
-        cfgB.setTemplateLoader(cfgB.getTemplateLoader());
-        assertEquals(1, cache.getSize());
-    }
-
-    public void testTemplateNameFormat() throws Exception {
-        StringTemplateLoader tl = new StringTemplateLoader();
-        tl.putTemplate("a/b.ftl", "In a/b.ftl");
-        tl.putTemplate("b.ftl", "In b.ftl");
-
-        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0)
-                .templateLoader(tl);
-
-        {
-            cfgB.setTemplateNameFormat(DefaultTemplateNameFormatFM2.INSTANCE);
-            final Template template = cfgB.build().getTemplate("a/./../b.ftl");
-            assertEquals("a/b.ftl", template.getLookupName());
-            assertEquals("a/b.ftl", template.getSourceName());
-            assertEquals("In a/b.ftl", template.toString());
-        }
-        
-        {
-            cfgB.setTemplateNameFormat(DefaultTemplateNameFormat.INSTANCE);
-            final Template template = cfgB.build().getTemplate("a/./../b.ftl");
-            assertEquals("b.ftl", template.getLookupName());
-            assertEquals("b.ftl", template.getSourceName());
-            assertEquals("In b.ftl", template.toString());
-        }
-    }
-
-    public void testTemplateNameFormatSetSetting() throws Exception {
-        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
-        assertSame(DefaultTemplateNameFormatFM2.INSTANCE, cfgB.getTemplateNameFormat());
-        cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_NAME_FORMAT_KEY, "defAult_2_4_0");
-        assertSame(DefaultTemplateNameFormat.INSTANCE, cfgB.getTemplateNameFormat());
-        cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_NAME_FORMAT_KEY, "defaUlt_2_3_0");
-        assertSame(DefaultTemplateNameFormatFM2.INSTANCE, cfgB.getTemplateNameFormat());
-        assertTrue(cfgB.isTemplateNameFormatSet());
-        cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_NAME_FORMAT_KEY, "defauLt");
-        assertFalse(cfgB.isTemplateNameFormatSet());
-    }
-
-    public void testObjectWrapperSetSetting() throws Exception {
-        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
-        {
-            cfgB.setSetting(MutableProcessingConfiguration.OBJECT_WRAPPER_KEY, "defAult");
-            DefaultObjectWrapper dow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
-            assertSame(dow, cfgB.getObjectWrapper());
-            assertEquals(Configuration.VERSION_3_0_0, dow.getIncompatibleImprovements());
-        }
-        
-        {
-            cfgB.setSetting(MutableProcessingConfiguration.OBJECT_WRAPPER_KEY, "restricted");
-            assertThat(cfgB.getObjectWrapper(), instanceOf(RestrictedObjectWrapper.class));
-        }
-    }
-    
-    public void testTemplateLookupStrategyDefaultAndSet() throws Exception {
-        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
-        assertSame(DefaultTemplateLookupStrategy.INSTANCE, cfgB.getTemplateLookupStrategy());
-        assertSame(DefaultTemplateLookupStrategy.INSTANCE, cfgB.build().getTemplateLookupStrategy());
-
-        cfgB.setTemplateLoader(new ClassTemplateLoader(ConfigurationTest.class, ""));
-        assertSame(DefaultTemplateLookupStrategy.INSTANCE, cfgB.getTemplateLookupStrategy());
-        Configuration cfg = cfgB.build();
-        assertSame(DefaultTemplateLookupStrategy.INSTANCE, cfg.getTemplateLookupStrategy());
-        cfg.getTemplate("toCache1.ftl");
-
-        final TemplateLookupStrategy myStrategy = new TemplateLookupStrategy() {
-            @Override
-            public TemplateLookupResult lookup(TemplateLookupContext ctx) throws IOException {
-                return ctx.lookupWithAcquisitionStrategy("toCache2.ftl");
-            }
-        };
-        cfgB.setTemplateLookupStrategy(myStrategy);
-        assertSame(myStrategy, cfgB.getTemplateLookupStrategy());
-        cfg = cfgB.build();
-        cfg.clearTemplateCache();
-        assertSame(myStrategy, cfg.getTemplateLookupStrategy());
-        Template template = cfg.getTemplate("toCache1.ftl");
-        assertEquals("toCache2.ftl", template.getSourceName());
-    }
-    
-    public void testSetTemplateConfigurations() throws Exception {
-        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
-        assertNull(cfgB.getTemplateConfigurations());
-
-        StringTemplateLoader tl = new StringTemplateLoader();
-        tl.putTemplate("t.de.ftlh", "");
-        tl.putTemplate("t.fr.ftlx", "");
-        tl.putTemplate("t.ftlx", "");
-        tl.putTemplate("Stat/t.de.ftlx", "");
-        cfgB.setTemplateLoader(tl);
-        
-        cfgB.setTimeZone(TimeZone.getTimeZone("GMT+09"));
-        
-        cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_CONFIGURATIONS_KEY,
-                "MergingTemplateConfigurationFactory("
-                    + "FirstMatchTemplateConfigurationFactory("
-                        + "ConditionalTemplateConfigurationFactory("
-                            + "FileNameGlobMatcher('*.de.*'), TemplateConfiguration(timeZone=TimeZone('GMT+01'))), "
-                        + "ConditionalTemplateConfigurationFactory("
-                            + "FileNameGlobMatcher('*.fr.*'), TemplateConfiguration(timeZone=TimeZone('GMT'))), "
-                        + "allowNoMatch=true"
-                    + "), "
-                    + "FirstMatchTemplateConfigurationFactory("
-                        + "ConditionalTemplateConfigurationFactory("
-                            + "FileExtensionMatcher('ftlh'), TemplateConfiguration(booleanFormat='TODO,HTML')), "
-                        + "ConditionalTemplateConfigurationFactory("
-                            + "FileExtensionMatcher('ftlx'), TemplateConfiguration(booleanFormat='TODO,XML')), "
-                        + "noMatchErrorDetails='Unrecognized template file extension'"
-                    + "), "
-                    + "ConditionalTemplateConfigurationFactory("
-                        + "PathGlobMatcher('stat/**', caseInsensitive=true), "
-                        + "TemplateConfiguration(timeZone=TimeZone('UTC'))"
-                    + ")"
-                + ")");
-
-        Configuration cfg = cfgB.build();
-        {
-            Template t = cfg.getTemplate("t.de.ftlh");
-            assertEquals("TODO,HTML", t.getBooleanFormat());
-            assertEquals(TimeZone.getTimeZone("GMT+01"), t.getTimeZone());
-        }
-        {
-            Template t = cfg.getTemplate("t.fr.ftlx");
-            assertEquals("TODO,XML", t.getBooleanFormat());
-            assertEquals(TimeZone.getTimeZone("GMT"), t.getTimeZone());
-        }
-        {
-            Template t = cfg.getTemplate("t.ftlx");
-            assertEquals("TODO,XML", t.getBooleanFormat());
-            assertEquals(TimeZone.getTimeZone("GMT+09"), t.getTimeZone());
-        }
-        {
-            Template t = cfg.getTemplate("Stat/t.de.ftlx");
-            assertEquals("TODO,XML", t.getBooleanFormat());
-            assertEquals(_DateUtil.UTC, t.getTimeZone());
-        }
-        
-        assertNotNull(cfgB.getTemplateConfigurations());
-        cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_CONFIGURATIONS_KEY, "null");
-        assertNull(cfgB.getTemplateConfigurations());
-    }
-
-    public void testSetAutoEscaping() throws Exception {
-       Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
-    
-       assertEquals(ParsingConfiguration.ENABLE_IF_DEFAULT_AUTO_ESCAPING_POLICY, cfgB.getAutoEscapingPolicy());
-
-       cfgB.setAutoEscapingPolicy(ParsingConfiguration.ENABLE_IF_SUPPORTED_AUTO_ESCAPING_POLICY);
-       assertEquals(ParsingConfiguration.ENABLE_IF_SUPPORTED_AUTO_ESCAPING_POLICY, cfgB.getAutoEscapingPolicy());
-
-       cfgB.setAutoEscapingPolicy(ParsingConfiguration.ENABLE_IF_DEFAULT_AUTO_ESCAPING_POLICY);
-       assertEquals(ParsingConfiguration.ENABLE_IF_DEFAULT_AUTO_ESCAPING_POLICY, cfgB.getAutoEscapingPolicy());
-
-       cfgB.setAutoEscapingPolicy(ParsingConfiguration.DISABLE_AUTO_ESCAPING_POLICY);
-       assertEquals(ParsingConfiguration.DISABLE_AUTO_ESCAPING_POLICY, cfgB.getAutoEscapingPolicy());
-       
-       cfgB.setSetting(Configuration.ExtendableBuilder.AUTO_ESCAPING_POLICY_KEY_CAMEL_CASE, "enableIfSupported");
-       assertEquals(ParsingConfiguration.ENABLE_IF_SUPPORTED_AUTO_ESCAPING_POLICY, cfgB.getAutoEscapingPolicy());
-
-       cfgB.setSetting(Configuration.ExtendableBuilder.AUTO_ESCAPING_POLICY_KEY_CAMEL_CASE, "enable_if_supported");
-       assertEquals(ParsingConfiguration.ENABLE_IF_SUPPORTED_AUTO_ESCAPING_POLICY, cfgB.getAutoEscapingPolicy());
-       
-       cfgB.setSetting(Configuration.ExtendableBuilder.AUTO_ESCAPING_POLICY_KEY_CAMEL_CASE, "enableIfDefault");
-       assertEquals(ParsingConfiguration.ENABLE_IF_DEFAULT_AUTO_ESCAPING_POLICY, cfgB.getAutoEscapingPolicy());
-
-       cfgB.setSetting(Configuration.ExtendableBuilder.AUTO_ESCAPING_POLICY_KEY_CAMEL_CASE, "enable_if_default");
-       assertEquals(ParsingConfiguration.ENABLE_IF_DEFAULT_AUTO_ESCAPING_POLICY, cfgB.getAutoEscapingPolicy());
-       
-       cfgB.setSetting(Configuration.ExtendableBuilder.AUTO_ESCAPING_POLICY_KEY_CAMEL_CASE, "disable");
-       assertEquals(ParsingConfiguration.DISABLE_AUTO_ESCAPING_POLICY, cfgB.getAutoEscapingPolicy());
-       
-       try {
-           cfgB.setAutoEscapingPolicy(ParsingConfiguration.CAMEL_CASE_NAMING_CONVENTION);
-           fail();
-       } catch (IllegalArgumentException e) {
-           // Expected
-       }
-    }
-
-    public void testSetOutputFormat() throws Exception {
-       Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
-       
-       assertEquals(UndefinedOutputFormat.INSTANCE, cfgB.getOutputFormat());
-       assertFalse(cfgB.isOutputFormatSet());
-       
-       try {
-           cfgB.setOutputFormat(null);
-           fail();
-       } catch (_NullArgumentException e) {
-           // Expected
-       }
-       
-       assertFalse(cfgB.isOutputFormatSet());
-       
-       cfgB.setSetting(Configuration.ExtendableBuilder.OUTPUT_FORMAT_KEY_CAMEL_CASE, XMLOutputFormat.class.getSimpleName());
-       assertEquals(XMLOutputFormat.INSTANCE, cfgB.getOutputFormat());
-       
-       cfgB.setSetting(Configuration.ExtendableBuilder.OUTPUT_FORMAT_KEY_SNAKE_CASE, HTMLOutputFormat.class.getSimpleName());
-       assertEquals(HTMLOutputFormat.INSTANCE, cfgB.getOutputFormat());
-       
-       cfgB.unsetOutputFormat();
-       assertEquals(UndefinedOutputFormat.INSTANCE, cfgB.getOutputFormat());
-       assertFalse(cfgB.isOutputFormatSet());
-       
-       cfgB.setOutputFormat(UndefinedOutputFormat.INSTANCE);
-       assertTrue(cfgB.isOutputFormatSet());
-       cfgB.setSetting(Configuration.ExtendableBuilder.OUTPUT_FORMAT_KEY_CAMEL_CASE, "default");
-       assertFalse(cfgB.isOutputFormatSet());
-       
-       try {
-           cfgB.setSetting(Configuration.ExtendableBuilder.OUTPUT_FORMAT_KEY, "null");
-       } catch (ConfigurationSettingValueException e) {
-           assertThat(e.getCause().getMessage(), containsString(UndefinedOutputFormat.class.getSimpleName()));
-       }
-    }
-    
-    @Test
-    public void testGetOutputFormatByName() throws Exception {
-        Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0).build();
-        
-        assertSame(HTMLOutputFormat.INSTANCE, cfg.getOutputFormat(HTMLOutputFormat.INSTANCE.getName()));
-        
-        try {
-            cfg.getOutputFormat("noSuchFormat");
-            fail();
-        } catch (UnregisteredOutputFormatException e) {
-            assertThat(e.getMessage(), containsString("noSuchFormat"));
-        }
-        
-        try {
-            cfg.getOutputFormat("HTML}");
-            fail();
-        } catch (IllegalArgumentException e) {
-            assertThat(e.getMessage(), containsString("'{'"));
-        }
-        
-        {
-            OutputFormat of = cfg.getOutputFormat("HTML{RTF}");
-            assertThat(of, instanceOf(CombinedMarkupOutputFormat.class));
-            CombinedMarkupOutputFormat combinedOF = (CombinedMarkupOutputFormat) of;
-            assertSame(HTMLOutputFormat.INSTANCE, combinedOF.getOuterOutputFormat());
-            assertSame(RTFOutputFormat.INSTANCE, combinedOF.getInnerOutputFormat());
-        }
-
-        {
-            OutputFormat of = cfg.getOutputFormat("XML{HTML{RTF}}");
-            assertThat(of, instanceOf(CombinedMarkupOutputFormat.class));
-            CombinedMarkupOutputFormat combinedOF = (CombinedMarkupOutputFormat) of;
-            assertSame(XMLOutputFormat.INSTANCE, combinedOF.getOuterOutputFormat());
-            MarkupOutputFormat innerOF = combinedOF.getInnerOutputFormat();
-            assertThat(innerOF, instanceOf(CombinedMarkupOutputFormat.class));
-            CombinedMarkupOutputFormat innerCombinedOF = (CombinedMarkupOutputFormat) innerOF; 
-            assertSame(HTMLOutputFormat.INSTANCE, innerCombinedOF.getOuterOutputFormat());
-            assertSame(RTFOutputFormat.INSTANCE, innerCombinedOF.getInnerOutputFormat());
-        }
-        
-        try {
-            cfg.getOutputFormat("plainText{HTML}");
-            fail();
-        } catch (IllegalArgumentException e) {
-            assertThat(e.getMessage(), allOf(containsString("plainText"), containsString("markup")));
-        }
-        try {
-            cfg.getOutputFormat("HTML{plainText}");
-            fail();
-        } catch (IllegalArgumentException e) {
-            assertThat(e.getMessage(), allOf(containsString("plainText"), containsString("markup")));
-        }
-    }
-
-    public void testSetRegisteredCustomOutputFormats() throws Exception {
-        Configuration.Builder cfg = new Configuration.Builder(Configuration.VERSION_3_0_0);
-        
-        assertTrue(cfg.getRegisteredCustomOutputFormats().isEmpty());
-        
-        cfg.setSetting(Configuration.ExtendableBuilder.REGISTERED_CUSTOM_OUTPUT_FORMATS_KEY_CAMEL_CASE,
-                "[org.apache.freemarker.core.userpkg.CustomHTMLOutputFormat(), "
-                + "org.apache.freemarker.core.userpkg.DummyOutputFormat()]");
-        assertEquals(
-                ImmutableList.of(CustomHTMLOutputFormat.INSTANCE, DummyOutputFormat.INSTANCE),
-                new ArrayList(cfg.getRegisteredCustomOutputFormats()));
-        
-        try {
-            cfg.setSetting(Configuration.ExtendableBuilder.REGISTERED_CUSTOM_OUTPUT_FORMATS_KEY_SNAKE_CASE, "[TemplateConfiguration()]");
-            fail();
-        } catch (ConfigurationSettingValueException e) {
-            assertThat(e.getMessage(), containsString(OutputFormat.class.getSimpleName()));
-        }
-    }
-
-    public void testSetRecognizeStandardFileExtensions() throws Exception {
-        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
-     
-        assertTrue(cfgB.getRecognizeStandardFileExtensions());
-        assertFalse(cfgB.isRecognizeStandardFileExtensionsSet());
-
-        cfgB.setRecognizeStandardFileExtensions(false);
-        assertFalse(cfgB.getRecognizeStandardFileExtensions());
-        assertTrue(cfgB.isRecognizeStandardFileExtensionsSet());
-     
-        cfgB.unsetRecognizeStandardFileExtensions();
-        assertTrue(cfgB.getRecognizeStandardFileExtensions());
-        assertFalse(cfgB.isRecognizeStandardFileExtensionsSet());
-        
-        cfgB.setRecognizeStandardFileExtensions(true);
-        assertTrue(cfgB.getRecognizeStandardFileExtensions());
-        assertTrue(cfgB.isRecognizeStandardFileExtensionsSet());
-     
-        cfgB.setSetting(Configuration.ExtendableBuilder.RECOGNIZE_STANDARD_FILE_EXTENSIONS_KEY_CAMEL_CASE, "false");
-        assertFalse(cfgB.getRecognizeStandardFileExtensions());
-        assertTrue(cfgB.isRecognizeStandardFileExtensionsSet());
-        
-        cfgB.setSetting(Configuration.ExtendableBuilder.RECOGNIZE_STANDARD_FILE_EXTENSIONS_KEY_SNAKE_CASE, "default");
-        assertTrue(cfgB.getRecognizeStandardFileExtensions());
-        assertFalse(cfgB.isRecognizeStandardFileExtensionsSet());
-     }
-    
-    public void testSetTimeZone() throws ConfigurationException {
-        TimeZone origSysDefTZ = TimeZone.getDefault();
-        try {
-            TimeZone sysDefTZ = TimeZone.getTimeZone("GMT-01");
-            TimeZone.setDefault(sysDefTZ);
-            
-            Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
-            assertEquals(sysDefTZ, cfgB.getTimeZone());
-            cfgB.setSetting(MutableProcessingConfiguration.TIME_ZONE_KEY, "JVM default");
-            assertEquals(sysDefTZ, cfgB.getTimeZone());
-            
-            TimeZone newSysDefTZ = TimeZone.getTimeZone("GMT+09");
-            TimeZone.setDefault(newSysDefTZ);
-            assertEquals(sysDefTZ, cfgB.getTimeZone());
-            cfgB.setSetting(MutableProcessingConfiguration.TIME_ZONE_KEY, "JVM default");
-            assertEquals(newSysDefTZ, cfgB.getTimeZone());
-        } finally {
-            TimeZone.setDefault(origSysDefTZ);
-        }
-    }
-    
-    public void testSetSQLDateAndTimeTimeZone() throws ConfigurationException {
-        TimeZone origSysDefTZ = TimeZone.getDefault();
-        try {
-            TimeZone sysDefTZ = TimeZone.getTimeZone("GMT-01");
-            TimeZone.setDefault(sysDefTZ);
-            
-            Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
-            assertNull(cfgB.getSQLDateAndTimeTimeZone());
-            
-            cfgB.setSQLDateAndTimeTimeZone(null);
-            assertNull(cfgB.getSQLDateAndTimeTimeZone());
-            
-            cfgB.setSetting(MutableProcessingConfiguration.SQL_DATE_AND_TIME_TIME_ZONE_KEY, "JVM default");
-            assertEquals(sysDefTZ, cfgB.getSQLDateAndTimeTimeZone());
-            
-            cfgB.setSetting(MutableProcessingConfiguration.SQL_DATE_AND_TIME_TIME_ZONE_KEY, "null");
-            assertNull(cfgB.getSQLDateAndTimeTimeZone());
-        } finally {
-            TimeZone.setDefault(origSysDefTZ);
-        }
-    }
-
-    public void testTimeZoneLayers() throws Exception {
-        TimeZone localTZ = TimeZone.getTimeZone("Europe/Brussels");
-
-        {
-            Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0).build();
-            Template t = new Template(null, "", cfg);
-            Environment env1 = t.createProcessingEnvironment(null, new StringWriter());
-            Environment env2 = t.createProcessingEnvironment(null, new StringWriter());
-
-            // cfg:
-            assertEquals(TimeZone.getDefault(), cfg.getTimeZone());
-            assertNull(cfg.getSQLDateAndTimeTimeZone());
-            // env:
-            assertEquals(TimeZone.getDefault(), env1.getTimeZone());
-            assertNull(env1.getSQLDateAndTimeTimeZone());
-            // env 2:
-            assertEquals(TimeZone.getDefault(), env2.getTimeZone());
-            assertNull(env2.getSQLDateAndTimeTimeZone());
-
-            env1.setSQLDateAndTimeTimeZone(_DateUtil.UTC);
-            // cfg:
-            assertEquals(TimeZone.getDefault(), cfg.getTimeZone());
-            assertNull(cfg.getSQLDateAndTimeTimeZone());
-            // env:
-            assertEquals(TimeZone.getDefault(), env1.getTimeZone());
-            assertEquals(_DateUtil.UTC, env1.getSQLDateAndTimeTimeZone());
-
-            env1.setTimeZone(localTZ);
-            // cfg:
-            assertEquals(TimeZone.getDefault(), cfg.getTimeZone());
-            assertNull(cfg.getSQLDateAndTimeTimeZone());
-            // env:
-            assertEquals(localTZ, env1.getTimeZone());
-            assertEquals(_DateUtil.UTC, env1.getSQLDateAndTimeTimeZone());
-            // env 2:
-            assertEquals(TimeZone.getDefault(), env2.getTimeZone());
-            assertNull(env2.getSQLDateAndTimeTimeZone());
-        }
-
-        {
-            TimeZone otherTZ1 = TimeZone.getTimeZone("GMT+05");
-            TimeZone otherTZ2 = TimeZone.getTimeZone("GMT+06");
-            Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0)
-                    .timeZone(otherTZ1)
-                    .sqlDateAndTimeTimeZone(otherTZ2)
-                    .build();
-
-            Template t = new Template(null, "", cfg);
-            Environment env1 = t.createProcessingEnvironment(null, new StringWriter());
-            Environment env2 = t.createProcessingEnvironment(null, new StringWriter());
-
-            env1.setTimeZone(localTZ);
-            env1.setSQLDateAndTimeTimeZone(_DateUtil.UTC);
-
-            // cfg:
-            assertEquals(otherTZ1, cfg.getTimeZone());
-            assertEquals(otherTZ2, cfg.getSQLDateAndTimeTimeZone());
-            // env:
-            assertEquals(localTZ, env1.getTimeZone());
-            assertEquals(_DateUtil.UTC, env1.getSQLDateAndTimeTimeZone());
-            // env 2:
-            assertEquals(otherTZ1, env2.getTimeZone());
-            assertEquals(otherTZ2, env2.getSQLDateAndTimeTimeZone());
-
-            try {
-                setTimeZoneToNull(env2);
-                fail();
-            } catch (IllegalArgumentException e) {
-                // expected
-            }
-            env2.setSQLDateAndTimeTimeZone(null);
-            assertEquals(otherTZ1, env2.getTimeZone());
-            assertNull(env2.getSQLDateAndTimeTimeZone());
-        }
-    }
-
-    @SuppressFBWarnings(value="NP_NULL_PARAM_DEREF_ALL_TARGETS_DANGEROUS", justification="Expected to fail")
-    private void setTimeZoneToNull(Environment env2) {
-        env2.setTimeZone(null);
-    }
-    
-    public void testSetICIViaSetSettingAPI() throws ConfigurationException {
-        Configuration.Builder cfg = new Configuration.Builder(Configuration.VERSION_3_0_0);
-        assertEquals(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS, cfg.getIncompatibleImprovements());
-        // This is the only valid value ATM:
-        cfg.setSetting(Configuration.ExtendableBuilder.INCOMPATIBLE_IMPROVEMENTS_KEY, "3.0.0");
-        assertEquals(Configuration.VERSION_3_0_0, cfg.getIncompatibleImprovements());
-    }
-
-    public void testSetLogTemplateExceptionsViaSetSettingAPI() throws ConfigurationException {
-        Configuration.Builder cfg = new Configuration.Builder(Configuration.VERSION_3_0_0);
-        assertFalse(cfg.getLogTemplateExceptions());
-        cfg.setSetting(MutableProcessingConfiguration.LOG_TEMPLATE_EXCEPTIONS_KEY, "true");
-        assertTrue(cfg.getLogTemplateExceptions());
-    }
-    
-    public void testSharedVariables() throws TemplateException, IOException {
-        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
-
-        Map<String, Object> vars = new HashMap<>();
-        vars.put("a", "aa");
-        vars.put("b", "bb");
-        vars.put("c", new MyScalarModel());
-        cfgB.setSharedVariables(vars);
-
-        assertNull(cfgB.getSharedVariable("erased"));
-        
-        {
-            Configuration cfg = cfgB.build();
-
-            TemplateScalarModel aVal = (TemplateScalarModel) cfg.getWrappedSharedVariable("a");
-            assertEquals("aa", aVal.getAsString());
-            assertEquals(SimpleScalar.class, aVal.getClass());
-
-            TemplateScalarModel bVal = (TemplateScalarModel) cfg.getWrappedSharedVariable("b");
-            assertEquals("bb", bVal.getAsString());
-            assertEquals(SimpleScalar.class, bVal.getClass());
-            
-            TemplateScalarModel cVal = (TemplateScalarModel) cfg.getWrappedSharedVariable("c");
-            assertEquals("my", cVal.getAsString());
-            assertEquals(MyScalarModel.class, cfg.getWrappedSharedVariable("c").getClass());
-
-            // See if it actually works in templates:
-            StringWriter sw = new StringWriter();
-            new Template(null, "${a} ${b}", cfg)
-                    .process(ImmutableMap.of("a", "aaDM"), sw);
-            assertEquals("aaDM bb", sw.toString());
-        }
-        
-        cfgB.setSharedVariable("b", "bbLegacy");
-        
-        {
-            Configuration cfg = cfgB.build();
-
-            TemplateScalarModel aVal = (TemplateScalarModel) cfg.getWrappedSharedVariable("a");
-            assertEquals("aa", aVal.getAsString());
-            assertEquals(SimpleScalar.class, aVal.getClass());
-            
-            TemplateScalarModel bVal = (TemplateScalarModel) cfg.getWrappedSharedVariable("b");
-            assertEquals("bbLegacy", bVal.getAsString());
-            assertEquals(SimpleScalar.class, bVal.getClass());
-        }
-    }
-
-    @Test
-    public void testApiBuiltinEnabled() throws Exception {
-        try {
-            new Template(
-                    null, "${1?api}",
-                    new Configuration.Builder(Configuration.VERSION_3_0_0).build())
-                    .process(null, _NullWriter.INSTANCE);
-            fail();
-        } catch (TemplateException e) {
-            assertThat(e.getMessage(), containsString(MutableProcessingConfiguration.API_BUILTIN_ENABLED_KEY));
-        }
-            
-        new Template(
-                null, "${m?api.hashCode()}",
-                new Configuration.Builder(Configuration.VERSION_3_0_0).apiBuiltinEnabled(true).build())
-                .process(Collections.singletonMap("m", new HashMap()), _NullWriter.INSTANCE);
-    }
-
-    @Test
-    public void testTemplateUpdateDelay() throws Exception {
-        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
-
-        assertEquals(DefaultTemplateResolver.DEFAULT_TEMPLATE_UPDATE_DELAY_MILLIS, cfgB.getTemplateUpdateDelayMilliseconds());
-        
-        cfgB.setTemplateUpdateDelayMilliseconds(4000);
-        assertEquals(4000L, cfgB.getTemplateUpdateDelayMilliseconds());
-        
-        cfgB.setTemplateUpdateDelayMilliseconds(100);
-        assertEquals(100L, cfgB.getTemplateUpdateDelayMilliseconds());
-        
-        try {
-            cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_UPDATE_DELAY_KEY, "5");
-            assertEquals(5000L, cfgB.getTemplateUpdateDelayMilliseconds());
-        } catch (ConfigurationSettingValueException e) {
-            assertThat(e.getMessage(), containsStringIgnoringCase("unit must be specified"));
-        }
-        cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_UPDATE_DELAY_KEY, "0");
-        assertEquals(0L, cfgB.getTemplateUpdateDelayMilliseconds());
-        try {
-            cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_UPDATE_DELAY_KEY, "5 foo");
-            assertEquals(5000L, cfgB.getTemplateUpdateDelayMilliseconds());
-        } catch (ConfigurationSettingValueException e) {
-            assertThat(e.getMessage(), containsStringIgnoringCase("\"foo\""));
-        }
-        
-        cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_UPDATE_DELAY_KEY, "3 ms");
-        assertEquals(3L, cfgB.getTemplateUpdateDelayMilliseconds());
-        cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_UPDATE_DELAY_KEY, "4ms");
-        assertEquals(4L, cfgB.getTemplateUpdateDelayMilliseconds());
-        
-        cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_UPDATE_DELAY_KEY, "3 s");
-        assertEquals(3000L, cfgB.getTemplateUpdateDelayMilliseconds());
-        cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_UPDATE_DELAY_KEY, "4s");
-        assertEquals(4000L, cfgB.getTemplateUpdateDelayMilliseconds());
-        
-        cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_UPDATE_DELAY_KEY, "3 m");
-        assertEquals(1000L * 60 * 3, cfgB.getTemplateUpdateDelayMilliseconds());
-        cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_UPDATE_DELAY_KEY, "4m");
-        assertEquals(1000L * 60 * 4, cfgB.getTemplateUpdateDelayMilliseconds());
-
-        cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_UPDATE_DELAY_KEY, "1 h");
-        assertEquals(1000L * 60 * 60, cfgB.getTemplateUpdateDelayMilliseconds());
-        cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_UPDATE_DELAY_KEY, "2h");
-        assertEquals(1000L * 60 * 60 * 2, cfgB.getTemplateUpdateDelayMilliseconds());
-    }
-    
-    @Test
-    @SuppressFBWarnings(value = "NP_NULL_PARAM_DEREF_ALL_TARGETS_DANGEROUS ", justification = "Testing wrong args")
-    public void testSetCustomNumberFormat() throws Exception {
-        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
-        
-        try {
-            cfgB.setCustomNumberFormats(null);
-            fail();
-        } catch (IllegalArgumentException e) {
-            assertThat(e.getMessage(), containsString("null"));
-        }
-
-        try {
-            cfgB.setCustomNumberFormats(Collections.<String, TemplateNumberFormatFactory>singletonMap(
-                    "", HexTemplateNumberFormatFactory.INSTANCE));
-            fail();
-        } catch (IllegalArgumentException e) {
-            assertThat(e.getMessage(), containsString("0 length"));
-        }
-
-        try {
-            cfgB.setCustomNumberFormats(Collections.<String, TemplateNumberFormatFactory>singletonMap(
-                    "a_b", HexTemplateNumberFormatFactory.INSTANCE));
-            fail();
-        } catch (IllegalArgumentException e) {
-            assertThat(e.getMessage(), containsString("a_b"));
-        }
-
-        try {
-            cfgB.setCustomNumberFormats(Collections.<String, TemplateNumberFormatFactory>singletonMap(
-                    "a b", HexTemplateNumberFormatFactory.INSTANCE));
-            fail();
-        } catch (IllegalArgumentException e) {
-            assertThat(e.getMessage(), containsString("a b"));
-        }
-        
-        try {
-            cfgB.setCustomNumberFormats(ImmutableMap.<String, TemplateNumberFormatFactory>of(
-                    "a", HexTemplateNumberFormatFactory.INSTANCE,
-                    "@wrong", HexTemplateNumberFormatFactory.INSTANCE));
-            fail();
-        } catch (IllegalArgumentException e) {
-            assertThat(e.getMessage(), containsString("@wrong"));
-        }
-        
-        cfgB.setSetting(MutableProcessingConfiguration.CUSTOM_NUMBER_FORMATS_KEY_CAMEL_CASE,
-                "{ 'base': " + BaseNTemplateNumberFormatFactory.class.getName() + "() }");
-        assertEquals(
-                Collections.singletonMap("base", BaseNTemplateNumberFormatFactory.INSTANCE),
-                cfgB.getCustomNumberFormats());
-        
-        cfgB.setSetting(MutableProcessingConfiguration.CUSTOM_NUMBER_FORMATS_KEY_SNAKE_CASE,
-                "{ "
-                + "'base': " + BaseNTemplateNumberFormatFactory.class.getName() + "(), "
-                + "'hex': " + HexTemplateNumberFormatFactory.class.getName() + "()"
-                + " }");
-        assertEquals(
-                ImmutableMap.of(
-                        "base", BaseNTemplateNumberFormatFactory.INSTANCE,
-                        "hex", HexTemplateNumberFormatFactory.INSTANCE),
-                cfgB.getCustomNumberFormats());
-        
-        cfgB.setSetting(MutableProcessingConfiguration.CUSTOM_NUMBER_FORMATS_KEY, "{}");
-        assertEquals(Collections.emptyMap(), cfgB.getCustomNumberFormats());
-        
-        try {
-            cfgB.setSetting(MutableProcessingConfiguration.CUSTOM_NUMBER_FORMATS_KEY_CAMEL_CASE,
-                    "{ 'x': " + EpochMillisTemplateDateFormatFactory.class.getName() + "() }");
-            fail();
-        } catch (ConfigurationException e) {
-            assertThat(e.getCause().getMessage(), allOf(
-                    containsString(EpochMillisTemplateDateFormatFactory.class.getName()),
-                    containsString(TemplateNumberFormatFactory.class.getName())));
-        }
-    }
-
-    @Test
-    public void testSetTabSize() throws Exception {
-        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
-        
-        String ftl = "${\t}";
-        
-        try {
-            new Template(null, ftl, cfgB.build());
-            fail();
-        } catch (ParseException e) {
-            assertEquals(9, e.getColumnNumber());
-        }
-        
-        cfgB.setTabSize(1);
-        try {
-            new Template(null, ftl, cfgB.build());
-            fail();
-        } catch (ParseException e) {
-            assertEquals(4, e.getColumnNumber());
-        }
-        
-        try {
-            cfgB.setTabSize(0);
-            fail();
-        } catch (IllegalArgumentException e) {
-            // Expected
-        }
-        
-        try {
-            cfgB.setTabSize(257);
-            fail();
-        } catch (IllegalArgumentException e) {
-            // Expected
-        }
-    }
-
-    @Test
-    public void testTabSizeSetting() throws Exception {
-        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
-        assertEquals(8, cfgB.getTabSize());
-        cfgB.setSetting(Configuration.ExtendableBuilder.TAB_SIZE_KEY_CAMEL_CASE, "4");
-        assertEquals(4, cfgB.getTabSize());
-        cfgB.setSetting(Configuration.ExtendableBuilder.TAB_SIZE_KEY_SNAKE_CASE, "1");
-        assertEquals(1, cfgB.getTabSize());
-        
-        try {
-            cfgB.setSetting(Configuration.ExtendableBuilder.TAB_SIZE_KEY_SNAKE_CASE, "x");
-            fail();
-        } catch (ConfigurationException e) {
-            assertThat(e.getCause(), instanceOf(NumberFormatException.class));
-        }
-    }
-    
-    @SuppressFBWarnings(value="NP_NULL_PARAM_DEREF_ALL_TARGETS_DANGEROUS", justification="We test failures")
-    @Test
-    public void testSetCustomDateFormat() throws Exception {
-        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
-        
-        try {
-            cfgB.setCustomDateFormats(null);
-            fail();
-        } catch (IllegalArgumentException e) {
-            assertThat(e.getMessage(), containsString("null"));
-        }
-        
-        try {
-            cfgB.setCustomDateFormats(Collections.<String, TemplateDateFormatFactory>singletonMap(
-                    "", EpochMillisTemplateDateFormatFactory.INSTANCE));
-            fail();
-        } catch (IllegalArgumentException e) {
-            assertThat(e.getMessage(), containsString("0 length"));
-        }
-
-        try {
-            cfgB.setCustomDateFormats(Collections.<String, TemplateDateFormatFactory>singletonMap(
-                    "a_b", EpochMillisTemplateDateFormatFactory.INSTANCE));
-            fail();
-        } catch (IllegalArgumentException e) {
-            assertThat(e.getMessage(), containsString("a_b"));
-        }
-
-        try {
-            cfgB.setCustomDateFormats(Collections.<String, TemplateDateFormatFactory>singletonMap(
-                    "a b", EpochMillisTemplateDateFormatFactory.INSTANCE));
-            fail();
-        } catch (IllegalArgumentException e) {
-            assertThat(e.getMessage(), containsString("a b"));
-        }
-        
-        try {
-            cfgB.setCustomDateFormats(ImmutableMap.<String, TemplateDateFormatFactory>of(
-                    "a", EpochMillisTemplateDateFormatFactory.INSTANCE,
-                    "@wrong", EpochMillisTemplateDateFormatFactory.INSTANCE));
-            fail();
-        } catch (IllegalArgumentException e) {
-            assertThat(e.getMessage(), containsString("@wrong"));
-        }
-        
-        cfgB.setSetting(MutableProcessingConfiguration.CUSTOM_DATE_FORMATS_KEY_CAMEL_CASE,
-                "{ 'epoch': " + EpochMillisTemplateDateFormatFactory.class.getName() + "() }");
-        assertEquals(
-                Collections.singletonMap("epoch", EpochMillisTemplateDateFormatFactory.INSTANCE),
-                cfgB.getCustomDateFormats());
-        
-        cfgB.setSetting(MutableProcessingConfiguration.CUSTOM_DATE_FORMATS_KEY_SNAKE_CASE,
-                "{ "
-                + "'epoch': " + EpochMillisTemplateDateFormatFactory.class.getName() + "(), "
-                + "'epochDiv': " + EpochMillisDivTemplateDateFormatFactory.class.getName() + "()"
-                + " }");
-        assertEquals(
-                ImmutableMap.of(
-                        "epoch", EpochMillisTemplateDateFormatFactory.INSTANCE,
-                        "epochDiv", EpochMillisDivTemplateDateFormatFactory.INSTANCE),
-                cfgB.getCustomDateFormats());
-        
-        cfgB.setSetting(MutableProcessingConfiguration.CUSTOM_DATE_FORMATS_KEY, "{}");
-        assertEquals(Collections.emptyMap(), cfgB.getCustomDateFormats());
-        
-        try {
-            cfgB.setSetting(MutableProcessingConfiguration.CUSTOM_DATE_FORMATS_KEY_CAMEL_CASE,
-                    "{ 'x': " + HexTemplateNumberFormatFactory.class.getName() + "() }");
-            fail();
-        } catch (ConfigurationException e) {
-            assertThat(e.getCause().getMessage(), allOf(
-                    containsString(HexTemplateNumberFormatFactory.class.getName()),
-                    containsString(TemplateDateFormatFactory.class.getName())));
-        }
-    }
-
-    public void testNamingConventionSetSetting() throws ConfigurationException {
-        Configuration.Builder cfg = new Configuration.Builder(Configuration.VERSION_3_0_0);
-
-        assertEquals(ParsingConfiguration.AUTO_DETECT_NAMING_CONVENTION, cfg.getNamingConvention());
-        
-        cfg.setSetting("naming_convention", "legacy");
-        assertEquals(ParsingConfiguration.LEGACY_NAMING_CONVENTION, cfg.getNamingConvention());
-        
-        cfg.setSetting("naming_convention", "camel_case");
-        assertEquals(ParsingConfiguration.CAMEL_CASE_NAMING_CONVENTION, cfg.getNamingConvention());
-        
-        cfg.setSetting("naming_convention", "auto_detect");
-        assertEquals(ParsingConfiguration.AUTO_DETECT_NAMING_CONVENTION, cfg.getNamingConvention());
-    }
-
-    public void testLazyImportsSetSetting() throws ConfigurationException {
-        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
-
-        assertFalse(cfgB.getLazyImports());
-        assertFalse(cfgB.isLazyImportsSet());
-        cfgB.setSetting("lazy_imports", "true");
-        assertTrue(cfgB.getLazyImports());
-        cfgB.setSetting("lazyImports", "false");
-        assertFalse(cfgB.getLazyImports());
-        assertTrue(cfgB.isLazyImportsSet());
-    }
-    
-    public void testLazyAutoImportsSetSetting() throws ConfigurationException {
-        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
-
-        assertNull(cfgB.getLazyAutoImports());
-        assertFalse(cfgB.isLazyAutoImportsSet());
-        cfgB.setSetting("lazy_auto_imports", "true");
-        assertEquals(Boolean.TRUE, cfgB.getLazyAutoImports());
-        assertTrue(cfgB.isLazyAutoImportsSet());
-        cfgB.setSetting("lazyAutoImports", "false");
-        assertEquals(Boolean.FALSE, cfgB.getLazyAutoImports());
-        cfgB.setSetting("lazyAutoImports", "null");
-        assertNull(cfgB.getLazyAutoImports());
-        assertTrue(cfgB.isLazyAutoImportsSet());
-        cfgB.unsetLazyAutoImports();
-        assertNull(cfgB.getLazyAutoImports());
-        assertFalse(cfgB.isLazyAutoImportsSet());
-    }
-
-    public void testLocaleSetting() throws TemplateException, ConfigurationException {
-        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
-
-        assertEquals(Locale.getDefault(), cfgB.getLocale());
-        assertFalse(cfgB.isLocaleSet());
-
-        Locale nonDefault = Locale.getDefault().equals(Locale.GERMANY) ? Locale.FRANCE : Locale.GERMANY;
-        cfgB.setLocale(nonDefault);
-        assertTrue(cfgB.isLocaleSet());
-        assertEquals(nonDefault, cfgB.getLocale());
-
-        cfgB.unsetLocale();
-        assertEquals(Locale.getDefault(), cfgB.getLocale());
-        assertFalse(cfgB.isLocaleSet());
-
-        cfgB.setSetting(Configuration.ExtendableBuilder.LOCALE_KEY, "JVM default");
-        assertEquals(Locale.getDefault(), cfgB.getLocale());
-        assertTrue(cfgB.isLocaleSet());
-    }
-
-    public void testDefaultEncodingSetting() throws TemplateException, ConfigurationException {
-        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
-
-        assertEquals(Charset.defaultCharset(), cfgB.getSourceEncoding());
-        assertFalse(cfgB.isSourceEncodingSet());
-
-        Charset nonDefault = Charset.defaultCharset().equals(StandardCharsets.UTF_8) ? StandardCharsets.ISO_8859_1
-                : StandardCharsets.UTF_8;
-        cfgB.setSourceEncoding(nonDefault);
-        assertTrue(cfgB.isSourceEncodingSet());
-        assertEquals(nonDefault, cfgB.getSourceEncoding());
-
-        cfgB.unsetSourceEncoding();
-        assertEquals(Charset.defaultCharset(), cfgB.getSourceEncoding());
-        assertFalse(cfgB.isSourceEncodingSet());
-
-        cfgB.setSetting(Configuration.ExtendableBuilder.SOURCE_ENCODING_KEY, "JVM default");
-        assertEquals(Charset.defaultCharset(), cfgB.getSourceEncoding());
-        assertTrue(cfgB.isSourceEncodingSet());
-    }
-
-    public void testTimeZoneSetting() throws TemplateException, ConfigurationException {
-        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
-
-        assertEquals(TimeZone.getDefault(), cfgB.getTimeZone());
-        assertFalse(cfgB.isTimeZoneSet());
-
-        TimeZone nonDefault = TimeZone.getDefault().equals(_DateUtil.UTC) ? TimeZone.getTimeZone("PST") : _DateUtil.UTC;
-        cfgB.setTimeZone(nonDefault);
-        assertTrue(cfgB.isTimeZoneSet());
-        assertEquals(nonDefault, cfgB.getTimeZone());
-
-        cfgB.unsetTimeZone();
-        assertEquals(TimeZone.getDefault(), cfgB.getTimeZone());
-        assertFalse(cfgB.isTimeZoneSet());
-
-        cfgB.setSetting(Configuration.ExtendableBuilder.TIME_ZONE_KEY, "JVM default");
-        assertEquals(TimeZone.getDefault(), cfgB.getTimeZone());
-        assertTrue(cfgB.isTimeZoneSet());
-    }
-
-    @Test
-    public void testGetSettingNamesAreSorted() throws Exception {
-        Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0).build();
-        for (boolean camelCase : new boolean[] { false, true }) {
-            List<String> names = new ArrayList<>(Configuration.Builder.getSettingNames(camelCase));
-            List<String> procCfgNames = new ArrayList<>(new Template(null, "", cfg)
-                    .createProcessingEnvironment(null, _NullWriter.INSTANCE)
-                    .getSettingNames(camelCase));
-            assertStartsWith(names, procCfgNames);
-            
-            String prevName = null;
-            for (int i = procCfgNames.size(); i < names.size(); i++) {
-                String name = names.get(i);
-                if (prevName != null) {
-                    assertThat(name, greaterThan(prevName));
-                }
-                prevName = name;
-            }
-        }
-    }
-
-    @Test
-    @SuppressFBWarnings("DLS_DEAD_LOCAL_STORE")
-    public void testGetSettingNamesNameConventionsContainTheSame() throws Exception {
-        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
-        ConfigurableTest.testGetSettingNamesNameConventionsContainTheSame(
-                new ArrayList<>(cfgB.getSettingNames(false)),
-                new ArrayList<>(cfgB.getSettingNames(true)));
-    }
-
-    @Test
-    @SuppressFBWarnings("DLS_DEAD_LOCAL_STORE")
-    public void testStaticFieldKeysCoverAllGetSettingNames() throws Exception {
-        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
-        List<String> names = new ArrayList<>(cfgB.getSettingNames(false));
-        List<String> cfgableNames = new ArrayList<>(cfgB.getSettingNames(false));
-        assertStartsWith(names, cfgableNames);
-        
-        for (int i = cfgableNames.size(); i < names.size(); i++) {
-            String name = names.get(i);
-            assertTrue("No field was found for " + name, keyFieldExists(name));
-        }
-    }
-    
-    @Test
-    public void testGetSettingNamesCoversAllStaticKeyFields() throws Exception {
-        Collection<String> names = new Configuration.Builder(Configuration.VERSION_3_0_0).getSettingNames(false);
-        
-        for (Class<? extends MutableProcessingConfiguration> cfgableClass : new Class[] { Configuration.class, MutableProcessingConfiguration.class }) {
-            for (Field f : cfgableClass.getFields()) {
-                if (f.getName().endsWith("_KEY")) {
-                    final Object name = f.get(null);
-                    assertTrue("Missing setting name: " + name, names.contains(name));
-                }
-            }
-        }
-    }
-    
-    @Test
-    public void testKeyStaticFieldsHasAllVariationsAndCorrectFormat() throws IllegalArgumentException, IllegalAccessException {
-        ConfigurableTest.testKeyStaticFieldsHasAllVariationsAndCorrectFormat(Configuration.ExtendableBuilder.class);
-    }
-
-    @Test
-    public void testGetSettingNamesCoversAllSettingNames() throws Exception {
-        Collection<String> names = new Configuration.Builder(Configuration.VERSION_3_0_0).getSettingNames(false);
-        
-        for (Field f : MutableProcessingConfiguration.class.getFields()) {
-            if (f.getName().endsWith("_KEY")) {
-                final Object name = f.get(null);
-                assertTrue("Missing setting name: " + name, names.contains(name));
-            }
-        }
-    }
-
-    @Test
-    public void testSetSettingSupportsBothNamingConventions() throws Exception {
-        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
-        
-        cfgB.setSetting(Configuration.ExtendableBuilder.SOURCE_ENCODING_KEY_CAMEL_CASE, StandardCharsets.UTF_16LE.name());
-        assertEquals(StandardCharsets.UTF_16LE, cfgB.getSourceEncoding());
-        cfgB.setSetting(Configuration.ExtendableBuilder.SOURCE_ENCODING_KEY_SNAKE_CASE, StandardCharsets.UTF_8.name());
-        assertEquals(StandardCharsets.UTF_8, cfgB.getSourceEncoding());
-        
-        for (String nameCC : cfgB.getSettingNames(true)) {
-            for (String value : new String[] { "1", "default", "true" }) {
-                Exception resultCC = null;
-                try {
-                    cfgB.setSetting(nameCC, value);
-                } catch (Exception e) {
-                    assertThat(e, not(instanceOf(UnknownConfigurationSettingException.class)));
-                    resultCC = e;
-                }
-                
-                String nameSC = _StringUtil.camelCaseToUnderscored(nameCC);
-                Exception resultSC = null;
-                try {
-                    cfgB.setSetting(nameSC, value);
-                } catch (Exception e) {
-                    assertThat(e, not(instanceOf(UnknownConfigurationSettingException.class)));
-                    resultSC = e;
-                }
-                
-                if (resultCC == null) {
-                    assertNull(resultSC);
-                } else {
-                    assertNotNull(resultSC);
-                    assertEquals(resultCC.getClass(), resultSC.getClass());
-                }
-            }
-        }
-    }
-    
-    @Test
-    public void testGetSupportedBuiltInDirectiveNames() {
-        Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0).build();
-        
-        Set<String> allNames = cfg.getSupportedBuiltInDirectiveNames(ParsingConfiguration.AUTO_DETECT_NAMING_CONVENTION);
-        Set<String> lNames = cfg.getSupportedBuiltInDirectiveNames(ParsingConfiguration.LEGACY_NAMING_CONVENTION);
-        Set<String> cNames = cfg.getSupportedBuiltInDirectiveNames(ParsingConfiguration.CAMEL_CASE_NAMING_CONVENTION);
-        
-        checkNamingConventionNameSets(allNames, lNames, cNames);
-        
-        for (String name : cNames) {
-            assertThat(name.toLowerCase(), isIn(lNames));
-        }
-    }
-
-    @Test
-    public void testGetSupportedBuiltInNames() {
-        Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0).build();
-        
-        Set<String> allNames = cfg.getSupportedBuiltInNames(ParsingConfiguration.AUTO_DETECT_NAMING_CONVENTION);
-        Set<String> lNames = cfg.getSupportedBuiltInNames(ParsingConfiguration.LEGACY_NAMING_CONVENTION);
-        Set<String> cNames = cfg.getSupportedBuiltInNames(ParsingConfiguration.CAMEL_CASE_NAMING_CONVENTION);
-        
-        checkNamingConventionNameSets(allNames, lNames, cNames);
-    }
-
-    private void checkNamingConventionNameSets(Set<String> allNames, Set<String> lNames, Set<String> cNames) {
-        for (String name : lNames) {
-            assertThat(allNames, hasItem(name));
-            assertTrue("Should be all-lowercase: " + name, name.equals(name.toLowerCase()));
-        }
-        for (String name : cNames) {
-            assertThat(allNames, hasItem(name));
-        }
-        for (String name : allNames) {
-            assertThat(name, anyOf(isIn(lNames), isIn(cNames)));
-        }
-        assertEquals(lNames.size(), cNames.size());
-    }
-    
-    @Test
-    public void testRemovedSettings() {
-        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
-        try {
-            cfgB.setSetting("classic_compatible", "true");
-            fail();
-        } catch (ConfigurationException e) {
-            assertThat(e.getMessage(), allOf(containsString("removed"), containsString("3.0.0")));
-        }
-        try {
-            cfgB.setSetting("strict_syntax", "true");
-            fail();
-        } catch (ConfigurationException e) {
-            assertThat(e.getMessage(), allOf(containsString("removed"), containsString("3.0.0")));
-        }
-    }
-    
-    @SuppressWarnings("boxing")
-    private void assertStartsWith(List<String> list, List<String> headList) {
-        int index = 0;
-        for (String name : headList) {
-            assertThat(index, lessThan(list.size()));
-            assertEquals(name, list.get(index));
-            index++;
-        }
-    }
-
-    private boolean keyFieldExists(String name) throws Exception {
-        Field field;
-        try {
-            field = Configuration.class.getField(name.toUpperCase() + "_KEY");
-        } catch (NoSuchFieldException e) {
-            return false;
-        }
-        assertEquals(name, field.get(null));
-        return true;
-    }
-    
-    private static class MyScalarModel implements TemplateScalarModel {
-
-        @Override
-        public String getAsString() throws TemplateModelException {
-            return "my";
-        }
-        
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/CoreLocaleUtilsTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/CoreLocaleUtilsTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/CoreLocaleUtilsTest.java
deleted file mode 100644
index 6714fc3..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/CoreLocaleUtilsTest.java
+++ /dev/null
@@ -1,73 +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;
-
-import static org.junit.Assert.*;
-
-import java.util.Locale;
-
-import org.apache.freemarker.core.util._LocaleUtil;
-import org.junit.Test;
-
-public class CoreLocaleUtilsTest {
-
-    @Test
-    public void testGetLessSpecificLocale() {
-        Locale locale;
-        
-        locale = new Locale("ru", "RU", "Linux");
-        assertEquals("ru_RU_Linux", locale.toString());
-        locale = _LocaleUtil.getLessSpecificLocale(locale);
-        assertEquals("ru_RU", locale.toString());
-        locale = _LocaleUtil.getLessSpecificLocale(locale);
-        assertEquals("ru", locale.toString());
-        locale = _LocaleUtil.getLessSpecificLocale(locale);
-        assertNull(locale);
-        
-        locale = new Locale("ch", "CH");
-        assertEquals("ch_CH", locale.toString());
-        locale = _LocaleUtil.getLessSpecificLocale(locale);
-        assertEquals("ch", locale.toString());
-        locale = _LocaleUtil.getLessSpecificLocale(locale);
-        assertNull(locale);
-        
-        locale = new Locale("ja");
-        assertEquals("ja", locale.toString());
-        locale = _LocaleUtil.getLessSpecificLocale(locale);
-        assertNull(locale);
-
-        locale = new Locale("ja", "", "");
-        assertEquals("ja", locale.toString());
-        locale = _LocaleUtil.getLessSpecificLocale(locale);
-        assertNull(locale);
-        
-        locale = new Locale("");
-        assertEquals("", locale.toString());
-        locale = _LocaleUtil.getLessSpecificLocale(locale);
-        assertNull(locale);
-        
-        locale = new Locale("hu", "", "Linux");
-        assertEquals("hu__Linux", locale.toString());
-        locale = _LocaleUtil.getLessSpecificLocale(locale);
-        assertEquals("hu", locale.toString());
-        locale = _LocaleUtil.getLessSpecificLocale(locale);
-        assertNull(locale);
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/CustomAttributeTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/CustomAttributeTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/CustomAttributeTest.java
deleted file mode 100644
index 726a20c..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/CustomAttributeTest.java
+++ /dev/null
@@ -1,163 +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;
-
-import static org.junit.Assert.*;
-
-import java.math.BigDecimal;
-import java.util.Arrays;
-
-import org.junit.Test;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-
-@SuppressWarnings("boxing")
-public class CustomAttributeTest {
-    
-    private static final String KEY_1 = "key1";
-    private static final String KEY_2 = "key2";
-    private static final String KEY_3 = "key3";
-    private static final Integer KEY_4 = 4;
-
-    private static final Integer VALUE_1 = 1; // Serializable
-    private static final Object VALUE_2 = new Object();
-    private static final Object VALUE_3 = new Object();
-    private static final Object VALUE_4 = new Object();
-    private static final Object VALUE_LIST = ImmutableList.<Object>of(
-            "s", BigDecimal.valueOf(2), Boolean.TRUE, ImmutableMap.of("a", "A"));
-    private static final Object VALUE_BIGDECIMAL = BigDecimal.valueOf(22);
-
-    private static final Object CUST_ATT_KEY = new Object();
-
-    @Test
-    public void testStringKey() throws Exception {
-        // Need some MutableProcessingConfiguration:
-        TemplateConfiguration.Builder mpc = new TemplateConfiguration.Builder();
-
-        assertEquals(0, mpc.getCustomAttributeNames().length);
-        assertNull(mpc.getCustomAttribute(KEY_1));
-        
-        mpc.setCustomAttribute(KEY_1, VALUE_1);
-        assertArrayEquals(new String[] { KEY_1 }, mpc.getCustomAttributeNames());
-        assertSame(VALUE_1, mpc.getCustomAttribute(KEY_1));
-        
-        mpc.setCustomAttribute(KEY_2, VALUE_2);
-        assertArrayEquals(new String[] { KEY_1, KEY_2 }, sort(mpc.getCustomAttributeNames()));
-        assertSame(VALUE_1, mpc.getCustomAttribute(KEY_1));
-        assertSame(VALUE_2, mpc.getCustomAttribute(KEY_2));
-
-        mpc.setCustomAttribute(KEY_1, VALUE_2);
-        assertArrayEquals(new String[] { KEY_1, KEY_2 }, sort(mpc.getCustomAttributeNames()));
-        assertSame(VALUE_2, mpc.getCustomAttribute(KEY_1));
-        assertSame(VALUE_2, mpc.getCustomAttribute(KEY_2));
-
-        mpc.setCustomAttribute(KEY_1, null);
-        assertArrayEquals(new String[] { KEY_1, KEY_2 }, sort(mpc.getCustomAttributeNames()));
-        assertNull(mpc.getCustomAttribute(KEY_1));
-        assertSame(VALUE_2, mpc.getCustomAttribute(KEY_2));
-
-        mpc.removeCustomAttribute(KEY_1);
-        assertArrayEquals(new String[] { KEY_2 }, mpc.getCustomAttributeNames());
-        assertNull(mpc.getCustomAttribute(KEY_1));
-        assertSame(VALUE_2, mpc.getCustomAttribute(KEY_2));
-    }
-
-    @Test
-    public void testRemoveFromEmptySet() throws Exception {
-        // Need some MutableProcessingConfiguration:
-        TemplateConfiguration.Builder mpc = new TemplateConfiguration.Builder();
-
-        mpc.removeCustomAttribute(KEY_1);
-        assertEquals(0, mpc.getCustomAttributeNames().length);
-        assertNull(mpc.getCustomAttribute(KEY_1));
-
-        mpc.setCustomAttribute(KEY_1, VALUE_1);
-        assertArrayEquals(new String[] { KEY_1 }, mpc.getCustomAttributeNames());
-        assertSame(VALUE_1, mpc.getCustomAttribute(KEY_1));
-    }
-
-    @Test
-    public void testAttrsFromFtlHeaderOnly() throws Exception {
-        Template t = new Template(null, "<#ftl attributes={"
-                + "'" + KEY_1 + "': [ 's', 2, true, {  'a': 'A' } ], "
-                + "'" + KEY_2 + "': " + VALUE_BIGDECIMAL + " "
-                + "}>",
-                new Configuration.Builder(Configuration.VERSION_3_0_0).build());
-
-        assertEquals(ImmutableSet.of(KEY_1, KEY_2), t.getCustomAttributes().keySet());
-        assertEquals(VALUE_LIST, t.getCustomAttribute(KEY_1));
-        assertEquals(VALUE_BIGDECIMAL, t.getCustomAttribute(KEY_2));
-
-        t.setCustomAttribute(KEY_1, VALUE_1);
-        assertEquals(VALUE_1, t.getCustomAttribute(KEY_1));
-        assertEquals(VALUE_BIGDECIMAL, t.getCustomAttribute(KEY_2));
-
-        t.setCustomAttribute(KEY_1, null);
-        assertEquals(ImmutableSet.of(KEY_1, KEY_2), t.getCustomAttributes().keySet());
-        assertNull(t.getCustomAttribute(KEY_1));
-    }
-
-    @Test
-    public void testAttrsFromFtlHeaderAndFromTemplateConfiguration() throws Exception {
-        TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
-        tcb.setCustomAttribute(KEY_3, VALUE_3);
-        tcb.setCustomAttribute(KEY_4, VALUE_4);
-        Template t = new Template(null, "<#ftl attributes={"
-                + "'" + KEY_1 + "': 'a', "
-                + "'" + KEY_2 + "': 'b', "
-                + "'" + KEY_3 + "': 'c' "
-                + "}>",
-                new Configuration.Builder(Configuration.VERSION_3_0_0).build(),
-                tcb.build());
-
-        assertEquals(ImmutableSet.of(KEY_1, KEY_2, KEY_3, KEY_4), t.getCustomAttributes().keySet());
-        assertEquals("a", t.getCustomAttribute(KEY_1));
-        assertEquals("b", t.getCustomAttribute(KEY_2));
-        assertEquals("c", t.getCustomAttribute(KEY_3)); // Has overridden TC attribute
-        assertEquals(VALUE_4, t.getCustomAttribute(KEY_4)); // Inherited TC attribute
-
-        t.setCustomAttribute(KEY_3, null);
-        assertEquals(ImmutableSet.of(KEY_1, KEY_2, KEY_3, KEY_4), t.getCustomAttributes().keySet());
-        assertNull("null value shouldn't cause fallback to TC attribute", t.getCustomAttribute(KEY_3));
-    }
-
-
-    @Test
-    public void testAttrsFromTemplateConfigurationOnly() throws Exception {
-        TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
-        tcb.setCustomAttribute(KEY_3, VALUE_3);
-        tcb.setCustomAttribute(KEY_4, VALUE_4);
-        Template t = new Template(null, "",
-                new Configuration.Builder(Configuration.VERSION_3_0_0).build(),
-                tcb.build());
-
-        assertEquals(ImmutableSet.of(KEY_3, KEY_4), t.getCustomAttributes().keySet());
-        assertEquals(VALUE_3, t.getCustomAttribute(KEY_3));
-        assertEquals(VALUE_4, t.getCustomAttribute(KEY_4));
-    }
-
-    private Object[] sort(String[] customAttributeNames) {
-        Arrays.sort(customAttributeNames);
-        return customAttributeNames;
-    }
-
-}


[27/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/default-object-wrapper.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/default-object-wrapper.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/default-object-wrapper.ftl
new file mode 100644
index 0000000..bcf903d
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/default-object-wrapper.ftl
@@ -0,0 +1,59 @@
+<#--
+  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.
+-->
+<#list array as item>
+${item}
+</#list>
+${array?size}
+${array[0]}
+${array[1]}
+<#list list as item>
+${item}
+</#list>
+${list?size}
+${list?hasContent?then('not empty', 'empty')}
+${list[0]}
+${map.key}
+${map?api.get(objKey)}
+${obj.foo}
+<#if obj.foo?exists>hasfoo<#else>nofoo</#if>
+<#if obj.baz?exists>hasbaz<#else>nobaz</#if>
+${obj.bar[0]}
+${obj.getFoo()}
+${obj.overloaded(1?int)}
+${obj.overloaded("String")}
+${resourceBundle.message}
+${resourceBundle("format", date)}
+<#assign static = statics["org.apache.freemarker.test.templatesuite.models.BeanTestClass"]>
+${static.staticMethod()}
+${static.staticOverloaded(1)}
+${static.staticOverloaded("String")}
+${static.STATIC_FINAL_FIELD}
+${static.STATIC_FIELD}
+<#assign enum = enums["org.apache.freemarker.test.templatesuite.models.EnumTestClass"]>
+${enum.ONE}
+${enum.TWO}
+${enum.THREE}
+${(enum.ONE == enum.ONE)?string("true", "false")}
+${(enum.ONE == enum.TWO)?string("true", "false")}
+${enums["org.apache.freemarker.test.templatesuite.models.BeanTestClass"]?exists?string("true", "false")}
+${obj.something}
+${obj.publicInner.x}
+${obj.publicInner.m()}
+<@assertFails message="obj.privateInner.x">${obj.privateInner.x}</@>
+<@assertFails message="obj.privateInner.m">${obj.privateInner.m()}</@>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/default-xmlns.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/default-xmlns.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/default-xmlns.ftl
new file mode 100644
index 0000000..4f01835
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/default-xmlns.ftl
@@ -0,0 +1,28 @@
+<#ftl ns_prefixes={"D" : "http://x.com", "y" : "http://y.com"}>
+<#--
+  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.
+-->
+<#assign r = doc.*[0]>
+${r["N:t1"]?default('-')} = No NS
+${r["t2"]?default('-')} = x NS
+${r["y:t3"]?default('-')} = y NS
+${r["./D:t4"]?default('-')} = x NS
+
+<#assign bool = doc["true()"]>
+${bool?string}
+

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/default.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/default.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/default.ftl
new file mode 100644
index 0000000..6ecf8b3
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/default.ftl
@@ -0,0 +1,34 @@
+<#--
+  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.
+-->
+${UNDEFINED!"foo"}
+
+<#assign duck = (FOO.BAR)!"luck">
+${duck}
+
+<#list UNDEFINED![] as item>
+   ${item}
+</#list>
+
+${UNDEFINED![]?size}
+
+<#if UNDEFINED??>
+   UNDEFINED is defined.
+<#else>
+   UNDEFINED is undefined.
+</#if>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/encoding-builtins.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/encoding-builtins.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/encoding-builtins.ftl
new file mode 100644
index 0000000..6ee2a26
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/encoding-builtins.ftl
@@ -0,0 +1,52 @@
+<#--
+  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.
+-->
+FreeMarker: Encoding built-in tests
+
+<#assign x = "&<>\"'{}\\a/">
+html: [${x?html}]
+xml:  [${x?xml}]
+xhtml: [${x?xhtml}]
+rtf:  [${x?rtf}]
+<#assign x = "a&a<a>a\"a'a{a}a\\">
+html: [${x?html}]
+xml:  [${x?xml}]
+xhtml: [${x?xhtml}]
+rtf:  [${x?rtf}]
+<#assign x = "<<<<<">
+html: [${x?html}]
+xml:  [${x?xml}]
+xhtml: [${x?xhtml}]
+<#assign x = "{{{{{">
+rtf:  [${x?rtf}]
+<#assign x = "">
+html: [${x?html}]
+xml:  [${x?xml}]
+xhtml: [${x?xhtml}]
+rtf:  [${x?rtf}]
+<#assign x = "a">
+html: [${x?html}]
+xml:  [${x?xml}]
+xhtml: [${x?xhtml}]
+rtf:  [${x?rtf}]
+<#assign x = "&">
+html: [${x?html}]
+xml:  [${x?xml}]
+xhtml: [${x?xhtml}]
+<#assign x = "{">
+rtf:  [${x?rtf}]
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/escapes.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/escapes.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/escapes.ftl
new file mode 100644
index 0000000..20efc67
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/escapes.ftl
@@ -0,0 +1,79 @@
+<#--
+  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.
+-->
+<#assign h=["","a","b","c"]>
+<#assign g={"x":1,"y":2,"z":3}>
+<#escape x as h[x]>
+${1}
+${2}
+${3}
+<#escape x as g[x]>
+${"x"}
+${"y"}
+${"z"}
+<#noescape>${1}</#noescape>
+<#noescape><#noescape>${1}</#noescape></#noescape>
+</#escape>
+${1}
+${2}
+${3}
+</#escape>
+<#escape x as x?html>
+${"<&>"}
+<#escape x as x?xml>
+${"<&>"}
+</#escape>
+${"<&>"}
+</#escape>
+---
+<#assign x = "<Mooo>">
+${x} = <Mooo>
+<#escape x as x?upper_case>
+  ${x} = <MOOO>
+  <#escape x as x?html>
+    ${x} = &lt;MOOO&gt;
+    <#noescape>
+      ${x} = <MOOO>
+    </#noescape>
+    ${x} = &lt;MOOO&gt;
+  </#escape>
+  ${x} = <MOOO>
+  <#noescape>
+    ${x} = <Mooo>
+    <#escape x as x?html>
+      ${x} = &lt;Mooo&gt;
+      <#noescape>
+        ${x} = <Mooo>
+      </#noescape>
+      ${x} = &lt;Mooo&gt;
+    </#escape>
+    ${x} = <Mooo>
+  </#noescape>
+  ${x} = <MOOO>
+</#escape>
+<#escape az as ["red", "green", "blue"][az-1]>
+  ${1} ${2} ${3}
+</#escape>
+---
+<#assign s = 'A&B'>
+<#escape x as '<' + x?html + '>[' + x?lower_case + '](' + x + ')'>
+  ${s} ${s + 2}
+  <#escape x as '{' + x?lower_case + '}' + x>
+    ${s} ${s + 2}
+  </#escape>
+</#escape>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/exception.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/exception.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/exception.ftl
new file mode 100644
index 0000000..83ae356
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/exception.ftl
@@ -0,0 +1,31 @@
+<#--
+  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.
+-->
+<html>
+<head>
+<title>FreeMarker: Exception Test</title>
+</head>
+<body>
+
+<p>A simple test follows:</p>
+
+<p>${message} <br />
+${test}</p>
+
+</body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/exception2.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/exception2.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/exception2.ftl
new file mode 100644
index 0000000..83ae356
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/exception2.ftl
@@ -0,0 +1,31 @@
+<#--
+  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.
+-->
+<html>
+<head>
+<title>FreeMarker: Exception Test</title>
+</head>
+<body>
+
+<p>A simple test follows:</p>
+
+<p>${message} <br />
+${test}</p>
+
+</body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/exception3.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/exception3.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/exception3.ftl
new file mode 100644
index 0000000..f386fec
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/exception3.ftl
@@ -0,0 +1,31 @@
+<#--
+  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.
+-->
+<html>
+<head>
+<title>FreeMarker: Exception Test</title>
+</head>
+<body>
+
+<p>A simple test follows:</p>
+
+<p>${message} <br />
+${%@#$test}</p>
+
+</body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/existence-operators.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/existence-operators.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/existence-operators.ftl
new file mode 100644
index 0000000..2f9bdce
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/existence-operators.ftl
@@ -0,0 +1,141 @@
+<#--
+  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.
+-->
+<@isIRE>${v}</@>
+<@isIRE>${w}</@>
+<@isNonFastIRE>${v}</@> <#-- To check that it isn't an IRE.FAST_INSTANCE -->
+
+<@assertEquals actual=v!'-' expected='-' />
+<@assertEquals actual=(v)!'-' expected='-' />
+<@assertEquals actual=(v!) expected='' />
+<@assertEquals actual=((v)!) expected='' />
+<@isNonFastIRE>${v}</@> <#-- To check that it isn't an IRE.FAST_INSTANCE -->
+<@assertEquals actual=v?? expected=false />
+<@assertEquals actual=(v)?? expected=false />
+<@assertEquals actual=v?default('-') expected='-' />
+<@assertEquals actual=(v)?default('-') expected='-' />
+<@isNonFastIRE>${v}</@> <#-- To check that it isn't an IRE.FAST_INSTANCE -->
+<@assertEquals actual=v?exists expected=false />
+<@assertEquals actual=(v)?exists expected=false />
+<@assertEquals actual=v?if_exists expected='' />
+<@assertEquals actual=(v)?if_exists expected='' />
+<@assertEquals actual=v?has_content expected=false />
+<@assertEquals actual=(v)?has_content expected=false />
+
+<@assertEquals actual=v?default(w, '-') expected='-' />
+<@assertEquals actual=v!w!'-' expected='-' />
+<#assign w = 'W'>
+<@assertEquals actual=v?default(w, '-') expected='W' />
+<@assertEquals actual=v!w!'-' expected='W' />
+
+<#list ['V', 1.5] as v>
+	<@assertEquals actual=v!'-' expected=v />
+	<@assertEquals actual=(v)!'-' expected=v />
+	<@assert test=v?? />
+	<@assert test=(v)?? />
+	<@assertEquals actual=v?default('-') expected=v />
+	<@assertEquals actual=(v)?default('-') expected=v />
+	<@assert test=v?exists />
+	<@assert test=(v)?exists />
+	<@assertEquals actual=v?if_exists expected=v />
+	<@assertEquals actual=(v)?if_exists expected=v />
+	<@assert test=v?has_content />
+	<@assert test=(v)?has_content />
+</#list>
+<@assert test=!v?? />
+<@assert test=!v?exists />
+<@isNonFastIRE>${v}</@> <#-- To check that it isn't an IRE.FAST_INSTANCE -->
+
+<@isIRE>${u.v!'-'}</@>
+<@assertEquals actual=(u.v)!'-' expected='-' />
+<@isIRE>${u.v??}</@>
+<@assertEquals actual=(u.v)?? expected=false />
+<@isIRE>${u.v?default('-')}</@>
+<@assertEquals actual=(u.v)?default('-') expected='-' />
+<@isIRE>${u.v?exists}</@>
+<@assertEquals actual=(u.v)?exists expected=false />
+<@isIRE>${u.v?if_exists}</@>
+<@assertEquals actual=(u.v)?if_exists expected='' />
+<@isIRE>${u.v?has_content}</@>
+<@assertEquals actual=(u.v)?has_content expected=false />
+
+<#assign u = { 'x': 'X' } >
+<@assertEquals actual=u.v!'-' expected='-' />
+<@assertEquals actual=(u.v)!'-' expected='-' />
+<@assertEquals actual=u.v?? expected=false />
+<@assertEquals actual=(u.v)?? expected=false />
+<@assertEquals actual=u.v?default('-') expected='-' />
+<@assertEquals actual=(u.v)?default('-') expected='-' />
+<@assertEquals actual=u.v?exists expected=false />
+<@assertEquals actual=(u.v)?exists expected=false />
+<@assertEquals actual=u.v?if_exists expected='' />
+<@assertEquals actual=(u.v)?if_exists expected='' />
+<@assertEquals actual=u.v?has_content expected=false />
+<@assertEquals actual=(u.v)?has_content expected=false />
+
+<#assign u = { 'v': 'V' } >
+<@assertEquals actual=u.v!'-' expected='V' />
+<@assertEquals actual=(u.v)!'-' expected='V' />
+<@assert test=u.v?? />
+<@assert test=(u.v)?? />
+<@assertEquals actual=u.v?default('-') expected='V' />
+<@assertEquals actual=(u.v)?default('-') expected='V' />
+<@assert test=u.v?exists />
+<@assert test=(u.v)?exists />
+<@assertEquals actual=u.v?if_exists expected='V' />
+<@assertEquals actual=(u.v)?if_exists expected='V' />
+<@assert test=u.v?has_content />
+<@assert test=(u.v)?has_content />
+
+<#list 1..4 as i>
+  <#if i == 3><#assign x = 'X'></#if>
+  <@assertEquals actual=((x!'-') == '-') expected=(i < 3) />
+</#list>
+
+<#macro attemptTest>
+  <#attempt>
+    ${fails}
+  <#recover>
+    <@assert test=isNonFastIREMessage(.error) />
+  </#attempt>
+</#macro>
+<@attemptTest />
+${(callMacroFromExpression(attemptTest))!}
+
+<#macro interpretTest><@'$\{fails}'?interpret /></#macro>
+<#attempt>
+  <@interpretTest />
+<#recover>
+  <@assert test=isNonFastIREMessage(.error) />
+</#attempt>
+<#attempt>
+  ${(callMacroFromExpression(interpretTest))!}
+<#recover>
+  <@assert test=isNonFastIREMessage(.error) />
+</#attempt>
+
+<@assertEquals actual='fails'?eval!'-' expected='-' />
+<@assertEquals actual=('fails')?eval!'-' expected='-' />
+
+<#macro isIRE><@assertFails exception="InvalidReferenceException"><#nested></@></#macro>
+<#macro isNonFastIRE><@assertFails exception="InvalidReferenceException" message="Tip:"><#nested></@></#macro>
+<#function isNonFastIREMessage msg><#return msg?contains('Tip:') && msg?contains('null or missing')></#function>
+<#function callMacroFromExpression m>
+  <#local captured><@m /></#local>
+  <#return captured>
+</#function>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/hashconcat.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/hashconcat.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/hashconcat.ftl
new file mode 100644
index 0000000..127d828
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/hashconcat.ftl
@@ -0,0 +1,60 @@
+[#ftl]
+[#--
+  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.
+--]
+[#assign a = {"a":1, "b":2, "c":3, "X": 4}]
+[#assign b = {"d":10, "e":20, "f":30, "X": 40}]
+
+a:
+[@dump a /]
+
+B:
+[@dump b /]
+
+a + B:
+[@dump a + b /]
+
+B + a:
+[@dump b + a /]
+
+a + a:
+[@dump a + a /]
+
+{} + a:
+[@dump {} + a /]
+
+a + {}:
+[@dump a + {} /]
+
+{} + {}:
+[@dump {} + {} /]
+
+a + b + {} + b + {} + a:
+[@dump a + b + {} + b + {} + a /]
+
+
+[#macro dump s]
+[#list s?keys as k]
+  ${k} = ${s[k]}
+[/#list]
+  ---
+[#list s?values as v]
+  ${v}
+[/#list]
+  ---
+[/#macro]
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/hashliteral.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/hashliteral.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/hashliteral.ftl
new file mode 100644
index 0000000..0a02a3a
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/hashliteral.ftl
@@ -0,0 +1,100 @@
+<#--
+  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.
+-->
+<html>
+<head>
+<title>FreeMarker: Hash Literal Test</title>
+</head>
+<body>
+
+<p>A simple test follows:</p>
+
+<p>${message}</p>
+
+<p>Now perform a hash assignment:</p>
+
+<#assign mymessage = "hello", foo="bar", one="1">
+<#assign test = { "test1": "test23", 
+                 "test45" : message, 
+                  mymessage : "hello all", 
+                  foo: one}>
+
+${test.test1}
+${test.test45}
+${test.hello}
+${test.bar}
+
+<p>Now update the assignment and repeat:</p>
+
+<#assign mymessage = "world">
+
+${test.test1}
+${test.test45}
+${test.hello}
+
+${test.bar}
+
+<p>Now reassign the list and repeat:</p>
+
+<#assign hash= {"temp" : "Temporary"}>
+<#assign test = { "test1" : "test23", 
+                        "test45" : message, 
+                        mymessage : "hello all", 
+                        foo : one, 
+                        "hash" : hash[ "temp" ], 
+                        "true" : hash.temp, 
+                        "newhash" : hash}>
+
+${test.test1}
+${test.test45}
+${test.hello?if_exists}
+
+${test.bar}
+${test.hash}
+${test.true}
+${test.newhash.temp}
+
+<p>Pathological case: zero item hash:</p>
+
+<#assign test = {}>
+${test.test1?if_exists}
+
+<p>Hash of number literals:</p>
+<#assign test = {"1" : 2}>
+${test["1"]}
+
+<p>Hash concatenation:</p>
+<#assign cc = { "a" : 1, "b" : 2 } + { "b" : 3, "c" : 4 }>
+<#list cc?keys?sort as key>
+${key} => ${cc[key]}
+</#list>
+
+<p>Empty hash concatenation:</p>
+${({} + { "a" : "foo" }).a}, ${({ "a" : "bar" } + {}).a}
+
+</body>
+</html>
+<@noOutput>
+
+<#assign m = { 'a': 1, 'b', 2, 'a': 3 }>
+<@assertEquals expected="a, b" actual=m?keys?join(', ') />
+<@assertEquals expected="3, 2" actual=m?values?join(', ') />
+<@assertEquals expected=3 actual=m['a'] />
+<@assertEquals expected=2 actual=m['b'] />
+
+</...@noOutput>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/helloworld.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/helloworld.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/helloworld.ftl
new file mode 100644
index 0000000..91816f6
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/helloworld.ftl
@@ -0,0 +1,30 @@
+<#--
+  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.
+-->
+<html>
+<head>
+<title>FreeMarker: Exec Model Test</title>
+</head>
+<body>
+
+<p>A simple test follows:</p>
+
+<p>${exec( "java freemarker.test.HelloWorld" )}</p>
+
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/identifier-escaping.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/identifier-escaping.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/identifier-escaping.ftl
new file mode 100644
index 0000000..9b39235
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/identifier-escaping.ftl
@@ -0,0 +1,81 @@
+<#--
+  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.
+-->
+<#macro m\-a data\-color>
+    <#local \.namespace = 123>
+    <a-b>${data\-color}<#nested \.namespace></a-b><#t>
+</#macro>
+<#macro "m-b2"></#macro>
+<#macro "m/b2"></#macro>
+
+<@m\-a data\-color="red"; loop\-var>${loop\-var}</@>
+
+<#function f\-a p\-a>
+    <#return p\-a + " works">
+</#function>
+${f\-a("f-a")}
+
+<#assign \-\-\-\.\: = 'dash-dash-dash etc.'>
+${\-\-\-\.\:}
+${.vars['---.:']}
+<#assign hash = { '--moz-prop': 'propVal' }>
+${hash.\-\-moz\-prop}
+${hash['--moz-prop']}
+
+<#assign ls\:a = 1..3>
+List: <#list ls\:a as \:i>${\:i}</#list>
+
+<#assign sw\-a=1>
+Switch: <#switch sw\-a>
+    <#case 1>OK<#break>
+    <#default>Fails
+</#switch>
+
+<#escape \-x as \-x?upper_case>${'escaped'}</#escape>
+
+<#if false && sw\-a == 1>
+    <#visit x\-y2 using x\-y1>
+    <#recurse x\-y2 using x\-y1>
+    <#import i\-a as i\-b>
+    <#include i\-c>
+</#if>
+
+<#assign @as@_a = 'as1'>
+${@as@_a}
+<#assign 'as-c' = 'as2'>
+${.vars['as-c']}
+<#assign "as/b" = 'as3'>
+${.vars["as/b"]}
+<#assign "as'c" = 'as4'>
+${.vars["as'c"]}
+<#assign 'as"d' = 'as5'>
+${.vars['as"d']}
+
+<#global g\-a=1 g\-b=2 "g-c"=3>
+
+<#macro catchAll x y attrs...>
+<catchAll x=${x} y=${y}<#list attrs?keys?sort as k> ${k}=${attrs[k]}</#list> />
+</#macro>
+<@catchAll x=1 y=2 z=3 data\-foo=4 a\:b\.c=5 />
+
+<#macro dumpNS>
+    <#list .namespace?keys?sort as k>
+        ${k} = <#local v = .namespace[k]><#if v?is_string>${v}<#else>...</#if><#lt>
+    </#list>
+</#macro>
+<@dumpNS />

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/identifier-non-ascii.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/identifier-non-ascii.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/identifier-non-ascii.ftl
new file mode 100644
index 0000000..59a4b0e
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/identifier-non-ascii.ftl
@@ -0,0 +1,21 @@
+<#--
+  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.
+-->
+<#macro árvíztűrőTükörfúrógép טֶקסט>${טֶקסט}</#macro>
+<#assign 한국어_키보드="Korean Keyboard">
+<@árvíztűrőTükörfúrógép 한국어_키보드 />
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/if.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/if.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/if.ftl
new file mode 100644
index 0000000..97c3f4b
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/if.ftl
@@ -0,0 +1,109 @@
+<#--
+  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.
+-->
+<#assign x = 1>
+
+- <#if x == 1>good</#if>
+- <#if x == 1></#if>good
+- <#if x == 1>goo${missing!'d'}</#if>
+- <#if x == 0>wrong</#if>good
+
+- <#if x == 1>good<#else>wrong</#if>
+- <#if x == 0>wrong<#else>good</#if>
+
+- <#if x == 1>good<#elseif x == 2>wrong<#else>wrong</#if>
+- <#if x == 1>good<#elseif x == 1>wrong<#else>wrong</#if>
+- <#if x == 0>wrong<#elseif x == 1>good<#else>wrong</#if>
+- <#if x == 0>wrong<#elseif x == 2>wrong<#else>good</#if>
+
+- <#if x == 1>good<#elseif x == 1>wrong</#if>
+- <#if x == 0>wrong<#elseif x == 1>good</#if>
+- <#if x == 0>wrong<#elseif x == 2>wrong</#if>good
+- <#if x == 0>wrong<#elseif x == 1><#else>wrong</#if>good
+
+<#-- Same with pre-calculable results, just in case later the dead code will be optimized out: -->
+- <#if 1 == 1>good</#if>
+- <#if 1 == 0>wrong</#if>good
+- <#if 1 == 1>goo${missing!'d'}</#if>
+- <#if 1 == 0>wrong</#if>good
+
+- <#if 1 == 1>good<#else>wrong</#if>
+- <#if 1 == 0>wrong<#else>good</#if>
+
+- <#if 1 == 1>good<#elseif 1 == 2>wrong<#else>wrong</#if>
+- <#if 1 == 1>good<#elseif 1 == 1>wrong<#else>wrong</#if>
+- <#if 1 == 0>wrong<#elseif 1 == 1>good<#else>wrong</#if>
+- <#if 1 == 0>wrong<#elseif 1 == 2>wrong<#else>good</#if>
+
+- <#if 1 == 1>good<#elseif 1 == 1>wrong</#if>
+- <#if 1 == 0>wrong<#elseif 1 == 1>good</#if>
+- <#if 1 == 0>wrong<#elseif 1 == 2>wrong</#if>good
+- <#if 1 == 0>wrong<#elseif 1 == 1><#else>wrong</#if>good
+
+<#-- Varying branch choice of the same AST nodes: -->
+<#list [1, 2, 3, 4] as x>
+- <#if x == 1>1</#if>
+- <#if x == 2>2</#if>
+- <#if x == 3>3</#if>
+- <#if x == 1>is 1<#else>isn't 1</#if>
+- <#if x == 2>is 2<#else>isn't 2</#if>
+- <#if x == 3>is 3<#else>isn't 3</#if>
+- Finally, it's: <#if x == 1>1<#elseif x == 2>2<#elseif x == 3>3<#else>4</#if>
+</#list>
+
+<#-- nested -->
+<#list [1, 2, 3] as x><#list [1, 2, 3] as y>
+  <#assign y = x * x>
+  <#if x == 1>
+    1:
+    <#if (x > y)>
+      > ${y}
+    <#elseif x == y>
+      == ${y}
+    <#else>
+      <= ${y}
+    </#if>
+  <#elseif x == 2>
+    2:
+    <#if (x > y)>
+      > ${y}
+    <#elseif x == y>
+      == ${y}
+    <#else>
+      <= ${y}
+    </#if>
+  <#else>
+    3:
+    <#if (x > y)>
+      > ${y}
+    <#elseif x == y>
+      == ${y}
+    <#else>
+      <= ${y}
+    </#if>
+    <#if x == 3 && y == 3>
+      End
+    </#if>
+  </#if>
+</#list></#list>
+
+<#-- parsing errors -->
+<@assertFails message="valid #if-#elseif-#else"><@"<#if t><#else><#elseif t2></#if>"?interpret /></@>
+<@assertFails message="valid #if-#elseif-#else"><@"<#if t><#else><#else></#if>"?interpret /></@>
+<@assertFails message="valid #if-#elseif-#else"><@"<#else></#else>"?interpret /></@>
+<@assertFails message="valid #if-#elseif-#else"><@"<#elseif t></#elseif>"?interpret /></@>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/import.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/import.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/import.ftl
new file mode 100644
index 0000000..bddd857
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/import.ftl
@@ -0,0 +1,45 @@
+<#--
+  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.
+-->
+--
+<#-- import "/import_lib.ftl" as my -->
+--
+
+<#if mail?exists || test?exists>
+  <#stop "mail or test should not exist">
+</#if>
+
+${my.mail}
+<@my.test foo="bar"/>
+
+<#assign mail="jsmith@other1.com">
+${my.mail}
+<@my.test foo="bar"/>
+
+<#assign mail in my>
+  jsmith@other2.com<#t>
+</#assign>
+${my.mail}
+<@my.test foo="bar"/>
+
+<#import "/import_lib.ftl" as my2>
+${my2.mail}
+<#assign mail="jsmith@other3.com" in my2>
+${my.mail}
+
+${my2.doubleUp("foobar")}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/import_lib.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/import_lib.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/import_lib.ftl
new file mode 100644
index 0000000..3329af9
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/import_lib.ftl
@@ -0,0 +1,31 @@
+<#--
+  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.
+-->
+<#macro test foo>
+  Test ${foo}.
+  Email: ${mail}
+  <#if .main.mail?exists>
+    Email in the root: ${.main.mail}
+  </#if>
+</#macro>
+
+<#function doubleUp foo>
+   <#return foo+foo>
+</#function>
+
+<#assign mail = "jsmith@acme.com">
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/include.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/include.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/include.ftl
new file mode 100644
index 0000000..3e997e7
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/include.ftl
@@ -0,0 +1,47 @@
+<#--
+  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.
+-->
+<html>
+<head>
+<title>FreeMarker: Include Instruction Test</title>
+</head>
+<body>
+
+<p>A simple test follows:</p>
+
+${message}
+
+<#if message?exists>
+	<p>Message exists!
+</#if>
+
+<p>Test normal includes:</p>
+<#include "included.ftl">
+
+${foo}
+${nestedMessage}
+
+<@twice>
+Kilroy
+</...@twice>
+
+<p>Test subdir includes:</p>
+<#include "subdir/include-subdir.ftl">
+</body>
+</html>
+

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/include2-included.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/include2-included.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/include2-included.ftl
new file mode 100644
index 0000000..db9dfc1
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/include2-included.ftl
@@ -0,0 +1,19 @@
+<#--
+  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.
+-->
+${'A'} próba

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/include2.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/include2.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/include2.ftl
new file mode 100644
index 0000000..5f3ccc3
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/include2.ftl
@@ -0,0 +1,32 @@
+<#--
+  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.
+-->
+<#include "include2" + "-included.ftl">
+<#assign s = "de">
+<#include "inclu" + s + "2-included.ftl">
+
+<#assign bTrue=true>
+<#assign bFalse=false>
+<#include "include2-included.ftl" ignore_missing=true>
+<#include "include2-included.ftl" ignore_missing=bTrue>
+<#include "include2-included.ftl" ignore_missing=false>
+<#include "include2-included.ftl" ignore_missing=bFalse>
+
+<@assertFails message="not found"><#include "missing.ftl"></@>
+[<#include "missing.ftl" ignore_missing=true>]
+[<#include "missing.ftl" ignore_missing=bTrue>]

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/included.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/included.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/included.ftl
new file mode 100644
index 0000000..f711a67
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/included.ftl
@@ -0,0 +1,30 @@
+<#--
+  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.
+-->
+<p>A test of included files:</p>
+
+<#if .globals.message?exists>
+	<p>Message exists!:<br />
+        ${.globals.message}</p>
+<#else>
+        <p>No message :(</p>
+</#if>
+
+<#assign foo="assigning from included template", bar=" Can you see me? ">
+<#macro twice><#nested/>${bar}<#nested/></#macro>
+<#include "nestedinclude.ftl">

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/interpret.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/interpret.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/interpret.ftl
new file mode 100644
index 0000000..41f8425
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/interpret.ftl
@@ -0,0 +1,25 @@
+<#--
+  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.
+-->
+<#global x=["a", "b", "c"]>
+<#global templateSource = r"<#list x as y>${y}</#list>">
+<@templateSource?interpret>def</@>
+<@[templateSource]?interpret>def</@>
+<@[templateSource,"id"]?interpret>def</@>
+
+<#assign t = '<#macro m>M</#macro>'?interpret><@t /><@m/>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/iterators.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/iterators.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/iterators.ftl
new file mode 100644
index 0000000..389abf3
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/iterators.ftl
@@ -0,0 +1,71 @@
+<#--
+  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.
+-->
+<html>
+<head>
+<title>FreeMarker: List Iterator Test</title>
+</head>
+<body>
+<#assign list= ["one", "two", "three", "four", "five"]>
+<#assign hash = {"key", list}>
+<#assign  hash2 = {"value", hash}>
+
+<p>A simple test follows:</p>
+
+<p>${message}</p>
+
+<p>Now iterate over a list:</p>
+
+<#list list as item>
+<p>${item}</p>
+</#list>
+
+<p>Now iterate again:</p>
+
+<#list list as item>
+<p>${item_index}. ${item}</p>
+</#list>
+
+<p>Iterate over a list in a hash:</p>
+
+<#list hash.key as item>
+<p>${item}</p>
+</#list>
+
+<#list hash.key as item>
+<p>${item}</p>
+</#list>
+
+<#list hash[ "key" ] as item>
+<p>${item}</p>
+</#list>
+
+<#list hash["key"] as item>
+<p>${item}</p>
+</#list>
+
+<#list hash2["value"].key as key>
+<p>${key}</p>
+</#list>
+
+<#list hash2.value.key as az>
+<p>${az}</p>
+</#list>
+
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/lastcharacter.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/lastcharacter.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/lastcharacter.ftl
new file mode 100644
index 0000000..e762356
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/lastcharacter.ftl
@@ -0,0 +1,31 @@
+<#--
+  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.
+-->
+<html>
+<head>
+<title>FreeMarker: Last Character Test</title>
+</head>
+<body>
+
+<p>A simple test follows:</p>
+  
+    #{message?capitalize?length}
+    
+    ${message [1..] ? upper_case}
+    
+    message: ${message ?capitalize[0..10]}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/list-bis.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/list-bis.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/list-bis.ftl
new file mode 100644
index 0000000..e52307f
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/list-bis.ftl
@@ -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.
+-->
+<#list ['a', 'b', 'c'] as x>
+    ${x?index}: ${x} [<#list ['A', 'B', 'C'] as x>${x?index}:${x}<#sep>, </#list>]
+</#list>
+
+<#list ['a', 'b', 'c'] as i>
+    ${i?index}: ${i} <#list ['A', 'B', 'C'] as j>${i?index}${i}/${j?index}${j}<#sep>, </#list>
+</#list>
+
+<#list ['a', 'b', 'c']><#items as x>${x?index}:${x}<#sep>, </#items></#list>
+<#list ['a', 'b', 'c']><#items as x>${x?counter}. ${x};<#sep> </#items></#list>
+
+<#list ['a', 'b', 'c'] as x>${x}<#if x?hasNext>, </#if></#list>
+<#list ['a', 'b', 'c'] as x\-y>${x\-y}<#if x\-y?hasNext>, </#if></#list>
+
+<#list ['a', 'b', 'c'] as x><#if x?isFirst>${x?capFirst}<#else>${x}</#if><#sep>, </#sep><#if x?isLast>.</#if></#list>
+
+<#list ['a', 'b', 'c'] as x>${x?isOddItem?c}/${x?isEvenItem?c}<#sep> </#list>
+
+<#list ['a', 'b', 'c'] as x>
+    <td class="${x?itemParity}Row">${x}</td>
+</#list>
+
+<#list ['a', 'b', 'c'] as x>
+    <td class="row${x?itemParityCap}">${x}</td>
+</#list>
+
+<#list ['a', 'b', 'c', 'd', 'e', 'f', 'g'] as x>
+    <td class="${x?itemCycle('R', 'G', 'B')}">${x}</td>
+</#list>
+<@assertFails message="expects 1"><#list 1..1 as x>${x?itemCycle()}</#list></@>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/list.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/list.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/list.ftl
new file mode 100644
index 0000000..280491c
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/list.ftl
@@ -0,0 +1,44 @@
+<#--
+  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.
+-->
+<@testList ["aardvark", "bear", "cat", "dog"] />
+
+<@testList ["aardvark"] />
+
+<@testList [] />
+
+<@testList listables.list />
+
+<@testList listables.linkedList />
+
+<@testList listables.set />
+
+<@testList listables.iterator />
+
+<@testList listables.emptyList />
+
+<@testList listables.emptyLinkedList />
+
+<@testList listables.emptySet />
+
+<@testList listables.emptyIterator />
+
+<#macro testList seq>
+Size: <#attempt>${seq?size}<#recover>failed</#attempt>
+Items: <#list seq as i>@${i_index} ${i}<#if i_has_next>, <#else>.</#if></#list>
+</#macro>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/list2.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/list2.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/list2.ftl
new file mode 100644
index 0000000..db64a4b
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/list2.ftl
@@ -0,0 +1,90 @@
+<#--
+  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.
+-->
+<@testList ["aardvark", "bear", "cat", "dog"] />
+
+<@testList ["aardvark"] />
+
+<@testList [] />
+
+<@testList listables.list />
+
+<@testList listables.set />
+
+<@testList listables.getIterator />
+
+<@testList listables.emptyList />
+
+<@testList listables.emptySet />
+
+<@testList listables.getEmptyIterator />
+
+<#macro testList xs>
+=== [${resolve(xs)?join(", ")}] ===
+<#assign resolveCallCnt = 0>
+
+-- List+sep:
+<#list resolve(xs) as x>
+    ${x}<#sep>,</#sep>
+</#list>
+-- List+else:
+<#list resolve(xs) as x>
+    ${x}
+<#else>
+    Empty!
+</#list>
+-- List+items:
+<#list resolve(xs)>
+    [
+    <#items as x>
+        ${x!'U'}
+    </#items>
+    ]
+</#list>
+-- List+items+else:
+<#list resolve(xs)>
+    [
+    <#items as x>
+        ${x!'U'}
+    </#items>
+    ]
+<#else>
+    Empty!
+</#list>
+-- List+items+sep+else:
+<#list resolve(xs)>
+    [
+    <#items as x>
+        ${x!'U'}<#sep>,</#sep>
+    </#items>
+    ]
+<#else>
+    Empty!
+</#list>
+<@assertEquals expected=5 actual=resolveCallCnt />
+--
+</#macro>
+
+<#function resolve xs>
+    <#assign resolveCallCnt = (resolveCallCnt!0) + 1>
+    <#if xs?isMethod>
+        <#return xs()>
+    <#else>
+        <#return xs>
+    </#if>
+</#function>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/list3.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/list3.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/list3.ftl
new file mode 100644
index 0000000..d2fcf71
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/list3.ftl
@@ -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.
+-->
+[
+<#list listables.list as i>
+    [<#list listables.list as j>(${i}@${i_index}, ${j}@${j_index})<#sep>, </#sep></#list>]<#sep>,</#sep>
+</#list>
+]
+
+<#macro hits xs style="">
+    <#list xs>
+        <p>${xs?size} hits:
+        <div class="hits">
+            <#switch style>
+                <#case "hidden">
+                    ...
+                    <#break>
+                <#case "other">
+                    <#items as x>
+                        <div class="hitOther">${x}</div>
+                    </#items>
+                    <#break>
+                <#case "none">
+                <#default>
+                    <#items as x>
+                        <div class="hit">${x}</div>
+                    </#items>
+                    <#break>
+            </#switch>
+        </div>
+    <#else>
+        <p>Nothing.
+    </#list>
+</#macro>
+
+<@hits ['a', 'b'] />
+
+<@hits ['a', 'b'], "other" />
+
+<@hits ['a', 'b'], "hidden" />
+
+<@hits [] />
+
+<#list listables.list as i><#if i_index gt 1>...<#break></#if>${i}<#sep>, </#sep></#list>
+<#list listables.list>[<#items as i><#if i_index gt 1>...<#break></#if>${i}<#sep>, </#sep></#items>]</#list>
+
+<@testAutoClosedSep 1..3 />
+<@testAutoClosedSep [1] />
+<@testAutoClosedSep [] />
+
+<#macro testAutoClosedSep xs>
+<#list xs as x>${x}<#sep>, <#else>Empty</#list>
+<#list xs as x>${x}<#sep><#if x_index == 0> /*first*/, <#else>, </#if><#else>Empty</#list>
+<#list xs>[<#items as x>${x}<#sep>, </#items>]<#else>Empty</#list>
+</#macro>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/listhash.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/listhash.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/listhash.ftl
new file mode 100644
index 0000000..6f22b43
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/listhash.ftl
@@ -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.
+-->
+<#setting booleanFormat='Y,N'>
+
+<#macro listings maps>
+  <#list maps as m>
+    Map:
+    
+    [
+    <#list m as k, v>
+      ${k!'null'} = ${v!'null'}
+    </#list>
+    ]
+  
+    [
+    <#list m as k, v>
+      ${k!'null'} = ${v!'null'}<#sep>;</#sep> // @${k?index}=@${v?index}; ${k?itemParity}=${v?itemParity}; ${k?hasNext}=${v?hasNext}
+    <#else>
+      Empty
+    </#list>
+    ]
+  
+    {
+    <#list m>
+      [
+      <#items as k, v>
+        ${k!'null'} = ${v!'null'}<#sep>;</#sep> // @${k?index}=@${v?index}; ${k?itemParity}=${v?itemParity}; ${k?hasNext}=${v?hasNext}
+      </#items>
+      ]
+    <#else>
+      Empty
+    </#list>
+    }
+
+  </#list>
+</#macro>
+
+Non-empty maps:
+
+<@listings listables.hashEx2s />
+<@listings [ listables.hashNonEx2 ] />
+
+Empty maps:
+
+<@listings listables.emptyHashes />
+
+<#list { 'a': { 'aa': 11 }, 'b': { 'ba': 21, 'bb': 22 }, 'c': {} } as k1, v1>
+  ${k1} @ ${k1?index}, ${v1?size}
+  <#list v1 as k2, v2>
+    ${k2} = ${v2}  @ ${k2?index} // inside ${k1} @ ${k1?index}, ${v1?size}
+  </#list>
+  ${k1} @ ${k1?index}, ${v1?size}
+  --
+</#list>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/listhashliteral.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/listhashliteral.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/listhashliteral.ftl
new file mode 100644
index 0000000..06694c9
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/listhashliteral.ftl
@@ -0,0 +1,35 @@
+<#--
+  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.
+-->
+<#list [ { "a": 1, "b": 2, "a": 3 }, { } ] as h>
+  KVPs:
+  <#list h as k, v>
+    ${k} = ${v}
+  </#list>
+  
+  Keys:
+  <#list h?keys as k>
+    ${k}
+  </#list>
+  
+  Values:
+  <#list h?values as v>
+    ${v}
+  </#list>
+
+</#list>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/listliteral.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/listliteral.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/listliteral.ftl
new file mode 100644
index 0000000..d48578c
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/listliteral.ftl
@@ -0,0 +1,84 @@
+<#--
+  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.
+-->
+<html>
+<head>
+<title>FreeMarker: List Literal Test</title>
+</head>
+<body>
+
+<p>A simple test follows:</p>
+
+<p>${message}</p>
+
+<p>Now perform a list assignment:</p>
+
+<#assign hash = {"temp", "Temporary"}>
+<#assign mymessage = "hello">
+<#assign test = [ "test1", "test23", "test45", message, mymessage]>
+
+The list contains #{test?size} items.
+
+<#list test as item>
+<p>${item}</p>
+</#list>
+
+<p>Now update the assignment and repeat:</p>
+
+<#assign mymessage = "world">
+
+<#list test as item>
+<p>${item}</p>
+</#list>
+
+<p>Now reassign the list and repeat:</p>
+
+<#assign test = [ hash.temp, "test1", "test23", "test45", mymessage, "hash", hash["temp"]]>
+<#assign test = [ "foo", "bar" ] + test>
+
+<#list test[1..4] as item>
+<p>${item}</p>
+</#list>
+
+<p>Silly, but necessary tests, for one and zero element lists:</p>
+
+<#assign test = [ "Hello, world" ]>
+
+<#list test as item>
+<p>${item}</p>
+</#list>
+
+<p>Zero item test:</p>
+
+<#assign test = []>
+
+<#list test as item>
+<p>${item}</p>
+</#list>
+
+<p>Dumb test for number literals -- these weren't working as expected:</p>
+
+<#assign test = [] + [1, 2,3, 5, 7]>
+
+<#list test as item>
+<p>${item}</p>
+<#if item == 5><#break></#if>
+</#list>
+
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/localization.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/localization.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/localization.ftl
new file mode 100644
index 0000000..cf46fbf
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/localization.ftl
@@ -0,0 +1,32 @@
+<#--
+  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.
+-->
+<html>
+<head>
+<title>FreeMarker: Localization Test</title>
+</head>
+<body>
+
+<p>A simple test follows:</p>
+
+<p>${message}</p>
+
+<p>Hello, in the default language.</p>
+
+</body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/localization_en.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/localization_en.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/localization_en.ftl
new file mode 100644
index 0000000..f8292bc
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/localization_en.ftl
@@ -0,0 +1,32 @@
+<#--
+  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.
+-->
+<html>
+<head>
+<title>FreeMarker: Localization Test</title>
+</head>
+<body>
+
+<p>A simple test follows:</p>
+
+<p>${message}</p>
+
+<p>Hello, in the English language.</p>
+
+</body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/localization_en_AU.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/localization_en_AU.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/localization_en_AU.ftl
new file mode 100644
index 0000000..938f681
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/localization_en_AU.ftl
@@ -0,0 +1,32 @@
+<#--
+  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.
+-->
+<html>
+<head>
+<title>FreeMarker: Localization Test</title>
+</head>
+<body>
+
+<p>A simple test follows:</p>
+
+<p>${message}</p>
+
+<p>G'day, mate!</p>
+
+</body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/logging.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/logging.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/logging.ftl
new file mode 100644
index 0000000..c44d6b8
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/logging.ftl
@@ -0,0 +1,42 @@
+<#--
+  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.
+-->
+<html>
+<head>
+<title>FreeMarker: Logging Test</title>
+</head>
+<body>
+
+A simple test follows:
+
+${message.test[ "me" ]}
+
+<if message>
+	<p>Message exists!
+	<transform message.sdf>
+		...and even generates output!
+	</transform>
+	</p>
+</if>
+
+<compress>
+Try this for size.
+</compress>
+
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/loopvariable.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/loopvariable.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/loopvariable.ftl
new file mode 100644
index 0000000..bc77b82
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/loopvariable.ftl
@@ -0,0 +1,49 @@
+<#--
+  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.
+-->
+<#setting locale="en_US">
+---
+<#macro myLoop from to>
+  <#list from..to as x>
+  - <#nested x></#list>*
+</#macro>
+<#list 2..1 as i>
+  ${i}
+  <@myLoop from=1 to=3; i>
+    L1 ${i}
+    <@myLoop from=1 to=2; i>
+      L2 ${i}: <#list 1..3 as i>${i}; </#list>
+    </@>
+  </@>
+</#list>
+---
+<#macro repeat count>
+  <#list 1..count as x>
+    <#nested x, x/2, x==count>
+  </#list>
+</#macro>
+<#macro test2>
+<#local c = 123>
+<@repeat count=4 ; c, halfc, last>
+  <#local c = .locals.c + 0.1>
+  ${c} ${halfc}<#if last> Last!</#if>
+</...@repeat>
+${c}
+</#macro>
+<@test2/>
+---
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/macros-return.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/macros-return.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/macros-return.ftl
new file mode 100644
index 0000000..220fa2a
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/macros-return.ftl
@@ -0,0 +1,34 @@
+<#--
+  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.
+-->
+<#macro m>m{<#return>}</#macro>
+<@m/>
+
+<#macro m><#if true>m{<#return>}</#if></#macro>
+<@m/>
+
+<#macro m><#if true>m{<#return></#if>}</#macro>
+<@m/>
+
+<#macro b>b{<#nested>}</#macro>
+<#macro m><@b><#return></@></#macro>
+<@m/>
+
+<#macro b>b{<#nested>}</#macro>
+<#macro m>m:<@b><#return></@></#macro>
+<@m/>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/macros.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/macros.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/macros.ftl
new file mode 100644
index 0000000..9d8f456
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/macros.ftl
@@ -0,0 +1,101 @@
+<#--
+  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.
+-->
+<html>
+<head>
+<title>FreeMarker: Function Test</title>
+</head>
+<body>
+
+<p>A simple test follows:</p>
+
+<p>${message}</p>
+
+<p>Now perform function tests:</p>
+
+<#assign urls = {"home" : "/home.html", "about" : "/about.html"}>
+<#assign images = {"home" : "/images/home.png", "about" : "/image/about-us.jpeg"}>
+<#assign preferences = {"showImages" : true}>
+<#assign "español" = français><#macro français(url, image, alt)>
+    <#local var = "Kilroy">
+    <a href="${url}">
+    <#if preferences.showImages>
+        <img src="${image}" border="0" alt="${alt}">
+    <#else>
+        ${alt}
+    </#if>
+    </a>
+    ${var} was here.
+</#macro>
+
+<p>Function is defined, now let's call it:</p>
+
+   <@español urls.home images.home "Home" /><#t>
+
+<p>Again, but with different parameters:</p>
+
+<@français 
+   url=urls.about 
+   image=images.about 
+   alt="About Us"
+/>
+
+<#if var?exists>
+   Something is wrong here.
+<#else>
+   Good.
+</#if>
+
+<p>A recursive function call:</p>
+
+<#macro recurse(dummy, a=3)>
+    <#if (a > 0)>
+        <@recurse dummy  a - 1 />
+    </#if>
+    ${a}
+</#macro>
+
+<@recurse urls />
+
+<p>Test "catch-all" macro parameter:</p>
+
+<#macro "catch-all" foo bar...>
+foo=${foo} baz=[<#list bar?keys?sort as key>${key}=${bar[key]}<#if key_has_next>, </#if></#list>]
+</#macro>
+<#assign catchall = .namespace["catch-all"]>
+
+<@catchall foo="a"/>
+<@catchall foo="a" bar="b"/>
+<@catchall foo="a" bar="b" baz="c"/>
+
+<#macro fmt pattern args...>
+  <#list args as arg>
+    <#local pattern = pattern?replace("{" + arg_index + "}", arg)>
+  </#list>
+  ${pattern}<#lt>
+</#macro>
+
+<#macro m a=1 b=2>
+</#macro>
+<@assertFails message='"c"'><@m c=3 /></@>
+<@assertFails message='3'><@m 9 8 7 /></@>
+
+<@fmt "Hello {0}! Today is {1}.", "World", "Monday" />
+
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/macros2.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/macros2.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/macros2.ftl
new file mode 100644
index 0000000..55ceefd
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/macros2.ftl
@@ -0,0 +1,35 @@
+<#--
+  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.
+-->
+<#macro m1 a b=a>
+${a} ${b}
+</#macro>
+<@m1 a="1"/>
+<#macro m2 a=b b="">
+${a} ${b}
+</#macro>
+<@m2 b="2"/>
+<#macro m3 d b=c[a] a=d c={"3":"4"}>
+${b}
+</#macro>
+<@m3 d="3"/>
+<#attempt>
+<@m3 d="4"/>
+<#recover>
+m3 with d="4" Failed!
+</#attempt>
\ No newline at end of file



[31/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-strlitinterpolation.ast
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-strlitinterpolation.ast b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-strlitinterpolation.ast
new file mode 100644
index 0000000..321721e
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-strlitinterpolation.ast
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+#mixed_content  // o.a.f.c.ASTImplicitParent
+    #text  // o.a.f.c.ASTStaticText
+        - content: "1. "  // String
+    @  // o.a.f.c.ASTDirUserDefined
+        - callee: m  // o.a.f.c.ASTExpVariable
+        - argument name: "x"  // String
+        - argument value: dynamic "..."  // o.a.f.c.ASTExpStringLiteral
+            - value part: ${...}  // o.a.f.c.ASTDollarInterpolation
+                - content: e1  // o.a.f.c.ASTExpVariable
+        - argument name: "y"  // String
+        - argument value: "$\\{e2}"  // o.a.f.c.ASTExpStringLiteral
+    #text  // o.a.f.c.ASTStaticText
+        - content: "\n2. "  // String
+    ${...}  // o.a.f.c.ASTDollarInterpolation
+        - content: dynamic "..."  // o.a.f.c.ASTExpStringLiteral
+            - value part: "a"  // String
+            - value part: ${...}  // o.a.f.c.ASTDollarInterpolation
+                - content: x  // o.a.f.c.ASTExpVariable
+            - value part: "b"  // String
+            - value part: ${...}  // o.a.f.c.ASTDollarInterpolation
+                - content: x  // o.a.f.c.ASTExpVariable
+            - value part: "c"  // String
+    #text  // o.a.f.c.ASTStaticText
+        - content: "\n3. "  // String
+    ${...}  // o.a.f.c.ASTDollarInterpolation
+        - content: dynamic "..."  // o.a.f.c.ASTExpStringLiteral
+            - value part: ${...}  // o.a.f.c.ASTDollarInterpolation
+                - content: x  // o.a.f.c.ASTExpVariable
+            - value part: "b"  // String
+    #text  // o.a.f.c.ASTStaticText
+        - content: "\n4. "  // String
+    ${...}  // o.a.f.c.ASTDollarInterpolation
+        - content: dynamic "..."  // o.a.f.c.ASTExpStringLiteral
+            - value part: "a"  // String
+            - value part: ${...}  // o.a.f.c.ASTDollarInterpolation
+                - content: x  // o.a.f.c.ASTExpVariable
+    #text  // o.a.f.c.ASTStaticText
+        - content: "\n5. "  // String
+    ${...}  // o.a.f.c.ASTDollarInterpolation
+        - content: dynamic "..."  // o.a.f.c.ASTExpStringLiteral
+            - value part: ${...}  // o.a.f.c.ASTDollarInterpolation
+                - content: x  // o.a.f.c.ASTExpVariable
+            - value part: #{...}  // o.a.f.c.ASTHashInterpolation
+                - content: y  // o.a.f.c.ASTExpVariable
+                - minimum decimals: "0"  // Integer
+                - maximum decimals: "0"  // Integer
+    #text  // o.a.f.c.ASTStaticText
+        - content: "\n6. "  // String
+    ${...}  // o.a.f.c.ASTDollarInterpolation
+        - content: dynamic "..."  // o.a.f.c.ASTExpStringLiteral
+            - value part: "a b "  // String
+            - value part: ${...}  // o.a.f.c.ASTDollarInterpolation
+                - content: x  // o.a.f.c.ASTExpVariable
+            - value part: " c d"  // String
+    #text  // o.a.f.c.ASTStaticText
+        - content: "\n7. "  // String
+    ${...}  // o.a.f.c.ASTDollarInterpolation
+        - content: dynamic "..."  // o.a.f.c.ASTExpStringLiteral
+            - value part: ${...}  // o.a.f.c.ASTDollarInterpolation
+                - content: x  // o.a.f.c.ASTExpVariable
+            - value part: " a b "  // String
+            - value part: ${...}  // o.a.f.c.ASTDollarInterpolation
+                - content: y  // o.a.f.c.ASTExpVariable
+            - value part: " c$d"  // String

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-strlitinterpolation.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-strlitinterpolation.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-strlitinterpolation.ftl
new file mode 100644
index 0000000..cd86f2f
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-strlitinterpolation.ftl
@@ -0,0 +1,25 @@
+<#--
+  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.
+-->
+1. <@m x='${e1}' y='$\\{e2}' />
+2. ${'a${x}b${x}c'}
+3. ${'${x}b'}
+4. ${'a${x}'}
+5. ${'${x}#{y}'}
+6. ${'a b ${x} c d'}
+7. ${'${x} a b ${y} c$d'}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-whitespacestripping.ast
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-whitespacestripping.ast b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-whitespacestripping.ast
new file mode 100644
index 0000000..868fc69
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-whitespacestripping.ast
@@ -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.
+ */
+#mixed_content  // o.a.f.c.ASTImplicitParent
+    #assign  // o.a.f.c.ASTDirAssignment
+        - assignment target: "xs"  // String
+        - assignment operator: "="  // String
+        - assignment source: [...]  // o.a.f.c.ASTExpListLiteral
+        - variable scope: "1"  // Integer
+        - namespace: null  // Null
+    #text  // o.a.f.c.ASTStaticText
+        - content: "\n"  // String
+    #list  // o.a.f.c.ASTDirList
+        - list source: x  // o.a.f.c.ASTExpVariable
+        - target loop variable: "xs"  // String
+        #text  // o.a.f.c.ASTStaticText
+            - content: "    "  // String
+        ${...}  // o.a.f.c.ASTDollarInterpolation
+            - content: x  // o.a.f.c.ASTExpVariable
+        #text  // o.a.f.c.ASTStaticText
+            - content: "\n"  // String
+    #text  // o.a.f.c.ASTStaticText
+        - content: "\n"  // String
+    #assign  // o.a.f.c.ASTDirAssignment
+        - assignment target: "a"  // String
+        - assignment operator: "="  // String
+        - assignment source: 1  // o.a.f.c.ASTExpNumberLiteral
+        - variable scope: "1"  // Integer
+        - namespace: null  // Null
+    #assign  // o.a.f.c.ASTDirAssignment
+        - assignment target: "b"  // String
+        - assignment operator: "="  // String
+        - assignment source: 1  // o.a.f.c.ASTExpNumberLiteral
+        - variable scope: "1"  // Integer
+        - namespace: null  // Null
+    #text  // o.a.f.c.ASTStaticText
+        - content: "\n"  // String
+    @  // o.a.f.c.ASTDirUserDefined
+        - callee: b  // o.a.f.c.ASTExpVariable
+        #text  // o.a.f.c.ASTStaticText
+            - content: "    x\n"  // String
+    #text  // o.a.f.c.ASTStaticText
+        - content: "\n"  // String
+    @  // o.a.f.c.ASTDirUserDefined
+        - callee: c  // o.a.f.c.ASTExpVariable
+    #text  // o.a.f.c.ASTStaticText
+        - content: "\n"  // String
+    @  // o.a.f.c.ASTDirUserDefined
+        - callee: d  // o.a.f.c.ASTExpVariable
+    #text  // o.a.f.c.ASTStaticText
+        - content: "\na\n"  // String
+    #--...--  // o.a.f.c.ASTComment
+        - content: " comment "  // String
+    #text  // o.a.f.c.ASTStaticText
+        - content: "b"  // String

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-whitespacestripping.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-whitespacestripping.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-whitespacestripping.ftl
new file mode 100644
index 0000000..cba7289
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-whitespacestripping.ftl
@@ -0,0 +1,40 @@
+<#--
+  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.
+-->
+
+
+<#assign xs = []>
+
+<#list x as xs>
+    ${x}
+</#list>
+
+<#assign a = 1>
+<#assign b = 1>
+
+<@b>
+    x
+</...@b>
+
+<@c />
+
+<@d...@d>
+
+a
+<#-- comment -->
+b
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-assignments.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-assignments.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-assignments.ftl
new file mode 100644
index 0000000..24c8984
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-assignments.ftl
@@ -0,0 +1,35 @@
+<#ftl stripWhitespace=false>
+<#--
+  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.
+-->
+<#assign x = 1>
+<#assign x = 1, y = 2>
+<#assign x = 1 in ns>
+<#assign x = 1, y = 2 in ns>
+<#assign a += b + c>
+<#assign a += 1, b -= 2, c *= 3, d /= 4, e %= 5, f++, g-->
+<#global x = 1>
+<#global x = 1, y = 2>
+<#global x++>
+<#macro m>
+  <#local x = 1>
+  <#local x = 1, y = 2>
+</#macro>
+<#assign x>
+  foo ${bar}
+</#assign>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-assignments.ftl.out
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-assignments.ftl.out b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-assignments.ftl.out
new file mode 100644
index 0000000..3dd2307
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-assignments.ftl.out
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+<#assign x = 1>
+<#assign x = 1, y = 2>
+<#assign x = 1 in ns>
+<#assign x = 1, y = 2 in ns>
+<#assign a += b + c>
+<#assign a += 1, b -= 2, c *= 3, d /= 4, e %= 5, f++, g-->
+<#global x = 1>
+<#global x = 1, y = 2>
+<#global x++>
+<#macro m>
+  <#local x = 1>
+  <#local x = 1, y = 2>
+</#macro>
+<#assign x>
+  foo ${bar}
+</#assign>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-builtins.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-builtins.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-builtins.ftl
new file mode 100644
index 0000000..74aee52
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-builtins.ftl
@@ -0,0 +1,23 @@
+<#--
+  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.
+-->
+${x?trim}
+${x?left_pad(5)}
+${x?left_pad(5, '-')}
+${x?then('y', 'n')}
+${x?switch(1, 11, 2, 22, 33)}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-builtins.ftl.out
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-builtins.ftl.out b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-builtins.ftl.out
new file mode 100644
index 0000000..3c62974
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-builtins.ftl.out
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+${x?trim}
+${x?left_pad(5)}
+${x?left_pad(5, "-")}
+${x?then("y", "n")}
+${x?switch(1, 11, 2, 22, 33)}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-identifier-escaping.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-identifier-escaping.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-identifier-escaping.ftl
new file mode 100644
index 0000000..75d52f1
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-identifier-escaping.ftl
@@ -0,0 +1,76 @@
+<#--
+  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.
+-->
+<#macro m\-a data\-color>
+    <#local \.namespace = 123>
+    <a-b>${data\-color}<#nested \.namespace></a-b><#t>
+</#macro>
+<#macro "m-b2"></#macro>
+<#macro "m/b2"></#macro>
+
+<@m\-a data\-color="red"; loop\-var, loopVar2>${loop\-var}</@>
+
+<#function f\-a p\-a>
+    <#return p\-a + " works">
+</#function>
+${f\-a("f-a")}
+
+<#assign \-\-\-\.\: = 'dash-dash-dash etc.'>
+${\-\-\-\.\:}
+${.vars['---.:']}
+<#assign hash = { '--moz-prop': 'propVal' }>
+${hash.\-\-moz\-prop}
+${hash['--moz-prop']}
+
+<#assign ls\:a = 1..3>
+List: <#list ls\:a as \:i>${\:i}</#list>
+
+<#assign sw\-a=1>
+Switch: <#switch sw\-a>
+    <#case 1>OK<#break>
+    <#default>Fails
+</#switch>
+
+<#escape \-x as \-x?upper_case>${'escaped'}</#escape>
+
+<#if false && sw\-a == 1>
+    <#visit x\-y2 using x\-y1>
+    <#recurse x\-y2 using x\-y1>
+    <#import i\-a as i\-b>
+    <#include i\-c>
+</#if>
+
+<#assign @as@_a = 'as1'>
+${@as@_a}
+<#assign 'as-c' = 'as2'>
+${.vars['as-c']}
+<#assign "as/b" = 'as3'>
+${.vars["as/b"]}
+<#assign "as'c" = 'as4'>
+${.vars["as'c"]}
+<#assign 'as"d' = 'as5'>
+${.vars['as"d']}
+
+<#global g\-a=1 g\-b=2 "g-c"=3>
+
+<#macro dumpNS>
+    <#list .namespace?keys?sort as k>
+        ${k} = <#local v = .namespace[k]><#if v?is_string>${v}<#else>...</#if><#lt>
+    </#list>
+</#macro>
+<@dumpNS />

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-identifier-escaping.ftl.out
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-identifier-escaping.ftl.out b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-identifier-escaping.ftl.out
new file mode 100644
index 0000000..17e2b4e
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-identifier-escaping.ftl.out
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+<#macro m\-a data\-color><#local \.namespace = 123><a-b>${data\-color}<#nested \.namespace></a-b></#macro><#macro m\-b2></#macro><#macro "m/b2"></#macro>
+<@m\-a data\-color="red"; loop\-var, loopVar2>${loop\-var}</@m\-a>
+
+<#function f\-a(p\-a)><#return p\-a + " works"/></#function>${f\-a("f-a")}
+
+<#assign \-\-\-\.\: = "dash-dash-dash etc.">${\-\-\-\.\:}
+${.vars["---.:"]}
+<#assign hash = {"--moz-prop": "propVal"}>${hash.\-\-moz\-prop}
+${hash["--moz-prop"]}
+
+<#assign ls\:a = 1..3>List: <#list ls\:a as \:i>${\:i}</#list>
+
+<#assign sw\-a = 1>Switch: <#switch sw\-a><#case 1>OK<#break/>
+    <#default>Fails
+</#switch>
+<#escape \-x as \-x?upper_case>${"escaped"}</#escape>
+
+<#if false && sw\-a == 1><#visit x\-y2 using x\-y1/><#recurse x\-y2 using x\-y1/><#import i\-a as i\-b/><#include i\-c/></#if>
+<#assign @as@_a = "as1">${@as@_a}
+<#assign as\-c = "as2">${.vars["as-c"]}
+<#assign "as/b" = "as3">${.vars["as/b"]}
+<#assign "as'c" = "as4">${.vars["as'c"]}
+<#assign 'as"d' = "as5">${.vars['as"d']}
+
+<#global g\-a = 1, g\-b = 2, g\-c = 3><#macro dumpNS><#list .namespace?keys?sort as k>${k} = <#local v = .namespace[k]><#if v?is_string>${v}<#else>...</#if>
+</#list></#macro><@dumpNS/>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-macros.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-macros.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-macros.ftl
new file mode 100644
index 0000000..9288e63
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-macros.ftl
@@ -0,0 +1,29 @@
+<#ftl stripWhitespace=false>
+<#--
+  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.
+-->
+<#macro m></#macro>
+<#macro m a></#macro>
+<#macro m a b></#macro>
+<#macro m a b c...></#macro>
+<#macro m a...></#macro>
+<#function f()></#function>
+<#function f(a)></#function>
+<#function f(a, b)></#function>
+<#function f(a, b, c...)></#function>
+<#function f(a...)></#function>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-macros.ftl.out
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-macros.ftl.out b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-macros.ftl.out
new file mode 100644
index 0000000..ad49cae
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-macros.ftl.out
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+<#macro m></#macro>
+<#macro m a></#macro>
+<#macro m a b></#macro>
+<#macro m a b c...></#macro>
+<#macro m a...></#macro>
+<#function f()></#function>
+<#function f(a)></#function>
+<#function f(a, b)></#function>
+<#function f(a, b, c...)></#function>
+<#function f(a...)></#function>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-strlitinterpolation.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-strlitinterpolation.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-strlitinterpolation.ftl
new file mode 100644
index 0000000..85189a4
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-strlitinterpolation.ftl
@@ -0,0 +1,19 @@
+<#--
+  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.
+-->
+<@m x='${e1 + "a\'b${x}"}#{x; M2}' y='$\{e2}' />
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-strlitinterpolation.ftl.out
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-strlitinterpolation.ftl.out b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-strlitinterpolation.ftl.out
new file mode 100644
index 0000000..754c225
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/cano-strlitinterpolation.ftl.out
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+<@m x="${e1 + \"a'b$\{x}\"}#{x ; m0M2}" y="$\{e2}"/>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/core/encodingOverride-ISO-8859-1.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/encodingOverride-ISO-8859-1.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/encodingOverride-ISO-8859-1.ftl
new file mode 100644
index 0000000..e0382c7
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/encodingOverride-ISO-8859-1.ftl
@@ -0,0 +1,20 @@
+<#ftl encoding="ISO-8859-1">
+<#--
+  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.
+-->
+B�ka
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/core/encodingOverride-UTF-8.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/encodingOverride-UTF-8.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/encodingOverride-UTF-8.ftl
new file mode 100644
index 0000000..5948e30
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/encodingOverride-UTF-8.ftl
@@ -0,0 +1,20 @@
+<#ftl encoding="UTF-8">
+<#--
+  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.
+-->
+Béka
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templateresolver/test.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templateresolver/test.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templateresolver/test.ftl
new file mode 100644
index 0000000..fb3f45d
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/templateresolver/test.ftl
@@ -0,0 +1,19 @@
+<#--
+  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.
+-->
+dummy
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/core/toCache1.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/toCache1.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/toCache1.ftl
new file mode 100644
index 0000000..462f1ae
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/toCache1.ftl
@@ -0,0 +1,19 @@
+<#--
+  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.
+-->
+Template 1
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/core/toCache2.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/toCache2.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/toCache2.ftl
new file mode 100644
index 0000000..f59424c
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/toCache2.ftl
@@ -0,0 +1,19 @@
+<#--
+  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.
+-->
+Template 2
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/dom/DOMSiblingTest.xml
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/dom/DOMSiblingTest.xml b/freemarker-core-test/src/test/resources/org/apache/freemarker/dom/DOMSiblingTest.xml
new file mode 100644
index 0000000..d1fe3dc
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/dom/DOMSiblingTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.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.
+-->
+<person>
+    <gender>male</gender>
+    <name>pradeep</name>
+    <dob>12th August</dob><address>Chennai, India</address>
+    <!--This is a comment Node -->
+    <?xml-stylesheet type="text/css" href="style.css"?>
+    <profession>Software Engineer</profession>
+    <![CDATA[    ]]>
+    <hobby>gardening</hobby>
+    <![CDATA[this is a valid cdata]]>
+    <phone>12345678</phone>
+</person>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-capture.ftlh
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-capture.ftlh b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-capture.ftlh
new file mode 100644
index 0000000..24bd0ee
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-capture.ftlh
@@ -0,0 +1,21 @@
+<#--
+  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.
+-->
+<#assign captured><b>Test</b></#assign>
+Just a string: ${"<b>Test</b>"}
+Captured output: ${captured}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-capture.ftlh.out
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-capture.ftlh.out b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-capture.ftlh.out
new file mode 100644
index 0000000..cf0da7e
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-capture.ftlh.out
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+Just a string: &lt;b&gt;Test&lt;/b&gt;
+Captured output: <b>Test</b>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-convert.ftlh
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-convert.ftlh b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-convert.ftlh
new file mode 100644
index 0000000..e0d3348
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-convert.ftlh
@@ -0,0 +1,27 @@
+<#--
+  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.
+-->
+<#assign mo1 = "Foo's bar {}"?esc>
+HTLM: ${mo1}
+XML:  <#outputformat 'XML'>${mo1}</#outputformat>
+RTF:  <#outputformat 'RTF'>${mo1}</#outputformat>
+
+<#assign mo2><p>Test</#assign>
+HTML: ${mo2}
+XML:  <#attempt><#outputformat 'XML'>${mo2}</#outputformat><#recover>Failed</#attempt>
+RTF:  <#attempt><#outputformat 'RTF'>${mo2}</#outputformat><#recover>Failed</#attempt>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-convert.ftlh.out
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-convert.ftlh.out b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-convert.ftlh.out
new file mode 100644
index 0000000..65be2a0
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-convert.ftlh.out
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+HTLM: Foo&#39;s bar {}
+XML:  Foo&apos;s bar {}
+RTF:  Foo's bar \{\}
+
+HTML: <p>Test
+XML:  Failed
+RTF:  Failed

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-convert2.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-convert2.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-convert2.ftl
new file mode 100644
index 0000000..80ae292
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-convert2.ftl
@@ -0,0 +1,25 @@
+<#--
+  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.
+-->
+<#outputformat "HTML"><#assign htmlMO><p>Test</#assign></#outputformat>
+<#outputformat "XML"><#assign xmlMO><p>Test</p></#assign></#outputformat>
+<#outputformat "RTF"><#assign rtfMO>\par Test</#assign></#outputformat>
+<#-- We assume that we have "undefined" output format here. -->
+HTML: ${htmlMO}
+XML:  ${xmlMO}
+RTF:  ${rtfMO}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-convert2.ftl.out
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-convert2.ftl.out b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-convert2.ftl.out
new file mode 100644
index 0000000..cd84bd2
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-convert2.ftl.out
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+HTML: <p>Test
+XML:  <p>Test</p>
+RTF:  \par Test
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-infoBox.ftlh
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-infoBox.ftlh b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-infoBox.ftlh
new file mode 100644
index 0000000..9b8dbd9
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-infoBox.ftlh
@@ -0,0 +1,26 @@
+<#--
+  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.
+-->
+<@infoBox "Foo & bar" />
+<@infoBox "Foo <b>bar</b>"?no_esc />
+
+<#macro infoBox message>
+  <div class="infoBox">
+    ${message}
+  </div>
+</#macro>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-infoBox.ftlh.out
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-infoBox.ftlh.out b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-infoBox.ftlh.out
new file mode 100644
index 0000000..9471ab7
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-infoBox.ftlh.out
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+  <div class="infoBox">
+    Foo &amp; bar
+  </div>
+  <div class="infoBox">
+    Foo <b>bar</b>
+  </div>
+

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-markup.ftlh
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-markup.ftlh b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-markup.ftlh
new file mode 100644
index 0000000..f9deeae
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-markup.ftlh
@@ -0,0 +1,28 @@
+<#--
+  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.
+-->
+<#assign markupOutput1="<b>Test</b>"?no_esc>
+<#assign markupOutput2="Foo & bar"?esc>
+
+As expected:
+${markupOutput1}
+${markupOutput2}
+
+Double escaping:
+${markupOutput1?markup_string}
+${markupOutput2?markup_string}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-markup.ftlh.out
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-markup.ftlh.out b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-markup.ftlh.out
new file mode 100644
index 0000000..0420cca
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-markup.ftlh.out
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+As expected:
+<b>Test</b>
+Foo &amp; bar
+
+Double escaping:
+&lt;b&gt;Test&lt;/b&gt;
+Foo &amp;amp; bar
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringConcat.ftlh
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringConcat.ftlh b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringConcat.ftlh
new file mode 100644
index 0000000..f7884bb
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringConcat.ftlh
@@ -0,0 +1,19 @@
+<#--
+  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.
+-->
+${"<h1>"?no_esc + "Foo & bar" + "</h1>"?no_esc}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringConcat.ftlh.out
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringConcat.ftlh.out b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringConcat.ftlh.out
new file mode 100644
index 0000000..d016072
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringConcat.ftlh.out
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+<h1>Foo &amp; bar</h1>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringLiteral.ftlh
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringLiteral.ftlh b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringLiteral.ftlh
new file mode 100644
index 0000000..4904f60
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringLiteral.ftlh
@@ -0,0 +1,21 @@
+<#--
+  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.
+-->
+<#assign s = "Foo & bar">
+${s}
+${"${s} & baz"}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringLiteral.ftlh.out
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringLiteral.ftlh.out b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringLiteral.ftlh.out
new file mode 100644
index 0000000..c6bd10d
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringLiteral.ftlh.out
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+Foo &amp; bar
+Foo &amp; bar &amp; baz
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringLiteral2.ftlh
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringLiteral2.ftlh b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringLiteral2.ftlh
new file mode 100644
index 0000000..52db70b
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringLiteral2.ftlh
@@ -0,0 +1,25 @@
+<#--
+  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.
+-->
+<#-- Markup output value created by escaping plain text: -->
+<#assign mo1 = "Foo & bar"?esc>
+<#-- Markup output value created outherwise: -->
+<#assign mo2 = "<p>Foo"?no_esc>
+
+${"${mo1} baz"}
+${"${mo2} baz"}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringLiteral2.ftlh.out
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringLiteral2.ftlh.out b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringLiteral2.ftlh.out
new file mode 100644
index 0000000..f47e521
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringLiteral2.ftlh.out
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+Foo &amp; bar baz
+<p>Foo baz
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/ConfigureOutputFormatExamples1.properties
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/ConfigureOutputFormatExamples1.properties b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/ConfigureOutputFormatExamples1.properties
new file mode 100644
index 0000000..0df9e33
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/ConfigureOutputFormatExamples1.properties
@@ -0,0 +1,21 @@
+# 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.
+
+templateConfigurations = \
+    ConditionalTemplateConfigurationFactory( \
+        PathGlobMatcher("mail/**"), \
+        TemplateConfiguration(outputFormat = HTMLOutputFormat()))
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/ConfigureOutputFormatExamples2.properties
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/ConfigureOutputFormatExamples2.properties b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/ConfigureOutputFormatExamples2.properties
new file mode 100644
index 0000000..5d2a738
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/ConfigureOutputFormatExamples2.properties
@@ -0,0 +1,31 @@
+# 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.
+
+templateConfigurations = \
+    FirstMatchTemplateConfigurationFactory( \
+        ConditionalTemplateConfigurationFactory( \
+            FileExtensionMatcher("xml"), \
+            TemplateConfiguration(outputFormat = XMLOutputFormat())), \
+        ConditionalTemplateConfigurationFactory( \
+            OrMatcher( \
+                FileExtensionMatcher("html"), \
+                FileExtensionMatcher("htm")), \
+            TemplateConfiguration(outputFormat = HTMLOutputFormat())), \
+        ConditionalTemplateConfigurationFactory( \
+            FileExtensionMatcher("rtf"), \
+            TemplateConfiguration(outputFormat = RTFOutputFormat())), \
+        allowNoMatch = true)

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-alias1.ftlh
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-alias1.ftlh b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-alias1.ftlh
new file mode 100644
index 0000000..fe9690c
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-alias1.ftlh
@@ -0,0 +1,22 @@
+<#--
+  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.
+-->
+${p?string.@price}
+${w?string.@weight}
+${fd?string.@fileDate}
+${let?datetime?string.@logEventTime}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-alias1.ftlh.out
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-alias1.ftlh.out b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-alias1.ftlh.out
new file mode 100644
index 0000000..717431f
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-alias1.ftlh.out
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+10,000.00
+10.31
+23/Dec/15 10:09 PM
+2015-12-23T21:09:04.213Z

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-alias2.ftlh
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-alias2.ftlh b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-alias2.ftlh
new file mode 100644
index 0000000..624950f
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-alias2.ftlh
@@ -0,0 +1,19 @@
+<#--
+  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.
+-->
+${10?string.@oct}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-alias2.ftlh.out
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-alias2.ftlh.out b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-alias2.ftlh.out
new file mode 100644
index 0000000..08d0fea
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-alias2.ftlh.out
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+12
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-modelAware.ftlh
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-modelAware.ftlh b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-modelAware.ftlh
new file mode 100644
index 0000000..9a34ac0
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-modelAware.ftlh
@@ -0,0 +1,20 @@
+<#--
+  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.
+-->
+${10.12356}
+${weight}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-modelAware.ftlh.out
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-modelAware.ftlh.out b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-modelAware.ftlh.out
new file mode 100644
index 0000000..25d6155
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-modelAware.ftlh.out
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+10.1236
+1.5 kg
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/TemplateConfigurationExamples1.properties
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/TemplateConfigurationExamples1.properties b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/TemplateConfigurationExamples1.properties
new file mode 100644
index 0000000..faf8592
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/TemplateConfigurationExamples1.properties
@@ -0,0 +1,25 @@
+# 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.
+
+templateConfigurations = \
+    ConditionalTemplateConfigurationFactory( \
+        FileExtensionMatcher("xml"), \
+        TemplateConfiguration( \
+            sourceEncoding = Charset("utf-8"), \
+            outputFormat = XMLOutputFormat() \
+        ) \
+    )
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/TemplateConfigurationExamples2.properties
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/TemplateConfigurationExamples2.properties b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/TemplateConfigurationExamples2.properties
new file mode 100644
index 0000000..f879e70
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/TemplateConfigurationExamples2.properties
@@ -0,0 +1,32 @@
+# 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.
+
+templateConfigurations = \
+    ConditionalTemplateConfigurationFactory( \
+        PathGlobMatcher("mail/**"), \
+        FirstMatchTemplateConfigurationFactory( \
+            ConditionalTemplateConfigurationFactory( \
+                FileNameGlobMatcher("*.subject.*"), \
+                TemplateConfiguration(outputFormat = PlainTextOutputFormat()) \
+            ), \
+            ConditionalTemplateConfigurationFactory( \
+                FileNameGlobMatcher("*.body.*"), \
+                TemplateConfiguration(outputFormat = HTMLOutputFormat()) \
+            ), \
+            noMatchErrorDetails = 'Mail template names must contain ".subject." or ".body."!' \
+        ) \
+    )

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/TemplateConfigurationExamples3.properties
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/TemplateConfigurationExamples3.properties b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/TemplateConfigurationExamples3.properties
new file mode 100644
index 0000000..ce72fef
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/TemplateConfigurationExamples3.properties
@@ -0,0 +1,47 @@
+# 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.
+
+templateConfigurations = \
+    MergingTemplateConfigurationFactory( \
+        ConditionalTemplateConfigurationFactory( \
+            FileNameGlobMatcher("*.stats.*"), \
+            TemplateConfiguration( \
+                dateTimeFormat = "iso", \
+                dateFormat = "iso", \
+                timeFormat = "iso", \
+                timeZone = TimeZone("UTC") \
+            ) \
+        ), \
+        ConditionalTemplateConfigurationFactory( \
+            PathGlobMatcher("mail/**"), \
+            TemplateConfiguration(sourceEncoding = Charset("utf-8")) \
+        ), \
+        FirstMatchTemplateConfigurationFactory( \
+            ConditionalTemplateConfigurationFactory( \
+                FileExtensionMatcher("xml"), \
+                TemplateConfiguration(outputFormat = XMLOutputFormat()) \
+            ), \
+            ConditionalTemplateConfigurationFactory( \
+                OrMatcher( \
+                    FileExtensionMatcher("html"), \
+                    FileExtensionMatcher("htm") \
+                ), \
+                TemplateConfiguration(outputFormat = HTMLOutputFormat()) \
+            ), \
+            allowNoMatch = true \
+        ) \
+    )

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/test.ftlh
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/test.ftlh b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/test.ftlh
new file mode 100644
index 0000000..852b82b
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/manualtest/test.ftlh
@@ -0,0 +1,28 @@
+<#--
+  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.
+-->
+<html>
+<head>
+  <title>Welcome!</title>
+</head>
+<body>
+  <h1>Welcome ${user}!</h1>
+  <p>Our latest product:
+  <a href="${latestProduct.url}">${latestProduct.name}</a>!
+</body>
+</html>
\ No newline at end of file


[05/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/util/FileTestCase.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/util/FileTestCase.java b/freemarker-core/src/test/java/org/apache/freemarker/test/util/FileTestCase.java
deleted file mode 100644
index b7e4c1d..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/util/FileTestCase.java
+++ /dev/null
@@ -1,217 +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.test.util;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.net.URL;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.IOUtils;
-import org.apache.freemarker.core.util._NullArgumentException;
-import org.apache.freemarker.core.util._StringUtil;
-import org.apache.freemarker.test.TestUtil;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import junit.framework.AssertionFailedError;
-import junit.framework.TestCase;
-
-/**
- * Test case that needs to compare a string to a reference (expected) text file, or two text files. 
- */
-public abstract class FileTestCase extends TestCase {
-
-    public static final Logger LOG = LoggerFactory.getLogger(FileTestCase.class);
-
-    public FileTestCase(String name) {
-        super(name);
-    }
-
-    protected void assertExpectedFileEqualsString(String expectedFileName, String actualContent) {
-        try {
-            final URL expectedFile = getExpectedContentFileURL(expectedFileName);
-            
-            try {
-                multilineAssertEquals(loadTestTextResource(expectedFile), actualContent);
-            } catch (AssertionFailedError | FileNotFoundException e) {
-                File actualFile = getActualContentFileFor(expectedFile);
-                if (actualFile != null) {
-                    FileUtils.write(actualFile, actualContent);
-                    reportActualFileSaved(actualFile);
-                }
-
-                throw e;
-            }
-        } catch (IOException e) {
-            throw new RuntimeException("Failed to do assertion", e);
-        }
-    }
-
-    private void multilineAssertEquals(String expected, String actual) {
-        String normExpected = _StringUtil.normalizeEOLs(expected);
-        final String normActual = _StringUtil.normalizeEOLs(actual);
-        
-        // Ignore final line-break difference:
-        if (normActual.endsWith("\n") && !normExpected.endsWith("\n")) {
-            normExpected += "\n";
-        } else if (!normActual.endsWith("\n") && normExpected.endsWith("\n")) {
-            normExpected = normExpected.substring(0, normExpected.length() -  1);
-        }
-        
-        assertEquals(normExpected, normActual);
-    }
-
-    protected void reportActualFileSaved(File actualContentFile) {
-        LOG.info("Saved actual output of the failed test to here: {}", actualContentFile.getAbsolutePath());
-    }
-
-    /**
-     * Convenience method for calling {@link #getTestFileURL(String, String)} with {@link
-     * #getExpectedContentFileDirectoryResourcePath()} as the first argument.
-     */
-    protected final URL getExpectedContentFileURL(String expectedContentFileName) throws IOException {
-        return getTestFileURL(getExpectedContentFileDirectoryResourcePath(), expectedContentFileName);
-    }
-
-    /**
-     * Gets the URL of the test file that contains the expected result.
-     *
-     * @param directoryResourcePath
-     *         The class-loader resource path of the containing directory; if relative, it's interpreted relatively to
-     *         the package of {@link #getTestResourcesBaseClass()}.
-     *
-     * @return Not {@code null}; if the file isn't found, throw {@link FileNotFoundException}
-     *
-     * @throws FileNotFoundException
-     *         If the requested file wasn't found.
-     */
-    protected final URL getTestFileURL(String directoryResourcePath, String fileName) throws IOException {
-        _NullArgumentException.check("directoryResourcePath", directoryResourcePath);
-        _NullArgumentException.check("testCaseFileName", fileName);
-
-        Class baseClass = getTestResourcesBaseClass();
-        String resourcePath = joinResourcePaths(directoryResourcePath, fileName);
-        // It's important that we only query an URL for the file (not for the parent package directory), because the
-        // parent URL can depend on the file name if the class loader uses multiple directories/jars.
-        URL resource = baseClass.getResource(resourcePath);
-        if (resource == null) {
-            throw new FileNotFoundException("Class-loader resource not found for: "
-                    + "baseClass: " + baseClass.getName() + "; "
-                    + "resourcePath (shown quoted): " + _StringUtil.jQuote(resourcePath));
-        }
-        return resource;
-    }
-
-    /**
-     * Concatenates two resource paths, taking care of the edge cases due to leading and trailing "/"
-     * characters in them.
-     */
-    protected final String joinResourcePaths(String dirPath, String tailPath) {
-        if (tailPath.startsWith("/") || dirPath.isEmpty()) {
-            return tailPath;
-        }
-        return dirPath.endsWith("/") ? dirPath + tailPath : dirPath + "/" + tailPath;
-    }
-
-    /**
-     * Gets the actual content file to create which belongs to an expected content file. Actual content files are
-     * created when the expected and the actual content differs.
-     *
-     * @return {@code null} if there's no place to write the files that contain the actual content
-     */
-    protected File getActualContentFileFor(URL expectedContentFile) throws IOException {
-        _NullArgumentException.check("expectedContentFile", expectedContentFile);
-
-        File actualContentFileDir = getActualContentFileDirectory(expectedContentFile);
-        if (actualContentFileDir == null) {
-            return null;
-        }
-
-        String expectedContentFileName = expectedContentFile.getPath();
-        int lastSlashIdx = expectedContentFileName.lastIndexOf('/');
-        if (lastSlashIdx != -1) {
-            expectedContentFileName = expectedContentFileName.substring(lastSlashIdx + 1);
-        }
-
-        return new File(actualContentFileDir, deduceActualContentFileName(expectedContentFileName));
-    }
-
-    /**
-     * Deduces the actual content file name from the expected content file name.
-     *
-     * @return Not {@code null}
-     */
-    protected String deduceActualContentFileName(String expectedContentFileName) {
-        _NullArgumentException.check("expectedContentFileName", expectedContentFileName);
-
-        int lastDotIdx = expectedContentFileName.lastIndexOf('.');
-        return lastDotIdx == -1
-                ? expectedContentFileName + ".actual"
-                : expectedContentFileName.substring(0, lastDotIdx) + "-actual" + expectedContentFileName.substring(lastDotIdx);
-    }
-
-    /**
-     * The class loader resource path of the directory that contains the expected files; must start and end with "/"!
-     */
-    protected String getExpectedContentFileDirectoryResourcePath() throws IOException {
-        return getTestClassDirectoryResourcePath();
-    }
-
-    /**
-     * @return {@code null} if there's no directory to write the actual files to
-     */
-    protected File getActualContentFileDirectory(URL expectedFile) throws IOException {
-        return FileUtils.toFile(expectedFile).getParentFile();
-    }
-
-    /**
-     * The class loader resource path of the directory that contains the test files; must not end with "/"!
-     */
-    protected String getTestClassDirectoryResourcePath() throws IOException {
-        return "";
-    }
-
-    /**
-     * Resource paths are loaded using this class's {@link Class#getResourceAsStream(String)} method; thus, if
-     * {@link #getTestClassDirectoryResourcePath()} and such return a relative paths, they will be relative to the
-     * package of this class.
-     */
-    protected Class getTestResourcesBaseClass() {
-        return getClass();
-    }
-
-    protected String loadTestTextResource(URL resource) throws IOException {
-        return loadTestTextResource(resource, getTestResourceDefaultCharset());
-    }
-    
-    protected String loadTestTextResource(URL resource, Charset charset) throws IOException {
-        return TestUtil.removeTxtCopyrightComment(
-                IOUtils.toString(resource, charset.name()));
-    }
-    
-    protected Charset getTestResourceDefaultCharset() {
-        return StandardCharsets.UTF_8;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/util/MissingRequiredParameterException.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/util/MissingRequiredParameterException.java b/freemarker-core/src/test/java/org/apache/freemarker/test/util/MissingRequiredParameterException.java
deleted file mode 100644
index 0bc37a3..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/util/MissingRequiredParameterException.java
+++ /dev/null
@@ -1,51 +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.test.util;
-
-import org.apache.freemarker.core.Environment;
-import org.apache.freemarker.core.util._StringUtil;
-
-/**
- * Indicates that a named directive/function parameter is missing.  
- * This is will be public and go into the org.apache.freemarker.core.ast when the directive/method stuff was reworked.
- */
-class MissingRequiredParameterException extends ParameterException {
-
-    public MissingRequiredParameterException(String parameterName, Environment env) {
-        this(parameterName, null, null, env);
-    }
-
-    public MissingRequiredParameterException(String parameterName, Exception cause, Environment env) {
-        this(parameterName, null, cause, env);
-    }
-
-    public MissingRequiredParameterException(String parameterName, String description, Environment env) {
-        this(parameterName, description, null, env);
-    }
-
-    public MissingRequiredParameterException(String parameterName, String description, Exception cause, Environment env) {
-        super(parameterName,
-                "Required parameter " + _StringUtil.jQuote(parameterName) + " is missing, "
-                + "or the parameter value was null."
-                + (description != null ? " " + _StringUtil.jQuote(description) : ""),
-                cause, env);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/util/NoOutputDirective.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/util/NoOutputDirective.java b/freemarker-core/src/test/java/org/apache/freemarker/test/util/NoOutputDirective.java
deleted file mode 100644
index d504bd5..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/util/NoOutputDirective.java
+++ /dev/null
@@ -1,50 +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.test.util;
-
-import java.io.IOException;
-import java.util.Map;
-
-import org.apache.freemarker.core.Environment;
-import org.apache.freemarker.core.TemplateException;
-import org.apache.freemarker.core.model.TemplateDirectiveBody;
-import org.apache.freemarker.core.model.TemplateDirectiveModel;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.util._NullWriter;
-
-public class NoOutputDirective implements TemplateDirectiveModel {
-
-    public static final NoOutputDirective INSTANCE = new NoOutputDirective(); 
-    
-    private NoOutputDirective() {
-        //
-    }
-
-    @Override
-    public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
-            throws TemplateException, IOException {
-        if (!params.isEmpty()) {
-            throw new TemplateModelException("This directivey doesn't support any parameters.");
-        }
-        body.render(_NullWriter.INSTANCE);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/util/ParameterException.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/util/ParameterException.java b/freemarker-core/src/test/java/org/apache/freemarker/test/util/ParameterException.java
deleted file mode 100644
index 47220d5..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/util/ParameterException.java
+++ /dev/null
@@ -1,54 +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.test.util;
-
-import org.apache.freemarker.core.Environment;
-import org.apache.freemarker.core.TemplateException;
-
-/**
- * An exception that is related to a named parameter of a directive or function.
- * This is will be public and go into the org.apache.freemarker.core.ast when the method/directive stuff was reworked.
- */
-abstract class ParameterException extends TemplateException {
-    
-    private final String parameterName;
-    
-    public ParameterException(String parameterName, Environment env) {
-        this(parameterName, null, null, env);
-    }
-
-    public ParameterException(String parameterName, Exception cause, Environment env) {
-        this(parameterName, null, cause, env);
-    }
-
-    public ParameterException(String parameterName, String description, Environment env) {
-        this(parameterName, description, null, env);
-    }
-
-    public ParameterException(String parameterName, String description, Exception cause, Environment env) {
-        super(description, cause, env);
-        this.parameterName = parameterName;
-    }
-
-    public String getParameterName() {
-        return parameterName;
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/util/SimpleMapAndCollectionObjectWrapper.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/util/SimpleMapAndCollectionObjectWrapper.java b/freemarker-core/src/test/java/org/apache/freemarker/test/util/SimpleMapAndCollectionObjectWrapper.java
deleted file mode 100644
index c1da1c4..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/util/SimpleMapAndCollectionObjectWrapper.java
+++ /dev/null
@@ -1,60 +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.test.util;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Map;
-
-import org.apache.freemarker.core.Version;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.impl.DefaultObjectWrapper;
-import org.apache.freemarker.core.model.impl.SimpleHash;
-import org.apache.freemarker.core.model.impl.SimpleSequence;
-
-/**
- * Forces using "simple" models for {@link Map}-s, {@link Collection}-s and arrays. This is mostly useful for template
- * test cases that wish to test with these models, but otherwise need to able to wrap beans and such. 
- */
-public class SimpleMapAndCollectionObjectWrapper extends DefaultObjectWrapper {
-
-    public SimpleMapAndCollectionObjectWrapper(Version incompatibleImprovements) {
-        super(new DefaultObjectWrapper.Builder(incompatibleImprovements), true);
-    }
-
-    @Override
-    public TemplateModel wrap(Object obj) throws TemplateModelException {
-        if (obj == null) {
-            return super.wrap(null);
-        }        
-        if (obj.getClass().isArray()) {
-            obj = Arrays.asList((Object[]) obj);
-        }
-        if (obj instanceof Collection) {
-            return new SimpleSequence((Collection<?>) obj, this);
-        }
-        if (obj instanceof Map) {
-            return new SimpleHash((Map<?, ?>) obj, this);
-        }
-        
-        return super.wrap(obj);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/util/UnsupportedParameterException.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/util/UnsupportedParameterException.java b/freemarker-core/src/test/java/org/apache/freemarker/test/util/UnsupportedParameterException.java
deleted file mode 100644
index ac4d528..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/util/UnsupportedParameterException.java
+++ /dev/null
@@ -1,50 +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.test.util;
-
-import org.apache.freemarker.core.Environment;
-import org.apache.freemarker.core.util._StringUtil;
-
-/**
- * Indicates that a named directive/function parameter is unsupported (like a typo).  
- * This is will be public and go into the org.apache.freemarker.core.ast when the directive/method stuff was reworked.
- */
-class UnsupportedParameterException extends ParameterException {
-
-    public UnsupportedParameterException(String parameterName, Environment env) {
-        this(parameterName, null, null, env);
-    }
-
-    public UnsupportedParameterException(String parameterName, Exception cause, Environment env) {
-        this(parameterName, null, cause, env);
-    }
-
-    public UnsupportedParameterException(String parameterName, String description, Environment env) {
-        this(parameterName, description, null, env);
-    }
-
-    public UnsupportedParameterException(String parameterName, String description, Exception cause, Environment env) {
-        super(parameterName,
-                "Unsuppored parameter: " + _StringUtil.jQuote(parameterName)
-                + (description == null ? "." : ". " + _StringUtil.jQuote(description)),
-                cause, env);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/util/XMLLoader.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/util/XMLLoader.java b/freemarker-core/src/test/java/org/apache/freemarker/test/util/XMLLoader.java
deleted file mode 100644
index 90763a0..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/util/XMLLoader.java
+++ /dev/null
@@ -1,138 +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.test.util;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.StringReader;
-import java.net.MalformedURLException;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-
-import org.apache.freemarker.dom.NodeModel;
-import org.w3c.dom.Document;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-
-public final class XMLLoader {
-
-    private static final Object STATIC_LOCK = new Object();
-    
-    static private DocumentBuilderFactory docBuilderFactory;
-    
-    private XMLLoader() {
-        //
-    }
-    
-    /**
-     * Convenience method to invoke a {@link NodeModel} from a SAX {@link InputSource}.
-     */
-    static public NodeModel toModel(InputSource is, boolean simplify)
-        throws SAXException, IOException, ParserConfigurationException {
-        DocumentBuilder builder = getDocumentBuilderFactory().newDocumentBuilder();
-        final Document doc;
-        try {
-            doc = builder.parse(is);
-        } catch (MalformedURLException e) {
-            // This typical error has an error message that is hard to understand, so let's translate it:
-            if (is.getSystemId() == null && is.getCharacterStream() == null && is.getByteStream() == null) {
-                throw new MalformedURLException(
-                        "The SAX InputSource has systemId == null && characterStream == null && byteStream == null. "
-                        + "This is often because it was created with a null InputStream or Reader, which is often because "
-                        + "the XML file it should point to was not found. "
-                        + "(The original exception was: " + e + ")");
-            } else {
-                throw e;
-            }
-        }
-        if (simplify) {
-            NodeModel.simplify(doc);
-        }
-        return NodeModel.wrap(doc);
-    }
-    
-    /**
-     * Same as {@link #toModel(InputSource, boolean) parse(is, true)}.
-     */
-    static public NodeModel toModel(InputSource is) throws SAXException, IOException, ParserConfigurationException {
-        return toModel(is, true);
-    }
-    
-    /**
-     * Same as {@link #toModel(InputSource, boolean)}, but loads from a {@link File}; don't miss the security
-     * warnings documented there.
-     */
-    static public NodeModel toModel(File f, boolean simplify) 
-    throws SAXException, IOException, ParserConfigurationException {
-        DocumentBuilder builder = getDocumentBuilderFactory().newDocumentBuilder();
-        Document doc = builder.parse(f);
-        if (simplify) {
-            NodeModel.simplify(doc);
-        }
-        return NodeModel.wrap(doc);
-    }
-    
-    /**
-     * Same as {@link #toModel(InputSource, boolean) parse(source, true)}, but loads from a {@link String}.
-     */
-    static public NodeModel toModel(File f) throws SAXException, IOException, ParserConfigurationException {
-        return toModel(f, true);
-    }
-    
-    /**
-     * Same as {@link #toModel(InputSource, boolean)}, but loads from a {@link File}; don't miss the security
-     * warnings documented there.
-     */
-    static public NodeModel toModel(String content, boolean simplify) 
-    throws SAXException, IOException, ParserConfigurationException {
-        return toModel(toInputSource(content));
-    }
-    
-    /**
-     * Same as {@link #toModel(InputSource, boolean) parse(source, true)}, but loads from a {@link String}.
-     */
-    static public NodeModel toModel(String content) throws SAXException, IOException, ParserConfigurationException {
-        return toModel(content, true);
-    }
-    
-    public static Document toDOM(String content) throws SAXException, IOException, ParserConfigurationException {
-        DocumentBuilder builder =  getDocumentBuilderFactory().newDocumentBuilder();
-        return builder.parse(toInputSource(content));
-    }
-    
-    static private DocumentBuilderFactory getDocumentBuilderFactory() {
-        synchronized (STATIC_LOCK) {
-            if (docBuilderFactory == null) {
-                DocumentBuilderFactory newFactory = DocumentBuilderFactory.newInstance();
-                newFactory.setNamespaceAware(true);
-                newFactory.setIgnoringElementContentWhitespace(true);
-                docBuilderFactory = newFactory;  // We only write it out when the initialization was full 
-            }
-            return docBuilderFactory;
-        }
-    }
-
-    private static InputSource toInputSource(String content) {
-        return new InputSource(new StringReader(content));
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-1.ast
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-1.ast b/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-1.ast
deleted file mode 100644
index 1cdd496..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-1.ast
+++ /dev/null
@@ -1,187 +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.
- */
-#mixed_content  // o.a.f.c.ASTImplicitParent
-    #text  // o.a.f.c.ASTStaticText
-        - content: "1 "  // String
-    @  // o.a.f.c.ASTDirUserDefined
-        - callee: foo  // o.a.f.c.ASTExpVariable
-        - argument name: "x"  // String
-        - argument value: 1  // o.a.f.c.ASTExpNumberLiteral
-        - argument name: "y"  // String
-        - argument value: 2  // o.a.f.c.ASTExpNumberLiteral
-        - target loop variable: "b1"  // String
-        - target loop variable: "b2"  // String
-        #text  // o.a.f.c.ASTStaticText
-            - content: "x"  // String
-    #text  // o.a.f.c.ASTStaticText
-        - content: "\n2 "  // String
-    @  // o.a.f.c.ASTDirUserDefined
-        - callee: .  // o.a.f.c.ASTExpDot
-            - left-hand operand: ns  // o.a.f.c.ASTExpVariable
-            - right-hand operand: "bar"  // String
-        - argument value: 1  // o.a.f.c.ASTExpNumberLiteral
-        - argument value: 2  // o.a.f.c.ASTExpNumberLiteral
-        - target loop variable: "b1"  // String
-        - target loop variable: "b2"  // String
-        #text  // o.a.f.c.ASTStaticText
-            - content: "y"  // String
-    #text  // o.a.f.c.ASTStaticText
-        - content: "\n3 "  // String
-    #assign  // o.a.f.c.ASTDirAssignment
-        - assignment target: "x"  // String
-        - assignment operator: "="  // String
-        - assignment source: 123  // o.a.f.c.ASTExpNumberLiteral
-        - variable scope: "1"  // Integer
-        - namespace: null  // Null
-    #assign  // o.a.f.c.ASTDirAssignment
-        - assignment target: "x"  // String
-        - assignment operator: "="  // String
-        - assignment source: 123  // o.a.f.c.ASTExpNumberLiteral
-        - variable scope: "1"  // Integer
-        - namespace: ns  // o.a.f.c.ASTExpVariable
-    #global  // o.a.f.c.ASTDirAssignment
-        - assignment target: "x"  // String
-        - assignment operator: "="  // String
-        - assignment source: 123  // o.a.f.c.ASTExpNumberLiteral
-        - variable scope: "3"  // Integer
-        - namespace: null  // Null
-    #text  // o.a.f.c.ASTStaticText
-        - content: "\n4 "  // String
-    #if-#elseif-#else-container  // o.a.f.c.ASTDirIfElseIfElseContainer
-        #if  // o.a.f.c.ASTDirIfOrElseOrElseIf
-            - condition: ==  // o.a.f.c.ASTExpComparison
-                - left-hand operand: +  // o.a.f.c.ASTExpAddOrConcat
-                    - left-hand operand: x  // o.a.f.c.ASTExpVariable
-                    - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
-                - right-hand operand: 0  // o.a.f.c.ASTExpNumberLiteral
-            - AST-node subtype: "0"  // Integer
-            #text  // o.a.f.c.ASTStaticText
-                - content: "foo"  // String
-            ${...}  // o.a.f.c.ASTDollarInterpolation
-                - content: y  // o.a.f.c.ASTExpVariable
-            #text  // o.a.f.c.ASTStaticText
-                - content: "bar"  // String
-        #else  // o.a.f.c.ASTDirIfOrElseOrElseIf
-            - condition: null  // Null
-            - AST-node subtype: "1"  // Integer
-            ${...}  // o.a.f.c.ASTDollarInterpolation
-                - content: "static"  // o.a.f.c.ASTExpStringLiteral
-            ${...}  // o.a.f.c.ASTDollarInterpolation
-                - content: dynamic "..."  // o.a.f.c.ASTExpStringLiteral
-                    - value part: "x"  // String
-                    - value part: ${...}  // o.a.f.c.ASTDollarInterpolation
-                        - content: *  // o.a.f.c.ArithmeticExpression
-                            - left-hand operand: baaz  // o.a.f.c.ASTExpVariable
-                            - right-hand operand: 10  // o.a.f.c.ASTExpNumberLiteral
-                            - AST-node subtype: "1"  // Integer
-                    - value part: "y"  // String
-    #text  // o.a.f.c.ASTStaticText
-        - content: "\n5 "  // String
-    #switch  // o.a.f.c.ASTDirSwitch
-        - value: x  // o.a.f.c.ASTExpVariable
-        #case  // o.a.f.c.ASTDirCase
-            - condition: 1  // o.a.f.c.ASTExpNumberLiteral
-            - AST-node subtype: "0"  // Integer
-            #text  // o.a.f.c.ASTStaticText
-                - content: "one"  // String
-        #case  // o.a.f.c.ASTDirCase
-            - condition: 2  // o.a.f.c.ASTExpNumberLiteral
-            - AST-node subtype: "0"  // Integer
-            #text  // o.a.f.c.ASTStaticText
-                - content: "two"  // String
-        #default  // o.a.f.c.ASTDirCase
-            - condition: null  // Null
-            - AST-node subtype: "1"  // Integer
-            #text  // o.a.f.c.ASTStaticText
-                - content: "more"  // String
-    #text  // o.a.f.c.ASTStaticText
-        - content: "\n6 "  // String
-    #macro  // o.a.f.c.ASTDirMacro
-        - assignment target: "foo"  // String
-        - parameter name: "x"  // String
-        - parameter default: null  // Null
-        - parameter name: "y"  // String
-        - parameter default: 2  // o.a.f.c.ASTExpNumberLiteral
-        - parameter name: "z"  // String
-        - parameter default: +  // o.a.f.c.ASTExpAddOrConcat
-            - left-hand operand: y  // o.a.f.c.ASTExpVariable
-            - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
-        - catch-all parameter name: "q"  // String
-        - AST-node subtype: "0"  // Integer
-        #nested  // o.a.f.c.ASTDirNested
-            - passed value: x  // o.a.f.c.ASTExpVariable
-            - passed value: y  // o.a.f.c.ASTExpVariable
-    #text  // o.a.f.c.ASTStaticText
-        - content: "\n7 "  // String
-    #function  // o.a.f.c.ASTDirMacro
-        - assignment target: "foo"  // String
-        - parameter name: "x"  // String
-        - parameter default: null  // Null
-        - parameter name: "y"  // String
-        - parameter default: null  // Null
-        - catch-all parameter name: null  // Null
-        - AST-node subtype: "1"  // Integer
-        #local  // o.a.f.c.ASTDirAssignment
-            - assignment target: "x"  // String
-            - assignment operator: "="  // String
-            - assignment source: 123  // o.a.f.c.ASTExpNumberLiteral
-            - variable scope: "2"  // Integer
-            - namespace: null  // Null
-        #return  // o.a.f.c.ASTDirReturn
-            - value: 1  // o.a.f.c.ASTExpNumberLiteral
-    #text  // o.a.f.c.ASTStaticText
-        - content: "\n8 "  // String
-    #list  // o.a.f.c.ASTDirList
-        - list source: xs  // o.a.f.c.ASTExpVariable
-        - target loop variable: "x"  // String
-    #text  // o.a.f.c.ASTStaticText
-        - content: "\n9 "  // String
-    #list-#else-container  // o.a.f.c.ASTDirListElseContainer
-        #list  // o.a.f.c.ASTDirList
-            - list source: xs  // o.a.f.c.ASTExpVariable
-            #text  // o.a.f.c.ASTStaticText
-                - content: "["  // String
-            #items  // o.a.f.c.ASTDirItems
-                - target loop variable: "x"  // String
-                ${...}  // o.a.f.c.ASTDollarInterpolation
-                    - content: x  // o.a.f.c.ASTExpVariable
-                #sep  // o.a.f.c.ASTDirSep
-                    #text  // o.a.f.c.ASTStaticText
-                        - content: ", "  // String
-            #text  // o.a.f.c.ASTStaticText
-                - content: "]"  // String
-        #else  // o.a.f.c.ASTDirElseOfList
-            #text  // o.a.f.c.ASTStaticText
-                - content: "None"  // String
-    #text  // o.a.f.c.ASTStaticText
-        - content: "\n10 "  // String
-    #--...--  // o.a.f.c.ASTComment
-        - content: " A comment "  // String
-    #text  // o.a.f.c.ASTStaticText
-        - content: "\n11 "  // String
-    #outputformat  // o.a.f.c.ASTDirOutputFormat
-        - value: "XML"  // o.a.f.c.ASTExpStringLiteral
-        #noautoesc  // o.a.f.c.ASTDirNoAutoEsc
-            ${...}  // o.a.f.c.ASTDollarInterpolation
-                - content: a  // o.a.f.c.ASTExpVariable
-            #autoesc  // o.a.f.c.ASTDirAutoEsc
-                ${...}  // o.a.f.c.ASTDollarInterpolation
-                    - content: b  // o.a.f.c.ASTExpVariable
-            ${...}  // o.a.f.c.ASTDollarInterpolation
-                - content: c  // o.a.f.c.ASTExpVariable

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-1.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-1.ftl b/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-1.ftl
deleted file mode 100644
index 8c8953a..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-1.ftl
+++ /dev/null
@@ -1,29 +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.
--->
-1 <@foo x=1 y=2; b1, b2>x</...@foo>
-2 <@ns.bar 1 2; b1, b2>y</@>
-3 <#assign x = 123><#assign x = 123 in ns><#global x = 123>
-4 <#if x + 1 == 0>foo${y}bar<#else>${"static"}${'x${baaz * 10}y'}</#if>
-5 <#switch x><#case 1>one<#case 2>two<#default>more</#switch>
-6 <#macro foo x y=2 z=y+1 q...><#nested x y></#macro>
-7 <#function foo x y><#local x = 123><#return 1></#function>
-8 <#list xs as x></#list>
-9 <#list xs>[<#items as x>${x}<#sep>, </#items>]<#else>None</#list>
-10 <#-- A comment -->
-11 <#outputFormat "XML"><#noAutoEsc>${a}<#autoEsc>${b}</#autoEsc>${c}</#noAutoEsc></#outputFormat>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-assignments.ast
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-assignments.ast b/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-assignments.ast
deleted file mode 100644
index 4839892..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-assignments.ast
+++ /dev/null
@@ -1,172 +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.
- */
-#mixed_content  // o.a.f.c.ASTImplicitParent
-    #text  // o.a.f.c.ASTStaticText
-        - content: "1 "  // String
-    #assign  // o.a.f.c.ASTDirAssignment
-        - assignment target: "x"  // String
-        - assignment operator: "="  // String
-        - assignment source: 1  // o.a.f.c.ASTExpNumberLiteral
-        - variable scope: "1"  // Integer
-        - namespace: null  // Null
-    #text  // o.a.f.c.ASTStaticText
-        - content: "\n2 "  // String
-    #assign  // o.a.f.c.ASTDirAssignmentsContainer
-        - variable scope: "1"  // Integer
-        - namespace: null  // Null
-        #assign  // o.a.f.c.ASTDirAssignment
-            - assignment target: "x"  // String
-            - assignment operator: "="  // String
-            - assignment source: 1  // o.a.f.c.ASTExpNumberLiteral
-            - variable scope: "1"  // Integer
-            - namespace: null  // Null
-        #assign  // o.a.f.c.ASTDirAssignment
-            - assignment target: "y"  // String
-            - assignment operator: "="  // String
-            - assignment source: 2  // o.a.f.c.ASTExpNumberLiteral
-            - variable scope: "1"  // Integer
-            - namespace: null  // Null
-    #text  // o.a.f.c.ASTStaticText
-        - content: "\n3 "  // String
-    #assign  // o.a.f.c.ASTDirAssignment
-        - assignment target: "x"  // String
-        - assignment operator: "="  // String
-        - assignment source: 1  // o.a.f.c.ASTExpNumberLiteral
-        - variable scope: "1"  // Integer
-        - namespace: ns  // o.a.f.c.ASTExpVariable
-    #text  // o.a.f.c.ASTStaticText
-        - content: "\n4 "  // String
-    #assign  // o.a.f.c.ASTDirAssignmentsContainer
-        - variable scope: "1"  // Integer
-        - namespace: ns  // o.a.f.c.ASTExpVariable
-        #assign  // o.a.f.c.ASTDirAssignment
-            - assignment target: "x"  // String
-            - assignment operator: "="  // String
-            - assignment source: 1  // o.a.f.c.ASTExpNumberLiteral
-            - variable scope: "1"  // Integer
-            - namespace: ns  // o.a.f.c.ASTExpVariable
-        #assign  // o.a.f.c.ASTDirAssignment
-            - assignment target: "y"  // String
-            - assignment operator: "="  // String
-            - assignment source: 2  // o.a.f.c.ASTExpNumberLiteral
-            - variable scope: "1"  // Integer
-            - namespace: ns  // o.a.f.c.ASTExpVariable
-    #text  // o.a.f.c.ASTStaticText
-        - content: "\n5 "  // String
-    #global  // o.a.f.c.ASTDirAssignment
-        - assignment target: "x"  // String
-        - assignment operator: "="  // String
-        - assignment source: 1  // o.a.f.c.ASTExpNumberLiteral
-        - variable scope: "3"  // Integer
-        - namespace: null  // Null
-    #text  // o.a.f.c.ASTStaticText
-        - content: "\n6 "  // String
-    #global  // o.a.f.c.ASTDirAssignmentsContainer
-        - variable scope: "3"  // Integer
-        - namespace: null  // Null
-        #global  // o.a.f.c.ASTDirAssignment
-            - assignment target: "x"  // String
-            - assignment operator: "="  // String
-            - assignment source: 1  // o.a.f.c.ASTExpNumberLiteral
-            - variable scope: "3"  // Integer
-            - namespace: null  // Null
-        #global  // o.a.f.c.ASTDirAssignment
-            - assignment target: "y"  // String
-            - assignment operator: "="  // String
-            - assignment source: 2  // o.a.f.c.ASTExpNumberLiteral
-            - variable scope: "3"  // Integer
-            - namespace: null  // Null
-    #macro  // o.a.f.c.ASTDirMacro
-        - assignment target: "m"  // String
-        - catch-all parameter name: null  // Null
-        - AST-node subtype: "0"  // Integer
-        #text  // o.a.f.c.ASTStaticText
-            - content: "  7 "  // String
-        #local  // o.a.f.c.ASTDirAssignment
-            - assignment target: "x"  // String
-            - assignment operator: "="  // String
-            - assignment source: 1  // o.a.f.c.ASTExpNumberLiteral
-            - variable scope: "2"  // Integer
-            - namespace: null  // Null
-        #text  // o.a.f.c.ASTStaticText
-            - content: "\n  8 "  // String
-        #local  // o.a.f.c.ASTDirAssignmentsContainer
-            - variable scope: "2"  // Integer
-            - namespace: null  // Null
-            #local  // o.a.f.c.ASTDirAssignment
-                - assignment target: "x"  // String
-                - assignment operator: "="  // String
-                - assignment source: 1  // o.a.f.c.ASTExpNumberLiteral
-                - variable scope: "2"  // Integer
-                - namespace: null  // Null
-            #local  // o.a.f.c.ASTDirAssignment
-                - assignment target: "y"  // String
-                - assignment operator: "="  // String
-                - assignment source: 2  // o.a.f.c.ASTExpNumberLiteral
-                - variable scope: "2"  // Integer
-                - namespace: null  // Null
-        #text  // o.a.f.c.ASTStaticText
-            - content: "\n"  // String
-    #text  // o.a.f.c.ASTStaticText
-        - content: "9 "  // String
-    #assign  // o.a.f.c.ASTDirAssignmentsContainer
-        - variable scope: "1"  // Integer
-        - namespace: null  // Null
-        #assign  // o.a.f.c.ASTDirAssignment
-            - assignment target: "a"  // String
-            - assignment operator: "+="  // String
-            - assignment source: 1  // o.a.f.c.ASTExpNumberLiteral
-            - variable scope: "1"  // Integer
-            - namespace: null  // Null
-        #assign  // o.a.f.c.ASTDirAssignment
-            - assignment target: "b"  // String
-            - assignment operator: "-="  // String
-            - assignment source: 2  // o.a.f.c.ASTExpNumberLiteral
-            - variable scope: "1"  // Integer
-            - namespace: null  // Null
-        #assign  // o.a.f.c.ASTDirAssignment
-            - assignment target: "c"  // String
-            - assignment operator: "*="  // String
-            - assignment source: 3  // o.a.f.c.ASTExpNumberLiteral
-            - variable scope: "1"  // Integer
-            - namespace: null  // Null
-        #assign  // o.a.f.c.ASTDirAssignment
-            - assignment target: "d"  // String
-            - assignment operator: "/="  // String
-            - assignment source: 4  // o.a.f.c.ASTExpNumberLiteral
-            - variable scope: "1"  // Integer
-            - namespace: null  // Null
-        #assign  // o.a.f.c.ASTDirAssignment
-            - assignment target: "e"  // String
-            - assignment operator: "%="  // String
-            - assignment source: 5  // o.a.f.c.ASTExpNumberLiteral
-            - variable scope: "1"  // Integer
-            - namespace: null  // Null
-        #assign  // o.a.f.c.ASTDirAssignment
-            - assignment target: "f"  // String
-            - assignment operator: "++"  // String
-            - assignment source: null  // Null
-            - variable scope: "1"  // Integer
-            - namespace: null  // Null
-        #assign  // o.a.f.c.ASTDirAssignment
-            - assignment target: "g"  // String
-            - assignment operator: "--"  // String
-            - assignment source: null  // Null
-            - variable scope: "1"  // Integer
-            - namespace: null  // Null

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-assignments.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-assignments.ftl b/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-assignments.ftl
deleted file mode 100644
index c070635..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-assignments.ftl
+++ /dev/null
@@ -1,29 +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.
--->
-1 <#assign x = 1>
-2 <#assign x = 1, y = 2>
-3 <#assign x = 1 in ns>
-4 <#assign x = 1, y = 2 in ns>
-5 <#global x = 1>
-6 <#global x = 1, y = 2>
-<#macro m>
-  7 <#local x = 1>
-  8 <#local x = 1, y = 2>
-</#macro>
-9 <#assign a += 1, b -= 2, c *= 3, d /= 4, e %= 5, f++, g-->

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-builtins.ast
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-builtins.ast b/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-builtins.ast
deleted file mode 100644
index b8b696f..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-builtins.ast
+++ /dev/null
@@ -1,59 +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.
- */
-#mixed_content  // o.a.f.c.ASTImplicitParent
-    ${...}  // o.a.f.c.ASTDollarInterpolation
-        - content: ?trim  // o.a.f.c.BuiltInsForStringsBasic$trimBI
-            - left-hand operand: x  // o.a.f.c.ASTExpVariable
-            - right-hand operand: "trim"  // String
-    #text  // o.a.f.c.ASTStaticText
-        - content: "\n"  // String
-    ${...}  // o.a.f.c.ASTDollarInterpolation
-        - content: ...(...)  // o.a.f.c.ASTExpMethodCall
-            - callee: ?left_pad  // o.a.f.c.BuiltInsForStringsBasic$padBI
-                - left-hand operand: x  // o.a.f.c.ASTExpVariable
-                - right-hand operand: "left_pad"  // String
-            - argument value: 5  // o.a.f.c.ASTExpNumberLiteral
-    #text  // o.a.f.c.ASTStaticText
-        - content: "\n"  // String
-    ${...}  // o.a.f.c.ASTDollarInterpolation
-        - content: ...(...)  // o.a.f.c.ASTExpMethodCall
-            - callee: ?left_pad  // o.a.f.c.BuiltInsForStringsBasic$padBI
-                - left-hand operand: x  // o.a.f.c.ASTExpVariable
-                - right-hand operand: "left_pad"  // String
-            - argument value: 5  // o.a.f.c.ASTExpNumberLiteral
-            - argument value: "-"  // o.a.f.c.ASTExpStringLiteral
-    #text  // o.a.f.c.ASTStaticText
-        - content: "\n"  // String
-    ${...}  // o.a.f.c.ASTDollarInterpolation
-        - content: ?then(...)  // o.a.f.c.BuiltInsWithParseTimeParameters$then_BI
-            - left-hand operand: x  // o.a.f.c.ASTExpVariable
-            - right-hand operand: "then"  // String
-            - argument value: "y"  // o.a.f.c.ASTExpStringLiteral
-            - argument value: "n"  // o.a.f.c.ASTExpStringLiteral
-    #text  // o.a.f.c.ASTStaticText
-        - content: "\n"  // String
-    ${...}  // o.a.f.c.ASTDollarInterpolation
-        - content: ?switch(...)  // o.a.f.c.BuiltInsWithParseTimeParameters$switch_BI
-            - left-hand operand: x  // o.a.f.c.ASTExpVariable
-            - right-hand operand: "switch"  // String
-            - argument value: 1  // o.a.f.c.ASTExpNumberLiteral
-            - argument value: 11  // o.a.f.c.ASTExpNumberLiteral
-            - argument value: 2  // o.a.f.c.ASTExpNumberLiteral
-            - argument value: 22  // o.a.f.c.ASTExpNumberLiteral
-            - argument value: 33  // o.a.f.c.ASTExpNumberLiteral

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-builtins.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-builtins.ftl b/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-builtins.ftl
deleted file mode 100644
index 74aee52..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-builtins.ftl
+++ /dev/null
@@ -1,23 +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.
--->
-${x?trim}
-${x?left_pad(5)}
-${x?left_pad(5, '-')}
-${x?then('y', 'n')}
-${x?switch(1, 11, 2, 22, 33)}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-locations.ast
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-locations.ast b/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-locations.ast
deleted file mode 100644
index 7770d72..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-locations.ast
+++ /dev/null
@@ -1,155 +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.
- */
-#mixed_content  // o.a.f.c.ASTImplicitParent; Location 1:1-18:8
-    #if  // o.a.f.c.ASTDirIfOrElseOrElseIf; Location 1:1-1:15
-        - condition: exp  // o.a.f.c.ASTExpVariable; Location 1:6-1:8
-        - AST-node subtype: "0"  // Integer
-    #if  // o.a.f.c.ASTDirIfOrElseOrElseIf; Location 2:1-2:16
-        - condition: exp  // o.a.f.c.ASTExpVariable; Location 2:6-2:8
-        - AST-node subtype: "0"  // Integer
-        #text  // o.a.f.c.ASTStaticText; Location 2:10-2:10
-            - content: "1"  // String
-    #text  // o.a.f.c.ASTStaticText; Location 2:17-2:17
-        - content: "\n"  // String
-    #if  // o.a.f.c.ASTDirIfOrElseOrElseIf; Location 3:1-3:20
-        - condition: exp  // o.a.f.c.ASTExpVariable; Location 3:6-3:8
-        - AST-node subtype: "0"  // Integer
-        ${...}  // o.a.f.c.ASTDollarInterpolation; Location 3:10-3:13
-            - content: 1  // o.a.f.c.ASTExpNumberLiteral; Location 3:12-3:12
-        #text  // o.a.f.c.ASTStaticText; Location 3:14-3:14
-            - content: "2"  // String
-    #text  // o.a.f.c.ASTStaticText; Location 3:21-3:21
-        - content: "\n"  // String
-    #if-#elseif-#else-container  // o.a.f.c.ASTDirIfElseIfElseContainer; Location 4:1-4:22
-        #if  // o.a.f.c.ASTDirIfOrElseOrElseIf; Location 4:1-4:9
-            - condition: exp  // o.a.f.c.ASTExpVariable; Location 4:6-4:8
-            - AST-node subtype: "0"  // Integer
-        #else  // o.a.f.c.ASTDirIfOrElseOrElseIf; Location 4:10-4:16
-            - condition: null  // Null
-            - AST-node subtype: "1"  // Integer
-    #if-#elseif-#else-container  // o.a.f.c.ASTDirIfElseIfElseContainer; Location 5:1-5:24
-        #if  // o.a.f.c.ASTDirIfOrElseOrElseIf; Location 5:1-5:10
-            - condition: exp  // o.a.f.c.ASTExpVariable; Location 5:6-5:8
-            - AST-node subtype: "0"  // Integer
-            #text  // o.a.f.c.ASTStaticText; Location 5:10-5:10
-                - content: "1"  // String
-        #else  // o.a.f.c.ASTDirIfOrElseOrElseIf; Location 5:11-5:18
-            - condition: null  // Null
-            - AST-node subtype: "1"  // Integer
-            #text  // o.a.f.c.ASTStaticText; Location 5:18-5:18
-                - content: "1"  // String
-    #text  // o.a.f.c.ASTStaticText; Location 5:25-5:25
-        - content: "\n"  // String
-    #if-#elseif-#else-container  // o.a.f.c.ASTDirIfElseIfElseContainer; Location 6:1-6:32
-        #if  // o.a.f.c.ASTDirIfOrElseOrElseIf; Location 6:1-6:14
-            - condition: exp  // o.a.f.c.ASTExpVariable; Location 6:6-6:8
-            - AST-node subtype: "0"  // Integer
-            ${...}  // o.a.f.c.ASTDollarInterpolation; Location 6:10-6:13
-                - content: 1  // o.a.f.c.ASTExpNumberLiteral; Location 6:12-6:12
-            #text  // o.a.f.c.ASTStaticText; Location 6:14-6:14
-                - content: "2"  // String
-        #else  // o.a.f.c.ASTDirIfOrElseOrElseIf; Location 6:15-6:26
-            - condition: null  // Null
-            - AST-node subtype: "1"  // Integer
-            ${...}  // o.a.f.c.ASTDollarInterpolation; Location 6:22-6:25
-                - content: 1  // o.a.f.c.ASTExpNumberLiteral; Location 6:24-6:24
-            #text  // o.a.f.c.ASTStaticText; Location 6:26-6:26
-                - content: "2"  // String
-    #text  // o.a.f.c.ASTStaticText; Location 6:33-6:33
-        - content: "\n"  // String
-    #if-#elseif-#else-container  // o.a.f.c.ASTDirIfElseIfElseContainer; Location 7:1-7:28
-        #if  // o.a.f.c.ASTDirIfOrElseOrElseIf; Location 7:1-7:9
-            - condition: exp  // o.a.f.c.ASTExpVariable; Location 7:6-7:8
-            - AST-node subtype: "0"  // Integer
-        #elseif  // o.a.f.c.ASTDirIfOrElseOrElseIf; Location 7:10-7:22
-            - condition: exp  // o.a.f.c.ASTExpVariable; Location 7:19-7:21
-            - AST-node subtype: "2"  // Integer
-    #if-#elseif-#else-container  // o.a.f.c.ASTDirIfElseIfElseContainer; Location 8:1-8:29
-        #if  // o.a.f.c.ASTDirIfOrElseOrElseIf; Location 8:1-8:9
-            - condition: exp  // o.a.f.c.ASTExpVariable; Location 8:6-8:8
-            - AST-node subtype: "0"  // Integer
-        #elseif  // o.a.f.c.ASTDirIfOrElseOrElseIf; Location 8:10-8:23
-            - condition: exp  // o.a.f.c.ASTExpVariable; Location 8:19-8:21
-            - AST-node subtype: "2"  // Integer
-            #text  // o.a.f.c.ASTStaticText; Location 8:23-8:23
-                - content: "1"  // String
-    #text  // o.a.f.c.ASTStaticText; Location 8:30-8:30
-        - content: "\n"  // String
-    #attempt  // o.a.f.c.ASTDirAttemptRecoverContainer; Location 9:1-9:31
-        - error handler: #recover  // o.a.f.c.ASTDirRecover; Location 9:11-9:20
-        #recover  // o.a.f.c.ASTDirRecover; Location 9:11-9:20
-    #attempt  // o.a.f.c.ASTDirAttemptRecoverContainer; Location 10:1-10:33
-        - error handler: #recover  // o.a.f.c.ASTDirRecover; Location 10:12-10:22
-            #text  // o.a.f.c.ASTStaticText; Location 10:22-10:22
-                - content: "1"  // String
-        #text  // o.a.f.c.ASTStaticText; Location 10:11-10:11
-            - content: "1"  // String
-        #recover  // o.a.f.c.ASTDirRecover; Location 10:12-10:22
-            #text  // o.a.f.c.ASTStaticText; Location 10:22-10:22
-                - content: "1"  // String
-    #text  // o.a.f.c.ASTStaticText; Location 10:34-10:34
-        - content: "\n"  // String
-    #list  // o.a.f.c.ASTDirList; Location 11:1-11:22
-        - list source: s  // o.a.f.c.ASTExpVariable; Location 11:8-11:8
-        - target loop variable: "i"  // String
-    #list  // o.a.f.c.ASTDirList; Location 12:1-12:23
-        - list source: s  // o.a.f.c.ASTExpVariable; Location 12:8-12:8
-        - target loop variable: "i"  // String
-        #text  // o.a.f.c.ASTStaticText; Location 12:15-12:15
-            - content: "1"  // String
-    #text  // o.a.f.c.ASTStaticText; Location 12:24-12:24
-        - content: "\n"  // String
-    #list  // o.a.f.c.ASTDirList; Location 13:1-13:28
-        - list source: s  // o.a.f.c.ASTExpVariable; Location 13:8-13:8
-        - target loop variable: "i"  // String
-        #sep  // o.a.f.c.ASTDirSep; Location 13:15-13:20
-    #list  // o.a.f.c.ASTDirList; Location 14:1-14:30
-        - list source: s  // o.a.f.c.ASTExpVariable; Location 14:8-14:8
-        - target loop variable: "i"  // String
-        #text  // o.a.f.c.ASTStaticText; Location 14:15-14:15
-            - content: "1"  // String
-        #sep  // o.a.f.c.ASTDirSep; Location 14:16-14:22
-            #text  // o.a.f.c.ASTStaticText; Location 14:22-14:22
-                - content: "1"  // String
-    #text  // o.a.f.c.ASTStaticText; Location 14:31-14:31
-        - content: "\n"  // String
-    #list  // o.a.f.c.ASTDirList; Location 15:1-15:45
-        - list source: s  // o.a.f.c.ASTExpVariable; Location 15:8-15:8
-        #items  // o.a.f.c.ASTDirItems; Location 15:10-15:37
-            - target loop variable: "i"  // String
-            #sep  // o.a.f.c.ASTDirSep; Location 15:23-15:28
-    #list  // o.a.f.c.ASTDirList; Location 16:1-16:49
-        - list source: s  // o.a.f.c.ASTExpVariable; Location 16:8-16:8
-        #text  // o.a.f.c.ASTStaticText; Location 16:10-16:10
-            - content: "1"  // String
-        #items  // o.a.f.c.ASTDirItems; Location 16:11-16:40
-            - target loop variable: "i"  // String
-            #text  // o.a.f.c.ASTStaticText; Location 16:24-16:24
-                - content: "1"  // String
-            #sep  // o.a.f.c.ASTDirSep; Location 16:25-16:31
-                #text  // o.a.f.c.ASTStaticText; Location 16:31-16:31
-                    - content: "1"  // String
-        #text  // o.a.f.c.ASTStaticText; Location 16:41-16:41
-            - content: "1"  // String
-    #text  // o.a.f.c.ASTStaticText; Location 16:50-17:2
-        - content: "\n1\n"  // String
-    ${...}  // o.a.f.c.ASTDollarInterpolation; Location 18:1-18:8
-        - content: +  // o.a.f.c.ASTExpAddOrConcat; Location 18:3-18:7
-            - left-hand operand: x  // o.a.f.c.ASTExpVariable; Location 18:3-18:3
-            - right-hand operand: y  // o.a.f.c.ASTExpVariable; Location 18:7-18:7

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-locations.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-locations.ftl b/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-locations.ftl
deleted file mode 100644
index 99fa244..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-locations.ftl
+++ /dev/null
@@ -1,36 +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.
--->
-<#if exp></#if>
-<#if exp>1</#if>
-<#if exp>${1}2</#if>
-<#if exp><#else></#if>
-<#if exp>1<#else>1</#if>
-<#if exp>${1}2<#else>${1}2</#if>
-<#if exp><#elseif exp></#if>
-<#if exp><#elseif exp>1</#if>
-<#attempt><#recover></#attempt>
-<#attempt>1<#recover>1</#attempt>
-<#list s as i></#list>
-<#list s as i>1</#list>
-<#list s as i><#sep></#list>
-<#list s as i>1<#sep>1</#list>
-<#list s><#items as i><#sep></#items></#list>
-<#list s>1<#items as i>1<#sep>1</#items>1</#list>
-1
-${x + y}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-mixedcontentsimplifications.ast
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-mixedcontentsimplifications.ast b/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-mixedcontentsimplifications.ast
deleted file mode 100644
index 41fc90b..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-mixedcontentsimplifications.ast
+++ /dev/null
@@ -1,38 +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.
- */
-#if  // o.a.f.c.ASTDirIfOrElseOrElseIf
-    - condition: true  // o.a.f.c.ASTExpBooleanLiteral
-    - AST-node subtype: "0"  // Integer
-    #if  // o.a.f.c.ASTDirIfOrElseOrElseIf
-        - condition: true  // o.a.f.c.ASTExpBooleanLiteral
-        - AST-node subtype: "0"  // Integer
-    #if  // o.a.f.c.ASTDirIfOrElseOrElseIf
-        - condition: true  // o.a.f.c.ASTExpBooleanLiteral
-        - AST-node subtype: "0"  // Integer
-        #text  // o.a.f.c.ASTStaticText
-            - content: "        text\n"  // String
-    #text  // o.a.f.c.ASTStaticText
-        - content: "    "  // String
-    #if  // o.a.f.c.ASTDirIfOrElseOrElseIf
-        - condition: true  // o.a.f.c.ASTExpBooleanLiteral
-        - AST-node subtype: "0"  // Integer
-        ${...}  // o.a.f.c.ASTDollarInterpolation
-            - content: x  // o.a.f.c.ASTExpVariable
-    #text  // o.a.f.c.ASTStaticText
-        - content: "\n"  // String

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-mixedcontentsimplifications.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-mixedcontentsimplifications.ftl b/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-mixedcontentsimplifications.ftl
deleted file mode 100644
index 53716e4..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-mixedcontentsimplifications.ftl
+++ /dev/null
@@ -1,26 +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.
--->
-<#if true>
-    <#if true>
-    </#if>
-    <#if true>
-        text
-    </#if>
-    <#if true>${x}</#if>
-</#if>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-multipleignoredchildren.ast
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-multipleignoredchildren.ast b/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-multipleignoredchildren.ast
deleted file mode 100644
index 7675522..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-multipleignoredchildren.ast
+++ /dev/null
@@ -1,30 +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.
- */
-#mixed_content  // o.a.f.c.ASTImplicitParent
-    #text  // o.a.f.c.ASTStaticText
-        - content: "a\n"  // String
-    #text  // o.a.f.c.ASTStaticText
-        - content: "b\n"  // String
-    #text  // o.a.f.c.ASTStaticText
-        - content: "c\n"  // String
-    #text  // o.a.f.c.ASTStaticText
-        - content: "d\n"  // String
-    #if  // o.a.f.c.ASTDirIfOrElseOrElseIf
-        - condition: true  // o.a.f.c.ASTExpBooleanLiteral
-        - AST-node subtype: "0"  // Integer

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-multipleignoredchildren.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-multipleignoredchildren.ftl b/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-multipleignoredchildren.ftl
deleted file mode 100644
index 501802a..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-multipleignoredchildren.ftl
+++ /dev/null
@@ -1,33 +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.
--->
-a
-<#compress></#compress>
-b
-<#compress></#compress>
-<#compress></#compress>
-c
-<#compress></#compress>
-<#compress></#compress>
-<#compress></#compress>
-d
-<#if true>
-  <#compress></#compress>
-  <#compress></#compress>
-  <#compress></#compress>
-</#if>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-nestedignoredchildren.ast
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-nestedignoredchildren.ast b/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-nestedignoredchildren.ast
deleted file mode 100644
index eefa5b1..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-nestedignoredchildren.ast
+++ /dev/null
@@ -1,20 +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.
- */
-#outputformat  // o.a.f.c.ASTDirOutputFormat
-    - value: "HTML"  // o.a.f.c.ASTExpStringLiteral

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-nestedignoredchildren.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-nestedignoredchildren.ftl b/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-nestedignoredchildren.ftl
deleted file mode 100644
index fbdb342..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-nestedignoredchildren.ftl
+++ /dev/null
@@ -1,19 +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.
--->
-<#outputFormat 'HTML'><#outputFormat 'HTML'><#outputFormat 'HTML'></#outputFormat></#outputFormat></#outputFormat>
\ No newline at end of file


[38/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/TypeFlagsTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/TypeFlagsTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/TypeFlagsTest.java
new file mode 100644
index 0000000..fe11d1c
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/TypeFlagsTest.java
@@ -0,0 +1,671 @@
+/*
+ * 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.model.impl;
+
+import java.io.File;
+import java.lang.reflect.Method;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.freemarker.core.Configuration;
+
+import junit.framework.TestCase;
+
+public class TypeFlagsTest extends TestCase {
+
+    public TypeFlagsTest(String name) {
+        super(name);
+    }
+    
+    private final DefaultObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
+
+    public void testSingleNumType() {
+        checkTypeFlags(SingleNumTypeC.class, "mInt",
+                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.INTEGER | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER
+                | TypeFlags.ACCEPTS_STRING);
+        checkTypeFlags(SingleNumTypeC.class, "mLong",
+                TypeFlags.LONG | TypeFlags.ACCEPTS_NUMBER);
+        checkTypeFlags(SingleNumTypeC.class, "mShort",
+                TypeFlags.SHORT | TypeFlags.ACCEPTS_NUMBER);
+        checkTypeFlags(SingleNumTypeC.class, "mByte",
+                TypeFlags.BYTE | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.ACCEPTS_ANY_OBJECT);
+        checkTypeFlags(SingleNumTypeC.class, "mDouble",
+                TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER);
+        checkTypeFlags(SingleNumTypeC.class, "mFloat",
+                TypeFlags.FLOAT | TypeFlags.ACCEPTS_NUMBER);
+        checkTypeFlags(SingleNumTypeC.class, "mUnknown",
+                TypeFlags.UNKNOWN_NUMERICAL_TYPE | TypeFlags.ACCEPTS_NUMBER);
+        
+        checkTypeFlags(SingleNumTypeC.class, "mVarParamCnt",
+                TypeFlags.BIG_DECIMAL | TypeFlags.ACCEPTS_NUMBER);
+        checkTypeFlags(SingleNumTypeC.class, "mVarParamCnt",
+                TypeFlags.BIG_INTEGER | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER);
+        checkTypeFlags(SingleNumTypeC.class, "mVarParamCnt",
+                TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.FLOAT | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER);
+    }
+    
+    static public class SingleNumTypeC {
+        public void mInt(int a1, String a2) { }
+        public void mInt(int a1, int a2) { }
+        public void mLong(long a1) { }
+        public void mLong(Long a1) { }
+        public void mShort(short a1) { }
+        public void mByte(byte a1, boolean a2) { }
+        public void mByte(byte a1, String a2) { }
+        public void mByte(byte a1, Object a2) { }
+        public void mDouble(double a1) { }
+        public void mFloat(float a1) { }
+        public void mUnknown(RationalNumber a1) { };
+        
+        public void mVarParamCnt(BigDecimal a1) { }
+        public void mVarParamCnt(BigInteger a1, Double a2) { }
+        public void mVarParamCnt(Double a1,     Float a2, Integer a3) { }
+        public void mVarParamCnt(Object a1,     char a2,  boolean a3, File a4, Map a5,    Boolean a6) { }
+        public void mVarParamCnt(Long a1,       int a2,   short a3,   byte a4, double a5, float a6) { }
+    }
+
+    public void testMultipleNumTypes() {
+        checkTypeFlags(MultiNumTypeC.class, "m1",
+                TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT 
+                | TypeFlags.BYTE | TypeFlags.DOUBLE | TypeFlags.INTEGER
+                | TypeFlags.ACCEPTS_NUMBER
+                );
+        
+        checkTypeFlags(MultiNumTypeC.class, "m2",
+                TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT 
+                | TypeFlags.SHORT | TypeFlags.LONG | TypeFlags.FLOAT
+                | TypeFlags.ACCEPTS_NUMBER | TypeFlags.CHARACTER
+                );
+
+        checkTypeFlags(MultiNumTypeC.class, "m3",
+                TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT 
+                | TypeFlags.BIG_DECIMAL | TypeFlags.BIG_INTEGER
+                | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.BIG_INTEGER | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT
+                | TypeFlags.BIG_DECIMAL | TypeFlags.UNKNOWN_NUMERICAL_TYPE
+                | TypeFlags.ACCEPTS_NUMBER
+                );
+        
+        checkTypeFlags(MultiNumTypeC.class, "m4",
+                TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.FLOAT | TypeFlags.ACCEPTS_NUMBER
+                | TypeFlags.CHARACTER
+                );
+        
+        checkTypeFlags(MultiNumTypeC.class, "m5",
+                TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT
+                | TypeFlags.FLOAT | TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER
+                );
+        
+        checkTypeFlags(MultiNumTypeC.class, "m6",
+                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER
+                );
+        assertSame(getTypeFlags(MultiNumTypeC.class, "m6", false, 2), OverloadedMethodsSubset.ALL_ZEROS_ARRAY);
+        assertSame(getTypeFlags(MultiNumTypeC.class, "m6", true, 2), OverloadedMethodsSubset.ALL_ZEROS_ARRAY);
+        assertSame(getTypeFlags(MultiNumTypeC.class, "m6", false, 3), OverloadedMethodsSubset.ALL_ZEROS_ARRAY);
+        assertSame(getTypeFlags(MultiNumTypeC.class, "m6", true, 3), OverloadedMethodsSubset.ALL_ZEROS_ARRAY);
+        checkTypeFlags(MultiNumTypeC.class, "m6",
+                TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER,
+                0
+                );
+    }
+    
+    static public class MultiNumTypeC {
+        public void m1(byte a1) { };
+        public void m1(int a1) { };
+        public void m1(double a2) { };
+        
+        public void m2(short a1) { };
+        public void m2(long a1) { };
+        public void m2(float a1) { };
+        public void m2(char a1) { };
+        
+        public void m3(BigInteger a1, BigInteger a2, BigDecimal a3) { };
+        public void m3(BigDecimal a1, BigInteger a2, RationalNumber a3) { };
+        
+        public void m4(float a1) { };
+        public void m4(char a1) { };
+        
+        public void m5(Float a1) { };
+        public void m5(Double a1) { };
+        public void m5(Enum a1) { };
+        
+        public void m6(int a1) { };
+        public void m6(File a1, Throwable a2) { };
+        public void m6(File a1, Throwable a2, StringBuilder a3) { };
+        public void m6(File a1, Throwable a2, Throwable a3) { };
+        public void m6(double a1, int a2, File a3, File a4) { };
+        public void m6(File a1, int a2, double a3, File a4) { };
+    }
+
+    public void testVarargsNums() {
+        checkTypeFlags(VarArgsC.class, "m1",
+                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER
+                );
+        checkTypeFlags(VarArgsC.class, "m2",
+                TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER
+                );
+        
+        checkTypeFlags(VarArgsC.class, "m3",
+                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER
+                );
+        checkTypeFlags(VarArgsC.class, "m3",
+                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.DOUBLE | TypeFlags.INTEGER
+                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER
+                );
+        checkTypeFlags(VarArgsC.class, "m3",
+                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.DOUBLE | TypeFlags.INTEGER
+                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.DOUBLE | TypeFlags.INTEGER
+                | TypeFlags.BIG_DECIMAL | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER
+                );
+        
+        checkTypeFlags(VarArgsC.class, "m4",
+                TypeFlags.INTEGER | TypeFlags.LONG
+                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER
+                );
+        
+        checkTypeFlags(VarArgsC.class, "m5",
+                TypeFlags.LONG | TypeFlags.ACCEPTS_NUMBER
+                );
+        
+        checkTypeFlags(VarArgsC.class, "m6",
+                TypeFlags.LONG | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER
+                | TypeFlags.ACCEPTS_STRING
+                );
+        
+        checkTypeFlags(VarArgsC.class, "m7",
+                TypeFlags.INTEGER | TypeFlags.BYTE
+                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.DOUBLE | TypeFlags.FLOAT
+                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER
+                );
+
+        checkTypeFlags(VarArgsC.class, "m8",
+                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.DOUBLE | TypeFlags.FLOAT
+                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER
+                );
+        
+        checkTypeFlags(VarArgsC.class, "m9",
+                TypeFlags.INTEGER | TypeFlags.BYTE
+                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER
+                );
+        
+        checkTypeFlags(VarArgsC.class, "m10",
+                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER
+                );
+        checkTypeFlags(VarArgsC.class, "m10",
+                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.LONG | TypeFlags.DOUBLE
+                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER
+                );
+        
+        checkTypeFlags(VarArgsC.class, "m11",
+                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.DOUBLE | TypeFlags.SHORT | TypeFlags.ACCEPTS_NUMBER
+                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER
+                );
+        checkTypeFlags(VarArgsC.class, "m11",
+                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.DOUBLE | TypeFlags.SHORT
+                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.LONG | TypeFlags.DOUBLE
+                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER
+                );
+        
+        checkTypeFlags(VarArgsC.class, "m12",
+                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER
+                );
+        checkTypeFlags(VarArgsC.class, "m12",
+                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.DOUBLE | TypeFlags.SHORT
+                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.DOUBLE | TypeFlags.BYTE
+                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.LONG | TypeFlags.DOUBLE
+                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER
+                );
+        
+        checkTypeFlags(VarArgsC.class, "m13",
+                TypeFlags.CHARACTER,
+                TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER);
+        checkTypeFlags(VarArgsC.class, "m13",
+                TypeFlags.CHARACTER,
+                TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.DOUBLE | TypeFlags.UNKNOWN_NUMERICAL_TYPE
+                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER,
+                TypeFlags.DOUBLE | TypeFlags.LONG
+                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER
+                );
+    }
+    
+    static public class VarArgsC {
+        public void m1(int... va) { }
+        
+        public void m2(double a1, int... va) { }
+        
+        public void m3(int... va) { }
+        public void m3(int a1, double... va) { }
+        public void m3(int a1, double a2, BigDecimal... va) { }
+        
+        public void m4(int... va) { }
+        public void m4(long... va) { }
+
+        public void m5(Long... va) { }
+        public void m5(long... va) { }
+        
+        public void m6(long... va) { }
+        public void m6(String... va) { }
+        
+        public void m7(int a1, double... va) { }
+        public void m7(byte a1, float... va) { }
+
+        public void m8(int a1, double... va) { }
+        public void m8(int a1, float... va) { }
+        
+        public void m9(int a1, double... va) { }
+        public void m9(byte a1, double... va) { }
+        
+        public void m10(int a1, double a2, long... va) { }
+        public void m10(int a1, double... va) { }
+        
+        public void m11(int a1, short a2, long... va) { }
+        public void m11(int a1, double... va) { }
+        
+        public void m12(int a1, short a2, byte a3, long... va) { }
+        public void m12(int a1, double... va) { }
+        
+        public void m13(char a1, double a2, RationalNumber a3, Long... va) { }
+        public void m13(char a1, Double... va) { }
+    }
+    
+    public void testAllZeros() {
+        for (boolean reverse : new boolean[] { true, false }) {
+            assertSame(OverloadedMethodsSubset.ALL_ZEROS_ARRAY, getTypeFlags(AllZeroC.class, "m1", reverse, 0));
+            assertSame(OverloadedMethodsSubset.ALL_ZEROS_ARRAY, getTypeFlags(AllZeroC.class, "m2", reverse, 2));
+            assertSame(OverloadedMethodsSubset.ALL_ZEROS_ARRAY, getTypeFlags(AllZeroC.class, "m3", reverse, 1));
+        }
+    }
+    
+    static public class AllZeroC {
+        public void m1() {}
+        
+        public void m2(File a1, File a2) {}
+        
+        public void m3(File a1) {}
+        public void m3(StringBuilder a1) {}
+    }
+
+    public void testAcceptanceNonOverloaded() {
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber1",  TypeFlags.ACCEPTS_NUMBER | TypeFlags.UNKNOWN_NUMERICAL_TYPE);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber2",  TypeFlags.ACCEPTS_NUMBER | TypeFlags.BYTE);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber3",  TypeFlags.ACCEPTS_NUMBER | TypeFlags.BYTE);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber4",  TypeFlags.ACCEPTS_NUMBER | TypeFlags.SHORT);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber5",  TypeFlags.ACCEPTS_NUMBER | TypeFlags.SHORT);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber6",  TypeFlags.ACCEPTS_NUMBER | TypeFlags.INTEGER);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber7",  TypeFlags.ACCEPTS_NUMBER | TypeFlags.INTEGER);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber8",  TypeFlags.ACCEPTS_NUMBER | TypeFlags.LONG);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber9",  TypeFlags.ACCEPTS_NUMBER | TypeFlags.LONG);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber10", TypeFlags.ACCEPTS_NUMBER | TypeFlags.FLOAT);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber11", TypeFlags.ACCEPTS_NUMBER | TypeFlags.FLOAT);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber12", TypeFlags.ACCEPTS_NUMBER | TypeFlags.DOUBLE);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber13", TypeFlags.ACCEPTS_NUMBER | TypeFlags.DOUBLE);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber14", TypeFlags.ACCEPTS_NUMBER | TypeFlags.BIG_INTEGER);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber15", TypeFlags.ACCEPTS_NUMBER | TypeFlags.BIG_DECIMAL);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber16", TypeFlags.ACCEPTS_NUMBER | TypeFlags.UNKNOWN_NUMERICAL_TYPE);
+        
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mDate", TypeFlags.ACCEPTS_DATE);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mSQLDate1", 0);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mSQLDate2", 0);
+        
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mString", TypeFlags.ACCEPTS_STRING);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mCharSequence", TypeFlags.ACCEPTS_STRING);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mStringBuilder", 0);
+        
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mBool", TypeFlags.ACCEPTS_BOOLEAN);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mBoolean", TypeFlags.ACCEPTS_BOOLEAN);
+        
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mMap1", TypeFlags.ACCEPTS_MAP);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mMap2", 0);
+        
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mList1", TypeFlags.ACCEPTS_LIST);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mList2", 0);
+        
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mSet1", TypeFlags.ACCEPTS_SET);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mSet2", 0);
+        
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mCollection", TypeFlags.ACCEPTS_SET | TypeFlags.ACCEPTS_LIST);
+        
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mChar1", TypeFlags.CHARACTER);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mChar2", TypeFlags.CHARACTER);
+        
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mArray1", TypeFlags.ACCEPTS_ARRAY);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mArray2", TypeFlags.ACCEPTS_ARRAY);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mArray3", TypeFlags.ACCEPTS_ARRAY);
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mArray4", TypeFlags.ACCEPTS_ARRAY);
+        
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mObject", TypeFlags.ACCEPTS_ANY_OBJECT);
+        assertTrue((TypeFlags.ACCEPTS_ANY_OBJECT & TypeFlags.ACCEPTS_NUMBER) != 0);
+        assertTrue((TypeFlags.ACCEPTS_ANY_OBJECT & TypeFlags.ACCEPTS_STRING) != 0);
+        assertTrue((TypeFlags.ACCEPTS_ANY_OBJECT & TypeFlags.ACCEPTS_BOOLEAN) != 0);
+        assertTrue((TypeFlags.ACCEPTS_ANY_OBJECT & TypeFlags.ACCEPTS_MAP) != 0);
+        assertTrue((TypeFlags.ACCEPTS_ANY_OBJECT & TypeFlags.ACCEPTS_LIST) != 0);
+        assertTrue((TypeFlags.ACCEPTS_ANY_OBJECT & TypeFlags.ACCEPTS_SET) != 0);
+        assertTrue((TypeFlags.ACCEPTS_ANY_OBJECT & TypeFlags.ACCEPTS_ARRAY) != 0);
+        assertTrue((TypeFlags.ACCEPTS_ANY_OBJECT & TypeFlags.CHARACTER) == 0);  // deliberatly 0 
+        
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mMapDate", 0);
+        
+        checkTypeFlags(AcceptanceNonoverloadedC.class, "mDateBooleanList",
+                TypeFlags.ACCEPTS_DATE, TypeFlags.ACCEPTS_BOOLEAN, TypeFlags.ACCEPTS_LIST);
+    }
+    
+    static public class AcceptanceNonoverloadedC {
+        public void mNumber1(Number a1) {}
+        public void mNumber2(Byte a1) {}
+        public void mNumber3(byte a1) {}
+        public void mNumber4(Short a1) {}
+        public void mNumber5(short a1) {}
+        public void mNumber6(Integer a1) {}
+        public void mNumber7(int a1) {}
+        public void mNumber8(Long a1) {}
+        public void mNumber9(long a1) {}
+        public void mNumber10(Float a1) {}
+        public void mNumber11(float a1) {}
+        public void mNumber12(Double a1) {}
+        public void mNumber13(double a1) {}
+        public void mNumber14(BigInteger a1) {}
+        public void mNumber15(BigDecimal a1) {}
+        public void mNumber16(RationalNumber a1) {}
+        
+        public void mDate(Date a1) {}
+        public void mSQLDate1(java.sql.Date a1) {}
+        public void mSQLDate2(java.sql.Timestamp a1) {}
+        
+        public void mString(String a1) {}
+        public void mCharSequence(CharSequence a1) {}
+        public void mStringBuilder(StringBuilder a1) {}
+        
+        public void mBool(boolean a1) {}
+        public void mBoolean(Boolean a1) {}
+
+        public void mMap1(Map a1) {}
+        public void mMap2(LinkedHashMap a1) {}
+        
+        public void mList1(List a1) {}
+        public void mList2(ArrayList a1) {}
+        
+        public void mSet1(Set a1) {}
+        public void mSet2(HashSet a1) {}
+        
+        public void mCollection(Collection a1) {}
+        
+        public void mMapDate(MapDate a1) {}
+
+        public void mChar1(Character a1) {}
+        public void mChar2(char a1) {}
+
+        public void mArray1(Object[] a1) {}
+        public void mArray2(int[] a1) {}
+        public void mArray3(Integer[] a1) {}
+        public void mArray4(Void[] a1) {}
+        
+        public void mObject(Object a1) {}
+        
+        public void mDateBooleanList(Date a1, boolean a2, List a3) {}
+    }
+
+    public void testAcceptanceOverloaded() {
+        checkTypeFlags(AcceptanceOverloadedC.class, "mLongDateList",
+                TypeFlags.ACCEPTS_NUMBER | TypeFlags.LONG | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT
+                | TypeFlags.ACCEPTS_DATE | TypeFlags.ACCEPTS_LIST);
+        checkTypeFlags(AcceptanceOverloadedC.class, "mBoolean", TypeFlags.ACCEPTS_BOOLEAN);
+        checkTypeFlags(AcceptanceOverloadedC.class, "mStringChar",
+                TypeFlags.ACCEPTS_STRING | TypeFlags.CHARACTER);
+        checkTypeFlags(AcceptanceOverloadedC.class, "mStringFile", TypeFlags.ACCEPTS_STRING);
+        checkTypeFlags(AcceptanceOverloadedC.class, "mMapObject", TypeFlags.ACCEPTS_ANY_OBJECT);
+        checkTypeFlags(AcceptanceOverloadedC.class, "mSetMap", TypeFlags.ACCEPTS_MAP | TypeFlags.ACCEPTS_SET);
+        checkTypeFlags(AcceptanceOverloadedC.class, "mCollectionMap",
+                TypeFlags.ACCEPTS_MAP | TypeFlags.ACCEPTS_SET | TypeFlags.ACCEPTS_LIST);
+        checkTypeFlags(AcceptanceOverloadedC.class, "mArray", TypeFlags.ACCEPTS_ARRAY);
+        checkTypeFlags(AcceptanceOverloadedC.class, "mArrayList", TypeFlags.ACCEPTS_ARRAY | TypeFlags.ACCEPTS_LIST);
+        
+        checkTypeFlags(AcceptanceOverloadedC.class, "mStringCollectionThenBooleanThenMapList",
+                TypeFlags.ACCEPTS_STRING | TypeFlags.ACCEPTS_LIST | TypeFlags.ACCEPTS_SET,
+                TypeFlags.ACCEPTS_BOOLEAN,
+                TypeFlags.ACCEPTS_MAP | TypeFlags.ACCEPTS_LIST);
+    }
+    
+    static public class AcceptanceOverloadedC {
+        public void mLongDateList(long a1) {}
+        public void mLongDateList(Date a1) {}
+        public void mLongDateList(List a1) {}
+
+        public void mBoolean(boolean a1) {}
+        public void mBoolean(Boolean a1) {}
+        
+        public void mDate(Date a1) {}
+        public void mDate(java.sql.Date a1) {}
+        public void mDate(java.sql.Timestamp a1) {}
+        
+        public void mStringChar(String a1) {}
+        public void mStringChar(char a1) {}
+        public void mStringChar(Character a1) {}
+
+        public void mStringFile(String a1) {}
+        public void mStringFile(File a1) {}
+        
+        public void mMapObject(Map a1) {}
+        public void mMapObject(Object a1) {}
+        
+        public void mSetMap(Set a1) {}
+        public void mSetMap(Map a1) {}
+        
+        public void mCollectionMap(Collection a1) {}
+        public void mCollectionMap(Map a1) {}
+        
+        public void mArray(Object[] a1) {}
+        public void mArray(int[] a1) {}
+        public void mArray(Integer[] a1) {}
+        public void mArray(Void[] a1) {}
+        
+        public void mArrayList(String[] a1) {}
+        public void mArrayList(List a1) {}
+        
+        public void mStringCollectionThenBooleanThenMapList(String a1, boolean a2, Map a3) {}
+        public void mStringCollectionThenBooleanThenMapList(Collection a1, boolean a2, Map a3) {}
+        public void mStringCollectionThenBooleanThenMapList(String a1, boolean a2, List a3) {}
+    }
+
+    public void testAcceptanceVarargsC() {
+        checkTypeFlags(AcceptanceVarArgsC.class, "m1",
+                TypeFlags.ACCEPTS_LIST | TypeFlags.ACCEPTS_STRING);
+        
+        checkTypeFlags(AcceptanceVarArgsC.class, "m2",
+                TypeFlags.ACCEPTS_MAP,
+                TypeFlags.ACCEPTS_MAP | TypeFlags.ACCEPTS_STRING | TypeFlags.ACCEPTS_BOOLEAN,
+                TypeFlags.ACCEPTS_MAP | TypeFlags.ACCEPTS_STRING);
+        checkTypeFlags(AcceptanceVarArgsC.class, "m2",
+                TypeFlags.ACCEPTS_MAP,
+                TypeFlags.ACCEPTS_MAP | TypeFlags.ACCEPTS_STRING | TypeFlags.ACCEPTS_BOOLEAN);
+        checkTypeFlags(AcceptanceVarArgsC.class, "m2",
+                TypeFlags.ACCEPTS_MAP);
+        
+        checkTypeFlags(AcceptanceVarArgsC.class, "m3",
+                TypeFlags.ACCEPTS_BOOLEAN);
+        checkTypeFlags(AcceptanceVarArgsC.class, "m3",
+                TypeFlags.ACCEPTS_BOOLEAN | TypeFlags.ACCEPTS_STRING,
+                TypeFlags.ACCEPTS_BOOLEAN | TypeFlags.ACCEPTS_MAP,
+                TypeFlags.ACCEPTS_BOOLEAN | TypeFlags.CHARACTER,
+                TypeFlags.ACCEPTS_BOOLEAN);
+    }
+    
+    static public class AcceptanceVarArgsC {
+        public void m1(List... a1) {}
+        public void m1(String... a1) {}
+
+        public void m2(Map a1, String... a2) {}
+        public void m2(Map a1, boolean a2, String... a3) {}
+        public void m2(Map... a1) {}
+        
+        public void m3(String a1, Map a2, char a3, Boolean... a4) {}
+        public void m3(boolean... a1) {}
+    }
+
+    static public class MapDate extends Date implements Map {
+    
+        @Override
+        public int size() {
+            return 0;
+        }
+    
+        @Override
+        public boolean isEmpty() {
+            return false;
+        }
+    
+        @Override
+        public boolean containsKey(Object key) {
+            return false;
+        }
+    
+        @Override
+        public boolean containsValue(Object value) {
+            return false;
+        }
+    
+        @Override
+        public Object get(Object key) {
+            return null;
+        }
+    
+        @Override
+        public Object put(Object key, Object value) {
+            return null;
+        }
+    
+        @Override
+        public Object remove(Object key) {
+            return null;
+        }
+    
+        @Override
+        public void putAll(Map m) {
+        }
+    
+        @Override
+        public void clear() {
+        }
+    
+        @Override
+        public Set keySet() {
+            return null;
+        }
+    
+        @Override
+        public Collection values() {
+            return null;
+        }
+    
+        @Override
+        public Set entrySet() {
+            return null;
+        }
+        
+    }
+
+    private OverloadedMethodsSubset newOverloadedMethodsSubset(Class cl, String methodName, final boolean desc) {
+        final Method[] ms = cl.getMethods();
+        
+        final List<Method> filteredMethods = new ArrayList();
+        for (Method m : ms) {
+            if (m.getName().equals(methodName)) {
+                filteredMethods.add(m);
+            }
+        }
+        // As the order in which getMethods() returns the methods is undefined, we sort them for test predictability: 
+        Collections.sort(filteredMethods, new Comparator<Method>() {
+            @Override
+            public int compare(Method o1, Method o2) {
+                int res = o1.toString().compareTo(o2.toString());
+                return desc ? -res : res;
+            }
+        });
+        
+        final OverloadedMethodsSubset oms = cl.getName().indexOf("VarArgs") == -1
+                ? new OverloadedFixArgsMethods() : new OverloadedVarArgsMethods();
+        for (Method m : filteredMethods) {
+            oms.addCallableMemberDescriptor(new ReflectionCallableMemberDescriptor(m, m.getParameterTypes()));
+        }
+        return oms;
+    }
+    
+    private void checkTypeFlags(Class cl, String methodName, int... expectedTypeFlags) {
+        checkTypeFlags(cl, methodName, false, expectedTypeFlags);
+        checkTypeFlags(cl, methodName, true, expectedTypeFlags);
+    }
+    
+    private void checkTypeFlags(Class cl, String methodName, boolean revMetOrder, int... expectedTypeFlags) {
+        int[] actualParamTypes = getTypeFlags(cl, methodName, revMetOrder, expectedTypeFlags.length);
+        assertNotNull("Method " + methodName + "(#" + expectedTypeFlags.length + ") doesn't exist", actualParamTypes);
+        if (actualParamTypes != OverloadedMethodsSubset.ALL_ZEROS_ARRAY) {
+            assertEquals(expectedTypeFlags.length, actualParamTypes.length);
+            for (int i = 0; i < expectedTypeFlags.length; i++) {
+                assertEquals(expectedTypeFlags[i], actualParamTypes[i]);
+            }
+        } else {
+            for (int expectedTypeFlag : expectedTypeFlags) {
+                assertEquals(expectedTypeFlag, 0);
+            }
+        }
+    }
+
+    private int[] getTypeFlags(Class cl, String methodName, boolean revMetOrder, int paramCnt) {
+        OverloadedMethodsSubset oms = newOverloadedMethodsSubset(cl, methodName, revMetOrder);
+        int[] actualParamTypes = oms.getTypeFlags(paramCnt);
+        return actualParamTypes;
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/outputformat/_OutputFormatTestAPI.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/outputformat/_OutputFormatTestAPI.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/outputformat/_OutputFormatTestAPI.java
new file mode 100644
index 0000000..0a479aa
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/outputformat/_OutputFormatTestAPI.java
@@ -0,0 +1,35 @@
+/*
+ * 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.outputformat;
+
+public final class _OutputFormatTestAPI {
+
+    private _OutputFormatTestAPI() {
+        //
+    }
+    
+    public static String getMarkupContent(CommonTemplateMarkupOutputModel<?> tm) {
+        return tm.getMarkupContent();
+    }
+    
+    public static String getPlainTextContent(CommonTemplateMarkupOutputModel<?> tm) {
+        return tm.getPlainTextContent();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/outputformat/impl/CombinedMarkupOutputFormatTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/outputformat/impl/CombinedMarkupOutputFormatTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/outputformat/impl/CombinedMarkupOutputFormatTest.java
new file mode 100644
index 0000000..19e45de
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/outputformat/impl/CombinedMarkupOutputFormatTest.java
@@ -0,0 +1,194 @@
+/*
+ * 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.outputformat.impl;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.io.StringWriter;
+
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.outputformat.MarkupOutputFormat;
+import org.apache.freemarker.core.outputformat._OutputFormatTestAPI;
+import org.junit.Test; 
+
+public class CombinedMarkupOutputFormatTest {
+    
+    private static final CombinedMarkupOutputFormat HTML_RTF = new CombinedMarkupOutputFormat(
+            HTMLOutputFormat.INSTANCE, RTFOutputFormat.INSTANCE);
+    private static final CombinedMarkupOutputFormat XML_XML = new CombinedMarkupOutputFormat(
+            XMLOutputFormat.INSTANCE, XMLOutputFormat.INSTANCE);
+
+    @Test
+    public void testName() {
+        assertEquals("HTML{RTF}", HTML_RTF.getName());
+        assertEquals("XML{XML}", XML_XML.getName());
+    }
+    
+    @Test
+    public void testOutputMO() throws TemplateModelException, IOException {
+       StringWriter out = new StringWriter();
+       
+       HTML_RTF.output(HTML_RTF.fromMarkup("<pre>\\par Test "), out);
+       HTML_RTF.output(HTML_RTF.fromPlainTextByEscaping("foo { bar } \\ "), out);
+       HTML_RTF.output(HTML_RTF.fromPlainTextByEscaping("& baaz "), out);
+       HTML_RTF.output(HTML_RTF.fromPlainTextByEscaping("\\par & qwe"), out);
+       HTML_RTF.output(HTML_RTF.fromMarkup("\\par{0} End</pre>"), out);
+       
+       assertEquals(
+               "<pre>\\par Test "
+               + "foo \\{ bar \\} \\\\ "
+               + "&amp; baaz "
+               + "\\\\par &amp; qwe"
+               + "\\par{0} End</pre>",
+               out.toString());
+    }
+
+    @Test
+    public void testOutputMO2() throws TemplateModelException, IOException {
+       StringWriter out = new StringWriter();
+       
+       XML_XML.output(XML_XML.fromMarkup("<pre>&lt;p&gt; Test "), out);
+       XML_XML.output(XML_XML.fromPlainTextByEscaping("a & b < c"), out);
+       XML_XML.output(XML_XML.fromMarkup(" End</pre>"), out);
+       
+       assertEquals(
+               "<pre>&lt;p&gt; Test "
+               + "a &amp;amp; b &amp;lt; c"
+               + " End</pre>",
+               out.toString());
+    }
+
+    @Test
+    public void testOutputMO3() throws TemplateModelException, IOException {
+        MarkupOutputFormat outputFormat = new CombinedMarkupOutputFormat(
+                RTFOutputFormat.INSTANCE,
+                new CombinedMarkupOutputFormat(RTFOutputFormat.INSTANCE, RTFOutputFormat.INSTANCE));
+        StringWriter out = new StringWriter();
+        
+        outputFormat.output(outputFormat.fromPlainTextByEscaping("b{}"), out);
+        outputFormat.output(outputFormat.fromMarkup("a{}"), out);
+        
+        assertEquals(
+                "b\\\\\\\\\\\\\\{\\\\\\\\\\\\\\}"
+                + "a{}",
+                out.toString());
+    }
+    
+    @Test
+    public void testOutputString() throws TemplateModelException, IOException {
+        StringWriter out = new StringWriter();
+        
+        HTML_RTF.output("a", out);
+        HTML_RTF.output("{", out);
+        HTML_RTF.output("<b>}c", out);
+        
+        assertEquals("a\\{&lt;b&gt;\\}c", out.toString());
+    }
+    
+    @Test
+    public void testOutputString2() throws TemplateModelException, IOException {
+        StringWriter out = new StringWriter();
+        
+        XML_XML.output("a", out);
+        XML_XML.output("&", out);
+        XML_XML.output("<b>", out);
+        
+        assertEquals("a&amp;amp;&amp;lt;b&amp;gt;", out.toString());
+    }
+    
+    @Test
+    public void testFromPlainTextByEscaping() throws TemplateModelException {
+        String plainText = "a\\b&c";
+        TemplateCombinedMarkupOutputModel mo = HTML_RTF.fromPlainTextByEscaping(plainText);
+        assertSame(plainText, _OutputFormatTestAPI.getPlainTextContent(mo));
+        assertNull(_OutputFormatTestAPI.getMarkupContent(mo)); // Not the MO's duty to calculate it!
+    }
+
+    @Test
+    public void testFromMarkup() throws TemplateModelException {
+        String markup = "a \\par <b>";
+        TemplateCombinedMarkupOutputModel mo = HTML_RTF.fromMarkup(markup);
+        assertSame(markup, _OutputFormatTestAPI.getMarkupContent(mo));
+        assertNull(_OutputFormatTestAPI.getPlainTextContent(mo)); // Not the MO's duty to calculate it!
+    }
+    
+    @Test
+    public void testGetMarkup() throws TemplateModelException {
+        {
+            String markup = "a \\par <b>";
+            TemplateCombinedMarkupOutputModel mo = HTML_RTF.fromMarkup(markup);
+            assertSame(markup, HTML_RTF.getMarkupString(mo));
+        }
+        
+        {
+            String safe = "abc";
+            TemplateCombinedMarkupOutputModel mo = HTML_RTF.fromPlainTextByEscaping(safe);
+            assertSame(safe, HTML_RTF.getMarkupString(mo));
+        }
+    }
+    
+    @Test
+    public void testConcat() throws Exception {
+        assertMO(
+                "ab", null,
+                HTML_RTF.concat(
+                        new TemplateCombinedMarkupOutputModel("a", null, HTML_RTF),
+                        new TemplateCombinedMarkupOutputModel("b", null, HTML_RTF)));
+        assertMO(
+                null, "ab",
+                HTML_RTF.concat(
+                        new TemplateCombinedMarkupOutputModel(null, "a", HTML_RTF),
+                        new TemplateCombinedMarkupOutputModel(null, "b", HTML_RTF)));
+        assertMO(
+                null, "{<a>}\\{&lt;b&gt;\\}",
+                HTML_RTF.concat(
+                        new TemplateCombinedMarkupOutputModel(null, "{<a>}", HTML_RTF),
+                        new TemplateCombinedMarkupOutputModel("{<b>}", null, HTML_RTF)));
+        assertMO(
+                null, "\\{&lt;a&gt;\\}{<b>}",
+                HTML_RTF.concat(
+                        new TemplateCombinedMarkupOutputModel("{<a>}", null, HTML_RTF),
+                        new TemplateCombinedMarkupOutputModel(null, "{<b>}", HTML_RTF)));
+    }
+    
+    @Test
+    public void testEscaplePlainText() throws TemplateModelException {
+        assertEquals("", HTML_RTF.escapePlainText(""));
+        assertEquals("a", HTML_RTF.escapePlainText("a"));
+        assertEquals("\\{a\\\\b&amp;\\}", HTML_RTF.escapePlainText("{a\\b&}"));
+        assertEquals("a\\\\b&amp;", HTML_RTF.escapePlainText("a\\b&"));
+        assertEquals("\\{\\}&amp;", HTML_RTF.escapePlainText("{}&"));
+        
+        assertEquals("a", XML_XML.escapePlainText("a"));
+        assertEquals("a&amp;apos;b", XML_XML.escapePlainText("a'b"));
+    }
+    
+    private void assertMO(String pc, String mc, TemplateCombinedMarkupOutputModel mo) {
+        assertEquals(pc, _OutputFormatTestAPI.getPlainTextContent(mo));
+        assertEquals(mc, _OutputFormatTestAPI.getMarkupContent(mo));
+    }
+    
+    @Test
+    public void testGetMimeType() {
+        assertEquals("text/html", HTML_RTF.getMimeType());
+        assertEquals("application/xml", XML_XML.getMimeType());
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/outputformat/impl/HTMLOutputFormatTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/outputformat/impl/HTMLOutputFormatTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/outputformat/impl/HTMLOutputFormatTest.java
new file mode 100644
index 0000000..2199179
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/outputformat/impl/HTMLOutputFormatTest.java
@@ -0,0 +1,187 @@
+/*
+ * 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.outputformat.impl;
+
+import static org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat.*;
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.io.StringWriter;
+
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.outputformat.CommonMarkupOutputFormat;
+import org.apache.freemarker.core.outputformat._OutputFormatTestAPI;
+import org.junit.Test; 
+
+/**
+ * This actually more a {@link CommonMarkupOutputFormat} test.
+ */
+public class HTMLOutputFormatTest {
+    
+    @Test
+    public void testOutputMO() throws TemplateModelException, IOException {
+       StringWriter out = new StringWriter();
+       
+       INSTANCE.output(INSTANCE.fromMarkup("<p>Test "), out);
+       INSTANCE.output(INSTANCE.fromPlainTextByEscaping("foo & bar "), out);
+       INSTANCE.output(INSTANCE.fromPlainTextByEscaping("baaz "), out);
+       INSTANCE.output(INSTANCE.fromPlainTextByEscaping("<b>A</b> <b>B</b> <b>C</b>"), out);
+       INSTANCE.output(INSTANCE.fromPlainTextByEscaping(""), out);
+       INSTANCE.output(INSTANCE.fromPlainTextByEscaping("\"' x's \"y\" \""), out);
+       INSTANCE.output(INSTANCE.fromMarkup("</p>"), out);
+       
+       assertEquals(
+               "<p>Test "
+               + "foo &amp; bar "
+               + "baaz "
+               + "&lt;b&gt;A&lt;/b&gt; &lt;b&gt;B&lt;/b&gt; &lt;b&gt;C&lt;/b&gt;"
+               + "&quot;&#39; x&#39;s &quot;y&quot; &quot;"
+               + "</p>",
+               out.toString());
+    }
+    
+    @Test
+    public void testOutputString() throws TemplateModelException, IOException {
+        StringWriter out = new StringWriter();
+        
+        INSTANCE.output("a", out);
+        INSTANCE.output("<", out);
+        INSTANCE.output("b'c", out);
+        
+        assertEquals("a&lt;b&#39;c", out.toString());
+    }
+    
+    @Test
+    public void testFromPlainTextByEscaping() throws TemplateModelException {
+        String plainText = "a&b";
+        TemplateHTMLOutputModel mo = INSTANCE.fromPlainTextByEscaping(plainText);
+        assertSame(plainText, _OutputFormatTestAPI.getPlainTextContent(mo));
+        assertNull(_OutputFormatTestAPI.getMarkupContent(mo)); // Not the MO's duty to calculate it!
+    }
+
+    @Test
+    public void testFromMarkup() throws TemplateModelException {
+        String markup = "a&amp;b";
+        TemplateHTMLOutputModel mo = INSTANCE.fromMarkup(markup);
+        assertSame(markup, _OutputFormatTestAPI.getMarkupContent(mo));
+        assertNull(_OutputFormatTestAPI.getPlainTextContent(mo)); // Not the MO's duty to calculate it!
+    }
+    
+    @Test
+    public void testGetMarkup() throws TemplateModelException {
+        {
+            String markup = "a&amp;b";
+            TemplateHTMLOutputModel mo = INSTANCE.fromMarkup(markup);
+            assertSame(markup, INSTANCE.getMarkupString(mo));
+        }
+        
+        {
+            String safe = "abc";
+            TemplateHTMLOutputModel mo = INSTANCE.fromPlainTextByEscaping(safe);
+            assertSame(safe, INSTANCE.getMarkupString(mo));
+        }
+        {
+            String safe = "";
+            TemplateHTMLOutputModel mo = INSTANCE.fromPlainTextByEscaping(safe);
+            assertSame(safe, INSTANCE.getMarkupString(mo));
+        }
+        {
+            TemplateHTMLOutputModel mo = INSTANCE.fromPlainTextByEscaping("<abc");
+            assertEquals("&lt;abc", INSTANCE.getMarkupString(mo));
+        }
+        {
+            TemplateHTMLOutputModel mo = INSTANCE.fromPlainTextByEscaping("abc>");
+            assertEquals("abc&gt;", INSTANCE.getMarkupString(mo));
+        }
+        {
+            TemplateHTMLOutputModel mo = INSTANCE.fromPlainTextByEscaping("<abc>");
+            assertEquals("&lt;abc&gt;", INSTANCE.getMarkupString(mo));
+        }
+        {
+            TemplateHTMLOutputModel mo = INSTANCE.fromPlainTextByEscaping("a&bc");
+            assertEquals("a&amp;bc", INSTANCE.getMarkupString(mo));
+        }
+        {
+            TemplateHTMLOutputModel mo = INSTANCE.fromPlainTextByEscaping("a&b&c");
+            assertEquals("a&amp;b&amp;c", INSTANCE.getMarkupString(mo));
+        }
+        {
+            TemplateHTMLOutputModel mo = INSTANCE.fromPlainTextByEscaping("a<&>b&c");
+            assertEquals("a&lt;&amp;&gt;b&amp;c", INSTANCE.getMarkupString(mo));
+        }
+        {
+            TemplateHTMLOutputModel mo = INSTANCE.fromPlainTextByEscaping("\"<a<&>b&c>\"");
+            assertEquals("&quot;&lt;a&lt;&amp;&gt;b&amp;c&gt;&quot;", INSTANCE.getMarkupString(mo));
+        }
+        {
+            TemplateHTMLOutputModel mo = INSTANCE.fromPlainTextByEscaping("<");
+            assertEquals("&lt;", INSTANCE.getMarkupString(mo));
+        }
+        {
+            TemplateHTMLOutputModel mo = INSTANCE.fromPlainTextByEscaping("'");
+            String mc = INSTANCE.getMarkupString(mo);
+            assertEquals("&#39;", mc);
+            assertSame(mc, INSTANCE.getMarkupString(mo)); // cached
+        }
+    }
+    
+    @Test
+    public void testConcat() throws Exception {
+        assertMO(
+                "ab", null,
+                INSTANCE.concat(new TemplateHTMLOutputModel("a", null), new TemplateHTMLOutputModel("b", null)));
+        assertMO(
+                null, "ab",
+                INSTANCE.concat(new TemplateHTMLOutputModel(null, "a"), new TemplateHTMLOutputModel(null, "b")));
+        assertMO(
+                null, "<a>&lt;b&gt;",
+                INSTANCE.concat(new TemplateHTMLOutputModel(null, "<a>"), new TemplateHTMLOutputModel("<b>", null)));
+        assertMO(
+                null, "&lt;a&gt;<b>",
+                INSTANCE.concat(new TemplateHTMLOutputModel("<a>", null), new TemplateHTMLOutputModel(null, "<b>")));
+    }
+    
+    @Test
+    public void testEscaplePlainText() {
+        assertEquals("", INSTANCE.escapePlainText(""));
+        assertEquals("a", INSTANCE.escapePlainText("a"));
+        assertEquals("&lt;a&amp;b&#39;c&quot;d&gt;", INSTANCE.escapePlainText("<a&b'c\"d>"));
+        assertEquals("a&amp;b", INSTANCE.escapePlainText("a&b"));
+        assertEquals("&lt;&gt;", INSTANCE.escapePlainText("<>"));
+    }
+    
+    @Test
+    public void testIsEmpty() throws Exception {
+        assertTrue(INSTANCE.isEmpty(INSTANCE.fromMarkup("")));
+        assertTrue(INSTANCE.isEmpty(INSTANCE.fromPlainTextByEscaping("")));
+        assertFalse(INSTANCE.isEmpty(INSTANCE.fromMarkup(" ")));
+        assertFalse(INSTANCE.isEmpty(INSTANCE.fromPlainTextByEscaping(" ")));
+    }
+    
+    private void assertMO(String pc, String mc, TemplateHTMLOutputModel mo) {
+        assertEquals(pc, _OutputFormatTestAPI.getPlainTextContent(mo));
+        assertEquals(mc, _OutputFormatTestAPI.getMarkupContent(mo));
+    }
+    
+    @Test
+    public void testGetMimeType() {
+        assertEquals("text/html", INSTANCE.getMimeType());
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/outputformat/impl/RTFOutputFormatTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/outputformat/impl/RTFOutputFormatTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/outputformat/impl/RTFOutputFormatTest.java
new file mode 100644
index 0000000..13563f5
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/outputformat/impl/RTFOutputFormatTest.java
@@ -0,0 +1,129 @@
+/*
+ * 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.outputformat.impl;
+
+import static org.apache.freemarker.core.outputformat.impl.RTFOutputFormat.*;
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.io.StringWriter;
+
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.outputformat._OutputFormatTestAPI;
+import org.junit.Test; 
+
+public class RTFOutputFormatTest {
+    
+    @Test
+    public void testOutputMO() throws TemplateModelException, IOException {
+       StringWriter out = new StringWriter();
+       
+       INSTANCE.output(INSTANCE.fromMarkup("\\par Test "), out);
+       INSTANCE.output(INSTANCE.fromPlainTextByEscaping("foo { bar } \\ "), out);
+       INSTANCE.output(INSTANCE.fromPlainTextByEscaping("baaz "), out);
+       INSTANCE.output(INSTANCE.fromPlainTextByEscaping("\\par qweqwe"), out);
+       INSTANCE.output(INSTANCE.fromMarkup("\\par{0} End"), out);
+       
+       assertEquals(
+               "\\par Test "
+               + "foo \\{ bar \\} \\\\ "
+               + "baaz "
+               + "\\\\par qweqwe"
+               + "\\par{0} End",
+               out.toString());
+    }
+    
+    @Test
+    public void testOutputString() throws TemplateModelException, IOException {
+        StringWriter out = new StringWriter();
+        
+        INSTANCE.output("a", out);
+        INSTANCE.output("{", out);
+        INSTANCE.output("b}c", out);
+        
+        assertEquals("a\\{b\\}c", out.toString());
+    }
+    
+    @Test
+    public void testFromPlainTextByEscaping() throws TemplateModelException {
+        String plainText = "a\\b";
+        TemplateRTFOutputModel mo = INSTANCE.fromPlainTextByEscaping(plainText);
+        assertSame(plainText, _OutputFormatTestAPI.getPlainTextContent(mo));
+        assertNull(_OutputFormatTestAPI.getMarkupContent(mo)); // Not the MO's duty to calculate it!
+    }
+
+    @Test
+    public void testFromMarkup() throws TemplateModelException {
+        String markup = "a \\par b";
+        TemplateRTFOutputModel mo = INSTANCE.fromMarkup(markup);
+        assertSame(markup, _OutputFormatTestAPI.getMarkupContent(mo));
+        assertNull(_OutputFormatTestAPI.getPlainTextContent(mo)); // Not the MO's duty to calculate it!
+    }
+    
+    @Test
+    public void testGetMarkup() throws TemplateModelException {
+        {
+            String markup = "a \\par b";
+            TemplateRTFOutputModel mo = INSTANCE.fromMarkup(markup);
+            assertSame(markup, INSTANCE.getMarkupString(mo));
+        }
+        
+        {
+            String safe = "abc";
+            TemplateRTFOutputModel mo = INSTANCE.fromPlainTextByEscaping(safe);
+            assertSame(safe, INSTANCE.getMarkupString(mo));
+        }
+    }
+    
+    @Test
+    public void testConcat() throws Exception {
+        assertMO(
+                "ab", null,
+                INSTANCE.concat(new TemplateRTFOutputModel("a", null), new TemplateRTFOutputModel("b", null)));
+        assertMO(
+                null, "ab",
+                INSTANCE.concat(new TemplateRTFOutputModel(null, "a"), new TemplateRTFOutputModel(null, "b")));
+        assertMO(
+                null, "{a}\\{b\\}",
+                INSTANCE.concat(new TemplateRTFOutputModel(null, "{a}"), new TemplateRTFOutputModel("{b}", null)));
+        assertMO(
+                null, "\\{a\\}{b}",
+                INSTANCE.concat(new TemplateRTFOutputModel("{a}", null), new TemplateRTFOutputModel(null, "{b}")));
+    }
+    
+    @Test
+    public void testEscaplePlainText() {
+        assertEquals("", INSTANCE.escapePlainText(""));
+        assertEquals("a", INSTANCE.escapePlainText("a"));
+        assertEquals("\\{a\\\\b\\}", INSTANCE.escapePlainText("{a\\b}"));
+        assertEquals("a\\\\b", INSTANCE.escapePlainText("a\\b"));
+        assertEquals("\\{\\}", INSTANCE.escapePlainText("{}"));
+    }
+    
+    private void assertMO(String pc, String mc, TemplateRTFOutputModel mo) {
+        assertEquals(pc, _OutputFormatTestAPI.getPlainTextContent(mo));
+        assertEquals(mc, _OutputFormatTestAPI.getMarkupContent(mo));
+    }
+    
+    @Test
+    public void testGetMimeType() {
+        assertEquals("application/rtf", INSTANCE.getMimeType());
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/templateresolver/DefaultTemplateResolverTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/templateresolver/DefaultTemplateResolverTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/templateresolver/DefaultTemplateResolverTest.java
new file mode 100644
index 0000000..a7063fd
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/templateresolver/DefaultTemplateResolverTest.java
@@ -0,0 +1,365 @@
+/*
+ * 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.templateresolver;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.nio.charset.StandardCharsets;
+import java.util.Locale;
+
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.Template;
+import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateLookupStrategy;
+import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormat;
+import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateResolver;
+import org.apache.freemarker.core.templateresolver.impl.StringTemplateLoader;
+import org.apache.freemarker.core.templateresolver.impl.StrongCacheStorage;
+import org.apache.freemarker.test.MonitoredTemplateLoader;
+import org.apache.freemarker.test.MonitoredTemplateLoader.CloseSessionEvent;
+import org.apache.freemarker.test.MonitoredTemplateLoader.CreateSessionEvent;
+import org.apache.freemarker.test.MonitoredTemplateLoader.LoadEvent;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+import org.hamcrest.Matchers;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+
+public class DefaultTemplateResolverTest {
+
+    @Test
+    public void testCachedException() throws Exception {
+        MockTemplateLoader loader = new MockTemplateLoader();
+        DefaultTemplateResolver tr = new DefaultTemplateResolver(
+                loader,
+                new StrongCacheStorage(), 1000L,
+                DefaultTemplateLookupStrategy.INSTANCE, true,
+                DefaultTemplateNameFormat.INSTANCE,
+                null,
+                new TestConfigurationBuilder().build());
+        loader.setThrowException(true);
+        try {
+            tr.getTemplate("t", Locale.getDefault(), null).getTemplate();
+            fail();
+        } catch (IOException e) {
+            assertEquals("mock IO exception", e.getMessage());
+            assertEquals(1, loader.getLoadAttemptCount());
+            try {
+                tr.getTemplate("t", Locale.getDefault(), null).getTemplate();
+                fail();
+            } catch (IOException e2) {
+                // Still 1 - returned cached exception
+                assertThat(e2.getMessage(),
+                        Matchers.allOf(Matchers.containsString("There was an error loading the template on an " +
+                        "earlier attempt")));
+                assertSame(e, e2.getCause());
+                assertEquals(1, loader.getLoadAttemptCount());
+                try {
+                    Thread.sleep(1100L);
+                    tr.getTemplate("t", Locale.getDefault(), null).getTemplate();
+                    fail();
+                } catch (IOException e3) {
+                    // Cache had to retest
+                    assertEquals("mock IO exception", e.getMessage());
+                    assertEquals(2, loader.getLoadAttemptCount());
+                }
+            }
+        }
+    }
+    
+    @Test
+    public void testCachedNotFound() throws Exception {
+        MockTemplateLoader loader = new MockTemplateLoader();
+        DefaultTemplateResolver cache = new DefaultTemplateResolver(
+                loader,
+                new StrongCacheStorage(), 1000L,
+                DefaultTemplateLookupStrategy.INSTANCE, false,
+                DefaultTemplateNameFormat.INSTANCE,
+                null, new TestConfigurationBuilder().build());
+        assertNull(cache.getTemplate("t", Locale.getDefault(), null).getTemplate());
+        assertEquals(1, loader.getLoadAttemptCount());
+        assertNull(cache.getTemplate("t", Locale.getDefault(), null).getTemplate());
+        // Still 1 - returned cached exception
+        assertEquals(1, loader.getLoadAttemptCount());
+        Thread.sleep(1100L);
+        assertNull(cache.getTemplate("t", Locale.getDefault(), null).getTemplate());
+        // Cache had to retest
+        assertEquals(2, loader.getLoadAttemptCount());
+    }
+
+    private static class MockTemplateLoader implements TemplateLoader {
+        private boolean throwException;
+        private int loadAttemptCount; 
+        
+        public void setThrowException(boolean throwException) {
+           this.throwException = throwException;
+        }
+        
+        public int getLoadAttemptCount() {
+            return loadAttemptCount;
+        }
+        
+        @Override
+        public TemplateLoaderSession createSession() {
+            return null;
+        }
+
+        @Override
+        public TemplateLoadingResult load(String name, TemplateLoadingSource ifSourceDiffersFrom,
+                Serializable ifVersionDiffersFrom, TemplateLoaderSession session) throws IOException {
+            ++loadAttemptCount;
+            if (throwException) {
+                throw new IOException("mock IO exception");
+            }
+            return TemplateLoadingResult.NOT_FOUND;
+        }
+
+        @Override
+        public void resetState() {
+            //
+        }
+        
+    }
+    
+    @Test
+    public void testManualRemovalPlain() throws Exception {
+        StringTemplateLoader loader = new StringTemplateLoader();
+        Configuration cfg = new TestConfigurationBuilder()
+                .cacheStorage(new StrongCacheStorage())
+                .templateLoader(loader)
+                .templateUpdateDelayMilliseconds(Long.MAX_VALUE)
+                .build();
+
+        loader.putTemplate("1.ftl", "1 v1");
+        loader.putTemplate("2.ftl", "2 v1");
+        assertEquals("1 v1", cfg.getTemplate("1.ftl").toString()); 
+        assertEquals("2 v1", cfg.getTemplate("2.ftl").toString());
+        
+        loader.putTemplate("1.ftl", "1 v2");
+        loader.putTemplate("2.ftl", "2 v2");
+        assertEquals("1 v1", cfg.getTemplate("1.ftl").toString()); // no change 
+        assertEquals("2 v1", cfg.getTemplate("2.ftl").toString()); // no change
+        
+        cfg.removeTemplateFromCache("1.ftl", cfg.getLocale(), null);
+        assertEquals("1 v2", cfg.getTemplate("1.ftl").toString()); // changed 
+        assertEquals("2 v1", cfg.getTemplate("2.ftl").toString());
+        
+        cfg.removeTemplateFromCache("2.ftl", cfg.getLocale(), null);
+        assertEquals("1 v2", cfg.getTemplate("1.ftl").toString()); 
+        assertEquals("2 v2", cfg.getTemplate("2.ftl").toString()); // changed
+    }
+
+    @Test
+    public void testManualRemovalI18ed() throws Exception {
+        StringTemplateLoader loader = new StringTemplateLoader();
+        Configuration cfg = new TestConfigurationBuilder()
+                .cacheStorage(new StrongCacheStorage())
+                .templateLoader(loader)
+                .templateUpdateDelayMilliseconds(Long.MAX_VALUE)
+                .build();
+
+        loader.putTemplate("1_en_US.ftl", "1_en_US v1");
+        loader.putTemplate("1_en.ftl", "1_en v1");
+        loader.putTemplate("1.ftl", "1 v1");
+        
+        assertEquals("1_en_US v1", cfg.getTemplate("1.ftl").toString());        
+        assertEquals("1_en v1", cfg.getTemplate("1.ftl", Locale.UK).toString());        
+        assertEquals("1 v1", cfg.getTemplate("1.ftl", Locale.GERMANY).toString());
+        
+        loader.putTemplate("1_en_US.ftl", "1_en_US v2");
+        loader.putTemplate("1_en.ftl", "1_en v2");
+        loader.putTemplate("1.ftl", "1 v2");
+        assertEquals("1_en_US v1", cfg.getTemplate("1.ftl").toString());        
+        assertEquals("1_en v1", cfg.getTemplate("1.ftl", Locale.UK).toString());        
+        assertEquals("1 v1", cfg.getTemplate("1.ftl", Locale.GERMANY).toString());
+        
+        cfg.removeTemplateFromCache("1.ftl", cfg.getLocale(), null);
+        assertEquals("1_en_US v2", cfg.getTemplate("1.ftl").toString());        
+        assertEquals("1_en v1", cfg.getTemplate("1.ftl", Locale.UK).toString());        
+        assertEquals("1 v1", cfg.getTemplate("1.ftl", Locale.GERMANY).toString());
+        assertEquals("1 v2", cfg.getTemplate("1.ftl", Locale.ITALY).toString());
+        
+        cfg.removeTemplateFromCache("1.ftl", Locale.GERMANY, null);
+        assertEquals("1_en v1", cfg.getTemplate("1.ftl", Locale.UK).toString());        
+        assertEquals("1 v2", cfg.getTemplate("1.ftl", Locale.GERMANY).toString());
+
+        cfg.removeTemplateFromCache("1.ftl", Locale.CANADA, null);
+        assertEquals("1_en v1", cfg.getTemplate("1.ftl", Locale.UK).toString());
+        
+        cfg.removeTemplateFromCache("1.ftl", Locale.UK, null);
+        assertEquals("1_en v2", cfg.getTemplate("1.ftl", Locale.UK).toString());        
+    }
+
+    @Test
+    public void testZeroUpdateDelay() throws Exception {
+        MonitoredTemplateLoader loader = new MonitoredTemplateLoader();
+        TestConfigurationBuilder cfgB = new TestConfigurationBuilder()
+                .cacheStorage(new StrongCacheStorage())
+                .templateLoader(loader)
+                .templateUpdateDelayMilliseconds(0);
+
+        Configuration cfg = cfgB.build();
+
+        for (int i = 1; i <= 3; i++) {
+            loader.putTextTemplate("t.ftl", "v" + i);
+            assertEquals("v" + i, cfg.getTemplate("t.ftl").toString());
+        }
+
+        loader.clearEvents();
+        loader.putTextTemplate("t.ftl", "v8");
+        assertEquals("v8", cfg.getTemplate("t.ftl").toString());
+        assertEquals("v8", cfg.getTemplate("t.ftl").toString());
+        loader.putTextTemplate("t.ftl", "v9");
+        assertEquals("v9", cfg.getTemplate("t.ftl").toString());
+        assertEquals("v9", cfg.getTemplate("t.ftl").toString());
+        assertEquals(
+                ImmutableList.of(
+                        new LoadEvent("t_en_US.ftl", TemplateLoadingResultStatus.NOT_FOUND), // v8
+                        new LoadEvent("t_en.ftl", TemplateLoadingResultStatus.NOT_FOUND),
+                        new LoadEvent("t.ftl", TemplateLoadingResultStatus.OPENED),
+
+                        new LoadEvent("t_en_US.ftl", TemplateLoadingResultStatus.NOT_FOUND), // v8
+                        new LoadEvent("t_en.ftl", TemplateLoadingResultStatus.NOT_FOUND),
+                        new LoadEvent("t.ftl", TemplateLoadingResultStatus.NOT_MODIFIED),
+                        
+                        new LoadEvent("t_en_US.ftl", TemplateLoadingResultStatus.NOT_FOUND), // v9
+                        new LoadEvent("t_en.ftl", TemplateLoadingResultStatus.NOT_FOUND),
+                        new LoadEvent("t.ftl", TemplateLoadingResultStatus.OPENED),
+
+                        new LoadEvent("t_en_US.ftl", TemplateLoadingResultStatus.NOT_FOUND), // v9
+                        new LoadEvent("t_en.ftl", TemplateLoadingResultStatus.NOT_FOUND),
+                        new LoadEvent("t.ftl", TemplateLoadingResultStatus.NOT_MODIFIED)
+                ),
+                loader.getEvents(LoadEvent.class));
+        
+        cfg = cfgB.localizedLookup(false).build();
+        loader.clearEvents();
+        loader.putTextTemplate("t.ftl", "v10");
+        assertEquals("v10", cfg.getTemplate("t.ftl").toString());
+        loader.putTextTemplate("t.ftl", "v11"); // same time stamp, different content
+        assertEquals("v11", cfg.getTemplate("t.ftl").toString());
+        assertEquals("v11", cfg.getTemplate("t.ftl").toString());
+        assertEquals("v11", cfg.getTemplate("t.ftl").toString());
+        Thread.sleep(17L);
+        assertEquals("v11", cfg.getTemplate("t.ftl").toString());
+        loader.putTextTemplate("t.ftl", "v12");
+        assertEquals("v12", cfg.getTemplate("t.ftl").toString());
+        assertEquals("v12", cfg.getTemplate("t.ftl").toString());
+        assertEquals(
+                ImmutableList.of(
+                        new LoadEvent("t.ftl", TemplateLoadingResultStatus.OPENED), // v10
+                        new LoadEvent("t.ftl", TemplateLoadingResultStatus.OPENED), // v11
+                        new LoadEvent("t.ftl", TemplateLoadingResultStatus.NOT_MODIFIED),
+                        new LoadEvent("t.ftl", TemplateLoadingResultStatus.NOT_MODIFIED),
+                        new LoadEvent("t.ftl", TemplateLoadingResultStatus.NOT_MODIFIED),
+                        new LoadEvent("t.ftl", TemplateLoadingResultStatus.OPENED), // v12
+                        new LoadEvent("t.ftl", TemplateLoadingResultStatus.NOT_MODIFIED)
+                ),
+                loader.getEvents(LoadEvent.class));
+    }
+    
+    @Test
+    public void testWrongEncodingReload() throws Exception {
+        MonitoredTemplateLoader loader = new MonitoredTemplateLoader();
+        loader.putBinaryTemplate("utf-8_en.ftl", "<#ftl encoding='utf-8'>Béka");
+        loader.putBinaryTemplate("utf-8.ftl", "Bar");
+        loader.putBinaryTemplate("iso-8859-1_en_US.ftl", "<#ftl encoding='ISO-8859-1'>Béka",
+                StandardCharsets.ISO_8859_1, "v1");
+        Configuration cfg = new TestConfigurationBuilder().templateLoader(loader).build();
+
+        {
+            Template t = cfg.getTemplate("utf-8.ftl");
+            assertEquals("utf-8.ftl", t.getLookupName());
+            assertEquals("utf-8_en.ftl", t.getSourceName());
+            assertEquals(StandardCharsets.UTF_8, t.getActualSourceEncoding());
+            assertEquals("Béka", t.toString());
+            
+            assertEquals(
+                    ImmutableList.of(
+                            CreateSessionEvent.INSTANCE,
+                            new LoadEvent("utf-8_en_US.ftl", TemplateLoadingResultStatus.NOT_FOUND),
+                            new LoadEvent("utf-8_en.ftl", TemplateLoadingResultStatus.OPENED),
+                            CloseSessionEvent.INSTANCE),
+                    loader.getEvents());
+        }
+
+        {
+            loader.clearEvents();
+            
+            Template t = cfg.getTemplate("iso-8859-1.ftl");
+            assertEquals("iso-8859-1.ftl", t.getLookupName());
+            assertEquals("iso-8859-1_en_US.ftl", t.getSourceName());
+            assertEquals(StandardCharsets.ISO_8859_1, t.getActualSourceEncoding());
+            assertEquals("Béka", t.toString());
+            
+            assertEquals(
+                    ImmutableList.of(
+                            CreateSessionEvent.INSTANCE,
+                            new LoadEvent("iso-8859-1_en_US.ftl", TemplateLoadingResultStatus.OPENED),
+                            CloseSessionEvent.INSTANCE),
+                    loader.getEvents());
+        }
+    }
+
+    @Test
+    public void testNoWrongEncodingForTemplateLoader2WithReader() throws Exception {
+        MonitoredTemplateLoader loader = new MonitoredTemplateLoader();
+        loader.putTextTemplate("foo_en.ftl", "<#ftl encoding='utf-8'>ő");
+        loader.putTextTemplate("foo.ftl", "B");
+        Configuration cfg = new TestConfigurationBuilder().templateLoader(loader).build();
+        
+        {
+            Template t = cfg.getTemplate("foo.ftl");
+            assertEquals("foo.ftl", t.getLookupName());
+            assertEquals("foo_en.ftl", t.getSourceName());
+            assertNull(t.getActualSourceEncoding());
+            assertEquals("ő", t.toString());
+            
+            assertEquals(
+                    ImmutableList.of(
+                            CreateSessionEvent.INSTANCE,
+                            new LoadEvent("foo_en_US.ftl", TemplateLoadingResultStatus.NOT_FOUND),
+                            new LoadEvent("foo_en.ftl", TemplateLoadingResultStatus.OPENED),
+                            CloseSessionEvent.INSTANCE),                
+                    loader.getEvents());
+        }
+    }
+
+    @Test
+    public void testTemplateNameFormatException() throws Exception {
+        Configuration cfg = new TestConfigurationBuilder()
+                .templateNameFormat(DefaultTemplateNameFormat.INSTANCE)
+                .build();
+        try {
+            cfg.getTemplate("../x");
+            fail();
+        } catch (MalformedTemplateNameException e) {
+            // expected
+        }
+        try {
+            cfg.getTemplate("\\x");
+            fail();
+        } catch (MalformedTemplateNameException e) {
+            // expected
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/templateresolver/FileTemplateLoaderTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/templateresolver/FileTemplateLoaderTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/templateresolver/FileTemplateLoaderTest.java
new file mode 100644
index 0000000..393dbae
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/templateresolver/FileTemplateLoaderTest.java
@@ -0,0 +1,122 @@
+/*
+ * 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.templateresolver;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.SystemUtils;
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.TemplateNotFoundException;
+import org.apache.freemarker.core.templateresolver.impl.FileTemplateLoader;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.io.Files;
+
+public class FileTemplateLoaderTest {
+    
+    private File templateRootDir;
+    
+    private Configuration cfg;
+    
+    @Before
+    public void setup() throws IOException {
+        templateRootDir = Files.createTempDir();
+        File sub1Dir = new File(templateRootDir, "sub1");
+        File sub2Dir = new File(sub1Dir, "sub2");
+        if (!sub2Dir.mkdirs()) {
+            throw new IOException("Failed to invoke subdirectories");
+        }
+        File tFile = new File(sub2Dir, "t.ftl");
+        FileUtils.write(tFile, "foo");
+
+        cfg = new TestConfigurationBuilder().templateLoader(new FileTemplateLoader(templateRootDir)).build();
+    }
+    
+    @Test
+    public void testSuccessful() throws Exception {
+        for (int i = 0; i < 2; i++) {
+            assertEquals("foo", cfg.getTemplate("sub1/sub2/t.ftl").toString());
+        }
+    }
+
+    @Test
+    public void testSuccessful2() throws Exception {
+        ((FileTemplateLoader) cfg.getTemplateLoader()).setEmulateCaseSensitiveFileSystem(true);
+        for (int i = 0; i < 2; i++) {
+            cfg.clearTemplateCache();
+            assertEquals("foo", cfg.getTemplate("sub1/sub2/t.ftl").toString());
+        }
+    }
+    
+    
+    @Test
+    public void testNotFound() throws Exception {
+        for (int i = 0; i < 2; i++) {
+            try {
+                cfg.getTemplate("sub1X/sub2/t.ftl");
+                fail();
+            } catch (TemplateNotFoundException e) {
+                assertThat(e.getMessage(), containsString("sub1X"));
+                assertNull(e.getCause());
+            }
+        }
+    }
+
+    @Test
+    public void testCaseSensitivity() throws Exception {
+        for (boolean emuCaseSensFS : new boolean[] { false, true }) {
+            for (String nameWithBadCase : new String[] { "SUB1/sub2/t.ftl", "sub1/SUB2/t.ftl", "sub1/sub2/T.FTL" }) {
+                ((FileTemplateLoader) cfg.getTemplateLoader()).setEmulateCaseSensitiveFileSystem(emuCaseSensFS);
+                cfg.clearTemplateCache();
+                
+                if ((SystemUtils.IS_OS_WINDOWS || SystemUtils.IS_OS_MAC_OSX) && !emuCaseSensFS) {
+                    assertEquals("foo", cfg.getTemplate(nameWithBadCase).toString());
+                } else {
+                    assertEquals("foo", cfg.getTemplate(nameWithBadCase.toLowerCase()).toString());
+                    try {
+                        cfg.getTemplate(nameWithBadCase);
+                        fail();
+                    } catch (TemplateNotFoundException e) {
+                        assertThat(e.getMessage(), containsString(nameWithBadCase));
+                        assertNull(e.getCause());
+                    }
+                }
+            }
+        }
+    }
+    
+    @Test
+    public void testDefault() throws IOException {
+        assertFalse(new FileTemplateLoader(templateRootDir).getEmulateCaseSensitiveFileSystem());
+    }
+    
+    @After
+    public void tearDown() throws IOException {
+        FileUtils.deleteDirectory(templateRootDir);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/templateresolver/MultiTemplateLoaderTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/templateresolver/MultiTemplateLoaderTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/templateresolver/MultiTemplateLoaderTest.java
new file mode 100644
index 0000000..c8531c5
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/templateresolver/MultiTemplateLoaderTest.java
@@ -0,0 +1,99 @@
+/*
+ * 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.templateresolver;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.freemarker.core.templateresolver.impl.ByteArrayTemplateLoader;
+import org.apache.freemarker.core.templateresolver.impl.MultiTemplateLoader;
+import org.apache.freemarker.core.templateresolver.impl.StringTemplateLoader;
+import org.junit.Test;
+
+public class MultiTemplateLoaderTest {
+
+    @Test
+    public void testBasics() throws IOException {
+        StringTemplateLoader stl1 = new StringTemplateLoader();
+        stl1.putTemplate("1.ftl", "1");
+        stl1.putTemplate("both.ftl", "both 1");
+
+        StringTemplateLoader stl2 = new StringTemplateLoader();
+        stl2.putTemplate("2.ftl", "2");
+        stl2.putTemplate("both.ftl", "both 2");
+        
+        MultiTemplateLoader mtl = new MultiTemplateLoader(stl1, stl2);
+        assertEquals("1", getTemplateContent(mtl, "1.ftl"));
+        assertEquals("2", getTemplateContent(mtl, "2.ftl"));
+        assertEquals("both 1", getTemplateContent(mtl, "both.ftl"));
+        assertNull(getTemplateContent(mtl, "neither.ftl"));
+    }
+
+    @Test
+    public void testSticky() throws IOException {
+        testStickiness(true);
+    }
+
+    @Test
+    public void testNonSticky() throws IOException {
+        testStickiness(false);
+    }
+    
+    private void testStickiness(boolean sticky) throws IOException {
+        StringTemplateLoader stl1 = new StringTemplateLoader();
+        stl1.putTemplate("both.ftl", "both 1");
+        
+        ByteArrayTemplateLoader stl2 = new ByteArrayTemplateLoader();
+        stl2.putTemplate("both.ftl", "both 2".getBytes(StandardCharsets.UTF_8));
+
+        MultiTemplateLoader mtl = new MultiTemplateLoader(stl1, stl2);
+        mtl.setSticky(sticky);
+        
+        assertEquals("both 1", getTemplateContent(mtl, "both.ftl"));
+        assertTrue(stl1.removeTemplate("both.ftl"));
+        assertEquals("both 2", getTemplateContent(mtl, "both.ftl"));
+        stl1.putTemplate("both.ftl", "both 1");
+        assertEquals(sticky ? "both 2" : "both 1", getTemplateContent(mtl, "both.ftl"));
+        assertTrue(stl2.removeTemplate("both.ftl"));
+        assertEquals("both 1", getTemplateContent(mtl, "both.ftl"));
+    }
+    
+    private String getTemplateContent(TemplateLoader tl, String name) throws IOException {
+        TemplateLoaderSession ses = tl.createSession();
+        try {
+            TemplateLoadingResult res = tl.load(name, null, null, ses);
+            if (res.getStatus() == TemplateLoadingResultStatus.NOT_FOUND) {
+                return null;
+            }
+            return IOUtils.toString(
+                    res.getReader() != null
+                            ? res.getReader()
+                            : new InputStreamReader(res.getInputStream(), StandardCharsets.UTF_8));
+        } finally {
+            if (ses != null) {
+                ses.close();
+            }
+        }
+    }
+    
+}


[42/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateGetEncodingTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateGetEncodingTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateGetEncodingTest.java
new file mode 100644
index 0000000..4b5bf59
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateGetEncodingTest.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 static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+
+import org.apache.freemarker.core.templateresolver.ConditionalTemplateConfigurationFactory;
+import org.apache.freemarker.core.templateresolver.FileNameGlobMatcher;
+import org.apache.freemarker.core.templateresolver.impl.StrongCacheStorage;
+import org.apache.freemarker.test.MonitoredTemplateLoader;
+import org.junit.Test;
+
+public class TemplateGetEncodingTest {
+
+    private static final Charset ISO_8859_2 = Charset.forName("ISO-8859-2");
+
+    @Test
+    public void test() throws IOException {
+        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
+        {
+            cfgB.setSourceEncoding(ISO_8859_2);
+            MonitoredTemplateLoader tl = new MonitoredTemplateLoader();
+            tl.putBinaryTemplate("bin", "test");
+            tl.putBinaryTemplate("bin-static", "<#test>");
+            tl.putTextTemplate("text", "test");
+            tl.putTextTemplate("text-static", "<#test>");
+            TemplateConfiguration.Builder staticTextTCB = new TemplateConfiguration.Builder();
+            staticTextTCB.setTemplateLanguage(TemplateLanguage.STATIC_TEXT);
+            cfgB.setTemplateConfigurations(
+                    new ConditionalTemplateConfigurationFactory(
+                            new FileNameGlobMatcher("*-static*"), staticTextTCB.build()));
+            cfgB.setTemplateLoader(tl);
+            cfgB.setCacheStorage(new StrongCacheStorage());
+        }
+
+        Configuration cfg = cfgB.build();
+        assertEquals(ISO_8859_2, cfg.getTemplate("bin").getActualSourceEncoding());
+        assertEquals(ISO_8859_2, cfg.getTemplate("bin-static").getActualSourceEncoding());
+        assertNull(cfg.getTemplate("text").getActualSourceEncoding());
+        assertNull(cfg.getTemplate("text-static").getActualSourceEncoding());
+        assertNull(new Template(null, "test", cfg).getActualSourceEncoding());
+        assertNull(Template.createPlainTextTemplate(null, "<#test>", cfg).getActualSourceEncoding());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateLookupStrategyTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateLookupStrategyTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateLookupStrategyTest.java
new file mode 100644
index 0000000..f0e63a8
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateLookupStrategyTest.java
@@ -0,0 +1,669 @@
+/*
+ * 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.apache.freemarker.core.Configuration.ExtendableBuilder.TEMPLATE_LOOKUP_STRATEGY_KEY;
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.io.StringWriter;
+import java.util.Locale;
+
+import org.apache.freemarker.core.templateresolver.TemplateLookupContext;
+import org.apache.freemarker.core.templateresolver.TemplateLookupResult;
+import org.apache.freemarker.core.templateresolver.TemplateLookupStrategy;
+import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateLookupStrategy;
+import org.apache.freemarker.test.MonitoredTemplateLoader;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+
+public class TemplateLookupStrategyTest {
+
+    @Test
+    public void testSetSetting() throws Exception {
+        assertSame(
+                DefaultTemplateLookupStrategy.INSTANCE,
+                new Configuration.Builder(Configuration.VERSION_3_0_0).build()
+                        .getTemplateLookupStrategy());
+
+        assertTrue(
+                new Configuration.Builder(Configuration.VERSION_3_0_0)
+                        .setting(TEMPLATE_LOOKUP_STRATEGY_KEY, MyTemplateLookupStrategy.class.getName() + "()")
+                        .build()
+                        .getTemplateLookupStrategy() instanceof MyTemplateLookupStrategy);
+        
+        assertSame(
+                DefaultTemplateLookupStrategy.INSTANCE,
+                new Configuration.Builder(Configuration.VERSION_3_0_0)
+                        .setting(TEMPLATE_LOOKUP_STRATEGY_KEY, "dEfault")
+                        .build()
+                        .getTemplateLookupStrategy());
+    }
+    
+    @Test
+    public void testCustomStrategy() throws IOException {
+        MonitoredTemplateLoader tl = new MonitoredTemplateLoader();
+        tl.putTextTemplate("test.ftl", "");
+        tl.putTextTemplate("aa/test.ftl", "");
+
+        Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0)
+                .templateLoader(tl)
+                .templateLookupStrategy(MyTemplateLookupStrategy.INSTANCE)
+                .build();
+        
+        final Locale locale = new Locale("aa", "BB", "CC_DD");
+        
+        try {
+            cfg.getTemplate("missing.ftl", locale);
+            fail();
+        } catch (TemplateNotFoundException e) {
+            assertEquals("missing.ftl", e.getTemplateName());
+            assertEquals(ImmutableList.of("aa/missing.ftl", "missing.ftl"), tl.getLoadNames());
+            tl.clearEvents();
+            cfg.clearTemplateCache();
+        }
+        
+        {
+            final Template t = cfg.getTemplate("test.ftl", locale);
+            assertEquals("test.ftl", t.getLookupName());
+            assertEquals("aa/test.ftl", t.getSourceName());
+            assertEquals(locale, t.getLocale());
+            assertNull(t.getCustomLookupCondition());
+            assertEquals(ImmutableList.of("aa/test.ftl"), tl.getLoadNames());
+            tl.clearEvents();
+            cfg.clearTemplateCache();
+        }
+    }
+    
+    @Test
+    public void testDefaultStrategy() throws IOException {
+        MonitoredTemplateLoader tl = new MonitoredTemplateLoader();
+        tl.putTextTemplate("test.ftl", "");
+        tl.putTextTemplate("test_aa.ftl", "");
+        tl.putTextTemplate("test_aa_BB.ftl", "");
+        tl.putTextTemplate("test_aa_BB_CC.ftl", "");
+        tl.putTextTemplate("test_aa_BB_CC_DD.ftl", "");
+
+        try {
+            new Configuration.Builder(Configuration.VERSION_3_0_0).templateLoader(tl).build()
+                    .getTemplate("missing.ftl", new Locale("aa", "BB", "CC_DD"));
+            fail();
+        } catch (TemplateNotFoundException e) {
+            assertEquals("missing.ftl", e.getTemplateName());
+            assertEquals(
+                    ImmutableList.of(
+                            "missing_aa_BB_CC_DD.ftl",
+                            "missing_aa_BB_CC.ftl",
+                            "missing_aa_BB.ftl",
+                            "missing_aa.ftl",
+                            "missing.ftl"),
+                    tl.getLoadNames());
+            tl.clearEvents();
+        }
+
+        try {
+            new Configuration.Builder(Configuration.VERSION_3_0_0).templateLoader(tl)
+                    .locale(new Locale("xx")).build()
+                    .getTemplate("missing.ftl");
+            fail();
+        } catch (TemplateNotFoundException e) {
+            assertEquals("missing.ftl", e.getTemplateName());
+            assertEquals(
+                    ImmutableList.of("missing_xx.ftl", "missing.ftl"),
+                    tl.getLoadNames());
+            tl.clearEvents();
+        }
+        
+        try {
+            new Configuration.Builder(Configuration.VERSION_3_0_0).templateLoader(tl)
+                    .locale(new Locale("xx"))
+                    .localizedLookup(false).build()
+                    .getTemplate("missing.ftl");
+            fail();
+        } catch (TemplateNotFoundException e) {
+            assertEquals("missing.ftl", e.getTemplateName());
+            assertEquals(
+                    ImmutableList.of("missing.ftl"),
+                    tl.getLoadNames());
+            tl.clearEvents();
+        }
+
+        try {
+            new Configuration.Builder(Configuration.VERSION_3_0_0).templateLoader(tl).build()
+                    .getTemplate("_a_b_.ftl", new Locale("xx", "yy"));
+            fail();
+        } catch (TemplateNotFoundException e) {
+            assertEquals("_a_b_.ftl", e.getTemplateName());
+            assertEquals(
+                    ImmutableList.of("_a_b__xx_YY.ftl", "_a_b__xx.ftl", "_a_b_.ftl"),
+                    tl.getLoadNames());
+            tl.clearEvents();
+        }
+
+        for (String templateName : new String[] { "test.ftl", "./test.ftl", "/test.ftl", "x/foo/../../test.ftl" }) {
+            {
+                final Locale locale = new Locale("aa", "BB", "CC_DD");
+                final Template t = new Configuration.Builder(Configuration.VERSION_3_0_0).templateLoader(tl).build()
+                        .getTemplate("test.ftl", locale);
+                assertEquals("test.ftl", t.getLookupName());
+                assertEquals("test_aa_BB_CC_DD.ftl", t.getSourceName());
+                assertEquals(locale, t.getLocale());
+                assertNull(t.getCustomLookupCondition());
+                assertEquals(ImmutableList.of("test_aa_BB_CC_DD.ftl"), tl.getLoadNames());
+                assertNull(t.getCustomLookupCondition());
+                tl.clearEvents();
+            }
+            
+            {
+                final Locale locale = new Locale("aa", "BB", "CC_XX");
+                final Template t = new Configuration.Builder(Configuration.VERSION_3_0_0).templateLoader(tl).build()
+                        .getTemplate(templateName, locale);
+                assertEquals("test.ftl", t.getLookupName());
+                assertEquals("test_aa_BB_CC.ftl", t.getSourceName());
+                assertEquals(locale, t.getLocale());
+                assertNull(t.getCustomLookupCondition());
+                assertEquals(ImmutableList.of("test_aa_BB_CC_XX.ftl", "test_aa_BB_CC.ftl"), tl.getLoadNames());
+                tl.clearEvents();
+            }
+            
+            {
+                final Locale locale = new Locale("aa", "BB", "XX_XX");
+                final Template t = new Configuration.Builder(Configuration.VERSION_3_0_0).templateLoader(tl).build()
+                        .getTemplate(templateName, locale);
+                assertEquals("test.ftl", t.getLookupName());
+                assertEquals("test_aa_BB.ftl", t.getSourceName());
+                assertEquals(locale, t.getLocale());
+                assertNull(t.getCustomLookupCondition());
+                assertEquals(
+                        ImmutableList.of("test_aa_BB_XX_XX.ftl", "test_aa_BB_XX.ftl", "test_aa_BB.ftl"),
+                        tl.getLoadNames());
+                tl.clearEvents();
+            }
+    
+            {
+                final Locale locale = new Locale("aa", "BB", "XX_XX");
+                final Template t = new Configuration.Builder(Configuration.VERSION_3_0_0).templateLoader(tl)
+                        .localizedLookup(false).build()
+                        .getTemplate(templateName, locale);
+                assertEquals("test.ftl", t.getLookupName());
+                assertEquals("test.ftl", t.getSourceName());
+                assertEquals(locale, t.getLocale());
+                assertNull(t.getCustomLookupCondition());
+                assertEquals(
+                        ImmutableList.of("test.ftl"),
+                        tl.getLoadNames());
+                tl.clearEvents();
+            }
+    
+            {
+                final Locale locale = new Locale("aa", "XX", "XX_XX");
+                final Template t = new Configuration.Builder(Configuration.VERSION_3_0_0).templateLoader(tl).build()
+                        .getTemplate(templateName, locale);
+                assertEquals("test.ftl", t.getLookupName());
+                assertEquals("test_aa.ftl", t.getSourceName());
+                assertEquals(locale, t.getLocale());
+                assertNull(t.getCustomLookupCondition());
+                assertEquals(
+                        ImmutableList.of("test_aa_XX_XX_XX.ftl", "test_aa_XX_XX.ftl", "test_aa_XX.ftl", "test_aa.ftl"),
+                        tl.getLoadNames());
+                tl.clearEvents();
+            }
+            
+            {
+                final Locale locale = new Locale("xx", "XX", "XX_XX");
+                final Template t = new Configuration.Builder(Configuration.VERSION_3_0_0).templateLoader(tl).build()
+                        .getTemplate(templateName, locale);
+                assertEquals("test.ftl", t.getLookupName());
+                assertEquals("test.ftl", t.getSourceName());
+                assertEquals(locale, t.getLocale());
+                assertNull(t.getCustomLookupCondition());
+                assertEquals(
+                        ImmutableList.of(
+                                "test_xx_XX_XX_XX.ftl", "test_xx_XX_XX.ftl", "test_xx_XX.ftl", "test_xx.ftl", "test.ftl"),
+                        tl.getLoadNames());
+                tl.clearEvents();
+            }
+            
+            {
+                final Locale locale = new Locale("xx", "BB", "CC_DD");
+                final Template t = new Configuration.Builder(Configuration.VERSION_3_0_0).templateLoader(tl).build()
+                        .getTemplate(templateName, locale);
+                assertEquals("test.ftl", t.getLookupName());
+                assertEquals("test.ftl", t.getSourceName());
+                assertEquals(locale, t.getLocale());
+                assertNull(t.getCustomLookupCondition());
+                assertEquals(
+                        ImmutableList.of(
+                            "test_xx_BB_CC_DD.ftl", "test_xx_BB_CC.ftl", "test_xx_BB.ftl", "test_xx.ftl", "test.ftl"),
+                        tl.getLoadNames());
+                tl.clearEvents();
+            }
+        }
+    }
+    
+    @Test
+    public void testAcquisition() throws IOException {
+        MonitoredTemplateLoader tl = new MonitoredTemplateLoader();
+        tl.putTextTemplate("t.ftl", "");
+        tl.putTextTemplate("sub/i.ftl", "");
+        tl.putTextTemplate("x/sub/i.ftl", "");
+
+        Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0).templateLoader(tl).build();
+
+        final Locale locale = new Locale("xx");
+        
+        {
+            final Template t = cfg.getTemplate("/./moo/../x/y/*/sub/i.ftl", locale);
+            assertEquals("x/y/*/sub/i.ftl", t.getLookupName());
+            assertEquals("x/sub/i.ftl", t.getSourceName());
+            assertEquals(locale, t.getLocale());
+            assertNull(t.getCustomLookupCondition());
+            assertEquals(
+                    ImmutableList.of(
+                        "x/y/sub/i_xx.ftl", "x/sub/i_xx.ftl", "sub/i_xx.ftl",
+                        "x/y/sub/i.ftl", "x/sub/i.ftl"),
+                    tl.getLoadNames());
+            tl.clearEvents();
+            cfg.clearTemplateCache();
+        }
+
+        {
+            final Template t = cfg.getTemplate("a/b/*/./sub/i.ftl", locale);
+            assertEquals("a/b/*/sub/i.ftl", t.getLookupName());
+            assertEquals("sub/i.ftl", t.getSourceName());
+            assertEquals(locale, t.getLocale());
+            assertNull(t.getCustomLookupCondition());
+            assertEquals(
+                    ImmutableList.of(
+                        "a/b/sub/i_xx.ftl", "a/sub/i_xx.ftl", "sub/i_xx.ftl",
+                        "a/b/sub/i.ftl", "a/sub/i.ftl", "sub/i.ftl"),
+                    tl.getLoadNames());
+            tl.clearEvents();
+            cfg.clearTemplateCache();
+        }
+    }
+
+    @Test
+    public void testCustomLookupCondition() throws IOException, TemplateException {
+        MonitoredTemplateLoader tl = new MonitoredTemplateLoader();
+
+        final Configuration cfg;
+        final Configuration cfgNoLocLU;
+        {
+            Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0)
+                    .templateLoader(tl)
+                    .templateLookupStrategy(new DomainTemplateLookupStrategy());
+            cfg = cfgB.build();
+            cfgNoLocLU = cfgB.localizedLookup(false).build();
+        }
+
+        final String iAtDefaultContent = "i at default";
+        final String iXxAtDefaultContent = "i_xx at default";
+        final String iAtBaazComContent = "i at baaz.com";
+        final String iAtFooComContent = "i at foo.com";
+        final String tAtDefaultWithoutIncludeContent = "t at default ";
+        final String tAtDefaultContent = toCanonicalFTL(tAtDefaultWithoutIncludeContent + "<#include 'i.ftl'>", cfg);
+        final String tAtBarComWithoutIncludeContent = "t at bar.com ";
+        final String tAtBarComContent = toCanonicalFTL(tAtBarComWithoutIncludeContent + "<#include 'i.ftl'>", cfg);
+        final String tAtFooComWithoutIncludeContent = "t at foo.com ";
+        final String tAtFooComContent = toCanonicalFTL(tAtFooComWithoutIncludeContent + "<#include 'i.ftl'>", cfg);
+        final String t2XxLocaleExpectedOutput = "i3_xx at foo.com";
+        final String t2OtherLocaleExpectedOutput = "i3 at foo.com";
+        
+        tl.putTextTemplate("@foo.com/t.ftl", tAtFooComContent);
+        tl.putTextTemplate("@bar.com/t.ftl", tAtBarComContent);
+        tl.putTextTemplate("@default/t.ftl", tAtDefaultContent);
+        tl.putTextTemplate("@foo.com/i.ftl", iAtFooComContent);
+        tl.putTextTemplate("@baaz.com/i.ftl", iAtBaazComContent);
+        tl.putTextTemplate("@default/i_xx.ftl", iXxAtDefaultContent);
+        tl.putTextTemplate("@default/i.ftl", iAtDefaultContent);
+        tl.putTextTemplate("@foo.com/t2.ftl", "<#import 'i2.ftl' as i2 />${proof}");
+        tl.putTextTemplate("@default/i2.ftl", "<#import 'i3.ftl' as i3 />");
+        tl.putTextTemplate("@foo.com/i3.ftl", "<#global proof = '" + t2OtherLocaleExpectedOutput + "'>");
+        tl.putTextTemplate("@foo.com/i3_xx.ftl", "<#global proof = '" + t2XxLocaleExpectedOutput + "'>");
+
+        {
+            final Locale locale = new Locale("xx");
+            final Domain domain = new Domain("foo.com");
+            final Template t = cfg.getTemplate("t.ftl", locale, domain);
+            assertEquals("t.ftl", t.getLookupName());
+            assertEquals("@foo.com/t.ftl", t.getSourceName());
+            assertEquals(locale, t.getLocale());
+            assertEquals(domain, t.getCustomLookupCondition());
+            assertEquals(tAtFooComContent, t.toString());
+            assertEquals(
+                    ImmutableList.of("@foo.com/t_xx.ftl", "@foo.com/t.ftl"),
+                    tl.getLoadNames());
+            
+            tl.clearEvents();
+            assertOutputEquals(tAtFooComWithoutIncludeContent + iAtFooComContent, t);
+            assertEquals(
+                    ImmutableList.of("@foo.com/i_xx.ftl", "@foo.com/i.ftl"),
+                    tl.getLoadNames());
+            
+            tl.clearEvents();
+            cfg.clearTemplateCache();
+        }
+
+        {
+            final Locale locale = new Locale("xx");
+            final Domain domain = new Domain("bar.com");
+            final Template t = cfg.getTemplate("t.ftl", locale, domain);
+            assertEquals("t.ftl", t.getLookupName());
+            assertEquals("@bar.com/t.ftl", t.getSourceName());
+            assertEquals(locale, t.getLocale());
+            assertEquals(domain, t.getCustomLookupCondition());
+            assertEquals(tAtBarComContent, t.toString());
+            assertEquals(
+                    ImmutableList.of("@bar.com/t_xx.ftl", "@bar.com/t.ftl"),
+                    tl.getLoadNames());
+            
+            tl.clearEvents();
+            assertOutputEquals(tAtBarComWithoutIncludeContent + iXxAtDefaultContent, t);
+            assertEquals(
+                    ImmutableList.of(
+                            "@bar.com/i_xx.ftl", "@bar.com/i.ftl",
+                            "@default/i_xx.ftl"),
+                    tl.getLoadNames());
+            
+            tl.clearEvents();
+            cfg.clearTemplateCache();
+        }
+        
+        {
+            final Locale locale = new Locale("xx", "YY");
+            final Domain domain = new Domain("baaz.com");
+            final Template t = cfg.getTemplate("t.ftl", locale, domain);
+            assertEquals("t.ftl", t.getLookupName());
+            assertEquals("@default/t.ftl", t.getSourceName());
+            assertEquals(locale, t.getLocale());
+            assertEquals(domain, t.getCustomLookupCondition());
+            assertEquals(tAtDefaultContent, t.toString());
+            assertEquals(
+                    ImmutableList.of(
+                            "@baaz.com/t_xx_YY.ftl", "@baaz.com/t_xx.ftl", "@baaz.com/t.ftl",
+                            "@default/t_xx_YY.ftl", "@default/t_xx.ftl", "@default/t.ftl"),
+                    tl.getLoadNames());
+            
+            tl.clearEvents();
+            assertOutputEquals(tAtDefaultWithoutIncludeContent + iAtBaazComContent, t);
+            assertEquals(
+                    ImmutableList.of("@baaz.com/i_xx_YY.ftl", "@baaz.com/i_xx.ftl", "@baaz.com/i.ftl"),
+                    tl.getLoadNames());
+            
+            tl.clearEvents();
+            cfg.clearTemplateCache();
+        }
+        
+        {
+            final Locale locale = new Locale("xx", "YY");
+            final Domain domain = new Domain("nosuch.com");
+            final Template t = cfg.getTemplate("i.ftl", locale, domain);
+            assertEquals("i.ftl", t.getLookupName());
+            assertEquals("@default/i_xx.ftl", t.getSourceName());
+            assertEquals(locale, t.getLocale());
+            assertEquals(domain, t.getCustomLookupCondition());
+            assertEquals(iXxAtDefaultContent, t.toString());
+            assertEquals(
+                    ImmutableList.of(
+                            "@nosuch.com/i_xx_YY.ftl", "@nosuch.com/i_xx.ftl", "@nosuch.com/i.ftl",
+                            "@default/i_xx_YY.ftl", "@default/i_xx.ftl"),
+                    tl.getLoadNames());
+            
+            tl.clearEvents();
+            cfg.clearTemplateCache();
+        }
+
+        {
+            final Locale locale = new Locale("xx", "YY");
+            final Domain domain = new Domain("nosuch.com");
+            final Template t = cfgNoLocLU.getTemplate("i.ftl", locale, domain);
+            assertEquals("i.ftl", t.getLookupName());
+            assertEquals("@default/i.ftl", t.getSourceName());
+            assertEquals(locale, t.getLocale());
+            assertEquals(domain, t.getCustomLookupCondition());
+            assertEquals(iAtDefaultContent, t.toString());
+            assertEquals(
+                    ImmutableList.of("@nosuch.com/i.ftl", "@default/i.ftl"),
+                    tl.getLoadNames());
+            
+            tl.clearEvents();
+            cfgNoLocLU.clearTemplateCache();
+        }
+        
+        {
+            final Locale locale = new Locale("xx");
+            final Domain domain = new Domain("foo.com");
+            final Template t = cfg.getTemplate("t2.ftl", locale, domain);
+            assertOutputEquals(t2XxLocaleExpectedOutput, t);
+            assertEquals(
+                    ImmutableList.of(
+                            "@foo.com/t2_xx.ftl", "@foo.com/t2.ftl",
+                            "@foo.com/i2_xx.ftl", "@foo.com/i2.ftl", "@default/i2_xx.ftl", "@default/i2.ftl",
+                            "@foo.com/i3_xx.ftl"),
+                    tl.getLoadNames());
+            
+            tl.clearEvents();
+            cfg.clearTemplateCache();
+        }
+        
+        {
+            final Locale locale = new Locale("yy");
+            final Domain domain = new Domain("foo.com");
+            final Template t = cfg.getTemplate("t2.ftl", locale, domain);
+            assertOutputEquals(t2OtherLocaleExpectedOutput, t);
+            assertEquals(
+                    ImmutableList.of(
+                            "@foo.com/t2_yy.ftl", "@foo.com/t2.ftl",
+                            "@foo.com/i2_yy.ftl", "@foo.com/i2.ftl", "@default/i2_yy.ftl", "@default/i2.ftl",
+                            "@foo.com/i3_yy.ftl", "@foo.com/i3.ftl"),
+                    tl.getLoadNames());
+            
+            tl.clearEvents();
+            cfg.clearTemplateCache();
+        }
+        
+        {
+            final Locale locale = new Locale("xx");
+            final Domain domain = new Domain("foo.com");
+            final Template t = cfgNoLocLU.getTemplate("t2.ftl", locale, domain);
+            assertOutputEquals(t2OtherLocaleExpectedOutput, t);
+            assertEquals(
+                    ImmutableList.of(
+                            "@foo.com/t2.ftl",
+                            "@foo.com/i2.ftl", "@default/i2.ftl",
+                            "@foo.com/i3.ftl"),
+                    tl.getLoadNames());
+            
+            tl.clearEvents();
+            cfgNoLocLU.clearTemplateCache();
+        }
+        
+        {
+            final Locale locale = new Locale("xx");
+            final Domain domain = new Domain("foo.com");
+            cfg.getTemplate("i3.ftl", locale, domain);
+            assertEquals(
+                    ImmutableList.of("@foo.com/i3_xx.ftl"),
+                    tl.getLoadNames());
+            
+            tl.clearEvents();
+            cfg.clearTemplateCache();
+        }
+        
+        {
+            final Locale locale = new Locale("xx");
+            final Domain domain = new Domain("bar.com");
+            try {
+                cfg.getTemplate("i3.ftl", locale, domain);
+            } catch (TemplateNotFoundException e) {
+                assertEquals("i3.ftl", e.getTemplateName());
+                assertEquals(domain, e.getCustomLookupCondition());
+            }
+            assertEquals(
+                    ImmutableList.of(
+                            "@bar.com/i3_xx.ftl", "@bar.com/i3.ftl",
+                            "@default/i3_xx.ftl", "@default/i3.ftl"),
+                    tl.getLoadNames());
+            
+            tl.clearEvents();
+            cfg.clearTemplateCache();
+        }
+        
+    }
+
+    public static class Domain implements Serializable {
+        private final String name;
+
+        public Domain(String name) {
+            this.name = name;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            Domain domain = (Domain) o;
+
+            return name != null ? name.equals(domain.name) : domain.name == null;
+        }
+
+        @Override
+        public int hashCode() {
+            return name != null ? name.hashCode() : 0;
+        }
+    }
+    
+    @Test
+    public void testNonparsed() throws IOException {
+        MonitoredTemplateLoader tl = new MonitoredTemplateLoader();
+        tl.putTextTemplate("test.txt", "");
+        tl.putTextTemplate("test_aa.txt", "");
+
+        Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0).templateLoader(tl).build();
+
+        try {
+            cfg.getTemplate("missing.txt", new Locale("aa", "BB"), null, false);
+            fail();
+        } catch (TemplateNotFoundException e) {
+            assertEquals("missing.txt", e.getTemplateName());
+            assertEquals(
+                    ImmutableList.of(
+                            "missing_aa_BB.txt",
+                            "missing_aa.txt",
+                            "missing.txt"),
+                    tl.getLoadNames());
+            tl.clearEvents();
+            cfg.clearTemplateCache();
+        }
+        
+        {
+            Template t = cfg.getTemplate("test.txt", new Locale("aa", "BB"), null, false);
+            assertEquals("test.txt", t.getLookupName());
+            assertEquals("test_aa.txt", t.getSourceName());
+            assertEquals(
+                    ImmutableList.of(
+                            "test_aa_BB.txt",
+                            "test_aa.txt"),
+                    tl.getLoadNames());
+        }
+    }
+
+    @Test
+    public void testParseError() throws IOException {
+        MonitoredTemplateLoader tl = new MonitoredTemplateLoader();
+        tl.putTextTemplate("test.ftl", "");
+        tl.putTextTemplate("test_aa.ftl", "<#wrong>");
+
+        Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0).templateLoader(tl).build();
+        
+        try {
+            cfg.getTemplate("test.ftl", new Locale("aa", "BB"));
+            fail();
+        } catch (ParseException e) {
+            assertEquals("test_aa.ftl", e.getTemplateSourceName());
+            assertEquals("test.ftl", e.getTemplateLookupName());
+        }
+    }
+    
+    private String toCanonicalFTL(String ftl, Configuration cfg) throws IOException {
+        return new Template(null, ftl, cfg).toString();        
+    }
+
+    private void assertOutputEquals(final String expectedContent, final Template t) throws TemplateException,
+            IOException {
+        StringWriter sw = new StringWriter(); 
+        t.process(null, sw);
+        assertEquals(expectedContent, sw.toString());
+    }
+    
+    public static class MyTemplateLookupStrategy extends TemplateLookupStrategy {
+        
+        public static final MyTemplateLookupStrategy INSTANCE = new MyTemplateLookupStrategy();
+        
+        private MyTemplateLookupStrategy() { }
+
+        @Override
+        public <R extends TemplateLookupResult> R lookup(TemplateLookupContext<R> ctx) throws IOException {
+            String lang = ctx.getTemplateLocale().getLanguage().toLowerCase();
+            R lookupResult = ctx.lookupWithAcquisitionStrategy(lang + "/" + ctx.getTemplateName());
+            if (lookupResult.isPositive()) {
+                return lookupResult;
+            }
+            
+            return ctx.lookupWithAcquisitionStrategy(ctx.getTemplateName());
+        }
+        
+    }
+    
+    public static class DomainTemplateLookupStrategy extends TemplateLookupStrategy {
+        
+        public static final DomainTemplateLookupStrategy INSTANCE = new DomainTemplateLookupStrategy();
+
+        @Override
+        public <R extends TemplateLookupResult> R lookup(TemplateLookupContext<R> ctx) throws IOException {
+            Domain domain = (Domain) ctx.getCustomLookupCondition();
+            if (domain == null) {
+                throw new NullPointerException("The domain wasn't specified");
+            }
+            
+            final String templateName = ctx.getTemplateName();
+            
+            // Disallow addressing the domain roots directly:
+            if (templateName.startsWith("@")) {
+                return ctx.createNegativeLookupResult();
+            }
+            
+            R lookupResult = ctx.lookupWithLocalizedThenAcquisitionStrategy(
+                    "@" + domain.name + "/" + templateName,
+                    ctx.getTemplateLocale());
+            if (lookupResult.isPositive()) {
+                return lookupResult;
+            }
+            
+            return ctx.lookupWithLocalizedThenAcquisitionStrategy("@default/" + templateName, ctx.getTemplateLocale());
+        }
+        
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateNameSpecialVariablesTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateNameSpecialVariablesTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateNameSpecialVariablesTest.java
new file mode 100644
index 0000000..7c9a98f
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateNameSpecialVariablesTest.java
@@ -0,0 +1,159 @@
+/*
+ * 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;
+
+public class TemplateNameSpecialVariablesTest extends TemplateTest {
+    
+    private static final String PRINT_ALL_FTL
+            = "ct=${.currentTemplateName!'-'}, mt=${.mainTemplateName!'-'}";
+
+    @Test
+    public void testMainTemplateName() throws IOException, TemplateException {
+        addTemplateNameTestTemplates(".mainTemplateName");
+        assertOutputForNamed("main.ftl",
+                "In main: main.ftl\n"
+                + "In imp: main.ftl\n"
+                + "In main: main.ftl\n"
+                + "main.ftl\n"
+                + "{main.ftl}\n"
+                + "In imp call imp:\n"
+                + "main.ftl\n"
+                + "{main.ftl}\n"
+                + "After: main.ftl\n"
+                + "In main: main.ftl\n"
+                + "In inc: main.ftl\n"
+                + "In inc call imp:\n"
+                + "main.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");
+    }
+
+    @Test
+    public void testCurrentTemplateName() throws IOException, TemplateException {
+        addTemplateNameTestTemplates(".currentTemplateName");
+        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");
+    }
+
+    private void addTemplateNameTestTemplates(String specVar) {
+        addTemplate("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"
+        );
+        addTemplate("imp.ftl",
+                "<#global inImp = " + specVar + ">"
+                        + "<#macro impM>"
+                        + "${" + specVar + "}\n"
+                        + "{<#nested>}"
+                        + "</#macro>"
+                        + "<#macro impM2>"
+                        + "In imp call imp:\n"
+                        + "<@impM>${" + specVar + "}</@>\n"
+                        + "After: ${" + specVar + "}"
+                        + "</#macro>"
+        );
+        addTemplate("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>"
+        );
+    }
+
+    @Test
+    public void testInAdhocTemplate() throws TemplateException, IOException {
+        addTemplate("inc.ftl", "Inc: " + PRINT_ALL_FTL);
+
+        // 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()),
+                "ct=-, mt=-; Inc: ct=inc.ftl, mt=-");
+        
+        assertOutput(new Template("foo.ftl", PRINT_ALL_FTL + "; <#include 'inc.ftl'>", getConfiguration()),
+                "ct=foo.ftl, mt=foo.ftl; Inc: ct=inc.ftl, mt=foo.ftl");
+    }
+
+    @Test
+    public void testInInterpretTemplate() throws TemplateException, IOException {
+        addToDataModel("t", PRINT_ALL_FTL);
+        assertOutput(new Template("foo.ftl", PRINT_ALL_FTL + "; <@t?interpret />", getConfiguration()),
+                "ct=foo.ftl, mt=foo.ftl; "
+                + "ct=foo.ftl->anonymous_interpreted, mt=foo.ftl");
+        assertOutput(new Template(null, PRINT_ALL_FTL + "; <@t?interpret />", getConfiguration()),
+                "ct=-, mt=-; "
+                + "ct=nameless_template->anonymous_interpreted, mt=-");
+        assertOutput(new Template("foo.ftl", PRINT_ALL_FTL + "; <@[t,'bar']?interpret />", getConfiguration()),
+                "ct=foo.ftl, mt=foo.ftl; "
+                + "ct=foo.ftl->bar, mt=foo.ftl");
+    }
+
+    @Override
+    protected Configuration createDefaultConfiguration() throws Exception {
+        return new TestConfigurationBuilder().whitespaceStripping(false).build();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateNotFoundMessageTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateNotFoundMessageTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateNotFoundMessageTest.java
new file mode 100644
index 0000000..66331ad
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateNotFoundMessageTest.java
@@ -0,0 +1,207 @@
+/*
+ * 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.apache.freemarker.test.hamcerst.Matchers.*;
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.Serializable;
+
+import org.apache.freemarker.core.templateresolver.MalformedTemplateNameException;
+import org.apache.freemarker.core.templateresolver.TemplateLoader;
+import org.apache.freemarker.core.templateresolver.TemplateLookupContext;
+import org.apache.freemarker.core.templateresolver.TemplateLookupResult;
+import org.apache.freemarker.core.templateresolver.TemplateLookupStrategy;
+import org.apache.freemarker.core.templateresolver.impl.ClassTemplateLoader;
+import org.apache.freemarker.core.templateresolver.impl.FileTemplateLoader;
+import org.apache.freemarker.core.templateresolver.impl.MultiTemplateLoader;
+import org.apache.freemarker.core.templateresolver.impl.StringTemplateLoader;
+import org.junit.Test;
+
+public class TemplateNotFoundMessageTest {
+
+    @Test
+    public void testFileTemplateLoader() throws IOException {
+        final File baseDir = new File(System.getProperty("user.home"));
+        final String errMsg = failWith(new FileTemplateLoader(baseDir));
+        showErrorMessage(errMsg);
+        assertThat(errMsg, containsString(baseDir.toString()));
+        assertThat(errMsg, containsString("FileTemplateLoader"));
+    }
+
+    @Test
+    public void testClassTemplateLoader() throws IOException {
+        final String errMsg = failWith(new ClassTemplateLoader(getClass(), "foo/bar"));
+        showErrorMessage(errMsg);
+        assertThat(errMsg, containsString("ClassTemplateLoader"));
+        assertThat(errMsg, containsString("foo/bar"));
+    }
+
+    @Test
+    public void testStringTemplateLoader() throws IOException {
+        StringTemplateLoader tl = new StringTemplateLoader();
+        tl.putTemplate("aaa", "A");
+        tl.putTemplate("bbb", "B");
+        tl.putTemplate("ccc", "C");
+        final String errMsg = failWith(tl);
+        showErrorMessage(errMsg);
+        assertThat(errMsg, containsString("StringTemplateLoader"));
+        assertThat(errMsg, containsString("aaa"));
+        assertThat(errMsg, containsString("bbb"));
+        assertThat(errMsg, containsString("ccc"));
+    }
+    
+    @Test
+    public void testMultiTemplateLoader() throws IOException {
+        final String errMsg = failWith(new MultiTemplateLoader(new TemplateLoader[] {
+                new StringTemplateLoader(),
+                new ClassTemplateLoader(getClass(), "foo/bar")
+        }));
+        showErrorMessage(errMsg);
+        assertThat(errMsg, containsString("MultiTemplateLoader"));
+        assertThat(errMsg, containsString("StringTemplateLoader"));
+        assertThat(errMsg, containsString("ClassTemplateLoader"));
+        assertThat(errMsg, containsString("foo/bar"));
+    }
+
+    @Test
+    public void testDefaultTemplateLoader() throws IOException {
+        String errMsg = failWith(null);
+        showErrorMessage(errMsg);
+        assertThat(errMsg, allOf(containsString("setTemplateLoader"), containsString("null")));
+    }
+    
+    @Test
+    public void testOtherMessageDetails() throws IOException {
+        // Non-null TemplateLoader:
+        StringTemplateLoader emptyLoader = new StringTemplateLoader();
+        {
+            String errMsg = failWith(emptyLoader, "../x");
+            showErrorMessage(errMsg);
+            assertThat(errMsg,
+                    allOf(
+                            containsStringIgnoringCase("Malformed template name"),
+                            containsStringIgnoringCase("root directory")));
+        }
+        {
+            String errMsg = failWith(emptyLoader, "x\u0000y");
+            showErrorMessage(errMsg);
+            assertThat(errMsg,
+                    allOf(
+                            containsStringIgnoringCase("Malformed template name"),
+                            containsStringIgnoringCase("null character")));
+        }
+        {
+            String errMsg = failWith(emptyLoader, "x\\y");
+            showErrorMessage(errMsg);
+            assertThat(errMsg,
+                    allOf(containsStringIgnoringCase("warning"), containsStringIgnoringCase("backslash")));
+        }
+        {
+            String errMsg = failWith(emptyLoader, "x/./y");
+            showErrorMessage(errMsg);
+            assertThat(errMsg,
+                    allOf(containsStringIgnoringCase("normalized"), containsStringIgnoringCase("x/y")));
+        }
+        {
+            String errMsg = failWith(emptyLoader, "/x/y");
+            showErrorMessage(errMsg);
+            assertThat(errMsg, not(containsStringIgnoringCase("normalized")));
+        }
+        {
+            String errMsg = failWith(emptyLoader, "x/y");
+            showErrorMessage(errMsg);
+            assertThat(errMsg, not(containsStringIgnoringCase("normalized")));
+            assertThat(errMsg, not(containsStringIgnoringCase("lookup strategy")));
+        }
+
+        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0)
+                .templateLoader(new StringTemplateLoader())
+                .templateLookupStrategy(
+                        new TemplateLookupStrategy() {
+                            @Override
+                            public TemplateLookupResult lookup(TemplateLookupContext ctx) throws IOException {
+                                return ctx.lookupWithAcquisitionStrategy(ctx.getTemplateName());
+                            }
+                        }
+        );
+        {
+            String errMsg = failWith(emptyLoader, "x/y",
+                    new TemplateLookupStrategy() {
+                        @Override
+                        public TemplateLookupResult lookup(TemplateLookupContext ctx) throws IOException {
+                            return ctx.lookupWithAcquisitionStrategy(ctx.getTemplateName());
+                        }
+                    }
+            );
+            showErrorMessage(errMsg);
+            assertThat(errMsg, containsStringIgnoringCase("lookup strategy"));
+        }
+        
+        try {
+            cfgB.build().getTemplate("./missing", null, new DomainLookupCondition());
+            fail();
+        } catch (TemplateNotFoundException e) {
+            showErrorMessage(e.getMessage());
+            assertThat(e.getMessage(), containsStringIgnoringCase("example.com"));
+        }
+    }
+
+    private void showErrorMessage(String errMsg) {
+        // System.out.println(errMsg);
+    }
+
+    private String failWith(TemplateLoader tl, String name, TemplateLookupStrategy templateLookupStrategy) {
+        try {
+            Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
+            cfgB.setTemplateLoader(tl);
+            if (templateLookupStrategy != null) {
+                cfgB.setTemplateLookupStrategy(templateLookupStrategy);
+            }
+            cfgB.build().getTemplate(name);
+            fail();
+        } catch (TemplateNotFoundException | MalformedTemplateNameException e) {
+            return e.getMessage();
+        } catch (IOException e) {
+            fail("Unexpected exception: " + e);
+        }
+        return null;
+    }
+
+    private String failWith(TemplateLoader tl, String name) {
+        return failWith(tl, name, null);
+    }
+
+    private String failWith(TemplateLoader tl) {
+        return failWith(tl, "missing.ftl", null);
+    }
+
+    @SuppressWarnings("serial")
+    private static final class DomainLookupCondition implements Serializable {
+        @Override
+        public String toString() {
+            return "example.com";
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/TheadInterruptingSupportTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/TheadInterruptingSupportTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TheadInterruptingSupportTest.java
new file mode 100644
index 0000000..a0174b3
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TheadInterruptingSupportTest.java
@@ -0,0 +1,163 @@
+/*
+ * 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.util.Map;
+
+import org.apache.freemarker.core.ThreadInterruptionSupportTemplatePostProcessor.TemplateProcessingThreadInterruptedException;
+import org.apache.freemarker.core.model.TemplateDirectiveBody;
+import org.apache.freemarker.core.model.TemplateDirectiveModel;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.util._NullWriter;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TheadInterruptingSupportTest {
+    
+    private static final Logger LOG = LoggerFactory.getLogger(TheadInterruptingSupportTest.class);
+
+    private static final int TEMPLATE_INTERRUPTION_TIMEOUT = 5000;
+    private final Configuration cfg = new TestConfigurationBuilder().build();
+
+    @Test
+    public void test() throws IOException, InterruptedException {
+        assertCanBeInterrupted("<#list 1.. as x></#list>");
+        assertCanBeInterrupted("<#list 1.. as x>${x}</#list>");
+        assertCanBeInterrupted("<#list 1.. as x>t${x}</#list>");
+        assertCanBeInterrupted("<#list 1.. as x><#list 1.. as y>${y}</#list></#list>");
+        assertCanBeInterrupted("<#list 1.. as x>${x}<#else>nope</#list>");
+        assertCanBeInterrupted("<#list 1..>[<#items as x>${x}</#items>]<#else>nope</#list>");
+        assertCanBeInterrupted("<@customLoopDirective />");
+        assertCanBeInterrupted("<@customLoopDirective>x</@>");
+        assertCanBeInterrupted("<@customLoopDirective><#if true>x</#if></@>");
+        assertCanBeInterrupted("<#macro selfCalling><@sleepDirective/><@selfCalling /></#macro><@selfCalling />");
+        assertCanBeInterrupted("<#function selfCalling><@sleepDirective/>${selfCalling()}</#function>${selfCalling()}");
+        assertCanBeInterrupted("<#list 1.. as _><#attempt><@sleepDirective/><#recover>suppress</#attempt></#list>");
+        assertCanBeInterrupted("<#attempt><#list 1.. as _></#list><#recover>suppress</#attempt>");
+    }
+
+    private void assertCanBeInterrupted(final String templateSourceCode) throws IOException, InterruptedException {
+        TemplateRunnerThread trt = new TemplateRunnerThread(templateSourceCode);
+        trt.start();
+        synchronized (trt) {
+            while (!trt.isStarted()) {
+                trt.wait();
+            }
+        }
+        Thread.sleep(50); // Just to ensure (hope...) that the template execution reaches "deep" enough
+        trt.interrupt();
+        trt.join(TEMPLATE_INTERRUPTION_TIMEOUT);
+        assertTrue(trt.isTemplateProcessingInterrupted());
+    }
+
+    public class TemplateRunnerThread extends Thread {
+
+        private final Template template;
+        private boolean started;
+        private boolean templateProcessingInterrupted;
+
+        public TemplateRunnerThread(String templateSourceCode) throws IOException {
+            template = new Template(null, "<@startedDirective/>" + templateSourceCode, cfg);
+            _CoreAPI.addThreadInterruptedChecks(template);
+        }
+
+        @Override
+        public void run() {
+            try {
+                template.process(this, _NullWriter.INSTANCE);
+            } catch (TemplateProcessingThreadInterruptedException e) {
+                //LOG.debug("Template processing interrupted", e);
+                synchronized (this) {
+                    templateProcessingInterrupted = true;
+                }
+            } catch (Throwable e) {
+                LOG.error("Template processing failed", e);
+            }
+        }
+
+        public synchronized boolean isTemplateProcessingInterrupted() {
+            return templateProcessingInterrupted;
+        }
+        
+        public synchronized boolean isStarted() {
+            return started;
+        }
+        
+        public TemplateDirectiveModel getStartedDirective() {
+            return new StartedDirective();
+        }
+
+        public TemplateDirectiveModel getCustomLoopDirective() {
+            return new CustomLoopDirective();
+        }
+        
+        public TemplateDirectiveModel getSleepDirective() {
+            return new SleepDirective();
+        }
+
+        public class StartedDirective implements TemplateDirectiveModel {
+            
+            @Override
+            public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
+                    throws TemplateException, IOException {
+                synchronized (TemplateRunnerThread.this) {
+                    started = true;
+                    TemplateRunnerThread.this.notifyAll();
+                }
+            }
+            
+        }
+
+        public class CustomLoopDirective implements TemplateDirectiveModel {
+
+            @Override
+            public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
+                    throws TemplateException, IOException {
+                // Deliberate infinite loop
+                while (true) {
+                    body.render(_NullWriter.INSTANCE);
+                }
+            }
+            
+        }
+        
+        public class SleepDirective implements TemplateDirectiveModel {
+
+            @Override
+            public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
+                    throws TemplateException, IOException {
+                try {
+                    Thread.sleep(100);
+                } catch (InterruptedException e) {
+                    // Thread.sleep has reset the interrupted flag (because it has thrown InterruptedException).  
+                    Thread.currentThread().interrupt();
+                }
+            }
+            
+        }
+        
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/TypeErrorMessagesTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/TypeErrorMessagesTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TypeErrorMessagesTest.java
new file mode 100644
index 0000000..749d057
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TypeErrorMessagesTest.java
@@ -0,0 +1,105 @@
+/*
+ * 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.StringReader;
+import java.util.Map;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.apache.freemarker.test.TemplateTest;
+import org.junit.Test;
+import org.w3c.dom.Document;
+import org.xml.sax.InputSource;
+
+public class TypeErrorMessagesTest extends TemplateTest {
+
+    static final Document doc;
+    static {
+        try {
+            DocumentBuilder docBuilder;
+            docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+            doc = docBuilder.parse(new InputSource(new StringReader(
+                    "<a><b>123</b><c a='true'>1</c><c a='false'>2</c></a>")));
+        } catch (Exception e) {
+            throw new RuntimeException("Failed to build data-model", e);
+        }
+    }
+
+    @Test
+    public void testNumericalBinaryOperator() {
+        assertErrorContains("${n - s}", "\"-\"", "right-hand", "number", "string");
+        assertErrorContains("${s - n}", "\"-\"", "left-hand", "number", "string");
+    }
+
+    @Test
+    public void testGetterMistake() {
+        assertErrorContains("${bean.getX}", "${...}",
+                "number", "string", "method", "obj.getSomething", "obj.something");
+        assertErrorContains("${1 * bean.getX}", "right-hand",
+                "number", "\\!string", "method", "obj.getSomething", "obj.something");
+        assertErrorContains("<#if bean.isB></#if>", "condition",
+                "boolean", "method", "obj.isSomething", "obj.something");
+        assertErrorContains("<#if bean.isB></#if>", "condition",
+                "boolean", "method", "obj.isSomething", "obj.something");
+        assertErrorContains("${bean.voidM}",
+                "string", "method", "\\!()");
+        assertErrorContains("${bean.intM}",
+                "string", "method", "obj.something()");
+        assertErrorContains("${bean.intMP}",
+                "string", "method", "obj.something(params)");
+    }
+
+    @Test
+    public void testXMLTypeMismarches() throws Exception {
+        assertErrorContains("${doc.a.c}",
+                "used as string", "query result", "2", "multiple matches");
+        assertErrorContains("${doc.a.c?boolean}",
+                "used as string", "query result", "2", "multiple matches");
+        assertErrorContains("${doc.a.d}",
+                "used as string", "query result", "0", "no matches");
+        assertErrorContains("${doc.a.d?boolean}",
+                "used as string", "query result", "0", "no matches");
+        
+        assertErrorContains("${doc.a.c.@a}",
+                "used as string", "query result", "2", "multiple matches");
+        assertErrorContains("${doc.a.d.@b}",
+                "used as string", "query result", "x", "no matches");
+        
+        assertErrorContains("${doc.a.b * 2}",
+                "used as number", "text", "explicit conversion");
+        assertErrorContains("<#if doc.a.b></#if>",
+                "used as number", "text", "explicit conversion");
+
+        assertErrorContains("${doc.a.d?nodeName}",
+                "used as node", "query result", "0", "no matches");
+        assertErrorContains("${doc.a.c?nodeName}",
+                "used as node", "query result", "2", "multiple matches");
+    }
+
+    @Override
+    protected Object createDataModel() {
+        Map<String, Object> dataModel = createCommonTestValuesDataModel();
+        dataModel.put("doc", doc);
+        return dataModel;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/UnclosedCommentTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/UnclosedCommentTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/UnclosedCommentTest.java
new file mode 100644
index 0000000..99bf5d3
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/UnclosedCommentTest.java
@@ -0,0 +1,41 @@
+/*
+ * 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.junit.Test;
+
+public class UnclosedCommentTest extends TemplateTest {
+    
+    @Test
+    public void test() throws IOException, TemplateException {
+        assertErrorContains("foo<#--", "end of file");  // Not too good...
+        assertErrorContains("foo<#-- ", "Unclosed", "<#--");
+        assertErrorContains("foo<#--bar", "Unclosed", "<#--");
+        assertErrorContains("foo\n<#--\n", "Unclosed", "<#--");
+        assertErrorContains("foo<#noparse>", "end of file");  // Not too good...
+        assertErrorContains("foo<#noparse> ", "Unclosed", "#noparse");
+        assertErrorContains("foo<#noparse>bar", "Unclosed", "#noparse");
+        assertErrorContains("foo\n<#noparse>\n", "Unclosed", "#noparse");
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/VersionTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/VersionTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/VersionTest.java
new file mode 100644
index 0000000..8c54df5
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/VersionTest.java
@@ -0,0 +1,227 @@
+/*
+ * 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.sql.Date;
+
+import org.junit.Test;
+
+@SuppressWarnings("boxing")
+public class VersionTest {
+
+    @Test
+    public void testFromNumber() {
+        Version v = new Version(1, 2, 3);
+        assertEquals("1.2.3", v.toString());
+        assertEquals(1002003, v.intValue());
+        assertEquals(1, v.getMajor());
+        assertEquals(2, v.getMinor());
+        assertEquals(3, v.getMicro());
+        assertNull(v.getExtraInfo());
+        assertNull(v.isGAECompliant());
+        assertNull(v.getBuildDate());
+    }
+
+    @Test
+    public void testFromNumber2() {
+        Version v = new Version(1, 2, 3, "beta8", Boolean.TRUE, new Date(5000));
+        assertEquals("1.2.3-beta8", v.toString());
+        assertEquals("beta8", v.getExtraInfo());
+        assertTrue(v.isGAECompliant().booleanValue());
+        assertEquals(new Date(5000), v.getBuildDate());
+    }
+
+    @Test
+    public void testFromNumber3() {
+        Version v = new Version(new Version(1, 2, 3).intValue());
+        assertEquals(1, v.getMajor());
+        assertEquals(2, v.getMinor());
+        assertEquals(3, v.getMicro());
+    }
+    
+    public void testFromNumberIncubating() {
+        Version v = new Version(2, 3, 24, "rc01-incubating", Boolean.FALSE, new Date(5000));
+        assertEquals("2.3.24-rc01-incubating", v.toString());
+        assertEquals("rc01-incubating", v.getExtraInfo());
+        assertFalse(v.isGAECompliant().booleanValue());
+        assertEquals(new Date(5000), v.getBuildDate());
+    }
+    
+    @Test
+    public void testFromString() {
+        Version v = new Version("1.2.3-beta2");
+        assertEquals("1.2.3-beta2", v.toString());
+        assertEquals(1002003, v.intValue());
+        assertEquals(1, v.getMajor());
+        assertEquals(2, v.getMinor());
+        assertEquals(3, v.getMicro());
+        assertEquals("beta2", v.getExtraInfo());
+        assertNull(v.isGAECompliant());
+        assertNull(v.getBuildDate());
+    }
+
+    @Test
+    public void testFromString2() {
+        Version v = new Version("10.20.30", Boolean.TRUE, new Date(5000));
+        assertEquals("10.20.30", v.toString());
+        assertEquals(10020030, v.intValue());
+        assertEquals(10, v.getMajor());
+        assertEquals(20, v.getMinor());
+        assertEquals(30, v.getMicro());
+        assertNull(v.getExtraInfo());
+        assertTrue(v.isGAECompliant().booleanValue());
+        assertEquals(new Date(5000), v.getBuildDate());
+    }
+
+    @Test
+    public void testFromString3() {
+        Version v = new Version("01.002.0003-20130524");
+        assertEquals("01.002.0003-20130524", v.toString());
+        assertEquals(1, v.getMajor());
+        assertEquals(2, v.getMinor());
+        assertEquals(3, v.getMicro());
+        assertEquals("20130524", v.getExtraInfo());
+
+        v = new Version("01.002.0003.4");
+        assertEquals("01.002.0003.4", v.toString());
+        assertEquals(1, v.getMajor());
+        assertEquals(2, v.getMinor());
+        assertEquals(3, v.getMicro());
+        assertEquals("4", v.getExtraInfo());
+        
+        v = new Version("1.2.3.FC");
+        assertEquals("1.2.3.FC", v.toString());
+        assertEquals("FC", v.getExtraInfo());
+        
+        v = new Version("1.2.3mod");
+        assertEquals("1.2.3mod", v.toString());
+        assertEquals(1, v.getMajor());
+        assertEquals(2, v.getMinor());
+        assertEquals(3, v.getMicro());
+        assertEquals("mod", v.getExtraInfo());
+        
+    }
+
+    @Test
+    public void testFromStringIncubating() {
+        Version v = new Version("2.3.24-rc01-incubating");
+        assertEquals("2.3.24-rc01-incubating", v.toString());
+        assertEquals(2, v.getMajor());
+        assertEquals(3, v.getMinor());
+        assertEquals(24, v.getMicro());
+        assertEquals("rc01-incubating", v.getExtraInfo());
+    }
+    
+    @Test
+    public void testHashAndEquals() {
+        Version v1 = new Version("1.2.3-beta2");
+        Version v2 = new Version(1, 2, 3, "beta2", null, null);
+        assertEquals(v1, v2);
+        assertEquals(v1.hashCode(), v2.hashCode());
+        
+        v2 = new Version("1.2.3-beta3");
+        assertTrue(!v1.equals(v2));
+        assertTrue(v1.hashCode() != v2.hashCode());
+        
+        v2 = new Version(1, 2, 3, "beta2", true, null);
+        assertTrue(!v1.equals(v2));
+        assertTrue(v1.hashCode() != v2.hashCode());
+        
+        v2 = new Version(1, 2, 3, "beta2", null, new Date(5000));
+        assertTrue(!v1.equals(v2));
+        assertTrue(v1.hashCode() != v2.hashCode());
+        
+        v2 = new Version("1.2.9-beta2");
+        assertTrue(!v1.equals(v2));
+        assertTrue(v1.hashCode() != v2.hashCode());
+        
+        v2 = new Version("1.9.3-beta2");
+        assertTrue(!v1.equals(v2));
+        assertTrue(v1.hashCode() != v2.hashCode());
+        
+        v2 = new Version("9.2.3-beta2");
+        assertTrue(!v1.equals(v2));
+        assertTrue(v1.hashCode() != v2.hashCode());
+        
+        v2 = new Version("1.2.3");
+        assertTrue(!v1.equals(v2));
+        assertTrue(v1.hashCode() != v2.hashCode());
+    }
+
+    @Test
+    public void testShortForms() {
+        Version v = new Version("1.0.0-beta2");
+        assertEquals(v, new Version("1.0-beta2"));
+        assertEquals(v, new Version("1-beta2"));
+
+        v = new Version("1.0.0");
+        assertEquals(v, new Version("1.0"));
+        assertEquals(v, new Version("1"));
+    }
+    
+    @Test
+    public void testMalformed() {
+        try {
+            new Version("1.2.");
+            fail();
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+        
+        try {
+            new Version("1.2.3.");
+            fail();
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+        
+        try {
+            new Version("1..3");
+            fail();
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+
+        try {
+            new Version(".2");
+            fail();
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+        
+        try {
+            new Version("a");
+            fail();
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+        
+        try {
+            new Version("-a");
+            fail();
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+    
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/WhitespaceStrippingTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/WhitespaceStrippingTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/WhitespaceStrippingTest.java
new file mode 100644
index 0000000..8e5b52e
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/WhitespaceStrippingTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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;
+
+public class WhitespaceStrippingTest extends TemplateTest {
+
+    @Test
+    public void testBasics() throws Exception {
+        assertOutput("<#assign x = 1>\n<#assign y = 2>\n${x}\n${y}", "1\n2", "\n\n1\n2");
+        assertOutput(" <#assign x = 1> \n <#assign y = 2> \n${x}\n${y}", "1\n2", "  \n  \n1\n2");
+    }
+
+    @Test
+    public void testFTLHeader() throws Exception {
+        assertOutput("<#ftl>x", "x", "x");
+        assertOutput("  <#ftl>  x", "  x", "  x");
+        assertOutput("\n<#ftl>\nx", "x", "x");
+        assertOutput("\n<#ftl>\t \nx", "x", "x");
+        assertOutput("  \n \n  <#ftl> \n \n  x", " \n  x", " \n  x");
+    }
+
+    @Test
+    public void testComment() throws Exception {
+        assertOutput(" a <#-- --> b ", " a  b ", " a  b ");
+        assertOutput(" a \n<#-- -->\n b ", " a \n b ", " a \n\n b ");
+        // These are wrong, but needed for 2.3.0 compatibility:
+        assertOutput(" a \n <#-- --> \n b ", " a \n  b ", " a \n  \n b ");
+        assertOutput(" a \n\t<#-- --> \n b ", " a \n\t b ", " a \n\t \n b ");
+    }
+    
+    private void assertOutput(String ftl, String expectedOutStripped, String expectedOutNonStripped)
+            throws IOException, TemplateException {
+        setConfiguration(new TestConfigurationBuilder().build());
+        assertOutput(ftl, expectedOutStripped);
+        
+        setConfiguration(new TestConfigurationBuilder().whitespaceStripping(false).build());
+        assertOutput(ftl, expectedOutNonStripped);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/XHTMLOutputFormatTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/XHTMLOutputFormatTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/XHTMLOutputFormatTest.java
new file mode 100644
index 0000000..77951ed
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/XHTMLOutputFormatTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.apache.freemarker.core.outputformat.impl.XHTMLOutputFormat.*;
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.io.StringWriter;
+
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.junit.Test; 
+
+public class XHTMLOutputFormatTest {
+    
+    @Test
+    public void testOutputMO() throws TemplateModelException, IOException {
+       StringWriter out = new StringWriter();
+       INSTANCE.output(INSTANCE.fromPlainTextByEscaping("a'b"), out);
+       assertEquals("a&#39;b", out.toString());
+    }
+    
+    @Test
+    public void testOutputString() throws TemplateModelException, IOException {
+        StringWriter out = new StringWriter();
+        INSTANCE.output("a'b", out);
+        assertEquals("a&#39;b", out.toString());
+    }
+    
+    @Test
+    public void testEscaplePlainText() {
+        assertEquals("", INSTANCE.escapePlainText(""));
+        assertEquals("a", INSTANCE.escapePlainText("a"));
+        assertEquals("&lt;a&amp;b&#39;c&quot;d&gt;", INSTANCE.escapePlainText("<a&b'c\"d>"));
+        assertEquals("&lt;&gt;", INSTANCE.escapePlainText("<>"));
+    }
+    
+    @Test
+    public void testGetMimeType() {
+        assertEquals("application/xhtml+xml", INSTANCE.getMimeType());
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/XMLOutputFormatTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/XMLOutputFormatTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/XMLOutputFormatTest.java
new file mode 100644
index 0000000..7e95e6d
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/XMLOutputFormatTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.apache.freemarker.core.outputformat.impl.XMLOutputFormat.*;
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.io.StringWriter;
+
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.junit.Test; 
+
+public class XMLOutputFormatTest {
+    
+    @Test
+    public void testOutputMO() throws TemplateModelException, IOException {
+       StringWriter out = new StringWriter();
+       INSTANCE.output(INSTANCE.fromPlainTextByEscaping("a'b"), out);
+       assertEquals("a&apos;b", out.toString());
+    }
+    
+    @Test
+    public void testOutputString() throws TemplateModelException, IOException {
+        StringWriter out = new StringWriter();
+        INSTANCE.output("a'b", out);
+        assertEquals("a&apos;b", out.toString());
+    }
+    
+    @Test
+    public void testEscaplePlainText() {
+        assertEquals("", INSTANCE.escapePlainText(""));
+        assertEquals("a", INSTANCE.escapePlainText("a"));
+        assertEquals("&lt;a&amp;b&apos;c&quot;d&gt;", INSTANCE.escapePlainText("<a&b'c\"d>"));
+        assertEquals("&lt;&gt;", INSTANCE.escapePlainText("<>"));
+    }
+    
+    @Test
+    public void testGetMimeType() {
+        assertEquals("application/xml", INSTANCE.getMimeType());
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/AbstractParallelIntrospectionTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/AbstractParallelIntrospectionTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/AbstractParallelIntrospectionTest.java
new file mode 100644
index 0000000..bdb9a56
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/AbstractParallelIntrospectionTest.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.model.impl;
+
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.model.TemplateHashModel;
+import org.apache.freemarker.core.model.TemplateMethodModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateNumberModel;
+
+import junit.framework.TestCase;
+
+public abstract class AbstractParallelIntrospectionTest extends TestCase {
+    
+    private static final int NUM_THREADS = 8;
+    private static final int NUM_ENTITYES = 8;
+    private static final int NUM_MEMBERS = 8;
+    private static final int ITERATIONS = 20000;
+    private static final double CACHE_CLEARING_CHANCE = 0.01;
+    
+    private DefaultObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0)
+            .usePrivateCaches(true).build();
+    
+    public AbstractParallelIntrospectionTest(String name) {
+        super(name);
+    }
+    
+    public void testReliability() {
+        testReliability(ITERATIONS);
+    }
+    
+    public void testReliability(int iterations) {
+        TestThread[] ts = new TestThread[NUM_THREADS]; 
+        for (int i = 0; i < NUM_THREADS; i++) {
+            ts[i] = new TestThread(iterations);
+            ts[i].start();
+        }
+
+        for (int i = 0; i < NUM_THREADS; i++) {
+            try {
+                ts[i].join();
+                if (ts[i].error != null) {
+                    throw new AssertionError(ts[i].error);
+                }
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    protected abstract TemplateHashModel getWrappedEntity(int objIdx) throws TemplateModelException;
+    
+    protected final DefaultObjectWrapper getObjectWrapper() {
+        return ow;
+    }
+    
+    private class TestThread extends Thread {
+        
+        private final int iterations;
+        
+        private Throwable error;
+        
+        private TestThread(int iterations) {
+            this.iterations = iterations;
+        }
+
+        @Override
+        public void run() {
+            try {
+                for (int i = 0; i < iterations; i++) {
+                    if (Math.random() < CACHE_CLEARING_CHANCE) {
+                        ow.clearClassIntrospecitonCache();
+                    }
+                    int objIdx = (int) (Math.random() * NUM_ENTITYES);
+                    TemplateHashModel h = getWrappedEntity(objIdx);
+                    int mIdx = (int) (Math.random() * NUM_MEMBERS);
+                    testProperty(h, objIdx, mIdx);
+                    testMethod(h, objIdx, mIdx);
+                }
+            } catch (Throwable e) {
+                error = e;
+            }
+        }
+
+        private void testProperty(TemplateHashModel h, int objIdx, int mIdx)
+                throws TemplateModelException, AssertionError {
+            TemplateNumberModel pv = (TemplateNumberModel) h.get("p" + mIdx);
+            final int expected = objIdx * 1000 + mIdx;
+            final int got = pv.getAsNumber().intValue();
+            if (got != expected) {
+                throw new AssertionError("Property assertation failed; " +
+                        "expected " + expected + ", but got " + got);
+            }
+        }
+
+        private void testMethod(TemplateHashModel h, int objIdx, int mIdx)
+                throws TemplateModelException, AssertionError {
+            TemplateMethodModel pv = (TemplateMethodModel) h.get("m" + mIdx);
+            final int expected = objIdx * 1000 + mIdx;
+            final int got = ((TemplateNumberModel) pv.exec(null)).getAsNumber().intValue();
+            if (got != expected) {
+                throw new AssertionError("Method assertation failed; " +
+                        "expected " + expected + ", but got " + got);
+            }
+        }
+        
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/AlphabeticalMethodSorter.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/AlphabeticalMethodSorter.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/AlphabeticalMethodSorter.java
new file mode 100644
index 0000000..149ad0d
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/AlphabeticalMethodSorter.java
@@ -0,0 +1,45 @@
+/*
+ * 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.model.impl;
+
+import java.beans.MethodDescriptor;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+class AlphabeticalMethodSorter implements MethodSorter {
+
+    private final boolean desc;
+    
+    public AlphabeticalMethodSorter(boolean desc) {
+        this.desc = desc;
+    }
+
+    @Override
+    public void sortMethodDescriptors(List<MethodDescriptor> methodDescriptors) {
+        Collections.sort(methodDescriptors, new Comparator<MethodDescriptor>() {
+            public int compare(MethodDescriptor o1, MethodDescriptor o2) {
+                int res = o1.getMethod().toString().compareTo(o2.getMethod().toString());
+                return desc ? -res : res;
+            }
+        });
+    }
+    
+}
\ No newline at end of file



[18/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/OutputFormatTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/OutputFormatTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/OutputFormatTest.java
deleted file mode 100644
index eedb4d1..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/OutputFormatTest.java
+++ /dev/null
@@ -1,1068 +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;
-
-import static org.apache.freemarker.core.ParsingConfiguration.*;
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.io.StringWriter;
-import java.io.Writer;
-import java.util.Collections;
-
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.outputformat.OutputFormat;
-import org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat;
-import org.apache.freemarker.core.outputformat.impl.PlainTextOutputFormat;
-import org.apache.freemarker.core.outputformat.impl.RTFOutputFormat;
-import org.apache.freemarker.core.outputformat.impl.UndefinedOutputFormat;
-import org.apache.freemarker.core.outputformat.impl.XMLOutputFormat;
-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.core.templateresolver.impl.NullCacheStorage;
-import org.apache.freemarker.core.userpkg.CustomHTMLOutputFormat;
-import org.apache.freemarker.core.userpkg.DummyOutputFormat;
-import org.apache.freemarker.core.userpkg.SeldomEscapedOutputFormat;
-import org.apache.freemarker.test.TemplateTest;
-import org.apache.freemarker.test.TestConfigurationBuilder;
-import org.junit.Before;
-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}");
-        
-        TestConfigurationBuilder cfgB = createDefaultConfigurationBuilder();
-        for (OutputFormat cfgOutputFormat
-                : new OutputFormat[] { UndefinedOutputFormat.INSTANCE, RTFOutputFormat.INSTANCE } ) {
-            if (!cfgOutputFormat.equals(UndefinedOutputFormat.INSTANCE)) {
-                cfgB.setOutputFormat(cfgOutputFormat);
-            }
-            setConfiguration(cfgB.build());
-
-            assertEquals(cfgOutputFormat, getConfiguration().getOutputFormat());
-            
-            {
-                Template t = getConfiguration().getTemplate("t");
-                assertEquals(cfgOutputFormat, t.getOutputFormat());
-                assertOutput(t, t.getOutputFormat().getName());
-            }
-            
-            {
-                Template t = getConfiguration().getTemplate("t.xml");
-                assertEquals(XMLOutputFormat.INSTANCE, t.getOutputFormat());
-                assertOutput(t, t.getOutputFormat().getName());
-            }
-            
-            {
-                Template t = getConfiguration().getTemplate("tWithHeader");
-                assertEquals(HTMLOutputFormat.INSTANCE, t.getOutputFormat());
-                assertOutput(t, t.getOutputFormat().getName());
-            }
-            
-            getConfiguration().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);
-        
-        TestConfigurationBuilder cfgB = createDefaultConfigurationBuilder();
-        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;
-                cfgB.setOutputFormat(cfgOutputFormat);
-                ftlhOutputFormat = HTMLOutputFormat.INSTANCE;
-                ftlxOutputFormat = XMLOutputFormat.INSTANCE;
-                break;
-            case 3:
-                cfgOutputFormat = UndefinedOutputFormat.INSTANCE;
-                cfgB.unsetOutputFormat();
-                TemplateConfiguration.Builder tcbXML = new TemplateConfiguration.Builder();
-                tcbXML.setOutputFormat(XMLOutputFormat.INSTANCE);
-                cfgB.setTemplateConfigurations(
-                        new ConditionalTemplateConfigurationFactory(
-                                new OrMatcher(
-                                        new FileNameGlobMatcher("*.ftlh"),
-                                        new FileNameGlobMatcher("*.FTLH"),
-                                        new FileNameGlobMatcher("*.fTlH")),
-                                tcbXML.build()));
-                ftlhOutputFormat = HTMLOutputFormat.INSTANCE; // can't be overidden
-                ftlxOutputFormat = XMLOutputFormat.INSTANCE;
-                break;
-            default:
-                throw new AssertionError();
-            }
-
-            setConfiguration(cfgB.build());
-            assertEquals(cfgOutputFormat, getConfiguration().getOutputFormat());
-            
-            {
-                Template t = getConfiguration().getTemplate("t");
-                assertEquals(cfgOutputFormat, t.getOutputFormat());
-                assertOutput(t, t.getOutputFormat().getName());
-            }
-            
-            {
-                Template t = getConfiguration().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 = getConfiguration().getTemplate(name);
-                assertEquals(ftlhOutputFormat, t.getOutputFormat());
-                assertOutput(t, t.getOutputFormat().getName());
-            }
-            
-            for (String name : new String[] { "t.ftlx", "t.FTLX", "t.fTlX" }) {
-                Template t = getConfiguration().getTemplate(name);
-                assertEquals(ftlxOutputFormat, t.getOutputFormat());
-                assertOutput(t, t.getOutputFormat().getName());
-            }
-
-            {
-                Template t = getConfiguration().getTemplate("tWithHeader.ftlx");
-                assertEquals(HTMLOutputFormat.INSTANCE, t.getOutputFormat());
-                assertOutput(t, t.getOutputFormat().getName());
-            }
-
-            getConfiguration().clearTemplateCache();
-        }
-    }
-    
-    @Test
-    public void testStandardFileExtensionsSettingOverriding() throws Exception {
-        addTemplate("t.ftlx",
-                "${\"'\"} ${\"'\"?esc} ${\"'\"?noEsc}");
-        addTemplate("t.ftl",
-                "${'{}'} ${'{}'?esc} ${'{}'?noEsc}");
-        
-        ConditionalTemplateConfigurationFactory tcfHTML = new ConditionalTemplateConfigurationFactory(
-                new FileNameGlobMatcher("t.*"),
-                new TemplateConfiguration.Builder()
-                        .outputFormat(HTMLOutputFormat.INSTANCE)
-                        .build());
-
-        ConditionalTemplateConfigurationFactory tcfNoAutoEsc = new ConditionalTemplateConfigurationFactory(
-                new FileNameGlobMatcher("t.*"),
-                new TemplateConfiguration.Builder()
-                        .autoEscapingPolicy(DISABLE_AUTO_ESCAPING_POLICY)
-                        .build());
-
-        {
-            TestConfigurationBuilder cfgB = createDefaultConfigurationBuilder();
-
-            setConfiguration(cfgB.outputFormat(HTMLOutputFormat.INSTANCE).build());
-            assertOutputForNamed("t.ftlx", "&apos; &apos; '");  // Can't override it
-            setConfiguration(cfgB.templateConfigurations(tcfHTML).build());
-            assertOutputForNamed("t.ftlx", "&apos; &apos; '");  // Can't override it
-            setConfiguration(cfgB.templateConfigurations(tcfNoAutoEsc).build());
-            assertOutputForNamed("t.ftlx", "&apos; &apos; '");  // Can't override it
-        }
-
-        {
-            TestConfigurationBuilder cfgB = createDefaultConfigurationBuilder();
-
-            setConfiguration(cfgB.recognizeStandardFileExtensions(false).build());
-            assertErrorContainsForNamed("t.ftlx", UndefinedOutputFormat.INSTANCE.getName());
-            setConfiguration(cfgB.outputFormat(HTMLOutputFormat.INSTANCE).build());
-            assertOutputForNamed("t.ftlx", "&#39; &#39; '");
-            setConfiguration(cfgB.outputFormat(XMLOutputFormat.INSTANCE).build());
-            assertOutputForNamed("t.ftlx", "&apos; &apos; '");
-            setConfiguration(cfgB.templateConfigurations(tcfHTML).build());
-            assertOutputForNamed("t.ftlx", "&#39; &#39; '");
-            setConfiguration(cfgB.templateConfigurations(tcfNoAutoEsc).build());
-            assertOutputForNamed("t.ftlx", "' &apos; '");
-        }
-
-        {
-            TestConfigurationBuilder cfgB = createDefaultConfigurationBuilder();
-            cfgB.setRecognizeStandardFileExtensions(true);
-
-            setConfiguration(cfgB.templateConfigurations(tcfHTML).build());
-            assertOutputForNamed("t.ftlx", "&apos; &apos; '");  // Can't override it
-            setConfiguration(cfgB.templateConfigurations(tcfNoAutoEsc).build());
-            assertOutputForNamed("t.ftlx", "&apos; &apos; '");  // Can't override it
-        }
-
-        {
-            TestConfigurationBuilder cfgB = createDefaultConfigurationBuilder();
-
-            setConfiguration(cfgB.templateConfigurations(tcfHTML).build());
-            assertOutputForNamed("t.ftlx", "&apos; &apos; '");  // Can't override it
-            setConfiguration(cfgB.recognizeStandardFileExtensions(false).build());
-            assertOutputForNamed("t.ftlx", "&#39; &#39; '");
-        }
-    }
-
-    @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("&apos;", out.toString());
-        }
-        {
-            Template t = new Template("foo.ftlh", commonFTL, cfg);
-            assertSame(HTMLOutputFormat.INSTANCE, t.getOutputFormat());
-            StringWriter out = new StringWriter();
-            t.process(null, out);
-            assertEquals("&#39;", out.toString());
-        }
-    }
-    
-    @Test
-    public void testStandardFileExtensionsFormatterImplOverriding() throws Exception {
-        addTemplate("t.ftlh", "${'a&x'}");
-
-        assertOutputForNamed("t.ftlh", "a&amp;x");
-
-        setConfiguration(new TestConfigurationBuilder()
-                .registeredCustomOutputFormats(Collections.<OutputFormat>singleton(CustomHTMLOutputFormat.INSTANCE))
-                .build());
-        assertOutputForNamed("t.ftlh", "a&amp;X");
-
-        setConfiguration(new TestConfigurationBuilder()
-                .registeredCustomOutputFormats(Collections.<OutputFormat>emptyList())
-                .build());
-        assertOutputForNamed("t.ftlh", "a&amp;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'}");
-        
-        TestConfigurationBuilder cfgB = createDefaultConfigurationBuilder().outputFormat(XMLOutputFormat.INSTANCE);
-        assertEquals(ENABLE_IF_DEFAULT_AUTO_ESCAPING_POLICY, cfgB.getAutoEscapingPolicy());
-
-        for (boolean cfgAutoEscaping : new boolean[] { true, false }) {
-            if (!cfgAutoEscaping) {
-                cfgB.setAutoEscapingPolicy(DISABLE_AUTO_ESCAPING_POLICY);
-            }
-            setConfiguration(cfgB.build());
-
-            {
-                Template t = getConfiguration().getTemplate("t");
-                if (cfgAutoEscaping) {
-                    assertEquals(ENABLE_IF_DEFAULT_AUTO_ESCAPING_POLICY, t.getAutoEscapingPolicy());
-                    assertOutput(t, "a&amp;b");
-                } else {
-                    assertEquals(DISABLE_AUTO_ESCAPING_POLICY, t.getAutoEscapingPolicy());
-                    assertOutput(t, "a&b");
-                }
-            }
-            
-            {
-                Template t = getConfiguration().getTemplate("tWithHeaderFalse");
-                assertEquals(DISABLE_AUTO_ESCAPING_POLICY, t.getAutoEscapingPolicy());
-                assertOutput(t, "a&b");
-            }
-            
-            {
-                Template t = getConfiguration().getTemplate("tWithHeaderTrue");
-                assertEquals(ENABLE_IF_SUPPORTED_AUTO_ESCAPING_POLICY, t.getAutoEscapingPolicy());
-                assertOutput(t, "a&amp;b");
-            }
-
-            getConfiguration().clearTemplateCache();
-        }
-    }
-    
-    @Test
-    public void testNumericalInterpolation() throws IOException, TemplateException {
-        setConfiguration(new TestConfigurationBuilder()
-                .registeredCustomOutputFormats(Collections.<OutputFormat>singleton(DummyOutputFormat.INSTANCE))
-                .build());
-        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 &lt; {h&#39;}; <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 (boolean cfgAutoEscaping : new boolean[] { true, false }) {
-            String commonAutoEscFtl = "<#ftl outputFormat='HTML'>${'&'}";
-            if (cfgAutoEscaping) {
-                // Cfg default is autoEscaping true
-                assertOutput(commonAutoEscFtl, "&amp;");
-            } else {
-                setConfiguration(createDefaultConfigurationBuilder()
-                        .autoEscapingPolicy(DISABLE_AUTO_ESCAPING_POLICY)
-                        .build());
-                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 &lt; {h&#39;} <p>c "
-                    + "a &lt; {x&#39;} "
-                    + "\\par a &amp; b");
-            assertOutput(
-                    "<#ftl outputFormat='XML'>"
-                    + "${xmlPlain} ${xmlMarkup} "
-                    + "${htmlPlain} "
-                    + "${rtfPlain}",
-                    "a &lt; {x&apos;} <p>c</p> "
-                    + "a &lt; {h&apos;} "
-                    + "\\par a &amp; 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 &lt; {x&apos;} <p>c</p> "
-                        + "a &lt; {h&#39;} <p>c "
-                        + "\\\\par a & b \\par c");
-            }
-        }
-    }
-
-    @Test
-    public void testStringLiteralsUseUndefinedOF() throws IOException, TemplateException {
-        String expectedOut = "&amp; (&) &amp;";
-        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.createPlainTextTemplate("x", content, getConfiguration());
-            Writer sw = new StringWriter();
-            t.process(null, sw);
-            assertEquals(content, sw.toString());
-            assertEquals(UndefinedOutputFormat.INSTANCE, t.getOutputFormat());
-        }
-        
-        {
-            setConfiguration(new TestConfigurationBuilder().outputFormat(HTMLOutputFormat.INSTANCE).build());
-            Template t = Template.createPlainTextTemplate("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 &lt; {x&apos;}");
-        assertOutput("${'${xmlMarkup}'}", "<p>c</p>");
-        assertErrorContains("${'${\"x\"?esc}'}", "?esc", "undefined");
-        assertOutput("<#ftl outputFormat='XML'>${'${xmlMarkup?esc} ${\"<\"?esc} ${\">\"} ${\"&amp;\"?noEsc}'}",
-                "<p>c</p> &lt; &gt; &amp;");
-    }
-    
-    @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}",
-                "&#39;<p>c <p>c&#39; <p>c<p>c");
-        assertOutput(
-                "${'\\'' + htmlPlain} ${htmlPlain + '\\''} ${htmlPlain + htmlPlain}",
-                "&#39;a &lt; {h&#39;} a &lt; {h&#39;}&#39; a &lt; {h&#39;}a &lt; {h&#39;}");
-        assertErrorContains(
-                "<#ftl outputFormat='XML'>${'\\'' + htmlMarkup}",
-                "HTML", "XML", "conversion");
-        assertErrorContains(
-                "${xmlMarkup + htmlMarkup}",
-                "HTML", "XML", "Conversion", "common");
-        assertOutput(
-                "${xmlMarkup + htmlPlain}",
-                "<p>c</p>a &lt; {h&apos;}");
-        assertOutput(
-                "${xmlPlain + htmlMarkup}",
-                "a &lt; {x&#39;}<p>c");
-        assertOutput(
-                "${xmlPlain + htmlPlain}",
-                "a &lt; {x&apos;}a &lt; {h&apos;}");
-        assertOutput(
-                "${xmlPlain + htmlPlain + '\\''}",
-                "a &lt; {x&apos;}a &lt; {h&apos;}&apos;");
-        assertOutput(
-                "${htmlPlain + xmlPlain + '\\''}",
-                "a &lt; {h&#39;}a &lt; {x&#39;}&#39;");
-        assertOutput(
-                "${xmlPlain + htmlPlain + '\\''}",
-                "a &lt; {x&apos;}a &lt; {h&apos;}&apos;");
-        assertOutput(
-                "<#ftl outputFormat='XML'>${htmlPlain + xmlPlain + '\\''}",
-                "a &lt; {h&apos;}a &lt; {x&apos;}&apos;");
-        assertOutput(
-                "<#ftl outputFormat='RTF'>${htmlPlain + xmlPlain + '\\''}",
-                "a < \\{h'\\}a < \\{x'\\}'");
-        assertOutput(
-                "<#ftl outputFormat='XML'>${'\\'' + htmlPlain}",
-                "&apos;a &lt; {h&apos;}");
-        assertOutput(
-                "<#ftl outputFormat='HTML'>${'\\'' + htmlPlain}",
-                "&#39;a &lt; {h&#39;}");
-        assertOutput(
-                "<#ftl outputFormat='HTML'>${'\\'' + xmlPlain}",
-                "&#39;a &lt; {x&#39;}");
-        assertOutput(
-                "<#ftl outputFormat='RTF'>${'\\'' + xmlPlain}",
-                "'a < \\{x'\\}");
-        
-        assertOutput(
-                "<#assign x = '\\''><#assign x += xmlMarkup>${x}",
-                "&apos;<p>c</p>");
-        assertOutput(
-                "<#assign x = xmlMarkup><#assign x += '\\''>${x}",
-                "<p>c</p>&apos;");
-        assertOutput(
-                "<#assign x = xmlMarkup><#assign x += htmlPlain>${x}",
-                "<p>c</p>a &lt; {h&apos;}");
-        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>&amp; &amp; 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", "&lt;x&gt; &lt;x&gt; <x>");
-        assertOutputForNamed("t-noAuto.ftlh", "<x> &lt;x&gt; <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}",
-                "&amp; &amp; & &");
-        
-        for (String bi : new String[] { "esc", "noEsc" } ) {
-            assertOutput(
-                    xmlHdr + "${rtfPlain?" + bi + "}",
-                    "\\par a &amp; b");
-            assertOutput(
-                    xmlHdr + "<#setting numberFormat='0.0'>${1?" + bi + "}",
-                    "1.0");
-            assertOutput(
-                    xmlHdr + "<#setting booleanFormat='&y,&n'>${true?" + bi + "}",
-                    bi.equals("esc") ? "&amp;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 &lt; {h&#39;} <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&#39; XML&apos; HTML&#39; undefined'");
-        assertOutput(
-                "<#ftl output_format='XML'>"
-                + "${.output_format}${'\\''} "
-                + "<#outputformat 'HTML'>${.output_format}${'\\''}</#outputformat> "
-                + "${.output_format}${'\\''}",
-                "XML&apos; HTML&#39; XML&apos;");
-        
-        // Custom format:
-        assertErrorContains(
-                "<#outputFormat 'dummy'></#outputFormat>",
-                "dummy", "nregistered");
-        setConfiguration(new TestConfigurationBuilder()
-                .registeredCustomOutputFormats(Collections.<OutputFormat>singleton(DummyOutputFormat.INSTANCE))
-                .build());
-        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&amp; false& true&amp; false& true&amp;");
-        assertOutput(
-                "<#ftl auto_esc=false output_format='XML'>"
-                + "${.auto_esc?c}${'&'} "
-                + "<#autoesc>${.auto_esc?c}${'&'}</#autoesc> "
-                + "${.auto_esc?c}${'&'}",
-                "false& true&amp; false&");
-        
-        // Bad came case:
-        assertErrorContains(
-                "<#noAutoesc></#noAutoesc>",
-                "Unknown directive");
-        assertErrorContains(
-                "<#noautoEsc></#noautoEsc>",
-                "Unknown directive");
-
-        setConfiguration(new TestConfigurationBuilder()
-                .outputFormat(XMLOutputFormat.INSTANCE)
-                .build());
-        
-        // 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 {
-        TestConfigurationBuilder cfgB = createDefaultConfigurationBuilder();
-        cfgB.setRegisteredCustomOutputFormats(ImmutableList.<OutputFormat>of(
-                SeldomEscapedOutputFormat.INSTANCE, DummyOutputFormat.INSTANCE));
-        assertEquals(ENABLE_IF_DEFAULT_AUTO_ESCAPING_POLICY, cfgB.getAutoEscapingPolicy());
-        
-        String commonFTL = "${'.'} ${.autoEsc?c}";
-        String notEsced = ". false";
-        String esced = "\\. true";
-
-        for (int autoEscPolicy : new int[] {
-                ENABLE_IF_DEFAULT_AUTO_ESCAPING_POLICY,
-                ENABLE_IF_SUPPORTED_AUTO_ESCAPING_POLICY,
-                DISABLE_AUTO_ESCAPING_POLICY }) {
-            cfgB.setAutoEscapingPolicy(autoEscPolicy);
-            
-            String sExpted = autoEscPolicy == ENABLE_IF_SUPPORTED_AUTO_ESCAPING_POLICY ? esced : notEsced;
-            cfgB.setOutputFormat(SeldomEscapedOutputFormat.INSTANCE);
-            setConfiguration(cfgB.build());
-            assertOutput(commonFTL, sExpted);
-            cfgB.setOutputFormat(UndefinedOutputFormat.INSTANCE);
-            setConfiguration(cfgB.build());
-            assertOutput("<#ftl outputFormat='seldomEscaped'>" + commonFTL, sExpted);
-            assertOutput("<#outputFormat 'seldomEscaped'>" + commonFTL + "</#outputFormat>", sExpted);
-            
-            String dExpted = autoEscPolicy == DISABLE_AUTO_ESCAPING_POLICY ? notEsced : esced;
-            cfgB.setOutputFormat(DummyOutputFormat.INSTANCE);
-            setConfiguration(cfgB.build());
-            assertOutput(commonFTL, dExpted);
-            cfgB.setOutputFormat(UndefinedOutputFormat.INSTANCE);
-            setConfiguration(cfgB.build());
-            assertOutput("<#ftl outputFormat='dummy'>" + commonFTL, dExpted);
-            assertOutput("<#outputFormat 'dummy'>" + commonFTL + "</#outputFormat>", dExpted);
-            
-            cfgB.setOutputFormat(DummyOutputFormat.INSTANCE);
-            setConfiguration(cfgB.build());
-            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 ParsingConfiguration of the calling template, and ignore anything
-        // inside the calling template itself. Except, the outputFormat and autoEscapingPolicy 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 {&amp;}");
-        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 {&amp;}");
-        
-        // 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 {&amp;} 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" }) {
-            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 &lt; {h&#39;} <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 &lt; {h&#39;} <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 &lt; {x&apos;} <p>c</p>");
-        assertOutput("${htmlPlain?xml} ${htmlMarkup?xml}", "a &lt; {h&#39;} <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>",
-                "&amp;#39;");
-        assertOutput(
-                "<#outputFormat 'HTML{RTF{XML}}'>${'<a=\\'{}\\' />'}</#outputFormat>",
-                "&amp;lt;a=&amp;apos;\\{\\}&amp;apos; /&amp;gt;");
-        
-        String commonFtl = "${'\\''} <#outputFormat '{HTML}'>${'\\''}</#outputFormat>";
-        String commonOutput = "&apos; &amp;#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");
-    }
-
-    private TestConfigurationBuilder createDefaultConfigurationBuilder() throws TemplateModelException {
-        return new TestConfigurationBuilder()
-                .templateConfigurations(
-                        new ConditionalTemplateConfigurationFactory(
-                                new FileNameGlobMatcher("*.xml"),
-                                new TemplateConfiguration.Builder()
-                                        .outputFormat(XMLOutputFormat.INSTANCE)
-                                        .build()))
-                .cacheStorage(NullCacheStorage.INSTANCE); // Prevent caching as we change the cfgB between build().
-    }
-
-    @Before
-    public void addCommonDataModelVariables() throws TemplateModelException {
-        addToDataModel("rtfPlain", RTFOutputFormat.INSTANCE.fromPlainTextByEscaping("\\par a & b"));
-        addToDataModel("rtfMarkup", RTFOutputFormat.INSTANCE.fromMarkup("\\par c"));
-        addToDataModel("htmlPlain", HTMLOutputFormat.INSTANCE.fromPlainTextByEscaping("a < {h'}"));
-        addToDataModel("htmlMarkup", HTMLOutputFormat.INSTANCE.fromMarkup("<p>c"));
-        addToDataModel("xmlPlain", XMLOutputFormat.INSTANCE.fromPlainTextByEscaping("a < {x'}"));
-        addToDataModel("xmlMarkup", XMLOutputFormat.INSTANCE.fromMarkup("<p>c</p>"));
-    }
-
-    @Override
-    protected Configuration createDefaultConfiguration() throws TemplateModelException {
-        return createDefaultConfigurationBuilder().build();
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/ParseTimeParameterBIErrorMessagesTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/ParseTimeParameterBIErrorMessagesTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/ParseTimeParameterBIErrorMessagesTest.java
deleted file mode 100644
index 77b46de..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/ParseTimeParameterBIErrorMessagesTest.java
+++ /dev/null
@@ -1,46 +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;
-
-import org.apache.freemarker.test.TemplateTest;
-import org.junit.Test;
-
-public class ParseTimeParameterBIErrorMessagesTest extends TemplateTest {
-
-    @Test
-    public void testThen() throws Exception {
-        assertErrorContains("${true?then}", "expecting", "\"(\"");
-        assertErrorContains("${true?then + 1}", "expecting", "\"(\"");
-        assertErrorContains("${true?then()}", "?then", "2 parameters");
-        assertErrorContains("${true?then(1)}", "?then", "2 parameters");
-        assertOutput("${true?then(1, 2)}", "1");
-        assertErrorContains("${true?then(1, 2, 3)}", "?then", "2 parameters");
-    }
-
-    @Test
-    public void testSwitch() throws Exception {
-        assertErrorContains("${true?switch}", "expecting", "\"(\"");
-        assertErrorContains("${true?switch + 1}", "expecting", "\"(\"");
-        assertErrorContains("${true?switch()}", "at least 2 parameters");
-        assertErrorContains("${true?switch(true)}", "at least 2 parameters");
-        assertOutput("${true?switch(true, 1)}", "1");
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/ParsingErrorMessagesTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/ParsingErrorMessagesTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/ParsingErrorMessagesTest.java
deleted file mode 100644
index 8f20d6c..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/ParsingErrorMessagesTest.java
+++ /dev/null
@@ -1,116 +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;
-
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-
-import org.apache.freemarker.core.util._StringUtil;
-import org.apache.freemarker.test.TestConfigurationBuilder;
-import org.junit.Test;
-
-public class ParsingErrorMessagesTest {
-
-    private Configuration cfg = new TestConfigurationBuilder()
-            .tagSyntax(ParsingConfiguration.AUTO_DETECT_TAG_SYNTAX)
-            .build();
-
-    @Test
-    public void testNeedlessInterpolation() {
-        assertErrorContains("<#if ${x} == 3></#if>", "instead of ${");
-        assertErrorContains("<#if ${x == 3}></#if>", "instead of ${");
-        assertErrorContains("<@foo ${x == 3} />", "instead of ${");
-    }
-
-    @Test
-    public void testWrongDirectiveNames() {
-        assertErrorContains("<#foo />", "nknown directive", "#foo");
-        assertErrorContains("<#set x = 1 />", "nknown directive", "#set", "#assign");
-        assertErrorContains("<#iterator></#iterator>", "nknown directive", "#iterator", "#list");
-    }
-
-    @Test
-    public void testBug402() {
-        assertErrorContains("<#list 1..i as k>${k}<#list>", "existing directive", "malformed", "#list");
-        assertErrorContains("<#assign>", "existing directive", "malformed", "#assign");
-        assertErrorContains("</#if x>", "existing directive", "malformed", "#if");
-        assertErrorContains("<#compress x>", "existing directive", "malformed", "#compress");
-    }
-
-    @Test
-    public void testUnclosedDirectives() {
-        assertErrorContains("<#macro x>", "#macro", "unclosed");
-        assertErrorContains("<#function x>", "#macro", "unclosed");
-        assertErrorContains("<#assign x>", "#assign", "unclosed");
-        assertErrorContains("<#macro m><#local x>", "#local", "unclosed");
-        assertErrorContains("<#global x>", "#global", "unclosed");
-        assertErrorContains("<@foo>", "@...", "unclosed");
-        assertErrorContains("<#list xs as x>", "#list", "unclosed");
-        assertErrorContains("<#list xs as x><#if x>", "#if", "unclosed");
-        assertErrorContains("<#list xs as x><#if x><#if q><#else>", "#if", "unclosed");
-        assertErrorContains("<#list xs as x><#if x><#if q><#else><#macro x>qwe", "#macro", "unclosed");
-        assertErrorContains("${(blah", "\"(\"", "unclosed");
-        assertErrorContains("${blah", "\"{\"", "unclosed");
-    }
-    
-    @Test
-    public void testInterpolatingClosingsErrors() {
-        assertErrorContains("${x", "unclosed");
-        assertErrorContains("<#assign x = x}>", "\"}\"", "open");
-        // TODO assertErrorContains("<#assign x = '${x'>", "unclosed");
-    }
-    
-    private void assertErrorContains(String ftl, String... expectedSubstrings) {
-        assertErrorContains(false, ftl, expectedSubstrings);
-        assertErrorContains(true, ftl, expectedSubstrings);
-    }
-
-    private void assertErrorContains(boolean squareTags, String ftl, String... expectedSubstrings) {
-        try {
-            if (squareTags) {
-                ftl = ftl.replace('<', '[').replace('>', ']');
-            }
-            new Template("adhoc", ftl, cfg);
-            fail("The template had to fail");
-        } catch (ParseException e) {
-            String msg = e.getMessage();
-            for (String needle: expectedSubstrings) {
-                if (needle.startsWith("\\!")) {
-                    String netNeedle = needle.substring(2); 
-                    if (msg.contains(netNeedle)) {
-                        fail("The message shouldn't contain substring " + _StringUtil.jQuote(netNeedle) + ":\n" + msg);
-                    }
-                } else if (!msg.contains(needle)) {
-                    fail("The message didn't contain substring " + _StringUtil.jQuote(needle) + ":\n" + msg);
-                }
-            }
-            showError(e);
-        } catch (IOException e) {
-            // Won't happen
-            throw new RuntimeException(e);
-        }
-    }
-    
-    private void showError(Throwable e) {
-        //System.out.println(e);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/RestrictedObjectWrapperTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/RestrictedObjectWrapperTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/RestrictedObjectWrapperTest.java
deleted file mode 100644
index 702a254..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/RestrictedObjectWrapperTest.java
+++ /dev/null
@@ -1,72 +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;
-
-import static org.apache.freemarker.test.hamcerst.Matchers.*;
-import static org.junit.Assert.*;
-
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashSet;
-
-import javax.annotation.PostConstruct;
-
-import org.apache.freemarker.core.model.TemplateBooleanModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.impl.DefaultArrayAdapter;
-import org.apache.freemarker.core.model.impl.DefaultListAdapter;
-import org.apache.freemarker.core.model.impl.DefaultMapAdapter;
-import org.apache.freemarker.core.model.impl.DefaultNonListCollectionAdapter;
-import org.apache.freemarker.core.model.impl.DefaultObjectWrapperTest.TestBean;
-import org.apache.freemarker.core.model.impl.RestrictedObjectWrapper;
-import org.apache.freemarker.core.model.impl.SimpleDate;
-import org.apache.freemarker.core.model.impl.SimpleNumber;
-import org.apache.freemarker.core.model.impl.SimpleScalar;
-import org.junit.Test;
-
-public class RestrictedObjectWrapperTest {
-
-    @Test
-    public void testBasics() throws TemplateModelException {
-        PostConstruct.class.toString();
-        RestrictedObjectWrapper ow = new RestrictedObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
-        testCustomizationCommonPart(ow);
-        assertTrue(ow.wrap(Collections.emptyMap()) instanceof DefaultMapAdapter);
-        assertTrue(ow.wrap(Collections.emptyList()) instanceof DefaultListAdapter);
-        assertTrue(ow.wrap(new boolean[] { }) instanceof DefaultArrayAdapter);
-        assertTrue(ow.wrap(new HashSet()) instanceof DefaultNonListCollectionAdapter);
-    }
-
-    @SuppressWarnings("boxing")
-    private void testCustomizationCommonPart(RestrictedObjectWrapper ow) throws TemplateModelException {
-        assertTrue(ow.wrap("x") instanceof SimpleScalar);
-        assertTrue(ow.wrap(1.5) instanceof SimpleNumber);
-        assertTrue(ow.wrap(new Date()) instanceof SimpleDate);
-        assertEquals(TemplateBooleanModel.TRUE, ow.wrap(true));
-        
-        try {
-            ow.wrap(new TestBean());
-            fail();
-        } catch (TemplateModelException e) {
-            assertThat(e.getMessage(), containsStringIgnoringCase("type"));
-        }
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/RestrictedObjetWrapperTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/RestrictedObjetWrapperTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/RestrictedObjetWrapperTest.java
deleted file mode 100644
index 43ff3bf..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/RestrictedObjetWrapperTest.java
+++ /dev/null
@@ -1,112 +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;
-
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.StringReader;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-
-import org.apache.freemarker.core.model.TemplateBooleanModel;
-import org.apache.freemarker.core.model.TemplateCollectionModel;
-import org.apache.freemarker.core.model.TemplateCollectionModelEx;
-import org.apache.freemarker.core.model.TemplateDateModel;
-import org.apache.freemarker.core.model.TemplateHashModelEx2;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateModelWithAPISupport;
-import org.apache.freemarker.core.model.TemplateNumberModel;
-import org.apache.freemarker.core.model.TemplateScalarModel;
-import org.apache.freemarker.core.model.TemplateSequenceModel;
-import org.apache.freemarker.core.model.impl.RestrictedObjectWrapper;
-import org.junit.Test;
-import org.w3c.dom.Document;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-
-public class RestrictedObjetWrapperTest {
-    
-    @Test
-    public void testDoesNotAllowAPIBuiltin() throws TemplateModelException {
-        RestrictedObjectWrapper sow = new RestrictedObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
-        
-        TemplateModelWithAPISupport map = (TemplateModelWithAPISupport) sow.wrap(new HashMap());
-        try {
-            map.getAPI();
-            fail();
-        } catch (TemplateException e) {
-            assertThat(e.getMessage(), containsString("?api"));
-        }
-    }
-
-    @SuppressWarnings("boxing")
-    @Test
-    public void testCanWrapBasicTypes() throws TemplateModelException {
-        RestrictedObjectWrapper sow = new RestrictedObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
-        assertTrue(sow.wrap("s") instanceof TemplateScalarModel);
-        assertTrue(sow.wrap(1) instanceof TemplateNumberModel);
-        assertTrue(sow.wrap(true) instanceof TemplateBooleanModel);
-        assertTrue(sow.wrap(new Date()) instanceof TemplateDateModel);
-        assertTrue(sow.wrap(new ArrayList()) instanceof TemplateSequenceModel);
-        assertTrue(sow.wrap(new String[0]) instanceof TemplateSequenceModel);
-        assertTrue(sow.wrap(new ArrayList().iterator()) instanceof TemplateCollectionModel);
-        assertTrue(sow.wrap(new HashSet()) instanceof TemplateCollectionModelEx);
-        assertTrue(sow.wrap(new HashMap()) instanceof TemplateHashModelEx2);
-        assertNull(sow.wrap(null));
-    }
-    
-    @Test
-    public void testWontWrapDOM() throws SAXException, IOException, ParserConfigurationException,
-            TemplateModelException {
-        DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
-        InputSource is = new InputSource();
-        is.setCharacterStream(new StringReader("<doc><sub a='1' /></doc>"));
-        Document doc = db.parse(is);
-        
-        RestrictedObjectWrapper sow = new RestrictedObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
-        try {
-            sow.wrap(doc);
-            fail();
-        } catch (TemplateModelException e) {
-            assertThat(e.getMessage(), containsString("won't wrap"));
-        }
-    }
-    
-    @Test
-    public void testWontWrapGenericObjects() {
-        RestrictedObjectWrapper sow = new RestrictedObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
-        try {
-            sow.wrap(new File("/x"));
-            fail();
-        } catch (TemplateModelException e) {
-            assertThat(e.getMessage(), containsString("won't wrap"));
-        }
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/SQLTimeZoneTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/SQLTimeZoneTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/SQLTimeZoneTest.java
deleted file mode 100644
index cf14b93..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/SQLTimeZoneTest.java
+++ /dev/null
@@ -1,371 +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;
-
-import static org.junit.Assert.*;
-
-import java.sql.Time;
-import java.sql.Timestamp;
-import java.text.DateFormat;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Locale;
-import java.util.TimeZone;
-
-import org.apache.freemarker.core.util._DateUtil;
-import org.apache.freemarker.test.TemplateTest;
-import org.junit.Test;
-
-public class SQLTimeZoneTest extends TemplateTest {
-
-    private final static TimeZone GMT_P02 = TimeZone.getTimeZone("GMT+02");
-    
-    private TimeZone lastDefaultTimeZone;
-
-    private final DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US);
-    {
-        df.setTimeZone(_DateUtil.UTC);
-    }
-    
-    // Values that JDBC in GMT+02 would produce
-    private final java.sql.Date sqlDate = new java.sql.Date(utcToLong("2014-07-11T22:00:00")); // 2014-07-12
-    private final Time sqlTime = new Time(utcToLong("1970-01-01T10:30:05")); // 12:30:05
-    private final Timestamp sqlTimestamp = new Timestamp(utcToLong("2014-07-12T10:30:05")); // 2014-07-12T12:30:05
-    private final Date javaDate = new Date(utcToLong("2014-07-12T10:30:05")); // 2014-07-12T12:30:05
-    private final Date javaDayErrorDate = new Date(utcToLong("2014-07-11T22:00:00")); // 2014-07-12T12:30:05
-    
-    public TimeZone getLastDefaultTimeZone() {
-        return lastDefaultTimeZone;
-    }
-
-    public void setLastDefaultTimeZone(TimeZone lastDefaultTimeZone) {
-        this.lastDefaultTimeZone = lastDefaultTimeZone;
-    }
-
-    public java.sql.Date getSqlDate() {
-        return sqlDate;
-    }
-
-    public Time getSqlTime() {
-        return sqlTime;
-    }
-
-    public Timestamp getSqlTimestamp() {
-        return sqlTimestamp;
-    }
-
-    public Date getJavaDate() {
-        return javaDate;
-    }
-    
-    public Date getJavaDayErrorDate() {
-        return javaDayErrorDate;
-    }
-
-    private static final String FTL =
-            "${sqlDate} ${sqlTime} ${sqlTimestamp} ${javaDate?datetime}\n"
-            + "${sqlDate?string.iso_fz} ${sqlTime?string.iso_fz} "
-            + "${sqlTimestamp?string.iso_fz} ${javaDate?datetime?string.iso_fz}\n"
-            + "${sqlDate?string.xs_fz} ${sqlTime?string.xs_fz} "
-            + "${sqlTimestamp?string.xs_fz} ${javaDate?datetime?string.xs_fz}\n"
-            + "${sqlDate?string.xs} ${sqlTime?string.xs} "
-            + "${sqlTimestamp?string.xs} ${javaDate?datetime?string.xs}\n"
-            + "<#setting time_zone='GMT'>\n"
-            + "${sqlDate} ${sqlTime} ${sqlTimestamp} ${javaDate?datetime}\n"
-            + "${sqlDate?string.iso_fz} ${sqlTime?string.iso_fz} "
-            + "${sqlTimestamp?string.iso_fz} ${javaDate?datetime?string.iso_fz}\n"
-            + "${sqlDate?string.xs_fz} ${sqlTime?string.xs_fz} "
-            + "${sqlTimestamp?string.xs_fz} ${javaDate?datetime?string.xs_fz}\n"
-            + "${sqlDate?string.xs} ${sqlTime?string.xs} "
-            + "${sqlTimestamp?string.xs} ${javaDate?datetime?string.xs}\n";
-
-    private static final String OUTPUT_BEFORE_SETTING_GMT_CFG_GMT2
-            = "2014-07-12 12:30:05 2014-07-12T12:30:05 2014-07-12T12:30:05\n"
-            + "2014-07-12 12:30:05+02:00 2014-07-12T12:30:05+02:00 2014-07-12T12:30:05+02:00\n"
-            + "2014-07-12+02:00 12:30:05+02:00 2014-07-12T12:30:05+02:00 2014-07-12T12:30:05+02:00\n"
-            + "2014-07-12 12:30:05 2014-07-12T12:30:05+02:00 2014-07-12T12:30:05+02:00\n";
-
-    private static final String OUTPUT_BEFORE_SETTING_GMT_CFG_GMT1_SQL_DIFFERENT
-            = "2014-07-12 12:30:05 2014-07-12T11:30:05 2014-07-12T11:30:05\n"
-            + "2014-07-12 12:30:05+02:00 2014-07-12T11:30:05+01:00 2014-07-12T11:30:05+01:00\n"
-            + "2014-07-12+02:00 12:30:05+02:00 2014-07-12T11:30:05+01:00 2014-07-12T11:30:05+01:00\n"
-            + "2014-07-12 12:30:05 2014-07-12T11:30:05+01:00 2014-07-12T11:30:05+01:00\n";
-
-    private static final String OUTPUT_BEFORE_SETTING_GMT_CFG_GMT1_SQL_SAME
-            = "2014-07-11 11:30:05 2014-07-12T11:30:05 2014-07-12T11:30:05\n"
-            + "2014-07-11 11:30:05+01:00 2014-07-12T11:30:05+01:00 2014-07-12T11:30:05+01:00\n"
-            + "2014-07-11+01:00 11:30:05+01:00 2014-07-12T11:30:05+01:00 2014-07-12T11:30:05+01:00\n"
-            + "2014-07-11 11:30:05 2014-07-12T11:30:05+01:00 2014-07-12T11:30:05+01:00\n";
-    
-    private static final String OUTPUT_AFTER_SETTING_GMT_CFG_SQL_SAME
-            = "2014-07-11 10:30:05 2014-07-12T10:30:05 2014-07-12T10:30:05\n"
-            + "2014-07-11 10:30:05Z 2014-07-12T10:30:05Z 2014-07-12T10:30:05Z\n"
-            + "2014-07-11Z 10:30:05Z 2014-07-12T10:30:05Z 2014-07-12T10:30:05Z\n"
-            + "2014-07-11 10:30:05 2014-07-12T10:30:05Z 2014-07-12T10:30:05Z\n";
-    
-    private static final String OUTPUT_AFTER_SETTING_GMT_CFG_SQL_DIFFERENT
-            = "2014-07-12 12:30:05 2014-07-12T10:30:05 2014-07-12T10:30:05\n"
-            + "2014-07-12 12:30:05+02:00 2014-07-12T10:30:05Z 2014-07-12T10:30:05Z\n"
-            + "2014-07-12+02:00 12:30:05+02:00 2014-07-12T10:30:05Z 2014-07-12T10:30:05Z\n"
-            + "2014-07-12 12:30:05 2014-07-12T10:30:05Z 2014-07-12T10:30:05Z\n";
-    
-    @Test
-    public void testWithDefaultTZAndNullSQL() throws Exception {
-        TimeZone prevSysDefTz = TimeZone.getDefault();
-        TimeZone.setDefault(GMT_P02);
-        try {
-            Configuration.ExtendableBuilder<?> cfgB = createConfigurationBuilder();
-            cfgB.unsetTimeZone();
-            setConfiguration(cfgB.build());
-
-            assertNull(getConfiguration().getSQLDateAndTimeTimeZone());
-            assertEquals(TimeZone.getDefault(), getConfiguration().getTimeZone());
-            
-            assertOutput(FTL, OUTPUT_BEFORE_SETTING_GMT_CFG_GMT2 + OUTPUT_AFTER_SETTING_GMT_CFG_SQL_SAME);
-        } finally {
-            TimeZone.setDefault(prevSysDefTz);
-        }
-    }
-
-    @Test
-    public void testWithDefaultTZAndGMT2SQL() throws Exception {
-        TimeZone prevSysDefTz = TimeZone.getDefault();
-        TimeZone.setDefault(GMT_P02);
-        try {
-            Configuration.ExtendableBuilder<?> cfgB = createConfigurationBuilder();
-            cfgB.sqlDateAndTimeTimeZone(GMT_P02).unsetTimeZone();
-            setConfiguration(cfgB.build());
-
-            assertOutput(FTL, OUTPUT_BEFORE_SETTING_GMT_CFG_GMT2 + OUTPUT_AFTER_SETTING_GMT_CFG_SQL_DIFFERENT);
-        } finally {
-            TimeZone.setDefault(prevSysDefTz);
-        }
-    }
-    
-    @Test
-    public void testWithGMT1AndNullSQL() throws Exception {
-        setConfiguration(createConfigurationBuilder()
-                .timeZone(TimeZone.getTimeZone("GMT+01:00"))
-                .build());
-        assertNull(getConfiguration().getSQLDateAndTimeTimeZone());
-
-        assertOutput(FTL, OUTPUT_BEFORE_SETTING_GMT_CFG_GMT1_SQL_SAME + OUTPUT_AFTER_SETTING_GMT_CFG_SQL_SAME);
-    }
-
-    @Test
-    public void testWithGMT1AndGMT2SQL() throws Exception {
-        setConfiguration(createConfigurationBuilder()
-                .sqlDateAndTimeTimeZone(GMT_P02)
-                .timeZone(TimeZone.getTimeZone("GMT+01:00"))
-                .build());
-
-        assertOutput(FTL, OUTPUT_BEFORE_SETTING_GMT_CFG_GMT1_SQL_DIFFERENT + OUTPUT_AFTER_SETTING_GMT_CFG_SQL_DIFFERENT);
-    }
-
-    @Test
-    public void testWithGMT2AndNullSQL() throws Exception {
-        setConfiguration(createConfigurationBuilder()
-                .timeZone(TimeZone.getTimeZone("GMT+02"))
-                .build());
-        assertNull(getConfiguration().getSQLDateAndTimeTimeZone());
-
-        assertOutput(FTL, OUTPUT_BEFORE_SETTING_GMT_CFG_GMT2 + OUTPUT_AFTER_SETTING_GMT_CFG_SQL_SAME);
-    }
-
-    @Test
-    public void testWithGMT2AndGMT2SQL() throws Exception {
-        setConfiguration(createConfigurationBuilder()
-            .sqlDateAndTimeTimeZone(GMT_P02)
-            .timeZone(TimeZone.getTimeZone("GMT+02"))
-            .build());
-        
-        assertOutput(FTL, OUTPUT_BEFORE_SETTING_GMT_CFG_GMT2 + OUTPUT_AFTER_SETTING_GMT_CFG_SQL_DIFFERENT);
-    }
-    
-    @Test
-    public void testCacheFlushings() throws Exception {
-        Configuration.ExtendableBuilder<?> cfgB = createConfigurationBuilder()
-                .timeZone(_DateUtil.UTC)
-                .dateFormat("yyyy-MM-dd E")
-                .timeFormat("HH:mm:ss E")
-                .dateTimeFormat("yyyy-MM-dd'T'HH:mm:ss E");
-
-        setConfiguration(cfgB.build());
-        assertOutput(
-                "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}, ${javaDate?date}, ${javaDate?time}\n"
-                + "<#setting locale='de'>\n"
-                + "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}, ${javaDate?date}, ${javaDate?time}\n",
-                "2014-07-11 Fri, 10:30:05 Thu, 2014-07-12T10:30:05 Sat, 2014-07-12T10:30:05 Sat, 2014-07-12 Sat, 10:30:05 Sat\n"
-                + "2014-07-11 Fr, 10:30:05 Do, 2014-07-12T10:30:05 Sa, 2014-07-12T10:30:05 Sa, 2014-07-12 Sa, 10:30:05 Sa\n");
-        assertOutput(
-                "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}, ${javaDate?date}, ${javaDate?time}\n"
-                + "<#setting date_format='yyyy-MM-dd'>\n"
-                + "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}, ${javaDate?date}, ${javaDate?time}\n",
-                "2014-07-11 Fri, 10:30:05 Thu, 2014-07-12T10:30:05 Sat, 2014-07-12T10:30:05 Sat, 2014-07-12 Sat, 10:30:05 Sat\n"
-                + "2014-07-11, 10:30:05 Thu, 2014-07-12T10:30:05 Sat, 2014-07-12T10:30:05 Sat, 2014-07-12, 10:30:05 Sat\n");
-        assertOutput(
-                "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}, ${javaDate?date}, ${javaDate?time}\n"
-                + "<#setting time_format='HH:mm:ss'>\n"
-                + "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}, ${javaDate?date}, ${javaDate?time}\n",
-                "2014-07-11 Fri, 10:30:05 Thu, 2014-07-12T10:30:05 Sat, 2014-07-12T10:30:05 Sat, 2014-07-12 Sat, 10:30:05 Sat\n"
-                + "2014-07-11 Fri, 10:30:05, 2014-07-12T10:30:05 Sat, 2014-07-12T10:30:05 Sat, 2014-07-12 Sat, 10:30:05\n");
-        assertOutput(
-                "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}, ${javaDate?date}, ${javaDate?time}\n"
-                + "<#setting datetime_format='yyyy-MM-dd\\'T\\'HH:mm:ss'>\n"
-                + "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}, ${javaDate?date}, ${javaDate?time}\n",
-                "2014-07-11 Fri, 10:30:05 Thu, 2014-07-12T10:30:05 Sat, 2014-07-12T10:30:05 Sat, 2014-07-12 Sat, 10:30:05 Sat\n"
-                + "2014-07-11 Fri, 10:30:05 Thu, 2014-07-12T10:30:05, 2014-07-12T10:30:05, 2014-07-12 Sat, 10:30:05 Sat\n");
-
-        setConfiguration(cfgB.sqlDateAndTimeTimeZone(GMT_P02).build());
-        assertOutput(
-                "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}, ${javaDate?date}, ${javaDate?time}\n"
-                + "<#setting locale='de'>\n"
-                + "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}, ${javaDate?date}, ${javaDate?time}\n",
-                "2014-07-12 Sat, 12:30:05 Thu, 2014-07-12T10:30:05 Sat, 2014-07-12T10:30:05 Sat, 2014-07-12 Sat, 10:30:05 Sat\n"
-                + "2014-07-12 Sa, 12:30:05 Do, 2014-07-12T10:30:05 Sa, 2014-07-12T10:30:05 Sa, 2014-07-12 Sa, 10:30:05 Sa\n");
-        assertOutput(
-                "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}, ${javaDate?date}, ${javaDate?time}\n"
-                + "<#setting date_format='yyyy-MM-dd'>\n"
-                + "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}, ${javaDate?date}, ${javaDate?time}\n",
-                "2014-07-12 Sat, 12:30:05 Thu, 2014-07-12T10:30:05 Sat, 2014-07-12T10:30:05 Sat, 2014-07-12 Sat, 10:30:05 Sat\n"
-                + "2014-07-12, 12:30:05 Thu, 2014-07-12T10:30:05 Sat, 2014-07-12T10:30:05 Sat, 2014-07-12, 10:30:05 Sat\n");
-        assertOutput(
-                "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}, ${javaDate?date}, ${javaDate?time}\n"
-                + "<#setting time_format='HH:mm:ss'>\n"
-                + "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}, ${javaDate?date}, ${javaDate?time}\n",
-                "2014-07-12 Sat, 12:30:05 Thu, 2014-07-12T10:30:05 Sat, 2014-07-12T10:30:05 Sat, 2014-07-12 Sat, 10:30:05 Sat\n"
-                + "2014-07-12 Sat, 12:30:05, 2014-07-12T10:30:05 Sat, 2014-07-12T10:30:05 Sat, 2014-07-12 Sat, 10:30:05\n");
-        assertOutput(
-                "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}, ${javaDate?date}, ${javaDate?time}\n"
-                + "<#setting datetime_format='yyyy-MM-dd\\'T\\'HH:mm:ss'>\n"
-                + "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}, ${javaDate?date}, ${javaDate?time}\n",
-                "2014-07-12 Sat, 12:30:05 Thu, 2014-07-12T10:30:05 Sat, 2014-07-12T10:30:05 Sat, 2014-07-12 Sat, 10:30:05 Sat\n"
-                + "2014-07-12 Sat, 12:30:05 Thu, 2014-07-12T10:30:05, 2014-07-12T10:30:05, 2014-07-12 Sat, 10:30:05 Sat\n");
-    }
-
-    @Test
-    public void testDateAndTimeBuiltInsHasNoEffect() throws Exception {
-        setConfiguration(createConfigurationBuilder()
-                .timeZone(_DateUtil.UTC)
-                .sqlDateAndTimeTimeZone(GMT_P02)
-                .build());
-
-        assertOutput(
-                "${javaDayErrorDate?date} ${javaDayErrorDate?time} ${sqlTimestamp?date} ${sqlTimestamp?time} "
-                + "${sqlDate?date} ${sqlTime?time}\n"
-                + "<#setting time_zone='GMT+02'>\n"
-                + "${javaDayErrorDate?date} ${javaDayErrorDate?time} ${sqlTimestamp?date} ${sqlTimestamp?time} "
-                + "${sqlDate?date} ${sqlTime?time}\n"
-                + "<#setting time_zone='GMT-11'>\n"
-                + "${javaDayErrorDate?date} ${javaDayErrorDate?time} ${sqlTimestamp?date} ${sqlTimestamp?time} "
-                + "${sqlDate?date} ${sqlTime?time}\n",
-                "2014-07-11 22:00:00 2014-07-12 10:30:05 2014-07-12 12:30:05\n"
-                + "2014-07-12 00:00:00 2014-07-12 12:30:05 2014-07-12 12:30:05\n"
-                + "2014-07-11 11:00:00 2014-07-11 23:30:05 2014-07-12 12:30:05\n");
-    }
-
-    @Test
-    public void testChangeSettingInTemplate() throws Exception {
-        setConfiguration(createConfigurationBuilder()
-                .timeZone(_DateUtil.UTC)
-                .build());
-
-        assertNull(getConfiguration().getSQLDateAndTimeTimeZone());
-
-        assertOutput(
-                "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}\n"
-                + "<#setting sql_date_and_time_time_zone='GMT+02'>\n"
-                + "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}\n"
-                + "<#setting sql_date_and_time_time_zone='null'>\n"
-                + "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}\n"
-                + "<#setting time_zone='GMT+03'>\n"
-                + "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}\n"
-                + "<#setting sql_date_and_time_time_zone='GMT+02'>\n"
-                + "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}\n"
-                + "<#setting sql_date_and_time_time_zone='GMT-11'>\n"
-                + "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}\n"
-                + "<#setting date_format='xs fz'>\n"
-                + "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}\n"
-                + "<#setting time_format='xs fz'>\n"
-                + "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}\n"
-                + "<#setting datetime_format='iso m'>\n"
-                + "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}\n",
-                "2014-07-11, 10:30:05, 2014-07-12T10:30:05, 2014-07-12T10:30:05\n"
-                + "2014-07-12, 12:30:05, 2014-07-12T10:30:05, 2014-07-12T10:30:05\n"
-                + "2014-07-11, 10:30:05, 2014-07-12T10:30:05, 2014-07-12T10:30:05\n"
-                + "2014-07-12, 13:30:05, 2014-07-12T13:30:05, 2014-07-12T13:30:05\n"
-                + "2014-07-12, 12:30:05, 2014-07-12T13:30:05, 2014-07-12T13:30:05\n"
-                + "2014-07-11, 23:30:05, 2014-07-12T13:30:05, 2014-07-12T13:30:05\n"
-                + "2014-07-11-11:00, 23:30:05, 2014-07-12T13:30:05, 2014-07-12T13:30:05\n"
-                + "2014-07-11-11:00, 23:30:05-11:00, 2014-07-12T13:30:05, 2014-07-12T13:30:05\n"
-                + "2014-07-11-11:00, 23:30:05-11:00, 2014-07-12T13:30+03:00, 2014-07-12T13:30+03:00\n");
-    }
-    
-    @Test
-    public void testFormatUTCFlagHasNoEffect() throws Exception {
-        setConfiguration(createConfigurationBuilder()
-                .sqlDateAndTimeTimeZone(GMT_P02)
-                .timeZone(TimeZone.getTimeZone("GMT-01"))
-                .build());
-        
-        assertOutput(
-                "<#setting date_format='xs fz'><#setting time_format='xs fz'>\n"
-                + "${sqlDate}, ${sqlTime}, ${javaDate?time}\n"
-                + "<#setting date_format='xs fz u'><#setting time_format='xs fz u'>\n"
-                + "${sqlDate}, ${sqlTime}, ${javaDate?time}\n"
-                + "<#setting sql_date_and_time_time_zone='GMT+03'>\n"
-                + "${sqlDate}, ${sqlTime}, ${javaDate?time}\n"
-                + "<#setting sql_date_and_time_time_zone='null'>\n"
-                + "${sqlDate}, ${sqlTime}, ${javaDate?time}\n"
-                + "<#setting date_format='xs fz'><#setting time_format='xs fz'>\n"
-                + "${sqlDate}, ${sqlTime}, ${javaDate?time}\n"
-                + "<#setting date_format='xs fz fu'><#setting time_format='xs fz fu'>\n"
-                + "${sqlDate}, ${sqlTime}, ${javaDate?time}\n",
-                "2014-07-12+02:00, 12:30:05+02:00, 09:30:05-01:00\n"
-                + "2014-07-12+02:00, 12:30:05+02:00, 10:30:05Z\n"
-                + "2014-07-12+03:00, 13:30:05+03:00, 10:30:05Z\n"
-                + "2014-07-11-01:00, 09:30:05-01:00, 10:30:05Z\n"
-                + "2014-07-11-01:00, 09:30:05-01:00, 09:30:05-01:00\n"
-                + "2014-07-11Z, 10:30:05Z, 10:30:05Z\n");
-    }
-
-    private Configuration.ExtendableBuilder<?> createConfigurationBuilder() {
-        return new Configuration.Builder(Configuration.VERSION_3_0_0)
-                .locale(Locale.US)
-                .dateFormat("yyyy-MM-dd")
-                .timeFormat("HH:mm:ss")
-                .dateTimeFormat("yyyy-MM-dd'T'HH:mm:ss");
-    }
-
-    @Override
-    protected Object createDataModel() {
-        return this;
-    }
-
-    private long utcToLong(String isoDateTime) {
-        try {
-            return df.parse(isoDateTime).getTime();
-        } catch (ParseException e) {
-            throw new RuntimeException(e);
-        }
-    }
-    
-}


[24/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/type-builtins.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/type-builtins.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/type-builtins.ftl
new file mode 100644
index 0000000..cb0f576
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/type-builtins.ftl
@@ -0,0 +1,44 @@
+<#--
+  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.
+-->
+<#setting boolean_format="1,0">
+StNuBoMeTaMaHaHxSeCoCxEnInDiNo
+<#list [
+  "a", 1, false,
+  testmethod, testmacro, html_escape,
+  {"a":1}, [1], testcollection, testcollectionEx,
+  testnode,
+  bean, bean.m, bean.mOverloaded
+] as x>
+  ${x?is_string} <#t>
+  ${x?is_number} <#t>
+  ${x?is_boolean} <#t>
+  ${x?is_method} <#t>
+  ${x?is_macro} <#t>
+  ${x?is_transform} <#t>
+  ${x?is_hash} <#t>
+  ${x?is_hash_ex} <#t>
+  ${x?is_sequence} <#t>
+  ${x?is_collection} <#t>
+  ${x?is_collection_ex} <#t>
+  ${x?is_enumerable} <#t>
+  ${x?is_indexable} <#t>
+  ${x?is_directive} <#t>
+  ${x?is_node}<#lt>
+</#list>
+<#macro testmacro></#macro>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/undefined.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/undefined.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/undefined.ftl
new file mode 100644
index 0000000..2ca96ac
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/undefined.ftl
@@ -0,0 +1,19 @@
+<#--
+  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.
+-->
+${undefined_variable}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/url.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/url.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/url.ftl
new file mode 100644
index 0000000..814de80
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/url.ftl
@@ -0,0 +1,24 @@
+<#--
+  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.
+-->
+<#setting url_escaping_charset="utf-8">
+<#assign s = 'a/báb?c/x;y=1' />
+<@assertEquals expected='a%2Fb%E1b%3Fc%2Fx%3By%3D1' actual=s?url('ISO-8859-1') />
+<@assertEquals expected='a%2Fb%C3%A1b%3Fc%2Fx%3By%3D1' actual=s?url />
+<@assertEquals expected='a/b%E1b%3Fc/x%3By%3D1' actual=s?url_path('ISO-8859-1') />
+<@assertEquals expected='a/b%C3%A1b%3Fc/x%3By%3D1' actual=s?url_path />
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/var-layers.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/var-layers.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/var-layers.ftl
new file mode 100644
index 0000000..25333de
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/var-layers.ftl
@@ -0,0 +1,39 @@
+<#--
+  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.
+-->
+<#import "varlayers_lib.ftl" as lib>
+<@foo 1/>
+${x} = ${.data_model.x} = ${.globals.x}
+<#assign x = 5>
+${x} = ${.main.x} = ${.namespace.x}
+<#global x = 6>
+${.globals.x} but ${.data_model.x} = 4
+${y} = ${.globals.y} = ${.data_model.y?default("ERROR")}
+Invisiblity test 1.: <#if .main.y?exists || .namespace.y?exists>failed<#else>passed</#if>
+Invisiblity test 2.: <#if .main.z?exists || .namespace.z?exists>failed<#else>passed</#if>
+Invisiblity test 3.: <#global q = 1><#if .main.q?exists || .namespace.q?exists || .data_model.q?exists>failed<#else>passed</#if>
+--
+<@lib.foo/>
+--
+<#macro foo x>
+  ${x} = ${.locals.x}
+  <#local x = 2>
+  ${x} = ${.locals.x}
+  <#local y = 3>
+  ${y} = ${.locals.y}
+</#macro>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/varargs.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/varargs.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/varargs.ftl
new file mode 100644
index 0000000..5e79aa7
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/varargs.ftl
@@ -0,0 +1,45 @@
+<#--
+  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.
+-->
+<#setting number_format="#">
+
+${m.bar()} == 0
+${m.bar([])} == 0
+${m.bar(11)} == 11
+${m.bar(null, 11)} == 11
+${m.bar(11, 22)} == 1122
+${m.bar(11.6, 22.4)} == 1122
+${m.bar(11, 22, 33)} == 112233
+${m.bar([11, 22, 33])} == 112233
+
+${m.bar2(11, [22, 33, 44])} == -22334411
+${m.bar2(11, 22, 33)} == -223311
+${m.bar2(11, 22)} == -2211
+${m.bar2(11)} == -11
+
+${m.overloaded()} == 0
+${m.overloaded(11)} == -11
+${m.overloaded(11, 22)} == 1122
+${m.overloaded(11, 22, 33)} == -112233
+${m.overloaded(11, 22, 33, 44)} == -11223344
+${m.overloaded([11, 22, 33, 44, 55])} == -1122334455
+
+${m.overloaded(11, 22)} == 1122
+${m.overloaded([11, 22])} == -1122
+
+${m.noVarArgs("string", true, 123, 1000000?number_to_date)} == string, true, 123, 1000000

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/variables.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/variables.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/variables.ftl
new file mode 100644
index 0000000..b927381
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/variables.ftl
@@ -0,0 +1,70 @@
+[#ftl]
+[#--
+  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.
+--]
+<html>
+<head>
+<title>FreeMarker: Variable Test</title>
+</head>
+<body>
+[#assign list = ["one", "two", "three", "four", "five"]]
+[#assign hash = {"output" : "My message.", "key" : list}]
+[#assign hash2 = {"value" : hash}]
+[#assign items = {"mykey" : "key", "_test", "out"}]
+
+<p>A simple test follows:</p>
+
+<p>${message}</p>
+
+<p>Now get into variable nesting:</p>
+
+<p>${hash.output}</p>
+<p>${hash["output"]}</p>
+<p>${hash. output}</p>
+<p>${hash .output}</p>
+<p>${hash 
+    .output}</p>
+<p>${hash 
+    . output}</p>
+<p>${hash ["output"]}</p>
+<p>${hash
+    [ "output" ]}</p>
+
+<p>More deep nesting...</p>
+
+<p>${hash2.value.output}</p>
+<p>${hash2.value.key[0]}</p>
+<p>${hash2["value"]["key"][0]}</p>
+
+
+<p>Nesting inside nesting...</p>
+
+<p>${hash2.value[ items.mykey ][ 1 ]}</p>
+<p>${hash2.value[ items[ "mykey" ]][ 1 ]}</p>
+<p>${hash2.value[ items[ "my" + items.mykey ]][ 1 ]}</p>
+<p>${hash2.value[ items[ "my" + items["mykey"] ]][ 1 ]}</p>
+
+<p>Test underscores...</p>
+
+<p>${items[ "_test" ]}</p>
+<p>${items._test}</p>
+
+${"God save the queen."?word_list[1]?upper_case}
+
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/varlayers_lib.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/varlayers_lib.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/varlayers_lib.ftl
new file mode 100644
index 0000000..9a1a471
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/varlayers_lib.ftl
@@ -0,0 +1,28 @@
+<#--
+  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.
+-->
+<#assign x1 = .data_model.x>
+<#assign x2 = x>
+<#assign z2 = z>
+<#macro foo>
+<@.main.foo 1/>
+  ${z} = ${z2} = ${x1} = ${.data_model.x}
+  5
+  ${x} == ${.globals.x}
+  ${y} == ${.globals.y} == ${.data_model.y?default("ERROR")}
+</#macro>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/whitespace-trim.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/whitespace-trim.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/whitespace-trim.ftl
new file mode 100644
index 0000000..9c10dd9
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/whitespace-trim.ftl
@@ -0,0 +1,102 @@
+<#--
+  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.
+-->
+  LB<#lt>
+  LB<#lt>
+	LB<#lt>
+LB<#lt>
+  IB
+  IC1<#rt>
+  IC2<#rt>
+C1<#rt>
+C2<#rt>
+  ICS <#rt>
+CS1 <#rt>
+  CS2 <#t>
+  C3<#t>
+  C1<#t>
+C2
+B
+B
+  C1<#t>
+CB
+C1
+  C2<#t>
+  ICB
+  IC<#rt>
+  ICB
+  IC<#rt>
+  CB<#lt>
+--
+<#macro x t>${t}</#macro>
+  ${""}<@x t="LB"/><#lt>
+  <@x t="LB"/><#lt>${""}
+	<@x t="LB"/><#lt>${""}
+<@x t="LB"/><#lt>${""}
+  <@x t="IB"/>${""}
+${""}  <@x t="IC1"/><#rt>
+  <@x t="IC2"/><#rt>${""}
+${""}<@x t="C1"/><#rt>
+<@x t="C2"/><#rt>${""}
+  <@x t="ICS"/> <#rt>${""}
+<@x t="CS1"/> <#rt>${""}
+  <@x t="CS2"/> <#t>${""}
+  <@x t="C3"/><#t>
+  <@x t="C1"/><#t>
+<@x t="C2"/>${""}
+<#nt><@x t="B"/>
+<@x t="B"/><#nt>
+  <@x t="C1"/><#t>
+<@x t="CB"/>${""}
+<@x t="C1"/>${""}
+  <@x t="C2"/><#t>${""}
+  <@x t="ICB"/>${""}
+  ${""}<@x t="IC"/><#rt>
+  <@x t="ICB"/>${""}
+${""}  <@x t="IC"/><#rt>
+  <@x t="CB"/>${""}<#lt>
+--
+   <#lt>  IB
+  IC1<#rt>
+  <#assign x = 1> <#-- just a comment -->
+  C2<#t>
+  <#assign x = 1>
+  IB
+1<#t>
+  <#assign x = 1>
+2
+---
+<#t>1
+  <#t> 2
+  <#lt>3
+  4
+  <#rt>5
+  6
+---
+a
+  <#assign x = 1><#t>
+b<#t>  
+c
+---
+  <#if true>
+    <#t>foo
+  </#if>
+---
+  <#if true><#-- just a comment -->
+    foo<#t>
+  </#if>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/wsstripinheader_inc.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/wsstripinheader_inc.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/wsstripinheader_inc.ftl
new file mode 100644
index 0000000..03cbfbe
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/wsstripinheader_inc.ftl
@@ -0,0 +1,22 @@
+<#ftl strip_whitespace="yes">
+<#--
+  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.
+-->
+a
+<#assign x = 1>
+b
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/wstrip-in-header.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/wstrip-in-header.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/wstrip-in-header.ftl
new file mode 100644
index 0000000..0dce83c
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/wstrip-in-header.ftl
@@ -0,0 +1,26 @@
+
+  
+
+  <#ftl strip_whitespace="no">
+<#--
+  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.
+-->
+a
+<#assign x = 1>
+b
+<#include "wsstripinheader_inc.ftl">
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/xml-fragment.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/xml-fragment.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/xml-fragment.ftl
new file mode 100644
index 0000000..226215b
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/xml-fragment.ftl
@@ -0,0 +1,26 @@
+<#ftl ns_prefixes = {"n" : "http://x"}>
+<#--
+  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.
+-->
+${node?node_name} = b
+${node?root?node_name} = @document
+${node['/']?node_name} = @document
+
+${node['n:c']} = C<>&"']]>
+
+${node?root.@@markup}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/xml-ns_prefix-scope-lib.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/xml-ns_prefix-scope-lib.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/xml-ns_prefix-scope-lib.ftl
new file mode 100644
index 0000000..0f0bde2
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/xml-ns_prefix-scope-lib.ftl
@@ -0,0 +1,23 @@
+<#ftl ns_prefixes={ "n": "http://freemarker.org/test/bar", "D": "http://freemarker.org/test/namespace-test" }>
+<#--
+  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.
+-->
+<#global libResult>//n:e: ${doc['//n:e']}, ${doc.root['n:e']}</#global>
+<#macro m>
+//n:e: ${doc['//n:e']}, ${doc.root['n:e']}
+</#macro>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/xml-ns_prefix-scope-main.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/xml-ns_prefix-scope-main.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/xml-ns_prefix-scope-main.ftl
new file mode 100644
index 0000000..5b7ce24
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/xml-ns_prefix-scope-main.ftl
@@ -0,0 +1,36 @@
+<#ftl ns_prefixes={
+    "D": "http://freemarker.org/test/namespace-test",
+    "n": "http://freemarker.org/test/foo",
+    "bar": "http://freemarker.org/test/bar"
+}>
+<#--
+  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.
+-->
+//e: ${doc['//D:e']}, ${doc.root.e}
+//n:e: ${doc['//n:e']}, ${doc.root['n:e']}
+//bar:e: ${doc['//bar:e']}, ${doc.root['bar:e']}
+
+Included:
+<#include "xml-ns_prefix-scope-lib.ftl">
+${libResult}
+<@m />
+
+Imported:
+<#import "xml-ns_prefix-scope-lib.ftl" as lib>
+${libResult}
+<@lib.m />

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/xml.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/xml.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/xml.ftl
new file mode 100644
index 0000000..b85fc03
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/xml.ftl
@@ -0,0 +1,47 @@
+<#--
+  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.
+-->
+<#-- test processing instructions -->
+<#global PIs = doc._content._ftype("p")>
+<#list PIs as pi>
+  ${pi}
+  ${pi["@target"]._text}
+  ${pi["@data"]._text}
+</#list>
+${PIs?size}
+<#global firstPi = PIs[0]>
+${firstPi._type}
+${firstPi["@customKey"]}
+${doc._registerNamespace("ns", "http://www.foo.com/ns1/")}
+${doc._descendant["ns:e11"]}
+${doc._descendant["ns:e12"]}
+<#global docRoot = doc["ns:root"]>
+${docRoot["ns:e1"]}
+${doc("//ns:e11")}
+${docRoot["ns:e1"]["@a1"]._name}
+${docRoot["ns:e1"]["@a2"]._text}
+${docRoot._children._parent._name}
+${docRoot._children._parent._unique._name}
+<#list doc._descendant as d>
+  ${d._name}
+</#list>
+<#list doc._descendant._ancestorOrSelf as d>
+  ${d._name}
+</#list>
+${docRoot["ns:e2"]["ns:e12"]._text}
+${docRoot["ns:e2"]["ns:e12"]._plaintext}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/xmlns1.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/xmlns1.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/xmlns1.ftl
new file mode 100644
index 0000000..8aa893e
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/xmlns1.ftl
@@ -0,0 +1,53 @@
+<#ftl ns_prefixes = {"D" : "http://example.com/eBook"}>
+<#--
+  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.
+-->
+
+${doc.@@markup}
+
+<#recurse doc >
+
+<#macro book>
+  <html>
+    <head>
+      <title><#recurse .node.title></title>
+    </head>
+    <body>
+      <h1><#recurse .node.title></h1>
+      <#recurse>
+    </body>
+  </html>
+</#macro>
+
+<#macro chapter>
+  <h2><#recurse .node.title></h2>
+  <#recurse>
+</#macro>
+
+<#macro para>
+  <p><#recurse>
+</#macro>
+
+<#macro title>
+  <#--
+    We have handled this element imperatively,
+    so we do nothing here.
+  -->
+</#macro>
+
+<#macro @text>${.node?html}</#macro>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/xmlns3.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/xmlns3.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/xmlns3.ftl
new file mode 100644
index 0000000..c84ec69
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/xmlns3.ftl
@@ -0,0 +1,70 @@
+<#ftl ns_prefixes = {"x" : "http://x", "y" : "http://y"}>
+<#--
+  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.
+-->
+<#recurse doc >
+
+<#macro book>
+  <html>
+    <head>
+      <title><#recurse .node["x:title"]></title>
+    </head>
+    <body>
+      <h1><#recurse .node["x:title"]></h1>
+      <#recurse>
+    </body>
+  </html>
+</#macro>
+
+<#macro chapter>
+  <h2><#recurse .node["y:title"]></h2>
+  <#recurse>
+</#macro>
+
+<#macro "x:chapter">
+  <h2><#recurse .node["y:title"]></h2>
+  <#recurse>
+</#macro>
+
+<#macro para>
+  <p><#recurse>
+</#macro>
+
+<#macro "x:para">
+  <p><#recurse>
+</#macro>
+
+<#macro "y:para">
+  <p><#recurse>
+</#macro>
+
+<#macro "x:title">
+  <#--
+    We have handled this element imperatively,
+    so we do nothing here.
+  -->
+</#macro>
+
+<#macro "y:title">
+  <#--
+    We have handled this element imperatively,
+    so we do nothing here.
+  -->
+</#macro>
+
+<#macro @text>${.node?html}</#macro>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/xmlns4.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/xmlns4.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/xmlns4.ftl
new file mode 100644
index 0000000..e97bfc0
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/xmlns4.ftl
@@ -0,0 +1,70 @@
+<#ftl ns_prefixes = {"x" : "http://x", "y" : "http://y"}>
+<#--
+  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.
+-->
+<#recurse doc >
+
+<#macro book>
+  <html>
+    <head>
+      <title><#recurse .node["x:title"]></title>
+    </head>
+    <body>
+      <h1><#recurse .node["x:title"]></h1>
+      <#recurse>
+    </body>
+  </html>
+</#macro>
+
+<#macro chapter>
+  <h2><#recurse .node["y:title"]></h2>
+  <#recurse>
+</#macro>
+
+<#macro 'x:chapter'>
+  <h2><#recurse .node["y:title"]></h2>
+  <#recurse>
+</#macro>
+
+<#macro para>
+  <p><#recurse>
+</#macro>
+
+<#macro 'x:para'>
+  <p><#recurse>
+</#macro>
+
+<#macro 'y:para'>
+  <p><#recurse>
+</#macro>
+
+<#macro "x:title">
+  <#--
+    We have handled this element imperatively,
+    so we do nothing here.
+  -->
+</#macro>
+
+<#macro "y:title">
+  <#--
+    We have handled this element imperatively,
+    so we do nothing here.
+  -->
+</#macro>
+
+<#macro @text>${.node?html}</#macro>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/xmlns5.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/xmlns5.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/xmlns5.ftl
new file mode 100644
index 0000000..edc3b4a
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/xmlns5.ftl
@@ -0,0 +1,28 @@
+<#ftl ns_prefixes = {"D": "http://y.com", "xx" : "http://x.com"}>
+<#--
+  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.
+-->
+<#assign r = doc["N:root"]>
+${r["N:t1"][0]?default('-')} = No NS
+${r["xx:t2"][0]?default('-')} = x NS
+${r["t3"][0]?default('-')} = y NS
+${r["xx:t4"][0]?default('-')} = x NS
+${r["//t1"][0]?default('-')} = No NS
+${r["//t2"][0]?default('-')} = -
+${r["//t3"][0]?default('-')} = -
+${r["//t4"][0]?default('-')} = -

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/testcases.xml
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/testcases.xml b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/testcases.xml
new file mode 100644
index 0000000..2cfe290
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/testcases.xml
@@ -0,0 +1,211 @@
+<?xml version="1.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.
+-->
+
+<!DOCTYPE testCases [
+  <!ELEMENT testCases (setting?, testCase*)>
+  <!ELEMENT testCase (setting?)>
+     <!ATTLIST testCase 
+               name CDATA #REQUIRED
+               template CDATA #IMPLIED
+               expected CDATA #IMPLIED
+               noOutput CDATA #IMPLIED
+     >
+     <!-- The default of `template` is "${name?keep_before('[#endTN]')}.ftl" -->
+     <!-- The default of `expected` is "${name}.txt" -->
+     <!-- The default of `noOutput` is false -->
+     
+ <!ELEMENT setting EMPTY>
+     <!ATTLIST setting 
+            auto_import CDATA #IMPLIED
+            source_encoding CDATA #IMPLIED
+            locale CDATA #IMPLIED
+            object_wrapper CDATA #IMPLIED
+            output_encoding CDATA #IMPLIED
+            output_dir CDATA #IMPLIED
+            new_builtin_class_resolver CDATA #IMPLIED
+            url_escaping_charset CDATA #IMPLIED
+            incompatible_improvements CDATA #IMPLIED
+            time_zone CDATA #IMPLIED
+            api_builtin_enabled CDATA #IMPLIED
+      >
+]>
+<!--
+Note that for the incompatible_improvements setting you can specify a list of versions, for example:
+<setting incompatible_improvements="min, 3.0.5, max" /> 
+-->
+
+<testCases>
+   <setting source_encoding="UTF-8" output_encoding="UTF-8" />
+   
+   <testCase name="api-builtins" noOutput="true">
+      <setting api_builtin_enabled="true" />
+   </testCase>
+   <testCase name="arithmetic" />
+   <testCase name="assignments" noOutput="true" />
+   <testCase name="boolean" />
+   <testCase name="charset-in-header" />
+   <testCase name="comment" />
+   <testCase name="comparisons" />
+   <testCase name="compress" />
+   <testCase name="then-builtin" noOutput="true" />
+   <testCase name="dateformat-java" />
+   <testCase name="dateformat-iso-like" noOutput="true" />
+   <testCase name="dateformat-iso-bi" noOutput="true" />
+   <testCase name="dateparsing" noOutput="true" />
+   <testCase name="default"/>
+   <testCase name="default-object-wrapper">
+      <setting api_builtin_enabled="true" />
+   </testCase>
+   <testCase name="default-xmlns" />
+   <testCase name="encoding-builtins" />
+   <testCase name="escapes" />
+   <testCase name="hashliteral" />
+   <testCase name="identifier-non-ascii" />
+   <testCase name="identifier-escaping" />
+   <testCase name="import">
+      <setting auto_import="import_lib.ftl as my"/>
+   </testCase>
+   <testCase name="include" />
+   <testCase name="include2">
+      <setting source_encoding="utf-8" />
+   </testCase>
+   <testCase name="interpret"/>
+   <testCase name="iterators"/>
+   <testCase name="lastcharacter"/>
+   <testCase name="list[#endTN]-simpleTemplateModels" expected="list.txt">
+      <setting object_wrapper="org.apache.freemarker.test.templatesuite.models.SimpleMapAndCollectionObjectWrapper(3.0.0)" />
+   </testCase>
+   <testCase name="list[#endTN]-collectionAdapter" expected="list.txt">
+      <setting object_wrapper="DefaultObjectWrapper(3.0.0)" />
+   </testCase>
+   <testCase name="list2[#endTN]-simpleTemplateModels" expected="list2.txt">
+      <setting object_wrapper="org.apache.freemarker.test.templatesuite.models.SimpleMapAndCollectionObjectWrapper(3.0.0)" />
+   </testCase>
+   <testCase name="list2[#endTN]-collectionAdapter" expected="list2.txt">
+      <setting object_wrapper="DefaultObjectWrapper(3.0.0)" />
+   </testCase>
+   <testCase name="list3[#endTN]-simpleTemplateModels" expected="list3.txt">
+      <setting object_wrapper="org.apache.freemarker.test.templatesuite.models.SimpleMapAndCollectionObjectWrapper(3.0.0)" />
+   </testCase>
+   <testCase name="list3[#endTN]-collectionAdapter" expected="list3.txt">
+      <setting object_wrapper="DefaultObjectWrapper(3.0.0)" />
+   </testCase>
+   <testCase name="list-bis" />
+   <testCase name="list-bis[#endTN]-collectionAdapter" expected="list-bis.txt">
+      <setting object_wrapper="DefaultObjectWrapper(3.0.0)" />
+   </testCase>
+   <testCase name="listhash" />
+   <testCase name="listhashliteral" />
+   <testCase name="listliteral" />
+   <testCase name="localization" >
+      <setting locale="en_AU"/>
+   </testCase>
+   <testCase name="loopvariable" />
+   <testCase name="macros"/>
+   <testCase name="macros2"/>
+   <testCase name="macros-return"/>
+   <testCase name="multimodels"/>
+   <testCase name="nested" />
+   <testCase name="newlines1" />
+   <testCase name="newlines2" />
+   <testCase name="noparse" />
+   <testCase name="number-format" />
+   <testCase name="number-literal" >
+      <setting locale="fr_FR"/>
+   </testCase>
+   <testCase name="numerical-cast" />
+   <testCase name="output-encoding1"/>
+   <testCase name="output-encoding2">
+       <setting output_encoding="UTF-16"/>
+   </testCase>
+   <testCase name="output-encoding3">
+       <setting output_encoding="ISO-8859-1" url_escaping_charset="UTF-16" />
+   </testCase>
+   <testCase name="precedence"/>
+   <testCase name="range" noOutput="true" />
+   <testCase name="recover" />
+   <testCase name="root" />
+   <testCase name="setting" noOutput="true" />
+   <testCase name="sequence-builtins[#endTN]-with-SimpleTemplateModel" expected="sequence-builtins.txt">
+      <setting object_wrapper="org.apache.freemarker.test.templatesuite.models.SimpleMapAndCollectionObjectWrapper(3.0.0)" />
+   </testCase>
+   <testCase name="sequence-builtins[#endTN]-with-DefaultObjectWrapper" expected="sequence-builtins.txt">
+      <setting object_wrapper="default"/> 
+   </testCase>
+   <testCase name="sequence-builtins[#endTN]-with-DefaultObjectWrapper-collAdapters" expected="sequence-builtins.txt">
+      <setting object_wrapper="DefaultObjectWrapper(3.0.0)"/>
+   </testCase>
+   <testCase name="simplehash-char-key" noOutput="true" />
+   <testCase name="existence-operators" noOutput="true" />
+   <testCase name="string-builtins1" />
+   <testCase name="string-builtins2" />
+   <testCase name="string-builtins3" noOutput="true" />
+   <testCase name="string-builtins-regexps" />
+   <testCase name="string-builtins-regexps-matches" />
+   <testCase name="stringbimethods" />
+   <testCase name="stringliteral"/>
+   <testCase name="if" />
+   <testCase name="switch" />
+   <testCase name="switch-builtin" noOutput="true" />
+   <testCase name="transforms"/>
+   <testCase name="type-builtins" />
+   <testCase name="date-type-builtins" noOutput="true" />
+   <testCase name="url" noOutput="true" />
+   <testCase name="var-layers"/>
+   <testCase name="variables"/>
+   <testCase name="whitespace-trim"/>
+   <testCase name="wstrip-in-header"/>
+   <testCase name="xml-fragment" />
+   <testCase name="xmlns1" />
+   <testCase name="xmlns2" template="xmlns1.ftl"  expected="xmlns1.txt" />
+   <testCase name="xmlns3" />
+   <testCase name="xmlns4" />
+   <testCase name="xmlns5" />
+   <testCase name="xml-ns_prefix-scope" template="xml-ns_prefix-scope-main.ftl" />
+   <testCase name="hashconcat"/>
+   <testCase name="new-defaultresolver" />
+   <testCase name="new-unrestricted" template="new-defaultresolver.ftl" expected="new-defaultresolver.txt">
+      <setting new_builtin_class_resolver="unrestricted"/>
+   </testCase>   
+   <testCase name="new-allowsnothing" template="new-defaultresolver.ftl">
+      <setting new_builtin_class_resolver="allows_nothing"/>
+   </testCase>   
+   <testCase name="new-optin">
+      <setting new_builtin_class_resolver="
+      		allowed_classes: org.apache.freemarker.test.templatesuite.models.NewTestModel,
+      		trusted_templates: subdir/new-optin.ftl, subdir/subsub/*"
+      />
+   </testCase>   
+   <testCase name="specialvars">
+      <setting locale="en_US" output_encoding="utf-8" url_escaping_charset="iso-8859-1"/>
+   </testCase>   
+   <testCase name="number-to-date" />
+   <testCase name="varargs" />
+   <testCase name="boolean-formatting"  />
+   <testCase name="number-math-builtins" noOutput="true" />
+   <testCase name="string-builtin-coercion" noOutput="true" />
+   
+   <testCase name="overloaded-methods[#endTN]-inc-dow" noOutput="true">
+      <setting object_wrapper="org.apache.freemarker.core.model.impl.DefaultObjectWrapperInc"/>
+   </testCase>
+   <testCase name="overloaded-methods[#endTN]-desc-dow" noOutput="true">
+      <setting object_wrapper="org.apache.freemarker.core.model.impl.DefaultObjectWrapperDesc"/>
+   </testCase>
+</testCases>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/README.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/README.txt b/freemarker-core/src/test/README.txt
new file mode 100644
index 0000000..fe68269
--- /dev/null
+++ b/freemarker-core/src/test/README.txt
@@ -0,0 +1,7 @@
+The tests were moved to the freemarker-core-test and freemarker-core-test-java8 projects.
+(This was necessary to avoid dependency loops. Some utility classes that are useful for testing
+the core are also useful for testing the other modules. This those classes had to be moved into
+a separate module, freemarker-test-utils, which however depends on freemarker-core to provide
+template testing facilities and such. Hence, freemarker-core can't depend on freemarker-test-utils,
+yet the classes in it are needed for testing freemarker-core, thus, yet another project had to be
+added.)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/ASTBasedErrorMessagesTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/ASTBasedErrorMessagesTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/ASTBasedErrorMessagesTest.java
deleted file mode 100644
index 10d63b3..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/ASTBasedErrorMessagesTest.java
+++ /dev/null
@@ -1,74 +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;
-
-import java.util.Map;
-
-import org.apache.freemarker.test.TemplateTest;
-import org.junit.Test;
-
-public class ASTBasedErrorMessagesTest extends TemplateTest {
-    
-    @Test
-    public void testInvalidRefBasic() {
-        assertErrorContains("${foo}", "foo", "specify a default");
-        assertErrorContains("${map[foo]}", "foo", "\\!map[", "specify a default");
-    }
-    
-    @Test
-    public void testInvalidRefDollar() {
-        assertErrorContains("${$x}", "$x", "must not start with \"$\"", "specify a default");
-        assertErrorContains("${map.$x}", "map.$x", "must not start with \"$\"", "specify a default");
-    }
-
-    @Test
-    public void testInvalidRefAfterDot() {
-        assertErrorContains("${map.foo.bar}", "map.foo", "\\!foo.bar", "after the last dot", "specify a default");
-    }
-
-    @Test
-    public void testInvalidRefInSquareBrackets() {
-        assertErrorContains("${map['foo']}", "map", "final [] step", "specify a default");
-    }
-
-    @Test
-    public void testInvalidRefSize() {
-        assertErrorContains("${map.size()}", "map.size", "?size", "specify a default");
-        assertErrorContains("${map.length()}", "map.length", "?length", "specify a default");
-    }
-
-    @Override
-    protected Object createDataModel() {
-        Map<String, Object> dataModel = createCommonTestValuesDataModel();
-        dataModel.put("overloads", new Overloads());
-        return dataModel;
-    }
-    
-    public static class Overloads {
-        
-        @SuppressWarnings("unused")
-        public void m(String s) {}
-        
-        @SuppressWarnings("unused")
-        public void m(int i) {}
-        
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/ASTPrinter.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/ASTPrinter.java b/freemarker-core/src/test/java/org/apache/freemarker/core/ASTPrinter.java
deleted file mode 100644
index 3518b29..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/ASTPrinter.java
+++ /dev/null
@@ -1,438 +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;
-
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.io.Writer;
-import java.nio.ByteBuffer;
-import java.nio.charset.CharacterCodingException;
-import java.nio.charset.Charset;
-import java.nio.charset.CodingErrorAction;
-import java.nio.charset.StandardCharsets;
-import java.util.Enumeration;
-import java.util.regex.Pattern;
-import java.util.regex.PatternSyntaxException;
-
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.util.FTLUtil;
-import org.apache.freemarker.core.util._ClassUtil;
-import org.apache.freemarker.core.util._StringUtil;
-import org.apache.freemarker.test.TestConfigurationBuilder;
-
-/**
- * Static methods and command-line tool for printing the AST of a template. 
- */
-public class ASTPrinter {
-
-    private final Configuration cfg;
-    private int successfulCounter;
-    private int failedCounter;
-    
-    static public void main(String[] args) throws IOException {
-        if (args.length == 0) {
-            usage();
-            System.exit(-1);
-        }
-        
-        ASTPrinter astp = new ASTPrinter(); 
-        if (args[0].equalsIgnoreCase("-r")) {
-            astp.mainRecursive(args);
-        } else {
-            astp.mainSingleTemplate(args);
-        }
-    }
-    
-    private ASTPrinter() {
-        cfg = new TestConfigurationBuilder(Configuration.VERSION_3_0_0).build();
-    }
-    
-    private void mainSingleTemplate(String[] args) throws IOException, FileNotFoundException {
-        final String templateFileName;
-        final String templateContent;
-        if (args[0].startsWith("ftl:")) {
-            templateFileName = null;
-            templateContent = args[0];
-        } else {
-            templateFileName = args[0];
-            templateContent = null;
-        }
-        
-        Template t = new Template(
-                templateFileName,
-                templateFileName == null ? new StringReader(templateContent) : new FileReader(templateFileName),
-                cfg);
-        
-        p(getASTAsString(t));
-    }
-
-    private void mainRecursive(String[] args) throws IOException {
-        if (args.length != 4) {
-            p("Number of arguments must be 4, but was: " + args.length);
-            usage();
-            System.exit(-1);
-        }
-        
-        final String srcDirPath = args[1].trim();
-        File srcDir = new File(srcDirPath);
-        if (!srcDir.isDirectory()) {
-            p("This should be an existing directory: " + srcDirPath);
-            System.exit(-1);
-        }
-        
-        Pattern fnPattern;
-        try {
-            fnPattern = Pattern.compile(args[2]);
-        } catch (PatternSyntaxException e) {
-            p(_StringUtil.jQuote(args[2]) + " is not a valid regular expression");
-            System.exit(-1);
-            return;
-        }
-        
-        final String dstDirPath = args[3].trim();
-        File dstDir = new File(dstDirPath);
-        if (!dstDir.isDirectory()) {
-            p("This should be an existing directory: " + dstDirPath);
-            System.exit(-1);
-        }
-        
-        long startTime = System.currentTimeMillis();
-        recurse(srcDir, fnPattern, dstDir);
-        long endTime = System.currentTimeMillis();
-        
-        p("Templates successfully processed " + successfulCounter + ", failed " + failedCounter
-                + ". Time taken: " + (endTime - startTime) / 1000.0 + " s");
-    }
-    
-    private void recurse(File srcDir, Pattern fnPattern, File dstDir) throws IOException {
-        File[] files = srcDir.listFiles();
-        if (files == null) {
-            throw new IOException("Failed to kust directory: " + srcDir);
-        }
-        for (File file : files) {
-            if (file.isDirectory()) {
-                recurse(file, fnPattern, new File(dstDir, file.getName()));
-            } else {
-                if (fnPattern.matcher(file.getName()).matches()) {
-                    File dstFile = new File(dstDir, file.getName());
-                    String res;
-                    try {
-                        Template t = new Template(file.getPath().replace('\\', '/'), loadIntoString(file), cfg);
-                        res = getASTAsString(t);
-                        successfulCounter++;
-                    } catch (ParseException e) {
-                        res = "<<<FAILED>>>\n" + e.getMessage();
-                        failedCounter++;
-                        p("");
-                        p("-------------------------failed-------------------------");
-                        p("Error message was saved into: " + dstFile.getAbsolutePath());
-                        p("");
-                        p(e.getMessage());
-                    }
-                    save(res, dstFile);
-                }
-            }
-        }
-    }
-
-    private String loadIntoString(File file) throws IOException {
-        long ln = file.length();
-        if (ln < 0) {
-            throw new IOException("Failed to get the length of " + file);
-        }
-        byte[] buffer = new byte[(int) ln];
-        InputStream in = new FileInputStream(file);
-        try {
-            int offset = 0;
-            int bytesRead;
-            while (offset < buffer.length) {
-                bytesRead = in.read(buffer, offset, buffer.length - offset);
-                if (bytesRead == -1) {
-                    throw new IOException("Unexpected end of file: " + file);
-                }
-                offset += bytesRead;
-            }
-        } finally {
-            in.close();
-        }
-        
-        try {
-            return decode(buffer, StandardCharsets.UTF_8);
-        } catch (CharacterCodingException e) {
-            return decode(buffer, StandardCharsets.ISO_8859_1);
-        }
-    }
-
-    private String decode(byte[] buffer, Charset charset) throws CharacterCodingException {
-        return charset.newDecoder()
-                .onMalformedInput(CodingErrorAction.REPORT).onUnmappableCharacter(CodingErrorAction.REPORT)
-                .decode(ByteBuffer.wrap(buffer)).toString();
-    }
-
-    private void save(String astStr, File file) throws IOException {
-        File parentDir = file.getParentFile();
-        if (!parentDir.isDirectory() && !parentDir.mkdirs()) {
-            throw new IOException("Failed to invoke parent directory: " + parentDir);
-        }
-        
-        Writer w = new BufferedWriter(new FileWriter(file));
-        try {
-            w.write(astStr);
-        } finally {
-            w.close();
-        }
-    }
-
-    private static void usage() {
-        p("Prints template Abstract Syntax Tree (AST) as plain text.");
-        p("Usage:");
-        p("    java org.apache.freemarker.core.PrintAST <templateFile>");
-        p("    java org.apache.freemarker.core.PrintAST ftl:<templateSource>");
-        p("    java org.apache.freemarker.core.PrintAST -r <src-directory> <regexp> <dst-directory>");
-    }
-
-    private static final String INDENTATION = "    ";
-
-    public static String getASTAsString(String ftl) throws IOException {
-        return getASTAsString(ftl, (Options) null);
-    }
-    
-    public static String getASTAsString(String ftl, Options opts) throws IOException {
-        return getASTAsString(null, ftl, opts);
-    }
-
-    public static String getASTAsString(String templateName, String ftl) throws IOException {
-        return getASTAsString(templateName, ftl, null);
-    }
-    
-    public static String getASTAsString(String templateName, String ftl, Options opts) throws IOException {
-        Template t = new Template(templateName, ftl, new TestConfigurationBuilder().build());
-        return getASTAsString(t, opts);
-    }
-
-    public static String getASTAsString(Template t) throws IOException {
-        return getASTAsString(t, null);
-    }
-
-    public static String getASTAsString(Template t, Options opts) throws IOException {
-        validateAST(t);
-        
-        StringWriter out = new StringWriter();
-        printNode(t.getRootASTNode(), "", null, opts != null ? opts : Options.DEFAULT_INSTANCE, out);
-        return out.toString();
-    }
-    
-    public static void validateAST(Template t) throws InvalidASTException {
-        final ASTElement node = t.getRootASTNode();
-        if (node.getParent() != null) {
-            throw new InvalidASTException("Root node parent must be null."
-                    + "\nRoot node: " + node.dump(false)
-                    + "\nParent"
-                    + ": " + node.getParent().getClass() + ", " + node.getParent().dump(false));
-        }
-        validateAST(node);
-    }
-
-    private static void validateAST(ASTElement te) {
-        int childCount = te.getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            ASTElement child = te.getChild(i);
-            ASTElement parentElement = child.getParent();
-            // As ASTImplicitParent.accept does nothing but returns its children, it's optimized out in the final
-            // AST tree. While it will be present as a child, the parent element also will have children
-            // that contains the children of the ASTImplicitParent directly. 
-            if (parentElement instanceof ASTImplicitParent && parentElement.getParent() != null) {
-                parentElement = parentElement.getParent();
-            }
-            if (parentElement != te) {
-                throw new InvalidASTException("Wrong parent node."
-                        + "\nNode: " + child.dump(false)
-                        + "\nExpected parent: " + te.dump(false)
-                        + "\nActual parent: " + parentElement.dump(false));
-            }
-            if (child.getIndex() != i) {
-                throw new InvalidASTException("Wrong node index."
-                        + "\nNode: " + child.dump(false)
-                        + "\nExpected index: " + i
-                        + "\nActual index: " + child.getIndex());
-            }
-        }
-        if (te instanceof ASTImplicitParent && te.getChildCount() < 2) {
-            throw new InvalidASTException("Mixed content with child count less than 2 should removed by optimizatoin, "
-                    + "but found one with " + te.getChildCount() + " child(ren).");
-        }
-        ASTElement[] children = te.getChildBuffer();
-        if (children != null) {
-            if (childCount == 0) {
-                throw new InvalidASTException(
-                        "Children must be null when childCount is 0."
-                        + "\nNode: " + te.dump(false));
-            }
-            for (int i = 0; i < te.getChildCount(); i++) {
-                if (children[i] == null) {
-                    throw new InvalidASTException(
-                            "Child can't be null at index " + i
-                            + "\nNode: " + te.dump(false));
-                }
-            }
-            for (int i = te.getChildCount(); i < children.length; i++) {
-                if (children[i] != null) {
-                    throw new InvalidASTException(
-                            "Children can't be non-null at index " + i
-                            + "\nNode: " + te.dump(false));
-                }
-            }
-        } else {
-            if (childCount != 0) {
-                throw new InvalidASTException(
-                        "Children mustn't be null when child count isn't 0."
-                        + "\nNode: " + te.dump(false));
-            }
-        }
-    }
-
-    private static void printNode(Object node, String ind, ParameterRole paramRole, Options opts, Writer out) throws IOException {
-        if (node instanceof ASTNode) {
-            ASTNode tObj = (ASTNode) node;
-
-            printNodeLineStart(paramRole, ind, out);
-            out.write(tObj.getNodeTypeSymbol());
-            printNodeLineEnd(node, out, opts);
-            
-            if (opts.getShowConstantValue() && node instanceof ASTExpression) {
-                TemplateModel tm = ((ASTExpression) node).constantValue;
-                if (tm != null) {
-                    out.write(INDENTATION);
-                    out.write(ind);
-                    out.write("= const ");
-                    out.write(FTLUtil.getTypeDescription(tm));
-                    out.write(' ');
-                    out.write(tm.toString());
-                    out.write('\n');
-                }
-            }
-            
-            int paramCnt = tObj.getParameterCount();
-            for (int i = 0; i < paramCnt; i++) {
-                ParameterRole role = tObj.getParameterRole(i);
-                if (role == null) throw new NullPointerException("parameter role");
-                Object value = tObj.getParameterValue(i);
-                printNode(value, ind + INDENTATION, role, opts, out);
-            }
-            if (tObj instanceof ASTElement) {
-                Enumeration enu = ((ASTElement) tObj).children();
-                while (enu.hasMoreElements()) {
-                    printNode(enu.nextElement(), INDENTATION + ind, null, opts, out);
-                }
-            }
-        } else {
-            printNodeLineStart(paramRole, ind, out);
-            out.write(_StringUtil.jQuote(node));
-            printNodeLineEnd(node, out, opts);
-        }
-    }
-
-    protected static void printNodeLineEnd(Object node, Writer out, Options opts) throws IOException {
-        boolean commentStared = false;
-        if (opts.getShowJavaClass()) {
-            out.write("  // ");
-            commentStared = true;
-            out.write(_ClassUtil.getShortClassNameOfObject(node, true));
-        }
-        if (opts.getShowLocation() && node instanceof ASTNode) {
-            if (!commentStared) {
-                out.write("  // ");
-                commentStared = true;
-            } else {
-                out.write("; ");
-            }
-            ASTNode tObj = (ASTNode) node;
-            out.write("Location " + tObj.beginLine + ":" + tObj.beginColumn + "-" + tObj.endLine + ":" + tObj.endColumn);
-        }
-        out.write('\n');
-    }
-
-    private static void printNodeLineStart(ParameterRole paramRole, String ind, Writer out) throws IOException {
-        out.write(ind);
-        if (paramRole != null) {
-            out.write("- ");
-            out.write(paramRole.toString());
-            out.write(": ");
-        }
-    }
-    
-    public static class Options {
-        
-        private final static Options DEFAULT_INSTANCE = new Options(); 
-        
-        private boolean showJavaClass = true;
-        private boolean showConstantValue = false;
-        private boolean showLocation = false;
-        
-        public boolean getShowJavaClass() {
-            return showJavaClass;
-        }
-        
-        public void setShowJavaClass(boolean showJavaClass) {
-            this.showJavaClass = showJavaClass;
-        }
-        
-        public boolean getShowConstantValue() {
-            return showConstantValue;
-        }
-        
-        public void setShowConstantValue(boolean showConstantValue) {
-            this.showConstantValue = showConstantValue;
-        }
-
-        public boolean getShowLocation() {
-            return showLocation;
-        }
-
-        public void setShowLocation(boolean showLocation) {
-            this.showLocation = showLocation;
-        }
-        
-    }
-    
-    private static void p(Object obj) {
-        System.out.println(obj);
-    }
-
-    public static class InvalidASTException extends RuntimeException {
-
-        public InvalidASTException(String message, Throwable cause) {
-            super(message, cause);
-        }
-
-        public InvalidASTException(String message) {
-            super(message);
-        }
-        
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/ASTTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/ASTTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/ASTTest.java
deleted file mode 100644
index 96f173a..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/ASTTest.java
+++ /dev/null
@@ -1,103 +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;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-
-import org.apache.freemarker.core.ASTPrinter.Options;
-import org.apache.freemarker.core.util._StringUtil;
-import org.apache.freemarker.test.util.FileTestCase;
-import org.apache.freemarker.test.TestUtil;
-
-public class ASTTest extends FileTestCase {
-
-    public ASTTest(String name) {
-        super(name);
-    }
-    
-    public void test1() throws Exception {
-        testAST("ast-1");
-    }
-
-    public void testRange() throws Exception {
-        testAST("ast-range");
-    }
-    
-    public void testAssignments() throws Exception {
-        testAST("ast-assignments");
-    }
-    
-    public void testBuiltins() throws Exception {
-        testAST("ast-builtins");
-    }
-    
-    public void testStringLiteralInterpolation() throws Exception {
-        testAST("ast-strlitinterpolation");
-    }
-    
-    public void testWhitespaceStripping() throws Exception {
-        testAST("ast-whitespacestripping");
-    }
-
-    public void testMixedContentSimplifications() throws Exception {
-        testAST("ast-mixedcontentsimplifications");
-    }
-
-    public void testMultipleIgnoredChildren() throws Exception {
-        testAST("ast-multipleignoredchildren");
-    }
-    
-    public void testNestedIgnoredChildren() throws Exception {
-        testAST("ast-nestedignoredchildren");
-    }
-
-    public void testLocations() throws Exception {
-        testASTWithLocations("ast-locations");
-    }
-    
-    private void testAST(String testName) throws FileNotFoundException, IOException {
-        testAST(testName, null);
-    }
-
-    private void testASTWithLocations(String testName) throws FileNotFoundException, IOException {
-        Options options = new Options();
-        options.setShowLocation(true);
-        testAST(testName, options);
-    }
-
-    private void testAST(String testName, Options ops) throws FileNotFoundException, IOException {
-        final String templateName = testName + ".ftl";
-        assertExpectedFileEqualsString(
-                testName + ".ast",
-                ASTPrinter.getASTAsString(templateName,
-                        TestUtil.removeFTLCopyrightComment(
-                                normalizeLineBreaks(
-                                        loadTestTextResource(
-                                                getTestFileURL(
-                                                        getExpectedContentFileDirectoryResourcePath(), templateName)))
-                        ), ops));
-    }
-    
-    private String normalizeLineBreaks(final String s) throws FileNotFoundException, IOException {
-        return _StringUtil.replace(s, "\r\n", "\n").replace('\r', '\n');
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/ActualNamingConvetionTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/ActualNamingConvetionTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/ActualNamingConvetionTest.java
deleted file mode 100644
index 57e40fa..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/ActualNamingConvetionTest.java
+++ /dev/null
@@ -1,66 +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;
-
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-
-import org.apache.freemarker.test.TestConfigurationBuilder;
-import org.junit.Test;
-
-public class ActualNamingConvetionTest {
-    
-    @Test
-    public void testUndetectable() throws IOException {
-        final String ftl = "<#if true>${x?size}</#if>";
-        assertEquals(getActualNamingConvention(ftl,
-                ParsingConfiguration.AUTO_DETECT_NAMING_CONVENTION), ParsingConfiguration.AUTO_DETECT_NAMING_CONVENTION);
-        assertEquals(getActualNamingConvention(ftl,
-                ParsingConfiguration.LEGACY_NAMING_CONVENTION), ParsingConfiguration.LEGACY_NAMING_CONVENTION);
-        assertEquals(getActualNamingConvention(ftl,
-                ParsingConfiguration.CAMEL_CASE_NAMING_CONVENTION), ParsingConfiguration.CAMEL_CASE_NAMING_CONVENTION);
-    }
-
-    @Test
-    public void testLegacyDetected() throws IOException {
-        final String ftl = "${x?upper_case}";
-        assertEquals(getActualNamingConvention(ftl,
-                ParsingConfiguration.AUTO_DETECT_NAMING_CONVENTION), ParsingConfiguration.LEGACY_NAMING_CONVENTION);
-        assertEquals(getActualNamingConvention(ftl,
-                ParsingConfiguration.LEGACY_NAMING_CONVENTION), ParsingConfiguration.LEGACY_NAMING_CONVENTION);
-    }
-
-    @Test
-    public void testCamelCaseDetected() throws IOException {
-        final String ftl = "${x?upperCase}";
-        assertEquals(getActualNamingConvention(ftl,
-                ParsingConfiguration.AUTO_DETECT_NAMING_CONVENTION), ParsingConfiguration.CAMEL_CASE_NAMING_CONVENTION);
-        assertEquals(getActualNamingConvention(ftl,
-                ParsingConfiguration.CAMEL_CASE_NAMING_CONVENTION), ParsingConfiguration.CAMEL_CASE_NAMING_CONVENTION);
-    }
-
-    private int getActualNamingConvention(String ftl, int namingConvention) throws IOException {
-        return new Template(null, ftl,
-                new TestConfigurationBuilder().namingConvention(namingConvention).build())
-                .getActualNamingConvention();
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/ActualTagSyntaxTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/ActualTagSyntaxTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/ActualTagSyntaxTest.java
deleted file mode 100644
index 88f0646..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/ActualTagSyntaxTest.java
+++ /dev/null
@@ -1,68 +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;
-
-import static org.apache.freemarker.core.ParsingConfiguration.*;
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-
-import org.apache.freemarker.test.TestConfigurationBuilder;
-import org.junit.Test;
-
-public class ActualTagSyntaxTest {
-
-    @Test
-    public void testWithFtlHeader() throws IOException {
-        testWithFtlHeader(AUTO_DETECT_TAG_SYNTAX);
-        testWithFtlHeader(ANGLE_BRACKET_TAG_SYNTAX);
-        testWithFtlHeader(SQUARE_BRACKET_TAG_SYNTAX);
-    }
-    
-    private void testWithFtlHeader(int cfgTagSyntax) throws IOException {
-        assertEquals(getActualTagSyntax("[#ftl]foo", cfgTagSyntax), SQUARE_BRACKET_TAG_SYNTAX);
-        assertEquals(getActualTagSyntax("<#ftl>foo", cfgTagSyntax), ANGLE_BRACKET_TAG_SYNTAX);
-    }
-    
-    @Test
-    public void testUndecidable() throws IOException {
-        assertEquals(getActualTagSyntax("foo", AUTO_DETECT_TAG_SYNTAX), ANGLE_BRACKET_TAG_SYNTAX);
-        assertEquals(getActualTagSyntax("foo", ANGLE_BRACKET_TAG_SYNTAX), ANGLE_BRACKET_TAG_SYNTAX);
-        assertEquals(getActualTagSyntax("foo", SQUARE_BRACKET_TAG_SYNTAX), SQUARE_BRACKET_TAG_SYNTAX);
-    }
-
-    @Test
-    public void testDecidableWithoutFtlHeader() throws IOException {
-        assertEquals(getActualTagSyntax("foo<#if true></#if>", AUTO_DETECT_TAG_SYNTAX), ANGLE_BRACKET_TAG_SYNTAX);
-        assertEquals(getActualTagSyntax("foo<#if true></#if>", ANGLE_BRACKET_TAG_SYNTAX), ANGLE_BRACKET_TAG_SYNTAX);
-        assertEquals(getActualTagSyntax("foo<#if true></#if>", SQUARE_BRACKET_TAG_SYNTAX), SQUARE_BRACKET_TAG_SYNTAX);
-        
-        assertEquals(getActualTagSyntax("foo[#if true][/#if]", AUTO_DETECT_TAG_SYNTAX), SQUARE_BRACKET_TAG_SYNTAX);
-        assertEquals(getActualTagSyntax("foo[#if true][/#if]", ANGLE_BRACKET_TAG_SYNTAX), ANGLE_BRACKET_TAG_SYNTAX);
-        assertEquals(getActualTagSyntax("foo[#if true][/#if]", SQUARE_BRACKET_TAG_SYNTAX), SQUARE_BRACKET_TAG_SYNTAX);
-    }
-    
-    private int getActualTagSyntax(String ftl, int cfgTagSyntax) throws IOException {
-        return new Template(
-                null, ftl,
-                new TestConfigurationBuilder().tagSyntax(cfgTagSyntax).build()).getActualTagSyntax();
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/BreakPlacementTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/BreakPlacementTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/BreakPlacementTest.java
deleted file mode 100644
index 61ba02b..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/BreakPlacementTest.java
+++ /dev/null
@@ -1,56 +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;
-
-import java.io.IOException;
-
-import org.apache.freemarker.test.TemplateTest;
-import org.junit.Test;
-
-public class BreakPlacementTest extends TemplateTest {
-    
-    private static final String BREAK_NESTING_ERROR_MESSAGE_PART = "<#break> must be nested";
-
-    @Test
-    public void testValidPlacements() throws IOException, TemplateException {
-        assertOutput("<#assign x = 1><#switch x><#case 1>one<#break><#case 2>two</#switch>", "one");
-        assertOutput("<#list 1..2 as x>${x}<#break></#list>", "1");
-        assertOutput("<#list 1..2>[<#items as x>${x}<#break></#items>]</#list>", "[1]");
-        assertOutput("<#list 1..2 as x>${x}<#list 1..3>B<#break>E<#items as y></#items></#list>E</#list>.", "1B.");
-        assertOutput("<#list 1..2 as x>${x}<#list 3..4 as x>${x}<#break></#list>;</#list>", "13;23;");
-        assertOutput("<#list [1..2, 3..4, [], 5..6] as xs>[<#list xs as x>${x}<#else><#break></#list>]</#list>.",
-                "[12][34][.");
-        assertOutput("<#list [1..2, 3..4, [], 5..6] as xs>"
-                + "<#list xs>[<#items as x>${x}</#items>]<#else><#break></#list>"
-                + "</#list>.",
-                "[12][34].");
-    }
-
-    @Test
-    public void testInvalidPlacements() throws IOException, TemplateException {
-        assertErrorContains("<#break>", BREAK_NESTING_ERROR_MESSAGE_PART);
-        assertErrorContains("<#list 1..2 as x>${x}</#list><#break>", BREAK_NESTING_ERROR_MESSAGE_PART);
-        assertErrorContains("<#if false><#break></#if>", BREAK_NESTING_ERROR_MESSAGE_PART);
-        assertErrorContains("<#list xs><#break></#list>", BREAK_NESTING_ERROR_MESSAGE_PART);
-        assertErrorContains("<#list 1..2 as x>${x}<#else><#break></#list>", BREAK_NESTING_ERROR_MESSAGE_PART);
-        assertErrorContains("<#list 1..2 as x>${x}<#macro m><#break></#macro></#list>", BREAK_NESTING_ERROR_MESSAGE_PART);
-    }
-
-}


[02/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/listhash.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/listhash.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/listhash.txt
deleted file mode 100644
index e251238..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/listhash.txt
+++ /dev/null
@@ -1,157 +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.
- */
-
-Non-empty maps:
-
-    Map:
-    
-    [
-      k1 = v1
-      2 = v2
-      k3 = v3
-      null = v4
-      Y = v5
-      N = null
-    ]
-  
-    [
-      k1 = v1; // @0=@0; odd=odd; Y=Y
-      2 = v2; // @1=@1; even=even; Y=Y
-      k3 = v3; // @2=@2; odd=odd; Y=Y
-      null = v4; // @3=@3; even=even; Y=Y
-      Y = v5; // @4=@4; odd=odd; Y=Y
-      N = null // @5=@5; even=even; N=N
-    ]
-  
-    {
-      [
-        k1 = v1; // @0=@0; odd=odd; Y=Y
-        2 = v2; // @1=@1; even=even; Y=Y
-        k3 = v3; // @2=@2; odd=odd; Y=Y
-        null = v4; // @3=@3; even=even; Y=Y
-        Y = v5; // @4=@4; odd=odd; Y=Y
-        N = null // @5=@5; even=even; N=N
-      ]
-    }
-
-    Map:
-    
-    [
-      k1 = v1
-      2 = v2
-      k3 = v3
-      null = v4
-      Y = v5
-      N = null
-    ]
-  
-    [
-      k1 = v1; // @0=@0; odd=odd; Y=Y
-      2 = v2; // @1=@1; even=even; Y=Y
-      k3 = v3; // @2=@2; odd=odd; Y=Y
-      null = v4; // @3=@3; even=even; Y=Y
-      Y = v5; // @4=@4; odd=odd; Y=Y
-      N = null // @5=@5; even=even; N=N
-    ]
-  
-    {
-      [
-        k1 = v1; // @0=@0; odd=odd; Y=Y
-        2 = v2; // @1=@1; even=even; Y=Y
-        k3 = v3; // @2=@2; odd=odd; Y=Y
-        null = v4; // @3=@3; even=even; Y=Y
-        Y = v5; // @4=@4; odd=odd; Y=Y
-        N = null // @5=@5; even=even; N=N
-      ]
-    }
-
-    Map:
-    
-    [
-      k1 = 11
-      k2 = 22
-    ]
-  
-    [
-      k1 = 11; // @0=@0; odd=odd; Y=Y
-      k2 = 22 // @1=@1; even=even; N=N
-    ]
-  
-    {
-      [
-        k1 = 11; // @0=@0; odd=odd; Y=Y
-        k2 = 22 // @1=@1; even=even; N=N
-      ]
-    }
-
-
-Empty maps:
-
-    Map:
-    
-    [
-    ]
-  
-    [
-      Empty
-    ]
-  
-    {
-      Empty
-    }
-
-    Map:
-    
-    [
-    ]
-  
-    [
-      Empty
-    ]
-  
-    {
-      Empty
-    }
-
-    Map:
-    
-    [
-    ]
-  
-    [
-      Empty
-    ]
-  
-    {
-      Empty
-    }
-
-
-  a @ 0, 1
-    aa = 11  @ 0 // inside a @ 0, 1
-  a @ 0, 1
-  --
-  b @ 1, 2
-    ba = 21  @ 0 // inside b @ 1, 2
-    bb = 22  @ 1 // inside b @ 1, 2
-  b @ 1, 2
-  --
-  c @ 2, 0
-  c @ 2, 0
-  --

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/listhashliteral.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/listhashliteral.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/listhashliteral.txt
deleted file mode 100644
index 937f0ea..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/listhashliteral.txt
+++ /dev/null
@@ -1,36 +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.
- */
-  KVPs:
-    a = 3
-    b = 2
-  
-  Keys:
-    a
-    b
-  
-  Values:
-    3
-    2
-
-  KVPs:
-  
-  Keys:
-  
-  Values:
-

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/listliteral.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/listliteral.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/listliteral.txt
deleted file mode 100644
index 2048ac5..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/listliteral.txt
+++ /dev/null
@@ -1,75 +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.
- */
-<html>
-<head>
-<title>FreeMarker: List Literal Test</title>
-</head>
-<body>
-
-<p>A simple test follows:</p>
-
-<p>Hello, world!</p>
-
-<p>Now perform a list assignment:</p>
-
-
-The list contains 5 items.
-
-<p>test1</p>
-<p>test23</p>
-<p>test45</p>
-<p>Hello, world!</p>
-<p>hello</p>
-
-<p>Now update the assignment and repeat:</p>
-
-
-<p>test1</p>
-<p>test23</p>
-<p>test45</p>
-<p>Hello, world!</p>
-<p>hello</p>
-
-<p>Now reassign the list and repeat:</p>
-
-
-<p>bar</p>
-<p>Temporary</p>
-<p>test1</p>
-<p>test23</p>
-
-<p>Silly, but necessary tests, for one and zero element lists:</p>
-
-
-<p>Hello, world</p>
-
-<p>Zero item test:</p>
-
-
-
-<p>Dumb test for number literals -- these weren't working as expected:</p>
-
-
-<p>1</p>
-<p>2</p>
-<p>3</p>
-<p>5</p>
-
-</body>
-</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/localization.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/localization.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/localization.txt
deleted file mode 100644
index bd3c87d..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/localization.txt
+++ /dev/null
@@ -1,32 +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.
- */
-<html>
-<head>
-<title>FreeMarker: Localization Test</title>
-</head>
-<body>
-
-<p>A simple test follows:</p>
-
-<p>Hello, world!</p>
-
-<p>G'day, mate!</p>
-
-</body>
-</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/logging.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/logging.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/logging.txt
deleted file mode 100644
index 4fa6b2a..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/logging.txt
+++ /dev/null
@@ -1,27 +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.
- */
-<html>
-<head>
-<title>FreeMarker: Logging Test</title>
-</head>
-<body>
-
-A simple test follows:
-
-ERROR [org.apache.freemarker.core.Template]: message is not a TemplateHashModel, it's a freemarker.template.SimpleScalar.

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/loopvariable.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/loopvariable.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/loopvariable.txt
deleted file mode 100644
index 25c20ac..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/loopvariable.txt
+++ /dev/null
@@ -1,54 +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.
- */
----
-  2
-  -     L1 1
-  -       L2 1: 1; 2; 3; 
-  -       L2 2: 1; 2; 3; 
-*
-  -     L1 2
-  -       L2 1: 1; 2; 3; 
-  -       L2 2: 1; 2; 3; 
-*
-  -     L1 3
-  -       L2 1: 1; 2; 3; 
-  -       L2 2: 1; 2; 3; 
-*
-*
-  1
-  -     L1 1
-  -       L2 1: 1; 2; 3; 
-  -       L2 2: 1; 2; 3; 
-*
-  -     L1 2
-  -       L2 1: 1; 2; 3; 
-  -       L2 2: 1; 2; 3; 
-*
-  -     L1 3
-  -       L2 1: 1; 2; 3; 
-  -       L2 2: 1; 2; 3; 
-*
-*
----
-  1 0.5
-  2 1
-  3 1.5
-  4 2 Last!
-123.4
----
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/macros-return.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/macros-return.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/macros-return.txt
deleted file mode 100644
index 5aa47ff..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/macros-return.txt
+++ /dev/null
@@ -1,23 +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.
- */
-m{
-m{
-m{
-b{
-m:b{
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/macros.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/macros.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/macros.txt
deleted file mode 100644
index 680a08e..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/macros.txt
+++ /dev/null
@@ -1,67 +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.
- */
-<html>
-<head>
-<title>FreeMarker: Function Test</title>
-</head>
-<body>
-
-<p>A simple test follows:</p>
-
-<p>Hello, world!</p>
-
-<p>Now perform function tests:</p>
-
-
-<p>Function is defined, now let's call it:</p>
-
-    <a href="/home.html">
-        <img src="/images/home.png" border="0" alt="Home">
-    </a>
-    Kilroy was here.
-
-<p>Again, but with different parameters:</p>
-
-    <a href="/about.html">
-        <img src="/image/about-us.jpeg" border="0" alt="About Us">
-    </a>
-    Kilroy was here.
-
-   Good.
-
-<p>A recursive function call:</p>
-
-
-    0
-    1
-    2
-    3
-
-<p>Test "catch-all" macro parameter:</p>
-
-
-foo=a baz=[]
-foo=a baz=[bar=b]
-foo=a baz=[bar=b, baz=c]
-
-
-Hello World! Today is Monday.
-
-</body>
-</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/macros2.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/macros2.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/macros2.txt
deleted file mode 100644
index 1b4e007..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/macros2.txt
+++ /dev/null
@@ -1,22 +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.
- */
-1 1
-2 2
-4
-m3 with d="4" Failed!

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/multimodels.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/multimodels.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/multimodels.txt
deleted file mode 100644
index 54ec68d..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/multimodels.txt
+++ /dev/null
@@ -1,93 +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.
- */
-<html>
-<head>
-<title>FreeMarker: Test of Multiple Model implementations</title>
-</head>
-<body>
-
-<p>Let's begin with a simple model:</p>
-<p>Hello, world!</p>
-
-<p>Cool, now get into the first model. This implements a scalar, list, and
-hash as a single class. Let's try some tests...</p>
-
-<p>MultiModel1 as a string!</p>
-
-<p>Now as a list...</p>
-
-Model1 value: 0<br />
-Model1 value: 1<br />
-Model1 value: 2<br />
-Model1 value: 3<br />
-Model1 value: 4<br />
-Model1 value: 5<br />
-Model1 value: 6<br />
-Model1 value: 7<br />
-Model1 value: 8<br />
-Model1 value: 9<br />
-Model3 is alive!<br />
-
-<p>Index into a list...</p>
-<p>Model1 value: 1</p>
-<p>List size is: Nasty!</p>
-<p>List size is: Nasty!</p>
-
-<p>Now, again, as a hash. First using dot notation, then using [] notation:</p>
-
-<p>Selftest of a hash from MultiModel1</p>
-<p>Selftest of a hash from MultiModel1</p>
-
-<p>Now for the tricky stuff... use a model to index into another model...</p>
-<p>selftest</p>
-<p>Selftest of a hash from MultiModel1</p>
-<p>self</p>
-<p>Selftest of a hash from MultiModel1</p>
-
-<p>Same thing, this time a List index...</p>
-<p>0</p>
-<p>Model1 value: 0</p>
-<p>Model1 value: 1</p>
-
-<p>Now, do the same recursively...</p>
-<p>MultiModel1 as a string!</p>
-<p>Model2 is alive!</p>
-<p>Arguments are:<br />test<br /></p>
-<p>Arguments are:<br />MultiModel1 as a string!<br />Selftest of a hash from MultiModel1<br />Hello, world!<br /></p>
-
-<p>Does this really not work?</p>
-<p>Model3 is alive!</p>
-<p>Selftest from MultiModel3!</p>
-<p>Hello world from MultiModel3!</p>
-
-<p>(Again, with Hashes)</p>
-<p>Model3 is alive!</p>
-<p>Selftest from MultiModel3!</p>
-
-<p>Model3 is alive!</p>
-<p>Selftest from MultiModel3!</p>
-<p>Selftest from MultiModel3!</p>
-
-<p>As I suspected! (Manual on Expressions needs updating.)</p>
-
-<p>Second test on list size</p>
-<p>Key size, not the listSize method.</p>
-<p>Key size, not the listSize method.</p>
-</body>
-</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/nested.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/nested.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/nested.txt
deleted file mode 100644
index bcfb104..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/nested.txt
+++ /dev/null
@@ -1,25 +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.
- */
-    test 3/1: undefined undefined undefined 
-    test 3/2: undefined undefined undefined 
-    test 3/3: undefined undefined undefined 
-
-    test 3/1: Y X Count 1 
-    test 3/2: Y X Count 2 
-    test 3/3: Y X Count 3 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/new-allowsnothing.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/new-allowsnothing.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/new-allowsnothing.txt
deleted file mode 100644
index b8384c7..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/new-allowsnothing.txt
+++ /dev/null
@@ -1,19 +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.
- */
-fails
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/new-defaultresolver.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/new-defaultresolver.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/new-defaultresolver.txt
deleted file mode 100644
index 35e7a3e..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/new-defaultresolver.txt
+++ /dev/null
@@ -1,19 +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.
- */
-works
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/new-optin.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/new-optin.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/new-optin.txt
deleted file mode 100644
index 9d8e883..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/new-optin.txt
+++ /dev/null
@@ -1,32 +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.
- */
-works
-fails
-
-works
-works
-
-works
-fails
-
-works
-fails
-
-works
-works
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/newlines1.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/newlines1.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/newlines1.txt
deleted file mode 100644
index bc58731..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/newlines1.txt
+++ /dev/null
@@ -1,29 +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.
- */
-<html>
-<head>
-<title>FreeMarker: Newlines Test</title>
-</head>
-<body>
-<p>A simple test follows:</p>
-
-<p>Hello, world!</p>
-
-</body>
-</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/newlines2.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/newlines2.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/newlines2.txt
deleted file mode 100644
index c131421..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/newlines2.txt
+++ /dev/null
@@ -1,30 +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.
- */
-<html>
-<head>
-<title>FreeMarker: Newlines the Second Test</title>
-</head>
-<body>
-<p>A simple test follows:</p>
-
-<p>Hello, world!
-</p>
-
-</body>
-</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/noparse.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/noparse.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/noparse.txt
deleted file mode 100644
index 5e8486c..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/noparse.txt
+++ /dev/null
@@ -1,54 +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.
- */
-<html>
-<head>
-<title>FreeMarker: NoParse Test</title>
-</head>
-<body>
-
-A simple test follows:
-
-${message}
-
-A more rigorous test, showing that we're not faking it:
-
-${message@#$%&}
-
-	<p>Message exists!
-		...and even generates output!
-		<#if message>
-			Nested statements are ok, too.
-		</#if>
-	</p>
-
-Here's another edge case, this time, trying to output a &lt;noparse&gt;
-inside another &lt;noparse&gt;
-
-
-This is what the noparse instruction looks like:
-
-<#noparse>This part of the template wont be parsed by the 
-FreeMarker parser. Instead, it will be treated as verbatim text information,
-and output as such.</#noparse>
-
-The rest of the template appears here.
-
-Simple.
-</body>
-</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/number-format.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/number-format.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/number-format.txt
deleted file mode 100644
index a6f8475..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/number-format.txt
+++ /dev/null
@@ -1,33 +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.
- */
-1
-1
-1 234 567,89
-1234567.886
-1,00
-1
-1234567,89
-1234567.886
-1
-1
-1.000000000000001
-0.0000000000000001
--0.0000000000000001
-1
-0.0000000000000001

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/number-literal.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/number-literal.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/number-literal.txt
deleted file mode 100644
index b80bc85..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/number-literal.txt
+++ /dev/null
@@ -1,79 +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.
- */
-<html>
-<head>
-<title>FreeMarker: Number Literal Test</title>
-</head>
-<body>
-
-<p>A simple test follows:</p>
-
-<p>Hello, world!</p>
-
-<p>Now perform a number assignment:</p>
-
-1,3
-
-
-My number is: 1,8
-My float is: 1.800000
-The int part is: 1
-
-
-1.83
-
-<p>Now use numbers in assignment</p>
-
-6
-
-8
-
-<p>Try numbers in tests</p>
-
-MyMessage is not 152, its: 8.
-
-<if (mymessage > 5)>
-   MyMessage is greater than five.
-</if
-
-		MyMessage is: 8.
-
-<p>Now for numbers in dynamic keys:</p>
-
-
-one
-three
-
-<p>Numbers in hashes:</p>
-
-twelve
-twelve
-twelve
-
-
-<p>Numbers in method calls:</p>
-
-Single argument value is: 1
-Single argument value is: 1
-Single argument value is: 12
-Single argument value is: 3
-Single argument value is: 3
-
-</body>
-</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/number-to-date.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/number-to-date.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/number-to-date.txt
deleted file mode 100644
index bc8a10e..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/number-to-date.txt
+++ /dev/null
@@ -1,31 +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.
- */
-2011-05-16T19:47:55.54Z == 2011-05-16T19:47:55.54Z
-2011-05-16 == 2011-05-16
-19:47:55.54Z == 19:47:55.54Z
-
-2011-05-16T19:47:55.54Z == 2011-05-16T19:47:55.54Z
-2011-05-16T19:47:55.54Z == 2011-05-16T19:47:55.54Z
-2011-05-16T19:47:55.54Z == 2011-05-16T19:47:55.54Z
-2011-05-16T19:47:55.54Z == 2011-05-16T19:47:55.54Z
-1970-01-01T00:00:01Z == 1970-01-01T00:00:01Z
-1970-01-01T00:00:01Z == 1970-01-01T00:00:01Z
-1970-01-01T00:00:00Z == 1970-01-01T00:00:00Z
-
-failed

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/numerical-cast.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/numerical-cast.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/numerical-cast.txt
deleted file mode 100644
index 3bf6cd0..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/numerical-cast.txt
+++ /dev/null
@@ -1,462 +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.
- */
-
-?int:
-    0?int=0
-    1?int=1
-    -1?int=-1
-    0.5?int=0
-    1.5?int=1
-    -0.5?int=0
-    -1.5?int=-1
-    0.25?int=0
-    -0.25?int=0
-    1.75?int=1
-    -1.75?int=-1
-    1.01?int=1
-    -1.01?int=-1
-    0.01?int=0
-    -0.01?int=0
-    127?int=127
-    128?int=128
-    -127?int=-127
-    -128?int=-128
-    32767?int=32767
-    32768?int=32768
-    -32767?int=-32767
-    -32768?int=-32768
-    2147483647?int=2147483647
-    2147483648?int=-2147483648
-    -2147483647?int=-2147483647
-    -2147483648?int=-2147483648
-    4294967295?int=-1
-    4294967296?int=0
-    -4294967295?int=1
-    -4294967296?int=0
-    2147483647.1?int=2147483647
-    2147483648.1?int=-2147483648
-    -2147483647.1?int=-2147483647
-    -2147483648.1?int=-2147483648
-    4294967295.1?int=-1
-    4294967296.1?int=0
-    -4294967295.1?int=1
-    -4294967296.1?int=0
-    2147483647.5?int=2147483647
-    2147483648.5?int=-2147483648
-    -2147483647.5?int=-2147483647
-    -2147483648.5?int=-2147483648
-    4294967295.5?int=-1
-    4294967296.5?int=0
-    -4294967295.5?int=1
-    -4294967296.5?int=0
-
-?double
-    0?double=0
-    1?double=1
-    -1?double=-1
-    0.5?double=0.5
-    1.5?double=1.5
-    -0.5?double=-0.5
-    -1.5?double=-1.5
-    0.25?double=0.25
-    -0.25?double=-0.25
-    1.75?double=1.75
-    -1.75?double=-1.75
-    1.01?double=1.01
-    -1.01?double=-1.01
-    0.01?double=0.01
-    -0.01?double=-0.01
-    127?double=127
-    128?double=128
-    -127?double=-127
-    -128?double=-128
-    32767?double=32767
-    32768?double=32768
-    -32767?double=-32767
-    -32768?double=-32768
-    2147483647?double=2147483647
-    2147483648?double=2147483648
-    -2147483647?double=-2147483647
-    -2147483648?double=-2147483648
-    4294967295?double=4294967295
-    4294967296?double=4294967296
-    -4294967295?double=-4294967295
-    -4294967296?double=-4294967296
-    2147483647.1?double=2147483647.1
-    2147483648.1?double=2147483648.1
-    -2147483647.1?double=-2147483647.1
-    -2147483648.1?double=-2147483648.1
-    4294967295.1?double=4294967295.1
-    4294967296.1?double=4294967296.1
-    -4294967295.1?double=-4294967295.1
-    -4294967296.1?double=-4294967296.1
-    2147483647.5?double=2147483647.5
-    2147483648.5?double=2147483648.5
-    -2147483647.5?double=-2147483647.5
-    -2147483648.5?double=-2147483648.5
-    4294967295.5?double=4294967295.5
-    4294967296.5?double=4294967296.5
-    -4294967295.5?double=-4294967295.5
-    -4294967296.5?double=-4294967296.5
-
-?long
-    0?long=0
-    1?long=1
-    -1?long=-1
-    0.5?long=0
-    1.5?long=1
-    -0.5?long=0
-    -1.5?long=-1
-    0.25?long=0
-    -0.25?long=0
-    1.75?long=1
-    -1.75?long=-1
-    1.01?long=1
-    -1.01?long=-1
-    0.01?long=0
-    -0.01?long=0
-    127?long=127
-    128?long=128
-    -127?long=-127
-    -128?long=-128
-    32767?long=32767
-    32768?long=32768
-    -32767?long=-32767
-    -32768?long=-32768
-    2147483647?long=2147483647
-    2147483648?long=2147483648
-    -2147483647?long=-2147483647
-    -2147483648?long=-2147483648
-    4294967295?long=4294967295
-    4294967296?long=4294967296
-    -4294967295?long=-4294967295
-    -4294967296?long=-4294967296
-    2147483647.1?long=2147483647
-    2147483648.1?long=2147483648
-    -2147483647.1?long=-2147483647
-    -2147483648.1?long=-2147483648
-    4294967295.1?long=4294967295
-    4294967296.1?long=4294967296
-    -4294967295.1?long=-4294967295
-    -4294967296.1?long=-4294967296
-    2147483647.5?long=2147483647
-    2147483648.5?long=2147483648
-    -2147483647.5?long=-2147483647
-    -2147483648.5?long=-2147483648
-    4294967295.5?long=4294967295
-    4294967296.5?long=4294967296
-    -4294967295.5?long=-4294967295
-    -4294967296.5?long=-4294967296
-
-?long from date
-    1304877615000 = 1304877615000
-
-?float
-    0?float=0
-    1?float=1
-    -1?float=-1
-    0.5?float=0.5
-    1.5?float=1.5
-    -0.5?float=-0.5
-    -1.5?float=-1.5
-    0.25?float=0.25
-    -0.25?float=-0.25
-    1.75?float=1.75
-    -1.75?float=-1.75
-    1.01?float=1.00999999
-    -1.01?float=-1.00999999
-    0.01?float=0.01
-    -0.01?float=-0.01
-    127?float=127
-    128?float=128
-    -127?float=-127
-    -128?float=-128
-    32767?float=32767
-    32768?float=32768
-    -32767?float=-32767
-    -32768?float=-32768
-    2147483647?float=2147483648
-    2147483648?float=2147483648
-    -2147483647?float=-2147483648
-    -2147483648?float=-2147483648
-    4294967295?float=4294967296
-    4294967296?float=4294967296
-    -4294967295?float=-4294967296
-    -4294967296?float=-4294967296
-    2147483647.1?float=2147483648
-    2147483648.1?float=2147483648
-    -2147483647.1?float=-2147483648
-    -2147483648.1?float=-2147483648
-    4294967295.1?float=4294967296
-    4294967296.1?float=4294967296
-    -4294967295.1?float=-4294967296
-    -4294967296.1?float=-4294967296
-    2147483647.5?float=2147483648
-    2147483648.5?float=2147483648
-    -2147483647.5?float=-2147483648
-    -2147483648.5?float=-2147483648
-    4294967295.5?float=4294967296
-    4294967296.5?float=4294967296
-    -4294967295.5?float=-4294967296
-    -4294967296.5?float=-4294967296
-
-?byte
-    0?byte=0
-    1?byte=1
-    -1?byte=-1
-    0.5?byte=0
-    1.5?byte=1
-    -0.5?byte=0
-    -1.5?byte=-1
-    0.25?byte=0
-    -0.25?byte=0
-    1.75?byte=1
-    -1.75?byte=-1
-    1.01?byte=1
-    -1.01?byte=-1
-    0.01?byte=0
-    -0.01?byte=0
-    127?byte=127
-    128?byte=-128
-    -127?byte=-127
-    -128?byte=-128
-    32767?byte=-1
-    32768?byte=0
-    -32767?byte=1
-    -32768?byte=0
-    2147483647?byte=-1
-    2147483648?byte=0
-    -2147483647?byte=1
-    -2147483648?byte=0
-    4294967295?byte=-1
-    4294967296?byte=0
-    -4294967295?byte=1
-    -4294967296?byte=0
-    2147483647.1?byte=-1
-    2147483648.1?byte=0
-    -2147483647.1?byte=1
-    -2147483648.1?byte=0
-    4294967295.1?byte=-1
-    4294967296.1?byte=0
-    -4294967295.1?byte=1
-    -4294967296.1?byte=0
-    2147483647.5?byte=-1
-    2147483648.5?byte=0
-    -2147483647.5?byte=1
-    -2147483648.5?byte=0
-    4294967295.5?byte=-1
-    4294967296.5?byte=0
-    -4294967295.5?byte=1
-    -4294967296.5?byte=0
-
-?short
-    0?short=0
-    1?short=1
-    -1?short=-1
-    0.5?short=0
-    1.5?short=1
-    -0.5?short=0
-    -1.5?short=-1
-    0.25?short=0
-    -0.25?short=0
-    1.75?short=1
-    -1.75?short=-1
-    1.01?short=1
-    -1.01?short=-1
-    0.01?short=0
-    -0.01?short=0
-    127?short=127
-    128?short=128
-    -127?short=-127
-    -128?short=-128
-    32767?short=32767
-    32768?short=-32768
-    -32767?short=-32767
-    -32768?short=-32768
-    2147483647?short=-1
-    2147483648?short=0
-    -2147483647?short=1
-    -2147483648?short=0
-    4294967295?short=-1
-    4294967296?short=0
-    -4294967295?short=1
-    -4294967296?short=0
-    2147483647.1?short=-1
-    2147483648.1?short=0
-    -2147483647.1?short=1
-    -2147483648.1?short=0
-    4294967295.1?short=-1
-    4294967296.1?short=0
-    -4294967295.1?short=1
-    -4294967296.1?short=0
-    2147483647.5?short=-1
-    2147483648.5?short=0
-    -2147483647.5?short=1
-    -2147483648.5?short=0
-    4294967295.5?short=-1
-    4294967296.5?short=0
-    -4294967295.5?short=1
-    -4294967296.5?short=0
-
-?floor
-    0?floor=0
-    1?floor=1
-    -1?floor=-1
-    0.5?floor=0
-    1.5?floor=1
-    -0.5?floor=-1
-    -1.5?floor=-2
-    0.25?floor=0
-    -0.25?floor=-1
-    1.75?floor=1
-    -1.75?floor=-2
-    1.01?floor=1
-    -1.01?floor=-2
-    0.01?floor=0
-    -0.01?floor=-1
-    127?floor=127
-    128?floor=128
-    -127?floor=-127
-    -128?floor=-128
-    32767?floor=32767
-    32768?floor=32768
-    -32767?floor=-32767
-    -32768?floor=-32768
-    2147483647?floor=2147483647
-    2147483648?floor=2147483648
-    -2147483647?floor=-2147483647
-    -2147483648?floor=-2147483648
-    4294967295?floor=4294967295
-    4294967296?floor=4294967296
-    -4294967295?floor=-4294967295
-    -4294967296?floor=-4294967296
-    2147483647.1?floor=2147483647
-    2147483648.1?floor=2147483648
-    -2147483647.1?floor=-2147483648
-    -2147483648.1?floor=-2147483649
-    4294967295.1?floor=4294967295
-    4294967296.1?floor=4294967296
-    -4294967295.1?floor=-4294967296
-    -4294967296.1?floor=-4294967297
-    2147483647.5?floor=2147483647
-    2147483648.5?floor=2147483648
-    -2147483647.5?floor=-2147483648
-    -2147483648.5?floor=-2147483649
-    4294967295.5?floor=4294967295
-    4294967296.5?floor=4294967296
-    -4294967295.5?floor=-4294967296
-    -4294967296.5?floor=-4294967297
-
-?ceiling
-    0?ceiling=0
-    1?ceiling=1
-    -1?ceiling=-1
-    0.5?ceiling=1
-    1.5?ceiling=2
-    -0.5?ceiling=0
-    -1.5?ceiling=-1
-    0.25?ceiling=1
-    -0.25?ceiling=0
-    1.75?ceiling=2
-    -1.75?ceiling=-1
-    1.01?ceiling=2
-    -1.01?ceiling=-1
-    0.01?ceiling=1
-    -0.01?ceiling=0
-    127?ceiling=127
-    128?ceiling=128
-    -127?ceiling=-127
-    -128?ceiling=-128
-    32767?ceiling=32767
-    32768?ceiling=32768
-    -32767?ceiling=-32767
-    -32768?ceiling=-32768
-    2147483647?ceiling=2147483647
-    2147483648?ceiling=2147483648
-    -2147483647?ceiling=-2147483647
-    -2147483648?ceiling=-2147483648
-    4294967295?ceiling=4294967295
-    4294967296?ceiling=4294967296
-    -4294967295?ceiling=-4294967295
-    -4294967296?ceiling=-4294967296
-    2147483647.1?ceiling=2147483648
-    2147483648.1?ceiling=2147483649
-    -2147483647.1?ceiling=-2147483647
-    -2147483648.1?ceiling=-2147483648
-    4294967295.1?ceiling=4294967296
-    4294967296.1?ceiling=4294967297
-    -4294967295.1?ceiling=-4294967295
-    -4294967296.1?ceiling=-4294967296
-    2147483647.5?ceiling=2147483648
-    2147483648.5?ceiling=2147483649
-    -2147483647.5?ceiling=-2147483647
-    -2147483648.5?ceiling=-2147483648
-    4294967295.5?ceiling=4294967296
-    4294967296.5?ceiling=4294967297
-    -4294967295.5?ceiling=-4294967295
-    -4294967296.5?ceiling=-4294967296
-
-?round
-    0?round=0
-    1?round=1
-    -1?round=-1
-    0.5?round=1
-    1.5?round=2
-    -0.5?round=0
-    -1.5?round=-1
-    0.25?round=0
-    -0.25?round=0
-    1.75?round=2
-    -1.75?round=-2
-    1.01?round=1
-    -1.01?round=-1
-    0.01?round=0
-    -0.01?round=0
-    127?round=127
-    128?round=128
-    -127?round=-127
-    -128?round=-128
-    32767?round=32767
-    32768?round=32768
-    -32767?round=-32767
-    -32768?round=-32768
-    2147483647?round=2147483647
-    2147483648?round=2147483648
-    -2147483647?round=-2147483647
-    -2147483648?round=-2147483648
-    4294967295?round=4294967295
-    4294967296?round=4294967296
-    -4294967295?round=-4294967295
-    -4294967296?round=-4294967296
-    2147483647.1?round=2147483647
-    2147483648.1?round=2147483648
-    -2147483647.1?round=-2147483647
-    -2147483648.1?round=-2147483648
-    4294967295.1?round=4294967295
-    4294967296.1?round=4294967296
-    -4294967295.1?round=-4294967295
-    -4294967296.1?round=-4294967296
-    2147483647.5?round=2147483648
-    2147483648.5?round=2147483649
-    -2147483647.5?round=-2147483647
-    -2147483648.5?round=-2147483648
-    4294967295.5?round=4294967296
-    4294967296.5?round=4294967297
-    -4294967295.5?round=-4294967295
-    -4294967296.5?round=-4294967296

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/output-encoding1.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/output-encoding1.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/output-encoding1.txt
deleted file mode 100644
index 3b5215a..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/output-encoding1.txt
+++ /dev/null
@@ -1,27 +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.
- */
-Output charset: UTF-8
-URL escaping charset: undefined
-
-a%FE%FF%00%2F%00%25b
-a%FE%FF%00%2F%00%25b
-a%2F%25b
-a%2F%25b
-a%FE%FF%00%2F%00%25b
-a%2F%25b
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/output-encoding2.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/output-encoding2.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/output-encoding2.txt
deleted file mode 100644
index 6956b6c..0000000
Binary files a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/output-encoding2.txt and /dev/null differ

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/output-encoding3.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/output-encoding3.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/output-encoding3.txt
deleted file mode 100644
index c0369f6..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/output-encoding3.txt
+++ /dev/null
@@ -1,26 +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.
- */
-Output charset: ISO-8859-1
-URL escaping charset: UTF-16
-
-UTF-16: a%FE%FF%00%2F%00%25b
-ISO-8859-1: a%2F%25b
-UTF-16: a%FE%FF%00%2F%00%25b
-ISO-8859-1: a%2F%25b
-ISO-8859-1: a%2F%25b
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/precedence.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/precedence.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/precedence.txt
deleted file mode 100644
index b19cb31..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/precedence.txt
+++ /dev/null
@@ -1,48 +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.
- */
-<html>
-<head>
-<title>FreeMarker: Operator Precedence Test</title>
-</head>
-<body>
-
-@@@@@@@@@@@
-
-<br />
-<br />
-
-##########
-
-<br />
-<br />
-
-&&&&&&&&&&&
-
-<br />
-<br />
-
-!!!!!!!!!!!
-
-<br />
-<br />
-
-$$$$$$$$$$$
-
-</body>
-</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/recover.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/recover.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/recover.txt
deleted file mode 100644
index 880cea3..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/recover.txt
+++ /dev/null
@@ -1,26 +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.
- */
- Hello, World
- Well, that did not work.
- Now we nest another attempt/recover here:
-   Oops...
-   Remember, freeMarker sequences are zero-based! Hello, World
- Now we check the current error message.
-  The template is not currently available
-  The included template had a problem.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/root.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/root.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/root.txt
deleted file mode 100644
index 041222c..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/root.txt
+++ /dev/null
@@ -1,44 +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.
- */
-<html>
-<head>
-<title>FreeMarker: Root Lookup Test</title>
-</head>
-<body>
-
-<p>A simple test follows:</p>
-
-<p>Hello, world!</p>
-
-<p>Access the same variable via the root variable (dot syntax):</p>
-
-<p>Hello, world!</p>
-
-<p>Access the same variable via the root variable (bracket syntax):</p>
-
-<p>Hello, world!</p>
-
-<p>Ensure that root lookups are unaffected by local variables:</p>
-
-
-  Hello, world!
-  Hello, world! Part Deux
-
-</body>
-</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/sequence-builtins.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/sequence-builtins.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/sequence-builtins.txt
deleted file mode 100644
index 4f7796a..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/sequence-builtins.txt
+++ /dev/null
@@ -1,404 +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.
- */
-Sorting scalars:
-----------------
-
-String order:
-- aardvark
-- Barbara
-- beetroot
-- whale
-- zeppelin
-
-First: aardvark
-Last: zeppelin
-Size 5
-
-Numerical order:
-- -324
-- -34
-- 0
-- 0.1
-- 0.11
-- 1
-- 5
-- 111
-- 123
-- 543
-
-First: -324
-Last: 543
-Size 10
-
-Date/time order:
-- 06:05
-- 08:05
-- 08:15
-- 18:00
-
-Boolean order:
-- false
-- false
-- true
-- true
-
-
-Sorting hashes:
----------------
-
-Order by name:
-- aardvark: 30
-- Barbara: 53
-- beetroot: 0.3
-- whale: 2000
-- zeppelin: -200
-
-Order by weight:
-- zeppelin: -200
-- beetroot: 0.3
-- aardvark: 30
-- Barbara: 53
-- whale: 2000
-
-Order by a.x.v:
-- aqweqw
-- dfgdf
-- qweqw
-- utyu
-
-Order by a.y, which is a date:
-- 1998-02-20
-- 1999-01-20
-- 1999-04-19
-- 1999-04-20
-
-Reverse:
---------
-
-Order by weight desc:
-- whale: 2000
-- Barbara: 53
-- aardvark: 30
-- beetroot: 0.3
-- zeppelin: -200
-
-Order by weight desc desc:
-- zeppelin: -200
-- beetroot: 0.3
-- aardvark: 30
-- Barbara: 53
-- whale: 2000
-
-Order by weight desc desc desc:
-- whale: 2000
-- Barbara: 53
-- aardvark: 30
-- beetroot: 0.3
-- zeppelin: -200
-
-Contains:
----------
-
-True:
-true
-true
-true
-true
-true
-true
-true
-
-False:
-false
-false
-false
-false
-false
-false
-false
-
-False: false
-
-Index_of:
----------
-
-0 = 0
-1 = 1
-2 = 2
-6 = 6
-0 = 0
-1 = 1
-2 = 2
-
--1 = -1
--1 = -1
--1 = -1
--1 = -1
--1 = -1
--1 = -1
--1 = -1
-
--1 = -1
-
-Last_index_of:
---------------
-
-6 = 6
-1 = 1
-2 = 2
-7 = 7
--1 = -1
-0 = 0
-1 = 1
-2 = 2
--1 = -1
-
-Index_of and last_index_of with starting indices
-------------------------------------------------
-
-seq_index_of "Joe":
-0 = 0
-0 = 0
-0 = 0
-2 = 2
-2 = 2
--1 = -1
--1 = -1
- 
-seq_last_index_of "Joe":
--1 = -1
--1 = -1
-0 = 0
-0 = 0
-2 = 2
-2 = 2
-2 = 2
- 
-seq_index_of "Susan":
-3 = 3
-3 = 3
-3 = 3
-3 = 3
-3 = 3
-3 = 3
--1 = -1
- 
-seq_last_index_of "Susan":
--1 = -1
--1 = -1
--1 = -1
--1 = -1
--1 = -1
-3 = 3
-3 = 3
-
-seq_index_of "a":
-0 = 0
-0 = 0
-0 = 0
--1 = -1
--1 = -1
--1 = -1
--1 = -1
-
-seq_index_of "b":
-1 = 1
-1 = 1
-1 = 1
-1 = 1
--1 = -1
--1 = -1
-
-seq_index_of "c":
-2 = 2
-2 = 2
-2 = 2
-2 = 2
-2 = 2
--1 = -1
- 
-seq_last_index_of "a":
--1 = -1
--1 = -1
-0 = 0
-0 = 0
-0 = 0
-0 = 0
-0 = 0
-
-seq_last_index_of "b":
--1 = -1
--1 = -1
--1 = -1
-1 = 1
-1 = 1
-1 = 1
-
-seq_last_index_of "c":
--1 = -1
--1 = -1
--1 = -1
--1 = -1
-2 = 2
-2 = 2
-
-Sequence builtins ignoring nulls
---------------------------------
-
-true = true
-2 = 2
-0 = 0
-
-These should throw exception, but for BC they don't:
-false = false
--1 = -1
--1 = -1
-
-Sequence built-ins failing on date-type mismatch
-------------------------------------------------
-
-
-Chunk
------
-
-columns = 1, fill = NULL:
-  Rows: 7
-    a   <-- Columns: 1
-    b   <-- Columns: 1
-    c   <-- Columns: 1
-    d   <-- Columns: 1
-    e   <-- Columns: 1
-    f   <-- Columns: 1
-    g   <-- Columns: 1
-  
-columns = 2, fill = NULL:
-  Rows: 4
-    a b   <-- Columns: 2
-    c d   <-- Columns: 2
-    e f   <-- Columns: 2
-    g   <-- Columns: 1
-  
-columns = 3, fill = NULL:
-  Rows: 3
-    a b c   <-- Columns: 3
-    d e f   <-- Columns: 3
-    g   <-- Columns: 1
-  
-columns = 4, fill = NULL:
-  Rows: 2
-    a b c d   <-- Columns: 4
-    e f g   <-- Columns: 3
-  
-columns = 5, fill = NULL:
-  Rows: 2
-    a b c d e   <-- Columns: 5
-    f g   <-- Columns: 2
-  
-columns = 10, fill = NULL:
-  Rows: 1
-    a b c d e f g   <-- Columns: 7
-  
-columns = 1, fill = -:
-  Rows: 7
-    a   <-- Columns: 1
-    b   <-- Columns: 1
-    c   <-- Columns: 1
-    d   <-- Columns: 1
-    e   <-- Columns: 1
-    f   <-- Columns: 1
-    g   <-- Columns: 1
-  
-columns = 2, fill = -:
-  Rows: 4
-    a b   <-- Columns: 2
-    c d   <-- Columns: 2
-    e f   <-- Columns: 2
-    g -   <-- Columns: 2
-  
-columns = 3, fill = -:
-  Rows: 3
-    a b c   <-- Columns: 3
-    d e f   <-- Columns: 3
-    g - -   <-- Columns: 3
-  
-columns = 4, fill = -:
-  Rows: 2
-    a b c d   <-- Columns: 4
-    e f g -   <-- Columns: 4
-  
-columns = 5, fill = -:
-  Rows: 2
-    a b c d e   <-- Columns: 5
-    f g - - -   <-- Columns: 5
-  
-columns = 10, fill = -:
-  Rows: 1
-    a b c d e f g - - -   <-- Columns: 10
-  
-columns = 3, fill = NULL:
-  Rows: 3
-    1 2 3   <-- Columns: 3
-    4 5 6   <-- Columns: 3
-    7 8 9   <-- Columns: 3
-  
-columns = 3, fill = -:
-  Rows: 3
-    1 2 3   <-- Columns: 3
-    4 5 6   <-- Columns: 3
-    7 8 9   <-- Columns: 3
-  
-columns = 3, fill = NULL:
-  Rows: 1
-    1   <-- Columns: 1
-  
-columns = 3, fill = -:
-  Rows: 1
-    1 - -   <-- Columns: 3
-  
-columns = 3, fill = NULL:
-  Rows: 0
-  
-columns = 3, fill = -:
-  Rows: 0
-  
-
-
-
-Join
-----
-
-- 1, two, three, 4
-- 
-- 1, two, three, 4.
-- (empty)
-- a, c
-- a, c
-- a, c.
-- 
-- (empty)
-- (empty)
-- a, b, c.
-- a, b, c.
-
-
-Misc
-----
-
-First of set 1: a
-First of set 2: a
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/specialvars.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/specialvars.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/specialvars.txt
deleted file mode 100644
index e2fa13e..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/specialvars.txt
+++ /dev/null
@@ -1,25 +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.
- */
-en == en
-en_US == en_US
-utf-8 == utf-8
-specialvars.ftl == specialvars.ftl
-iso-8859-1 == iso-8859-1
-x == x
-true == true
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/string-builtins-regexps-matches.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/string-builtins-regexps-matches.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/string-builtins-regexps-matches.txt
deleted file mode 100644
index ba14e7f..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/string-builtins-regexps-matches.txt
+++ /dev/null
@@ -1,99 +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.
- */
-
-List mode:
-Size: 4
-[L16][L27][L38][L49]
-[L16][L27][L38][L49]
-
-Iterator mode:
-[L16][L27][L38][L49]
-[L16(L16, L27, L38, L49)][L27(L16, L27, L38, L49)][L38(L16, L27, L38, L49)][L49(L16, L27, L38, L49)]
-[L16][L27][L38][L49]
-
-Iterator mode changes to list mode:
-[L16]/4[L27]/4[L38]/4[L49]/4
-[L16][L27][L38][L49]
-
-Iterator mode changes to list mode 2:
-[L16][L27][L38][L49]
-[L16]/4[L27]/4[L38]/4[L49]/4
-
-List mode with embedded iteration:
-[L16(L16, L27, L38, L49)][L27(L16, L27, L38, L49)][L38(L16, L27, L38, L49)][L49(L16, L27, L38, L49)]
-
-Entire input match:
-- M: L16
-    - G: L16
-    - G: 1
-    - G: 6
-- M: L27
-    - G: L27
-    - G: 2
-    - G: 7
-- M: L38
-    - G: L38
-    - G: 3
-    - G: 8
-- M: L49
-    - G: L49
-    - G: 4
-    - G: 9
-firstGS was: L16, 1, 6
-
-Entire input match 2:
-Matches: true
-- G: x12
-- G: 1
-- G: 2
-As list:
-- M: x12
-    - G: x12
-    - G: 1
-    - G: 2
-Groups again:
-- G: x12
-- G: 1
-- G: 2
-
-Entire input match 3:
-Matches: false
-
-Entire input match 4:
-Matches: true
-- G: x12
-- G: 1
-- G: 2
-
-Substring match nested into entire input match:
-- G: x12 ([x12{x12, 1, 2}])
-- G: 1 ([x12{x12, 1, 2}])
-- G: 2 ([x12{x12, 1, 2}])
-
-Different entire input and substring matches:
-123, 123
-- M: 1 (Gs: 1, 1)
-- M: 2 (Gs: 2, 2)
-- M: 3 (Gs: 3, 3)
-
-Different entire input and substring matches 2:
-123
-- M: 1 (Gs: 1)
-- M: 2 (Gs: 2)
-- M: 3 (Gs: 3)

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/string-builtins-regexps.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/string-builtins-regexps.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/string-builtins-regexps.txt
deleted file mode 100644
index c54dc96..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/string-builtins-regexps.txt
+++ /dev/null
@@ -1,112 +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.
- */
-true == true
-true == true
-
-false == false
-true == true
-
-false == false
-true == true
-
-false == false
-true == true
-
-false == false
-false == false
-false == false
-true == true
-true == true
-true == true
-
-false == false
-false == false
-true == true
-true == true
-true == true
-true == true
-
-
-Lower 'c'-words:
-- coverage
-- considered
-
-Any 'c'-words:
-- Code
-- coverage
-- considered
-
-Lower line-last words:
-- coverage
-
-Any line-last words:
-- coverage
-- BROKEN
-
-Any last words:
-- BROKEN
-
-c-word with follower:
-- "Code without"
-  Groups: "Code without", "Code", "without"
-- "coverage\nis"
-  Groups: "coverage\nis", "coverage", "is"
-- "considered to"
-  Groups: "considered to", "considered", "to"
-
-c-word with follower in the same line:
-- Code without
-- considered to
-
-Lower c-word with follower in the same line:
-- considered to
-
-  Ignored but logged in 2.3: False == False
-  Ignored but logged in 2.3: False == False
-
-FOObar == FOObar
-Foobar == Foobar
-FOObar == FOObar
-FOObarFOO == FOObarFOO
-FOObarfOO == FOObarfOO
-FOObarfOO == FOObarfOO
-Foobar == Foobar
-FOObar == FOObar
-FOObarFOO == FOObarFOO
-FOObarfOO == FOObarfOO
-FOObarfOO == FOObarfOO
-foobar == foobar
-foobar == foobar
-FOObar == FOObar
-FOObarFOO == FOObarFOO
-FOObarfOo == FOObarfOo
-FAlse == FAlse
-FAlse == FAlse
-
-  Ignored but logged in 2.3: FOObar
-
-[foo, barxbaaz] == [foo, barxbaaz]
-[foo, barxbaaz] == [foo, barxbaaz]
-[foo, bar, baaz] == [foo, bar, baaz]
-[foo, barxbaaz] == [foo, barxbaaz]
-[foo, bar, baaz] == [foo, bar, baaz]
-[fooXXbarxxbaaz] == [fooXXbarxxbaaz]
-[foo, bar, baaz] == [foo, bar, baaz]
-[F, ls] == [F, ls]
-[Fals, ] == [Fals, ]
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/string-builtins1.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/string-builtins1.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/string-builtins1.txt
deleted file mode 100644
index 6e689ac..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/string-builtins1.txt
+++ /dev/null
@@ -1,112 +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.
- */
-FreeMarker: Encoding string built-in tests
-
-  
-cap_first:    DieBugsDie! * vazzZE 123456 --cdc-- --<<--@ x ${"kigyo"?upper_case}  
-uncap_first:  dieBugsDie! * vazzZE 123456 --cdc-- --<<--@ x ${"kigyo"?upper_case}  
-uncap_first:blah
-capitalize:   Diebugsdie! * Vazzze 123456 --cdc-- --<<--@ X ${"kigyo"?upper_case}  
-html:         dieBugsDie! * vazzZE 123456 --cdc-- --&lt;&lt;--@ x ${&quot;kigyo&quot;?upper_case}  
-length:     71
-lower_case:   diebugsdie! * vazzze 123456 --cdc-- --<<--@ x ${"kigyo"?upper_case}  
-rtf:          dieBugsDie! * vazzZE 123456 --cdc-- --<<--@ x $\{"kigyo"?upper_case\}  
-trim:       dieBugsDie! * vazzZE 123456 --cdc-- --<<--@ x ${"kigyo"?upper_case}
-trim2:      foo bar
-trim3:      foo bar
-trim4:      foo bar
-upper_case:   DIEBUGSDIE! * VAZZZE 123456 --CDC-- --<<--@ X ${"KIGYO"?UPPER_CASE}  
-xml:          dieBugsDie! * vazzZE 123456 --cdc-- --&lt;&lt;--@ x ${&quot;kigyo&quot;?upper_case}  
-xhtml:      &quot;Blah&#39;s is &gt; 1 &amp; &lt; 2&quot;
-
-word_list:
-- dieBugsDie!
-- *
-- vazzZE
-- 123456
-- --cdc--
-- --<<--@
-- x
-- ${"kigyo"?upper_case}
-
-interpret:   dieBugsDie! * vazzZE 123456 --cdc-- --<<--@ x KIGYO  
-number: -122,35
-1500
-5
-0
-0
-true
-true
-true
-true
-true
-
-default constructor
-1
-xxx
-xxx:yyy
-
-
-In The Sacred, Holy beginning, God created The Sacred, Holy Heavens and The Sacred, Holy Earth. 
-In the very beginning, God created the Heavens and The Earth. 
-|I|n| |t|h|e| |b|e|g|i|n|n|i|n|g|,| |G|o|d| |c|r|e|a|t|e|d| |t|h|e| |H|e|a|v|e|n|s| |a|n|d| |T|h|e| |E|a|r|t|h|.| 
-|In the beginning, God created the Heavens and The Earth. 
-
-In the beginning, God created the sky and The Earth. 
-
-matches
-
-  the beginning
-  the sacred beginning
-  the Heavens
-  the sacred Heavens
-  The Earth
-  The sacred Earth
-
-In the beginning, God created the Heavens and The Earth.
-beginning
-the Heavens and The Earth.
-
-   foo
-   bar
-   baz
-       foobar
-
-
-FOOBAR
-
-[a] = [a]
-[a\\'x'\nb] = [a\\'x'\nb]
-[\u0001\u001a ] = [\u0001\u001a ]
-
-[a] = [a]
-[a\\\'x\'\nb] = [a\\\'x\'\nb]
-[\x01\x1A ] = [\x01\x1A ]
-[\x3C![CDATA[] = [\x3C![CDATA[]
-[]]\>] = []]\>]
-
-[a] = [a]
-[a\\'x'\nb] = [a\\'x'\nb]
-[\u0001\u001A ] = [\u0001\u001A ]
-[\n\r\t\f\b\"] = [\n\r\t\f\b\"]
-[\/] = [\/]
-[a/b] = [a/b]
-[<\/script>] = [<\/script>]
-[\u003C![CDATA[] = [\u003C![CDATA[]
-[]]\u003E] = []]\u003E]

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/string-builtins2.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/string-builtins2.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/string-builtins2.txt
deleted file mode 100644
index f5eebd9..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/string-builtins2.txt
+++ /dev/null
@@ -1,135 +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.
- */
---
-1 = 1
-5 = 5
-0 = 0
---
-5 = 5
-1 = 1
-7 = 7
---
-true = true
-false = false
-true = true
---
-true = true
-false = false
-true = true
---
-true = true
-true = true
-true = true
-false = false
-true = true
---
-[abbcdbb] = [abbcdbb]
-[qwe] = [qwe]
-[qwe] = [qwe]
-[qwe] = [qwe]
-[qwe
-] = [qwe
-]
-[qwe
-] = [qwe
-]
---
-[abbcdbb] = [abbcdbb]
-[abb-dbb] = [abb-dbb]
-[a-=*cd-=*] = [a-=*cd-=*]
---
-[a][][cd][][] == [a][][cd][][]
-[][die][maggots][!] == [][die][maggots][!]
-[Die maggots!] == [Die maggots!]
---
-[     ]
-[    a]
-[   ab]
-[  abc]
-[ abcd]
-[abcde]
-[abcdef]
-[abcdefg]
-[abcdefgh]
-[-----]
-[----a]
-[---ab]
-[--abc]
-[-abcd]
-[abcde]
-[abcdef]
-[abcdefg]
-[abcdefgh]
-[.oO.oO.o]
-[.oO.oO.a]
-[.oO.oOab]
-[.oO.oabc]
-[.oO.abcd]
-[.oOabcde]
-[.oabcdef]
-[.abcdefg]
-[abcdefgh]
-[abcdefghi]
-[abcdefghij]
-[]
-[/]
-[/\]
-[/\_]
-[/\_/]
-[/\_/\]
-[/\_/\_]
-[/\_/\_/]
---
-[     ]
-[a    ]
-[ab   ]
-[abc  ]
-[abcd ]
-[abcde]
-[abcdef]
-[abcdefg]
-[abcdefgh]
-[-----]
-[a----]
-[ab---]
-[abc--]
-[abcd-]
-[abcde]
-[abcdef]
-[abcdefg]
-[abcdefgh]
-[.oO.oO.o]
-[aoO.oO.o]
-[abO.oO.o]
-[abc.oO.o]
-[abcdoO.o]
-[abcdeO.o]
-[abcdef.o]
-[abcdefgo]
-[abcdefgh]
-[abcdefghi]
-[abcdefghij]
-[]
-[/]
-[/\]
-[/\_]
-[/\_/]
-[/\_/\]
-[/\_/\_]
-[/\_/\_/]
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/stringbimethods.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/stringbimethods.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/stringbimethods.txt
deleted file mode 100644
index 8ef415d..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/stringbimethods.txt
+++ /dev/null
@@ -1,29 +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.
- */
-3.00
-3.00
-01:02:03.000
-01:02:03.000
----
-de
-true false
-yes no
-igen nem
-0.0 1.0
-true true
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/stringliteral.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/stringliteral.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/stringliteral.txt
deleted file mode 100644
index 3d9d4c9..0000000
Binary files a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/stringliteral.txt and /dev/null differ

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/switch.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/switch.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/switch.txt
deleted file mode 100644
index 5d42785..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/switch.txt
+++ /dev/null
@@ -1,80 +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.
- */
-<html>
-<head>
-<title>FreeMarker: Switch-Case Test</title>
-</head>
-<body>
-
-<p>Here we iterate over a list of animals.</p>
-
-<p>Animal is: aardvark.<br />
-        This is the HTML for other animals.
-</p>
-<p>Animal is: kiwi.<br />
-        This is the HTML for the user's favorite animal.
-</p>
-<p>Animal is: gecko.<br />
-        This is the HTML for small animals.
-</p>
-<p>Animal is: cat.<br />
-        This is the HTML for other animals.
-</p>
-<p>Animal is: dog.<br />
-        This is the HTML for other animals.
-</p>
-<p>Animal is: elephant.<br />
-        This is the HTML for large animals.
-</p>
-<p>Animal is: squirrel.<br />
-        This is the HTML for small animals.
-</p>
-<p>Animal is: zebra.<br />
-        This is the HTML for a large stripey animal.
-        This is the HTML for large animals.
-</p>
-
-      1
-          i2
-      2
-          i4
-          ft
-      ft
-      3
-          i4
-      3
-          i6
-
-[]
-
-  ""
-  "1234"
-  "234"
-  "34"
-  "4"
-
-  "12default45"
-  "2default45"
-  "default"
-  "45"
-  "5"
-
-
-</body>
-</html>


[06/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/OverloadedMethods2.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/OverloadedMethods2.java b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/OverloadedMethods2.java
deleted file mode 100644
index 4e80e71..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/OverloadedMethods2.java
+++ /dev/null
@@ -1,1110 +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.test.templatesuite.models;
-
-import java.io.File;
-import java.io.Serializable;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.freemarker.core.Environment;
-import org.apache.freemarker.core.model.AdapterTemplateModel;
-import org.apache.freemarker.core.model.ObjectWrapper;
-import org.apache.freemarker.core.model.TemplateBooleanModel;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateNumberModel;
-import org.apache.freemarker.core.model.WrapperTemplateModel;
-import org.apache.freemarker.core.model.impl.RationalNumber;
-import org.apache.freemarker.core.util._StringUtil;
-import org.apache.freemarker.test.TestUtil;
-
-public class OverloadedMethods2 {
-
-    public String mVarargs(String... a1) {
-        StringBuilder sb = new StringBuilder();
-        for (String s : a1) {
-            sb.append(s);
-        }
-        return "mVarargs(String... a1 = " + sb + ")";
-    }
-    
-    public BigInteger bigInteger(BigDecimal n) {
-        return n.toBigInteger();
-    }
-
-    public RationalNumber rational(int a, int b) {
-        return new RationalNumber(a, b);
-    }
-    
-    public String mVarargs(File a1, String... a2) {
-        return "mVarargs(File a1, String... a2)";
-    }
-
-    public NumberAndStringModel getNnS(String s) {
-        return new NumberAndStringModel(s);
-    }
-    
-    public String mNull1(String a1) {
-        return "mNull1(String a1 = " + a1 + ")";
-    }
-
-    public String mNull1(int a1) {
-        return "mNull1(int a1 = " + a1 + ")";
-    }
-    
-    public String mNull2(String a1) {
-        return "mNull2(String a1 = " + a1 + ")";
-    }
-    
-    public String mNull2(Object a1) {
-        return "mNull2(Object a1 = " + a1 + ")";
-    }
-    
-    public String mSpecificity(Object a1, String a2) {
-        return "mSpecificity(Object a1, String a2)";
-    }
-    
-    public String mSpecificity(String a1, Object a2) {
-        return "mSpecificity(String a1, Object a2)";
-    }
-    
-    public String mChar(char a1) {
-        return "mChar(char a1 = " + a1 + ")";
-    }
-    
-    public String mChar(Character a1) {
-        return "mChar(Character a1 = " + a1 + ")";
-    }
-    
-    public String mBoolean(boolean a1) {
-        return "mBoolean(boolean a1 = " + a1 + ")";
-    }
-    
-    public String mBoolean(Boolean a1) {
-        return "mBoolean(Boolean a1 = " + a1 + ")";
-    }
-
-    public int mIntNonOverloaded(int a1) {
-        return a1;
-    }
-
-    public String mIntPrimVSBoxed(int a1) {
-        return "mIntPrimVSBoxed(int a1 = " + a1 + ")";
-    }
-    
-    public String mIntPrimVSBoxed(Integer a1) {
-        return "mIntPrimVSBoxed(Integer a1 = " + a1 + ")";
-    }
-
-    public String mNumPrimVSPrim(short a1) {
-        return "mNumPrimVSPrim(short a1 = " + a1 + ")";
-    }
-    
-    public String mNumPrimVSPrim(long a1) {
-        return "mNumPrimVSPrim(long a1 = " + a1 + ")";
-    }
-
-    public String mNumBoxedVSBoxed(Short a1) {
-        return "mNumBoxedVSBoxed(Short a1 = " + a1 + ")";
-    }
-    
-    public String mNumBoxedVSBoxed(Long a1) {
-        return "mNumBoxedVSBoxed(Long a1 = " + a1 + ")";
-    }
-
-    public String mNumUnambigous(Short a1, boolean otherOverload) {
-        return "mmNumUnambigous won't be called";
-    }
-    
-    public String mNumUnambigous(Integer a1) {
-        return "mNumUnambigous(Integer a1 = " + a1 + ")";
-    }
-    
-    public String mNumBoxedAll(Byte a1) {
-        return "mNumBoxedAll(Byte a1 = " + a1 + ")";
-    }
-    
-    public String mNumBoxedAll(Short a1) {
-        return "mNumBoxedAll(Short a1 = " + a1 + ")";
-    }
-
-    public String mNumBoxedAll(Integer a1) {
-        return "mNumBoxedAll(Integer a1 = " + a1 + ")";
-    }
-    
-    public String mNumBoxedAll(Long a1) {
-        return "mNumBoxedAll(Long a1 = " + a1 + ")";
-    }
-    
-    public String mNumBoxedAll(Float a1) {
-        return "mNumBoxedAll(Float a1 = " + a1 + ")";
-    }
-    
-    public String mNumBoxedAll(Double a1) {
-        return "mNumBoxedAll(Double a1 = " + a1 + ")";
-    }
-    
-    public String mNumBoxedAll(BigInteger a1) {
-        return "mNumBoxedAll(BigInteger a1 = " + a1 + ")";
-    }
-    
-    public String mNumBoxedAll(BigDecimal a1) {
-        return "mNumBoxedAll(BigDecimal a1 = " + a1 + ")";
-    }
-    
-    public String mNumPrimAll(byte a1) {
-        return "mNumPrimAll(byte a1 = " + a1 + ")";
-    }
-    
-    public String mNumPrimAll(short a1) {
-        return "mNumPrimAll(short a1 = " + a1 + ")";
-    }
-
-    public String mNumPrimAll(int a1) {
-        return "mNumPrimAll(int a1 = " + a1 + ")";
-    }
-    
-    public String mNumPrimAll(long a1) {
-        return "mNumPrimAll(long a1 = " + a1 + ")";
-    }
-    
-    public String mNumPrimAll(float a1) {
-        return "mNumPrimAll(float a1 = " + a1 + ")";
-    }
-    
-    public String mNumPrimAll(double a1) {
-        return "mNumPrimAll(double a1 = " + a1 + ")";
-    }
-    
-    public String mNumPrimAll(BigInteger a1) {
-        return "mNumPrimAll(BigInteger a1 = " + a1 + ")";
-    }
-    
-    public String mNumPrimAll(BigDecimal a1) {
-        return "mNumPrimAll(BigDecimal a1 = " + a1 + ")";
-    }
-
-    
-    public String mNumBoxedAll2nd(Short a1) {
-        return "mNumBoxedAll2nd(Short a1 = " + a1 + ")";
-    }
-
-    public String mNumBoxedAll2nd(Long a1) {
-        return "mNumBoxedAll2nd(Long a1 = " + a1 + ")";
-    }
-    
-    public String mNumBoxedAll2nd(Double a1) {
-        return "mNumBoxedAll2nd(Double a1 = " + a1 + ")";
-    }
-    
-    public String mNumPrimAll2nd(short a1) {
-        return "mNumPrimAll2nd(short a1 = " + a1 + ")";
-    }
-    
-    public String mNumPrimAll2nd(long a1) {
-        return "mNumPrimAll2nd(long a1 = " + a1 + ")";
-    }
-    
-    public String mNumPrimAll2nd(double a1) {
-        return "mNumPrimAll2nd(double a1 = " + a1 + ")";
-    }
-    
-    public String mNumPrimFallbackToNumber(long a1) {
-        return "mNumPrimFallbackToNumber(long a1 = " + a1 + ")";
-    }
-    
-    public String mNumPrimFallbackToNumber(Number a1) {
-        return "mNumPrimFallbackToNumber(Number a1 = " + a1 + ")";
-    }
-    
-    public String mNumPrimFallbackToNumber(Object a1) {
-        return "mNumPrimFallbackToNumber(Object a1 = " + a1 + ")";
-    }
-    
-    public String mNumBoxedFallbackToNumber(Long a1) {
-        return "mNumBoxedFallbackToNumber(Long a1 = " + a1 + ")";
-    }
-    
-    public String mNumBoxedFallbackToNumber(Number a1) {
-        return "mNumBoxedFallbackToNumber(Number a1 = " + a1 + ")";
-    }
-    
-    public String mNumBoxedFallbackToNumber(Object a1) {
-        return "mNumBoxedFallbackToNumber(Object a1 = " + a1 + ")";
-    }
-
-    public String mDecimalLoss(int a1) {
-        return "mDecimalLoss(int a1 = " + a1 + ")";
-    }
-        
-    public String mDecimalLoss(double a1) {
-        return "mDecimalLoss(double a1 = " + a1 + ")";
-    }
-    
-    public String mNumConversionLoses1(byte i, Object o1, Object o2) {
-        return "byte " + i;
-    }
-    
-    public String mNumConversionLoses1(double i, Object o1, Object o2) {
-        return "double " + i;
-    }
-
-    public String mNumConversionLoses1(Number i, String o1, String o2) {
-        return "Number " + i + " " + i.getClass().getName();
-    }
-
-    public String mNumConversionLoses2(int i, Object o1, Object o2) {
-        return "int " + i;
-    }
-
-    public String mNumConversionLoses2(long i, Object o1, Object o2) {
-        return "long " + i;
-    }
-
-    public String mNumConversionLoses2(Number i, String o1, String o2) {
-        return "Number " + i + " " + i.getClass().getName();
-    }
-
-    public String mNumConversionLoses3(int i, Object o1, Object o2) {
-        return "int " + i;
-    }
-
-    public String mNumConversionLoses3(Serializable i, String o1, String o2) {
-        return "Serializable " + i + " " + i.getClass().getName();
-    }
-    
-    public String nIntAndLong(int i) {
-        return "nIntAndLong(int " + i + ")";
-    }
-    
-    public String nIntAndLong(long i) {
-        return "nIntAndLong(long " + i + ")";
-    }
-
-    public String nIntAndShort(int i) {
-        return "nIntAndShort(int " + i + ")";
-    }
-    
-    public String nIntAndShort(short i) {
-        return "nIntAndShort(short " + i + ")";
-    }
-
-    public String nLongAndShort(long i) {
-        return "nLongAndShort(long " + i + ")";
-    }
-    
-    public String nLongAndShort(short i) {
-        return "nLongAndShort(short " + i + ")";
-    }
-
-    public String varargs1(String s, int... xs) {
-        return "varargs1(String s = " + _StringUtil.jQuote(s) + ", int... xs = " + TestUtil.arrayToString(xs) + ")";
-    }
-
-    public String varargs1(String s, double... xs) {
-        return "varargs1(String s = " + _StringUtil.jQuote(s) + ", double... xs = " + TestUtil.arrayToString(xs) + ")";
-    }
-
-    public String varargs1(String s, Object... xs) {
-        return "varargs1(String s = " + _StringUtil.jQuote(s) + ", Object... xs = " + TestUtil.arrayToString(xs) + ")";
-    }
-
-    public String varargs1(Object s, Object... xs) {
-        return "varargs1(Object s = " + s + ", Object... xs = " + TestUtil.arrayToString(xs) + ")";
-    }
-
-    public String varargs2(int... xs) {
-        return "varargs2(int... xs = " + TestUtil.arrayToString(xs) + ")";
-    }
-
-    public String varargs2(double... xs) {
-        return "varargs2(double... xs = " + TestUtil.arrayToString(xs) + ")";
-    }
-
-    public String varargs3(String... xs) {
-        return "varargs3(String... xs = " + TestUtil.arrayToString(xs) + ")";
-    }
-
-    public String varargs3(Comparable... xs) {
-        return "varargs3(Comparable... xs = " + TestUtil.arrayToString(xs) + ")";
-    }
-    
-    public String varargs3(Object... xs) {
-        return "varargs3(Object... xs = " + TestUtil.arrayToString(xs) + ")";
-    }
-    
-    public String varargs4(Integer... xs) {
-        return "varargs4(Integer... xs = " + TestUtil.arrayToString(xs) + ")";
-    }
-
-    public String varargs4(int... xs) {
-        return "varargs4(int... xs = " + TestUtil.arrayToString(xs) + ")";
-    }
-
-    public String varargs5(int... xs) {
-        return "varargs5(int... xs = " + TestUtil.arrayToString(xs) + ")";
-    }
-    
-    public String varargs5(int a1, int... xs) {
-        return "varargs5(int a1 = " + a1 + ", int... xs = " + TestUtil.arrayToString(xs) + ")";
-    }
-    
-    public String varargs5(int a1, int a2, int... xs) {
-        return "varargs5(int a1 = " + a1 + ", int a2 = " + a2 + ", int... xs = " + TestUtil.arrayToString(xs) + ")";
-    }
-
-    public String varargs5(int a1, int a2, int a3, int... xs) {
-        return "varargs5(int a1 = " + a1 + ", int a2 = " + a2 + ", int a3 = " + a3
-                + ", int... xs = " + TestUtil.arrayToString(xs) + ")";
-    }
-
-    public String varargs6(String a1, int... xs) {
-        return "varargs6(String a1 = " + a1 + ", int... xs = " + TestUtil.arrayToString(xs) + ")";
-    }
-    
-    public String varargs6(Object a1, int a2, int... xs) {
-        return "varargs6(Object a1 = " + a1 + ", int a2 = " + a2 + ", int... xs = " + TestUtil.arrayToString(xs) + ")";
-    }
-    
-    public String varargs7(int... xs) {
-        return "varargs7(int... xs = " + TestUtil.arrayToString(xs) + ")";
-    }
-    
-    public String varargs7(short a1, int... xs) {
-        return "varargs7(short a1 = " + a1 + ", int... xs = " + TestUtil.arrayToString(xs) + ")";
-    }
-    
-    public String mNullAmbiguous(String s) {
-        return "mNullAmbiguous(String s = " + s + ")";
-    }
-
-    public String mNullAmbiguous(int i) {
-        return "mNullAmbiguous(int i = " + i + ")";
-    }
-
-    public String mNullAmbiguous(File f) {
-        return "mNullAmbiguous(File f = " + f + ")";
-    }
-    
-    public String mNullAmbiguous2(String s) {
-        return "mNullNonAmbiguous(String s = " + s + ")";
-    }
-
-    public String mNullAmbiguous2(File f) {
-        return "mNullAmbiguous(File f = " + f + ")";
-    }
-
-    public String mNullAmbiguous2(Object o) {
-        return "mNullAmbiguous(Object o = " + o + ")";
-    }
-
-    public String mNullNonAmbiguous(String s) {
-        return "mNullNonAmbiguous(String s = " + s + ")";
-    }
-
-    public String mNullNonAmbiguous(int i) {
-        return "mNullNonAmbiguous(int i = " + i + ")";
-    }
-    
-    public String mVarargsIgnoredTail(int i, double... ds) {
-        return "mVarargsIgnoredTail(int i = " + i + ", double... ds = " + TestUtil.arrayToString(ds) + ")"; 
-    }
-    
-    public String mVarargsIgnoredTail(int... is) {
-        return "mVarargsIgnoredTail(int... is = " + TestUtil.arrayToString(is) + ")"; 
-    }
-    
-    public String mLowRankWins(int x, int y, Object o) {
-        return "mLowRankWins(int x = " + x + ", int y = " + y + ", Object o = " + o + ")";
-    }
-
-    public String mLowRankWins(Integer x, Integer y, String s) {
-        return "mLowRankWins(Integer x = " + x + ", Integer y = " + y + ", String s = " + s + ")";
-    }
-    
-    public String mRareWrappings(File f, double d1, Double d2, double d3, boolean b) {
-        return "mRareWrappings(File f = " + f + ", double d1 = " + d1 + ", Double d2 = " + d2
-                + ", double d3 = " + d3 + ", b = " + b + ")";
-    }
-
-    public String mRareWrappings(Object o, double d1, Double d2, Double d3, boolean b) {
-        return "mRareWrappings(Object o = " + o + ", double d1 = " + d1 + ", Double d2 = " + d2
-                + ", double d3 = " + d3 + ", b = " + b + ")";
-    }
-
-    public String mRareWrappings(String s, double d1, Double d2, Double d3, boolean b) {
-        return "mRareWrappings(String s = " + s + ", double d1 = " + d1 + ", Double d2 = " + d2
-                + ", double d3 = " + d3 + ", b = " + b + ")";
-    }
-
-    public String mRareWrappings2(String s) {
-        return "mRareWrappings2(String s = " + s + ")";
-    }
-    
-    public String mRareWrappings2(byte b) {
-        return "mRareWrappings2(byte b = " + b + ")";
-    }
-    
-    public File getFile() {
-        return new File("file");
-    }
-
-    public String mSeqToArrayNonOverloaded(String[] items, String s) {
-        return "mSeqToArrayNonOverloaded(String[] " + TestUtil.arrayToString(items) + ", String " + s + ")";
-    }
-    
-    public String mSeqToArrayGoodHint(String[] items, String s) {
-        return "mSeqToArrayGoodHint(String[] " + TestUtil.arrayToString(items) + ", String " + s + ")";
-    }
-
-    public String mSeqToArrayGoodHint(String[] items, int i) {
-        return "mSeqToArrayGoodHint(String[] " + TestUtil.arrayToString(items) + ", int " + i + ")";
-    }
-
-    public String mSeqToArrayGoodHint2(String[] items, String s) {
-        return "mSeqToArrayGoodHint2(String[] " + TestUtil.arrayToString(items) + ", String " + s + ")";
-    }
-
-    public String mSeqToArrayGoodHint2(String item) {
-        return "mSeqToArrayGoodHint2(String " + item + ")";
-    }
-    
-    public String mSeqToArrayPoorHint(String[] items, String s) {
-        return "mSeqToArrayPoorHint(String[] " + TestUtil.arrayToString(items) + ", String " + s + ")";
-    }
-
-    public String mSeqToArrayPoorHint(String item, int i) {
-        return "mSeqToArrayPoorHint(String " + item + ", int " + i + ")";
-    }
-
-    public String mSeqToArrayPoorHint2(String[] items) {
-        return "mSeqToArrayPoorHint2(String[] " + TestUtil.arrayToString(items) + ")";
-    }
-
-    public String mSeqToArrayPoorHint2(String item) {
-        return "mSeqToArrayPoorHint2(String " + item + ")";
-    }
-    
-    public String mSeqToArrayPoorHint3(String[] items) {
-        return "mSeqToArrayPoorHint3(String[] " + TestUtil.arrayToString(items) + ")";
-    }
-
-    public String mSeqToArrayPoorHint3(int[] items) {
-        return "mSeqToArrayPoorHint3(int[] " + TestUtil.arrayToString(items) + ")";
-    }
-
-    public String mStringArrayVsListPreference(String[] items) {
-        return "mStringArrayVsListPreference(String[] " + TestUtil.arrayToString(items) + ")";
-    }
-
-    public String mStringArrayVsListPreference(List items) {
-        return "mStringArrayVsListPreference(List " + TestUtil.listToString(items) + ")";
-    }
-
-    public String mStringArrayVsObjectArrayPreference(String[] items) {
-        return "mStringArrayVsObjectArrayPreference(String[] " + TestUtil.arrayToString(items) + ")";
-    }
-
-    public String mStringArrayVsObjectArrayPreference(Object[] items) {
-        return "mStringArrayVsObjectArrayPreference(Object[] " + TestUtil.arrayToString(items) + ")";
-    }
-
-    public String mIntArrayVsIntegerArrayPreference(int[] items) {
-        return "mIntArrayVsIntegerArrayPreference(int[] " + TestUtil.arrayToString(items) + ")";
-    }
-
-    public String mIntArrayVsIntegerArrayPreference(Integer[] items) {
-        return "mIntArrayVsIntegerArrayPreference(Integer[] " + TestUtil.arrayToString(items) + ")";
-    }
-    
-    public String mIntArrayNonOverloaded(int[] items) {
-        return "mIntArrayNonOverloaded(int[] " + TestUtil.arrayToString(items) + ")";
-    }
-
-    public String mIntegerArrayNonOverloaded(Integer[] items) {
-        return "mIntegerArrayNonOverloaded(Integer[] " + TestUtil.arrayToString(items) + ")";
-    }
-
-    public String mIntegerListNonOverloaded(List<Integer> items) {
-        return "mIntegerListNonOverloaded(List<Integer> " + items + ")";
-    }
-
-    public String mStringListNonOverloaded(List<String> items) {
-        return "mStringListNonOverloaded(List<String> " + items + ")";
-    }
-
-    public String mStringArrayNonOverloaded(String[] items) {
-        return "mStringArrayNonOverloaded(String[] " + TestUtil.arrayToString(items) + ")";
-    }
-
-    public String mObjectListNonOverloaded(List<Object> items) {
-        return "mObjectListNonOverloaded(List<Object> " + items + ")";
-    }
-
-    public String mObjectArrayNonOverloaded(Object[] items) {
-        return "mObjectArrayNonOverloaded(Object[] " + TestUtil.arrayToString(items) + ")";
-    }
-
-    public String mIntegerArrayOverloaded(Integer[] items, int i) {
-        return "mIntegerArrayOverloaded(Integer[] " + TestUtil.arrayToString(items) + ", int " + i + ")";
-    }
-
-    public String mIntegerArrayOverloaded(Object obj, boolean b) {
-        return "mIntegerArrayOverloaded(Object " + obj + ", boolean " + b + ")";
-    }
-
-    public String mStringArrayOverloaded(String[] items, int i) {
-        return "mStringArrayOverloaded(String[] " + TestUtil.arrayToString(items) + ", int " + i + ")";
-    }
-
-    public String mStringArrayOverloaded(Object obj, boolean b) {
-        return "mStringArrayOverloaded(Object " + obj + ", boolean " + b + ")";
-    }
-
-    public String mCharArrayOverloaded(char[] items, int i) {
-        return "mCharArrayOverloaded(char[] " + TestUtil.arrayToString(items) + ", int " + i + ")";
-    }
-
-    public String mCharArrayOverloaded(Character[] items, String s) {
-        return "mCharArrayOverloaded(Character[] " + TestUtil.arrayToString(items) + ", String " + s + ")";
-    }
-    
-    public String mCharArrayOverloaded(Object obj, boolean b) {
-        return "mCharArrayOverloaded(Object " + obj + ", boolean " + b + ")";
-    }
-
-    public String mStringArrayArrayOverloaded(String[][] arrayArray, int i) {
-        return "mStringArrayArrayOverloaded(String[][] " + TestUtil.arrayToString(arrayArray) + ", int " + i + ")";
-    }
-    
-    public String mStringArrayArrayOverloaded(Object obj, boolean b) {
-        return "mStringArrayArrayOverloaded(Object " + obj + ", boolean " + b + ")";
-    }
-    
-    public String mIntArrayArrayOverloaded(int[][] xss) {
-        return "mIntArrayArrayOverloaded(" + TestUtil.arrayToString(xss) + ")";
-    }
-
-    public String mIntArrayArrayOverloaded(String s) {
-        return "mIntArrayArrayOverloaded(" + s + ")";
-    }
-    
-    public String mArrayOfListsOverloaded(List[] xss) {
-        return "mArrayOfListsOverloaded(" + TestUtil.arrayToString(xss) + ")";
-    }
-
-    public String mArrayOfListsOverloaded(String x) {
-        return "mArrayOfListsOverloaded(" + x + ")";
-    }
-    
-    public String mIntArrayArrayNonOverloaded(int[][] xss) {
-        return "mIntArrayArrayNonOverloaded(" + TestUtil.arrayToString(xss) + ")";
-    }
-
-    public String mArrayOfListsNonOverloaded(List[] xss) {
-        return "mArrayOfListsNonOverloaded(" + TestUtil.arrayToString(xss) + ")";
-    }
-    
-    public String mStringArrayVarargsNonOverloaded(String... items) {
-        return "mStringArrayVarargsNonOverloaded(String[] " + TestUtil.arrayToString(items) + ")";
-    }
-
-    public String mStringArrayVarargsOverloaded(String... items) {
-        return "mStringArrayVarargsNonOverloaded(String[] " + TestUtil.arrayToString(items) + ")";
-    }
-
-    public String mStringArrayVarargsOverloaded1(String... items) {
-        return "mStringArrayVarargsOverloaded1(String[] " + TestUtil.arrayToString(items) + ")";
-    }
-
-    public String mStringArrayVarargsOverloaded1(List<String> items) {
-        return "mStringArrayVarargsOverloaded1(List " + TestUtil.listToString(items) + ")";
-    }
-
-    public String mStringArrayVarargsOverloaded2(String... items) {
-        return "mStringArrayVarargsOverloaded2(String[] " + TestUtil.arrayToString(items) + ")";
-    }
-
-    public String mStringArrayVarargsOverloaded2(String item) {
-        return "mStringArrayVarargsOverloaded2(String " + item + ")";
-    }
-    
-    public String mStringArrayVarargsOverloaded3(String... items) {
-        return "mStringArrayVarargsOverloaded3(String[] " + TestUtil.arrayToString(items) + ")";
-    }
-
-    public String mStringArrayVarargsOverloaded3(String item1, String item2) {
-        return "mStringArrayVarargsOverloaded3(String " + item1 + ", String " + item2 + ")";
-    }
-    
-    public String mStringArrayVarargsOverloaded4(String... items) {
-        return "mStringArrayVarargsOverloaded4(String[] " + TestUtil.arrayToString(items) + ")";
-    }
-
-    public String mStringArrayVarargsOverloaded4(List... items) {
-        return "mStringArrayVarargsOverloaded4(List[] " + TestUtil.arrayToString(items) + ")";
-    }
-    
-    public String mListOrString(List<String> items) {
-        return "mListOrString(List " + TestUtil.listToString(items) + ")";
-    }
-
-    public String mListOrString(String item) {
-        return "mListOrString(String " + item + ")";
-    }
-
-    public String mListListOrString(List<List<Object>> items) {
-        return "mListListOrString(List " + TestUtil.listToString(items) + ")";
-    }
-
-    public String mListListOrString(String item) {
-        return "mListListOrString(String " + item + ")";
-    }
-    
-    public String mMapOrBoolean(Map v) {
-        return "mMapOrBoolean(Map " + v + ")";
-    }
-
-    public String mMapOrBoolean(boolean v) {
-        return "mMapOrBoolean(boolean " + v + ")";
-    }
-
-    public String mMapOrBooleanVarargs(Map... v) {
-        return "mMapOrBooleanVarargs(Map... " + TestUtil.arrayToString(v) + ")";
-    }
-
-    public String mMapOrBooleanVarargs(boolean... v) {
-        return "mMapOrBooleanVarargs(boolean... " + TestUtil.arrayToString(v) + ")";
-    }
-
-    public String mMapOrBooleanFixedAndVarargs(Map v) {
-        return "mMapOrBooleanFixedAndVarargs(Map " + v + ")";
-    }
-
-    public String mMapOrBooleanFixedAndVarargs(boolean v) {
-        return "mMapOrBooleanFixedAndVarargs(boolean " + v + ")";
-    }
-
-    public String mMapOrBooleanFixedAndVarargs(Map... v) {
-        return "mMapOrBooleanFixedAndVarargs(Map... " + TestUtil.arrayToString(v) + ")";
-    }
-
-    public String mMapOrBooleanFixedAndVarargs(boolean... v) {
-        return "mMapOrBooleanFixedAndVarargs(boolean... " + TestUtil.arrayToString(v) + ")";
-    }
-    
-    public String mNumberOrArray(Number v) {
-        return "mNumberOrArray(Number " + v + ")";
-    }
-
-    public String mNumberOrArray(Object[] v) {
-        return "mNumberOrArray(Object[] " + TestUtil.arrayToString(v) + ")";
-    }
-    
-    public String mIntOrArray(int v) {
-        return "mIntOrArray(int " + v + ")";
-    }
-
-    public String mIntOrArray(Object[] v) {
-        return "mIntOrArray(Object[] " + TestUtil.arrayToString(v) + ")";
-    }
-
-    public String mDateOrArray(Date v) {
-        return "mDateOrArray(Date " + v.getTime() + ")";
-    }
-
-    public String mDateOrArray(Object[] v) {
-        return "mDateOrArray(Object[] " + TestUtil.arrayToString(v) + ")";
-    }
-    
-    public String mStringOrArray(String v) {
-        return "mStringOrArray(String " + v + ")";
-    }
-
-    public String mStringOrArray(Object[] v) {
-        return "mStringOrArray(Object[] " + TestUtil.arrayToString(v) + ")";
-    }
-    
-    public String mBooleanOrArray(boolean v) {
-        return "mBooleanOrArray(boolean " + v + ")";
-    }
-
-    public String mBooleanOrArray(Object[] v) {
-        return "mBooleanOrArray(Object[] " + TestUtil.arrayToString(v) + ")";
-    }
-    
-    public String mMapOrArray(Map v) {
-        return "mMapOrArray(Map " + v + ")";
-    }
-
-    public String mMapOrArray(Object[] v) {
-        return "mMapOrArray(Object[] " + TestUtil.arrayToString(v) + ")";
-    }
-    
-    public String mListOrArray(List v) {
-        return "mListOrArray(List " + v + ")";
-    }
-
-    public String mListOrArray(Object[] v) {
-        return "mListOrArray(Object[] " + TestUtil.arrayToString(v) + ")";
-    }
-    
-    public String mSetOrArray(Set v) {
-        return "mSetOrArray(Set " + v + ")";
-    }
-
-    public String mSetOrArray(Object[] v) {
-        return "mSetOrArray(Object[] " + TestUtil.arrayToString(v) + ")";
-    }
-    
-    public String mCharNonOverloaded(char c) {
-        return "mCharNonOverloaded(char " + c + ")";
-    }
-
-    public String mCharacterNonOverloaded(Character c) {
-        return "mCharacterNonOverloaded(Character " + c + ")";
-    }
-    
-    public String mCharOrCharacterOverloaded(char c) {
-        return "mCharOrCharacterOverloaded(char " + c + ")";
-    }
-
-    public String mCharOrCharacterOverloaded(Character c) {
-        return "mCharOrCharacterOverloaded(Character " + c + ")";
-    }
-
-    public String mCharOrBooleanOverloaded(char c) {
-        return "mCharOrBooleanOverloaded(char " + c + ")";
-    }
-
-    public String mCharOrBooleanOverloaded(boolean b) {
-        return "mCharOrBooleanOverloaded(boolean " + b + ")";
-    }
-
-    public String mCharOrStringOverloaded(char c, boolean b) {
-        return "mCharOrStringOverloaded(char " + c + ", boolean " + b + ")";
-    }
-
-    public String mCharOrStringOverloaded(String s, int i) {
-        return "mCharOrStringOverloaded(String " + s + ", int " + i + ")";
-    }
-
-    public String mCharacterOrStringOverloaded(Character c, boolean b) {
-        return "mCharacterOrStringOverloaded(Character " + c + ", boolean " + b + ")";
-    }
-
-    public String mCharacterOrStringOverloaded(String s, int i) {
-        return "mCharacterOrStringOverloaded(String " + s + ", int " + i + ")";
-    }
-    
-    public String mCharOrStringOverloaded2(String s) {
-        return "mCharOrStringOverloaded2(String " + s + ")";
-    }
-
-    public String mCharOrStringOverloaded2(char c) {
-        return "mCharOrStringOverloaded2(char " + c + ")";
-    }
-    
-    public String mCharacterOrStringOverloaded2(String s) {
-        return "mCharacterOrStringOverloaded2(String " + s + ")";
-    }
-
-    public String mCharacterOrStringOverloaded2(Character c) {
-        return "mCharacterOrStringOverloaded2(Character " + c + ")";
-    }
-    
-
-    public String getJavaString() {
-        return "s";
-    }
-    
-    public List getJavaStringList() {
-        List list = new ArrayList();
-        list.add("a");
-        list.add("b");
-        return list;
-    }
-
-    public List getJavaString2List() {
-        List list = new ArrayList();
-        list.add("aa");
-        list.add("bb");
-        return list;
-    }
-
-    public List getJavaStringListList() {
-        List listList = new ArrayList();
-        {
-            List list = new ArrayList();
-            list.add("a");
-            list.add("b");
-            
-            listList.add(list);
-        }
-        {
-            List list = new ArrayList();
-            list.add("c");
-            
-            listList.add(list);
-        }
-        return listList;
-    }
-
-    public List getJavaStringSequenceList() throws TemplateModelException {
-        ObjectWrapper ow = Environment.getCurrentEnvironment().getObjectWrapper();
-        
-        List listList = new ArrayList();
-        {
-            List list = new ArrayList();
-            list.add("a");
-            list.add("b");
-            
-            listList.add(ow.wrap(list));
-        }
-        {
-            List list = new ArrayList();
-            list.add("c");
-            
-            listList.add(ow.wrap(list));
-        }
-        return listList;
-    }
-    
-    public List<int[]> getJavaListOfIntArrays() {
-        List list = new ArrayList();
-        list.add(new int[] {1, 2, 3});
-        list.add(new int[] {});
-        list.add(new int[] {4});
-        return list;
-    }
-    
-    @SuppressWarnings("boxing")
-    public List getJavaIntegerListList() {
-        List listList = new ArrayList();
-        {
-            List list = new ArrayList();
-            list.add(1);
-            list.add(2);
-            
-            listList.add(list);
-        }
-        {
-            List list = new ArrayList();
-            list.add(3);
-            
-            listList.add(list);
-        }
-        return listList;
-    }
-    
-    @SuppressWarnings("boxing")
-    public List<Integer> getJavaIntegerList() {
-        List<Integer> list = new ArrayList<>();
-        list.add(1);
-        list.add(2);
-        return list;
-    }
-
-    @SuppressWarnings("boxing")
-    public List<Byte> getJavaByteList() {
-        List<Byte> list = new ArrayList<>();
-        list.add((byte) 1);
-        list.add((byte) 2);
-        return list;
-    }
-
-    @SuppressWarnings("boxing")
-    public List<Character> getJavaCharacterList() {
-        List<Character> list = new ArrayList<>();
-        list.add('c');
-        list.add('C');
-        return list;
-    }
-    
-    public String[] getJavaStringArray() {
-        return new String[] { "a", "b" };
-    }
-
-    public int[] getJavaIntArray() {
-        return new int[] { 11, 22 };
-    }
-
-    public Integer[] getJavaIntegerArray() {
-        return new Integer[] { Integer.valueOf(11), Integer.valueOf(22) };
-    }
-    
-    public String[] getJavaEmptyStringArray() {
-        return new String[] { };
-    }
-    
-    public String[][] getJavaStringArrayArray() {
-        return new String[][] { new String[] { "a", "b" }, new String[] { }, new String[] { "c" } };
-    }
-    
-    public Object[] getJavaObjectArray() {
-        return new Object[] { "a", "b" };
-    }
-    
-    public TemplateModel getHashAndScalarModel() {
-        return HashAndScalarModel.INSTANCE;
-    }
-
-    public TemplateModel getBooleanAndScalarModel() {
-        return BooleanAndScalarModel.INSTANCE;
-    }
-    
-    public TemplateModel getAllModels() {
-        return AllTemplateModels.INSTANCE;
-    }
-
-    public TemplateNumberModel getAdaptedNumber() {
-        return new MyAdapterNumberModel();
-    }
-
-    public TemplateNumberModel getWrapperNumber() {
-        return new MyWrapperNumberModel();
-    }
-
-    public TemplateBooleanModel getStringAdaptedToBoolean() {
-        return new MyStringAdaptedToBooleanModel();
-    }
-    
-    public TemplateBooleanModel getStringAdaptedToBoolean2() {
-        return new MyStringAdaptedToBooleanModel2();
-    }
-    
-    public TemplateBooleanModel getStringWrappedAsBoolean() {
-        return new MyStringWrapperAsBooleanModel();
-    }
-    
-    public TemplateBooleanModel getBooleanWrappedAsAnotherBoolean() {
-        return new MyBooleanWrapperAsAnotherBooleanModel(); 
-    }
-    
-    public String bugReport363(Map<String, ?> fields, List<?> listField) {
-        return "Executed: testMethod(Map fields, List listField) on input: fields=" + fields
-                + " and listField=" + listField;
-    }
-
-    public String bugReport363(Object... fields) {
-        return "Executed: testMethod(Object... fields) on input: fields=" + TestUtil.arrayToString(fields);
-    }
-    
-    private static class MyAdapterNumberModel implements TemplateNumberModel, AdapterTemplateModel {
-
-        @Override
-        public Object getAdaptedObject(Class hint) {
-            if (hint == double.class) {
-                return Double.valueOf(123.0001);
-            } else if (hint == Double.class) {
-                return Double.valueOf(123.0002);
-            } else {
-                return Long.valueOf(124L);
-            }
-        }
-
-        @Override
-        public Number getAsNumber() throws TemplateModelException {
-            return Integer.valueOf(122);
-        }
-        
-    }
-    
-    private static class MyWrapperNumberModel implements TemplateNumberModel, WrapperTemplateModel {
-
-        @Override
-        public Number getAsNumber() throws TemplateModelException {
-            return Integer.valueOf(122);
-        }
-
-        @Override
-        public Object getWrappedObject() {
-            return Double.valueOf(123.0001);
-        }
-        
-    }
-    
-    private static class MyStringWrapperAsBooleanModel implements TemplateBooleanModel, WrapperTemplateModel {
-
-        @Override
-        public Object getWrappedObject() {
-            return "yes";
-        }
-
-        @Override
-        public boolean getAsBoolean() throws TemplateModelException {
-            return true;
-        }
-        
-    }
-
-    private static class MyBooleanWrapperAsAnotherBooleanModel implements TemplateBooleanModel, WrapperTemplateModel {
-
-        @Override
-        public Object getWrappedObject() {
-            return Boolean.TRUE;
-        }
-
-        @Override
-        public boolean getAsBoolean() throws TemplateModelException {
-            return false;
-        }
-        
-    }
-    
-    private static class MyStringAdaptedToBooleanModel implements TemplateBooleanModel, AdapterTemplateModel {
-
-        @Override
-        public Object getAdaptedObject(Class hint) {
-            if (hint != Boolean.class && hint != boolean.class) {
-                return "yes";
-            } else {
-                return Boolean.TRUE;
-            }
-        }
-
-        @Override
-        public boolean getAsBoolean() throws TemplateModelException {
-            return false;
-        }
-        
-    }
-
-    private static class MyStringAdaptedToBooleanModel2 implements TemplateBooleanModel, AdapterTemplateModel {
-
-        @Override
-        public Object getAdaptedObject(Class hint) {
-            return "yes";
-        }
-
-        @Override
-        public boolean getAsBoolean() throws TemplateModelException {
-            return true;
-        }
-        
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/SimpleTestMethod.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/SimpleTestMethod.java b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/SimpleTestMethod.java
deleted file mode 100644
index 85e27d7..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/SimpleTestMethod.java
+++ /dev/null
@@ -1,49 +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.test.templatesuite.models;
-
-import java.util.List;
-
-import org.apache.freemarker.core.model.TemplateMethodModel;
-import org.apache.freemarker.core.model.impl.SimpleScalar;
-
-/**
- * A simple method model used as a test bed.
- */
-public class SimpleTestMethod implements TemplateMethodModel {
-
-    /**
-     * Executes a method call.
-     *
-     * @param arguments a <tt>List</tt> of <tt>String</tt> objects containing
-     * the values of the arguments passed to the method.
-     * @return the <tt>TemplateModel</tt> produced by the method, or null.
-     */
-    @Override
-    public Object exec(List arguments) {
-        if ( arguments.size() == 0 ) {
-            return new SimpleScalar( "Empty list provided" );
-        } else if ( arguments.size() > 1 ) {
-            return new SimpleScalar( "Argument size is: " + arguments.size() );
-        } else {
-            return new SimpleScalar( "Single argument value is: " + arguments.get(0) );
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/TransformHashWrapper.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/TransformHashWrapper.java b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/TransformHashWrapper.java
deleted file mode 100644
index 4602b67..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/TransformHashWrapper.java
+++ /dev/null
@@ -1,79 +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.test.templatesuite.models;
-
-import org.apache.freemarker.core.Configuration;
-import org.apache.freemarker.core.model.ObjectWrapper;
-import org.apache.freemarker.core.model.TemplateHashModel;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateScalarModel;
-import org.apache.freemarker.core.model.impl.DefaultObjectWrapper;
-import org.apache.freemarker.core.model.impl.SimpleHash;
-import org.apache.freemarker.core.util.HtmlEscape;
-import org.apache.freemarker.core.util.StandardCompress;
-
-/**
- * Part of the TestTransform testcase suite.
- */
-public class TransformHashWrapper implements TemplateHashModel,
-        TemplateScalarModel {
-
-    private ObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
-    private SimpleHash m_cHashModel = new SimpleHash(ow);
-
-    /** Creates new TransformHashWrapper */
-    public TransformHashWrapper() {
-        m_cHashModel.put( "htmlEscape", new HtmlEscape() );
-        m_cHashModel.put( "compress", new StandardCompress() );
-        m_cHashModel.put( "escape", new TransformMethodWrapper1() );
-        m_cHashModel.put( "special", new TransformMethodWrapper2() );
-    }
-
-    /**
-     * Gets a <tt>TemplateModel</tt> from the hash.
-     *
-     * @param key the name by which the <tt>TemplateModel</tt>
-     * is identified in the template.
-     * @return the <tt>TemplateModel</tt> referred to by the key,
-     * or null if not found.
-     */
-    @Override
-    public TemplateModel get(String key) throws TemplateModelException {
-        return m_cHashModel.get( key );
-    }
-
-    /**
-     * @return true if this object is empty.
-     */
-    @Override
-    public boolean isEmpty() {
-        return false;
-    }
-
-    /**
-     * Returns the scalar's value as a String.
-     * @return the String value of this scalar.
-     */
-    @Override
-    public String getAsString() {
-        return "Utility transformations";
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/TransformMethodWrapper1.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/TransformMethodWrapper1.java b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/TransformMethodWrapper1.java
deleted file mode 100644
index 8311134..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/TransformMethodWrapper1.java
+++ /dev/null
@@ -1,49 +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.test.templatesuite.models;
-
-import java.util.List;
-
-import org.apache.freemarker.core.model.TemplateMethodModel;
-import org.apache.freemarker.core.util.HtmlEscape;
-import org.apache.freemarker.core.util.XmlEscape;
-
-/**
- * Simple test of the interaction between MethodModels and TransformModels.
- */
-public class TransformMethodWrapper1 implements TemplateMethodModel {
-
-    /**
-     * Executes a method call.
-     *
-     * @param arguments a <tt>List</tt> of <tt>String</tt> objects containing
-     * the values of the arguments passed to the method.
-     * @return the <tt>TemplateModel</tt> produced by the method, or null.
-     */
-    @Override
-    public Object exec(List arguments) {
-
-        if (( arguments.size() > 0 ) && ( arguments.get( 0 ).toString().equals( "xml" ))) {
-            return new XmlEscape();
-        } else {
-            return new HtmlEscape();
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/TransformMethodWrapper2.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/TransformMethodWrapper2.java b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/TransformMethodWrapper2.java
deleted file mode 100644
index 96eb1a5..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/TransformMethodWrapper2.java
+++ /dev/null
@@ -1,64 +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.test.templatesuite.models;
-
-import java.util.Iterator;
-import java.util.List;
-
-import org.apache.freemarker.core.model.TemplateMethodModel;
-
-/**
- * Another test of the interaction between MethodModels and TransformModels.
- */
-public class TransformMethodWrapper2 implements TemplateMethodModel {
-
-    /**
-     * Executes a method call.
-     *
-     * @param arguments a <tt>List</tt> of <tt>String</tt> objects containing
-     * the values of the arguments passed to the method.
-     * @return the <tt>TemplateModel</tt> produced by the method, or null.
-     */
-    @Override
-    public Object exec(List arguments) {
-        TransformModel1 cTransformer = new TransformModel1();
-        Iterator    iArgument = arguments.iterator();
-
-        // Sets up properties of the Transform model based on the arguments
-        // passed into this method
-
-        while ( iArgument.hasNext() ) {
-            String  aArgument = (String) iArgument.next();
-
-            if ( aArgument.equals( "quote" )) {
-                cTransformer.setQuotes( true );
-            } else if ( aArgument.equals( "tag" )) {
-                cTransformer.setTags( true );
-            } else if ( aArgument.equals( "ampersand" )) {
-                cTransformer.setAmpersands( true );
-            } else {
-                cTransformer.setComment( aArgument );
-            }
-        }
-
-        // Now return the transform class.
-        return cTransformer;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/TransformModel1.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/TransformModel1.java b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/TransformModel1.java
deleted file mode 100644
index 0875679..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/TransformModel1.java
+++ /dev/null
@@ -1,175 +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.test.templatesuite.models;
-
-import java.io.IOException;
-import java.io.Reader;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.io.Writer;
-import java.util.Map;
-
-import org.apache.freemarker.core.model.TemplateTransformModel;
-
-/**
- * A TemplateTransformModel that includes properties. These properties can be
- * set at model construction time, or, for the purposes of this demonstration,
- * can be passed in from a wrapper TemplateMethodModel.
- */
-public class TransformModel1 implements TemplateTransformModel {
-
-    private boolean m_bAmpersands = false;
-    private boolean m_bQuotes = false;
-    private boolean m_bTags = false;
-    private String  m_aComment = "";
-
-    private static final int READER_BUFFER_SIZE = 4096;
-
-    @Override
-    public Writer getWriter(final Writer out,
-                            final Map args) {
-        final StringBuilder buf = new StringBuilder();
-        return new Writer(out) {
-            @Override
-            public void write(char cbuf[], int off, int len) {
-                buf.append(cbuf, off, len);
-            }
-
-            @Override
-            public void flush() {
-            }
-
-            @Override
-            public void close() throws IOException {
-                StringReader sr = new StringReader(buf.toString());
-                StringWriter sw = new StringWriter();
-                transform(sr, sw);
-                out.write(sw.toString());
-            }
-        };
-    }
-
-
-    /**
-     * Indicates whether we escape ampersands. This property can be set either
-     * while the model is being constructed, or via a property passed in through
-     * a <code>TemplateMethodModel</code>.
-     */
-    public void setAmpersands( boolean bAmpersands ) {
-        m_bAmpersands = bAmpersands;
-    }
-
-    /**
-     * Indicates whether we escape quotes. This property can be set either
-     * while the model is being constructed, or via a property passed in through
-     * a <code>TemplateMethodModel</code>.
-     */
-    public void setQuotes( boolean bQuotes ) {
-        m_bQuotes = bQuotes;
-    }
-
-    /**
-     * Indicates whether we escape tags. This property can be set either
-     * while the model is being constructed, or via a property passed in through
-     * a <code>TemplateMethodModel</code>.
-     */
-    public void setTags( boolean bTags ) {
-        m_bTags = bTags;
-    }
-
-    /**
-     * Sets a comment for this transformation. This property can be set either
-     * while the model is being constructed, or via a property passed in through
-     * a <code>TemplateMethodModel</code>.
-     */
-    public void setComment( String aComment ) {
-        m_aComment = aComment;
-    }
-
-    /**
-     * Performs a transformation/filter on FreeMarker output.
-     *
-     * @param source the input to be transformed
-     * @param output the destination of the transformation
-     */
-    public void transform(Reader source, Writer output)
-    throws IOException {
-        // Output the source, converting unsafe certain characters to their
-        // equivalent entities.
-        int n = 0;
-        boolean bCommentSent = false;
-        char[]  aBuffer = new char[ READER_BUFFER_SIZE ];
-        int i = source.read( aBuffer );
-        while (i >= 0) {
-            for ( int j = 0; j < i; j++ ) {
-                char c = aBuffer[j];
-                switch (c) {
-                    case '&':
-                        if ( m_bAmpersands ) {
-                            output.write("&amp;");
-                        } else {
-                            output.write( c );
-                        }
-                        break;
-                    case '<':
-                        if ( m_bTags ) {
-                            output.write("&lt;");
-                        } else {
-                            output.write( c );
-                        }
-                        break;
-                    case '>':
-                        if ( m_bTags ) {
-                            output.write("&gt;");
-                        } else {
-                            output.write( c );
-                        }
-                        break;
-                    case '"':
-                        if ( m_bQuotes ) {
-                            output.write("&quot;");
-                        } else {
-                            output.write( c );
-                        }
-                        break;
-                    case '\'':
-                        if ( m_bQuotes ) {
-                            output.write("&apos;");
-                        } else {
-                            output.write( c );
-                        }
-                        break;
-                    case '*':
-                        if ( ! bCommentSent ) {
-                            output.write( m_aComment );
-                            bCommentSent = true;
-                        } else {
-                            output.write( c );
-                        }
-                        break;
-                    default:
-                        output.write(c);
-                }
-                n++;
-            }
-            i = source.read( aBuffer );
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/VarArgTestModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/VarArgTestModel.java b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/VarArgTestModel.java
deleted file mode 100644
index 940cb17..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/VarArgTestModel.java
+++ /dev/null
@@ -1,63 +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.test.templatesuite.models;
-
-import java.util.Date;
-
-public class VarArgTestModel {
-
-    public int bar(Integer... xs) {
-        int sum = 0;
-        for (Integer x : xs) {
-            if (x != null) {
-                sum *= 100;
-                sum += x;
-            }
-        }
-        return sum;
-    }
-
-    public int bar2(int first, int... xs) {
-        int sum = 0;
-        for (int x : xs) {
-            sum *= 100;
-            sum += x;
-        }
-        return -(sum * 100 + first);
-    }
-    
-    public int overloaded(int x, int y) {
-        return x * 100 + y;
-    }
-
-    public int overloaded(int... xs) {
-        int sum = 0;
-        for (int x : xs) {
-            sum *= 100;
-            sum += x;
-        }
-        return -sum;
-    }
-    
-    public String noVarArgs(String s, boolean b, int i, Date d) {
-        return s + ", " + b + ", " + i + ", " + d.getTime();
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/package.html
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/package.html b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/package.html
deleted file mode 100644
index cabffb0..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/package.html
+++ /dev/null
@@ -1,42 +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.
--->
-<html>
-<head>
-</head>
-<body>
-
-<p>JUnit test-suite that processes FreeMarker templates and compare their
-output to reference files.</p>
-
-<p>To add a test-case, go to
-<tt>src/test/resources/freemarker/test/templatesuite/</tt> and inside that
-directory:</p>
-<ol>
-  <li>Add a template to under <tt>templates/</tt> with whatever meaningful
-      file name</li>
-  <li>Add the expected output to <tt>references/</tt> with exactly the same
-      file name</li>
-  <li>Add a new <tt>testcase</tt> elemen to <tt>testcases.xml</tt></li>
-  <li>If you want to add items to the data-model or do something else special,
-      modify the <tt>setUp()</tt> method in
-      <tt>src/test/java/freemarker/test/templatesuite/TemplateTestCase.java</tt>
-      </li>
-</ol>
-</body>
-</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/util/AssertDirective.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/util/AssertDirective.java b/freemarker-core/src/test/java/org/apache/freemarker/test/util/AssertDirective.java
deleted file mode 100644
index 8f31680..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/util/AssertDirective.java
+++ /dev/null
@@ -1,73 +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.test.util;
-
-import java.io.IOException;
-import java.util.Map;
-
-import org.apache.freemarker.core.Environment;
-import org.apache.freemarker.core.NestedContentNotSupportedException;
-import org.apache.freemarker.core.TemplateException;
-import org.apache.freemarker.core.model.TemplateBooleanModel;
-import org.apache.freemarker.core.model.TemplateDirectiveBody;
-import org.apache.freemarker.core.model.TemplateDirectiveModel;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.util.FTLUtil;
-
-public class AssertDirective implements TemplateDirectiveModel {
-
-    public static AssertDirective INSTANCE = new AssertDirective();
-    
-    private static final String TEST_PARAM = "test";
-    
-    private AssertDirective() { }
-    
-    @Override
-    public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
-            throws TemplateException, IOException {
-        TemplateModel test = null;
-        for (Object paramEnt  : params.entrySet()) {
-            Map.Entry<String, TemplateModel> param = (Map.Entry) paramEnt;
-            String paramName = param.getKey();
-            if (paramName.equals(TEST_PARAM)) {
-                test = param.getValue();
-            } else {
-                throw new UnsupportedParameterException(paramName, env);
-            }
-        }
-        if (test == null) {
-            throw new MissingRequiredParameterException(TEST_PARAM, env);
-        }
-        NestedContentNotSupportedException.check(body);
-        
-        if (!(test instanceof TemplateBooleanModel)) {
-            throw new AssertationFailedInTemplateException("Assertion failed:\n"
-                    + "The value had to be boolean, but it was of type" + FTLUtil.getTypeDescription(test),
-                    env);
-        }
-        if (!((TemplateBooleanModel) test).getAsBoolean()) {
-            throw new AssertationFailedInTemplateException("Assertion failed:\n"
-                    + "the value was false.",
-                    env);
-        }
-        
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/util/AssertEqualsDirective.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/util/AssertEqualsDirective.java b/freemarker-core/src/test/java/org/apache/freemarker/test/util/AssertEqualsDirective.java
deleted file mode 100644
index 63a9ebc..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/util/AssertEqualsDirective.java
+++ /dev/null
@@ -1,91 +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.test.util;
-
-import java.io.IOException;
-import java.util.Map;
-
-import org.apache.freemarker.core.Environment;
-import org.apache.freemarker.core.NestedContentNotSupportedException;
-import org.apache.freemarker.core.TemplateException;
-import org.apache.freemarker.core.model.TemplateBooleanModel;
-import org.apache.freemarker.core.model.TemplateDateModel;
-import org.apache.freemarker.core.model.TemplateDirectiveBody;
-import org.apache.freemarker.core.model.TemplateDirectiveModel;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateNumberModel;
-import org.apache.freemarker.core.model.TemplateScalarModel;
-import org.apache.freemarker.core.util._StringUtil;
-
-public class AssertEqualsDirective implements TemplateDirectiveModel {
-    
-    public static AssertEqualsDirective INSTANCE = new AssertEqualsDirective();
-
-    private static final String ACTUAL_PARAM = "actual";
-    private static final String EXPECTED_PARAM = "expected";
-
-    private AssertEqualsDirective() { }
-    
-    @Override
-    public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
-            throws TemplateException, IOException {
-        TemplateModel actual = null;
-        TemplateModel expected = null;
-        for (Object paramEnt  : params.entrySet()) {
-            Map.Entry<String, TemplateModel> param = (Map.Entry) paramEnt;
-            String paramName = param.getKey();
-            if (paramName.equals(ACTUAL_PARAM)) {
-                actual = param.getValue();
-            } else if (paramName.equals(EXPECTED_PARAM)) {
-                expected = param.getValue();
-            } else {
-                throw new UnsupportedParameterException(paramName, env);
-            }
-        }
-        if (actual == null) {
-            throw new MissingRequiredParameterException(ACTUAL_PARAM, env);
-        }
-        if (expected == null) {
-            throw new MissingRequiredParameterException(EXPECTED_PARAM, env);
-        }
-        NestedContentNotSupportedException.check(body);
-        
-        if (!env.applyEqualsOperatorLenient(actual, expected)) {
-            throw new AssertationFailedInTemplateException("Assertion failed:\n"
-                    + "Expected: " + tryUnwrapp(expected) + "\n"
-                    + "Actual: " + tryUnwrapp(actual),
-                    env);
-        }
-        
-    }
-
-    private String tryUnwrapp(TemplateModel value) throws TemplateModelException {
-        if (value == null) return "null";
-        // This is the same order as comparison goes:
-        else if (value instanceof TemplateNumberModel) return ((TemplateNumberModel) value).getAsNumber().toString();
-        else if (value instanceof TemplateDateModel) return ((TemplateDateModel) value).getAsDate().toString();
-        else if (value instanceof TemplateScalarModel) return _StringUtil.jQuote(((TemplateScalarModel) value).getAsString());
-        else if (value instanceof TemplateBooleanModel) return String.valueOf(((TemplateBooleanModel) value).getAsBoolean());
-        // This shouldn't be reached, as the comparison should have failed earlier:
-        else return value.toString();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/util/AssertFailsDirective.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/util/AssertFailsDirective.java b/freemarker-core/src/test/java/org/apache/freemarker/test/util/AssertFailsDirective.java
deleted file mode 100644
index bd18d8d..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/util/AssertFailsDirective.java
+++ /dev/null
@@ -1,152 +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.test.util;
-
-import java.io.IOException;
-import java.util.Map;
-import java.util.regex.Pattern;
-
-import org.apache.freemarker.core.Environment;
-import org.apache.freemarker.core.TemplateException;
-import org.apache.freemarker.core.model.TemplateDirectiveBody;
-import org.apache.freemarker.core.model.TemplateDirectiveModel;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateNumberModel;
-import org.apache.freemarker.core.model.TemplateScalarModel;
-import org.apache.freemarker.core.util._NullWriter;
-import org.apache.freemarker.core.util._StringUtil;
-
-public class AssertFailsDirective implements TemplateDirectiveModel {
-    
-    public static AssertFailsDirective INSTANCE = new AssertFailsDirective();
-
-    private static final String MESSAGE_PARAM = "message";
-    private static final String MESSAGE_REGEXP_PARAM = "messageRegexp";
-    private static final String EXCEPTION_PARAM = "exception";
-    private static final String CAUSE_NESTING_LEVEL_PARAM = "causeNestingLevel";
-    
-    private AssertFailsDirective() { }
-
-    @Override
-    public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
-            throws TemplateException, IOException {
-        String message = null;
-        Pattern messageRegexp = null;
-        String exception = null;
-        int causeNestingLevel = 0;
-        for (Object paramEnt  : params.entrySet()) {
-            Map.Entry<String, TemplateModel> param = (Map.Entry) paramEnt;
-            String paramName = param.getKey();
-            if (paramName.equals(MESSAGE_PARAM)) {
-                message = getAsString(param.getValue(), MESSAGE_PARAM, env);
-            } else if (paramName.equals(MESSAGE_REGEXP_PARAM)) {
-                messageRegexp = Pattern.compile(
-                        getAsString(param.getValue(), MESSAGE_REGEXP_PARAM, env),
-                        Pattern.CASE_INSENSITIVE);
-            } else if (paramName.equals(EXCEPTION_PARAM)) {
-                exception = getAsString(param.getValue(), EXCEPTION_PARAM, env);
-            } else if (paramName.equals(CAUSE_NESTING_LEVEL_PARAM)) {
-                causeNestingLevel = getAsInt(param.getValue(), CAUSE_NESTING_LEVEL_PARAM, env);
-            } else {
-                throw new UnsupportedParameterException(paramName, env);
-            }
-        }
-        
-        if (body != null) {
-            boolean blockFailed;
-            try {
-                body.render(_NullWriter.INSTANCE);
-                blockFailed = false;
-            } catch (Throwable e) {
-                blockFailed = true;
-                
-                int causeNestingLevelCountDown = causeNestingLevel; 
-                while (causeNestingLevelCountDown != 0) {
-                    e = e.getCause();
-                    if (e == null) {
-                        throw new AssertationFailedInTemplateException(
-                                "Failure is not like expected: The cause exception nesting dept was lower than "
-                                + causeNestingLevel + ".",
-                                env);
-                    }
-                    causeNestingLevelCountDown--;
-                }
-                
-                if (message != null || messageRegexp != null) {
-                    if (e.getMessage() == null) {
-                        throw new AssertationFailedInTemplateException(
-                                "Failure is not like expected. The exception message was null, "
-                                + "and thus it doesn't contain:\n" + _StringUtil.jQuote(message) + ".",
-                                env);
-                    }
-                    if (message != null) {
-                        String actualMessage = e instanceof TemplateException
-                                ? ((TemplateException) e).getMessageWithoutStackTop() : e.getMessage();
-                        if (actualMessage.toLowerCase().indexOf(message.toLowerCase()) == -1) {
-                            throw new AssertationFailedInTemplateException(
-                                    "Failure is not like expected. The exception message:\n" + _StringUtil.jQuote(actualMessage)
-                                    + "\ndoesn't contain:\n" + _StringUtil.jQuote(message) + ".",
-                                    env);
-                        }
-                    }
-                    if (messageRegexp != null) {
-                        if (!messageRegexp.matcher(e.getMessage()).find()) {
-                            throw new AssertationFailedInTemplateException(
-                                    "Failure is not like expected. The exception message:\n" + _StringUtil.jQuote(e.getMessage())
-                                    + "\ndoesn't match this regexp:\n" + _StringUtil.jQuote(messageRegexp.toString())
-                                    + ".",
-                                    env);
-                        }
-                    }
-                }
-                if (exception != null && e.getClass().getName().indexOf(exception) == -1) {
-                    throw new AssertationFailedInTemplateException(
-                            "Failure is not like expected. The exception class name " + _StringUtil.jQuote(e.getClass().getName())
-                            + " doesn't contain " + _StringUtil.jQuote(message) + ".",
-                            env);
-                }
-            }
-            if (!blockFailed) {
-                throw new AssertationFailedInTemplateException(
-                        "Block was expected to fail, but it didn't.",
-                        env);
-            }
-        }
-    }
-
-    private String getAsString(TemplateModel value, String paramName, Environment env)
-            throws BadParameterTypeException, TemplateModelException {
-        if (value instanceof TemplateScalarModel) {
-            return ((TemplateScalarModel) value).getAsString(); 
-        } else {
-            throw new BadParameterTypeException(paramName, "string", value, env);
-        }
-    }
-
-    private int getAsInt(TemplateModel value, String paramName, Environment env) throws BadParameterTypeException, TemplateModelException {
-        if (value instanceof TemplateNumberModel) {
-            return ((TemplateNumberModel) value).getAsNumber().intValue(); 
-        } else {
-            throw new BadParameterTypeException(paramName, "number", value, env);
-        }
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/util/AssertationFailedInTemplateException.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/util/AssertationFailedInTemplateException.java b/freemarker-core/src/test/java/org/apache/freemarker/test/util/AssertationFailedInTemplateException.java
deleted file mode 100644
index 7a65c42..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/util/AssertationFailedInTemplateException.java
+++ /dev/null
@@ -1,46 +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.test.util;
-
-import org.apache.freemarker.core.Environment;
-import org.apache.freemarker.core.TemplateException;
-
-/**
- * Fills the role of {@link junit.framework.AssertionFailedError}, but carries the template location information.  
- */
-public class AssertationFailedInTemplateException extends TemplateException {
-
-    public AssertationFailedInTemplateException(Environment env) {
-        super(env);
-    }
-
-    public AssertationFailedInTemplateException(String description, Environment env) {
-        super(description, env);
-    }
-
-    public AssertationFailedInTemplateException(Exception cause, Environment env) {
-        super(cause, env);
-    }
-
-    public AssertationFailedInTemplateException(String description, Exception cause, Environment env) {
-        super(description, cause, env);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/util/BadParameterTypeException.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/util/BadParameterTypeException.java b/freemarker-core/src/test/java/org/apache/freemarker/test/util/BadParameterTypeException.java
deleted file mode 100644
index f1230be..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/util/BadParameterTypeException.java
+++ /dev/null
@@ -1,60 +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.test.util;
-
-import org.apache.freemarker.core.Environment;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.util._StringUtil;
-
-/**
- * Indicates that a named directive/function parameter is not of the expected type.  
- * This is will be public and go into the org.apache.freemarker.core.ast when the directive/method stuff was reworked.
- */
-public class BadParameterTypeException extends ParameterException {
-
-    public BadParameterTypeException(String parameterName, String expectedType, TemplateModel value, Environment env) {
-        this(parameterName, expectedType, value, null, null, env);
-    }
-
-    public BadParameterTypeException(String parameterName, String expectedType, TemplateModel value,
-            Exception cause, Environment env) {
-        this(parameterName, expectedType, value, null, cause, env);
-    }
-
-    public BadParameterTypeException(String parameterName, String expectedType, TemplateModel value,
-            String description, Environment env) {
-        this(parameterName, expectedType, value, description, null, env);
-    }
-
-    public BadParameterTypeException(
-            String parameterName, String expectedType, TemplateModel value, String description, Exception cause, Environment env) {
-        super(parameterName,
-                "The type of the parameter " + _StringUtil.jQuote(parameterName) + " should be " + expectedType
-                + ", but the actual value was " + getTypeDescription(value) + "."
-                + (description != null ? " " + _StringUtil.jQuote(description) : ""),
-                cause, env);
-    }
-
-    private static String getTypeDescription(TemplateModel value) {
-        //FIXME: This should call EvaluationUtil.getTypeDescriptionForDebugging, but that's not visible from here yet.
-        return value == null ? "Null" : value.getClass().getName();
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/util/CoreTestUtil.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/util/CoreTestUtil.java b/freemarker-core/src/test/java/org/apache/freemarker/test/util/CoreTestUtil.java
deleted file mode 100644
index d9770fc..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/util/CoreTestUtil.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package org.apache.freemarker.test.util;
-
-import org.apache.freemarker.core.Configuration;
-import org.apache.freemarker.core.Version;
-
-public final class CoreTestUtil {
-
-    private CoreTestUtil() {
-        // Not meant to be instantiated
-    }
-
-    /**
-     * Returns the closes FreeMarker version number that doesn't exit yet (so it's illegal).
-     */
-    public static Version getClosestFutureVersion() {
-        Version v = Configuration.getVersion();
-        return new Version(v.getMajor(), v.getMinor(), v.getMicro() + 1);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/util/EntirelyCustomObjectWrapper.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/util/EntirelyCustomObjectWrapper.java b/freemarker-core/src/test/java/org/apache/freemarker/test/util/EntirelyCustomObjectWrapper.java
deleted file mode 100644
index cdcde1f..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/util/EntirelyCustomObjectWrapper.java
+++ /dev/null
@@ -1,91 +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.test.util;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Map;
-
-import org.apache.freemarker.core.model.ObjectWrapper;
-import org.apache.freemarker.core.model.TemplateBooleanModel;
-import org.apache.freemarker.core.model.TemplateDateModel;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateModelAdapter;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.impl.DefaultObjectWrapper;
-import org.apache.freemarker.core.model.impl.SimpleDate;
-import org.apache.freemarker.core.model.impl.SimpleHash;
-import org.apache.freemarker.core.model.impl.SimpleNumber;
-import org.apache.freemarker.core.model.impl.SimpleScalar;
-import org.apache.freemarker.core.model.impl.SimpleSequence;
-
-/**
- * An object wrapper that doesn't extend {@link DefaultObjectWrapper}.
- */
-public class EntirelyCustomObjectWrapper implements ObjectWrapper {
-
-    @Override
-    public TemplateModel wrap(Object obj) throws TemplateModelException {
-        if (obj == null) {
-            return null;
-        }
-
-        if (obj instanceof TemplateModel) {
-            return (TemplateModel) obj;
-        }
-        if (obj instanceof TemplateModelAdapter) {
-            return ((TemplateModelAdapter) obj).getTemplateModel();
-        }
-
-        if (obj instanceof String) {
-            return new SimpleScalar((String) obj);
-        }
-        if (obj instanceof Number) {
-            return new SimpleNumber((Number) obj);
-        }
-        if (obj instanceof Boolean) {
-            return obj.equals(Boolean.TRUE) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
-        }
-        if (obj instanceof java.util.Date) {
-            if (obj instanceof java.sql.Date) {
-                return new SimpleDate((java.sql.Date) obj);
-            }
-            if (obj instanceof java.sql.Time) {
-                return new SimpleDate((java.sql.Time) obj);
-            }
-            if (obj instanceof java.sql.Timestamp) {
-                return new SimpleDate((java.sql.Timestamp) obj);
-            }
-            return new SimpleDate((java.util.Date) obj, TemplateDateModel.UNKNOWN);
-        }
-
-        if (obj.getClass().isArray()) {
-            obj = Arrays.asList((Object[]) obj);
-        }
-        if (obj instanceof Collection) {
-            return new SimpleSequence((Collection<?>) obj, this);
-        }
-        if (obj instanceof Map) {
-            return new SimpleHash((Map<?, ?>) obj, this);
-        }
-
-        return null;
-    }
-}


[51/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a consequence of this, freemarker-core tests were moved into their own project, freemarker-core-test (and freemarker-core-test-java8, which has existed earlier too).


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/28a276c8
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/28a276c8
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/28a276c8

Branch: refs/heads/3
Commit: 28a276c80496b164b35a8dc04d6ad87ea1ddc800
Parents: b053951
Author: ddekany <dd...@apache.org>
Authored: Mon May 15 20:46:41 2017 +0200
Committer: ddekany <dd...@apache.org>
Committed: Mon May 15 23:22:55 2017 +0200

----------------------------------------------------------------------
 freemarker-core-java8-test/build.gradle         |   19 -
 .../src/main/resources/META-INF/DISCLAIMER      |    8 -
 .../src/main/resources/META-INF/LICENSE         |  202 ---
 .../core/model/impl/BridgeMethodsBean.java      |   30 -
 .../core/model/impl/BridgeMethodsBeanBase.java  |   29 -
 ...Java8BridgeMethodsWithDefaultMethodBean.java |   29 -
 ...ava8BridgeMethodsWithDefaultMethodBean2.java |   23 -
 ...8BridgeMethodsWithDefaultMethodBeanBase.java |   31 -
 ...BridgeMethodsWithDefaultMethodBeanBase2.java |   28 -
 .../model/impl/Java8DefaultMethodsBean.java     |   84 -
 .../model/impl/Java8DefaultMethodsBeanBase.java |   97 --
 ...a8DefaultObjectWrapperBridgeMethodsTest.java |   65 -
 .../impl/Java8DefaultObjectWrapperTest.java     |  160 --
 freemarker-core-test-java8/build.gradle         |   25 +
 .../src/main/resources/META-INF/DISCLAIMER      |    8 +
 .../src/main/resources/META-INF/LICENSE         |  202 +++
 .../core/model/impl/BridgeMethodsBean.java      |   30 +
 .../core/model/impl/BridgeMethodsBeanBase.java  |   29 +
 ...Java8BridgeMethodsWithDefaultMethodBean.java |   29 +
 ...ava8BridgeMethodsWithDefaultMethodBean2.java |   23 +
 ...8BridgeMethodsWithDefaultMethodBeanBase.java |   31 +
 ...BridgeMethodsWithDefaultMethodBeanBase2.java |   28 +
 .../model/impl/Java8DefaultMethodsBean.java     |   84 +
 .../model/impl/Java8DefaultMethodsBeanBase.java |   97 ++
 ...a8DefaultObjectWrapperBridgeMethodsTest.java |   65 +
 .../impl/Java8DefaultObjectWrapperTest.java     |  160 ++
 freemarker-core-test/build.gradle               |   19 +
 .../core/ASTBasedErrorMessagesTest.java         |   74 +
 .../org/apache/freemarker/core/ASTPrinter.java  |  438 +++++
 .../org/apache/freemarker/core/ASTTest.java     |  103 ++
 .../core/ActualNamingConvetionTest.java         |   66 +
 .../freemarker/core/ActualTagSyntaxTest.java    |   68 +
 .../freemarker/core/BreakPlacementTest.java     |   56 +
 .../apache/freemarker/core/CamelCaseTest.java   |  486 ++++++
 .../freemarker/core/CanonicalFormTest.java      |   68 +
 .../freemarker/core/CoercionToTextualTest.java  |  149 ++
 .../freemarker/core/ConfigurableTest.java       |  176 ++
 .../freemarker/core/ConfigurationTest.java      | 1486 +++++++++++++++++
 .../freemarker/core/CoreLocaleUtilsTest.java    |   73 +
 .../freemarker/core/CustomAttributeTest.java    |  163 ++
 .../apache/freemarker/core/DateFormatTest.java  |  464 ++++++
 .../freemarker/core/DirectiveCallPlaceTest.java |  249 +++
 .../freemarker/core/EncodingOverrideTest.java   |   62 +
 .../EnvironmentGetTemplateVariantsTest.java     |  214 +++
 .../apache/freemarker/core/ExceptionTest.java   |  115 ++
 .../apache/freemarker/core/GetSourceTest.java   |   52 +
 .../freemarker/core/HeaderParsingTest.java      |   60 +
 .../IncludeAndImportConfigurableLayersTest.java |  354 +++++
 .../freemarker/core/IncludeAndImportTest.java   |  270 ++++
 .../freemarker/core/IncudeFromNamelessTest.java |   58 +
 .../core/InterpretAndEvalTemplateNameTest.java  |   70 +
 .../core/InterpretSettingInheritanceTest.java   |  104 ++
 .../freemarker/core/IteratorIssuesTest.java     |   64 +
 .../core/JavaCCExceptionAsEOFFixTest.java       |  126 ++
 .../apache/freemarker/core/ListErrorsTest.java  |  130 ++
 .../freemarker/core/MiscErrorMessagesTest.java  |   48 +
 .../core/MistakenlyPublicImportAPIsTest.java    |  104 ++
 .../core/MistakenlyPublicMacroAPIsTest.java     |   88 +
 .../core/NewBiObjectWrapperRestrictionTest.java |  117 ++
 .../core/ObjectBuilderSettingsTest.java         | 1499 ++++++++++++++++++
 .../core/OptInTemplateClassResolverTest.java    |  230 +++
 .../freemarker/core/OutputFormatTest.java       | 1068 +++++++++++++
 .../ParseTimeParameterBIErrorMessagesTest.java  |   46 +
 .../core/ParsingErrorMessagesTest.java          |  116 ++
 .../core/RestrictedObjectWrapperTest.java       |   72 +
 .../core/RestrictedObjetWrapperTest.java        |  112 ++
 .../apache/freemarker/core/SQLTimeZoneTest.java |  371 +++++
 .../freemarker/core/SettingDirectiveTest.java   |   40 +
 .../freemarker/core/SpecialVariableTest.java    |  114 ++
 .../core/StringLiteralInterpolationTest.java    |  135 ++
 .../org/apache/freemarker/core/TabSizeTest.java |   91 ++
 .../core/TagSyntaxVariationsTest.java           |  186 +++
 .../core/TemplateConfigurationTest.java         |  909 +++++++++++
 ...gurationWithDefaultTemplateResolverTest.java |  267 ++++
 .../core/TemplateConstructorsTest.java          |  113 ++
 .../core/TemplateGetEncodingTest.java           |   64 +
 .../core/TemplateLookupStrategyTest.java        |  669 ++++++++
 .../core/TemplateNameSpecialVariablesTest.java  |  159 ++
 .../core/TemplateNotFoundMessageTest.java       |  207 +++
 .../core/TheadInterruptingSupportTest.java      |  163 ++
 .../freemarker/core/TypeErrorMessagesTest.java  |  105 ++
 .../freemarker/core/UnclosedCommentTest.java    |   41 +
 .../org/apache/freemarker/core/VersionTest.java |  227 +++
 .../core/WhitespaceStrippingTest.java           |   63 +
 .../freemarker/core/XHTMLOutputFormatTest.java  |   59 +
 .../freemarker/core/XMLOutputFormatTest.java    |   59 +
 .../impl/AbstractParallelIntrospectionTest.java |  126 ++
 .../model/impl/AlphabeticalMethodSorter.java    |   45 +
 .../CommonSupertypeForUnwrappingHintTest.java   |  129 ++
 .../model/impl/DefaultObjectWrapperDesc.java    |   31 +
 .../model/impl/DefaultObjectWrapperInc.java     |   31 +
 ...jectWrapperModelFactoryRegistrationTest.java |   63 +
 .../DefaultObjectWrapperSingletonsTest.java     |  675 ++++++++
 .../model/impl/DefaultObjectWrapperTest.java    |  901 +++++++++++
 .../core/model/impl/EnumModelsTest.java         |   85 +
 .../core/model/impl/ErrorMessagesTest.java      |  170 ++
 .../impl/FineTuneMethodAppearanceTest.java      |   65 +
 .../GetlessMethodsAsPropertyGettersRule.java    |   67 +
 .../core/model/impl/IsApplicableTest.java       |  171 ++
 .../impl/IsMoreSpecificParameterTypeTest.java   |   98 ++
 .../Java7MembersOnlyDefaultObjectWrapper.java   |  101 ++
 .../impl/ManyObjectsOfDifferentClasses.java     |  249 +++
 .../impl/ManyStaticsOfDifferentClasses.java     |  236 +++
 .../model/impl/MiscNumericalOperationsTest.java |  111 ++
 .../model/impl/ModelAPINewInstanceTest.java     |  134 ++
 .../core/model/impl/ModelCacheTest.java         |   71 +
 .../model/impl/OverloadedNumberUtilTest.java    |  585 +++++++
 .../impl/ParameterListPreferabilityTest.java    |  445 ++++++
 .../impl/PrallelObjectIntrospectionTest.java    |   43 +
 .../impl/PrallelStaticIntrospectionTest.java    |   47 +
 .../core/model/impl/RationalNumber.java         |   90 ++
 .../core/model/impl/StaticModelsTest.java       |   91 ++
 .../core/model/impl/TypeFlagsTest.java          |  671 ++++++++
 .../core/outputformat/_OutputFormatTestAPI.java |   35 +
 .../impl/CombinedMarkupOutputFormatTest.java    |  194 +++
 .../outputformat/impl/HTMLOutputFormatTest.java |  187 +++
 .../outputformat/impl/RTFOutputFormatTest.java  |  129 ++
 .../DefaultTemplateResolverTest.java            |  365 +++++
 .../FileTemplateLoaderTest.java                 |  122 ++
 .../MultiTemplateLoaderTest.java                |   99 ++
 .../TemplateConfigurationFactoryTest.java       |  203 +++
 .../TemplateNameFormatTest.java                 |  330 ++++
 .../TemplateSourceMatcherTest.java              |  188 +++
 .../AppMetaTemplateDateFormatFactory.java       |  129 ++
 .../BaseNTemplateNumberFormatFactory.java       |  128 ++
 .../core/userpkg/CustomHTMLOutputFormat.java    |   72 +
 .../core/userpkg/CustomTemplateHTMLModel.java   |   34 +
 .../core/userpkg/DummyOutputFormat.java         |   65 +
 ...EpochMillisDivTemplateDateFormatFactory.java |  102 ++
 .../EpochMillisTemplateDateFormatFactory.java   |   92 ++
 .../HTMLISOTemplateDateFormatFactory.java       |  114 ++
 .../userpkg/HexTemplateNumberFormatFactory.java |   77 +
 ...AndTZSensitiveTemplateDateFormatFactory.java |   97 ++
 ...aleSensitiveTemplateNumberFormatFactory.java |   78 +
 .../core/userpkg/PackageVisibleAll.java         |   26 +
 .../userpkg/PackageVisibleAllWithBuilder.java   |   26 +
 .../PackageVisibleAllWithBuilderBuilder.java    |   28 +
 .../PackageVisibleWithPublicConstructor.java    |   27 +
 .../PrintfGTemplateNumberFormatFactory.java     |  138 ++
 .../freemarker/core/userpkg/PublicAll.java      |   24 +
 .../userpkg/PublicWithMixedConstructors.java    |   38 +
 .../PublicWithPackageVisibleConstructor.java    |   26 +
 .../core/userpkg/SeldomEscapedOutputFormat.java |   71 +
 .../core/userpkg/TemplateDummyOutputModel.java  |   34 +
 .../TemplateSeldomEscapedOutputModel.java       |   34 +
 .../freemarker/core/util/DateUtilTest.java      | 1085 +++++++++++++
 .../freemarker/core/util/FTLUtilTest.java       |  117 ++
 .../freemarker/core/util/NumberUtilTest.java    |  215 +++
 .../freemarker/core/util/StringUtilTest.java    |  403 +++++
 .../core/valueformat/NumberFormatTest.java      |  365 +++++
 .../impl/ExtendedDecimalFormatTest.java         |  343 ++++
 .../apache/freemarker/dom/DOMSiblingTest.java   |   99 ++
 .../freemarker/dom/DOMSimplifiersTest.java      |  201 +++
 .../java/org/apache/freemarker/dom/DOMTest.java |  159 ++
 .../manualtest/AutoEscapingExample.java         |   72 +
 .../ConfigureOutputFormatExamples.java          |  105 ++
 .../manualtest/CustomFormatsExample.java        |   84 +
 .../manualtest/GettingStartedExample.java       |   69 +
 .../apache/freemarker/manualtest/Product.java   |   49 +
 .../TemplateConfigurationExamples.java          |  191 +++
 .../UnitAwareTemplateNumberFormatFactory.java   |   80 +
 .../UnitAwareTemplateNumberModel.java           |   43 +
 .../test/templatesuite/TemplateTestCase.java    |  515 ++++++
 .../test/templatesuite/TemplateTestSuite.java   |  298 ++++
 .../templatesuite/models/AllTemplateModels.java |  128 ++
 .../templatesuite/models/BeanTestClass.java     |   93 ++
 .../templatesuite/models/BeanTestInterface.java |   25 +
 .../models/BeanTestSuperclass.java              |   30 +
 .../models/BooleanAndScalarModel.java           |   40 +
 .../models/BooleanAndStringTemplateModel.java   |   38 +
 .../test/templatesuite/models/BooleanHash1.java |   58 +
 .../test/templatesuite/models/BooleanHash2.java |   50 +
 .../test/templatesuite/models/BooleanList1.java |   62 +
 .../test/templatesuite/models/BooleanList2.java |   53 +
 .../models/BooleanVsStringMethods.java          |   40 +
 .../templatesuite/models/EnumTestClass.java     |   34 +
 .../templatesuite/models/ExceptionModel.java    |   39 +
 .../models/HashAndScalarModel.java              |   84 +
 .../templatesuite/models/JavaObjectInfo.java    |   35 +
 .../test/templatesuite/models/Listables.java    |  185 +++
 .../test/templatesuite/models/MultiModel1.java  |  116 ++
 .../test/templatesuite/models/MultiModel2.java  |   63 +
 .../test/templatesuite/models/MultiModel3.java  |   69 +
 .../test/templatesuite/models/MultiModel4.java  |   77 +
 .../test/templatesuite/models/MultiModel5.java  |   81 +
 .../test/templatesuite/models/NewTestModel.java |   52 +
 .../templatesuite/models/NewTestModel2.java     |   52 +
 .../models/NumberAndStringModel.java            |   47 +
 .../models/OverloadedConstructor.java           |   46 +
 .../templatesuite/models/OverloadedMethods.java |  191 +++
 .../models/OverloadedMethods2.java              | 1110 +++++++++++++
 .../SimpleMapAndCollectionObjectWrapper.java    |   60 +
 .../templatesuite/models/SimpleTestMethod.java  |   49 +
 .../models/TransformHashWrapper.java            |   79 +
 .../models/TransformMethodWrapper1.java         |   49 +
 .../models/TransformMethodWrapper2.java         |   64 +
 .../templatesuite/models/TransformModel1.java   |  175 ++
 .../templatesuite/models/VarArgTestModel.java   |   63 +
 .../freemarker/test/templatesuite/package.html  |   42 +
 .../org/apache/freemarker/core/ast-1.ast        |  187 +++
 .../org/apache/freemarker/core/ast-1.ftl        |   29 +
 .../apache/freemarker/core/ast-assignments.ast  |  172 ++
 .../apache/freemarker/core/ast-assignments.ftl  |   29 +
 .../org/apache/freemarker/core/ast-builtins.ast |   59 +
 .../org/apache/freemarker/core/ast-builtins.ftl |   23 +
 .../apache/freemarker/core/ast-locations.ast    |  155 ++
 .../apache/freemarker/core/ast-locations.ftl    |   36 +
 .../core/ast-mixedcontentsimplifications.ast    |   38 +
 .../core/ast-mixedcontentsimplifications.ftl    |   26 +
 .../core/ast-multipleignoredchildren.ast        |   30 +
 .../core/ast-multipleignoredchildren.ftl        |   33 +
 .../core/ast-nestedignoredchildren.ast          |   20 +
 .../core/ast-nestedignoredchildren.ftl          |   19 +
 .../org/apache/freemarker/core/ast-range.ast    |  281 ++++
 .../org/apache/freemarker/core/ast-range.ftl    |   47 +
 .../freemarker/core/ast-strlitinterpolation.ast |   82 +
 .../freemarker/core/ast-strlitinterpolation.ftl |   25 +
 .../freemarker/core/ast-whitespacestripping.ast |   70 +
 .../freemarker/core/ast-whitespacestripping.ftl |   40 +
 .../apache/freemarker/core/cano-assignments.ftl |   35 +
 .../freemarker/core/cano-assignments.ftl.out    |   34 +
 .../apache/freemarker/core/cano-builtins.ftl    |   23 +
 .../freemarker/core/cano-builtins.ftl.out       |   23 +
 .../core/cano-identifier-escaping.ftl           |   76 +
 .../core/cano-identifier-escaping.ftl.out       |   44 +
 .../org/apache/freemarker/core/cano-macros.ftl  |   29 +
 .../apache/freemarker/core/cano-macros.ftl.out  |   28 +
 .../core/cano-strlitinterpolation.ftl           |   19 +
 .../core/cano-strlitinterpolation.ftl.out       |   19 +
 .../core/encodingOverride-ISO-8859-1.ftl        |   20 +
 .../freemarker/core/encodingOverride-UTF-8.ftl  |   20 +
 .../freemarker/core/templateresolver/test.ftl   |   19 +
 .../org/apache/freemarker/core/toCache1.ftl     |   19 +
 .../org/apache/freemarker/core/toCache2.ftl     |   19 +
 .../apache/freemarker/dom/DOMSiblingTest.xml    |   31 +
 .../manualtest/AutoEscapingExample-capture.ftlh |   21 +
 .../AutoEscapingExample-capture.ftlh.out        |   20 +
 .../manualtest/AutoEscapingExample-convert.ftlh |   27 +
 .../AutoEscapingExample-convert.ftlh.out        |   25 +
 .../manualtest/AutoEscapingExample-convert2.ftl |   25 +
 .../AutoEscapingExample-convert2.ftl.out        |   21 +
 .../manualtest/AutoEscapingExample-infoBox.ftlh |   26 +
 .../AutoEscapingExample-infoBox.ftlh.out        |   25 +
 .../manualtest/AutoEscapingExample-markup.ftlh  |   28 +
 .../AutoEscapingExample-markup.ftlh.out         |   26 +
 .../AutoEscapingExample-stringConcat.ftlh       |   19 +
 .../AutoEscapingExample-stringConcat.ftlh.out   |   19 +
 .../AutoEscapingExample-stringLiteral.ftlh      |   21 +
 .../AutoEscapingExample-stringLiteral.ftlh.out  |   20 +
 .../AutoEscapingExample-stringLiteral2.ftlh     |   25 +
 .../AutoEscapingExample-stringLiteral2.ftlh.out |   21 +
 .../ConfigureOutputFormatExamples1.properties   |   21 +
 .../ConfigureOutputFormatExamples2.properties   |   31 +
 .../manualtest/CustomFormatsExample-alias1.ftlh |   22 +
 .../CustomFormatsExample-alias1.ftlh.out        |   22 +
 .../manualtest/CustomFormatsExample-alias2.ftlh |   19 +
 .../CustomFormatsExample-alias2.ftlh.out        |   19 +
 .../CustomFormatsExample-modelAware.ftlh        |   20 +
 .../CustomFormatsExample-modelAware.ftlh.out    |   20 +
 .../TemplateConfigurationExamples1.properties   |   25 +
 .../TemplateConfigurationExamples2.properties   |   32 +
 .../TemplateConfigurationExamples3.properties   |   47 +
 .../org/apache/freemarker/manualtest/test.ftlh  |   28 +
 .../org/apache/freemarker/test/servlet/web.xml  |  101 ++
 .../test/templatesuite/expected/arithmetic.txt  |   46 +
 .../expected/boolean-formatting.txt             |   31 +
 .../test/templatesuite/expected/boolean.txt     |  102 ++
 .../expected/charset-in-header.txt              |   26 +
 .../test/templatesuite/expected/comment.txt     |   34 +
 .../test/templatesuite/expected/comparisons.txt |   93 ++
 .../test/templatesuite/expected/compress.txt    |   40 +
 .../templatesuite/expected/dateformat-java.txt  |   55 +
 .../expected/default-object-wrapper.txt         |   55 +
 .../templatesuite/expected/default-xmlns.txt    |   25 +
 .../test/templatesuite/expected/default.txt     |   26 +
 .../expected/encoding-builtins.txt              |   44 +
 .../test/templatesuite/expected/escapes.txt     |   49 +
 .../test/templatesuite/expected/exception.txt   |   43 +
 .../test/templatesuite/expected/exception2.txt  |   47 +
 .../test/templatesuite/expected/exception3.txt  |   21 +
 .../test/templatesuite/expected/exthash.txt     |   76 +
 .../test/templatesuite/expected/hashconcat.txt  |  138 ++
 .../test/templatesuite/expected/hashliteral.txt |   74 +
 .../test/templatesuite/expected/helloworld.txt  |   31 +
 .../expected/identifier-escaping.txt            |   57 +
 .../expected/identifier-non-ascii.txt           |   19 +
 .../test/templatesuite/expected/if.txt          |  104 ++
 .../test/templatesuite/expected/import.txt      |   40 +
 .../test/templatesuite/expected/include.txt     |   67 +
 .../test/templatesuite/expected/include2.txt    |   28 +
 .../test/templatesuite/expected/interpret.txt   |   23 +
 .../test/templatesuite/expected/iterators.txt   |   84 +
 .../templatesuite/expected/lastcharacter.txt    |   31 +
 .../test/templatesuite/expected/list-bis.txt    |   51 +
 .../test/templatesuite/expected/list.txt        |   51 +
 .../test/templatesuite/expected/list2.txt       |  211 +++
 .../test/templatesuite/expected/list3.txt       |   57 +
 .../test/templatesuite/expected/listhash.txt    |  157 ++
 .../templatesuite/expected/listhashliteral.txt  |   36 +
 .../test/templatesuite/expected/listliteral.txt |   75 +
 .../templatesuite/expected/localization.txt     |   32 +
 .../test/templatesuite/expected/logging.txt     |   27 +
 .../templatesuite/expected/loopvariable.txt     |   54 +
 .../templatesuite/expected/macros-return.txt    |   23 +
 .../test/templatesuite/expected/macros.txt      |   67 +
 .../test/templatesuite/expected/macros2.txt     |   22 +
 .../test/templatesuite/expected/multimodels.txt |   93 ++
 .../test/templatesuite/expected/nested.txt      |   25 +
 .../expected/new-allowsnothing.txt              |   19 +
 .../expected/new-defaultresolver.txt            |   19 +
 .../test/templatesuite/expected/new-optin.txt   |   32 +
 .../test/templatesuite/expected/newlines1.txt   |   29 +
 .../test/templatesuite/expected/newlines2.txt   |   30 +
 .../test/templatesuite/expected/noparse.txt     |   54 +
 .../templatesuite/expected/number-format.txt    |   33 +
 .../templatesuite/expected/number-literal.txt   |   79 +
 .../templatesuite/expected/number-to-date.txt   |   31 +
 .../templatesuite/expected/numerical-cast.txt   |  462 ++++++
 .../templatesuite/expected/output-encoding1.txt |   27 +
 .../templatesuite/expected/output-encoding2.txt |  Bin 0 -> 1972 bytes
 .../templatesuite/expected/output-encoding3.txt |   26 +
 .../test/templatesuite/expected/precedence.txt  |   48 +
 .../test/templatesuite/expected/recover.txt     |   26 +
 .../test/templatesuite/expected/root.txt        |   44 +
 .../expected/sequence-builtins.txt              |  404 +++++
 .../test/templatesuite/expected/specialvars.txt |   25 +
 .../string-builtins-regexps-matches.txt         |   99 ++
 .../expected/string-builtins-regexps.txt        |  112 ++
 .../templatesuite/expected/string-builtins1.txt |  112 ++
 .../templatesuite/expected/string-builtins2.txt |  135 ++
 .../templatesuite/expected/stringbimethods.txt  |   29 +
 .../templatesuite/expected/stringliteral.txt    |  Bin 0 -> 1550 bytes
 .../test/templatesuite/expected/switch.txt      |   80 +
 .../test/templatesuite/expected/transforms.txt  |   68 +
 .../templatesuite/expected/type-builtins.txt    |   33 +
 .../test/templatesuite/expected/var-layers.txt  |   37 +
 .../test/templatesuite/expected/varargs.txt     |   44 +
 .../test/templatesuite/expected/variables.txt   |   62 +
 .../templatesuite/expected/whitespace-trim.txt  |   60 +
 .../templatesuite/expected/wstrip-in-header.txt |   23 +
 .../test/templatesuite/expected/wstripping.txt  |   39 +
 .../templatesuite/expected/xml-fragment.txt     |   25 +
 .../expected/xml-ns_prefix-scope.txt            |   29 +
 .../test/templatesuite/expected/xml.txt         |   65 +
 .../test/templatesuite/expected/xmlns1.txt      |   63 +
 .../test/templatesuite/expected/xmlns3.txt      |   47 +
 .../test/templatesuite/expected/xmlns4.txt      |   47 +
 .../test/templatesuite/expected/xmlns5.txt      |   26 +
 .../models/BeansTestResources.properties        |   19 +
 .../test/templatesuite/models/defaultxmlns1.xml |   24 +
 .../models/xml-ns_prefix-scope.xml              |   26 +
 .../test/templatesuite/models/xml.xml           |   31 +
 .../test/templatesuite/models/xmlfragment.xml   |   19 +
 .../test/templatesuite/models/xmlns.xml         |   32 +
 .../test/templatesuite/models/xmlns2.xml        |   32 +
 .../test/templatesuite/models/xmlns3.xml        |   32 +
 .../templatesuite/templates/api-builtins.ftl    |   40 +
 .../test/templatesuite/templates/arithmetic.ftl |   50 +
 .../templatesuite/templates/assignments.ftl     |  108 ++
 .../templates/boolean-formatting.ftl            |   82 +
 .../test/templatesuite/templates/boolean.ftl    |  142 ++
 .../templates/charset-in-header.ftl             |   27 +
 .../templates/charset-in-header_inc1.ftl        |   20 +
 .../templates/charset-in-header_inc2.ftl        |   19 +
 .../test/templatesuite/templates/comment.ftl    |   50 +
 .../templatesuite/templates/comparisons.ftl     |  218 +++
 .../test/templatesuite/templates/compress.ftl   |   59 +
 .../templates/date-type-builtins.ftl            |   47 +
 .../templates/dateformat-iso-bi.ftl             |  163 ++
 .../templates/dateformat-iso-like.ftl           |  155 ++
 .../templatesuite/templates/dateformat-java.ftl |   71 +
 .../templatesuite/templates/dateparsing.ftl     |   84 +
 .../templates/default-object-wrapper.ftl        |   59 +
 .../templatesuite/templates/default-xmlns.ftl   |   28 +
 .../test/templatesuite/templates/default.ftl    |   34 +
 .../templates/encoding-builtins.ftl             |   52 +
 .../test/templatesuite/templates/escapes.ftl    |   79 +
 .../test/templatesuite/templates/exception.ftl  |   31 +
 .../test/templatesuite/templates/exception2.ftl |   31 +
 .../test/templatesuite/templates/exception3.ftl |   31 +
 .../templates/existence-operators.ftl           |  141 ++
 .../test/templatesuite/templates/hashconcat.ftl |   60 +
 .../templatesuite/templates/hashliteral.ftl     |  100 ++
 .../test/templatesuite/templates/helloworld.ftl |   30 +
 .../templates/identifier-escaping.ftl           |   81 +
 .../templates/identifier-non-ascii.ftl          |   21 +
 .../test/templatesuite/templates/if.ftl         |  109 ++
 .../test/templatesuite/templates/import.ftl     |   45 +
 .../test/templatesuite/templates/import_lib.ftl |   31 +
 .../test/templatesuite/templates/include.ftl    |   47 +
 .../templates/include2-included.ftl             |   19 +
 .../test/templatesuite/templates/include2.ftl   |   32 +
 .../test/templatesuite/templates/included.ftl   |   30 +
 .../test/templatesuite/templates/interpret.ftl  |   25 +
 .../test/templatesuite/templates/iterators.ftl  |   71 +
 .../templatesuite/templates/lastcharacter.ftl   |   31 +
 .../test/templatesuite/templates/list-bis.ftl   |   48 +
 .../test/templatesuite/templates/list.ftl       |   44 +
 .../test/templatesuite/templates/list2.ftl      |   90 ++
 .../test/templatesuite/templates/list3.ftl      |   70 +
 .../test/templatesuite/templates/listhash.ftl   |   70 +
 .../templatesuite/templates/listhashliteral.ftl |   35 +
 .../templatesuite/templates/listliteral.ftl     |   84 +
 .../templatesuite/templates/localization.ftl    |   32 +
 .../templatesuite/templates/localization_en.ftl |   32 +
 .../templates/localization_en_AU.ftl            |   32 +
 .../test/templatesuite/templates/logging.ftl    |   42 +
 .../templatesuite/templates/loopvariable.ftl    |   49 +
 .../templatesuite/templates/macros-return.ftl   |   34 +
 .../test/templatesuite/templates/macros.ftl     |  101 ++
 .../test/templatesuite/templates/macros2.ftl    |   35 +
 .../templatesuite/templates/multimodels.ftl     |   84 +
 .../test/templatesuite/templates/nested.ftl     |   29 +
 .../templatesuite/templates/nestedinclude.ftl   |   21 +
 .../templates/new-defaultresolver.ftl           |   23 +
 .../test/templatesuite/templates/new-optin.ftl  |   30 +
 .../test/templatesuite/templates/newlines1.ftl  |   29 +
 .../test/templatesuite/templates/newlines2.ftl  |   33 +
 .../test/templatesuite/templates/noparse.ftl    |   62 +
 .../templatesuite/templates/number-format.ftl   |   42 +
 .../templatesuite/templates/number-literal.ftl  |  133 ++
 .../templates/number-math-builtins.ftl          |   78 +
 .../templatesuite/templates/number-to-date.ftl  |   35 +
 .../templatesuite/templates/numerical-cast.ftl  |   82 +
 .../templates/output-encoding1.ftl              |   30 +
 .../templates/output-encoding2.ftl              |   28 +
 .../templates/output-encoding3.ftl              |   28 +
 .../templates/overloaded-methods.ftl            |  411 +++++
 .../test/templatesuite/templates/precedence.ftl |   61 +
 .../templatesuite/templates/range-common.ftl    |  314 ++++
 .../test/templatesuite/templates/range.ftl      |   50 +
 .../test/templatesuite/templates/recover.ftl    |   47 +
 .../test/templatesuite/templates/root.ftl       |   47 +
 .../templates/sequence-builtins.ftl             |  360 +++++
 .../test/templatesuite/templates/setting.ftl    |   53 +
 .../templates/simplehash-char-key.ftl           |   44 +
 .../templatesuite/templates/specialvars.ftl     |   38 +
 .../templates/string-builtin-coercion.ftl       |   34 +
 .../string-builtins-regexps-matches.ftl         |  118 ++
 .../templates/string-builtins-regexps.ftl       |  136 ++
 .../templates/string-builtins1.ftl              |  129 ++
 .../templates/string-builtins2.ftl              |  135 ++
 .../templates/string-builtins3.ftl              |  225 +++
 .../templatesuite/templates/stringbimethods.ftl |   36 +
 .../templatesuite/templates/stringliteral.ftl   |   69 +
 .../templates/subdir/include-subdir.ftl         |   27 +
 .../templates/subdir/include-subdir2.ftl        |   19 +
 .../templates/subdir/new-optin-2.ftl            |   24 +
 .../templates/subdir/new-optin.ftl              |   26 +
 .../templates/subdir/subsub/new-optin.ftl       |   24 +
 .../templatesuite/templates/switch-builtin.ftl  |   54 +
 .../test/templatesuite/templates/switch.ftl     |  139 ++
 .../templatesuite/templates/then-builtin.ftl    |   53 +
 .../test/templatesuite/templates/transforms.ftl |  100 ++
 .../templatesuite/templates/type-builtins.ftl   |   44 +
 .../test/templatesuite/templates/undefined.ftl  |   19 +
 .../test/templatesuite/templates/url.ftl        |   24 +
 .../test/templatesuite/templates/var-layers.ftl |   39 +
 .../test/templatesuite/templates/varargs.ftl    |   45 +
 .../test/templatesuite/templates/variables.ftl  |   70 +
 .../templatesuite/templates/varlayers_lib.ftl   |   28 +
 .../templatesuite/templates/whitespace-trim.ftl |  102 ++
 .../templates/wsstripinheader_inc.ftl           |   22 +
 .../templates/wstrip-in-header.ftl              |   26 +
 .../templatesuite/templates/xml-fragment.ftl    |   26 +
 .../templates/xml-ns_prefix-scope-lib.ftl       |   23 +
 .../templates/xml-ns_prefix-scope-main.ftl      |   36 +
 .../test/templatesuite/templates/xml.ftl        |   47 +
 .../test/templatesuite/templates/xmlns1.ftl     |   53 +
 .../test/templatesuite/templates/xmlns3.ftl     |   70 +
 .../test/templatesuite/templates/xmlns4.ftl     |   70 +
 .../test/templatesuite/templates/xmlns5.ftl     |   28 +
 .../freemarker/test/templatesuite/testcases.xml |  211 +++
 freemarker-core/src/test/README.txt             |    7 +
 .../core/ASTBasedErrorMessagesTest.java         |   74 -
 .../org/apache/freemarker/core/ASTPrinter.java  |  438 -----
 .../org/apache/freemarker/core/ASTTest.java     |  103 --
 .../core/ActualNamingConvetionTest.java         |   66 -
 .../freemarker/core/ActualTagSyntaxTest.java    |   68 -
 .../freemarker/core/BreakPlacementTest.java     |   56 -
 .../apache/freemarker/core/CamelCaseTest.java   |  486 ------
 .../freemarker/core/CanonicalFormTest.java      |   68 -
 .../freemarker/core/CoercionToTextualTest.java  |  149 --
 .../freemarker/core/ConfigurableTest.java       |  176 --
 .../freemarker/core/ConfigurationTest.java      | 1486 -----------------
 .../freemarker/core/CoreLocaleUtilsTest.java    |   73 -
 .../freemarker/core/CustomAttributeTest.java    |  163 --
 .../apache/freemarker/core/DateFormatTest.java  |  464 ------
 .../freemarker/core/DirectiveCallPlaceTest.java |  249 ---
 .../freemarker/core/EncodingOverrideTest.java   |   62 -
 .../EnvironmentGetTemplateVariantsTest.java     |  214 ---
 .../apache/freemarker/core/ExceptionTest.java   |  115 --
 .../apache/freemarker/core/GetSourceTest.java   |   52 -
 .../freemarker/core/HeaderParsingTest.java      |   60 -
 .../IncludeAndImportConfigurableLayersTest.java |  354 -----
 .../freemarker/core/IncludeAndImportTest.java   |  270 ----
 .../freemarker/core/IncudeFromNamelessTest.java |   58 -
 .../core/InterpretAndEvalTemplateNameTest.java  |   70 -
 .../core/InterpretSettingInheritanceTest.java   |  104 --
 .../freemarker/core/IteratorIssuesTest.java     |   64 -
 .../core/JavaCCExceptionAsEOFFixTest.java       |  126 --
 .../apache/freemarker/core/ListErrorsTest.java  |  130 --
 .../freemarker/core/MiscErrorMessagesTest.java  |   48 -
 .../core/MistakenlyPublicImportAPIsTest.java    |  104 --
 .../core/MistakenlyPublicMacroAPIsTest.java     |   88 -
 .../core/NewBiObjectWrapperRestrictionTest.java |   50 -
 .../core/ObjectBuilderSettingsTest.java         | 1499 ------------------
 .../core/OptInTemplateClassResolverTest.java    |  230 ---
 .../freemarker/core/OutputFormatTest.java       | 1068 -------------
 .../ParseTimeParameterBIErrorMessagesTest.java  |   46 -
 .../core/ParsingErrorMessagesTest.java          |  116 --
 .../core/RestrictedObjectWrapperTest.java       |   72 -
 .../core/RestrictedObjetWrapperTest.java        |  112 --
 .../apache/freemarker/core/SQLTimeZoneTest.java |  371 -----
 .../freemarker/core/SettingDirectiveTest.java   |   40 -
 .../freemarker/core/SpecialVariableTest.java    |  114 --
 .../core/StringLiteralInterpolationTest.java    |  135 --
 .../org/apache/freemarker/core/TabSizeTest.java |   91 --
 .../core/TagSyntaxVariationsTest.java           |  186 ---
 .../core/TemplateConfigurationTest.java         |  909 -----------
 ...gurationWithDefaultTemplateResolverTest.java |  267 ----
 .../core/TemplateConstructorsTest.java          |  113 --
 .../core/TemplateGetEncodingTest.java           |   64 -
 .../core/TemplateLookupStrategyTest.java        |  669 --------
 .../core/TemplateNameSpecialVariablesTest.java  |  159 --
 .../core/TemplateNotFoundMessageTest.java       |  207 ---
 .../core/TheadInterruptingSupportTest.java      |  163 --
 .../freemarker/core/TypeErrorMessagesTest.java  |  105 --
 .../freemarker/core/UnclosedCommentTest.java    |   41 -
 .../org/apache/freemarker/core/VersionTest.java |  227 ---
 .../core/WhitespaceStrippingTest.java           |   63 -
 .../freemarker/core/XHTMLOutputFormatTest.java  |   59 -
 .../freemarker/core/XMLOutputFormatTest.java    |   59 -
 .../impl/AbstractParallelIntrospectionTest.java |  126 --
 .../model/impl/AlphabeticalMethodSorter.java    |   45 -
 .../CommonSupertypeForUnwrappingHintTest.java   |  129 --
 .../model/impl/DefaultObjectWrapperDesc.java    |   31 -
 .../model/impl/DefaultObjectWrapperInc.java     |   31 -
 ...jectWrapperModelFactoryRegistrationTest.java |   63 -
 .../DefaultObjectWrapperSingletonsTest.java     |  675 --------
 .../model/impl/DefaultObjectWrapperTest.java    |  901 -----------
 .../core/model/impl/EnumModelsTest.java         |   85 -
 .../core/model/impl/ErrorMessagesTest.java      |  170 --
 .../impl/FineTuneMethodAppearanceTest.java      |   65 -
 .../GetlessMethodsAsPropertyGettersRule.java    |   67 -
 .../core/model/impl/IsApplicableTest.java       |  171 --
 .../impl/IsMoreSpecificParameterTypeTest.java   |   98 --
 .../Java7MembersOnlyDefaultObjectWrapper.java   |  101 --
 .../impl/ManyObjectsOfDifferentClasses.java     |  249 ---
 .../impl/ManyStaticsOfDifferentClasses.java     |  236 ---
 .../model/impl/MiscNumericalOperationsTest.java |  111 --
 .../model/impl/ModelAPINewInstanceTest.java     |  134 --
 .../core/model/impl/ModelCacheTest.java         |   71 -
 .../model/impl/OverloadedNumberUtilTest.java    |  585 -------
 .../impl/ParameterListPreferabilityTest.java    |  445 ------
 .../impl/PrallelObjectIntrospectionTest.java    |   43 -
 .../impl/PrallelStaticIntrospectionTest.java    |   47 -
 .../core/model/impl/RationalNumber.java         |   90 --
 .../core/model/impl/StaticModelsTest.java       |   91 --
 .../core/model/impl/TypeFlagsTest.java          |  671 --------
 .../core/outputformat/_OutputFormatTestAPI.java |   35 -
 .../impl/CombinedMarkupOutputFormatTest.java    |  194 ---
 .../outputformat/impl/HTMLOutputFormatTest.java |  187 ---
 .../outputformat/impl/RTFOutputFormatTest.java  |  129 --
 .../DefaultTemplateResolverTest.java            |  365 -----
 .../FileTemplateLoaderTest.java                 |  122 --
 .../MultiTemplateLoaderTest.java                |   99 --
 .../TemplateConfigurationFactoryTest.java       |  203 ---
 .../TemplateNameFormatTest.java                 |  330 ----
 .../TemplateSourceMatcherTest.java              |  188 ---
 .../AppMetaTemplateDateFormatFactory.java       |  129 --
 .../BaseNTemplateNumberFormatFactory.java       |  128 --
 .../core/userpkg/CustomHTMLOutputFormat.java    |   72 -
 .../core/userpkg/CustomTemplateHTMLModel.java   |   34 -
 .../core/userpkg/DummyOutputFormat.java         |   65 -
 ...EpochMillisDivTemplateDateFormatFactory.java |  102 --
 .../EpochMillisTemplateDateFormatFactory.java   |   92 --
 .../HTMLISOTemplateDateFormatFactory.java       |  114 --
 .../userpkg/HexTemplateNumberFormatFactory.java |   77 -
 ...AndTZSensitiveTemplateDateFormatFactory.java |   97 --
 ...aleSensitiveTemplateNumberFormatFactory.java |   78 -
 .../core/userpkg/PackageVisibleAll.java         |   26 -
 .../userpkg/PackageVisibleAllWithBuilder.java   |   26 -
 .../PackageVisibleAllWithBuilderBuilder.java    |   28 -
 .../PackageVisibleWithPublicConstructor.java    |   27 -
 .../PrintfGTemplateNumberFormatFactory.java     |  138 --
 .../freemarker/core/userpkg/PublicAll.java      |   24 -
 .../userpkg/PublicWithMixedConstructors.java    |   38 -
 .../PublicWithPackageVisibleConstructor.java    |   26 -
 .../core/userpkg/SeldomEscapedOutputFormat.java |   71 -
 .../core/userpkg/TemplateDummyOutputModel.java  |   34 -
 .../TemplateSeldomEscapedOutputModel.java       |   34 -
 .../freemarker/core/util/DateUtilTest.java      | 1085 -------------
 .../freemarker/core/util/FTLUtilTest.java       |  117 --
 .../freemarker/core/util/NumberUtilTest.java    |  215 ---
 .../freemarker/core/util/StringUtilTest.java    |  403 -----
 .../core/valueformat/NumberFormatTest.java      |  365 -----
 .../impl/ExtendedDecimalFormatTest.java         |  343 ----
 .../apache/freemarker/dom/DOMSiblingTest.java   |   99 --
 .../freemarker/dom/DOMSimplifiersTest.java      |  201 ---
 .../java/org/apache/freemarker/dom/DOMTest.java |  159 --
 .../manualtest/AutoEscapingExample.java         |   72 -
 .../ConfigureOutputFormatExamples.java          |  105 --
 .../manualtest/CustomFormatsExample.java        |   84 -
 .../manualtest/GettingStartedExample.java       |   69 -
 .../apache/freemarker/manualtest/Product.java   |   49 -
 .../TemplateConfigurationExamples.java          |  191 ---
 .../UnitAwareTemplateNumberFormatFactory.java   |   80 -
 .../UnitAwareTemplateNumberModel.java           |   43 -
 .../CopyrightCommentRemoverTemplateLoader.java  |  104 --
 .../test/MonitoredTemplateLoader.java           |  325 ----
 .../apache/freemarker/test/TemplateTest.java    |  341 ----
 .../test/TestConfigurationBuilder.java          |   92 --
 .../freemarker/test/hamcerst/Matchers.java      |   34 -
 .../hamcerst/StringContainsIgnoringCase.java    |   47 -
 .../org/apache/freemarker/test/package.html     |   28 -
 .../test/templatesuite/TemplateTestCase.java    |  515 ------
 .../test/templatesuite/TemplateTestSuite.java   |  298 ----
 .../templatesuite/models/AllTemplateModels.java |  128 --
 .../templatesuite/models/BeanTestClass.java     |   93 --
 .../templatesuite/models/BeanTestInterface.java |   25 -
 .../models/BeanTestSuperclass.java              |   30 -
 .../models/BooleanAndScalarModel.java           |   40 -
 .../models/BooleanAndStringTemplateModel.java   |   38 -
 .../test/templatesuite/models/BooleanHash1.java |   58 -
 .../test/templatesuite/models/BooleanHash2.java |   50 -
 .../test/templatesuite/models/BooleanList1.java |   62 -
 .../test/templatesuite/models/BooleanList2.java |   53 -
 .../models/BooleanVsStringMethods.java          |   40 -
 .../templatesuite/models/EnumTestClass.java     |   34 -
 .../templatesuite/models/ExceptionModel.java    |   39 -
 .../models/HashAndScalarModel.java              |   84 -
 .../templatesuite/models/JavaObjectInfo.java    |   35 -
 .../test/templatesuite/models/Listables.java    |  185 ---
 .../test/templatesuite/models/MultiModel1.java  |  116 --
 .../test/templatesuite/models/MultiModel2.java  |   63 -
 .../test/templatesuite/models/MultiModel3.java  |   69 -
 .../test/templatesuite/models/MultiModel4.java  |   77 -
 .../test/templatesuite/models/MultiModel5.java  |   81 -
 .../test/templatesuite/models/NewTestModel.java |   52 -
 .../templatesuite/models/NewTestModel2.java     |   52 -
 .../models/NumberAndStringModel.java            |   47 -
 .../models/OverloadedConstructor.java           |   46 -
 .../templatesuite/models/OverloadedMethods.java |  191 ---
 .../models/OverloadedMethods2.java              | 1110 -------------
 .../templatesuite/models/SimpleTestMethod.java  |   49 -
 .../models/TransformHashWrapper.java            |   79 -
 .../models/TransformMethodWrapper1.java         |   49 -
 .../models/TransformMethodWrapper2.java         |   64 -
 .../templatesuite/models/TransformModel1.java   |  175 --
 .../templatesuite/models/VarArgTestModel.java   |   63 -
 .../freemarker/test/templatesuite/package.html  |   42 -
 .../freemarker/test/util/AssertDirective.java   |   73 -
 .../test/util/AssertEqualsDirective.java        |   91 --
 .../test/util/AssertFailsDirective.java         |  152 --
 .../AssertationFailedInTemplateException.java   |   46 -
 .../test/util/BadParameterTypeException.java    |   60 -
 .../freemarker/test/util/CoreTestUtil.java      |   19 -
 .../test/util/EntirelyCustomObjectWrapper.java  |   91 --
 .../freemarker/test/util/FileTestCase.java      |  217 ---
 .../util/MissingRequiredParameterException.java |   51 -
 .../freemarker/test/util/NoOutputDirective.java |   50 -
 .../test/util/ParameterException.java           |   54 -
 .../SimpleMapAndCollectionObjectWrapper.java    |   60 -
 .../util/UnsupportedParameterException.java     |   50 -
 .../apache/freemarker/test/util/XMLLoader.java  |  138 --
 .../org/apache/freemarker/core/ast-1.ast        |  187 ---
 .../org/apache/freemarker/core/ast-1.ftl        |   29 -
 .../apache/freemarker/core/ast-assignments.ast  |  172 --
 .../apache/freemarker/core/ast-assignments.ftl  |   29 -
 .../org/apache/freemarker/core/ast-builtins.ast |   59 -
 .../org/apache/freemarker/core/ast-builtins.ftl |   23 -
 .../apache/freemarker/core/ast-locations.ast    |  155 --
 .../apache/freemarker/core/ast-locations.ftl    |   36 -
 .../core/ast-mixedcontentsimplifications.ast    |   38 -
 .../core/ast-mixedcontentsimplifications.ftl    |   26 -
 .../core/ast-multipleignoredchildren.ast        |   30 -
 .../core/ast-multipleignoredchildren.ftl        |   33 -
 .../core/ast-nestedignoredchildren.ast          |   20 -
 .../core/ast-nestedignoredchildren.ftl          |   19 -
 .../org/apache/freemarker/core/ast-range.ast    |  281 ----
 .../org/apache/freemarker/core/ast-range.ftl    |   47 -
 .../freemarker/core/ast-strlitinterpolation.ast |   82 -
 .../freemarker/core/ast-strlitinterpolation.ftl |   25 -
 .../freemarker/core/ast-whitespacestripping.ast |   70 -
 .../freemarker/core/ast-whitespacestripping.ftl |   40 -
 .../apache/freemarker/core/cano-assignments.ftl |   35 -
 .../freemarker/core/cano-assignments.ftl.out    |   34 -
 .../apache/freemarker/core/cano-builtins.ftl    |   23 -
 .../freemarker/core/cano-builtins.ftl.out       |   23 -
 .../core/cano-identifier-escaping.ftl           |   76 -
 .../core/cano-identifier-escaping.ftl.out       |   44 -
 .../org/apache/freemarker/core/cano-macros.ftl  |   29 -
 .../apache/freemarker/core/cano-macros.ftl.out  |   28 -
 .../core/cano-strlitinterpolation.ftl           |   19 -
 .../core/cano-strlitinterpolation.ftl.out       |   19 -
 .../core/encodingOverride-ISO-8859-1.ftl        |   20 -
 .../freemarker/core/encodingOverride-UTF-8.ftl  |   20 -
 .../freemarker/core/templateresolver/test.ftl   |   19 -
 .../org/apache/freemarker/core/toCache1.ftl     |   19 -
 .../org/apache/freemarker/core/toCache2.ftl     |   19 -
 .../apache/freemarker/dom/DOMSiblingTest.xml    |   31 -
 .../manualtest/AutoEscapingExample-capture.ftlh |   21 -
 .../AutoEscapingExample-capture.ftlh.out        |   20 -
 .../manualtest/AutoEscapingExample-convert.ftlh |   27 -
 .../AutoEscapingExample-convert.ftlh.out        |   25 -
 .../manualtest/AutoEscapingExample-convert2.ftl |   25 -
 .../AutoEscapingExample-convert2.ftl.out        |   21 -
 .../manualtest/AutoEscapingExample-infoBox.ftlh |   26 -
 .../AutoEscapingExample-infoBox.ftlh.out        |   25 -
 .../manualtest/AutoEscapingExample-markup.ftlh  |   28 -
 .../AutoEscapingExample-markup.ftlh.out         |   26 -
 .../AutoEscapingExample-stringConcat.ftlh       |   19 -
 .../AutoEscapingExample-stringConcat.ftlh.out   |   19 -
 .../AutoEscapingExample-stringLiteral.ftlh      |   21 -
 .../AutoEscapingExample-stringLiteral.ftlh.out  |   20 -
 .../AutoEscapingExample-stringLiteral2.ftlh     |   25 -
 .../AutoEscapingExample-stringLiteral2.ftlh.out |   21 -
 .../ConfigureOutputFormatExamples1.properties   |   21 -
 .../ConfigureOutputFormatExamples2.properties   |   31 -
 .../manualtest/CustomFormatsExample-alias1.ftlh |   22 -
 .../CustomFormatsExample-alias1.ftlh.out        |   22 -
 .../manualtest/CustomFormatsExample-alias2.ftlh |   19 -
 .../CustomFormatsExample-alias2.ftlh.out        |   19 -
 .../CustomFormatsExample-modelAware.ftlh        |   20 -
 .../CustomFormatsExample-modelAware.ftlh.out    |   20 -
 .../TemplateConfigurationExamples1.properties   |   25 -
 .../TemplateConfigurationExamples2.properties   |   32 -
 .../TemplateConfigurationExamples3.properties   |   47 -
 .../org/apache/freemarker/manualtest/test.ftlh  |   28 -
 .../org/apache/freemarker/test/servlet/web.xml  |  101 --
 .../test/templatesuite/expected/arithmetic.txt  |   46 -
 .../expected/boolean-formatting.txt             |   31 -
 .../test/templatesuite/expected/boolean.txt     |  102 --
 .../expected/charset-in-header.txt              |   26 -
 .../test/templatesuite/expected/comment.txt     |   34 -
 .../test/templatesuite/expected/comparisons.txt |   93 --
 .../test/templatesuite/expected/compress.txt    |   40 -
 .../templatesuite/expected/dateformat-java.txt  |   55 -
 .../expected/default-object-wrapper.txt         |   55 -
 .../templatesuite/expected/default-xmlns.txt    |   25 -
 .../test/templatesuite/expected/default.txt     |   26 -
 .../expected/encoding-builtins.txt              |   44 -
 .../test/templatesuite/expected/escapes.txt     |   49 -
 .../test/templatesuite/expected/exception.txt   |   43 -
 .../test/templatesuite/expected/exception2.txt  |   47 -
 .../test/templatesuite/expected/exception3.txt  |   21 -
 .../test/templatesuite/expected/exthash.txt     |   76 -
 .../test/templatesuite/expected/hashconcat.txt  |  138 --
 .../test/templatesuite/expected/hashliteral.txt |   74 -
 .../test/templatesuite/expected/helloworld.txt  |   31 -
 .../expected/identifier-escaping.txt            |   57 -
 .../expected/identifier-non-ascii.txt           |   19 -
 .../test/templatesuite/expected/if.txt          |  104 --
 .../test/templatesuite/expected/import.txt      |   40 -
 .../test/templatesuite/expected/include.txt     |   67 -
 .../test/templatesuite/expected/include2.txt    |   28 -
 .../test/templatesuite/expected/interpret.txt   |   23 -
 .../test/templatesuite/expected/iterators.txt   |   84 -
 .../templatesuite/expected/lastcharacter.txt    |   31 -
 .../test/templatesuite/expected/list-bis.txt    |   51 -
 .../test/templatesuite/expected/list.txt        |   51 -
 .../test/templatesuite/expected/list2.txt       |  211 ---
 .../test/templatesuite/expected/list3.txt       |   57 -
 .../test/templatesuite/expected/listhash.txt    |  157 --
 .../templatesuite/expected/listhashliteral.txt  |   36 -
 .../test/templatesuite/expected/listliteral.txt |   75 -
 .../templatesuite/expected/localization.txt     |   32 -
 .../test/templatesuite/expected/logging.txt     |   27 -
 .../templatesuite/expected/loopvariable.txt     |   54 -
 .../templatesuite/expected/macros-return.txt    |   23 -
 .../test/templatesuite/expected/macros.txt      |   67 -
 .../test/templatesuite/expected/macros2.txt     |   22 -
 .../test/templatesuite/expected/multimodels.txt |   93 --
 .../test/templatesuite/expected/nested.txt      |   25 -
 .../expected/new-allowsnothing.txt              |   19 -
 .../expected/new-defaultresolver.txt            |   19 -
 .../test/templatesuite/expected/new-optin.txt   |   32 -
 .../test/templatesuite/expected/newlines1.txt   |   29 -
 .../test/templatesuite/expected/newlines2.txt   |   30 -
 .../test/templatesuite/expected/noparse.txt     |   54 -
 .../templatesuite/expected/number-format.txt    |   33 -
 .../templatesuite/expected/number-literal.txt   |   79 -
 .../templatesuite/expected/number-to-date.txt   |   31 -
 .../templatesuite/expected/numerical-cast.txt   |  462 ------
 .../templatesuite/expected/output-encoding1.txt |   27 -
 .../templatesuite/expected/output-encoding2.txt |  Bin 1972 -> 0 bytes
 .../templatesuite/expected/output-encoding3.txt |   26 -
 .../test/templatesuite/expected/precedence.txt  |   48 -
 .../test/templatesuite/expected/recover.txt     |   26 -
 .../test/templatesuite/expected/root.txt        |   44 -
 .../expected/sequence-builtins.txt              |  404 -----
 .../test/templatesuite/expected/specialvars.txt |   25 -
 .../string-builtins-regexps-matches.txt         |   99 --
 .../expected/string-builtins-regexps.txt        |  112 --
 .../templatesuite/expected/string-builtins1.txt |  112 --
 .../templatesuite/expected/string-builtins2.txt |  135 --
 .../templatesuite/expected/stringbimethods.txt  |   29 -
 .../templatesuite/expected/stringliteral.txt    |  Bin 1550 -> 0 bytes
 .../test/templatesuite/expected/switch.txt      |   80 -
 .../test/templatesuite/expected/transforms.txt  |   68 -
 .../templatesuite/expected/type-builtins.txt    |   33 -
 .../test/templatesuite/expected/var-layers.txt  |   37 -
 .../test/templatesuite/expected/varargs.txt     |   44 -
 .../test/templatesuite/expected/variables.txt   |   62 -
 .../templatesuite/expected/whitespace-trim.txt  |   60 -
 .../templatesuite/expected/wstrip-in-header.txt |   23 -
 .../test/templatesuite/expected/wstripping.txt  |   39 -
 .../templatesuite/expected/xml-fragment.txt     |   25 -
 .../expected/xml-ns_prefix-scope.txt            |   29 -
 .../test/templatesuite/expected/xml.txt         |   65 -
 .../test/templatesuite/expected/xmlns1.txt      |   63 -
 .../test/templatesuite/expected/xmlns3.txt      |   47 -
 .../test/templatesuite/expected/xmlns4.txt      |   47 -
 .../test/templatesuite/expected/xmlns5.txt      |   26 -
 .../models/BeansTestResources.properties        |   19 -
 .../test/templatesuite/models/defaultxmlns1.xml |   24 -
 .../models/xml-ns_prefix-scope.xml              |   26 -
 .../test/templatesuite/models/xml.xml           |   31 -
 .../test/templatesuite/models/xmlfragment.xml   |   19 -
 .../test/templatesuite/models/xmlns.xml         |   32 -
 .../test/templatesuite/models/xmlns2.xml        |   32 -
 .../test/templatesuite/models/xmlns3.xml        |   32 -
 .../templatesuite/templates/api-builtins.ftl    |   40 -
 .../test/templatesuite/templates/arithmetic.ftl |   50 -
 .../templatesuite/templates/assignments.ftl     |  108 --
 .../templates/boolean-formatting.ftl            |   82 -
 .../test/templatesuite/templates/boolean.ftl    |  142 --
 .../templates/charset-in-header.ftl             |   27 -
 .../templates/charset-in-header_inc1.ftl        |   20 -
 .../templates/charset-in-header_inc2.ftl        |   19 -
 .../test/templatesuite/templates/comment.ftl    |   50 -
 .../templatesuite/templates/comparisons.ftl     |  218 ---
 .../test/templatesuite/templates/compress.ftl   |   59 -
 .../templates/date-type-builtins.ftl            |   47 -
 .../templates/dateformat-iso-bi.ftl             |  163 --
 .../templates/dateformat-iso-like.ftl           |  155 --
 .../templatesuite/templates/dateformat-java.ftl |   71 -
 .../templatesuite/templates/dateparsing.ftl     |   84 -
 .../templates/default-object-wrapper.ftl        |   59 -
 .../templatesuite/templates/default-xmlns.ftl   |   28 -
 .../test/templatesuite/templates/default.ftl    |   34 -
 .../templates/encoding-builtins.ftl             |   52 -
 .../test/templatesuite/templates/escapes.ftl    |   79 -
 .../test/templatesuite/templates/exception.ftl  |   31 -
 .../test/templatesuite/templates/exception2.ftl |   31 -
 .../test/templatesuite/templates/exception3.ftl |   31 -
 .../templates/existence-operators.ftl           |  141 --
 .../test/templatesuite/templates/hashconcat.ftl |   60 -
 .../templatesuite/templates/hashliteral.ftl     |  100 --
 .../test/templatesuite/templates/helloworld.ftl |   30 -
 .../templates/identifier-escaping.ftl           |   81 -
 .../templates/identifier-non-ascii.ftl          |   21 -
 .../test/templatesuite/templates/if.ftl         |  109 --
 .../test/templatesuite/templates/import.ftl     |   45 -
 .../test/templatesuite/templates/import_lib.ftl |   31 -
 .../test/templatesuite/templates/include.ftl    |   47 -
 .../templates/include2-included.ftl             |   19 -
 .../test/templatesuite/templates/include2.ftl   |   32 -
 .../test/templatesuite/templates/included.ftl   |   30 -
 .../test/templatesuite/templates/interpret.ftl  |   25 -
 .../test/templatesuite/templates/iterators.ftl  |   71 -
 .../templatesuite/templates/lastcharacter.ftl   |   31 -
 .../test/templatesuite/templates/list-bis.ftl   |   48 -
 .../test/templatesuite/templates/list.ftl       |   44 -
 .../test/templatesuite/templates/list2.ftl      |   90 --
 .../test/templatesuite/templates/list3.ftl      |   70 -
 .../test/templatesuite/templates/listhash.ftl   |   70 -
 .../templatesuite/templates/listhashliteral.ftl |   35 -
 .../templatesuite/templates/listliteral.ftl     |   84 -
 .../templatesuite/templates/localization.ftl    |   32 -
 .../templatesuite/templates/localization_en.ftl |   32 -
 .../templates/localization_en_AU.ftl            |   32 -
 .../test/templatesuite/templates/logging.ftl    |   42 -
 .../templatesuite/templates/loopvariable.ftl    |   49 -
 .../templatesuite/templates/macros-return.ftl   |   34 -
 .../test/templatesuite/templates/macros.ftl     |  101 --
 .../test/templatesuite/templates/macros2.ftl    |   35 -
 .../templatesuite/templates/multimodels.ftl     |   84 -
 .../test/templatesuite/templates/nested.ftl     |   29 -
 .../templatesuite/templates/nestedinclude.ftl   |   21 -
 .../templates/new-defaultresolver.ftl           |   23 -
 .../test/templatesuite/templates/new-optin.ftl  |   30 -
 .../test/templatesuite/templates/newlines1.ftl  |   29 -
 .../test/templatesuite/templates/newlines2.ftl  |   33 -
 .../test/templatesuite/templates/noparse.ftl    |   62 -
 .../templatesuite/templates/number-format.ftl   |   42 -
 .../templatesuite/templates/number-literal.ftl  |  133 --
 .../templates/number-math-builtins.ftl          |   78 -
 .../templatesuite/templates/number-to-date.ftl  |   35 -
 .../templatesuite/templates/numerical-cast.ftl  |   82 -
 .../templates/output-encoding1.ftl              |   30 -
 .../templates/output-encoding2.ftl              |   28 -
 .../templates/output-encoding3.ftl              |   28 -
 .../templates/overloaded-methods.ftl            |  411 -----
 .../test/templatesuite/templates/precedence.ftl |   61 -
 .../templatesuite/templates/range-common.ftl    |  314 ----
 .../test/templatesuite/templates/range.ftl      |   50 -
 .../test/templatesuite/templates/recover.ftl    |   47 -
 .../test/templatesuite/templates/root.ftl       |   47 -
 .../templates/sequence-builtins.ftl             |  360 -----
 .../test/templatesuite/templates/setting.ftl    |   53 -
 .../templates/simplehash-char-key.ftl           |   44 -
 .../templatesuite/templates/specialvars.ftl     |   38 -
 .../templates/string-builtin-coercion.ftl       |   34 -
 .../string-builtins-regexps-matches.ftl         |  118 --
 .../templates/string-builtins-regexps.ftl       |  136 --
 .../templates/string-builtins1.ftl              |  129 --
 .../templates/string-builtins2.ftl              |  135 --
 .../templates/string-builtins3.ftl              |  225 ---
 .../templatesuite/templates/stringbimethods.ftl |   36 -
 .../templatesuite/templates/stringliteral.ftl   |   69 -
 .../templates/subdir/include-subdir.ftl         |   27 -
 .../templates/subdir/include-subdir2.ftl        |   19 -
 .../templates/subdir/new-optin-2.ftl            |   24 -
 .../templates/subdir/new-optin.ftl              |   26 -
 .../templates/subdir/subsub/new-optin.ftl       |   24 -
 .../templatesuite/templates/switch-builtin.ftl  |   54 -
 .../test/templatesuite/templates/switch.ftl     |  139 --
 .../templatesuite/templates/then-builtin.ftl    |   53 -
 .../test/templatesuite/templates/transforms.ftl |  100 --
 .../templatesuite/templates/type-builtins.ftl   |   44 -
 .../test/templatesuite/templates/undefined.ftl  |   19 -
 .../test/templatesuite/templates/url.ftl        |   24 -
 .../test/templatesuite/templates/var-layers.ftl |   39 -
 .../test/templatesuite/templates/varargs.ftl    |   45 -
 .../test/templatesuite/templates/variables.ftl  |   70 -
 .../templatesuite/templates/varlayers_lib.ftl   |   28 -
 .../templatesuite/templates/whitespace-trim.ftl |  102 --
 .../templates/wsstripinheader_inc.ftl           |   22 -
 .../templates/wstrip-in-header.ftl              |   26 -
 .../templatesuite/templates/xml-fragment.ftl    |   26 -
 .../templates/xml-ns_prefix-scope-lib.ftl       |   23 -
 .../templates/xml-ns_prefix-scope-main.ftl      |   36 -
 .../test/templatesuite/templates/xml.ftl        |   47 -
 .../test/templatesuite/templates/xmlns1.ftl     |   53 -
 .../test/templatesuite/templates/xmlns3.ftl     |   70 -
 .../test/templatesuite/templates/xmlns4.ftl     |   70 -
 .../test/templatesuite/templates/xmlns5.ftl     |   28 -
 .../freemarker/test/templatesuite/testcases.xml |  211 ---
 freemarker-test-utils/build.gradle              |    2 +
 .../CopyrightCommentRemoverTemplateLoader.java  |  105 ++
 .../apache/freemarker/test/FileTestCase.java    |  216 +++
 .../test/MonitoredTemplateLoader.java           |  325 ++++
 .../freemarker/test/ResourcesExtractor.java     |   14 +-
 .../apache/freemarker/test/TemplateTest.java    |  340 ++++
 .../test/TestConfigurationBuilder.java          |   92 ++
 .../org/apache/freemarker/test/TestUtil.java    |   85 +-
 .../org/apache/freemarker/test/XMLLoader.java   |  138 ++
 .../apache/freemarker/test/_TStringUtil.java    |   65 -
 .../freemarker/test/hamcerst/Matchers.java      |   34 +
 .../hamcerst/StringContainsIgnoringCase.java    |   47 +
 .../test/templateutil/AssertDirective.java      |   73 +
 .../templateutil/AssertEqualsDirective.java     |   91 ++
 .../test/templateutil/AssertFailsDirective.java |  152 ++
 .../AssertationFailedInTemplateException.java   |   46 +
 .../templateutil/BadParameterTypeException.java |   60 +
 .../MissingRequiredParameterException.java      |   51 +
 .../test/templateutil/NoOutputDirective.java    |   50 +
 .../test/templateutil/ParameterException.java   |   54 +
 .../UnsupportedParameterException.java          |   50 +
 settings.gradle                                 |    3 +-
 962 files changed, 48802 insertions(+), 48913 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-java8-test/build.gradle
----------------------------------------------------------------------
diff --git a/freemarker-core-java8-test/build.gradle b/freemarker-core-java8-test/build.gradle
deleted file mode 100644
index ad08d33..0000000
--- a/freemarker-core-java8-test/build.gradle
+++ /dev/null
@@ -1,19 +0,0 @@
-// Override inherited default Java version:
-sourceCompatibility = "1.8"
-targetCompatibility = "1.8"
-[compileJava, compileTestJava]*.options*.bootClasspath = bootClasspathJava8
-
-dependencies {
-    compile project(":freemarker-core")
-}
-
-// We have nothing to put into the jar, as we have test classes only
-jar.enabled = false
-
-javadoc.enabled = false
-
-// Must not be deployed to a public Maven repository
-uploadArchives.enabled = false
-
-// Doesn't make sense to Maven "install" this, as the artifact won't contain test classes
-install.enabled = false

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-java8-test/src/main/resources/META-INF/DISCLAIMER
----------------------------------------------------------------------
diff --git a/freemarker-core-java8-test/src/main/resources/META-INF/DISCLAIMER b/freemarker-core-java8-test/src/main/resources/META-INF/DISCLAIMER
deleted file mode 100644
index 569ba05..0000000
--- a/freemarker-core-java8-test/src/main/resources/META-INF/DISCLAIMER
+++ /dev/null
@@ -1,8 +0,0 @@
-Apache FreeMarker is an effort undergoing incubation at The Apache Software
-Foundation (ASF), sponsored by the Apache Incubator. Incubation is required of
-all newly accepted projects until a further review indicates that the
-infrastructure, communications, and decision making process have stabilized in
-a manner consistent with other successful ASF projects. While incubation
-status is not necessarily a reflection of the completeness or stability of the
-code, it does indicate that the project has yet to be fully endorsed by the
-ASF.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-java8-test/src/main/resources/META-INF/LICENSE
----------------------------------------------------------------------
diff --git a/freemarker-core-java8-test/src/main/resources/META-INF/LICENSE b/freemarker-core-java8-test/src/main/resources/META-INF/LICENSE
deleted file mode 100644
index d645695..0000000
--- a/freemarker-core-java8-test/src/main/resources/META-INF/LICENSE
+++ /dev/null
@@ -1,202 +0,0 @@
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright [yyyy] [name of copyright owner]
-
-   Licensed 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.

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/BridgeMethodsBean.java
----------------------------------------------------------------------
diff --git a/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/BridgeMethodsBean.java b/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/BridgeMethodsBean.java
deleted file mode 100644
index 2c9d4e9..0000000
--- a/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/BridgeMethodsBean.java
+++ /dev/null
@@ -1,30 +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.model.impl;
-
-public class BridgeMethodsBean extends BridgeMethodsBeanBase<String> {
-
-    static final String M1_RETURN_VALUE = "m1ReturnValue"; 
-    
-    @Override
-    public String m1() {
-        return M1_RETURN_VALUE;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/BridgeMethodsBeanBase.java
----------------------------------------------------------------------
diff --git a/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/BridgeMethodsBeanBase.java b/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/BridgeMethodsBeanBase.java
deleted file mode 100644
index 4ecec7c..0000000
--- a/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/BridgeMethodsBeanBase.java
+++ /dev/null
@@ -1,29 +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.model.impl;
-
-public abstract class BridgeMethodsBeanBase<T> {
-
-    public abstract T m1();
-    
-    public T m2() {
-        return null;
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBean.java
----------------------------------------------------------------------
diff --git a/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBean.java b/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBean.java
deleted file mode 100644
index c7d27a6..0000000
--- a/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBean.java
+++ /dev/null
@@ -1,29 +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.model.impl;
-
-public class Java8BridgeMethodsWithDefaultMethodBean implements Java8BridgeMethodsWithDefaultMethodBeanBase<String> {
-
-    static final String M1_RETURN_VALUE = "m1ReturnValue"; 
-    
-    public String m1() {
-        return M1_RETURN_VALUE;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBean2.java
----------------------------------------------------------------------
diff --git a/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBean2.java b/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBean2.java
deleted file mode 100644
index 7dfb39a..0000000
--- a/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBean2.java
+++ /dev/null
@@ -1,23 +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.model.impl;
-
-public class Java8BridgeMethodsWithDefaultMethodBean2 implements Java8BridgeMethodsWithDefaultMethodBeanBase2 {
-    // All inherited
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBeanBase.java
----------------------------------------------------------------------
diff --git a/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBeanBase.java b/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBeanBase.java
deleted file mode 100644
index fdd8821..0000000
--- a/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBeanBase.java
+++ /dev/null
@@ -1,31 +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.model.impl;
-
-public interface Java8BridgeMethodsWithDefaultMethodBeanBase<T> {
-
-    default T m1() {
-        return null;
-    }
-    
-    default T m2() {
-        return null;
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBeanBase2.java
----------------------------------------------------------------------
diff --git a/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBeanBase2.java b/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBeanBase2.java
deleted file mode 100644
index 6f68dc7..0000000
--- a/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBeanBase2.java
+++ /dev/null
@@ -1,28 +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.model.impl;
-
-public interface Java8BridgeMethodsWithDefaultMethodBeanBase2 extends Java8BridgeMethodsWithDefaultMethodBeanBase<String> {
-
-    @Override
-    default String m1() {
-        return Java8BridgeMethodsWithDefaultMethodBean.M1_RETURN_VALUE;
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultMethodsBean.java
----------------------------------------------------------------------
diff --git a/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultMethodsBean.java b/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultMethodsBean.java
deleted file mode 100644
index eabc3d0..0000000
--- a/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultMethodsBean.java
+++ /dev/null
@@ -1,84 +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.model.impl;
-
-public class Java8DefaultMethodsBean implements Java8DefaultMethodsBeanBase {
-    
-    static final String NORMAL_PROP = "normalProp";
-    static final String NORMAL_PROP_VALUE = "normalPropValue";
-    static final String PROP_2_OVERRIDE_VALUE = "prop2OverrideValue";
-    static final int NOT_AN_INDEXED_PROP_VALUE = 1;
-    static final String ARRAY_PROP_2_VALUE_0 = "arrayProp2[0].value";
-    private static final int NOT_AN_INDEXED_PROP_3_VALUE = 3;
-    private static final String NOT_AN_INDEXED_PROP_2_VALUE = "notAnIndecedProp2Value";
-    static final String INDEXED_PROP_4 = "indexedProp4";
-    static final String INDEXED_PROP_GETTER_4 = "getIndexedProp4";
-    static final String INDEXED_PROP_4_VALUE = "indexedProp4Value[0]";
-    static final String NORMAL_ACTION = "normalAction";
-    static final String NORMAL_ACTION_RETURN_VALUE = "normalActionReturnValue";
-    static final String OVERRIDDEN_DEFAULT_METHOD_ACTION_RETURN_VALUE = "overriddenValue";
-    
-    public String getNormalProp() {
-        return NORMAL_PROP_VALUE;
-    }
-    
-    @Override
-    public String getDefaultMethodProp2() {
-        return PROP_2_OVERRIDE_VALUE;
-    }
-    
-    public String[] getDefaultMethodIndexedProp2() {
-        return new String[] { ARRAY_PROP_2_VALUE_0 };
-    }
-
-    /**
-     * There's a matching non-indexed reader method in the base class, but as this is indexed, it takes over. 
-     */
-    public String getDefaultMethodIndexedProp3(int index) {
-        return "";
-    }
-    
-    public int getDefaultMethodNotAnIndexedProp() {
-        return NOT_AN_INDEXED_PROP_VALUE;
-    }
-
-    /** Actually, this will be indexed if the default method support is off. */
-    public String getDefaultMethodNotAnIndexedProp2(int index) {
-        return NOT_AN_INDEXED_PROP_2_VALUE;
-    }
-    
-    /** Actually, this will be indexed if the default method support is off. */
-    public int getDefaultMethodNotAnIndexedProp3(int index) {
-        return NOT_AN_INDEXED_PROP_3_VALUE;
-    }
-    
-    public String getIndexedProp4(int index) {
-        return INDEXED_PROP_4_VALUE;
-    }
-    
-    public String normalAction() {
-        return NORMAL_ACTION_RETURN_VALUE;
-    }
-    
-    @Override
-    public String overriddenDefaultMethodAction() {
-        return OVERRIDDEN_DEFAULT_METHOD_ACTION_RETURN_VALUE;
-    }
-
-}


[04/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-range.ast
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-range.ast b/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-range.ast
deleted file mode 100644
index 831c7dc..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-range.ast
+++ /dev/null
@@ -1,281 +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.
- */
-#mixed_content  // o.a.f.c.ASTImplicitParent
-    #assign  // o.a.f.c.ASTDirAssignment
-        - assignment target: "x"  // String
-        - assignment operator: "="  // String
-        - assignment source: ..  // o.a.f.c.ASTExpRange
-            - left-hand operand: 0  // o.a.f.c.ASTExpNumberLiteral
-            - right-hand operand: null  // Null
-        - variable scope: "1"  // Integer
-        - namespace: null  // Null
-    #assign  // o.a.f.c.ASTDirAssignment
-        - assignment target: "x"  // String
-        - assignment operator: "="  // String
-        - assignment source: ..  // o.a.f.c.ASTExpRange
-            - left-hand operand: 0  // o.a.f.c.ASTExpNumberLiteral
-            - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
-        - variable scope: "1"  // Integer
-        - namespace: null  // Null
-    #assign  // o.a.f.c.ASTDirAssignment
-        - assignment target: "x"  // String
-        - assignment operator: "="  // String
-        - assignment source: ..<  // o.a.f.c.ASTExpRange
-            - left-hand operand: 0  // o.a.f.c.ASTExpNumberLiteral
-            - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
-        - variable scope: "1"  // Integer
-        - namespace: null  // Null
-    #assign  // o.a.f.c.ASTDirAssignment
-        - assignment target: "x"  // String
-        - assignment operator: "="  // String
-        - assignment source: ..<  // o.a.f.c.ASTExpRange
-            - left-hand operand: 0  // o.a.f.c.ASTExpNumberLiteral
-            - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
-        - variable scope: "1"  // Integer
-        - namespace: null  // Null
-    #assign  // o.a.f.c.ASTDirAssignment
-        - assignment target: "x"  // String
-        - assignment operator: "="  // String
-        - assignment source: ..  // o.a.f.c.ASTExpRange
-            - left-hand operand: +  // o.a.f.c.ASTExpAddOrConcat
-                - left-hand operand: n  // o.a.f.c.ASTExpVariable
-                - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
-            - right-hand operand: +  // o.a.f.c.ASTExpAddOrConcat
-                - left-hand operand: m  // o.a.f.c.ASTExpVariable
-                - right-hand operand: 2  // o.a.f.c.ASTExpNumberLiteral
-        - variable scope: "1"  // Integer
-        - namespace: null  // Null
-    #assign  // o.a.f.c.ASTDirAssignment
-        - assignment target: "x"  // String
-        - assignment operator: "="  // String
-        - assignment source: ..<  // o.a.f.c.ASTExpRange
-            - left-hand operand: +  // o.a.f.c.ASTExpAddOrConcat
-                - left-hand operand: n  // o.a.f.c.ASTExpVariable
-                - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
-            - right-hand operand: +  // o.a.f.c.ASTExpAddOrConcat
-                - left-hand operand: m  // o.a.f.c.ASTExpVariable
-                - right-hand operand: 2  // o.a.f.c.ASTExpNumberLiteral
-        - variable scope: "1"  // Integer
-        - namespace: null  // Null
-    #assign  // o.a.f.c.ASTDirAssignment
-        - assignment target: "x"  // String
-        - assignment operator: "="  // String
-        - assignment source: ..<  // o.a.f.c.ASTExpRange
-            - left-hand operand: +  // o.a.f.c.ASTExpAddOrConcat
-                - left-hand operand: n  // o.a.f.c.ASTExpVariable
-                - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
-            - right-hand operand: +  // o.a.f.c.ASTExpAddOrConcat
-                - left-hand operand: m  // o.a.f.c.ASTExpVariable
-                - right-hand operand: 2  // o.a.f.c.ASTExpNumberLiteral
-        - variable scope: "1"  // Integer
-        - namespace: null  // Null
-    #assign  // o.a.f.c.ASTDirAssignment
-        - assignment target: "x"  // String
-        - assignment operator: "="  // String
-        - assignment source: ..  // o.a.f.c.ASTExpRange
-            - left-hand operand: *  // o.a.f.c.ArithmeticExpression
-                - left-hand operand: n  // o.a.f.c.ASTExpVariable
-                - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
-                - AST-node subtype: "1"  // Integer
-            - right-hand operand: *  // o.a.f.c.ArithmeticExpression
-                - left-hand operand: m  // o.a.f.c.ASTExpVariable
-                - right-hand operand: 2  // o.a.f.c.ASTExpNumberLiteral
-                - AST-node subtype: "1"  // Integer
-        - variable scope: "1"  // Integer
-        - namespace: null  // Null
-    #assign  // o.a.f.c.ASTDirAssignment
-        - assignment target: "x"  // String
-        - assignment operator: "="  // String
-        - assignment source: ..  // o.a.f.c.ASTExpRange
-            - left-hand operand: ?abs  // o.a.f.c.BuiltInsForNumbers$absBI
-                - left-hand operand: n  // o.a.f.c.ASTExpVariable
-                - right-hand operand: "abs"  // String
-            - right-hand operand: ?abs  // o.a.f.c.BuiltInsForNumbers$absBI
-                - left-hand operand: m  // o.a.f.c.ASTExpVariable
-                - right-hand operand: "abs"  // String
-        - variable scope: "1"  // Integer
-        - namespace: null  // Null
-    #assign  // o.a.f.c.ASTDirAssignment
-        - assignment target: "x"  // String
-        - assignment operator: "="  // String
-        - assignment source: ..  // o.a.f.c.ASTExpRange
-            - left-hand operand: ...(...)  // o.a.f.c.ASTExpMethodCall
-                - callee: ?index_of  // o.a.f.c.BuiltInsForStringsBasic$index_ofBI
-                    - left-hand operand: n  // o.a.f.c.ASTExpVariable
-                    - right-hand operand: "index_of"  // String
-                - argument value: "x"  // o.a.f.c.ASTExpStringLiteral
-            - right-hand operand: ...(...)  // o.a.f.c.ASTExpMethodCall
-                - callee: ?index_of  // o.a.f.c.BuiltInsForStringsBasic$index_ofBI
-                    - left-hand operand: m  // o.a.f.c.ASTExpVariable
-                    - right-hand operand: "index_of"  // String
-                - argument value: "y"  // o.a.f.c.ASTExpStringLiteral
-        - variable scope: "1"  // Integer
-        - namespace: null  // Null
-    #assign  // o.a.f.c.ASTDirAssignment
-        - assignment target: "x"  // String
-        - assignment operator: "="  // String
-        - assignment source: ==  // o.a.f.c.ASTExpComparison
-            - left-hand operand: ..  // o.a.f.c.ASTExpRange
-                - left-hand operand: n  // o.a.f.c.ASTExpVariable
-                - right-hand operand: m  // o.a.f.c.ASTExpVariable
-            - right-hand operand: ..  // o.a.f.c.ASTExpRange
-                - left-hand operand: o  // o.a.f.c.ASTExpVariable
-                - right-hand operand: p  // o.a.f.c.ASTExpVariable
-        - variable scope: "1"  // Integer
-        - namespace: null  // Null
-    #assign  // o.a.f.c.ASTDirAssignment
-        - assignment target: "x"  // String
-        - assignment operator: "="  // String
-        - assignment source: ==  // o.a.f.c.ASTExpComparison
-            - left-hand operand: ..  // o.a.f.c.ASTExpRange
-                - left-hand operand: +  // o.a.f.c.ASTExpAddOrConcat
-                    - left-hand operand: +  // o.a.f.c.ASTExpAddOrConcat
-                        - left-hand operand: n  // o.a.f.c.ASTExpVariable
-                        - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
-                    - right-hand operand: 2  // o.a.f.c.ASTExpNumberLiteral
-                - right-hand operand: -  // o.a.f.c.ArithmeticExpression
-                    - left-hand operand: -  // o.a.f.c.ArithmeticExpression
-                        - left-hand operand: m  // o.a.f.c.ASTExpVariable
-                        - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
-                        - AST-node subtype: "0"  // Integer
-                    - right-hand operand: 2  // o.a.f.c.ASTExpNumberLiteral
-                    - AST-node subtype: "0"  // Integer
-            - right-hand operand: ..  // o.a.f.c.ASTExpRange
-                - left-hand operand: +  // o.a.f.c.ASTExpAddOrConcat
-                    - left-hand operand: +  // o.a.f.c.ASTExpAddOrConcat
-                        - left-hand operand: o  // o.a.f.c.ASTExpVariable
-                        - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
-                    - right-hand operand: 2  // o.a.f.c.ASTExpNumberLiteral
-                - right-hand operand: -  // o.a.f.c.ArithmeticExpression
-                    - left-hand operand: -  // o.a.f.c.ArithmeticExpression
-                        - left-hand operand: p  // o.a.f.c.ASTExpVariable
-                        - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
-                        - AST-node subtype: "0"  // Integer
-                    - right-hand operand: 2  // o.a.f.c.ASTExpNumberLiteral
-                    - AST-node subtype: "0"  // Integer
-        - variable scope: "1"  // Integer
-        - namespace: null  // Null
-    #assign  // o.a.f.c.ASTDirAssignment
-        - assignment target: "x"  // String
-        - assignment operator: "="  // String
-        - assignment source: ..  // o.a.f.c.ASTExpRange
-            - left-hand operand: +  // o.a.f.c.ASTExpAddOrConcat
-                - left-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
-                - right-hand operand: a  // o.a.f.c.ASTExpVariable
-            - right-hand operand: +...  // o.a.f.c.ASTExpNegateOrPlus
-                - right-hand operand: 2  // o.a.f.c.ASTExpNumberLiteral
-                - AST-node subtype: "1"  // Integer
-        - variable scope: "1"  // Integer
-        - namespace: null  // Null
-    #assign  // o.a.f.c.ASTDirAssignment
-        - assignment target: "x"  // String
-        - assignment operator: "="  // String
-        - assignment source: ..  // o.a.f.c.ASTExpRange
-            - left-hand operand: -  // o.a.f.c.ArithmeticExpression
-                - left-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
-                - right-hand operand: a  // o.a.f.c.ASTExpVariable
-                - AST-node subtype: "0"  // Integer
-            - right-hand operand: -...  // o.a.f.c.ASTExpNegateOrPlus
-                - right-hand operand: 2  // o.a.f.c.ASTExpNumberLiteral
-                - AST-node subtype: "0"  // Integer
-        - variable scope: "1"  // Integer
-        - namespace: null  // Null
-    #assign  // o.a.f.c.ASTDirAssignment
-        - assignment target: "x"  // String
-        - assignment operator: "="  // String
-        - assignment source: ..*  // o.a.f.c.ASTExpRange
-            - left-hand operand: *  // o.a.f.c.ArithmeticExpression
-                - left-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
-                - right-hand operand: a  // o.a.f.c.ASTExpVariable
-                - AST-node subtype: "1"  // Integer
-            - right-hand operand: 2  // o.a.f.c.ASTExpNumberLiteral
-        - variable scope: "1"  // Integer
-        - namespace: null  // Null
-    #assign  // o.a.f.c.ASTDirAssignment
-        - assignment target: "x"  // String
-        - assignment operator: "="  // String
-        - assignment source: ||  // o.a.f.c.ASTExpOr
-            - left-hand operand: &&  // o.a.f.c.ASTExpAnd
-                - left-hand operand: a  // o.a.f.c.ASTExpVariable
-                - right-hand operand: ..  // o.a.f.c.ASTExpRange
-                    - left-hand operand: b  // o.a.f.c.ASTExpVariable
-                    - right-hand operand: c  // o.a.f.c.ASTExpVariable
-            - right-hand operand: d  // o.a.f.c.ASTExpVariable
-        - variable scope: "1"  // Integer
-        - namespace: null  // Null
-    #assign  // o.a.f.c.ASTDirAssignment
-        - assignment target: "x"  // String
-        - assignment operator: "="  // String
-        - assignment source: ||  // o.a.f.c.ASTExpOr
-            - left-hand operand: &&  // o.a.f.c.ASTExpAnd
-                - left-hand operand: ..  // o.a.f.c.ASTExpRange
-                    - left-hand operand: a  // o.a.f.c.ASTExpVariable
-                    - right-hand operand: null  // Null
-                - right-hand operand: ..  // o.a.f.c.ASTExpRange
-                    - left-hand operand: b  // o.a.f.c.ASTExpVariable
-                    - right-hand operand: null  // Null
-            - right-hand operand: d  // o.a.f.c.ASTExpVariable
-        - variable scope: "1"  // Integer
-        - namespace: null  // Null
-    #text  // o.a.f.c.ASTStaticText
-        - content: "\n"  // String
-    ${...}  // o.a.f.c.ASTDollarInterpolation
-        - content: ...(...)  // o.a.f.c.ASTExpMethodCall
-            - callee: f  // o.a.f.c.ASTExpVariable
-            - argument value: ..  // o.a.f.c.ASTExpRange
-                - left-hand operand: m  // o.a.f.c.ASTExpVariable
-                - right-hand operand: null  // Null
-            - argument value: ..  // o.a.f.c.ASTExpRange
-                - left-hand operand: -  // o.a.f.c.ArithmeticExpression
-                    - left-hand operand: m  // o.a.f.c.ASTExpVariable
-                    - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
-                    - AST-node subtype: "0"  // Integer
-                - right-hand operand: null  // Null
-            - argument value: ..  // o.a.f.c.ASTExpRange
-                - left-hand operand: +  // o.a.f.c.ASTExpAddOrConcat
-                    - left-hand operand: m  // o.a.f.c.ASTExpVariable
-                    - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
-                - right-hand operand: -  // o.a.f.c.ArithmeticExpression
-                    - left-hand operand: n  // o.a.f.c.ASTExpVariable
-                    - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
-                    - AST-node subtype: "0"  // Integer
-    #text  // o.a.f.c.ASTStaticText
-        - content: "\n\n"  // String
-    @  // o.a.f.c.ASTDirUserDefined
-        - callee: m  // o.a.f.c.ASTExpVariable
-        - argument value: ..  // o.a.f.c.ASTExpRange
-            - left-hand operand: *  // o.a.f.c.ArithmeticExpression
-                - left-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
-                - right-hand operand: m  // o.a.f.c.ASTExpVariable
-                - AST-node subtype: "1"  // Integer
-            - right-hand operand: -  // o.a.f.c.ArithmeticExpression
-                - left-hand operand: m  // o.a.f.c.ASTExpVariable
-                - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
-                - AST-node subtype: "0"  // Integer
-        - argument value: ..  // o.a.f.c.ASTExpRange
-            - left-hand operand: +  // o.a.f.c.ASTExpAddOrConcat
-                - left-hand operand: m  // o.a.f.c.ASTExpVariable
-                - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
-            - right-hand operand: -  // o.a.f.c.ArithmeticExpression
-                - left-hand operand: n  // o.a.f.c.ASTExpVariable
-                - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
-                - AST-node subtype: "0"  // Integer
-        - argument value: ..  // o.a.f.c.ASTExpRange
-            - left-hand operand: m  // o.a.f.c.ASTExpVariable
-            - right-hand operand: null  // Null

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-range.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-range.ftl b/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-range.ftl
deleted file mode 100644
index cb55c8a..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-range.ftl
+++ /dev/null
@@ -1,47 +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.
--->
-<#assign x = 0..>
-
-<#assign x = 0..1>
-<#assign x = 0..<1>
-<#assign x = 0..!1>
-
-<#assign x = n + 1 .. m + 2>
-<#assign x = n + 1 ..< m + 2>
-<#assign x = n + 1 ..! m + 2>
-
-<#assign x = n * 1 .. m * 2>
-
-<#assign x = n?abs .. m?abs>
-
-<#assign x = n?index_of('x') .. m?index_of('y')>
-
-<#assign x = n..m == o..p>
-
-<#assign x = n+1+2..m-1-2 == o+1+2..p-1-2>
-
-<#assign x = 1+a..+2>
-<#assign x = 1-a..-2>
-<#assign x = 1*a..*2> 
-<#assign x = a && b..c || d> 
-<#assign x = a.. && b.. || d> 
-
-${f(m.., m-1.., m+1..n-1)}
-
-<@m 1 * m .. m - 1 m + 1 .. n - 1 m .. />

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-strlitinterpolation.ast
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-strlitinterpolation.ast b/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-strlitinterpolation.ast
deleted file mode 100644
index 321721e..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-strlitinterpolation.ast
+++ /dev/null
@@ -1,82 +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.
- */
-#mixed_content  // o.a.f.c.ASTImplicitParent
-    #text  // o.a.f.c.ASTStaticText
-        - content: "1. "  // String
-    @  // o.a.f.c.ASTDirUserDefined
-        - callee: m  // o.a.f.c.ASTExpVariable
-        - argument name: "x"  // String
-        - argument value: dynamic "..."  // o.a.f.c.ASTExpStringLiteral
-            - value part: ${...}  // o.a.f.c.ASTDollarInterpolation
-                - content: e1  // o.a.f.c.ASTExpVariable
-        - argument name: "y"  // String
-        - argument value: "$\\{e2}"  // o.a.f.c.ASTExpStringLiteral
-    #text  // o.a.f.c.ASTStaticText
-        - content: "\n2. "  // String
-    ${...}  // o.a.f.c.ASTDollarInterpolation
-        - content: dynamic "..."  // o.a.f.c.ASTExpStringLiteral
-            - value part: "a"  // String
-            - value part: ${...}  // o.a.f.c.ASTDollarInterpolation
-                - content: x  // o.a.f.c.ASTExpVariable
-            - value part: "b"  // String
-            - value part: ${...}  // o.a.f.c.ASTDollarInterpolation
-                - content: x  // o.a.f.c.ASTExpVariable
-            - value part: "c"  // String
-    #text  // o.a.f.c.ASTStaticText
-        - content: "\n3. "  // String
-    ${...}  // o.a.f.c.ASTDollarInterpolation
-        - content: dynamic "..."  // o.a.f.c.ASTExpStringLiteral
-            - value part: ${...}  // o.a.f.c.ASTDollarInterpolation
-                - content: x  // o.a.f.c.ASTExpVariable
-            - value part: "b"  // String
-    #text  // o.a.f.c.ASTStaticText
-        - content: "\n4. "  // String
-    ${...}  // o.a.f.c.ASTDollarInterpolation
-        - content: dynamic "..."  // o.a.f.c.ASTExpStringLiteral
-            - value part: "a"  // String
-            - value part: ${...}  // o.a.f.c.ASTDollarInterpolation
-                - content: x  // o.a.f.c.ASTExpVariable
-    #text  // o.a.f.c.ASTStaticText
-        - content: "\n5. "  // String
-    ${...}  // o.a.f.c.ASTDollarInterpolation
-        - content: dynamic "..."  // o.a.f.c.ASTExpStringLiteral
-            - value part: ${...}  // o.a.f.c.ASTDollarInterpolation
-                - content: x  // o.a.f.c.ASTExpVariable
-            - value part: #{...}  // o.a.f.c.ASTHashInterpolation
-                - content: y  // o.a.f.c.ASTExpVariable
-                - minimum decimals: "0"  // Integer
-                - maximum decimals: "0"  // Integer
-    #text  // o.a.f.c.ASTStaticText
-        - content: "\n6. "  // String
-    ${...}  // o.a.f.c.ASTDollarInterpolation
-        - content: dynamic "..."  // o.a.f.c.ASTExpStringLiteral
-            - value part: "a b "  // String
-            - value part: ${...}  // o.a.f.c.ASTDollarInterpolation
-                - content: x  // o.a.f.c.ASTExpVariable
-            - value part: " c d"  // String
-    #text  // o.a.f.c.ASTStaticText
-        - content: "\n7. "  // String
-    ${...}  // o.a.f.c.ASTDollarInterpolation
-        - content: dynamic "..."  // o.a.f.c.ASTExpStringLiteral
-            - value part: ${...}  // o.a.f.c.ASTDollarInterpolation
-                - content: x  // o.a.f.c.ASTExpVariable
-            - value part: " a b "  // String
-            - value part: ${...}  // o.a.f.c.ASTDollarInterpolation
-                - content: y  // o.a.f.c.ASTExpVariable
-            - value part: " c$d"  // String

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-strlitinterpolation.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-strlitinterpolation.ftl b/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-strlitinterpolation.ftl
deleted file mode 100644
index cd86f2f..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-strlitinterpolation.ftl
+++ /dev/null
@@ -1,25 +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.
--->
-1. <@m x='${e1}' y='$\\{e2}' />
-2. ${'a${x}b${x}c'}
-3. ${'${x}b'}
-4. ${'a${x}'}
-5. ${'${x}#{y}'}
-6. ${'a b ${x} c d'}
-7. ${'${x} a b ${y} c$d'}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-whitespacestripping.ast
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-whitespacestripping.ast b/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-whitespacestripping.ast
deleted file mode 100644
index 868fc69..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-whitespacestripping.ast
+++ /dev/null
@@ -1,70 +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.
- */
-#mixed_content  // o.a.f.c.ASTImplicitParent
-    #assign  // o.a.f.c.ASTDirAssignment
-        - assignment target: "xs"  // String
-        - assignment operator: "="  // String
-        - assignment source: [...]  // o.a.f.c.ASTExpListLiteral
-        - variable scope: "1"  // Integer
-        - namespace: null  // Null
-    #text  // o.a.f.c.ASTStaticText
-        - content: "\n"  // String
-    #list  // o.a.f.c.ASTDirList
-        - list source: x  // o.a.f.c.ASTExpVariable
-        - target loop variable: "xs"  // String
-        #text  // o.a.f.c.ASTStaticText
-            - content: "    "  // String
-        ${...}  // o.a.f.c.ASTDollarInterpolation
-            - content: x  // o.a.f.c.ASTExpVariable
-        #text  // o.a.f.c.ASTStaticText
-            - content: "\n"  // String
-    #text  // o.a.f.c.ASTStaticText
-        - content: "\n"  // String
-    #assign  // o.a.f.c.ASTDirAssignment
-        - assignment target: "a"  // String
-        - assignment operator: "="  // String
-        - assignment source: 1  // o.a.f.c.ASTExpNumberLiteral
-        - variable scope: "1"  // Integer
-        - namespace: null  // Null
-    #assign  // o.a.f.c.ASTDirAssignment
-        - assignment target: "b"  // String
-        - assignment operator: "="  // String
-        - assignment source: 1  // o.a.f.c.ASTExpNumberLiteral
-        - variable scope: "1"  // Integer
-        - namespace: null  // Null
-    #text  // o.a.f.c.ASTStaticText
-        - content: "\n"  // String
-    @  // o.a.f.c.ASTDirUserDefined
-        - callee: b  // o.a.f.c.ASTExpVariable
-        #text  // o.a.f.c.ASTStaticText
-            - content: "    x\n"  // String
-    #text  // o.a.f.c.ASTStaticText
-        - content: "\n"  // String
-    @  // o.a.f.c.ASTDirUserDefined
-        - callee: c  // o.a.f.c.ASTExpVariable
-    #text  // o.a.f.c.ASTStaticText
-        - content: "\n"  // String
-    @  // o.a.f.c.ASTDirUserDefined
-        - callee: d  // o.a.f.c.ASTExpVariable
-    #text  // o.a.f.c.ASTStaticText
-        - content: "\na\n"  // String
-    #--...--  // o.a.f.c.ASTComment
-        - content: " comment "  // String
-    #text  // o.a.f.c.ASTStaticText
-        - content: "b"  // String

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-whitespacestripping.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-whitespacestripping.ftl b/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-whitespacestripping.ftl
deleted file mode 100644
index cba7289..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/core/ast-whitespacestripping.ftl
+++ /dev/null
@@ -1,40 +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.
--->
-
-
-<#assign xs = []>
-
-<#list x as xs>
-    ${x}
-</#list>
-
-<#assign a = 1>
-<#assign b = 1>
-
-<@b>
-    x
-</...@b>
-
-<@c />
-
-<@d...@d>
-
-a
-<#-- comment -->
-b
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-assignments.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-assignments.ftl b/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-assignments.ftl
deleted file mode 100644
index 24c8984..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-assignments.ftl
+++ /dev/null
@@ -1,35 +0,0 @@
-<#ftl stripWhitespace=false>
-<#--
-  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.
--->
-<#assign x = 1>
-<#assign x = 1, y = 2>
-<#assign x = 1 in ns>
-<#assign x = 1, y = 2 in ns>
-<#assign a += b + c>
-<#assign a += 1, b -= 2, c *= 3, d /= 4, e %= 5, f++, g-->
-<#global x = 1>
-<#global x = 1, y = 2>
-<#global x++>
-<#macro m>
-  <#local x = 1>
-  <#local x = 1, y = 2>
-</#macro>
-<#assign x>
-  foo ${bar}
-</#assign>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-assignments.ftl.out
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-assignments.ftl.out b/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-assignments.ftl.out
deleted file mode 100644
index 3dd2307..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-assignments.ftl.out
+++ /dev/null
@@ -1,34 +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.
- */
-<#assign x = 1>
-<#assign x = 1, y = 2>
-<#assign x = 1 in ns>
-<#assign x = 1, y = 2 in ns>
-<#assign a += b + c>
-<#assign a += 1, b -= 2, c *= 3, d /= 4, e %= 5, f++, g-->
-<#global x = 1>
-<#global x = 1, y = 2>
-<#global x++>
-<#macro m>
-  <#local x = 1>
-  <#local x = 1, y = 2>
-</#macro>
-<#assign x>
-  foo ${bar}
-</#assign>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-builtins.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-builtins.ftl b/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-builtins.ftl
deleted file mode 100644
index 74aee52..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-builtins.ftl
+++ /dev/null
@@ -1,23 +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.
--->
-${x?trim}
-${x?left_pad(5)}
-${x?left_pad(5, '-')}
-${x?then('y', 'n')}
-${x?switch(1, 11, 2, 22, 33)}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-builtins.ftl.out
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-builtins.ftl.out b/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-builtins.ftl.out
deleted file mode 100644
index 3c62974..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-builtins.ftl.out
+++ /dev/null
@@ -1,23 +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.
- */
-${x?trim}
-${x?left_pad(5)}
-${x?left_pad(5, "-")}
-${x?then("y", "n")}
-${x?switch(1, 11, 2, 22, 33)}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-identifier-escaping.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-identifier-escaping.ftl b/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-identifier-escaping.ftl
deleted file mode 100644
index 75d52f1..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-identifier-escaping.ftl
+++ /dev/null
@@ -1,76 +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.
--->
-<#macro m\-a data\-color>
-    <#local \.namespace = 123>
-    <a-b>${data\-color}<#nested \.namespace></a-b><#t>
-</#macro>
-<#macro "m-b2"></#macro>
-<#macro "m/b2"></#macro>
-
-<@m\-a data\-color="red"; loop\-var, loopVar2>${loop\-var}</@>
-
-<#function f\-a p\-a>
-    <#return p\-a + " works">
-</#function>
-${f\-a("f-a")}
-
-<#assign \-\-\-\.\: = 'dash-dash-dash etc.'>
-${\-\-\-\.\:}
-${.vars['---.:']}
-<#assign hash = { '--moz-prop': 'propVal' }>
-${hash.\-\-moz\-prop}
-${hash['--moz-prop']}
-
-<#assign ls\:a = 1..3>
-List: <#list ls\:a as \:i>${\:i}</#list>
-
-<#assign sw\-a=1>
-Switch: <#switch sw\-a>
-    <#case 1>OK<#break>
-    <#default>Fails
-</#switch>
-
-<#escape \-x as \-x?upper_case>${'escaped'}</#escape>
-
-<#if false && sw\-a == 1>
-    <#visit x\-y2 using x\-y1>
-    <#recurse x\-y2 using x\-y1>
-    <#import i\-a as i\-b>
-    <#include i\-c>
-</#if>
-
-<#assign @as@_a = 'as1'>
-${@as@_a}
-<#assign 'as-c' = 'as2'>
-${.vars['as-c']}
-<#assign "as/b" = 'as3'>
-${.vars["as/b"]}
-<#assign "as'c" = 'as4'>
-${.vars["as'c"]}
-<#assign 'as"d' = 'as5'>
-${.vars['as"d']}
-
-<#global g\-a=1 g\-b=2 "g-c"=3>
-
-<#macro dumpNS>
-    <#list .namespace?keys?sort as k>
-        ${k} = <#local v = .namespace[k]><#if v?is_string>${v}<#else>...</#if><#lt>
-    </#list>
-</#macro>
-<@dumpNS />

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-identifier-escaping.ftl.out
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-identifier-escaping.ftl.out b/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-identifier-escaping.ftl.out
deleted file mode 100644
index 17e2b4e..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-identifier-escaping.ftl.out
+++ /dev/null
@@ -1,44 +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.
- */
-<#macro m\-a data\-color><#local \.namespace = 123><a-b>${data\-color}<#nested \.namespace></a-b></#macro><#macro m\-b2></#macro><#macro "m/b2"></#macro>
-<@m\-a data\-color="red"; loop\-var, loopVar2>${loop\-var}</@m\-a>
-
-<#function f\-a(p\-a)><#return p\-a + " works"/></#function>${f\-a("f-a")}
-
-<#assign \-\-\-\.\: = "dash-dash-dash etc.">${\-\-\-\.\:}
-${.vars["---.:"]}
-<#assign hash = {"--moz-prop": "propVal"}>${hash.\-\-moz\-prop}
-${hash["--moz-prop"]}
-
-<#assign ls\:a = 1..3>List: <#list ls\:a as \:i>${\:i}</#list>
-
-<#assign sw\-a = 1>Switch: <#switch sw\-a><#case 1>OK<#break/>
-    <#default>Fails
-</#switch>
-<#escape \-x as \-x?upper_case>${"escaped"}</#escape>
-
-<#if false && sw\-a == 1><#visit x\-y2 using x\-y1/><#recurse x\-y2 using x\-y1/><#import i\-a as i\-b/><#include i\-c/></#if>
-<#assign @as@_a = "as1">${@as@_a}
-<#assign as\-c = "as2">${.vars["as-c"]}
-<#assign "as/b" = "as3">${.vars["as/b"]}
-<#assign "as'c" = "as4">${.vars["as'c"]}
-<#assign 'as"d' = "as5">${.vars['as"d']}
-
-<#global g\-a = 1, g\-b = 2, g\-c = 3><#macro dumpNS><#list .namespace?keys?sort as k>${k} = <#local v = .namespace[k]><#if v?is_string>${v}<#else>...</#if>
-</#list></#macro><@dumpNS/>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-macros.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-macros.ftl b/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-macros.ftl
deleted file mode 100644
index 9288e63..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-macros.ftl
+++ /dev/null
@@ -1,29 +0,0 @@
-<#ftl stripWhitespace=false>
-<#--
-  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.
--->
-<#macro m></#macro>
-<#macro m a></#macro>
-<#macro m a b></#macro>
-<#macro m a b c...></#macro>
-<#macro m a...></#macro>
-<#function f()></#function>
-<#function f(a)></#function>
-<#function f(a, b)></#function>
-<#function f(a, b, c...)></#function>
-<#function f(a...)></#function>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-macros.ftl.out
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-macros.ftl.out b/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-macros.ftl.out
deleted file mode 100644
index ad49cae..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-macros.ftl.out
+++ /dev/null
@@ -1,28 +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.
- */
-<#macro m></#macro>
-<#macro m a></#macro>
-<#macro m a b></#macro>
-<#macro m a b c...></#macro>
-<#macro m a...></#macro>
-<#function f()></#function>
-<#function f(a)></#function>
-<#function f(a, b)></#function>
-<#function f(a, b, c...)></#function>
-<#function f(a...)></#function>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-strlitinterpolation.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-strlitinterpolation.ftl b/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-strlitinterpolation.ftl
deleted file mode 100644
index 85189a4..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-strlitinterpolation.ftl
+++ /dev/null
@@ -1,19 +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.
--->
-<@m x='${e1 + "a\'b${x}"}#{x; M2}' y='$\{e2}' />
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-strlitinterpolation.ftl.out
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-strlitinterpolation.ftl.out b/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-strlitinterpolation.ftl.out
deleted file mode 100644
index 754c225..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/core/cano-strlitinterpolation.ftl.out
+++ /dev/null
@@ -1,19 +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.
- */
-<@m x="${e1 + \"a'b$\{x}\"}#{x ; m0M2}" y="$\{e2}"/>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/core/encodingOverride-ISO-8859-1.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/core/encodingOverride-ISO-8859-1.ftl b/freemarker-core/src/test/resources/org/apache/freemarker/core/encodingOverride-ISO-8859-1.ftl
deleted file mode 100644
index e0382c7..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/core/encodingOverride-ISO-8859-1.ftl
+++ /dev/null
@@ -1,20 +0,0 @@
-<#ftl encoding="ISO-8859-1">
-<#--
-  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.
--->
-B�ka
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/core/encodingOverride-UTF-8.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/core/encodingOverride-UTF-8.ftl b/freemarker-core/src/test/resources/org/apache/freemarker/core/encodingOverride-UTF-8.ftl
deleted file mode 100644
index 5948e30..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/core/encodingOverride-UTF-8.ftl
+++ /dev/null
@@ -1,20 +0,0 @@
-<#ftl encoding="UTF-8">
-<#--
-  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.
--->
-Béka
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/core/templateresolver/test.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/core/templateresolver/test.ftl b/freemarker-core/src/test/resources/org/apache/freemarker/core/templateresolver/test.ftl
deleted file mode 100644
index fb3f45d..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/core/templateresolver/test.ftl
+++ /dev/null
@@ -1,19 +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.
--->
-dummy
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/core/toCache1.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/core/toCache1.ftl b/freemarker-core/src/test/resources/org/apache/freemarker/core/toCache1.ftl
deleted file mode 100644
index 462f1ae..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/core/toCache1.ftl
+++ /dev/null
@@ -1,19 +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.
--->
-Template 1
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/core/toCache2.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/core/toCache2.ftl b/freemarker-core/src/test/resources/org/apache/freemarker/core/toCache2.ftl
deleted file mode 100644
index f59424c..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/core/toCache2.ftl
+++ /dev/null
@@ -1,19 +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.
--->
-Template 2
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/dom/DOMSiblingTest.xml
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/dom/DOMSiblingTest.xml b/freemarker-core/src/test/resources/org/apache/freemarker/dom/DOMSiblingTest.xml
deleted file mode 100644
index d1fe3dc..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/dom/DOMSiblingTest.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.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.
--->
-<person>
-    <gender>male</gender>
-    <name>pradeep</name>
-    <dob>12th August</dob><address>Chennai, India</address>
-    <!--This is a comment Node -->
-    <?xml-stylesheet type="text/css" href="style.css"?>
-    <profession>Software Engineer</profession>
-    <![CDATA[    ]]>
-    <hobby>gardening</hobby>
-    <![CDATA[this is a valid cdata]]>
-    <phone>12345678</phone>
-</person>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-capture.ftlh
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-capture.ftlh b/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-capture.ftlh
deleted file mode 100644
index 24bd0ee..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-capture.ftlh
+++ /dev/null
@@ -1,21 +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.
--->
-<#assign captured><b>Test</b></#assign>
-Just a string: ${"<b>Test</b>"}
-Captured output: ${captured}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-capture.ftlh.out
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-capture.ftlh.out b/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-capture.ftlh.out
deleted file mode 100644
index cf0da7e..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-capture.ftlh.out
+++ /dev/null
@@ -1,20 +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.
- */
-Just a string: &lt;b&gt;Test&lt;/b&gt;
-Captured output: <b>Test</b>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-convert.ftlh
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-convert.ftlh b/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-convert.ftlh
deleted file mode 100644
index e0d3348..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-convert.ftlh
+++ /dev/null
@@ -1,27 +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.
--->
-<#assign mo1 = "Foo's bar {}"?esc>
-HTLM: ${mo1}
-XML:  <#outputformat 'XML'>${mo1}</#outputformat>
-RTF:  <#outputformat 'RTF'>${mo1}</#outputformat>
-
-<#assign mo2><p>Test</#assign>
-HTML: ${mo2}
-XML:  <#attempt><#outputformat 'XML'>${mo2}</#outputformat><#recover>Failed</#attempt>
-RTF:  <#attempt><#outputformat 'RTF'>${mo2}</#outputformat><#recover>Failed</#attempt>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-convert.ftlh.out
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-convert.ftlh.out b/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-convert.ftlh.out
deleted file mode 100644
index 65be2a0..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-convert.ftlh.out
+++ /dev/null
@@ -1,25 +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.
- */
-HTLM: Foo&#39;s bar {}
-XML:  Foo&apos;s bar {}
-RTF:  Foo's bar \{\}
-
-HTML: <p>Test
-XML:  Failed
-RTF:  Failed

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-convert2.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-convert2.ftl b/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-convert2.ftl
deleted file mode 100644
index 80ae292..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-convert2.ftl
+++ /dev/null
@@ -1,25 +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.
--->
-<#outputformat "HTML"><#assign htmlMO><p>Test</#assign></#outputformat>
-<#outputformat "XML"><#assign xmlMO><p>Test</p></#assign></#outputformat>
-<#outputformat "RTF"><#assign rtfMO>\par Test</#assign></#outputformat>
-<#-- We assume that we have "undefined" output format here. -->
-HTML: ${htmlMO}
-XML:  ${xmlMO}
-RTF:  ${rtfMO}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-convert2.ftl.out
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-convert2.ftl.out b/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-convert2.ftl.out
deleted file mode 100644
index cd84bd2..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-convert2.ftl.out
+++ /dev/null
@@ -1,21 +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.
- */
-HTML: <p>Test
-XML:  <p>Test</p>
-RTF:  \par Test
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-infoBox.ftlh
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-infoBox.ftlh b/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-infoBox.ftlh
deleted file mode 100644
index 9b8dbd9..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-infoBox.ftlh
+++ /dev/null
@@ -1,26 +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.
--->
-<@infoBox "Foo & bar" />
-<@infoBox "Foo <b>bar</b>"?no_esc />
-
-<#macro infoBox message>
-  <div class="infoBox">
-    ${message}
-  </div>
-</#macro>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-infoBox.ftlh.out
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-infoBox.ftlh.out b/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-infoBox.ftlh.out
deleted file mode 100644
index 9471ab7..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-infoBox.ftlh.out
+++ /dev/null
@@ -1,25 +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.
- */
-  <div class="infoBox">
-    Foo &amp; bar
-  </div>
-  <div class="infoBox">
-    Foo <b>bar</b>
-  </div>
-

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-markup.ftlh
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-markup.ftlh b/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-markup.ftlh
deleted file mode 100644
index f9deeae..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-markup.ftlh
+++ /dev/null
@@ -1,28 +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.
--->
-<#assign markupOutput1="<b>Test</b>"?no_esc>
-<#assign markupOutput2="Foo & bar"?esc>
-
-As expected:
-${markupOutput1}
-${markupOutput2}
-
-Double escaping:
-${markupOutput1?markup_string}
-${markupOutput2?markup_string}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-markup.ftlh.out
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-markup.ftlh.out b/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-markup.ftlh.out
deleted file mode 100644
index 0420cca..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-markup.ftlh.out
+++ /dev/null
@@ -1,26 +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.
- */
-
-As expected:
-<b>Test</b>
-Foo &amp; bar
-
-Double escaping:
-&lt;b&gt;Test&lt;/b&gt;
-Foo &amp;amp; bar
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringConcat.ftlh
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringConcat.ftlh b/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringConcat.ftlh
deleted file mode 100644
index f7884bb..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringConcat.ftlh
+++ /dev/null
@@ -1,19 +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.
--->
-${"<h1>"?no_esc + "Foo & bar" + "</h1>"?no_esc}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringConcat.ftlh.out
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringConcat.ftlh.out b/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringConcat.ftlh.out
deleted file mode 100644
index d016072..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringConcat.ftlh.out
+++ /dev/null
@@ -1,19 +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.
- */
-<h1>Foo &amp; bar</h1>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringLiteral.ftlh
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringLiteral.ftlh b/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringLiteral.ftlh
deleted file mode 100644
index 4904f60..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringLiteral.ftlh
+++ /dev/null
@@ -1,21 +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.
--->
-<#assign s = "Foo & bar">
-${s}
-${"${s} & baz"}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringLiteral.ftlh.out
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringLiteral.ftlh.out b/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringLiteral.ftlh.out
deleted file mode 100644
index c6bd10d..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringLiteral.ftlh.out
+++ /dev/null
@@ -1,20 +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.
- */
-Foo &amp; bar
-Foo &amp; bar &amp; baz
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringLiteral2.ftlh
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringLiteral2.ftlh b/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringLiteral2.ftlh
deleted file mode 100644
index 52db70b..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringLiteral2.ftlh
+++ /dev/null
@@ -1,25 +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.
--->
-<#-- Markup output value created by escaping plain text: -->
-<#assign mo1 = "Foo & bar"?esc>
-<#-- Markup output value created outherwise: -->
-<#assign mo2 = "<p>Foo"?no_esc>
-
-${"${mo1} baz"}
-${"${mo2} baz"}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringLiteral2.ftlh.out
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringLiteral2.ftlh.out b/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringLiteral2.ftlh.out
deleted file mode 100644
index f47e521..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/AutoEscapingExample-stringLiteral2.ftlh.out
+++ /dev/null
@@ -1,21 +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.
- */
-
-Foo &amp; bar baz
-<p>Foo baz
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/ConfigureOutputFormatExamples1.properties
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/ConfigureOutputFormatExamples1.properties b/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/ConfigureOutputFormatExamples1.properties
deleted file mode 100644
index 0df9e33..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/ConfigureOutputFormatExamples1.properties
+++ /dev/null
@@ -1,21 +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.
-
-templateConfigurations = \
-    ConditionalTemplateConfigurationFactory( \
-        PathGlobMatcher("mail/**"), \
-        TemplateConfiguration(outputFormat = HTMLOutputFormat()))
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/ConfigureOutputFormatExamples2.properties
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/ConfigureOutputFormatExamples2.properties b/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/ConfigureOutputFormatExamples2.properties
deleted file mode 100644
index 5d2a738..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/ConfigureOutputFormatExamples2.properties
+++ /dev/null
@@ -1,31 +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.
-
-templateConfigurations = \
-    FirstMatchTemplateConfigurationFactory( \
-        ConditionalTemplateConfigurationFactory( \
-            FileExtensionMatcher("xml"), \
-            TemplateConfiguration(outputFormat = XMLOutputFormat())), \
-        ConditionalTemplateConfigurationFactory( \
-            OrMatcher( \
-                FileExtensionMatcher("html"), \
-                FileExtensionMatcher("htm")), \
-            TemplateConfiguration(outputFormat = HTMLOutputFormat())), \
-        ConditionalTemplateConfigurationFactory( \
-            FileExtensionMatcher("rtf"), \
-            TemplateConfiguration(outputFormat = RTFOutputFormat())), \
-        allowNoMatch = true)

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-alias1.ftlh
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-alias1.ftlh b/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-alias1.ftlh
deleted file mode 100644
index fe9690c..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-alias1.ftlh
+++ /dev/null
@@ -1,22 +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.
--->
-${p?string.@price}
-${w?string.@weight}
-${fd?string.@fileDate}
-${let?datetime?string.@logEventTime}



[25/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/range.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/range.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/range.ftl
new file mode 100644
index 0000000..d2f5450
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/range.ftl
@@ -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.
+-->
+<#include 'range-common.ftl'>
+
+<@assertEquals actual=(4..)?size expected=2147483647 />
+<@assertEquals actual=limitedJoin(4.., 3) expected="4, 5, 6, ..." />
+
+<@assertEquals actual=(4..)[0] expected=4 />
+<@assertEquals actual=(4..)[1] expected=5 />
+<@assertEquals actual=(4..)[1000000] expected=1000004 />
+<@assertFails message="out of bounds">
+	<@assertEquals actual=(4..)[-1] expected=5 />
+</@>
+
+<#assign r = 2147483646..>
+<@assertEquals actual=r?size expected=2147483647 />
+<@assertEquals actual=limitedJoin(r, 3) expected="2147483646, 2147483647, 2147483648, ..." />
+<@assertEquals actual=r[100] expected=2147483746 />
+
+<#assign r = -2..>
+<@assertEquals actual=limitedJoin(r, 5) expected="-2, -1, 0, 1, 2, ..." />
+<@assertEquals actual=r[0] expected=-2 />
+<@assertEquals actual=r[1] expected=-1 />
+
+<#function limitedJoin range limit>
+	<#assign joined="">
+	<#list range as i>
+		<#assign joined = joined + i?c>
+		<#if i_has_next><#assign joined = joined + ', '></#if>
+		<#local limit = limit - 1>
+		<#if limit == 0><#assign joined = joined + "..."><#break></#if>
+	</#list>
+	<#return joined>
+</#function>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/recover.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/recover.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/recover.ftl
new file mode 100644
index 0000000..f7dc437
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/recover.ftl
@@ -0,0 +1,47 @@
+<#--
+  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.
+-->
+<#attempt>
+ <#assign sequence = ["Hello, World"]>
+ ${sequence[0]}
+<#recover>
+  We should never get here.
+</#recover>
+<#attempt>
+ Let's try to output an undefined variable: ${undefinedVariable}
+<#recover>
+ Well, that did not work.<@assert test=.error?contains('undefinedVariable') />
+ Now we nest another attempt/recover here:
+ <#attempt>
+   ${sequence[1]}
+ <#recover>
+   Oops...<@assert test=.error?contains('sequence[1]') />
+   Remember, freeMarker sequences are zero-based! ${sequence[0]}
+ </#recover>
+ Now we check the current error message.<@assert test=.error?contains('undefinedVariable') />
+</#recover>
+<#attempt>
+  <#include "nonexistent_template">
+<#recover>
+  The template is not currently available
+</#recover>
+<#attempt>
+  <#include "undefined.ftl">
+<#recover>
+  The included template had a problem.<@assert test=.error?contains('undefined_variable') />
+</#attempt>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/root.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/root.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/root.ftl
new file mode 100644
index 0000000..e1bc7f3
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/root.ftl
@@ -0,0 +1,47 @@
+<#--
+  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.
+-->
+<html>
+<head>
+<title>FreeMarker: Root Lookup Test</title>
+</head>
+<body>
+
+<p>A simple test follows:</p>
+
+<p>${message}</p>
+
+<p>Access the same variable via the root variable (dot syntax):</p>
+
+<p>${.data_model.message}</p>
+
+<p>Access the same variable via the root variable (bracket syntax):</p>
+
+<p>${.data_model["message"]}</p>
+
+<p>Ensure that root lookups are unaffected by local variables:</p>
+
+<#macro test message>
+  ${.data_model.message}
+  ${message}
+</#macro>
+
+<@test message + " Part Deux" />
+
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/sequence-builtins.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/sequence-builtins.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/sequence-builtins.ftl
new file mode 100644
index 0000000..e21bc2d
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/sequence-builtins.ftl
@@ -0,0 +1,360 @@
+<#--
+  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.
+-->
+<@noOutput>
+<#setting locale="en_US">
+<#setting number_format="0.#########">
+
+<#assign ls = []?sort>
+<#list ls as i>
+- ${i}
+</#list>
+<@assertEquals expected=0 actual=ls?size />
+<@assertEquals expected=3 actual=set?size />
+</...@noOutput>
+Sorting scalars:
+----------------
+
+String order:
+<#assign ls = ["whale", "Barbara", "zeppelin", "aardvark", "beetroot"]?sort>
+<#list ls as i>
+- ${i}
+</#list>
+
+First: ${ls?first}
+Last: ${ls?last}
+Size ${ls?size}
+
+Numerical order:
+<#assign ls = [123?byte, 543, -324, -34?float, 0.11, 0, 111?int, 0.1?double, 1, 5]?sort>
+<#list ls as i>
+- ${i}
+</#list>
+
+First: ${ls?first}
+Last: ${ls?last}
+Size ${ls?size}
+
+Date/time order:
+<#assign x = [
+        '08:05'?time('HH:mm'),
+        '18:00'?time('HH:mm'),
+        '06:05'?time('HH:mm'),
+        '08:15'?time('HH:mm')]>
+<#list x?sort as i>
+- ${i?string('HH:mm')}
+</#list>
+
+Boolean order:
+<#assign x = [
+        true,
+        false,
+        false,
+        true]>
+<#list x?sort as i>
+- ${i?string}
+</#list>
+
+
+Sorting hashes:
+---------------
+
+<#assign ls = [
+  {"name":"whale", "weight":2000?short},
+  {"name":"Barbara", "weight":53},
+  {"name":"zeppelin", "weight":-200?float},
+  {"name":"aardvark", "weight":30?long},
+  {"name":"beetroot", "weight":0.3}
+]>
+Order by name:
+<#assign ls = ls?sort_by("name")>
+<#list ls as i>
+- ${i.name}: ${i.weight}
+</#list>
+
+Order by weight:
+<#assign ls = ls?sort_by("weight")>
+<#list ls as i>
+- ${i.name}: ${i.weight}
+</#list>
+
+Order by a.x.v:
+<#assign x = [
+        {"a": {"x": {"v": "qweqw", "w": "asd"}, "y": '1998-02-20'?date('yyyy-MM-dd')}},
+        {"a": {"x": {"v": "aqweqw", "w": "asd"}, "y": '1999-01-20'?date('yyyy-MM-dd')}},
+        {"a": {"x": {"v": "dfgdf", "w": "asd"}, "y": '1999-04-20'?date('yyyy-MM-dd')}},
+        {"a": {"x": {"v": "utyu", "w": "asd"}, "y": '1999-04-19'?date('yyyy-MM-dd')}}]>
+<#list x?sort_by(['a', 'x', 'v']) as i>
+- ${i.a.x.v}
+</#list>
+
+Order by a.y, which is a date:
+<#list x?sort_by(['a', 'y']) as i>
+- ${i.a.y?string('yyyy-MM-dd')}
+</#list>
+
+Reverse:
+--------
+
+Order by weight desc:
+<#assign ls = ls?reverse>
+<#list ls as i>
+- ${i.name}: ${i.weight}
+</#list>
+
+Order by weight desc desc:
+<#assign ls = ls?reverse>
+<#list ls as i>
+- ${i.name}: ${i.weight}
+</#list>
+
+Order by weight desc desc desc:
+<#assign ls = ls?reverse>
+<#list ls as i>
+- ${i.name}: ${i.weight}
+</#list>
+
+Contains:
+---------
+
+<#macro test></#macro>
+<#assign x = [1, "2", true, [1,2,3], {"a":1}, test, '1992-02-21'?date('yyyy-MM-dd')]>
+True:
+${x?seq_contains(1.0)?string}
+${x?seq_contains("2")?string}
+${x?seq_contains(true)?string}
+${x?seq_contains('1992-02-21'?date('yyyy-MM-dd'))?string}
+${abcSet?seq_contains("a")?string}
+${abcSet?seq_contains("b")?string}
+${abcSet?seq_contains("c")?string}
+
+False:
+${x?seq_contains("1")?string}
+${x?seq_contains(2)?string}
+${x?seq_contains(false)?string}
+${x?seq_contains('1992-02-22'?date('yyyy-MM-dd'))?string}
+${abcSet?seq_contains("A")?string}
+${abcSet?seq_contains(1)?string}
+${abcSet?seq_contains(true)?string}
+
+<#assign x = []>
+False: ${x?seq_contains(1)?string}
+
+Index_of:
+---------
+
+<#assign x = [1, "2", true, [1,2,3], {"a":1}, test, '1992-02-21'?date('yyyy-MM-dd')]>
+0 = ${x?seq_index_of(1.0)}
+1 = ${x?seq_index_of("2")}
+2 = ${x?seq_index_of(true)}
+6 = ${x?seq_index_of('1992-02-21'?date('yyyy-MM-dd'))}
+0 = ${abcSet?seq_index_of("a")}
+1 = ${abcSet?seq_index_of("b")}
+2 = ${abcSet?seq_index_of("c")}
+
+-1 = ${x?seq_index_of("1")}
+-1 = ${x?seq_index_of(2)}
+-1 = ${x?seq_index_of(false)}
+-1 = ${x?seq_index_of('1992-02-22'?date('yyyy-MM-dd'))}
+-1 = ${abcSet?seq_index_of("A")}
+-1 = ${abcSet?seq_index_of(1)}
+-1 = ${abcSet?seq_index_of(true)}
+
+<#assign x = []>
+-1 = ${x?seq_index_of(1)}
+
+Last_index_of:
+--------------
+
+<#assign x = [1, "2", true, [1,2,3], {"a":1}, test, 1, '1992-02-21'?date('yyyy-MM-dd')]>
+6 = ${x?seq_last_index_of(1.0)}
+1 = ${x?seq_last_index_of("2")}
+2 = ${x?seq_last_index_of(true)}
+7 = ${x?seq_last_index_of('1992-02-21'?date('yyyy-MM-dd'))}
+-1 = ${x?seq_last_index_of("1")}
+0 = ${abcSet?seq_last_index_of("a")}
+1 = ${abcSet?seq_last_index_of("b")}
+2 = ${abcSet?seq_last_index_of("c")}
+-1 = ${abcSet?seq_last_index_of("A")}
+
+Index_of and last_index_of with starting indices
+------------------------------------------------
+
+<#assign names = ["Joe", "Fred", "Joe", "Susan"]>
+seq_index_of "Joe":
+0 = ${names?seq_index_of("Joe", -2)}
+0 = ${names?seq_index_of("Joe", -1)}
+0 = ${names?seq_index_of("Joe", 0)}
+2 = ${names?seq_index_of("Joe", 1)}
+2 = ${names?seq_index_of("Joe", 2)}
+-1 = ${names?seq_index_of("Joe", 3)}
+-1 = ${names?seq_index_of("Joe", 4)}
+ 
+seq_last_index_of "Joe":
+-1 = ${names?seq_last_index_of("Joe", -2)}
+-1 = ${names?seq_last_index_of("Joe", -1)}
+0 = ${names?seq_last_index_of("Joe", 0)}
+0 = ${names?seq_last_index_of("Joe", 1)}
+2 = ${names?seq_last_index_of("Joe", 2)}
+2 = ${names?seq_last_index_of("Joe", 3)}
+2 = ${names?seq_last_index_of("Joe", 4)}
+ 
+seq_index_of "Susan":
+3 = ${names?seq_index_of("Susan", -2)}
+3 = ${names?seq_index_of("Susan", -1)}
+3 = ${names?seq_index_of("Susan", 0)}
+3 = ${names?seq_index_of("Susan", 1)}
+3 = ${names?seq_index_of("Susan", 2)}
+3 = ${names?seq_index_of("Susan", 3)}
+-1 = ${names?seq_index_of("Susan", 4)}
+ 
+seq_last_index_of "Susan":
+-1 = ${names?seq_last_index_of("Susan", -2)}
+-1 = ${names?seq_last_index_of("Susan", -1)}
+-1 = ${names?seq_last_index_of("Susan", 0)}
+-1 = ${names?seq_last_index_of("Susan", 1)}
+-1 = ${names?seq_last_index_of("Susan", 2)}
+3 = ${names?seq_last_index_of("Susan", 3)}
+3 = ${names?seq_last_index_of("Susan", 4)}
+
+seq_index_of "a":
+0 = ${abcSet?seq_index_of("a", -2)}
+0 = ${abcSet?seq_index_of("a", -1)}
+0 = ${abcSet?seq_index_of("a", 0)}
+-1 = ${abcSet?seq_index_of("a", 1)}
+-1 = ${abcSet?seq_index_of("a", 2)}
+-1 = ${abcSet?seq_index_of("a", 3)}
+-1 = ${abcSet?seq_index_of("a", 4)}
+
+seq_index_of "b":
+1 = ${abcSet?seq_index_of("b", -2)}
+1 = ${abcSet?seq_index_of("b", -1)}
+1 = ${abcSet?seq_index_of("b", 0)}
+1 = ${abcSet?seq_index_of("b", 1)}
+-1 = ${abcSet?seq_index_of("b", 2)}
+-1 = ${abcSet?seq_index_of("b", 3)}
+
+seq_index_of "c":
+2 = ${abcSet?seq_index_of("c", -2)}
+2 = ${abcSet?seq_index_of("c", -1)}
+2 = ${abcSet?seq_index_of("c", 0)}
+2 = ${abcSet?seq_index_of("c", 1)}
+2 = ${abcSet?seq_index_of("c", 2)}
+-1 = ${abcSet?seq_index_of("c", 3)}
+ 
+seq_last_index_of "a":
+-1 = ${abcSet?seq_last_index_of("a", -2)}
+-1 = ${abcSet?seq_last_index_of("a", -1)}
+0 = ${abcSet?seq_last_index_of("a", 0)}
+0 = ${abcSet?seq_last_index_of("a", 1)}
+0 = ${abcSet?seq_last_index_of("a", 2)}
+0 = ${abcSet?seq_last_index_of("a", 3)}
+0 = ${abcSet?seq_last_index_of("a", 4)}
+
+seq_last_index_of "b":
+-1 = ${abcSet?seq_last_index_of("b", -2)}
+-1 = ${abcSet?seq_last_index_of("b", -1)}
+-1 = ${abcSet?seq_last_index_of("b", 0)}
+1 = ${abcSet?seq_last_index_of("b", 1)}
+1 = ${abcSet?seq_last_index_of("b", 2)}
+1 = ${abcSet?seq_last_index_of("b", 3)}
+
+seq_last_index_of "c":
+-1 = ${abcSet?seq_last_index_of("c", -2)}
+-1 = ${abcSet?seq_last_index_of("c", -1)}
+-1 = ${abcSet?seq_last_index_of("c", 0)}
+-1 = ${abcSet?seq_last_index_of("c", 1)}
+2 = ${abcSet?seq_last_index_of("c", 2)}
+2 = ${abcSet?seq_last_index_of("c", 3)}
+
+Sequence builtins ignoring nulls
+--------------------------------
+
+true = ${listWithNull?seq_contains('c')?string}
+2 = ${listWithNull?seq_index_of('c')}
+0 = ${listWithNull?seq_last_index_of('a')}
+
+These should throw exception, but for BC they don't:
+false = ${listWithNull?seq_contains(noSuchVar)?string}
+-1 = ${listWithNull?seq_index_of(noSuchVar)}
+-1 = ${listWithNull?seq_last_index_of(noSuchVar)}
+
+Sequence built-ins failing on date-type mismatch
+------------------------------------------------
+
+<#assign x = ['1992-02-21'?date('yyyy-MM-dd'), 'foo']>
+<@assertEquals actual=x?seq_index_of('foo') expected=1 />
+<@assertEquals actual=x?seq_index_of('1992-02-21'?date('yyyy-MM-dd')) expected=0 />
+<@assertFails message="dates of different types">
+  0 = ${x?seq_index_of('1992-02-21 00:00:00'?datetime('yyyy-MM-dd HH:mm:ss'))}
+</@>
+
+Chunk
+-----
+
+<#assign ls = ['a', 'b', 'c', 'd', 'e', 'f', 'g']>
+<#list ['NULL', '-'] as fill>
+  <#list [1, 2, 3, 4, 5, 10] as columns>
+    <@printTable ls, columns, fill />
+  </#list>
+</#list>
+<@printTable [1, 2, 3, 4, 5, 6, 7, 8, 9], 3, 'NULL' />
+<@printTable [1, 2, 3, 4, 5, 6, 7, 8, 9], 3, '-' />
+<@printTable [1], 3, 'NULL' />
+<@printTable [1], 3, '-' />
+<@printTable [], 3, 'NULL' />
+<@printTable [], 3, '-' />
+
+<#macro printTable ls columns fill>
+  columns = ${columns}, fill = ${fill}:<#lt>
+  <#if fill='NULL'>
+    <#local rows = ls?chunk(columns)>
+  <#else>
+    <#local rows = ls?chunk(columns, fill)>
+  </#if>
+  Rows: ${rows?size}
+  <#list rows as row>
+    <#list row as i>${i} </#list>  <-- Columns: ${row?size}
+  </#list>
+  
+</#macro>
+
+
+Join
+----
+
+<#assign xs = [1, "two", "three", 4]>
+- ${xs?join(", ")}
+- ${[]?join(", ")}
+- ${xs?join(", ", "(empty)", ".")}
+- ${[]?join(", ", "(empty)", ".")}
+- ${listWithNull?join(", ")}
+- ${listWithNull?join(", ", "(empty)")}
+- ${listWithNull?join(", ", "(empty)", ".")}
+- ${listWithNullsOnly?join(", ")}
+- ${listWithNullsOnly?join(", ", "(empty)")}
+- ${listWithNullsOnly?join(", ", "(empty)", ".")}
+- ${abcSet?join(", ", "(empty)", ".")}
+- ${abcCollection?join(", ", "(empty)", ".")}
+<@assertFails message="index 1">${['a', [], 'c']?join(", ", "(empty)", ".")}</@>
+
+Misc
+----
+
+First of set 1: ${abcSet?first}
+First of set 2: ${abcSetNonSeq?first}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/setting.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/setting.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/setting.ftl
new file mode 100644
index 0000000..89f3e23
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/setting.ftl
@@ -0,0 +1,53 @@
+<#--
+  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.
+-->
+<#setting locale='de_DE'>
+<@assertEquals expected='de_DE' actual=.locale />
+<@assertEquals expected='de' actual=.lang />
+<@assertEquals expected='java.util.Locale "de_DE"' actual=javaObjectInfo.info(.locale_object) />
+
+<#setting number_format="'f'#">
+<@assertEquals expected='f1' actual=1?string />
+
+<#setting boolean_format="t,f">
+<@assertEquals expected='t' actual=true?string />
+
+<#setting date_format="'df'">
+<@assertEquals expected='df' actual=.now?date?string />
+
+<#setting time_format="'tf'">
+<@assertEquals expected='tf' actual=.now?time?string />
+
+<#setting datetime_format="'dtf'">
+<@assertEquals expected='dtf' actual=.now?string />
+
+<#setting time_zone='GMT+00'>
+<#assign t1='2000'?datetime('yyyy')>
+<#setting time_zone='GMT+01'>
+<#assign t2='2000'?datetime('yyyy')>
+<@assertEquals expected=1000*60*60 actual=t1?long-t2?long />
+
+<#setting sql_date_and_time_time_zone='GMT+01'>
+
+<#setting url_escaping_charset='ISO-8859-1'>
+<@assertEquals expected='%E1' actual='á'?url />
+<#setting url_escaping_charset='UTF-8'>
+<@assertEquals expected='%C3%A1' actual='á'?url />
+
+<#setting output_encoding="ISO-8859-2">
+<@assertEquals expected="ISO-8859-2" actual=.output_encoding />

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/simplehash-char-key.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/simplehash-char-key.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/simplehash-char-key.ftl
new file mode 100644
index 0000000..07a3f1e
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/simplehash-char-key.ftl
@@ -0,0 +1,44 @@
+<#--
+  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.
+-->
+<@assertEquals expected="string" actual=mStringC.c />
+<@assertEquals expected=1 actual=mStringC?keys?size />
+<@assertEquals expected="null" actual=mStringC.d!'null' />
+<@assertEquals expected=1 actual=mStringC?keys?size />
+
+<@assertEquals expected="null" actual=mStringCNull.c!'null' />
+<@assertEquals expected=1 actual=mStringCNull?keys?size />
+<@assertEquals expected="null" actual=mStringCNull.d!'null' />
+<@assertEquals expected=1 actual=mStringCNull?keys?size />
+
+<@assertEquals expected="char" actual=mCharC.c />
+<@assertEquals expected=1 actual=mCharC?keys?size />
+<@assertEquals expected="null" actual=mCharC.d!'null' />
+<@assertEquals expected=1 actual=mCharC?keys?size />
+
+<@assertEquals expected="null" actual=mCharCNull.c!'null' />
+<@assertEquals expected=1 actual=mCharCNull?keys?size />
+<@assertEquals expected="null" actual=mCharCNull.d!'null' />
+<@assertEquals expected=1 actual=mCharCNull?keys?size />
+
+<@assertEquals expected="char" actual=mMixed.c />
+<@assertEquals expected="string" actual=mMixed.s />
+<@assertEquals expected="string2" actual=mMixed.s2 />
+<@assertEquals expected="null" actual=mMixed.s2n!'null' />
+<@assertEquals expected="null" actual=mMixed.wrong!'null' />
+<@assertEquals expected=4 actual=mMixed?keys?size />

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/specialvars.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/specialvars.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/specialvars.ftl
new file mode 100644
index 0000000..50416c9
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/specialvars.ftl
@@ -0,0 +1,38 @@
+<#--
+  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.
+-->
+<#-- Mostly just checks if the expressions doesn't fail -->
+<#assign works = .data_model>
+<#attempt>
+  ${noSuchVariableExists}
+<#recover>
+  <#assign works = .error>
+</#attempt>
+<#assign works = .globals>
+${.lang} == en
+${.locale} == en_US
+<#assign works = .locals!>
+<#assign works = .main>
+<#assign works = .node!>
+${.output_encoding?lower_case} == utf-8
+${.template_name} == specialvars.ftl
+${.url_escaping_charset?lower_case} == iso-8859-1
+<#assign foo = "x">
+${.vars['foo']} == x
+<#assign works = .version>
+${.now?is_datetime?c} == true
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/string-builtin-coercion.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/string-builtin-coercion.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/string-builtin-coercion.ftl
new file mode 100644
index 0000000..5d2e094
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/string-builtin-coercion.ftl
@@ -0,0 +1,34 @@
+<#--
+  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.
+-->
+Was broken 2.3.19:
+<#setting number_format="0.#">
+<@assert test=1232?contains('2') />
+<@assert test=1232?index_of('2') == 1 />
+<@assert test=1232?last_index_of('2') == 3 />
+<@assert test=1232?left_pad(6) == '  1232' /><@assert test=1232?left_pad(6, '0') == '001232' />
+<@assert test=1232?right_pad(6) == '1232  ' /><@assert test=1232?right_pad(6, '0') == '123200' />
+<@assert test=1232?matches('[1-3]+') />
+<@assert test=1232?replace('2', 'z') == '1z3z' />
+<@assert test=1232?replace('2', 'z', 'r') == '1z3z' />
+<@assert test=1232?split('2')[1] == '3' /><@assert test=1232?split('2')[2] == '' />
+<@assert test=1232?split('2', 'r')[1] == '3' />
+
+Was no broken in 2.3.19:
+<@assert test=1232?starts_with('12') />
+<@assert test=1232?ends_with('32') />

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/string-builtins-regexps-matches.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/string-builtins-regexps-matches.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/string-builtins-regexps-matches.ftl
new file mode 100644
index 0000000..201f404
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/string-builtins-regexps-matches.ftl
@@ -0,0 +1,118 @@
+<#--
+  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.
+-->
+<#assign input>
+L16
+L27
+L38
+L49
+</#assign>
+
+List mode:
+<#assign matches = input?matches(".+") >
+Size: ${matches?size}
+<#list 0..<matches?size as i>[${matches[i]}]</#list>
+<#list matches as m>[${m}]</#list>
+
+Iterator mode:
+<#assign matches = input?matches(".+") >
+<#list matches as m>[${m}]</#list>
+<#list matches as m>[${m}(${matches?join(', ')})]</#list>
+<#list matches as m>[${m}]</#list>
+
+Iterator mode changes to list mode:
+<#assign matches = input?matches(".+") >
+<#list matches as m>[${m}]/${matches?size}</#list>
+<#list matches as m>[${m}]</#list>
+
+Iterator mode changes to list mode 2:
+<#assign matches = input?matches(".+") >
+<#list matches as m>[${m}]</#list>
+<#list matches as m>[${m}]/${matches?size}<#t></#list>
+
+List mode with embedded iteration:
+<#assign matches = input?matches(".+") >
+<#list 0..<matches?size as i>[${matches[i]}(${matches?join(', ')})]</#list>
+
+Entire input match:
+<#assign matches = input?matches(r".*(\d)(\d)") >
+<#assign firstGS = false>
+<#list matches as m>
+- M: ${m}
+    <#if firstGS?is_boolean>
+      <#assign firstGS = m?groups>
+    </#if>
+    <#list m?groups as g>
+    - G: ${g}
+    </#list>
+</#list>
+firstGS was: ${firstGS?join(', ')}
+
+Entire input match 2:
+<#assign match = "x12"?matches(r"x(\d)(\d)") >
+Matches: ${match?c}
+<#list match?groups as g>
+- G: ${g}
+</#list>
+As list:
+<#list match as m>
+- M: ${m}
+  <#list m?groups as g>
+    - G: ${g}
+  </#list>
+</#list>
+Groups again:
+<#list match?groups as g>
+- G: ${g}
+</#list>
+
+Entire input match 3:
+<#assign match = "x12"?matches(r"y(\d)(\d)") >
+Matches: ${match?c}
+<@assertEquals expected=3 actual=match?groups?size />
+<@assertEquals expected=0 actual=match?size />
+
+Entire input match 4:
+<#assign match = "x12"?matches(r"x(\d)(\d)") >
+Matches: ${match?c}
+<#assign gs = match?groups>
+<@assertEquals expected=3 actual=gs?size />
+<@assertEquals expected=1 actual=match?size />
+- G: ${gs[0]}
+- G: ${match?groups[1]}
+- G: ${gs[2]}
+
+Substring match nested into entire input match:
+<#assign match = "x12"?matches(r"x(\d)(\d)") >
+<#list match?groups as g>
+- G: ${g} (<#list match as m>[${m}{${m?groups?join(', ')}}]</#list>)
+</#list>
+
+Different entire input and substring matches:
+<#assign match = "123"?matches(r"(\d+?)") >
+${match?groups?join(", ")}
+<#list match as m>
+- M: ${m} (Gs: ${m?groups?join(", ")})
+</#list>
+
+Different entire input and substring matches 2:
+<#assign match = "123"?matches(r"\d+?") >
+${match?groups?join(", ")}
+<#list match as m>
+- M: ${m} (Gs: ${m?groups?join(", ")})
+</#list>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/string-builtins-regexps.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/string-builtins-regexps.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/string-builtins-regexps.ftl
new file mode 100644
index 0000000..81c0b8f
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/string-builtins-regexps.ftl
@@ -0,0 +1,136 @@
+<#--
+  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.
+-->
+${"test"?matches('test')?string} == true
+${"test"?matches('test', '')?string} == true
+
+${"TEST"?matches('test')?string} == false
+${"TEST"?matches('test', 'i')?string} == true
+
+${"test\nfoo"?matches('.*^foo')?string} == false
+${"test\nfoo"?matches(r'.*\n^foo', 'm')?string} == true
+
+${"test\nfoo"?matches('test.foo')?string} == false
+${"test\nfoo"?matches('test.foo', 's')?string} == true
+
+${"test\nFoo"?matches('.*foo', 's')?string} == false
+${"test\nFoo"?matches('.*foo', 'i')?string} == false
+${"test\nFoo"?matches('.*foo', 'im')?string} == false
+${"test\nFoo"?matches('.*foo', 'si')?string} == true
+${"test\nFoo"?matches('.*foo', 'is')?string} == true
+${"test\nFoo"?matches('.*foo', 'mis')?string} == true
+
+${"test\nFoo"?matches('.*\n^foo', 'm')?string} == false
+${"test\nFoo"?matches('.*\n^foo', 'i')?string} == false
+${"test\nFoo"?matches('.*\n^foo', 'im')?string} == true
+${"test\nFoo"?matches('.*\n^foo', 'mi')?string} == true
+${"test\nFoo"?matches('.*^foo', 'ism')?string} == true
+${"test\nFoo"?matches('.*^foo', 'smi')?string} == true
+<#setting boolean_format="True,False">
+<@assert test=false?matches('[eslaF]+') />
+<@assert test='False'?matches('[eslaF]+') />
+
+<#assign s = "Code without test coverage\nis considered to be BROKEN">
+
+Lower 'c'-words:
+<#list s?matches('c[a-z]*') as m>
+- ${m}
+</#list>
+
+Any 'c'-words:
+<#list s?matches('c[a-z]*', 'i') as m>
+- ${m}
+</#list>  
+
+Lower line-last words:
+<#list s?matches('[a-z]+$', 'm') as m>
+- ${m}
+</#list>  
+
+Any line-last words:
+<#list s?matches('[a-z]+$', 'mi') as m>
+- ${m}
+</#list>
+
+Any last words:
+<#list s?matches('[a-z]+$', 'i') as m>
+- ${m}
+</#list>
+
+c-word with follower:
+<#list s?matches('(c[a-z]*+).([a-z]++)', 'is') as m>
+- "${m?j_string}"
+  Groups: <#list m?groups as g>"${g?j_string}"<#if g_has_next>, </#if></#list>
+</#list>
+
+c-word with follower in the same line:
+<#list s?matches('c[a-z]*+.[a-z]++', 'i') as m>
+- ${m}
+</#list>
+
+Lower c-word with follower in the same line:
+<#list s?matches('c[a-z]*+.[a-z]++', '') as m>
+- ${m}
+</#list>
+
+<#attempt>
+  Ignored but logged in 2.3: ${s?matches('broken', 'I')?string} == False
+<#recover>
+  Fails in 2.4
+</#attempt>
+<#attempt>
+  Ignored but logged in 2.3: ${s?matches('broken', 'f')?string} == False
+<#recover>
+  Fails in 2.4
+</#attempt>
+
+${"foobar"?replace("foo", "FOO")} == FOObar
+${"Foobar"?replace("foo", "FOO", "")} == Foobar
+${"Foobar"?replace("foo", "FOO", "i")} == FOObar
+${"FoobarfOO"?replace("foo", "FOO", "i")} == FOObarFOO
+${"FoobarfOO"?replace("foo", "FOO", "if")} == FOObarfOO
+${"FoobarfOO"?replace("foo", "FOO", "fi")} == FOObarfOO
+${"Foobar"?replace("foo", "FOO", "r")} == Foobar
+${"Foobar"?replace("foo", "FOO", "ri")} == FOObar
+${"FoobarfOO"?replace("foo", "FOO", "ri")} == FOObarFOO
+${"FoobarfOO"?replace("foo", "FOO", "rif")} == FOObarfOO
+${"FoobarfOO"?replace("foo", "FOO", "fri")} == FOObarfOO
+${"foobar"?replace("fo+", "FOO")} == foobar
+${"foobar"?replace("fo+", "FOO", "")} == foobar
+${"foobar"?replace("fo+", "FOO", "r")} == FOObar
+${"foobarfOo"?replace("fo+", "FOO", "ri")} == FOObarFOO
+${"foobarfOo"?replace("fo+", "FOO", "rif")} == FOObarfOo
+${false?replace('a', 'A')} == FAlse
+${false?replace('[abc]', 'A', 'r')} == FAlse
+
+<#attempt>
+  Ignored but logged in 2.3: ${"foobar"?replace("foo", "FOO", "c")}
+<#recover>
+  Fails in 2.4
+</#attempt>
+
+<#macro dumpList xs>[<#list xs as x>${x}<#if x_has_next>, </#if></#list>]</#macro>
+<@dumpList "fooXbarxbaaz"?split("X") /> == [foo, barxbaaz]
+<@dumpList "fooXbarxbaaz"?split("X", "") /> == [foo, barxbaaz]
+<@dumpList "fooXbarxbaaz"?split("X", "i") /> == [foo, bar, baaz]
+<@dumpList "fooXbarxbaaz"?split("X", "r") /> == [foo, barxbaaz]
+<@dumpList "fooXbarxbaaz"?split("X", "ri") /> == [foo, bar, baaz]
+<@dumpList "fooXXbarxxbaaz"?split("X+", "i") /> == [fooXXbarxxbaaz]
+<@dumpList "fooXXbarxxbaaz"?split("X+", "ri") /> == [foo, bar, baaz]
+<@dumpList false?split("[ae]", "r") /> == [F, ls]
+<@dumpList false?split("e") /> == [Fals, ]
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/string-builtins1.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/string-builtins1.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/string-builtins1.ftl
new file mode 100644
index 0000000..0e18520
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/string-builtins1.ftl
@@ -0,0 +1,129 @@
+<#--
+  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.
+-->
+FreeMarker: Encoding string built-in tests
+
+<#assign x = r'  dieBugsDie! * vazzZE 123456 --cdc-- --<<--@ x ${"kigyo"?upper_case}  '>
+  
+cap_first:  ${x?cap_first}
+uncap_first:${x?uncap_first}
+uncap_first:${"Blah"?uncap_first}
+capitalize: ${x?capitalize}
+html:       ${x?html}
+length:     ${x?length}
+lower_case: ${x?lower_case}
+rtf:        ${x?rtf}
+trim:       ${x?trim}
+trim2:      ${"foo bar"?trim}
+trim3:      ${" foo bar"?trim}
+trim4:      ${"foo bar "?trim}
+upper_case: ${x?upper_case}
+xml:        ${x?xml}
+xhtml:      ${"\"Blah's is > 1 & < 2\""?xhtml}
+<@assertEquals actual="'"?html expected="&#39;" />
+<@assertEquals actual="'"?xhtml expected="&#39;" />
+<@assertEquals actual="'"?xml expected="&apos;" />
+<#-- ?substring: -->
+<@assertEquals actual="ab"?substring(0) expected="ab" />
+<@assertEquals actual="ab"?substring(1) expected="b" />
+<@assertEquals actual="ab"?substring(2) expected="" />
+<@assertFails message="at least 0">${"ab"?substring(-1)}</@><#t>
+<@assertFails message="greater than the length of the string">${"ab"?substring(3)}</@><#t>
+<@assertEquals actual="ab"?substring(0, 0) expected="" />
+<@assertEquals actual="ab"?substring(0, 1) expected="a" />
+<@assertEquals actual="ab"?substring(0, 2) expected="ab" />
+<@assertFails message="at least 0">${"ab"?substring(0, -1)}</@><#t>
+<@assertFails message="greater than the length of the string">${"ab"?substring(0, 3)}</@><#t>
+<@assertEquals actual="ab"?substring(1, 1) expected="" />
+<@assertEquals actual="ab"?substring(1, 2) expected="b" />
+<@assertFails message="at least 0">${"ab"?substring(1, -1)}</@><#t>
+<@assertFails message="greater than the length of the string">${"ab"?substring(1, 3)}</@><#t>
+<@assertFails message="shouldn't be greater than the end index">${"ab"?substring(1, 0)}</@><#t>
+
+word_list:
+<#global words = x?word_list>
+<#list words as w>- ${w}
+</#list>
+
+<#global canufeelitbabe = x?interpret>
+interpret: <@canufeelitbabe></@>
+<#setting locale="es_ES">number: ${"-123.45"?number + 1.1}
+${"1.5e3"?number?c}
+${"0005"?number?c}
+${"+0"?number?c}
+${"-0"?number?c}
+${"NaN"?number?is_nan?c}
+${("INF"?number?is_infinite && "INF"?number > 0)?c}
+${("-INF"?number?is_infinite && "-INF"?number < 0)?c}
+${("Infinity"?number?is_infinite && "Infinity"?number > 0)?c}
+${("-Infinity"?number?is_infinite && "-Infinity"?number < 0)?c}
+
+${"org.apache.freemarker.test.templatesuite.models.NewTestModel"?new()}
+${"org.apache.freemarker.test.templatesuite.models.NewTestModel"?new(1)}
+${"org.apache.freemarker.test.templatesuite.models.NewTestModel"?new("xxx")}
+${"org.apache.freemarker.test.templatesuite.models.NewTestModel"?new("xxx", "yyy")}
+
+<#assign x = "In the beginning, God created the Heavens and The Earth.">
+
+${x?replace("the", "The Sacred, Holy", "i")} <#-- case insensitive replacement -->
+${x?replace("the", "the very", "f")} <#-- replace only the first one -->
+${x?replace("", "|")} <#-- replace empry string -->
+${x?replace("", "|", "f")} <#-- replace first empty string -->
+
+${x?replace("the H[a-z]+", "the sky", "r")} <#-- regexp replacement -->
+
+<#if x?matches(".*Heav..s.*")>matches<#else>Really?</#if>
+
+<#list x?matches("(the) ([a-z]+)", "i") as match>
+  ${match}
+  ${match?groups[1]} sacred ${match?groups[2]}
+</#list>  
+
+<#assign matches = x?matches("In the ([a-z]+), God created (.*)")>
+${matches?groups[0]}
+${matches?groups[1]}
+${matches?groups[2]}
+
+<#assign x="foo, bar;baz,     foobar">
+<#list x?split("[,;] ?", "r") as word>
+   ${word}
+</#list>
+
+
+<#assign a = "foo", b="bar", c="(a+b)?upper_case">
+${c?eval}
+
+[${"a"?j_string}] = [a]
+[${"a\\'x'\nb"?j_string}] = [a\\'x'\nb]
+[${"\x1\x1A\x20"?j_string}] = [\u0001\u001a ]
+
+[${"a"?js_string}] = [a]
+[${"a\\'x'\nb"?js_string}] = [a\\\'x\'\nb]
+[${"\x1\x1A\x20"?js_string}] = [\x01\x1A ]
+[${"<![CDATA["?js_string}] = [\x3C![CDATA[]
+[${"]]>"?js_string}] = []]\>]
+
+[${"a"?json_string}] = [a]
+[${"a\\'x'\nb"?json_string}] = [a\\'x'\nb]
+[${"\x1\x1A\x20"?json_string}] = [\u0001\u001A ]
+[${"\n\r\t\f\b\""?json_string}] = [\n\r\t\f\b\"]
+[${"/"?json_string}] = [\/]
+[${"a/b"?json_string}] = [a/b]
+[${"</script>"?json_string}] = [<\/script>]
+[${"<![CDATA["?json_string}] = [\u003C![CDATA[]
+[${"]]>"?json_string}] = []]\u003E]

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/string-builtins2.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/string-builtins2.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/string-builtins2.ftl
new file mode 100644
index 0000000..c9294fa
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/string-builtins2.ftl
@@ -0,0 +1,135 @@
+<#--
+  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.
+-->
+--
+<#assign s = "abbcdbb">
+${s?index_of("bb")} = 1
+${s?index_of("bb", 2)} = 5
+${s?index_of("")} = 0
+--
+${s?last_index_of("bb")} = 5
+${s?last_index_of("bb", 4)} = 1
+${s?last_index_of("")} = ${s?length}
+--
+${s?starts_with("abb")?string} = true
+${s?starts_with("bb")?string} = false
+${s?starts_with("")?string} = true
+--
+${s?ends_with("dbb")?string} = true
+${s?ends_with("cbb")?string} = false
+${s?ends_with("")?string} = true
+--
+${s?contains("abb")?string} = true
+${s?contains("bcd")?string} = true
+${s?contains("dbb")?string} = true
+${s?contains("bbx")?string} = false
+${s?contains("")?string} = true
+--
+[${s?chop_linebreak}] = [abbcdbb]
+[${"qwe\n"?chop_linebreak}] = [qwe]
+[${"qwe\r"?chop_linebreak}] = [qwe]
+[${"qwe\r\n"?chop_linebreak}] = [qwe]
+[${"qwe\r\n\r\n"?chop_linebreak}] = [qwe
+]
+[${"qwe\n\n"?chop_linebreak}] = [qwe
+]
+--
+[${s?replace("A", "-")}] = [abbcdbb]
+[${s?replace("c", "-")}] = [abb-dbb]
+[${s?replace("bb", "-=*")}] = [a-=*cd-=*]
+--
+<#assign ls = s?split("b")>
+<#list ls as i>[${i}]</#list> == [a][][cd][][]
+<#list "--die--maggots--!"?split("--") as i>[${i}]</#list> == [][die][maggots][!]
+<#list "Die maggots!"?split("--") as i>[${i}]</#list> == [Die maggots!]
+--
+[${""?left_pad(5)}]
+[${"a"?left_pad(5)}]
+[${"ab"?left_pad(5)}]
+[${"abc"?left_pad(5)}]
+[${"abcd"?left_pad(5)}]
+[${"abcde"?left_pad(5)}]
+[${"abcdef"?left_pad(5)}]
+[${"abcdefg"?left_pad(5)}]
+[${"abcdefgh"?left_pad(5)}]
+[${""?left_pad(5, "-")}]
+[${"a"?left_pad(5, "-")}]
+[${"ab"?left_pad(5, "-")}]
+[${"abc"?left_pad(5, "-")}]
+[${"abcd"?left_pad(5, "-")}]
+[${"abcde"?left_pad(5, "-")}]
+[${"abcdef"?left_pad(5, "-")}]
+[${"abcdefg"?left_pad(5, "-")}]
+[${"abcdefgh"?left_pad(5, "-")}]
+[${""?left_pad(8, ".oO")}]
+[${"a"?left_pad(8, ".oO")}]
+[${"ab"?left_pad(8, ".oO")}]
+[${"abc"?left_pad(8, ".oO")}]
+[${"abcd"?left_pad(8, ".oO")}]
+[${"abcde"?left_pad(8, ".oO")}]
+[${"abcdef"?left_pad(8, ".oO")}]
+[${"abcdefg"?left_pad(8, ".oO")}]
+[${"abcdefgh"?left_pad(8, ".oO")}]
+[${"abcdefghi"?left_pad(8, ".oO")}]
+[${"abcdefghij"?left_pad(8, ".oO")}]
+[${""?left_pad(0, r"/\_")}]
+[${""?left_pad(1, r"/\_")}]
+[${""?left_pad(2, r"/\_")}]
+[${""?left_pad(3, r"/\_")}]
+[${""?left_pad(4, r"/\_")}]
+[${""?left_pad(5, r"/\_")}]
+[${""?left_pad(6, r"/\_")}]
+[${""?left_pad(7, r"/\_")}]
+--
+[${""?right_pad(5)}]
+[${"a"?right_pad(5)}]
+[${"ab"?right_pad(5)}]
+[${"abc"?right_pad(5)}]
+[${"abcd"?right_pad(5)}]
+[${"abcde"?right_pad(5)}]
+[${"abcdef"?right_pad(5)}]
+[${"abcdefg"?right_pad(5)}]
+[${"abcdefgh"?right_pad(5)}]
+[${""?right_pad(5, "-")}]
+[${"a"?right_pad(5, "-")}]
+[${"ab"?right_pad(5, "-")}]
+[${"abc"?right_pad(5, "-")}]
+[${"abcd"?right_pad(5, "-")}]
+[${"abcde"?right_pad(5, "-")}]
+[${"abcdef"?right_pad(5, "-")}]
+[${"abcdefg"?right_pad(5, "-")}]
+[${"abcdefgh"?right_pad(5, "-")}]
+[${""?right_pad(8, ".oO")}]
+[${"a"?right_pad(8, ".oO")}]
+[${"ab"?right_pad(8, ".oO")}]
+[${"abc"?right_pad(8, ".oO")}]
+[${"abcd"?right_pad(8, ".oO")}]
+[${"abcde"?right_pad(8, ".oO")}]
+[${"abcdef"?right_pad(8, ".oO")}]
+[${"abcdefg"?right_pad(8, ".oO")}]
+[${"abcdefgh"?right_pad(8, ".oO")}]
+[${"abcdefghi"?right_pad(8, ".oO")}]
+[${"abcdefghij"?right_pad(8, ".oO")}]
+[${""?right_pad(0, r"/\_")}]
+[${""?right_pad(1, r"/\_")}]
+[${""?right_pad(2, r"/\_")}]
+[${""?right_pad(3, r"/\_")}]
+[${""?right_pad(4, r"/\_")}]
+[${""?right_pad(5, r"/\_")}]
+[${""?right_pad(6, r"/\_")}]
+[${""?right_pad(7, r"/\_")}]
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/string-builtins3.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/string-builtins3.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/string-builtins3.ftl
new file mode 100644
index 0000000..77389fa
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/string-builtins3.ftl
@@ -0,0 +1,225 @@
+<#--
+  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.
+-->
+<@assertEquals expected='foo' actual='foo'?keep_before('x') />
+<@assertEquals expected='f' actual='foo'?keep_before('o') />
+<@assertEquals expected='' actual='foo'?keep_before('f') />
+<@assertEquals expected='fo' actual='foobar'?keep_before('ob') />
+<@assertEquals expected='foob' actual='foobar'?keep_before('ar') />
+<@assertEquals expected='' actual='foobar'?keep_before('foobar') />
+<@assertEquals expected='' actual='foobar'?keep_before('') />
+<@assertEquals expected='' actual='foobar'?keep_before('', 'r') />
+<@assertEquals expected='FOO' actual='FOO'?keep_before('o') />
+<@assertEquals expected='F' actual='FOO'?keep_before('o', 'i') />
+<@assertEquals expected='fo' actual='fo.o'?keep_before('.') />
+<@assertEquals expected='' actual='fo.o'?keep_before('.', 'r') />
+<@assertEquals expected='FOOb' actual='FOObaar'?keep_before(r'([a-z])\1', 'r') />
+<@assertEquals expected='F' actual='FOObaar'?keep_before(r'([a-z])\1', 'ri') />
+<@assertEquals expected='foo' actual="foo : bar"?keep_before(r"\s*:\s*", "r") />
+<@assertEquals expected='foo' actual="foo:bar"?keep_before(r"\s*:\s*", "r") />
+<@assertFails message='"m" flag'>
+    ${'x'?keep_before('x', 'm')}
+</...@assertFails>
+<@assertFails message='3'>
+    ${'x'?keep_before('x', 'i', 'x')}
+</...@assertFails>
+<@assertFails message='none'>
+    ${'x'?keep_before()}
+</...@assertFails>
+
+<@assertEquals expected='' actual=''?keep_before_last('f') />
+<@assertEquals expected='ff' actual='fff'?keep_before_last('f') />
+<@assertEquals expected='' actual='foo'?keep_before_last('f') />
+<@assertEquals expected='' actual='f'?keep_before_last('f') />
+<@assertEquals expected='a.b' actual='a.b.txt'?keep_before_last('.') />
+<@assertEquals expected='ab' actual='ab'?keep_before_last('.') />
+<@assertEquals expected='a' actual='ab'?keep_before_last('.', 'r') />
+<@assertEquals expected='ab' actual='ab'?keep_before_last(r'\.', 'r') />
+<@assertEquals expected='af' actual='afFf'?keep_before_last('F') />
+<@assertEquals expected='afF' actual='afFf'?keep_before_last('F', 'i') />
+<@assertEquals expected='1a2' actual='1a2b3'?keep_before_last('[ab]', 'r') />
+<@assertEquals expected='aa' actual='aaabb'?keep_before_last('[ab]{3}', 'r') />
+<@assertEquals expected='aaabbx' actual='aaabbxbabe'?keep_before_last('[ab]{3}', 'r') />
+<@assertEquals expected='xxxaa' actual='xxxaaayyy'?keep_before_last('a+', 'r') />
+<@assertEquals expected='foobar' actual='foobar'?keep_before_last('') />
+<@assertEquals expected='foobar' actual='foobar'?keep_before_last('', 'r') />
+<@assertFails message='"m" flag'>
+    ${'x'?keep_before_last('x', 'm')}
+</...@assertFails>
+<@assertFails message='3'>
+    ${'x'?keep_before_last('x', 'i', 'x')}
+</...@assertFails>
+<@assertFails message='none'>
+    ${'x'?keep_before_last()}
+</...@assertFails>
+
+<@assertEquals expected='' actual='foo'?keep_after('x') />
+<@assertEquals expected='o' actual='foo'?keep_after('o') />
+<@assertEquals expected='oo' actual='foo'?keep_after('f') />
+<@assertEquals expected='ar' actual='foobar'?keep_after('ob') />
+<@assertEquals expected='' actual='foobar'?keep_after('ar') />
+<@assertEquals expected='' actual='foobar'?keep_after('foobar') />
+<@assertEquals expected='foobar' actual='foobar'?keep_after('') />
+<@assertEquals expected='foobar' actual='foobar'?keep_after('', 'r') />
+<@assertEquals expected='' actual='FOO'?keep_after('o') />
+<@assertEquals expected='O' actual='FOO'?keep_after('o', 'i') />
+<@assertEquals expected='o' actual='fo.o'?keep_after('.') />
+<@assertEquals expected='o.o' actual='fo.o'?keep_after('.', 'r') />
+<@assertEquals expected='r' actual='FOObaar'?keep_after(r'([a-z])\1', 'r') />
+<@assertEquals expected='baar' actual='FOObaar'?keep_after(r'([a-z])\1', 'ri') />
+<@assertEquals expected='bar' actual="foo : bar"?keep_after(r"\s*:\s*", "r") />
+<@assertEquals expected='bar' actual="foo:bar"?keep_after(r"\s*:\s*", "r") />
+<@assertFails message='"m" flag'>
+    ${'x'?keep_after('x', 'm')}
+</...@assertFails>
+<@assertFails message='3'>
+    ${'x'?keep_after('x', 'i', 'x')}
+</...@assertFails>
+<@assertFails message='none'>
+    ${'x'?keep_after()}
+</...@assertFails>
+
+<@assertEquals expected='' actual=''?keep_after_last('f') />
+<@assertEquals expected='' actual='fff'?keep_after_last('f') />
+<@assertEquals expected='' actual='oof'?keep_after_last('f') />
+<@assertEquals expected='' actual='f'?keep_after_last('f') />
+<@assertEquals expected='txt' actual='a.b.txt'?keep_after_last('.') />
+<@assertEquals expected='' actual='ab'?keep_after_last('.') />
+<@assertEquals expected='' actual='ab'?keep_after_last('.', 'r') />
+<@assertEquals expected='' actual='ab'?keep_after_last(r'\.', 'r') />
+<@assertEquals expected='fa' actual='fFfa'?keep_after_last('F') />
+<@assertEquals expected='a' actual='fFfa'?keep_after_last('F', 'i') />
+<@assertEquals expected='3' actual='1a2b3'?keep_after_last('[ab]', 'r') />
+<@assertEquals expected='' actual='aaabb'?keep_after_last('[ab]{3}', 'r') />
+<@assertEquals expected='x' actual='aaabbx'?keep_after_last('[ab]{3}', 'r') />
+<@assertEquals expected='e' actual='aaabbxbabe'?keep_after_last('[ab]{3}', 'r') />
+<@assertEquals expected='12345' actual='aaabb12345'?keep_after_last('[ab]{3}', 'r') />
+<@assertEquals expected='yyy' actual='xxxaaayyy'?keep_after_last('a+', 'r') />
+<@assertEquals expected='' actual='foobar'?keep_after_last('') />
+<@assertEquals expected='' actual='foobar'?keep_after_last('', 'r') />
+<@assertFails message='"m" flag'>
+    ${'x'?keep_after_last('x', 'm')}
+</...@assertFails>
+<@assertFails message='3'>
+    ${'x'?keep_after_last('x', 'i', 'x')}
+</...@assertFails>
+<@assertFails message='none'>
+    ${'x'?keep_after_last()}
+</...@assertFails>
+
+<@assertEquals expected='foo' actual='foo'?remove_beginning('x') />
+<@assertEquals expected='foo' actual='foo'?remove_beginning('o') />
+<@assertEquals expected='foo' actual='foo'?remove_beginning('fooo') />
+<@assertEquals expected='oo' actual='foo'?remove_beginning('f') />
+<@assertEquals expected='o' actual='foo'?remove_beginning('fo') />
+<@assertEquals expected='' actual='foo'?remove_beginning('foo') />
+<@assertEquals expected='foo' actual='foo'?remove_beginning('') />
+<@assertFails message='2'>
+    ${'x'?remove_beginning('x', 'x')}
+</...@assertFails>
+<@assertFails message='none'>
+    ${'x'?remove_beginning()}
+</...@assertFails>
+
+<@assertEquals expected='bar' actual='bar'?remove_ending('x') />
+<@assertEquals expected='bar' actual='bar'?remove_ending('a') />
+<@assertEquals expected='bar' actual='bar'?remove_ending('barr') />
+<@assertEquals expected='ba' actual='bar'?remove_ending('r') />
+<@assertEquals expected='b' actual='bar'?remove_ending('ar') />
+<@assertEquals expected='' actual='bar'?remove_ending('bar') />
+<@assertEquals expected='bar' actual='bar'?remove_ending('') />
+<@assertFails message='2'>
+    ${'x'?remove_ending('x', 'x')}
+</...@assertFails>
+<@assertFails message='none'>
+    ${'x'?remove_ending()}
+</...@assertFails>
+
+<@assertEquals expected='xfoo' actual='foo'?ensure_starts_with('x') />
+<@assertEquals expected='foo' actual='foo'?ensure_starts_with('f') />
+<@assertEquals expected='foo' actual='foo'?ensure_starts_with('foo') />
+<@assertEquals expected='fooofoo' actual='foo'?ensure_starts_with('fooo') />
+<@assertEquals expected='foo' actual='foo'?ensure_starts_with('') />
+<@assertEquals expected='x' actual=''?ensure_starts_with('x') />
+<@assertEquals expected='' actual=''?ensure_starts_with('') />
+<@assertEquals expected='bacdef' actual="bacdef"?ensure_starts_with("[ab]{2}", "ab") />
+<@assertEquals expected='bacdef' actual="bacdef"?ensure_starts_with("^[ab]{2}", "ab") />
+<@assertEquals expected='abcacdef' actual="cacdef"?ensure_starts_with("[ab]{2}", "ab") />
+<@assertEquals expected='abcacdef' actual="cacdef"?ensure_starts_with("^[ab]{2}", "ab") />
+<@assertEquals expected='ab!cdef' actual="cdef"?ensure_starts_with("ab", "ab!") />
+<@assertEquals expected='ab!ABcdef' actual="ABcdef"?ensure_starts_with("ab", "ab!") />
+<@assertEquals expected='ABcdef' actual="ABcdef"?ensure_starts_with("ab", "ab!", 'i') />
+<@assertEquals expected='abABcdef' actual="ABcdef"?ensure_starts_with(".b", "ab", 'i') />
+<@assertEquals expected='ABcdef' actual="ABcdef"?ensure_starts_with(".b", "ab", 'ri') />
+<@assertEquals expected='http://example.com' actual="example.com"?ensure_starts_with("[a-z]+://", "http://") />
+<@assertEquals expected='http://example.com' actual="http://example.com"?ensure_starts_with("[a-z]+://", "http://") />
+<@assertEquals expected='https://example.com' actual="https://example.com"?ensure_starts_with("[a-z]+://", "http://") />
+<@assertEquals expected='http://HTTP://example.com' actual="HTTP://example.com"?ensure_starts_with("[a-z]+://", "http://") />
+<@assertEquals expected='HTTP://example.com' actual="HTTP://example.com"?ensure_starts_with("[a-z]+://", "http://", "ir") />
+<@assertFails message='4'>
+    ${'x'?ensure_starts_with('x', 'x', 'x', 'x')}
+</...@assertFails>
+<@assertFails message='none'>
+    ${'x'?ensure_starts_with()}
+</...@assertFails>
+
+<@assertEquals expected='foox' actual='foo'?ensure_ends_with('x') />
+<@assertEquals expected='foo' actual='foo'?ensure_ends_with('o') />
+<@assertEquals expected='foo' actual='foo'?ensure_ends_with('foo') />
+<@assertEquals expected='foofooo' actual='foo'?ensure_ends_with('fooo') />
+<@assertEquals expected='foo' actual='foo'?ensure_ends_with('') />
+<@assertEquals expected='x' actual=''?ensure_ends_with('x') />
+<@assertEquals expected='' actual=''?ensure_ends_with('') />
+<@assertFails message='2'>
+    ${'x'?ensure_ends_with('x', 'x')}
+</...@assertFails>
+<@assertFails message='none'>
+    ${'x'?ensure_ends_with()}
+</...@assertFails>
+
+<@assertEquals expected='a' actual=1?lower_abc />
+<@assertEquals expected='b' actual=2?lower_abc />
+<@assertEquals expected='z' actual=26?lower_abc />
+<@assertEquals expected='aa' actual=27?lower_abc />
+<@assertEquals expected='ab' actual=28?lower_abc />
+<@assertEquals expected='cv' actual=100?lower_abc />
+<@assertFails messageRegexp='0|at least 1']>
+    ${0?lower_abc}
+</...@assertFails>
+<@assertFails messageRegexp='0|at least 1'>
+    ${-1?lower_abc}
+</...@assertFails>
+<@assertFails messageRegexp='1.00001|integer'>
+    ${1.00001?lower_abc}
+</...@assertFails>
+
+<@assertEquals expected='A' actual=1?upper_abc />
+<@assertEquals expected='B' actual=2?upper_abc />
+<@assertEquals expected='Z' actual=26?upper_abc />
+<@assertEquals expected='AA' actual=27?upper_abc />
+<@assertEquals expected='AB' actual=28?upper_abc />
+<@assertEquals expected='CV' actual=100?upper_abc />
+<@assertFails messageRegexp='0|at least 1']>
+    ${0?upper_abc}
+</...@assertFails>
+<@assertFails messageRegexp='0|at least 1'>
+    ${-1?upper_abc}
+</...@assertFails>
+<@assertFails messageRegexp='1.00001|integer'>
+    ${1.00001?upper_abc}
+</...@assertFails>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/stringbimethods.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/stringbimethods.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/stringbimethods.ftl
new file mode 100644
index 0000000..1d31c44
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/stringbimethods.ftl
@@ -0,0 +1,36 @@
+<#--
+  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.
+-->
+<#setting locale="en_US">
+<#assign x = 3>
+${x?string["0.00"]}
+${x?string("0.00")}
+${'01:02:03'?time.iso?string["iso ms nz"]}
+${'01:02:03'?time.iso?string("iso ms nz")}
+---
+${multi}
+<#assign a = true>
+<#assign b = false>
+${a?string} ${b?string}
+${a?string("yes", "no")} ${b?string("yes", "no")}
+<#setting boolean_format="igen,nem"/>
+${a?string} ${b?string}
+<#setting number_format="0.0">
+${a?string(0, 1)} ${b?string(0, 1)}
+<#setting boolean_format="true,false"/>
+${a?string(0, 1)?is_string?string} ${b?string(0, 1)?is_string?string}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/stringliteral.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/stringliteral.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/stringliteral.ftl
new file mode 100644
index 0000000..436c632
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/stringliteral.ftl
@@ -0,0 +1,69 @@
+<#--
+  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.
+-->
+<html>
+<head>
+  <title>FreeMarker: String literal test</title>
+  <meta http-equiv="Content-type" content="text/html; charset=UTF-8">
+</head>
+<body>
+
+<p>A simple test follows:</p>
+
+<#assign x = "Hello", y = "World">
+<#assign message = "${x}, ${y}!">
+
+${message}
+
+<p>
+[${""}] = []<br>
+[${"a"}] = [a]<br>
+[${"abcdef"}] = [abcdef]<br>
+[${"\""}] = ["]<br>
+[${"\"\"\""}] = ["""]<br>
+[${"a\""}] = [a"]<br>
+[${"\"a"}] = ["a]<br>
+[${"a\"b"}] = [a"b]<br>
+[${"a\nb"}] = [a
+b]<br>
+[${"'"}] = [']<br>
+[${"a'a"}] = [a'a]<br>
+[${"\"\'\n\r\f\b\t\l\a\g"}]<br>
+[${"\xA\x0A\x00A\x000A\x0000A"}]<br>
+[${"\x15Bz\x15b"}]<br>
+[${"\x010Cz\x010c"}]<br>
+
+<p>
+[${''}] = []<br>
+[${'a'}] = [a]<br>
+[${'abcdef'}] = [abcdef]<br>
+[${'"'}] = ["]<br>
+[${'"""'}] = ["""]<br>
+[${'a"'}] = [a"]<br>
+[${'"a'}] = ["a]<br>
+[${'a"b'}] = [a"b]<br>
+[${'a\nb'}] = [a
+b]<br>
+[${'\''}] = [']<br>
+[${'a\'a'}] = [a'a]<br>
+[${'\"\'\n\r\f\b\t\l\a\g'}]<br>
+[${'\xA\x0A\x00A\x000A\x0000A'}]<br>
+[${'\x15Bz\x15b'}]<br>
+[${'\x010Cz\x010c'}]<br>
+</body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/subdir/include-subdir.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/subdir/include-subdir.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/subdir/include-subdir.ftl
new file mode 100644
index 0000000..cd24873
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/subdir/include-subdir.ftl
@@ -0,0 +1,27 @@
+<#--
+  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.
+-->
+<p>This is include-subdir.ftl</p>
+<p>Testing including from same directory</p>
+<#include "include-subdir2.ftl">
+<p>Testing including from relative parent</p>
+<#include "../included.ftl">
+<p>Testing including from loader root</p>
+<#include "/included.ftl">
+<p>Testing including through acquisition</p>
+<#include "*/subdir/include-subdir2.ftl">
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/subdir/include-subdir2.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/subdir/include-subdir2.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/subdir/include-subdir2.ftl
new file mode 100644
index 0000000..356fcb2
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/subdir/include-subdir2.ftl
@@ -0,0 +1,19 @@
+<#--
+  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.
+-->
+<p>This is include-subdir2.ftl</p>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/subdir/new-optin-2.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/subdir/new-optin-2.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/subdir/new-optin-2.ftl
new file mode 100644
index 0000000..687661b
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/subdir/new-optin-2.ftl
@@ -0,0 +1,24 @@
+<#--
+  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.
+-->
+${"org.apache.freemarker.test.templatesuite.models.NewTestModel"?new("works")}
+<#attempt>
+${"org.apache.freemarker.test.templatesuite.models.NewTestModel2"?new("works")}
+<#recover>
+fails
+</#attempt>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/subdir/new-optin.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/subdir/new-optin.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/subdir/new-optin.ftl
new file mode 100644
index 0000000..242d221
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/subdir/new-optin.ftl
@@ -0,0 +1,26 @@
+<#--
+  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.
+-->
+${"org.apache.freemarker.test.templatesuite.models.NewTestModel"?new("works")}
+<#attempt>
+${"org.apache.freemarker.test.templatesuite.models.NewTestModel2"?new("works")}
+<#recover>
+fails
+</#attempt>
+
+<#include "new-optin-2.ftl">
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/subdir/subsub/new-optin.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/subdir/subsub/new-optin.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/subdir/subsub/new-optin.ftl
new file mode 100644
index 0000000..687661b
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/subdir/subsub/new-optin.ftl
@@ -0,0 +1,24 @@
+<#--
+  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.
+-->
+${"org.apache.freemarker.test.templatesuite.models.NewTestModel"?new("works")}
+<#attempt>
+${"org.apache.freemarker.test.templatesuite.models.NewTestModel2"?new("works")}
+<#recover>
+fails
+</#attempt>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/switch-builtin.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/switch-builtin.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/switch-builtin.ftl
new file mode 100644
index 0000000..7441733
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/switch-builtin.ftl
@@ -0,0 +1,54 @@
+<#--
+  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.
+-->
+<@assertEquals expected="A" actual="a"?switch("a", "A") />
+<@assertFails message="didn't match">${"b"?switch("a", "A")}</@>
+<@assertEquals expected="D" actual="b"?switch("a", "A", "D") />
+<@assertEquals expected="B" actual="b"?switch("a", "A", "b", "B") />
+<@assertFails message="didn't match">${"c"?switch("a", "A", "b", "B")}</@>
+<@assertEquals expected="D" actual="c"?switch("a", "A", "b", "B", "D") />
+
+<#assign out = "">
+<#assign fInvocationCnt = 0>
+<#list 0..5 as x>
+  <#assign out += x?switch(1, f("one"), 2, f("two"), 3, f("three"), f("default")) + ";">
+</#list>
+<@assertEquals expected="default;one;two;three;default;default;" actual=out />
+<@assertEquals expected=6 actual=fInvocationCnt />
+
+<#assign out = "">
+<#list 0..5 as x>
+  <#assign out += true?switch(x <= 1, "low", x == 2 || x == 3, "medium", x >= 3, "high") + ";">
+</#list>
+<@assertEquals expected="low;low;medium;medium;high;high;" actual=out />
+
+<#function f x>
+  <#assign fInvocationCnt++>
+  <#return x>
+</#function>
+
+<@assertFails message="noSuchVar1">${1?switch(noSuchVar1, noSuchVar2)}</@>
+<@assertFails message="noSuchVar2">${1?switch(1, noSuchVar2)}</@>
+<@assertFails message="noSuchVar3">${noSuchVar3?switch(1, 1)}</@>
+
+<@assertEquals expected="one" actual=1?switch(1, "one", "2", "two") />
+<@assertFails messageRegexp="Can't compare.+number.+string">${2?switch(1, "one", "2", "two")}</@>
+<@assertFails messageRegexp="Can't compare.+number.+string">${2?switch(1, "one", "2", "two", "default")}</@>
+
+<#assign out><#escape x as x?switch(2 * x, "zero", 1, "one", x, x?string("0.0"))>${0} ${1} ${2}</#escape></#assign>
+<@assertEquals expected="zero one 2.0" actual=out />

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/switch.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/switch.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/switch.ftl
new file mode 100644
index 0000000..6bbab3c
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/switch.ftl
@@ -0,0 +1,139 @@
+<#--
+  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.
+-->
+<html>
+<head>
+<title>FreeMarker: Switch-Case Test</title>
+</head>
+<body>
+
+<p>Here we iterate over a list of animals.</p>
+<#assign animalList = [ "aardvark", "kiwi", "gecko", "cat", "dog", "elephant",
+    "squirrel", "zebra" ]>
+<#assign favoriteAnimal = "kiwi">
+
+<#list animalList as animal>
+<p>Animal is: ${animal}.<br />
+<#switch animal>
+    <#case "zebra">
+        This is the HTML for a large stripey animal.
+    <#case "elephant">
+    <#case "rhinocerous">
+        This is the HTML for large animals.
+        <#break>
+    <#case "squirrel">
+    <#case "gecko">
+        This is the HTML for small animals.
+        <#break>
+    <#case favoriteAnimal>
+        This is the HTML for the user's favorite animal.
+        <#break>
+    <#default>
+        This is the HTML for other animals.
+        <#break>
+</#switch>
+</p>
+</#list>
+
+<#-- Nesting and no-match -->
+<#list [ 1, 2, 3 ] as x>
+  <#switch x>
+    <#case 1>
+      1
+      <#switch x*2>
+        <#case 1>
+          i1
+          <#break>
+        <#case 2>
+          i2
+          <#break>
+        <#case 3>
+          i3
+          <#break>
+        <#case 4>
+          i4
+          <#break>
+        <#case 6>
+          i6
+          <#break>
+      </#switch>
+      <#break>     
+    <#case 2>
+      2
+      <#switch x*2>
+        <#case 1>
+          i1
+          <#break>
+        <#case 2>
+          i2
+          <#break>
+        <#case 3>
+          i3
+          <#break>
+        <#case 4>
+          i4
+          <#-- falls through -->
+        <#case 5>
+          ft
+          <#-- falls through -->
+      </#switch>
+      ft
+      <#-- falls through -->     
+    <#case 3>
+      3
+      <#switch x*2>
+        <#case 1>
+          i1
+          <#break>
+        <#case 2>
+          i2
+          <#break>
+        <#case 3>
+          i3
+          <#break>
+        <#case 4>
+          i4
+          <#break>
+        <#case 6>
+          i6
+          <#break>
+      </#switch>
+      <#break>     
+  </#switch>
+</#list>
+
+<#-- No match -->
+[<#switch 213>
+  <#case 1>sadas
+</#switch>]
+
+<#-- Fall-through -->
+<#list [ 0, 1, 2, 3, 4 ] as x>
+  "<#switch x><#case 1>1<#case 2>2<#case 3>3<#case 4>4</#switch>"
+</#list>
+
+<#-- Legacy parser bug: #default might not be the last, but it doesn't fall through if called directly -->
+<#list [1, 2, 3, 4, 5] as x>
+  "<#switch x><#case 1>1<#case 2>2<#default>default<#case 4>4<#case 5>5</#switch>"
+</#list>
+
+<#-- two #default-s are parsing error -->
+<@assertFails message="can only have one default"><@"<#switch 1><#case 1><#default><#default></#switch>"?interpret /></@>
+
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/then-builtin.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/then-builtin.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/then-builtin.ftl
new file mode 100644
index 0000000..de809e1
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/then-builtin.ftl
@@ -0,0 +1,53 @@
+<#--
+  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.
+-->
+<#assign f1InvocationCnt = 0>
+<#assign f2InvocationCnt = 0>
+
+<@assertEquals expected="f1 1" actual=true?then(f1(), f2()) />
+<@assertEquals expected="f2 1" actual=false?then(f1(), f2()) />
+<@assertEquals expected="f1 2" actual=true?then(f1(), f2()) />
+<@assertEquals expected="f2 2" actual=false?then(f1(), f2()) />
+<@assertEquals expected=2 actual=f1InvocationCnt />
+<@assertEquals expected=2 actual=f2InvocationCnt />
+
+<#function f1>
+  <#assign f1InvocationCnt++>
+  <#return "f1 " + f1InvocationCnt>
+</#function>
+
+<#function f2>
+  <#assign f2InvocationCnt++>
+  <#return "f2 " + f2InvocationCnt>
+</#function>
+
+<#assign x = 1>
+<@assertEquals expected='Y' actual=(x < 2 * x)?then(-x < x, false)?then('Y', 'N') />
+
+<@assertEquals expected=1 actual=true?then(x, noSuchVar) />
+<@assertEquals expected=1 actual=false?then(noSuchVar, x) />
+
+<@assertFails message="noSuchVar1">${true?then(noSuchVar1, noSuchVar2)}</@>
+<@assertFails message="noSuchVar2">${false?then(noSuchVar1, noSuchVar2)}</@>
+<@assertFails message="noSuchVar3">${noSuchVar3?then(noSuchVar1, noSuchVar2)}</@>
+
+<#assign out><#escape x as x?then(1, 0)>${false} ${true}</#escape></#assign>
+<@assertEquals expected="0 1" actual=out />
+
+<#assign out><#escape x as (x < 0)?then(-x * 3, x * 2)>${-1} ${1}</#escape></#assign>
+<@assertEquals expected="3 2" actual=out />
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/transforms.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/transforms.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/transforms.ftl
new file mode 100644
index 0000000..9e5613a
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/transforms.ftl
@@ -0,0 +1,100 @@
+<#--
+  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.
+-->
+<#assign htmlEscape = "org.apache.freemarker.core.util.HtmlEscape"?new(),
+         utility = "org.apache.freemarker.test.templatesuite.models.TransformHashWrapper"?new()>
+<html>
+<head>
+<title>FreeMarker: Transformation Test</title>
+</head>
+<body>
+
+<p>A simple test follows:</p>
+
+<p>${message}</p>
+
+<@htmlEscape>
+<p>${message}</p>
+</...@htmlEscape>
+
+<P>Now try the Utility package:</p>
+<p>${utility}</p>
+
+<@utility.htmlEscape>
+<p>${utility}</p>
+</@>
+
+<p>Now some nested transforms:</p>
+<@utility.compress>
+<p    >This tests the compress transformation</p >
+</@>
+<@utility.compress>
+<@utility.htmlEscape>
+<p    >This tests the compress transformation</p >
+</@>
+</...@utility.compress>
+<#assign html_transform = "org.apache.freemarker.core.util.HtmlEscape"?new() />
+<@html_transform><#--Using the transform via an instantiation -->
+<@utility.compress>
+<p    >This tests the compress transformation</p >
+</@>
+</@>
+
+<p>Now try method and transform interactions:</p>
+<@utility.escape("xml")>
+<p>This isn't a valid XML string.</p>
+</@>
+<@utility.escape("html")>
+<p>This isn't a valid HTML string.</p>
+</@>
+
+<p>A more advanced interaction involves getting a TemplateMethodModel
+to initialise a TemplateTransformModel, as follow:</p>
+
+<@utility.special("This is a comment")>
+Comment: *
+
+A test string containing quotes: "This isn't a test".
+A test string containing amps: Fish & Chips.
+A test string containing tags: <p>Fish &amp; Chips.</p>
+</@>
+
+<@utility.special("This is a second comment", "quote")>
+Comment: *
+
+A test string containing quotes: "This isn't a test".
+A test string containing amps: Fish & Chips.
+A test string containing tags: <p>Fish &amp; Chips.</p>
+</@>
+<@utility.special("This is a third comment", "ampersand", "quote")>
+Comment: *
+
+A test string containing quotes: "This isn't a test".
+A test string containing amps: Fish & Chips.
+A test string containing tags: <p>Fish &amp; Chips.</p>
+</@>
+<@utility.special("tag", utility)>
+Comment: *
+
+A test string containing quotes: "This isn't a test".
+A test string containing amps: Fish & Chips.
+A test string containing tags: <p>Fish &amp; Chips.</p>
+</@>
+
+</body>
+</html>


[07/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/TemplateTestSuite.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/TemplateTestSuite.java b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/TemplateTestSuite.java
deleted file mode 100644
index 0edae99..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/TemplateTestSuite.java
+++ /dev/null
@@ -1,298 +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.test.templatesuite;
-
-import java.io.IOException;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Pattern;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-
-import org.apache.freemarker.core.Configuration;
-import org.apache.freemarker.core.Version;
-import org.apache.freemarker.core.util._StringUtil;
-import org.apache.freemarker.dom.NodeModel;
-import org.w3c.dom.Attr;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.NamedNodeMap;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-import org.xml.sax.SAXException;
-
-import junit.framework.TestSuite;
-
-/**
- * Test suite where the test cases are defined in testcases.xml, and usually process
- * templates and compare their output with the expected output.
- * 
- * If you only want to run certain tests, you can specify a regular expression for
- * the test name in the {@link #TEST_FILTER_PROPERTY_NAME} system property.
- */
-public class TemplateTestSuite extends TestSuite {
-    
-    private static final String ELEM_TEST_CASE = "testCase";
-
-    private static final String ELEM_SETTING = "setting";
-
-    private static final String ATTR_NO_OUTPUT = "noOutput";
-
-    private static final String ATTR_EXPECTED = "expected";
-
-    private static final String ATTR_TEMPLATE = "template";
-
-    private static final String END_TEMPLATE_NAME_MARK = "[#endTN]";
-
-    public static final String CONFIGURATION_XML_FILE_NAME = "testcases.xml";
-
-    /**
-     * When setting this system property, only the tests whose name matches the
-     * given regular expression will be executed.
-     */
-    public static final String TEST_FILTER_PROPERTY_NAME = "freemareker.templateTestSuite.testFilter";
-    
-    /**
-     * Comma separated list of "incompatible improvements" versions to run the test cases with.
-     */
-    public static final String INCOMPATIBLE_IMPROVEMENTS_PROPERTY_NAME
-            = "freemareker.templateTestSuite.incompatibleImprovements";
-    
-    private final Map<String, String> testSuiteSettings = new LinkedHashMap<>();
-
-    private final ArrayList<Version> testSuiteIcis;
-
-    private final Pattern testCaseNameFilter;
-    
-    public static TestSuite suite() throws Exception {
-        return new TemplateTestSuite();
-    }
-    
-    public TemplateTestSuite() throws Exception {
-        NodeModel.useJaxenXPathSupport();
-        
-        String filterStr = System.getProperty(TEST_FILTER_PROPERTY_NAME);
-        testCaseNameFilter = filterStr != null ? Pattern.compile(filterStr) : null;
-        if (testCaseNameFilter != null) {
-            System.out.println("Note: " + TEST_FILTER_PROPERTY_NAME + " is " + _StringUtil.jQuote(testCaseNameFilter));
-        }
-        
-        testSuiteIcis = new ArrayList<>();
-        String testedIcIsStr = System.getProperty(INCOMPATIBLE_IMPROVEMENTS_PROPERTY_NAME);
-        if (testedIcIsStr != null) {
-            for (String iciStr : testedIcIsStr.split(",")) {
-                iciStr = iciStr.trim();
-                if (iciStr.length() != 0) {
-                    testSuiteIcis.add(new Version(iciStr));
-                }
-            }
-        }
-        if (testSuiteIcis.isEmpty()) {
-            testSuiteIcis.add(getMinIcIVersion());
-            testSuiteIcis.add(getMaxIcIVersion());
-        }
-        
-        java.net.URL url = TemplateTestSuite.class.getResource(CONFIGURATION_XML_FILE_NAME);
-        if (url == null) {
-            throw new IOException("Resource not found: "
-                    + TemplateTestSuite.class.getName() + ", " + CONFIGURATION_XML_FILE_NAME);
-        }
-        processConfigXML(url.toURI());
-    }
-    
-    /**
-     * Read the test case configurations file and build up the test suite.
-     */
-    public void processConfigXML(URI uri) throws Exception {
-        Element testCasesElem = loadXMLFromURL(uri);
-        
-        NodeList children = testCasesElem.getChildNodes();
-        for (int childIdx = 0; childIdx < children.getLength(); childIdx++) {
-            Node n = children.item(childIdx);
-            if (n.getNodeType() == Node.ELEMENT_NODE) {
-                final String nodeName = n.getNodeName();
-                if (nodeName.equals(ELEM_SETTING)) {
-                    NamedNodeMap attrs = n.getAttributes();
-                    for (int attrIdx = 0; attrIdx < attrs.getLength(); attrIdx++) {
-                        Attr attr = (Attr) attrs.item(attrIdx);
-                        testSuiteSettings.put(attr.getName(), attr.getValue());
-                    }
-                } else if (nodeName.equals(ELEM_TEST_CASE)) {
-                    for (TemplateTestCase testCase : createTestCasesFromElement((Element) n)) {
-                        addTest(testCase);
-                    }
-                }
-            }
-        }
-    }
-
-    private Element loadXMLFromURL(URI uri) throws ParserConfigurationException, SAXException, IOException {
-        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
-        // dbf.setValidating(true);
-        DocumentBuilder db = dbf.newDocumentBuilder();
-        Document d = db.parse(uri.toString());
-        return d.getDocumentElement();
-    }
-    
-    String getTextInElement(Element e) {
-        StringBuilder buf = new StringBuilder();
-        NodeList children = e.getChildNodes();
-        for (int i = 0; i < children.getLength(); i++) {
-            Node n = children.item(i);
-            short type = n.getNodeType();
-            if (type == Node.TEXT_NODE || type == Node.CDATA_SECTION_NODE) {
-                buf.append(n.getNodeValue());
-            }
-        }
-        return buf.toString();
-    }
-    
-    /**
-     * Returns the list of test cases generated from the {@link #ELEM_TEST_CASE} element.
-     * There can be multiple generated test cases because of "incompatible improvements" variations, or none because
-     * of the {@code nameFilter}.
-     */
-    private List<TemplateTestCase> createTestCasesFromElement(Element testCaseElem)
-            throws Exception {
-        final String caseName = _StringUtil.emptyToNull(testCaseElem.getAttribute("name"));
-        if (caseName == null) throw new Exception("Invalid XML: the \"name\" attribute is mandatory.");
-        
-        if (testCaseNameFilter != null
-                && !testCaseNameFilter.matcher(caseName).matches()) {
-            return Collections.emptyList();
-        }
-        
-        final String templateName;
-        final String expectedFileName;
-        {
-            final String beforeEndTN;
-            final String afterEndTN;
-            {
-                int tBNameSep = caseName.indexOf(END_TEMPLATE_NAME_MARK);
-                beforeEndTN = tBNameSep == -1 ? caseName : caseName.substring(0, tBNameSep);
-                afterEndTN = tBNameSep == -1
-                        ? "" : caseName.substring(tBNameSep + END_TEMPLATE_NAME_MARK.length());
-            }
-            
-            {
-                String s = _StringUtil.emptyToNull(testCaseElem.getAttribute(ATTR_TEMPLATE));
-                templateName = s != null ? s : beforeEndTN + ".ftl";
-            }
-    
-            {
-                String s = _StringUtil.emptyToNull(testCaseElem.getAttribute(ATTR_EXPECTED));
-                expectedFileName = s != null ? s : beforeEndTN + afterEndTN + ".txt";
-            }
-        }
-        
-        final boolean noOutput;
-        {
-            String s = _StringUtil.emptyToNull(testCaseElem.getAttribute(ATTR_NO_OUTPUT));
-            noOutput = s != null && _StringUtil.getYesNo(s);
-        }
-
-        final Map<String, String> testCaseSettings = getCaseFMSettings(testCaseElem);
-        
-        final List<Version> icisToTest;
-        {
-            final String testCaseIcis = testCaseSettings.get(Configuration.ExtendableBuilder.INCOMPATIBLE_IMPROVEMENTS_KEY);
-                    
-            icisToTest = testCaseIcis != null ? parseVersionList(testCaseIcis) : testSuiteIcis;
-            if (icisToTest.isEmpty()) {
-                throw new Exception("The incompatible_improvement list was empty");
-            }
-        }
-
-        List<TemplateTestCase> result = new ArrayList<>();
-        for (Version iciToTest : icisToTest) {
-            TemplateTestCase testCase = new TemplateTestCase(
-                    caseName + "(ici=" + iciToTest + ")", caseName,
-                    templateName, expectedFileName, noOutput, iciToTest);
-            for (Map.Entry<String, String> setting : testSuiteSettings.entrySet()) {
-                testCase.setSetting(setting.getKey(), setting.getValue());
-            }
-            for (Map.Entry<String, String> setting : testCaseSettings.entrySet()) {
-                testCase.setSetting(setting.getKey(), setting.getValue());
-            }
-            
-            result.add(testCase);
-        }
-        
-        return result;
-    }
-
-    private List<Version> parseVersionList(String versionsStr) {
-        List<Version> versions = new ArrayList<>();
-        for (String versionStr : versionsStr.split(",")) {
-            versionStr = versionStr.trim();
-            if (versionStr.length() != 0) {
-                final Version v;
-                if ("min".equals(versionStr)) {
-                    v = getMinIcIVersion();
-                } else if ("max".equals(versionStr)) {
-                    v = getMaxIcIVersion();
-                } else {
-                    v = new Version(versionStr);
-                }
-                if (!versions.contains(v)) {
-                    versions.add(v);
-                }
-            }
-        }
-        return versions;
-    }
-
-    private Version getMaxIcIVersion() {
-        Version v = Configuration.getVersion();
-        // Remove nightly, RC and such:
-        return new Version(v.getMajor(), v.getMinor(), v.getMicro());
-    }
-
-    private Version getMinIcIVersion() {
-        return Configuration.VERSION_3_0_0;
-    }
-
-    private Map<String, String> getCaseFMSettings(Element e) {
-        final Map<String, String> caseFMSettings;
-        caseFMSettings = new LinkedHashMap<>();
-        NodeList settingElems = e.getElementsByTagName(ELEM_SETTING);
-        for (int elemIdx = 0; elemIdx < settingElems.getLength(); elemIdx++) {
-            NamedNodeMap attrs = settingElems.item(elemIdx).getAttributes();
-            for (int attrIdx = 0; attrIdx < attrs.getLength(); attrIdx++) {
-                Attr attr = (Attr) attrs.item(attrIdx);
-
-                final String settingName = attr.getName();
-                caseFMSettings.put(settingName, attr.getValue());
-            }
-        }
-        return caseFMSettings;
-    }
-    
-    public static void main (String[] args) throws Exception {
-        junit.textui.TestRunner.run(new TemplateTestSuite());
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/AllTemplateModels.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/AllTemplateModels.java b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/AllTemplateModels.java
deleted file mode 100644
index 974b3f9..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/AllTemplateModels.java
+++ /dev/null
@@ -1,128 +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.test.templatesuite.models;
-
-import java.util.Date;
-
-import org.apache.freemarker.core.model.TemplateBooleanModel;
-import org.apache.freemarker.core.model.TemplateCollectionModel;
-import org.apache.freemarker.core.model.TemplateDateModel;
-import org.apache.freemarker.core.model.TemplateHashModelEx;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateModelIterator;
-import org.apache.freemarker.core.model.TemplateNumberModel;
-import org.apache.freemarker.core.model.TemplateScalarModel;
-import org.apache.freemarker.core.model.TemplateSequenceModel;
-import org.apache.freemarker.core.model.impl.SimpleScalar;
-
-/**
- * Implements all template models that are interesting when calling overloaded Java methods.
- */
-public class AllTemplateModels implements
-        TemplateScalarModel, TemplateNumberModel, TemplateDateModel, TemplateBooleanModel,
-        TemplateHashModelEx, TemplateSequenceModel, TemplateCollectionModel {
-
-    public static final AllTemplateModels INSTANCE = new AllTemplateModels();
-    
-    private final TemplateModelIterator EMPTY_ITERATOR = new TemplateModelIterator() {
-
-        @Override
-        public TemplateModel next() throws TemplateModelException {
-            return null;
-        }
-
-        @Override
-        public boolean hasNext() throws TemplateModelException {
-            return false;
-        }
-        
-    };
-    
-    private final TemplateCollectionModel EMPTY_COLLECTION = new TemplateCollectionModel() {
-
-        @Override
-        public TemplateModelIterator iterator() throws TemplateModelException {
-            return EMPTY_ITERATOR;
-        }
-    };
-    
-    @Override
-    public TemplateModel get(String key) throws TemplateModelException {
-        return new SimpleScalar("value for key " + key);
-    }
-
-    @Override
-    public boolean isEmpty() throws TemplateModelException {
-        return true;
-    }
-
-    @Override
-    public TemplateModelIterator iterator() throws TemplateModelException {
-        return EMPTY_ITERATOR;
-    }
-
-    @Override
-    public TemplateModel get(int index) throws TemplateModelException {
-        return null;
-    }
-
-    @Override
-    public int size() throws TemplateModelException {
-        return 0;
-    }
-
-    @Override
-    public TemplateCollectionModel keys() throws TemplateModelException {
-        return EMPTY_COLLECTION;
-    }
-
-    @Override
-    public TemplateCollectionModel values() throws TemplateModelException {
-        return EMPTY_COLLECTION;
-    }
-
-    @Override
-    public boolean getAsBoolean() throws TemplateModelException {
-        return true;
-    }
-
-    @Override
-    public Date getAsDate() throws TemplateModelException {
-        return new Date(0);
-    }
-
-    @Override
-    public int getDateType() {
-        return TemplateDateModel.DATETIME;
-    }
-
-    @Override
-    @SuppressWarnings("boxing")
-    public Number getAsNumber() throws TemplateModelException {
-        return 1;
-    }
-
-    @Override
-    public String getAsString() throws TemplateModelException {
-        return "s";
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BeanTestClass.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BeanTestClass.java b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BeanTestClass.java
deleted file mode 100644
index 7e7fa82..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BeanTestClass.java
+++ /dev/null
@@ -1,93 +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.test.templatesuite.models;
-
-/**
- */
-public class BeanTestClass extends BeanTestSuperclass implements BeanTestInterface<Integer> {
-    public static final String STATIC_FINAL_FIELD = "static-final-field";
-    public static String STATIC_FIELD = "static-field";
-    
-	public String getFoo() {
-	    return "foo-value";
-	}
-	
-	public String getBar(int index) {
-	    return "bar-value-" + index;
-	}
-
-	public String[] getBar() {
-		return new String[] { "bar-value-0", "bar-value-1", "bar-value-2" };
-	}
-
-	public String overloaded(int i) {
-	    return "overloaded-int-" + i;
-	}
-	
-	public String overloaded(String s) {
-	    return "overloaded-String-" + s;
-	}
-	
-	public static String staticMethod() {
-	    return "static-method";
-	}
-	
-	public static String staticOverloaded(int i) {
-	    return "static-overloaded-int-" + i;
-	}
-
-	public static String staticOverloaded(String s) {
-	    return "static-overloaded-String-" + s;
-	}
-	
-	public PrivateInner getPrivateInner() {
-	    return new PrivateInner();
-	}
-
-        public PublicInner getPublicInner() {
-            return new PublicInner();
-        }
-	
-        public class PublicInner {
-            
-            public int getX() {
-                return 1;
-            }
-            
-            public String m() {
-                return "m";
-            }
-            
-        }
-        
-        @SuppressWarnings("unused")
-	private class PrivateInner {
-	    
-            public int getX() {
-	        return 2;
-	    }
-	    
-	    public String m() {
-	        return "M";
-	    }
-	    
-	}
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BeanTestInterface.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BeanTestInterface.java b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BeanTestInterface.java
deleted file mode 100644
index 6737b87..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BeanTestInterface.java
+++ /dev/null
@@ -1,25 +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.test.templatesuite.models;
-
-public interface BeanTestInterface<T> {
-    T getSomething();
-    void setSomething(T s);
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BeanTestSuperclass.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BeanTestSuperclass.java b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BeanTestSuperclass.java
deleted file mode 100644
index b462e9a..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BeanTestSuperclass.java
+++ /dev/null
@@ -1,30 +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.test.templatesuite.models;
-
-public class BeanTestSuperclass {
-    public Integer getSomething() {
-        return 42;
-    }
-    
-    public void setSomething(Integer x) {
-        
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanAndScalarModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanAndScalarModel.java b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanAndScalarModel.java
deleted file mode 100644
index 4af030e..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanAndScalarModel.java
+++ /dev/null
@@ -1,40 +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.test.templatesuite.models;
-
-import org.apache.freemarker.core.model.TemplateBooleanModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateScalarModel;
-
-public class BooleanAndScalarModel implements TemplateBooleanModel, TemplateScalarModel {
-
-    public static final BooleanAndScalarModel INSTANCE = new BooleanAndScalarModel();
-
-    @Override
-    public String getAsString() throws TemplateModelException {
-        return "s";
-    }
-
-    @Override
-    public boolean getAsBoolean() throws TemplateModelException {
-        return true;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanAndStringTemplateModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanAndStringTemplateModel.java b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanAndStringTemplateModel.java
deleted file mode 100644
index d87b65c..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanAndStringTemplateModel.java
+++ /dev/null
@@ -1,38 +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.test.templatesuite.models;
-
-import org.apache.freemarker.core.model.TemplateBooleanModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateScalarModel;
-
-public class BooleanAndStringTemplateModel implements TemplateBooleanModel, TemplateScalarModel {
-
-    @Override
-    public String getAsString() throws TemplateModelException {
-        return "theStringValue";
-    }
-
-    @Override
-    public boolean getAsBoolean() throws TemplateModelException {
-        return true;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanHash1.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanHash1.java b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanHash1.java
deleted file mode 100644
index 524d003..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanHash1.java
+++ /dev/null
@@ -1,58 +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.test.templatesuite.models;
-
-import org.apache.freemarker.core.model.TemplateBooleanModel;
-import org.apache.freemarker.core.model.TemplateHashModel;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.impl.SimpleScalar;
-
-/**
- * Tests the impact that the isEmpty() has on template hash models.
- */
-public class BooleanHash1 implements TemplateHashModel {
-
-    /**
-     * Gets a <tt>TemplateModel</tt> from the hash.
-     *
-     * @param key the name by which the <tt>TemplateModel</tt>
-     * is identified in the template.
-     * @return the <tt>TemplateModel</tt> referred to by the key,
-     * or null if not found.
-     */
-    @Override
-    public TemplateModel get(String key) {
-        if ( key.equals( "temp" )) {
-            return new SimpleScalar( "Hello, world." );
-        } else if ( key.equals( "boolean" )) {
-            return TemplateBooleanModel.FALSE;
-        } else {
-            return new SimpleScalar( "Just another key..." );
-        }
-    }
-
-    /**
-     * @return true if this object is empty.
-     */
-    @Override
-    public boolean isEmpty() {
-        return true;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanHash2.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanHash2.java b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanHash2.java
deleted file mode 100644
index 8bae7ab..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanHash2.java
+++ /dev/null
@@ -1,50 +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.test.templatesuite.models;
-
-import org.apache.freemarker.core.model.TemplateHashModel;
-import org.apache.freemarker.core.model.TemplateModel;
-
-/**
- * Tests the impact that the isEmpty() has on template hash models.
- */
-public class BooleanHash2 implements TemplateHashModel {
-
-    /**
-     * Gets a <tt>TemplateModel</tt> from the hash.
-     *
-     * @param key the name by which the <tt>TemplateModel</tt>
-     * is identified in the template.
-     * @return the <tt>TemplateModel</tt> referred to by the key,
-     * or null if not found.
-     */
-    @Override
-    public TemplateModel get(String key) {
-        return null;
-    }
-
-    /**
-     * @return true if this object is empty.
-     */
-    @Override
-    public boolean isEmpty() {
-        return false;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanList1.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanList1.java b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanList1.java
deleted file mode 100644
index 3e0a69c..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanList1.java
+++ /dev/null
@@ -1,62 +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.test.templatesuite.models;
-
-import org.apache.freemarker.core.model.ObjectWrapper;
-import org.apache.freemarker.core.model.TemplateBooleanModel;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateSequenceModel;
-import org.apache.freemarker.core.model.impl.SimpleSequence;
-
-/**
- * Model for testing the impact of isEmpty() on template list models. Every
- * other method simply delegates to a SimpleList model.
- */
-public class BooleanList1 implements TemplateSequenceModel {
-
-    private SimpleSequence cList;
-
-    /** Creates new BooleanList1 */
-    public BooleanList1(ObjectWrapper ow) {
-        cList = new SimpleSequence(ow);
-        cList.add( "false" );
-        cList.add( "0" );
-        cList.add(TemplateBooleanModel.FALSE);
-        cList.add(TemplateBooleanModel.TRUE);
-        cList.add(TemplateBooleanModel.TRUE);
-        cList.add(TemplateBooleanModel.TRUE);
-        cList.add(TemplateBooleanModel.FALSE);
-    }
-
-    /**
-     * @return the specified index in the list
-     */
-    @Override
-    public TemplateModel get(int i) throws TemplateModelException {
-        return cList.get(i);
-    }
-
-    @Override
-    public int size() {
-        return cList.size();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanList2.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanList2.java b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanList2.java
deleted file mode 100644
index 939fb5f..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanList2.java
+++ /dev/null
@@ -1,53 +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.test.templatesuite.models;
-
-import org.apache.freemarker.core.model.ObjectWrapper;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateSequenceModel;
-import org.apache.freemarker.core.model.impl.SimpleSequence;
-
-/**
- * Model for testing list models. Every
- * other method simply delegates to a SimpleList model.
- */
-public class BooleanList2 implements TemplateSequenceModel {
-
-    private SimpleSequence cList;
-
-    /** Creates new BooleanList2 */
-    public BooleanList2(ObjectWrapper ow) {
-        cList = new SimpleSequence(ow);
-    }
-
-    /**
-     * @return the specified index in the list
-     */
-    @Override
-    public TemplateModel get(int i) throws TemplateModelException {
-        return cList.get(i);
-    }
-
-    @Override
-    public int size() {
-        return cList.size();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanVsStringMethods.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanVsStringMethods.java b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanVsStringMethods.java
deleted file mode 100644
index 3e13623..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanVsStringMethods.java
+++ /dev/null
@@ -1,40 +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.test.templatesuite.models;
-
-public class BooleanVsStringMethods {
-    
-    public String expectsString(String s) {
-        return s;
-    }
-
-    public boolean expectsBoolean(boolean b) {
-        return b;
-    }
-    
-    public String overloaded(String s) {
-        return "String " + s;
-    }
-    
-    public String overloaded(boolean s) {
-        return "boolean " + s;
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/EnumTestClass.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/EnumTestClass.java b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/EnumTestClass.java
deleted file mode 100644
index 359e4a4..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/EnumTestClass.java
+++ /dev/null
@@ -1,34 +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.test.templatesuite.models;
-
-/**
- */
-public enum EnumTestClass
-{
-    ONE, 
-    TWO, 
-    THREE;
-    
-    @Override
-    public String toString() {
-        return name() + "x";
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/ExceptionModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/ExceptionModel.java b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/ExceptionModel.java
deleted file mode 100644
index ca0f9be..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/ExceptionModel.java
+++ /dev/null
@@ -1,39 +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.test.templatesuite.models;
-
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateScalarModel;
-
-/**
- * A template that always throws an exception whenever we call getAsString()
- */
-public class ExceptionModel implements TemplateScalarModel {
-
-    /**
-     * Returns the scalar's value as a String.
-     *
-     * @return the String value of this scalar.
-     */
-    @Override
-    public String getAsString () throws TemplateModelException {
-        throw new TemplateModelException( "Throwing from ExceptionModel!" );
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/HashAndScalarModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/HashAndScalarModel.java b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/HashAndScalarModel.java
deleted file mode 100644
index 70ea42a..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/HashAndScalarModel.java
+++ /dev/null
@@ -1,84 +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.test.templatesuite.models;
-
-import org.apache.freemarker.core.model.TemplateCollectionModel;
-import org.apache.freemarker.core.model.TemplateHashModelEx;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateModelIterator;
-import org.apache.freemarker.core.model.TemplateScalarModel;
-import org.apache.freemarker.core.model.impl.SimpleScalar;
-
-public class HashAndScalarModel implements TemplateHashModelEx, TemplateScalarModel {
-    
-    public static final HashAndScalarModel INSTANCE = new HashAndScalarModel();
-    
-    private final TemplateCollectionModel EMPTY_COLLECTION = new TemplateCollectionModel() {
-
-        @Override
-        public TemplateModelIterator iterator() throws TemplateModelException {
-            return new TemplateModelIterator() {
-
-                @Override
-                public TemplateModel next() throws TemplateModelException {
-                    return null;
-                }
-
-                @Override
-                public boolean hasNext() throws TemplateModelException {
-                    return false;
-                }
-                
-            };
-        }
-    };
-
-    @Override
-    public String getAsString() throws TemplateModelException {
-        return "scalarValue";
-    }
-
-    @Override
-    public TemplateModel get(String key) throws TemplateModelException {
-        return new SimpleScalar("mapValue for " + key);
-    }
-
-    @Override
-    public boolean isEmpty() throws TemplateModelException {
-        return true;
-    }
-
-    @Override
-    public int size() throws TemplateModelException {
-        return 0;
-    }
-
-    @Override
-    public TemplateCollectionModel keys() throws TemplateModelException {
-        return EMPTY_COLLECTION;
-    }
-
-    @Override
-    public TemplateCollectionModel values() throws TemplateModelException {
-        return EMPTY_COLLECTION;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/JavaObjectInfo.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/JavaObjectInfo.java b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/JavaObjectInfo.java
deleted file mode 100644
index 4673b09..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/JavaObjectInfo.java
+++ /dev/null
@@ -1,35 +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.test.templatesuite.models;
-
-import org.apache.freemarker.core.util._StringUtil;
-
-public class JavaObjectInfo {
-    
-    public static final Object INSTANCE = new JavaObjectInfo();
-
-    private JavaObjectInfo() { }
-    
-    public String info(Object o) {
-        if (o == null) return "null";
-        return o.getClass().getName() + " " + _StringUtil.jQuote(o.toString());
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/Listables.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/Listables.java b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/Listables.java
deleted file mode 100644
index c2d7c90..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/Listables.java
+++ /dev/null
@@ -1,185 +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.test.templatesuite.models;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
-
-import org.apache.freemarker.core.Configuration;
-import org.apache.freemarker.core.model.ObjectWrapper;
-import org.apache.freemarker.core.model.TemplateCollectionModel;
-import org.apache.freemarker.core.model.TemplateHashModelEx;
-import org.apache.freemarker.core.model.TemplateHashModelEx2;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.WrappingTemplateModel;
-import org.apache.freemarker.core.model.impl.DefaultMapAdapter;
-import org.apache.freemarker.core.model.impl.DefaultObjectWrapper;
-import org.apache.freemarker.core.model.impl.SimpleCollection;
-import org.apache.freemarker.core.model.impl.SimpleHash;
-
-import com.google.common.collect.ImmutableMap;
-
-@SuppressWarnings("boxing")
-public class Listables {
-    
-    private static final List<Integer> LIST;
-    static {
-        List<Integer> list = new ArrayList<>();
-        list.add(11);
-        list.add(22);
-        list.add(33);
-        LIST = list;
-    }
-
-    private static final List<Integer> LINKED_LIST;
-    static {
-        List<Integer> list = new LinkedList<>();
-        list.add(11);
-        list.add(22);
-        list.add(33);
-        LINKED_LIST = list;
-    }
-
-    private static final List<Integer> EMPTY_LINKED_LIST = new LinkedList<>();
-
-    private static final Set<Integer> SET;
-    static {
-        Set<Integer> set = new TreeSet<>();
-        set.add(11);
-        set.add(22);
-        set.add(33);
-        SET = set;
-    }
-    
-    public List<Integer> getList() {
-        return LIST;
-    }
-    
-    public List<Integer> getLinkedList() {
-        return LINKED_LIST;
-    }
-    
-    public Set<Integer> getSet() {
-        return SET;
-    }
-
-    public Iterator<Integer> getIterator() {
-        return SET.iterator();
-    }
-
-    public List<Integer> getEmptyList() {
-        return Collections.emptyList();
-    }
-    
-    public List<Integer> getEmptyLinkedList() {
-        return Collections.emptyList();
-    }
-    
-    public Set<Integer> getEmptySet() {
-        return Collections.emptySet();
-    }
-
-    public Iterator<Integer> getEmptyIterator() {
-        return Collections.<Integer>emptySet().iterator();
-    }
-    
-    public List<TemplateHashModelEx2> getHashEx2s() throws TemplateModelException {
-        Map<Object, Object> map;
-        map = new LinkedHashMap<>();
-        map.put("k1", "v1");
-        map.put(2, "v2");
-        map.put("k3", "v3");
-        map.put(null, "v4");
-        map.put(true, "v5");
-        map.put(false, null);
-        
-        return getMapsWrappedAsEx2(map);
-    }
-
-    public List<? extends TemplateHashModelEx> getEmptyHashes() throws TemplateModelException {
-        List<TemplateHashModelEx> emptyMaps = new ArrayList<>();
-        emptyMaps.addAll(getMapsWrappedAsEx2(Collections.emptyMap()));
-        emptyMaps.add((TemplateHashModelEx) new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build()
-                .wrap(Collections.emptyMap()));
-        return emptyMaps;
-    }
-    
-    /**
-     * Returns the map wrapped on various ways.
-     */
-    private List<TemplateHashModelEx2> getMapsWrappedAsEx2(Map<?, ?> map) throws TemplateModelException {
-        List<TemplateHashModelEx2> maps = new ArrayList<>();
-        
-        DefaultObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
-        maps.add(new SimpleHash(map, ow));
-        maps.add((DefaultMapAdapter) ow.wrap(map));
-
-        return maps;
-    }
-    
-    public TemplateHashModelEx getHashNonEx2() {
-        return new NonEx2MapAdapter(ImmutableMap.of("k1", 11, "k2", 22),
-                new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build());
-    }
-    
-    public static class NonEx2MapAdapter extends WrappingTemplateModel implements TemplateHashModelEx {
-
-        private final Map<?, ?> map;
-        
-        public NonEx2MapAdapter(Map<?, ?> map, ObjectWrapper wrapper) {
-            super(wrapper);
-            this.map = map;
-        }
-        
-        @Override
-        public TemplateModel get(String key) throws TemplateModelException {
-            return wrap(map.get(key));
-        }
-        
-        @Override
-        public boolean isEmpty() {
-            return map.isEmpty();
-        }
-        
-        @Override
-        public int size() {
-            return map.size();
-        }
-        
-        @Override
-        public TemplateCollectionModel keys() {
-            return new SimpleCollection(map.keySet(), getObjectWrapper());
-        }
-        
-        @Override
-        public TemplateCollectionModel values() {
-            return new SimpleCollection(map.values(), getObjectWrapper());
-        }
-        
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel1.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel1.java b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel1.java
deleted file mode 100644
index 66a0ffe..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel1.java
+++ /dev/null
@@ -1,116 +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.test.templatesuite.models;
-
-import org.apache.freemarker.core.Configuration;
-import org.apache.freemarker.core.model.ObjectWrapper;
-import org.apache.freemarker.core.model.TemplateHashModel;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateScalarModel;
-import org.apache.freemarker.core.model.TemplateSequenceModel;
-import org.apache.freemarker.core.model.impl.DefaultObjectWrapper;
-import org.apache.freemarker.core.model.impl.SimpleHash;
-import org.apache.freemarker.core.model.impl.SimpleScalar;
-import org.apache.freemarker.core.model.impl.SimpleSequence;
-
-/**
- * Testcase to see how FreeMarker deals with multiple Template models.
- */
-public class MultiModel1 implements TemplateHashModel,
-        TemplateSequenceModel, TemplateScalarModel {
-
-    private ObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
-
-    private TemplateModel m_cSubModel = new MultiModel2();
-    private TemplateModel m_cListHashModel1 = new MultiModel4(ow);
-    private TemplateModel m_cListHashModel2 = new MultiModel5(ow);
-    private TemplateSequenceModel m_cListModel = new SimpleSequence(ow);
-    private TemplateHashModel m_cHashModel = new SimpleHash(ow);
-
-    /** Creates new MultiModel1 */
-    public MultiModel1() {
-        for ( int i = 0; i < 10; i++ ) {
-            ((SimpleSequence) m_cListModel).add( "Model1 value: " + Integer.toString( i ));
-        }
-        ((SimpleSequence) m_cListModel).add( new MultiModel3() );
-        ((SimpleHash) m_cHashModel).put( "nested", new MultiModel3() );
-    }
-
-    /**
-     * Gets a <tt>TemplateModel</tt> from the hash.
-     *
-     * @param key the name by which the <tt>TemplateModel</tt>
-     * is identified in the template.
-     * @return the <tt>TemplateModel</tt> referred to by the key,
-     * or null if not found.
-     */
-    @Override
-    public TemplateModel get(String key) {
-        if ( key.equals( "model2" )) {
-            return m_cSubModel;
-        } else if ( key.equals( "modellist" )) {
-            return m_cListModel;
-        } else if ( key.equals( "selftest" )) {
-            return new SimpleScalar( "Selftest of a hash from MultiModel1" );
-        } else if ( key.equals( "one" )) {
-            return m_cListHashModel1;
-        } else if ( key.equals( "two" )) {
-            return m_cListHashModel2;
-        } else if ( key.equals( "size" )) {
-            return new SimpleScalar( "Nasty!" );
-        } else if ( key.equals( "nesting1" )) {
-            return m_cHashModel;
-        } else {
-            return null;
-        }
-    }
-
-    /**
-     * @return true if this object is empty.
-     */
-    @Override
-    public boolean isEmpty() {
-        return false;
-    }
-
-    /**
-     * @return the specified index in the list
-     */
-    @Override
-    public TemplateModel get(int i) throws TemplateModelException {
-        return m_cListModel.get( i );
-    }
-
-    /**
-     * Returns the scalar's value as a String.
-     *
-     * @return the String value of this scalar.
-     */
-    @Override
-    public String getAsString() {
-        return "MultiModel1 as a string!";
-    }
-
-    @Override
-    public int size() throws TemplateModelException {
-        return m_cListModel.size();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel2.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel2.java b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel2.java
deleted file mode 100644
index a7a75b5..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel2.java
+++ /dev/null
@@ -1,63 +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.test.templatesuite.models;
-
-import java.util.Iterator;
-import java.util.List;
-
-import org.apache.freemarker.core.model.TemplateMethodModel;
-import org.apache.freemarker.core.model.TemplateScalarModel;
-import org.apache.freemarker.core.model.impl.SimpleScalar;
-
-/**
- * Testcase to see how FreeMarker deals with multiple Template models.
- */
-public class MultiModel2 implements TemplateScalarModel, TemplateMethodModel {
-
-    /**
-     * Returns the scalar's value as a String.
-     *
-     * @return the String value of this scalar.
-     */
-    @Override
-    public String getAsString() {
-        return "Model2 is alive!";
-    }
-
-    /**
-     * Executes a method call.
-     *
-     * @param arguments a <tt>List</tt> of <tt>String</tt> objects containing the values
-     * of the arguments passed to the method.
-     * @return the <tt>TemplateModel</tt> produced by the method, or null.
-     */
-    @Override
-    public Object exec(List arguments) {
-        StringBuilder  aResults = new StringBuilder( "Arguments are:<br />" );
-        Iterator    iList = arguments.iterator();
-
-        while ( iList.hasNext() ) {
-            aResults.append( (String) iList.next() );
-            aResults.append( "<br />" );
-        }
-
-        return new SimpleScalar( aResults.toString() );
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel3.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel3.java b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel3.java
deleted file mode 100644
index 4434afc..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel3.java
+++ /dev/null
@@ -1,69 +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.test.templatesuite.models;
-
-import org.apache.freemarker.core.model.TemplateHashModel;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateScalarModel;
-import org.apache.freemarker.core.model.impl.SimpleScalar;
-
-/**
- * Testcase to see how FreeMarker deals with multiple Template models.
- */
-public class MultiModel3 implements TemplateScalarModel, TemplateHashModel {
-
-    /**
-     * Returns the scalar's value as a String.
-     *
-     * @return the String value of this scalar.
-     */
-    @Override
-    public String getAsString() {
-        return "Model3 is alive!";
-    }
-
-    /**
-     * @return true if this object is empty.
-     */
-    @Override
-    public boolean isEmpty() {
-        return false;
-    }
-
-    /**
-     * Gets a <tt>TemplateModel</tt> from the hash.
-     *
-     * @param key the name by which the <tt>TemplateModel</tt>
-     * is identified in the template.
-     * @return the <tt>TemplateModel</tt> referred to by the key,
-     * or null if not found.
-     */
-    @Override
-    public TemplateModel get(String key) {
-        if ( key.equals( "selftest" )) {
-            return new SimpleScalar( "Selftest from MultiModel3!" );
-        } else if ( key.equals( "message" )) {
-            return new SimpleScalar( "Hello world from MultiModel3!" );
-        } else {
-            return null;
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel4.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel4.java b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel4.java
deleted file mode 100644
index bdd11fc..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel4.java
+++ /dev/null
@@ -1,77 +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.test.templatesuite.models;
-
-import org.apache.freemarker.core.model.ObjectWrapper;
-import org.apache.freemarker.core.model.TemplateHashModel;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateSequenceModel;
-import org.apache.freemarker.core.model.impl.SimpleScalar;
-import org.apache.freemarker.core.model.impl.SimpleSequence;
-
-/**
- * Testcase to see how FreeMarker deals with multiple Template models.
- */
-public class MultiModel4 implements TemplateSequenceModel, TemplateHashModel {
-
-    private final SimpleSequence m_cList;
-
-    public MultiModel4(ObjectWrapper ow) {
-        this.m_cList = new SimpleSequence(ow);
-    }
-
-    /**
-     * @return the specified index in the list
-     */
-    @Override
-    public TemplateModel get(int i) throws TemplateModelException {
-        return m_cList.get( i );
-    }
-
-    /**
-     * Gets a <tt>TemplateModel</tt> from the hash.
-     *
-     * @param key the name by which the <tt>TemplateModel</tt>
-     * is identified in the template.
-     * @return the <tt>TemplateModel</tt> referred to by the key,
-     * or null if not found.
-     */
-    @Override
-    public TemplateModel get(String key) {
-        if ( key.equals( "size" )) {
-            return new SimpleScalar( "Key size, not the listSize method." );
-        } else {
-            return null;
-        }
-    }
-
-
-    @Override
-    public int size() {
-        return m_cList.size();
-    }
-
-    @Override
-    public boolean isEmpty() {
-        return size() == 0;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel5.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel5.java b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel5.java
deleted file mode 100644
index 01f7a3e..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel5.java
+++ /dev/null
@@ -1,81 +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.test.templatesuite.models;
-
-import org.apache.freemarker.core.model.ObjectWrapper;
-import org.apache.freemarker.core.model.TemplateHashModel;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateSequenceModel;
-import org.apache.freemarker.core.model.impl.SimpleScalar;
-import org.apache.freemarker.core.model.impl.SimpleSequence;
-
-/**
- * Testcase to see how FreeMarker deals with multiple Template models.
- */
-public class MultiModel5 implements TemplateSequenceModel, TemplateHashModel {
-
-    private final SimpleSequence m_cList;
-
-    /** Creates new MultiModel5 */
-    public MultiModel5(ObjectWrapper ow) {
-        this.m_cList = new SimpleSequence(ow);
-        m_cList.add( new SimpleScalar( "Dummy to make list non-empty" ));
-    }
-
-    /**
-     * @return the specified index in the list
-     */
-    @Override
-    public TemplateModel get(int i) throws TemplateModelException {
-        return m_cList.get( i );
-    }
-
-    /**
-     * @return true if this object is empty.
-     */
-    @Override
-    public boolean isEmpty() {
-        return false;
-    }
-
-    @Override
-    public int size() {
-        return m_cList.size();
-    }
-
-    /**
-     * Gets a <tt>TemplateModel</tt> from the hash.
-     *
-     * @param key the name by which the <tt>TemplateModel</tt>
-     * is identified in the template.
-     * @return the <tt>TemplateModel</tt> referred to by the key,
-     * or null if not found.
-     */
-    @Override
-    public TemplateModel get(String key) {
-        if ( key.equals( "empty" )) {
-            return new SimpleScalar( "Dummy hash value, for test purposes." );
-        } else {
-            return null;
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/NewTestModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/NewTestModel.java b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/NewTestModel.java
deleted file mode 100644
index 9f51458..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/NewTestModel.java
+++ /dev/null
@@ -1,52 +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.test.templatesuite.models;
-
-import org.apache.freemarker.core.model.TemplateScalarModel;
-
-/**
- * Testcase to see how FreeMarker's ?new built-in deals with constructors.
- */
-public class NewTestModel
-implements
-    TemplateScalarModel {
-    private final String string;
-    
-    public NewTestModel() {
-        string = "default constructor";
-    }
-
-    public NewTestModel(String str) {
-        string = str;
-    }
-
-    public NewTestModel(long i) {
-        string = Long.toString(i);
-    }
-
-    public NewTestModel(Object o1, java.io.Serializable o2) {
-        string = o1 + ":" + o2;
-    }
-
-    @Override
-    public String getAsString() {
-        return string;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/NewTestModel2.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/NewTestModel2.java b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/NewTestModel2.java
deleted file mode 100644
index 420b4fa..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/NewTestModel2.java
+++ /dev/null
@@ -1,52 +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.test.templatesuite.models;
-
-import org.apache.freemarker.core.model.TemplateScalarModel;
-
-/**
- * Testcase to see how FreeMarker's ?new built-in deals with constructors.
- */
-public class NewTestModel2
-implements
-    TemplateScalarModel {
-    private final String string;
-    
-    public NewTestModel2() {
-        string = "default constructor";
-    }
-
-    public NewTestModel2(String str) {
-        string = str;
-    }
-
-    public NewTestModel2(long i) {
-        string = Long.toString(i);
-    }
-
-    public NewTestModel2(Object o1, java.io.Serializable o2) {
-        string = o1 + ":" + o2;
-    }
-
-    @Override
-    public String getAsString() {
-        return string;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/NumberAndStringModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/NumberAndStringModel.java b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/NumberAndStringModel.java
deleted file mode 100644
index 5c8e7db..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/NumberAndStringModel.java
+++ /dev/null
@@ -1,47 +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.test.templatesuite.models;
-
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateNumberModel;
-import org.apache.freemarker.core.model.TemplateScalarModel;
-
-public class NumberAndStringModel implements TemplateNumberModel,
-		TemplateScalarModel {
-	
-	private final String s;
-	
-	public NumberAndStringModel(String s) {
-		super();
-		this.s = s;
-	}
-
-	@Override
-    public String getAsString() throws TemplateModelException {
-		return s;
-	}
-
-	@Override
-    @SuppressWarnings("boxing")
-    public Number getAsNumber() throws TemplateModelException {
-		return s.length();
-	}
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/OverloadedConstructor.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/OverloadedConstructor.java b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/OverloadedConstructor.java
deleted file mode 100644
index 6e09053..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/OverloadedConstructor.java
+++ /dev/null
@@ -1,46 +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.test.templatesuite.models;
-
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateScalarModel;
-
-public class OverloadedConstructor implements TemplateScalarModel {
-    
-    String value;
-    
-    public OverloadedConstructor(int i) {
-        value = "int " + i;
-    }
-    
-    public OverloadedConstructor(String s) {
-        value = "String " + s;
-    }
-
-    public OverloadedConstructor(CharSequence s) {
-        value = "CharSequence " + s;
-    }
-    
-    @Override
-    public String getAsString() throws TemplateModelException {
-        return value;
-    }
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/OverloadedMethods.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/OverloadedMethods.java b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/OverloadedMethods.java
deleted file mode 100644
index ebd505a..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/models/OverloadedMethods.java
+++ /dev/null
@@ -1,191 +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.test.templatesuite.models;
-
-import java.math.BigDecimal;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.freemarker.core.util.FTLUtil;
-
-/**
- * For testing overloaded method selection.
- */
-public class OverloadedMethods {
-
-	public String oneArg(Object a1) {
-		return methodCallToStr("oneArg<Object>", a1);
-	}
-
-	public String oneArg(String a1) {
-		return methodCallToStr("oneArg<String>", a1);
-	}
-
-	public String oneArg(Boolean a1) {
-		return methodCallToStr("oneArg<Boolean>", a1);
-	}
-
-	public String oneArg(boolean a1) {
-		return methodCallToStr("oneArg<boolean>", Boolean.valueOf(a1));
-	}
-	
-	public String oneArg(List a1) {
-		return methodCallToStr("oneArg<List>", a1);
-	}
-
-	public String oneArg(Map a1) {
-		return methodCallToStr("oneArg<Map>", a1);
-	}
-
-    public String oneArg2(Map a1) {
-        return methodCallToStr("oneArg2<Map>", a1);
-    }
-
-    public String oneArg2(List a1) {
-        return methodCallToStr("oneArg2<List>", a1);
-    }
-    
-    public String oneArg3(List a1, List a2) {
-        return methodCallToStr("oneArg3<List, List>", a1, a2);
-    }
-
-    public String oneArg3(List a1) {
-        return methodCallToStr("oneArg3<List>", a1);
-    }
-    
-    public String oneArg4(Integer a1) {
-        return methodCallToStr("oneArg4<Integer>", a1);
-    }
-
-    public String oneArg4(int a1) {
-        return methodCallToStr("oneArg4<int>", Integer.valueOf(a1));
-    }
-
-    public String notOverloaded(List a1) {
-        return methodCallToStr("notOverloaded<List>", a1);
-    }
-    
-	public String varargsIssue1(Map a1, List a2) {
-	    return methodCallToStr("varargsIssue1<Map, List>", a1, a2);
-	}
-
-    public String varargsIssue1(Object... a1) {
-        return methodCallToStr("varargsIssue1<Object...>", a1);
-    }
-
-    public String varargsIssue2(String a1, List a2) {
-        return methodCallToStr("varargsIssue2<String, List>", a1, a2);
-    }
-
-    public String varargsIssue2(String a1, Map a2) {
-        return methodCallToStr("varargsIssue2<String, Map>", a1, a2);
-    }
-
-    public String varargsIssue2(Object... a1) {
-        return methodCallToStr("varargsIssue2<Object...>", a1);
-    }
-    
-    public String numberIssue1(int a1) {
-        return methodCallToStr("numberIssue1<int>", a1);
-    }
-    
-    public String numberIssue1(float a1) {
-        return methodCallToStr("numberIssue1<float>", a1);
-    }
-    
-    public String numberIssue2(int a1) {
-        return methodCallToStr("numberIssue2<int>", a1);
-    }
-    
-    public String numberIssue2(BigDecimal a1) {
-        return methodCallToStr("numberIssue2<BigDecimal>", a1);
-    }
-
-    public String numberIssue3(int a1) {
-        return methodCallToStr("numberIssue3<int>", a1);
-    }
-    
-    public String numberIssue3(double a1) {
-        return methodCallToStr("numberIssue3<double>", a1);
-    }
-    
-	private String methodCallToStr(String methodName, Object... args) {
-		StringBuilder sb = new StringBuilder();
-		
-		sb.append(methodName);
-		sb.append('(');
-		boolean hadItems = false;
-		for (Object arg : args) {
-			if (hadItems) sb.append(", ");
-			sb.append(valueToStr(arg));
-			hadItems = true;
-		}
-		sb.append(')');
-		
-		return sb.toString();
-	}
-	
-	private String valueToStr(Object value) {
-		if (value == null) {
-		    return "null";
-		} else if (value instanceof Character) {
-			return "'" + FTLUtil.escapeStringLiteralPart(value.toString()) + "'";
-		} else if (value instanceof String) {
-			return "\"" + FTLUtil.escapeStringLiteralPart((String) value) + "\"";
-		} else if (value instanceof Map) {
-			StringBuilder sb = new StringBuilder(); 
-			sb.append("{");
-			boolean hadItems = false;
-			for (Map.Entry<?, ?> ent : ((Map<?, ?>) value).entrySet()) {
-				if (hadItems) sb.append(", ");
-				sb.append(valueToStr(ent.getKey()));
-				sb.append(": ");
-				sb.append(valueToStr(ent.getValue()));
-				hadItems = true;
-			}
-			sb.append("}");
-			return sb.toString();
-		} else if (value instanceof Collection || value.getClass().isArray()) {
-			StringBuilder sb = new StringBuilder();
-			
-	        if (value.getClass().isArray()) {
-	            value = Arrays.asList(value);
-                sb.append("array");
-	        } else if (value instanceof Set) {
-				sb.append("set");
-			}
-			sb.append("[");
-			boolean hadItems = false;
-			for (Object i : (Collection) value) {
-				if (hadItems) sb.append(", ");
-				sb.append(i);
-				hadItems = true;
-			}
-			sb.append("]");
-			return sb.toString();
-		} else {
-			return value.toString(); 
-		}
-	}
-	
-}



[13/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/OverloadedNumberUtilTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/OverloadedNumberUtilTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/OverloadedNumberUtilTest.java
deleted file mode 100644
index 37e4726..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/OverloadedNumberUtilTest.java
+++ /dev/null
@@ -1,585 +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.model.impl;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-
-import junit.framework.TestCase;
-
-@SuppressWarnings("boxing")
-public class OverloadedNumberUtilTest extends TestCase {
-
-    public OverloadedNumberUtilTest(String name) {
-        super(name);
-    }
-    
-    public void testIntegerCoercions() {
-        cipEqu(Byte.valueOf(Byte.MAX_VALUE));
-        cipEqu(Byte.valueOf((byte) 0));
-        cipEqu(Byte.valueOf(Byte.MIN_VALUE));
-        
-        cipEqu(Short.valueOf(Byte.MAX_VALUE),
-                new OverloadedNumberUtil.ShortOrByte((short) Byte.MAX_VALUE, Byte.MAX_VALUE));
-        cipEqu(Short.valueOf((short) 0),
-                new OverloadedNumberUtil.ShortOrByte((short) 0, (byte) 0));
-        cipEqu(Short.valueOf(Byte.MIN_VALUE),
-                new OverloadedNumberUtil.ShortOrByte((short) Byte.MIN_VALUE, Byte.MIN_VALUE));
-        
-        cipEqu(Short.valueOf((short) (Byte.MAX_VALUE + 1)));
-        cipEqu(Short.valueOf((short) (Byte.MIN_VALUE - 1)));
-        cipEqu(Short.valueOf(Short.MAX_VALUE));
-        cipEqu(Short.valueOf(Short.MIN_VALUE));
-        
-        cipEqu(Integer.valueOf(Byte.MAX_VALUE),
-                new OverloadedNumberUtil.IntegerOrByte((int) Byte.MAX_VALUE, Byte.MAX_VALUE));
-        cipEqu(Integer.valueOf(0),
-                new OverloadedNumberUtil.IntegerOrByte(0, (byte) 0));
-        cipEqu(Integer.valueOf(Byte.MIN_VALUE),
-                new OverloadedNumberUtil.IntegerOrByte((int) Byte.MIN_VALUE, Byte.MIN_VALUE));
-        
-        cipEqu(Integer.valueOf(Byte.MAX_VALUE + 1),
-                new OverloadedNumberUtil.IntegerOrShort(Byte.MAX_VALUE + 1, (short) (Byte.MAX_VALUE + 1)));
-        cipEqu(Integer.valueOf(Byte.MIN_VALUE - 1),
-                new OverloadedNumberUtil.IntegerOrShort(Byte.MIN_VALUE - 1, (short) (Byte.MIN_VALUE - 1)));
-        cipEqu(Integer.valueOf(Short.MAX_VALUE),
-                new OverloadedNumberUtil.IntegerOrShort((int) Short.MAX_VALUE, Short.MAX_VALUE));
-        cipEqu(Integer.valueOf(Short.MIN_VALUE),
-                new OverloadedNumberUtil.IntegerOrShort((int) Short.MIN_VALUE, Short.MIN_VALUE));
-        
-        cipEqu(Integer.valueOf(Short.MAX_VALUE + 1));
-        cipEqu(Integer.valueOf(Short.MIN_VALUE - 1));
-        cipEqu(Integer.valueOf(Integer.MAX_VALUE));
-        cipEqu(Integer.valueOf(Integer.MIN_VALUE));
-        
-        cipEqu(Long.valueOf(Byte.MAX_VALUE),
-                new OverloadedNumberUtil.LongOrByte((long) Byte.MAX_VALUE, Byte.MAX_VALUE));
-        cipEqu(Long.valueOf(0),
-                new OverloadedNumberUtil.LongOrByte((long) 0, (byte) 0));
-        cipEqu(Long.valueOf(Byte.MIN_VALUE),
-                new OverloadedNumberUtil.LongOrByte((long) Byte.MIN_VALUE, Byte.MIN_VALUE));
-        
-        cipEqu(Long.valueOf(Byte.MAX_VALUE + 1),
-                new OverloadedNumberUtil.LongOrShort((long) (Byte.MAX_VALUE + 1), (short) (Byte.MAX_VALUE + 1)));
-        cipEqu(Long.valueOf(Byte.MIN_VALUE - 1),
-                new OverloadedNumberUtil.LongOrShort((long) (Byte.MIN_VALUE - 1), (short) (Byte.MIN_VALUE - 1)));
-        cipEqu(Long.valueOf(Short.MAX_VALUE),
-                new OverloadedNumberUtil.LongOrShort((long) Short.MAX_VALUE, Short.MAX_VALUE));
-        cipEqu(Long.valueOf(Short.MIN_VALUE),
-                new OverloadedNumberUtil.LongOrShort((long) Short.MIN_VALUE, Short.MIN_VALUE));
-
-        cipEqu(Long.valueOf(Short.MAX_VALUE + 1),
-                new OverloadedNumberUtil.LongOrInteger((long) Short.MAX_VALUE + 1, Short.MAX_VALUE + 1));
-        cipEqu(Long.valueOf(Short.MIN_VALUE - 1),
-                new OverloadedNumberUtil.LongOrInteger((long) Short.MIN_VALUE - 1, Short.MIN_VALUE - 1));
-        cipEqu(Long.valueOf(Integer.MAX_VALUE),
-                new OverloadedNumberUtil.LongOrInteger((long) Integer.MAX_VALUE, Integer.MAX_VALUE));
-        cipEqu(Long.valueOf(Integer.MIN_VALUE),
-                new OverloadedNumberUtil.LongOrInteger((long) Integer.MIN_VALUE, Integer.MIN_VALUE));
-        
-        cipEqu(Long.valueOf(Integer.MAX_VALUE + 1L));
-        cipEqu(Long.valueOf(Integer.MIN_VALUE - 1L));
-        cipEqu(Long.valueOf(Long.MAX_VALUE));
-        cipEqu(Long.valueOf(Long.MIN_VALUE));
-    }
-    
-    public void testIntegerNoCoercions() {
-        cipEqu(Integer.valueOf(Byte.MAX_VALUE), Integer.valueOf(Byte.MAX_VALUE), 0);
-        cipEqu(Integer.valueOf(0), Integer.valueOf(0), 0);
-        cipEqu(Integer.valueOf(Byte.MIN_VALUE), Integer.valueOf(Byte.MIN_VALUE), 0);
-    }
-    
-    public void testIntegerLimitedCoercions() {
-        cipEqu(Integer.valueOf(Byte.MAX_VALUE), Integer.valueOf(Byte.MAX_VALUE), TypeFlags.INTEGER);
-        cipEqu(Integer.valueOf(0), Integer.valueOf(0), TypeFlags.INTEGER);
-        cipEqu(Integer.valueOf(Byte.MIN_VALUE), Integer.valueOf(Byte.MIN_VALUE), TypeFlags.INTEGER);
-        
-        cipEqu(Long.valueOf(Integer.MAX_VALUE + 1L), Long.valueOf(Integer.MAX_VALUE + 1L), TypeFlags.INTEGER);
-        
-        for (int n = -1; n < 2; n++) {
-            final Long longN = Long.valueOf(n);
-            cipEqu(longN, new OverloadedNumberUtil.LongOrInteger(longN, n), TypeFlags.INTEGER);
-            cipEqu(longN, new OverloadedNumberUtil.LongOrShort(longN, (short) n), TypeFlags.SHORT);
-            cipEqu(longN, new OverloadedNumberUtil.LongOrByte(longN, (byte) n), TypeFlags.BYTE);
-            cipEqu(longN, new OverloadedNumberUtil.LongOrShort(longN, (short) n),
-                    TypeFlags.SHORT | TypeFlags.INTEGER);
-        }
-    }
-
-    public void testBigDecimalCoercions() {
-        cipEqu(new BigDecimal(123), new OverloadedNumberUtil.IntegerBigDecimal(new BigDecimal(123)));
-        cipEqu(new BigDecimal(123), new OverloadedNumberUtil.IntegerBigDecimal(new BigDecimal(123)),
-                TypeFlags.DOUBLE | TypeFlags.INTEGER);
-        cipEqu(new BigDecimal(123), TypeFlags.INTEGER);
-        cipEqu(new BigDecimal(123), TypeFlags.INTEGER | TypeFlags.LONG);
-        cipEqu(new BigDecimal(123), TypeFlags.DOUBLE);
-        cipEqu(new BigDecimal(123), TypeFlags.DOUBLE | TypeFlags.FLOAT);
-        
-        cipEqu(new BigDecimal(123.5));
-        // Not wasting time with check if it's a whole number if we only have integer-only or non-integer-only targets:  
-        cipEqu(new BigDecimal(123.5), TypeFlags.INTEGER | TypeFlags.LONG);
-        cipEqu(new BigDecimal(123.5), TypeFlags.DOUBLE | TypeFlags.FLOAT);
-        
-        cipEqu(new BigDecimal("0.01"));
-        cipEqu(new BigDecimal("-0.01"));
-        cipEqu(BigDecimal.ZERO, new OverloadedNumberUtil.IntegerBigDecimal(BigDecimal.ZERO));
-    }
-
-    public void testUnknownNumberCoercion() {
-        cipEqu(new RationalNumber(2, 3));
-    }
-
-    @SuppressWarnings("boxing")
-    public void testDoubleCoercion() {
-        cipEqu(Double.valueOf(1.5), new OverloadedNumberUtil.DoubleOrFloat(1.5));
-        cipEqu(Double.valueOf(-0.125), new OverloadedNumberUtil.DoubleOrFloat(-0.125));
-        cipEqu(Double.valueOf(Float.MAX_VALUE), new OverloadedNumberUtil.DoubleOrFloat((double) Float.MAX_VALUE));
-        cipEqu(Double.valueOf(-Float.MAX_VALUE), new OverloadedNumberUtil.DoubleOrFloat((double) -Float.MAX_VALUE));
-        cipEqu(Double.valueOf(Float.MAX_VALUE * 10.0));
-        cipEqu(Double.valueOf(-Float.MAX_VALUE * 10.0));
-        
-        cipEqu(Double.valueOf(0), new OverloadedNumberUtil.DoubleOrByte(0.0, (byte) 0));
-        cipEqu(Double.valueOf(Byte.MAX_VALUE), new OverloadedNumberUtil.DoubleOrByte((double) Byte.MAX_VALUE, Byte.MAX_VALUE));
-        cipEqu(Double.valueOf(Byte.MIN_VALUE), new OverloadedNumberUtil.DoubleOrByte((double) Byte.MIN_VALUE, Byte.MIN_VALUE));
-        
-        cipEqu(Double.valueOf(Byte.MAX_VALUE + 1), new OverloadedNumberUtil.DoubleOrShort((double)
-                (Byte.MAX_VALUE + 1), (short) (Byte.MAX_VALUE + 1)));
-        cipEqu(Double.valueOf(Byte.MIN_VALUE - 1), new OverloadedNumberUtil.DoubleOrShort((double)
-                (Byte.MIN_VALUE - 1), (short) (Byte.MIN_VALUE - 1)));
-        
-        cipEqu(Double.valueOf(Short.MAX_VALUE + 1),
-                new OverloadedNumberUtil.DoubleOrIntegerOrFloat((double) Short.MAX_VALUE + 1, Short.MAX_VALUE + 1));
-        cipEqu(Double.valueOf(Short.MIN_VALUE - 1),
-                new OverloadedNumberUtil.DoubleOrIntegerOrFloat((double) Short.MIN_VALUE - 1, Short.MIN_VALUE -  1));
-        cipEqu(Double.valueOf(16777216), new OverloadedNumberUtil.DoubleOrIntegerOrFloat(16777216.0, 16777216));
-        cipEqu(Double.valueOf(-16777216), new OverloadedNumberUtil.DoubleOrIntegerOrFloat(-16777216.0, -16777216));
-        
-        cipEqu(Double.valueOf(Integer.MAX_VALUE),
-                new OverloadedNumberUtil.DoubleOrInteger((double) Integer.MAX_VALUE, Integer.MAX_VALUE));
-        cipEqu(Double.valueOf(Integer.MIN_VALUE),
-                new OverloadedNumberUtil.DoubleOrInteger((double) Integer.MIN_VALUE, Integer.MIN_VALUE));
-        
-        cipEqu(Double.valueOf(Integer.MAX_VALUE + 1L),
-                new OverloadedNumberUtil.DoubleOrLong(Double.valueOf(Integer.MAX_VALUE + 1L), Integer.MAX_VALUE + 1L));
-        cipEqu(Double.valueOf(Integer.MIN_VALUE - 1L),
-                new OverloadedNumberUtil.DoubleOrLong(Double.valueOf(Integer.MIN_VALUE - 1L), Integer.MIN_VALUE - 1L));
-        cipEqu(Double.valueOf(Long.MAX_VALUE),
-                new OverloadedNumberUtil.DoubleOrFloat((double) Long.MAX_VALUE));
-        cipEqu(Double.valueOf(Long.MIN_VALUE),
-                new OverloadedNumberUtil.DoubleOrFloat((double) Long.MIN_VALUE));
-
-        // When only certain target types are present:
-        cipEqu(Double.valueOf(5), new OverloadedNumberUtil.DoubleOrByte(5.0, (byte) 5), TypeFlags.BYTE);
-        cipEqu(Double.valueOf(5), new OverloadedNumberUtil.DoubleOrByte(5.0, (byte) 5), TypeFlags.BYTE | TypeFlags.SHORT);
-        cipEqu(Double.valueOf(-129), TypeFlags.BYTE);
-        cipEqu(Double.valueOf(5), new OverloadedNumberUtil.DoubleOrShort(5.0, (short) 5), TypeFlags.SHORT);
-        cipEqu(Double.valueOf(5), new OverloadedNumberUtil.DoubleOrInteger(5.0, 5), TypeFlags.INTEGER);
-        cipEqu(Double.valueOf(5), new OverloadedNumberUtil.DoubleOrLong(5.0, 5), TypeFlags.LONG);
-        cipEqu(Double.valueOf(5), new OverloadedNumberUtil.DoubleOrFloat(5.0), TypeFlags.FLOAT);
-        cipEqu(Double.valueOf(5), Double.valueOf(5), TypeFlags.DOUBLE);
-        cipEqu(Double.valueOf(5), new OverloadedNumberUtil.DoubleOrFloat(5.0),
-                TypeFlags.DOUBLE | TypeFlags.FLOAT);
-        cipEqu(Double.valueOf(5.9), new OverloadedNumberUtil.DoubleOrFloat(5.9),
-                TypeFlags.DOUBLE | TypeFlags.FLOAT);
-        cipEqu(Double.valueOf(5.9),
-                TypeFlags.DOUBLE | TypeFlags.INTEGER);
-        cipEqu(Double.valueOf(5.9), new OverloadedNumberUtil.DoubleOrFloat(5.9),
-                TypeFlags.FLOAT | TypeFlags.INTEGER);
-        cipEqu(Double.valueOf(5.9), TypeFlags.INTEGER);
-        cipEqu(Double.valueOf(Long.MAX_VALUE),
-                new OverloadedNumberUtil.DoubleOrFloat((double) Long.MAX_VALUE),
-                TypeFlags.DOUBLE | TypeFlags.FLOAT);
-        cipEqu(Double.valueOf(Long.MAX_VALUE),
-                TypeFlags.DOUBLE | TypeFlags.LONG);
-        cipEqu(Double.valueOf(Long.MIN_VALUE),
-                new OverloadedNumberUtil.DoubleOrFloat((double) Long.MIN_VALUE),
-                TypeFlags.DOUBLE | TypeFlags.FLOAT);
-        cipEqu(Double.valueOf(Float.MAX_VALUE * 10),
-                TypeFlags.DOUBLE | TypeFlags.FLOAT);
-        cipEqu(Double.valueOf(-Float.MAX_VALUE * 10),
-                TypeFlags.DOUBLE | TypeFlags.FLOAT);
-        
-        // Rounded values:
-        cipEqu(Double.valueOf(0.0000009),
-                new OverloadedNumberUtil.DoubleOrByte(0.0000009, (byte) 0));
-        cipEqu(Double.valueOf(-0.0000009),
-                new OverloadedNumberUtil.DoubleOrByte(-0.0000009, (byte) 0));
-        cipEqu(Double.valueOf(0.9999991),
-                new OverloadedNumberUtil.DoubleOrByte(0.9999991, (byte) 1));
-        cipEqu(Double.valueOf(-0.9999991),
-                new OverloadedNumberUtil.DoubleOrByte(-0.9999991, (byte) -1));
-        cipEqu(Double.valueOf(0.0000009),
-                new OverloadedNumberUtil.DoubleOrShort(0.0000009, (short) 0),
-                TypeFlags.SHORT | TypeFlags.DOUBLE);
-        cipEqu(Double.valueOf(0.0000009), new OverloadedNumberUtil.DoubleOrInteger(0.0000009, 0),
-                TypeFlags.INTEGER | TypeFlags.DOUBLE);
-        cipEqu(Double.valueOf(0.0000009), new OverloadedNumberUtil.DoubleOrLong(0.0000009, 0),
-                TypeFlags.LONG | TypeFlags.DOUBLE);
-        cipEqu(Double.valueOf(0.0000009),
-                new OverloadedNumberUtil.DoubleOrByte(0.0000009, (byte) 0), TypeFlags.BYTE);
-        cipEqu(Double.valueOf(0.0000009),
-                new OverloadedNumberUtil.DoubleOrShort(0.0000009, (short) 0), TypeFlags.SHORT);
-        cipEqu(Double.valueOf(0.0000009),
-                new OverloadedNumberUtil.DoubleOrInteger(0.0000009, 0), TypeFlags.INTEGER);
-        cipEqu(Double.valueOf(0.0000009),
-                new OverloadedNumberUtil.DoubleOrLong(0.0000009, 0L), TypeFlags.LONG);
-        cipEqu(Double.valueOf(0.9999999),
-                new OverloadedNumberUtil.DoubleOrInteger(0.9999999, 1), TypeFlags.INTEGER);
-        cipEqu(Double.valueOf(Byte.MAX_VALUE + 0.9e-6),
-                new OverloadedNumberUtil.DoubleOrByte(Byte.MAX_VALUE + 0.9e-6, Byte.MAX_VALUE));
-        cipEqu(Double.valueOf(Byte.MIN_VALUE - 0.9e-6),
-                new OverloadedNumberUtil.DoubleOrByte(Byte.MIN_VALUE - 0.9e-6, Byte.MIN_VALUE));
-        cipEqu(Double.valueOf(Byte.MAX_VALUE + 1.1e-6),
-                new OverloadedNumberUtil.DoubleOrFloat(Byte.MAX_VALUE + 1.1e-6));
-        cipEqu(Double.valueOf(Byte.MIN_VALUE - 1.1e-6),
-                new OverloadedNumberUtil.DoubleOrFloat(Byte.MIN_VALUE - 1.1e-6));
-        cipEqu(Double.valueOf(Byte.MAX_VALUE + 0.9999991),
-                new OverloadedNumberUtil.DoubleOrShort(
-                        Byte.MAX_VALUE + 0.9999991, (short) (Byte.MAX_VALUE + 1)));
-        cipEqu(Double.valueOf(Byte.MIN_VALUE - 0.9999991),
-                new OverloadedNumberUtil.DoubleOrShort(
-                        Byte.MIN_VALUE - 0.9999991, (short) (Byte.MIN_VALUE - 1)));
-        
-        cipEqu(Double.valueOf(Byte.MAX_VALUE + 1), new OverloadedNumberUtil.DoubleOrShort((double)
-                (Byte.MAX_VALUE + 1), (short) (Byte.MAX_VALUE + 1)));
-        cipEqu(Double.valueOf(Byte.MIN_VALUE - 1), new OverloadedNumberUtil.DoubleOrShort((double)
-                (Byte.MIN_VALUE - 1), (short) (Byte.MIN_VALUE - 1)));
-        
-        cipEqu(Short.MAX_VALUE + 0.9999991,
-                new OverloadedNumberUtil.DoubleOrIntegerOrFloat(Short.MAX_VALUE + 0.9999991, Short.MAX_VALUE + 1));
-        cipEqu(Short.MIN_VALUE - 0.9999991,
-                new OverloadedNumberUtil.DoubleOrIntegerOrFloat(Short.MIN_VALUE - 0.9999991, Short.MIN_VALUE - 1));
-        cipEqu(16777216 + 0.9e-6,
-                new OverloadedNumberUtil.DoubleOrIntegerOrFloat(16777216 + 0.9e-6, 16777216));
-        cipEqu(-16777216 - 0.9e-6,
-                new OverloadedNumberUtil.DoubleOrIntegerOrFloat(-16777216 - 0.9e-6, -16777216));
-        
-        cipEqu(Integer.MAX_VALUE + 0.9e-6,
-                new OverloadedNumberUtil.DoubleOrInteger(Integer.MAX_VALUE + 0.9e-6, Integer.MAX_VALUE));
-        cipEqu(Integer.MIN_VALUE - 0.9e-6,
-                new OverloadedNumberUtil.DoubleOrInteger(Integer.MIN_VALUE - 0.9e-6, Integer.MIN_VALUE));
-        
-        cipEqu(Integer.MAX_VALUE + 1L + 0.9e-6,
-                new OverloadedNumberUtil.DoubleOrFloat(Integer.MAX_VALUE + 1L + 0.9e-6));
-        cipEqu(Integer.MIN_VALUE - 1L - 0.9e-6,
-                new OverloadedNumberUtil.DoubleOrFloat(Integer.MIN_VALUE - 1L - 0.9e-6));
-        cipEqu(Long.MAX_VALUE + 0.9e-6,
-                new OverloadedNumberUtil.DoubleOrFloat(Long.MAX_VALUE + 0.9e-6));
-        cipEqu(Long.MIN_VALUE - 0.9e-6,
-                new OverloadedNumberUtil.DoubleOrFloat(Long.MIN_VALUE - 0.9e-6));
-    }
-
-    @SuppressWarnings("boxing")
-    public void testFloatCoercion() {
-        cipEqu(1.00002f);
-        cipEqu(-1.00002f);
-        cipEqu(1.999989f);
-        cipEqu(-1.999989f);
-        cipEqu(16777218f);
-        cipEqu(-16777218f);
-        
-        cipEqu(1f, new OverloadedNumberUtil.FloatOrByte(1f, (byte) 1));
-        cipEqu(-1f, new OverloadedNumberUtil.FloatOrByte(-1f, (byte) -1));
-        cipEqu(1.000009f, new OverloadedNumberUtil.FloatOrByte(1.000009f, (byte) 1));
-        cipEqu(-1.000009f, new OverloadedNumberUtil.FloatOrByte(-1.000009f, (byte) -1));
-        cipEqu(1.999991f, new OverloadedNumberUtil.FloatOrByte(1.999991f, (byte) 2));
-        cipEqu(-1.999991f, new OverloadedNumberUtil.FloatOrByte(-1.999991f, (byte) -2));
-        
-        cipEqu(1000f, new OverloadedNumberUtil.FloatOrShort(1000f, (short) 1000));
-        cipEqu(-1000f, new OverloadedNumberUtil.FloatOrShort(-1000f, (short) -1000));
-        cipEqu(1000.00006f);
-
-        cipEqu(60000f, new OverloadedNumberUtil.FloatOrInteger(60000f, 60000));
-        cipEqu(-60000f, new OverloadedNumberUtil.FloatOrInteger(-60000f, -60000));
-        cipEqu(60000.004f);
-
-        cipEqu(100f, new OverloadedNumberUtil.FloatOrByte(100f, (byte) 100), TypeFlags.MASK_KNOWN_INTEGERS);
-        cipEqu(1000f, new OverloadedNumberUtil.FloatOrShort(1000f, (short) 1000), TypeFlags.MASK_KNOWN_INTEGERS);
-        cipEqu(60000f, new OverloadedNumberUtil.FloatOrInteger(60000f, 60000), TypeFlags.MASK_KNOWN_INTEGERS);
-        cipEqu(60000f, new OverloadedNumberUtil.FloatOrInteger(60000f, 60000), TypeFlags.LONG);
-        cipEqu((float) Integer.MAX_VALUE, (float) Integer.MAX_VALUE, TypeFlags.LONG);
-        cipEqu((float) -Integer.MAX_VALUE, (float) -Integer.MAX_VALUE);
-        
-        cipEqu(0.5f, 0.5f, TypeFlags.DOUBLE | TypeFlags.FLOAT);
-        cipEqu(0.5f, 0.5f, TypeFlags.DOUBLE);
-    }
-    
-    public void testBigIntegerCoercion() {
-        BigInteger bi;
-        
-        cipEqu(BigInteger.ZERO, new OverloadedNumberUtil.BigIntegerOrByte(BigInteger.ZERO));
-        bi = new BigInteger(String.valueOf(Byte.MAX_VALUE));
-        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrByte(bi));
-        bi = new BigInteger(String.valueOf(Byte.MIN_VALUE));
-        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrByte(bi));
-        
-        bi = new BigInteger(String.valueOf(Byte.MAX_VALUE + 1));
-        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrShort(bi));
-        bi = new BigInteger(String.valueOf(Byte.MIN_VALUE - 1));
-        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrShort(bi));
-        bi = new BigInteger(String.valueOf(Short.MAX_VALUE));
-        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrShort(bi));
-        bi = new BigInteger(String.valueOf(Short.MIN_VALUE));
-        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrShort(bi));
-        
-        bi = new BigInteger(String.valueOf(Short.MAX_VALUE + 1));
-        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrInteger(bi));
-        bi = new BigInteger(String.valueOf(Short.MIN_VALUE - 1));
-        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrInteger(bi));
-        bi = new BigInteger(String.valueOf(Integer.MAX_VALUE));
-        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrInteger(bi));
-        bi = new BigInteger(String.valueOf(Integer.MIN_VALUE));
-        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrInteger(bi));
-        
-        bi = new BigInteger(String.valueOf(Integer.MAX_VALUE + 1L));
-        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrLong(bi));
-        bi = new BigInteger(String.valueOf(Integer.MIN_VALUE - 1L));
-        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrLong(bi));
-        bi = new BigInteger(String.valueOf(Long.MAX_VALUE));
-        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrLong(bi));
-        bi = new BigInteger(String.valueOf(Long.MIN_VALUE));
-        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrLong(bi));
-        
-        cipEqu(new BigInteger(String.valueOf(Long.MAX_VALUE)).add(BigInteger.ONE));
-        cipEqu(new BigInteger(String.valueOf(Long.MIN_VALUE)).subtract(BigInteger.ONE));
-        
-        bi = new BigInteger("0");
-        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrFloat(bi),
-                TypeFlags.DOUBLE | TypeFlags.FLOAT);
-        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrFloat(bi),
-                TypeFlags.MASK_KNOWN_NONINTEGERS);
-        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrFloat(bi),
-                TypeFlags.FLOAT);
-        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrDouble(bi),
-                TypeFlags.DOUBLE);
-
-        bi = new BigInteger("16777215");
-        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrFloat(bi), TypeFlags.MASK_KNOWN_NONINTEGERS);
-        bi = new BigInteger("-16777215");
-        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrFloat(bi), TypeFlags.MASK_KNOWN_NONINTEGERS);
-        
-        bi = new BigInteger("16777216");
-        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrFloat(bi), TypeFlags.MASK_KNOWN_NONINTEGERS);
-        bi = new BigInteger("-16777216");
-        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrFloat(bi), TypeFlags.MASK_KNOWN_NONINTEGERS);
-        
-        bi = new BigInteger("16777217");
-        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrDouble(bi), TypeFlags.MASK_KNOWN_NONINTEGERS);
-        cipEqu(bi, TypeFlags.FLOAT);
-        bi = new BigInteger("-16777217");
-        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrDouble(bi), TypeFlags.MASK_KNOWN_NONINTEGERS);
-        cipEqu(bi, TypeFlags.FLOAT);
-        
-        bi = new BigInteger("9007199254740991");
-        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrDouble(bi), TypeFlags.MASK_KNOWN_NONINTEGERS);
-        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrDouble(bi), TypeFlags.DOUBLE);
-        bi = new BigInteger("-9007199254740991");
-        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrDouble(bi), TypeFlags.MASK_KNOWN_NONINTEGERS);
-        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrDouble(bi), TypeFlags.DOUBLE);
-        
-        bi = new BigInteger("9007199254740992");
-        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrDouble(bi), TypeFlags.MASK_KNOWN_NONINTEGERS);
-        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrDouble(bi), TypeFlags.DOUBLE);
-        bi = new BigInteger("-9007199254740992");
-        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrDouble(bi), TypeFlags.MASK_KNOWN_NONINTEGERS);
-        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrDouble(bi), TypeFlags.DOUBLE);
-        
-        bi = new BigInteger("9007199254740993");
-        cipEqu(bi, TypeFlags.MASK_KNOWN_NONINTEGERS);
-        cipEqu(bi, TypeFlags.DOUBLE | TypeFlags.FLOAT);
-        cipEqu(bi, TypeFlags.FLOAT);
-        cipEqu(bi, TypeFlags.DOUBLE);
-        bi = new BigInteger("-9007199254740993");
-        cipEqu(bi, TypeFlags.MASK_KNOWN_NONINTEGERS);
-        cipEqu(bi, TypeFlags.DOUBLE | TypeFlags.FLOAT);
-        cipEqu(bi, TypeFlags.FLOAT);
-        cipEqu(bi, TypeFlags.DOUBLE);
-        
-        bi = new BigInteger("9007199254740994");
-        cipEqu(bi, TypeFlags.MASK_KNOWN_NONINTEGERS);
-        bi = new BigInteger("-9007199254740994");
-        cipEqu(bi, TypeFlags.MASK_KNOWN_NONINTEGERS);
-    }
-    
-    private void cipEqu(Number actualAndExpected) {
-        cipEqu(actualAndExpected, actualAndExpected, -1);
-    }
-    
-    private void cipEqu(Number actual, Number expected) {
-        cipEqu(actual, expected, -1);
-    }
-
-    private void cipEqu(Number actualAndExpected, int flags) {
-        cipEqu(actualAndExpected, actualAndExpected, flags);
-    }
-    
-    @SuppressWarnings("boxing")
-    private void cipEqu(Number actual, Number expected, int flags) {
-        Number res = OverloadedNumberUtil.addFallbackType(actual, flags);
-        assertEquals(expected.getClass(), res.getClass());
-        assertEquals(expected, res);
-        
-        // Some number types wrap the number with multiple types and equals() only compares one of them. So we try to
-        // catch any inconsistency:
-        assertEquals(expected.byteValue(), res.byteValue());
-        assertEquals(expected.shortValue(), res.shortValue());
-        assertEquals(expected.intValue(), res.intValue());
-        assertEquals(expected.longValue(), res.longValue());
-        assertEquals(expected.floatValue(), res.floatValue());
-        assertEquals(expected.doubleValue(), res.doubleValue());
-    }
-    
-    public void testGetArgumentConversionPrice() {
-        // Unknown number types:
-        assertEquals(Integer.MAX_VALUE, OverloadedNumberUtil.getArgumentConversionPrice(
-                RationalNumber.class, Integer.class));
-        assertEquals(Integer.MAX_VALUE, OverloadedNumberUtil.getArgumentConversionPrice(
-                Integer.class, RationalNumber.class));
-        assertEquals(Integer.MAX_VALUE, OverloadedNumberUtil.getArgumentConversionPrice(
-                RationalNumber.class, Float.class));
-        assertEquals(Integer.MAX_VALUE, OverloadedNumberUtil.getArgumentConversionPrice(
-                Float.class, RationalNumber.class));
-        assertEquals(0, OverloadedNumberUtil.getArgumentConversionPrice(
-                RationalNumber.class, RationalNumber.class));
-        
-        // Fully check some rows (not all of them; the code is generated anyways):
-
-        assertEquals(Integer.MAX_VALUE, OverloadedNumberUtil.getArgumentConversionPrice(
-                Integer.class, Byte.class));
-        assertEquals(Integer.MAX_VALUE, OverloadedNumberUtil.getArgumentConversionPrice(
-                Integer.class, Short.class));
-        assertEquals(0, OverloadedNumberUtil.getArgumentConversionPrice(
-                Integer.class, Integer.class));
-        assertEquals(10004, OverloadedNumberUtil.getArgumentConversionPrice(
-                Integer.class, Long.class));
-        assertEquals(10005, OverloadedNumberUtil.getArgumentConversionPrice(
-                Integer.class, BigInteger.class));
-        assertEquals(30006, OverloadedNumberUtil.getArgumentConversionPrice(
-                Integer.class, Float.class));
-        assertEquals(20007, OverloadedNumberUtil.getArgumentConversionPrice(
-                Integer.class, Double.class));
-        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
-                Integer.class, BigDecimal.class));
-        
-        assertEquals(45001, OverloadedNumberUtil.getArgumentConversionPrice(
-                BigDecimal.class, Byte.class));
-        assertEquals(44002, OverloadedNumberUtil.getArgumentConversionPrice(
-                BigDecimal.class, Short.class));
-        assertEquals(41003, OverloadedNumberUtil.getArgumentConversionPrice(
-                BigDecimal.class, Integer.class));
-        assertEquals(41004, OverloadedNumberUtil.getArgumentConversionPrice(
-                BigDecimal.class, Long.class));
-        assertEquals(40005, OverloadedNumberUtil.getArgumentConversionPrice(
-                BigDecimal.class, BigInteger.class));
-        assertEquals(33006, OverloadedNumberUtil.getArgumentConversionPrice(
-                BigDecimal.class, Float.class));
-        assertEquals(32007, OverloadedNumberUtil.getArgumentConversionPrice(
-                BigDecimal.class, Double.class));
-        assertEquals(0, OverloadedNumberUtil.getArgumentConversionPrice(
-                BigDecimal.class, BigDecimal.class));
-        
-        assertEquals(Integer.MAX_VALUE, OverloadedNumberUtil.getArgumentConversionPrice(
-                OverloadedNumberUtil.DoubleOrLong.class, Byte.class));
-        assertEquals(Integer.MAX_VALUE, OverloadedNumberUtil.getArgumentConversionPrice(
-                OverloadedNumberUtil.DoubleOrLong.class, Short.class));
-        assertEquals(Integer.MAX_VALUE, OverloadedNumberUtil.getArgumentConversionPrice(
-                OverloadedNumberUtil.DoubleOrLong.class, Integer.class));
-        assertEquals(21004, OverloadedNumberUtil.getArgumentConversionPrice(
-                OverloadedNumberUtil.DoubleOrLong.class, Long.class));
-        assertEquals(21005, OverloadedNumberUtil.getArgumentConversionPrice(
-                OverloadedNumberUtil.DoubleOrLong.class, BigInteger.class));
-        assertEquals(40006, OverloadedNumberUtil.getArgumentConversionPrice(
-                OverloadedNumberUtil.DoubleOrLong.class, Float.class));
-        assertEquals(0, OverloadedNumberUtil.getArgumentConversionPrice(
-                OverloadedNumberUtil.DoubleOrLong.class, Double.class));
-        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
-                OverloadedNumberUtil.DoubleOrLong.class, BigDecimal.class));
-        
-        assertEquals(Integer.MAX_VALUE, OverloadedNumberUtil.getArgumentConversionPrice(
-                OverloadedNumberUtil.BigIntegerOrDouble.class, Byte.class));
-        assertEquals(Integer.MAX_VALUE, OverloadedNumberUtil.getArgumentConversionPrice(
-                OverloadedNumberUtil.BigIntegerOrDouble.class, Short.class));
-        assertEquals(Integer.MAX_VALUE, OverloadedNumberUtil.getArgumentConversionPrice(
-                OverloadedNumberUtil.BigIntegerOrDouble.class, Integer.class));
-        assertEquals(Integer.MAX_VALUE, OverloadedNumberUtil.getArgumentConversionPrice(
-                OverloadedNumberUtil.BigIntegerOrDouble.class, Long.class));
-        assertEquals(0, OverloadedNumberUtil.getArgumentConversionPrice(
-                OverloadedNumberUtil.BigIntegerOrDouble.class, BigInteger.class));
-        assertEquals(40006, OverloadedNumberUtil.getArgumentConversionPrice(
-                OverloadedNumberUtil.BigIntegerOrDouble.class, Float.class));
-        assertEquals(20007, OverloadedNumberUtil.getArgumentConversionPrice(
-                OverloadedNumberUtil.BigIntegerOrDouble.class, Double.class));
-        assertEquals(10008, OverloadedNumberUtil.getArgumentConversionPrice(
-                OverloadedNumberUtil.BigIntegerOrDouble.class, BigDecimal.class));
-        
-        // Check if all fromC is present:
-        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
-                Byte.class, BigDecimal.class));
-        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
-                Short.class, BigDecimal.class));
-        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
-                Integer.class, BigDecimal.class));
-        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
-                Long.class, BigDecimal.class));
-        assertEquals(10008, OverloadedNumberUtil.getArgumentConversionPrice(
-                BigInteger.class, BigDecimal.class));
-        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
-                Float.class, BigDecimal.class));
-        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
-                Double.class, BigDecimal.class));
-        assertEquals(0, OverloadedNumberUtil.getArgumentConversionPrice(
-                BigDecimal.class, BigDecimal.class));
-        assertEquals(0, OverloadedNumberUtil.getArgumentConversionPrice(
-                OverloadedNumberUtil.IntegerBigDecimal.class, BigDecimal.class));
-        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
-                OverloadedNumberUtil.DoubleOrFloat.class, BigDecimal.class));
-        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
-                OverloadedNumberUtil.FloatOrByte.class, BigDecimal.class));
-        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
-                OverloadedNumberUtil.DoubleOrShort.class, BigDecimal.class));
-        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
-                OverloadedNumberUtil.FloatOrByte.class, BigDecimal.class));
-        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
-                OverloadedNumberUtil.FloatOrShort.class, BigDecimal.class));
-        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
-                OverloadedNumberUtil.FloatOrInteger.class, BigDecimal.class));
-        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
-                OverloadedNumberUtil.DoubleOrByte.class, BigDecimal.class));
-        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
-                OverloadedNumberUtil.DoubleOrIntegerOrFloat.class, BigDecimal.class));
-        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
-                OverloadedNumberUtil.DoubleOrInteger.class, BigDecimal.class));
-        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
-                OverloadedNumberUtil.DoubleOrLong.class, BigDecimal.class));
-        assertEquals(10008, OverloadedNumberUtil.getArgumentConversionPrice(
-                OverloadedNumberUtil.BigIntegerOrByte.class, BigDecimal.class));
-        assertEquals(10008, OverloadedNumberUtil.getArgumentConversionPrice(
-                OverloadedNumberUtil.BigIntegerOrShort.class, BigDecimal.class));
-        assertEquals(10008, OverloadedNumberUtil.getArgumentConversionPrice(
-                OverloadedNumberUtil.BigIntegerOrInteger.class, BigDecimal.class));
-        assertEquals(10008, OverloadedNumberUtil.getArgumentConversionPrice(
-                OverloadedNumberUtil.BigIntegerOrLong.class, BigDecimal.class));
-        assertEquals(10008, OverloadedNumberUtil.getArgumentConversionPrice(
-                OverloadedNumberUtil.BigIntegerOrFloat.class, BigDecimal.class));
-        assertEquals(10008, OverloadedNumberUtil.getArgumentConversionPrice(
-                OverloadedNumberUtil.BigIntegerOrDouble.class, BigDecimal.class));
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/ParameterListPreferabilityTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/ParameterListPreferabilityTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/ParameterListPreferabilityTest.java
deleted file mode 100644
index 3e6c2ed..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/ParameterListPreferabilityTest.java
+++ /dev/null
@@ -1,445 +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.model.impl;
-
-import java.io.Serializable;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.TreeMap;
-
-import org.apache.freemarker.core.util._NumberUtil;
-
-import junit.framework.TestCase;
-
-@SuppressWarnings("boxing")
-public class ParameterListPreferabilityTest extends TestCase {
-
-    public ParameterListPreferabilityTest(String name) {
-        super(name);
-    }
-    
-    public void testNumberical() {
-        // Note: the signature lists consists of the same elements, only their order changes depending on the type
-        // of the argument value.
-        
-        testAllCmpPermutationsInc(
-                new Class[][] {
-                    new Class[] { byte.class },
-                    new Class[] { Byte.class },
-                    new Class[] { short.class },
-                    new Class[] { Short.class },
-                    new Class[] { int.class },
-                    new Class[] { Integer.class },
-                    new Class[] { long.class },
-                    new Class[] { Long.class },
-                    new Class[] { BigInteger.class },
-                    new Class[] { float.class },
-                    new Class[] { Float.class },
-                    new Class[] { double.class },
-                    new Class[] { Double.class },
-                    new Class[] { BigDecimal.class },
-                    new Class[] { Number.class },
-                    new Class[] { Serializable.class },
-                    new Class[] { Object.class }
-                },
-                new Object[] { (byte) 1 });
-        
-        testAllCmpPermutationsInc(
-                new Class[][] {
-                    new Class[] { BigDecimal.class },
-                    new Class[] { BigInteger.class },
-                    new Class[] { int.class },
-                    new Class[] { Integer.class },
-                    new Class[] { long.class },
-                    new Class[] { Long.class },
-                    new Class[] { double.class },
-                    new Class[] { Double.class },
-                    new Class[] { float.class },
-                    new Class[] { Float.class },
-                    new Class[] { short.class },
-                    new Class[] { Short.class },
-                    new Class[] { byte.class },
-                    new Class[] { Byte.class },
-                    new Class[] { Number.class },
-                    new Class[] { Serializable.class },
-                    new Class[] { Object.class },
-                },
-                new Object[] { new OverloadedNumberUtil.IntegerBigDecimal(new BigDecimal("1")) });
-
-        testAllCmpPermutationsInc(
-                new Class[][] {
-                    new Class[] { BigDecimal.class },
-                    new Class[] { double.class },
-                    new Class[] { Double.class },
-                    new Class[] { float.class },
-                    new Class[] { Float.class },
-                    new Class[] { BigInteger.class },
-                    new Class[] { int.class },
-                    new Class[] { Integer.class },
-                    new Class[] { long.class },
-                    new Class[] { Long.class },
-                    new Class[] { short.class },
-                    new Class[] { Short.class },
-                    new Class[] { byte.class },
-                    new Class[] { Byte.class },
-                    new Class[] { Number.class },
-                    new Class[] { Serializable.class },
-                    new Class[] { Object.class },
-                },
-                new Object[] { new BigDecimal("1") /* possibly non-integer */ });
-        
-        testAllCmpPermutationsInc(
-                new Class[][] {
-                    new Class[] { float.class },
-                    new Class[] { Float.class },
-                    new Class[] { double.class },
-                    new Class[] { Double.class },
-                    new Class[] { BigDecimal.class },
-                    new Class[] { int.class },
-                    new Class[] { Integer.class },
-                    new Class[] { long.class },
-                    new Class[] { Long.class },
-                    new Class[] { short.class },
-                    new Class[] { Short.class },
-                    new Class[] { byte.class },
-                    new Class[] { Byte.class },
-                    new Class[] { BigInteger.class },
-                    new Class[] { Number.class },
-                    new Class[] { Serializable.class },
-                    new Class[] { Object.class },
-                },
-                new Object[] { new OverloadedNumberUtil.FloatOrByte(1f, (byte) 1) });
-        
-        testAllCmpPermutationsInc(
-                new Class[][] {
-                    new Class[] { int.class },
-                    new Class[] { Integer.class },
-                    new Class[] { long.class },
-                    new Class[] { Long.class },
-                    new Class[] { BigInteger.class },
-                    new Class[] { double.class },
-                    new Class[] { Double.class },
-                    new Class[] { BigDecimal.class },
-                    new Class[] { short.class },
-                    new Class[] { Short.class },
-                    new Class[] { float.class },
-                    new Class[] { Float.class },
-                    
-                    // Two incompatibles removed, would be removed in reality:
-                    new Class[] { byte.class },
-                    new Class[] { Byte.class },
-                    
-                    new Class[] { Number.class },
-                    new Class[] { Serializable.class },
-                    new Class[] { Object.class }
-                },
-                new Object[] { new OverloadedNumberUtil.IntegerOrShort(1, (short) 1) });
-        
-        testAllCmpPermutationsInc(
-                new Class[][] {
-                    new Class[] { long.class },
-                    new Class[] { Long.class },
-                    new Class[] { BigInteger.class },
-                    new Class[] { BigDecimal.class },
-                    new Class[] { double.class },
-                    new Class[] { Double.class },
-                    new Class[] { float.class },
-                    new Class[] { Float.class },
-                    // skip byte and short  as the would be equal with int (all invalid target types)
-                    new Class[] { int.class },  // In reality, this and Integer are removed as not-applicable overloads
-                    new Class[] { Integer.class },
-                    new Class[] { Number.class },
-                    new Class[] { Serializable.class },
-                    new Class[] { Object.class }
-                },
-                new Object[] { 1L });
-        
-        // Undecidable comparisons:
-        
-        testAllCmpPermutationsEqu(
-                new Class[][] {
-                        new Class[] { Byte.class },
-                        new Class[] { Short.class },
-                        new Class[] { Integer.class },
-                        new Class[] { Long.class },
-                        new Class[] { BigInteger.class },
-                        new Class[] { Float.class },
-                    },
-                    new Object[] { 1.0 });
-        
-        testAllCmpPermutationsEqu(
-                new Class[][] {
-                        new Class[] { byte.class },
-                        new Class[] { short.class },
-                        new Class[] { int.class },
-                        new Class[] { long.class },
-                        new Class[] { float.class },
-                    },
-                    new Object[] { 1.0 });
-    }
-    
-    public void testPrimitiveIsMoreSpecific() {
-        testAllCmpPermutationsInc(
-                new Class[][] {
-                    new Class[] { boolean.class },
-                    new Class[] { Boolean.class }
-                },
-                new Object[] { true });
-        testAllCmpPermutationsInc(
-                new Class[][] {
-                    new Class[] { char.class },
-                    new Class[] { Character.class }
-                },
-                new Object[] { 'x' });
-    }
-    
-    public void testCharIsMoreSpecificThanString() {
-        testAllCmpPermutationsInc(
-                new Class[][] {
-                    new Class[] { char.class },
-                    new Class[] { Character.class },
-                    new Class[] { String.class },
-                    new Class[] { CharSequence.class }
-                },
-                new Object[] { "s" });
-        testAllCmpPermutationsInc(
-                new Class[][] {
-                    new Class[] { char.class },
-                    new Class[] { Character.class },
-                    new Class[] { String.class }
-                },
-                new Object[] { 'c' });
-    }
-    
-    public void testClassHierarchy() {
-        testAllCmpPermutationsInc(
-                new Class[][] {
-                    new Class[] { LinkedHashMap.class },
-                    new Class[] { HashMap.class },
-                    new Class[] { Map.class },
-                    new Class[] { Object.class }
-                },
-                new Object[] { new LinkedHashMap() });
-        testAllCmpPermutationsInc(
-                new Class[][] {
-                    new Class[] { LinkedHashMap.class },
-                    new Class[] { Cloneable.class },
-                    new Class[] { Object.class }
-                },
-                new Object[] { new LinkedHashMap() });
-    }
-
-    public void testNumericalWithNonNumerical() {
-        testAllCmpPermutationsInc(
-                new Class[][] {
-                    new Class[] { int.class },
-                    new Class[] { Integer.class },
-                    new Class[] { Comparable.class },
-                    new Class[] { Object.class },
-                },
-                new Object[] { 1 });
-        testAllCmpPermutationsInc(
-                new Class[][] {
-                    new Class[] { int.class },
-                    new Class[] { Integer.class },
-                    new Class[] { char.class },
-                    new Class[] { Character.class },
-                },
-                new Object[] { 1 });
-    }
-    
-    public void testUnrelated() {
-        testAllCmpPermutationsEqu(
-                new Class[][] {
-                    new Class[] { Serializable.class },
-                    new Class[] { CharSequence.class },
-                    new Class[] { Comparable.class }
-                },
-                new Object[] { "s" });
-        
-        testAllCmpPermutationsEqu(
-                new Class[][] {
-                    new Class[] { HashMap.class },
-                    new Class[] { TreeMap.class }
-                },
-                new Object[] { null });
-    }
-
-    public void testMultiParameter() {
-        testAllCmpPermutationsInc(
-                new Class[][] {
-                    new Class[] { String.class, String.class, String.class },
-                        
-                    new Class[] { String.class, String.class, Object.class },
-                    new Class[] { String.class, Object.class, String.class },
-                    new Class[] { Object.class, String.class, String.class },
-                    
-                    new Class[] { String.class, Object.class, Object.class },
-                    new Class[] { Object.class, String.class, Object.class },
-                    new Class[] { Object.class, Object.class, String.class },
-                    
-                    new Class[] { Object.class, Object.class, Object.class },
-                },
-                new Object[] { "a", "b", "c" });
-        
-        testAllCmpPermutationsInc(
-                new Class[][] {
-                    new Class[] { String.class, String.class },
-                    new Class[] { String.class, Object.class },
-                    new Class[] { CharSequence.class, CharSequence.class },
-                    new Class[] { CharSequence.class, Object.class },
-                    new Class[] { Object.class, String.class },
-                    new Class[] { Object.class, CharSequence.class },
-                    new Class[] { Object.class, Object.class },
-                },
-                new Object[] { "a", "b" });
-        
-        // Subclassing is more important than primitive-VS-boxed:
-        testAllCmpPermutationsInc(
-                new Class[][] {
-                    new Class[] { boolean.class, boolean.class, boolean.class, String.class },
-                    new Class[] { Boolean.class, boolean.class, boolean.class, String.class },
-                    new Class[] { boolean.class, Boolean.class, Boolean.class, String.class },
-                    new Class[] { Boolean.class, boolean.class, Boolean.class, String.class },
-                    new Class[] { Boolean.class, Boolean.class, boolean.class, String.class },
-                    new Class[] { Boolean.class, Boolean.class, Boolean.class, String.class },
-                    new Class[] { Boolean.class, Boolean.class, Boolean.class, CharSequence.class },
-                    new Class[] { boolean.class, boolean.class, boolean.class, Object.class },
-                    new Class[] { Boolean.class, boolean.class, boolean.class, Object.class },
-                    new Class[] { boolean.class, Boolean.class, Boolean.class, Object.class },
-                    new Class[] { Boolean.class, boolean.class, Boolean.class, Object.class },
-                    new Class[] { Boolean.class, Boolean.class, boolean.class, Object.class },
-                    new Class[] { Boolean.class, Boolean.class, Boolean.class, Object.class },
-                },
-                new Object[] { true, false, true, "a" });
-        
-        // Subclassing is more important than primitive-VS-boxed:
-        testAllCmpPermutationsInc(
-                new Class[][] {
-                    new Class[] { int.class, int.class, int.class, String.class },
-                    new Class[] { Integer.class, int.class, int.class, String.class },
-                    new Class[] { int.class, Integer.class, Integer.class, String.class },
-                    new Class[] { Integer.class, int.class, Integer.class, String.class },
-                    new Class[] { Integer.class, Integer.class, int.class, String.class },
-                    new Class[] { Integer.class, Integer.class, Integer.class, String.class },
-                    new Class[] { Integer.class, Integer.class, Integer.class, CharSequence.class },
-                    new Class[] { int.class, int.class, int.class, Object.class },
-                    new Class[] { Integer.class, int.class, int.class, Object.class },
-                    new Class[] { int.class, Integer.class, Integer.class, Object.class },
-                    new Class[] { Integer.class, int.class, Integer.class, Object.class },
-                    new Class[] { Integer.class, Integer.class, int.class, Object.class },
-                    new Class[] { Integer.class, Integer.class, Integer.class, Object.class },
-                },
-                new Object[] { 1, 2, 3, "a" });
-    }
-
-    public void testVarargs() {
-        testAllCmpPermutationsInc(
-                new Class[][] {
-                    new Class[] { String.class, String[].class },
-                    new Class[] { String.class, CharSequence[].class },
-                    new Class[] { String.class, Object[].class },
-                },
-                new Object[] { "a", "b", "c" },
-                true);
-        
-        testAllCmpPermutationsInc(
-                new Class[][] {
-                    new Class[] { String.class, int[].class },
-                    new Class[] { String.class, Integer[].class },
-                    new Class[] { String.class, long[].class },
-                    new Class[] { String.class, Long[].class },
-                    new Class[] { String.class, double[].class },
-                    new Class[] { String.class, Double[].class },
-                    new Class[] { String.class, Serializable[].class },
-                    new Class[] { String.class, Object[].class },
-                },
-                new Object[] { "a", 1, 2, 3 },
-                true);
-        
-        // 0-long varargs list; in case of ambiguity, the varargs component type decides:
-        testAllCmpPermutationsInc(
-                new Class[][] {
-                    new Class[] { String.class, Object[].class },
-                    new Class[] { CharSequence.class, int[].class },
-                    new Class[] { CharSequence.class, Integer[].class },
-                    new Class[] { CharSequence.class, long[].class },
-                    new Class[] { CharSequence.class, Long[].class },
-                    new Class[] { CharSequence.class, double[].class },
-                    new Class[] { CharSequence.class, Double[].class },
-                    new Class[] { CharSequence.class, Serializable[].class },
-                    new Class[] { CharSequence.class, Object[].class },
-                    new Class[] { Object.class, int[].class },
-                },
-                new Object[] { "a" },
-                true);
-        
-        
-        // Different oms prefix length; in the case of ambiguity, the one with higher oms param count wins.
-        testAllCmpPermutationsInc(
-                new Class[][] {
-                    new Class[] { String.class, int.class, int.class, int[].class },
-                    new Class[] { String.class, int.class, int[].class },
-                    new Class[] { String.class, int[].class },
-                },
-                new Object[] { "a", 1, 2, 3 },
-                true);
-    }
-    
-    private void testAllCmpPermutationsInc(Class[][] sortedSignatures, Object[] args) {
-        testAllCmpPermutationsInc(sortedSignatures, args, false);
-    }
-
-    /**
-     * Compares all items with all other items in the provided descending sorted array of signatures, checking that
-     * for all valid indexes i and j, where j > i, it stands that sortedSignatures[i] > sortedSignatures[j].
-     * The comparisons are done with both operand orders, also each items is compared to itself too.
-     * 
-     * @param sortedSignatures method signatures sorted by decreasing specificity
-     */
-    private void testAllCmpPermutationsInc(Class[][] sortedSignatures, Object[] args, boolean varargs) {
-        final ArgumentTypes argTs = new ArgumentTypes(args);
-        for (int i = 0; i < sortedSignatures.length; i++) {
-            for (int j = 0; j < sortedSignatures.length; j++) {
-                assertEquals("sortedSignatures[" + i + "] <==> sortedSignatures [" + j + "]",
-                        _NumberUtil.getSignum(
-                                Integer.valueOf(j).compareTo(i)),
-                        _NumberUtil.getSignum(
-                                argTs.compareParameterListPreferability(
-                                        sortedSignatures[i], sortedSignatures[j], varargs)));
-            }
-        }
-    }
-
-    private void testAllCmpPermutationsEqu(Class[][] signatures, Object[] args) {
-        final ArgumentTypes argTs = new ArgumentTypes(args);
-        for (int i = 0; i < signatures.length; i++) {
-            for (int j = 0; j < signatures.length; j++) {
-                assertEquals("sortedSignatures[" + i + "] <==> sortedSignatures [" + j + "]",
-                        0,
-                        argTs.compareParameterListPreferability(signatures[i], signatures[j], false));
-            }
-        }
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/PrallelObjectIntrospectionTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/PrallelObjectIntrospectionTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/PrallelObjectIntrospectionTest.java
deleted file mode 100644
index 4f4c0a1..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/PrallelObjectIntrospectionTest.java
+++ /dev/null
@@ -1,43 +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.model.impl;
-
-import org.apache.freemarker.core.model.TemplateHashModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-
-public class PrallelObjectIntrospectionTest extends AbstractParallelIntrospectionTest {
-
-    public PrallelObjectIntrospectionTest(String name) {
-        super(name);
-    }
-
-    public static void main(String[] args) {
-        new PrallelObjectIntrospectionTest("almostForever")
-                .testReliability(Integer.MAX_VALUE);
-    }
-    
-    @Override
-    protected TemplateHashModel getWrappedEntity(int objIdx)
-    throws TemplateModelException {
-        return (TemplateHashModel) getObjectWrapper().wrap(
-                ManyObjectsOfDifferentClasses.OBJECTS[objIdx]);
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/PrallelStaticIntrospectionTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/PrallelStaticIntrospectionTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/PrallelStaticIntrospectionTest.java
deleted file mode 100644
index 836d559..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/PrallelStaticIntrospectionTest.java
+++ /dev/null
@@ -1,47 +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.model.impl;
-
-import org.apache.freemarker.core.model.TemplateHashModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-
-public class PrallelStaticIntrospectionTest extends AbstractParallelIntrospectionTest {
-
-    private static final String STATICS_CLASS_CONTAINER_CLASS_NAME
-            = ManyStaticsOfDifferentClasses.class.getName();
-
-    public PrallelStaticIntrospectionTest(String name) {
-        super(name);
-    }
-
-    public static void main(String[] args) {
-        new PrallelStaticIntrospectionTest("almostForever")
-                .testReliability(Integer.MAX_VALUE);
-    }
-    
-    @Override
-    protected TemplateHashModel getWrappedEntity(int clIdx)
-    throws TemplateModelException {
-        return (TemplateHashModel) getObjectWrapper().getStaticModels().get(
-                STATICS_CLASS_CONTAINER_CLASS_NAME + "$C"
-                + clIdx);
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/RationalNumber.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/RationalNumber.java b/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/RationalNumber.java
deleted file mode 100644
index 806a186..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/RationalNumber.java
+++ /dev/null
@@ -1,90 +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.model.impl;
-
-public final class RationalNumber extends Number {
-    
-    final int divident;
-    final int divisor;
-    
-    public RationalNumber(int divident, int divisor) {
-        this.divident = divident;
-        this.divisor = divisor;
-    }
-
-    @Override
-    public int intValue() {
-        return divident / divisor;
-    }
-
-    @Override
-    public long longValue() {
-        return divident / (long) divisor;
-    }
-
-    @Override
-    public float floatValue() {
-        return (float) (divident / (double) divisor);
-    }
-
-    @Override
-    public double doubleValue() {
-        return divident / (double) divisor;
-    }
-
-    public int getDivident() {
-        return divident;
-    }
-
-    public int getDivisor() {
-        return divisor;
-    }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + divident;
-        result = prime * result + divisor;
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        RationalNumber other = (RationalNumber) obj;
-        if (divident != other.divident)
-            return false;
-        if (divisor != other.divisor)
-            return false;
-        return true;
-    }
-
-    @Override
-    public String toString() {
-        return divident + "/" + divisor;
-    }
-    
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/StaticModelsTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/StaticModelsTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/StaticModelsTest.java
deleted file mode 100644
index 609d632..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/StaticModelsTest.java
+++ /dev/null
@@ -1,91 +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.model.impl;
-
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
-import java.util.ArrayList;
-
-import org.apache.freemarker.core.Configuration;
-import org.apache.freemarker.core.model.TemplateHashModel;
-import org.apache.freemarker.core.model.TemplateMethodModelEx;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateScalarModel;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class StaticModelsTest {
-
-    @Test
-    public void modelCaching() throws Exception {
-        DefaultObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).usePrivateCaches(true)
-                .build();
-        TemplateHashModel statics = ow.getStaticModels();
-        TemplateHashModel s = (TemplateHashModel) statics.get(S.class.getName());
-        assertNotNull(s);
-        assertNotNull(s.get("F"));
-        assertNotNull(s.get("m"));
-        try {
-            s.get("x");
-            fail();
-        } catch (TemplateModelException e) {
-            assertThat(e.getMessage(), containsString("No such key"));
-        }
-        
-        try {
-            statics.get("no.such.ClassExists");
-            fail();
-        } catch (TemplateModelException e) {
-            assertTrue(e.getCause() instanceof ClassNotFoundException);
-        }
-        
-        TemplateModel f = s.get("F");
-        assertTrue(f instanceof TemplateScalarModel);
-        assertEquals(((TemplateScalarModel) f).getAsString(), "F OK");
-        
-        TemplateModel m = s.get("m");
-        assertTrue(m instanceof TemplateMethodModelEx);
-        assertEquals(((TemplateScalarModel) ((TemplateMethodModelEx) m).exec(new ArrayList())).getAsString(), "m OK");
-        
-        assertSame(s, statics.get(S.class.getName()));
-        
-        ow.clearClassIntrospecitonCache();
-        TemplateHashModel sAfterClean = (TemplateHashModel) statics.get(S.class.getName());
-        assertNotSame(s, sAfterClean);
-        assertSame(sAfterClean, statics.get(S.class.getName()));
-        assertNotNull(sAfterClean.get("F"));
-        assertNotNull(sAfterClean.get("m"));
-    }
-    
-    public static class S {
-        
-        public static final String F = "F OK"; 
-        
-        public static String m() {
-            return "m OK";
-        }
-        
-    }
-    
-}


[03/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-alias1.ftlh.out
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-alias1.ftlh.out b/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-alias1.ftlh.out
deleted file mode 100644
index 717431f..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-alias1.ftlh.out
+++ /dev/null
@@ -1,22 +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.
- */
-10,000.00
-10.31
-23/Dec/15 10:09 PM
-2015-12-23T21:09:04.213Z

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-alias2.ftlh
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-alias2.ftlh b/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-alias2.ftlh
deleted file mode 100644
index 624950f..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-alias2.ftlh
+++ /dev/null
@@ -1,19 +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.
--->
-${10?string.@oct}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-alias2.ftlh.out
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-alias2.ftlh.out b/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-alias2.ftlh.out
deleted file mode 100644
index 08d0fea..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-alias2.ftlh.out
+++ /dev/null
@@ -1,19 +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.
- */
-12
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-modelAware.ftlh
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-modelAware.ftlh b/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-modelAware.ftlh
deleted file mode 100644
index 9a34ac0..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-modelAware.ftlh
+++ /dev/null
@@ -1,20 +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.
--->
-${10.12356}
-${weight}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-modelAware.ftlh.out
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-modelAware.ftlh.out b/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-modelAware.ftlh.out
deleted file mode 100644
index 25d6155..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/CustomFormatsExample-modelAware.ftlh.out
+++ /dev/null
@@ -1,20 +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.
- */
-10.1236
-1.5 kg
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/TemplateConfigurationExamples1.properties
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/TemplateConfigurationExamples1.properties b/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/TemplateConfigurationExamples1.properties
deleted file mode 100644
index faf8592..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/TemplateConfigurationExamples1.properties
+++ /dev/null
@@ -1,25 +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.
-
-templateConfigurations = \
-    ConditionalTemplateConfigurationFactory( \
-        FileExtensionMatcher("xml"), \
-        TemplateConfiguration( \
-            sourceEncoding = Charset("utf-8"), \
-            outputFormat = XMLOutputFormat() \
-        ) \
-    )
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/TemplateConfigurationExamples2.properties
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/TemplateConfigurationExamples2.properties b/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/TemplateConfigurationExamples2.properties
deleted file mode 100644
index f879e70..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/TemplateConfigurationExamples2.properties
+++ /dev/null
@@ -1,32 +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.
-
-templateConfigurations = \
-    ConditionalTemplateConfigurationFactory( \
-        PathGlobMatcher("mail/**"), \
-        FirstMatchTemplateConfigurationFactory( \
-            ConditionalTemplateConfigurationFactory( \
-                FileNameGlobMatcher("*.subject.*"), \
-                TemplateConfiguration(outputFormat = PlainTextOutputFormat()) \
-            ), \
-            ConditionalTemplateConfigurationFactory( \
-                FileNameGlobMatcher("*.body.*"), \
-                TemplateConfiguration(outputFormat = HTMLOutputFormat()) \
-            ), \
-            noMatchErrorDetails = 'Mail template names must contain ".subject." or ".body."!' \
-        ) \
-    )

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/TemplateConfigurationExamples3.properties
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/TemplateConfigurationExamples3.properties b/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/TemplateConfigurationExamples3.properties
deleted file mode 100644
index ce72fef..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/TemplateConfigurationExamples3.properties
+++ /dev/null
@@ -1,47 +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.
-
-templateConfigurations = \
-    MergingTemplateConfigurationFactory( \
-        ConditionalTemplateConfigurationFactory( \
-            FileNameGlobMatcher("*.stats.*"), \
-            TemplateConfiguration( \
-                dateTimeFormat = "iso", \
-                dateFormat = "iso", \
-                timeFormat = "iso", \
-                timeZone = TimeZone("UTC") \
-            ) \
-        ), \
-        ConditionalTemplateConfigurationFactory( \
-            PathGlobMatcher("mail/**"), \
-            TemplateConfiguration(sourceEncoding = Charset("utf-8")) \
-        ), \
-        FirstMatchTemplateConfigurationFactory( \
-            ConditionalTemplateConfigurationFactory( \
-                FileExtensionMatcher("xml"), \
-                TemplateConfiguration(outputFormat = XMLOutputFormat()) \
-            ), \
-            ConditionalTemplateConfigurationFactory( \
-                OrMatcher( \
-                    FileExtensionMatcher("html"), \
-                    FileExtensionMatcher("htm") \
-                ), \
-                TemplateConfiguration(outputFormat = HTMLOutputFormat()) \
-            ), \
-            allowNoMatch = true \
-        ) \
-    )

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/test.ftlh
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/test.ftlh b/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/test.ftlh
deleted file mode 100644
index 852b82b..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/manualtest/test.ftlh
+++ /dev/null
@@ -1,28 +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.
--->
-<html>
-<head>
-  <title>Welcome!</title>
-</head>
-<body>
-  <h1>Welcome ${user}!</h1>
-  <p>Our latest product:
-  <a href="${latestProduct.url}">${latestProduct.name}</a>!
-</body>
-</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/servlet/web.xml
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/servlet/web.xml b/freemarker-core/src/test/resources/org/apache/freemarker/test/servlet/web.xml
deleted file mode 100644
index e406b1a..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/servlet/web.xml
+++ /dev/null
@@ -1,101 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1" ?>
-<!--
-  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.
--->
-
-<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
-	version="2.4">
-
-	<servlet>
-		<servlet-name>controller</servlet-name>
-		<servlet-class>com.example.Model2ControllerServlet</servlet-class>
-	</servlet>
-
-	<servlet-mapping>
-		<servlet-name>controller</servlet-name>
-		<url-pattern>*.c</url-pattern>
-    </servlet-mapping>
-    <servlet-mapping>
-        <servlet-name>controller</servlet-name>
-        <url-pattern>/</url-pattern>
-	</servlet-mapping>
-
-	<servlet>
-		<servlet-name>freemarker</servlet-name>
-		<servlet-class>org.apache.freemarker.servlet.FreemarkerServlet</servlet-class>
-
-		<!-- FreemarkerServlet settings: -->
-		<init-param>
-			<param-name>TemplatePath</param-name>
-			<param-value>/</param-value>
-		</init-param>
-		<init-param>
-			<param-name>NoCache</param-name>
-			<param-value>true</param-value>
-		</init-param>
-		<init-param>
-			<param-name>ContentType</param-name>
-			<param-value>text/html; charset=UTF-8</param-value> <!-- Forces UTF-8 output encoding! -->
-		</init-param>
-
-		<!-- FreeMarker settings: -->
-		<init-param>
-			<param-name>incompatible_improvements</param-name>
-			<param-value>3.0.0</param-value>
-		</init-param>
-		<init-param>
-			<param-name>template_exception_handler</param-name>
-			<!-- Some may prefer "html_debug" for development. -->
-			<param-value>rethrow</param-value>
-		</init-param>
-		<init-param>
-			<param-name>template_update_delay</param-name>
-			<param-value>0</param-value> <!-- 0 is for development only! Use higher value otherwise. -->
-		</init-param>
-		<init-param>
-			<param-name>sourceEncoding</param-name>
-			<param-value>UTF-8</param-value> <!-- The encoding of the template files. -->
-		</init-param>
-		<init-param>
-			<param-name>number_format</param-name>
-			<param-value>0.##########</param-value>
-		</init-param>
-
-		<load-on-startup>1</load-on-startup>
-	</servlet>
-
-	<servlet-mapping>
-		<servlet-name>freemarker</servlet-name>
-		<url-pattern>*.ftl</url-pattern>
-	</servlet-mapping>
-
-	<!-- Prevent the visiting of MVC Views from outside the servlet container. 
-		RequestDispatcher.forward/include should and will still work. Removing this 
-		may open security holes! -->
-	<security-constraint>
-		<web-resource-collection>
-			<web-resource-name>FreeMarker MVC Views</web-resource-name>
-			<url-pattern>*.ftl</url-pattern>
-		</web-resource-collection>
-		<auth-constraint>
-			<!-- Nobody is allowed to visit these -->
-		</auth-constraint>
-	</security-constraint>
-
-</web-app>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/arithmetic.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/arithmetic.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/arithmetic.txt
deleted file mode 100644
index 33a7186..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/arithmetic.txt
+++ /dev/null
@@ -1,46 +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.
- */
-<html>
-<head>
-<title>FreeMarker: Arithmetic Test</title>
-</head>
-<body>
-
-<p>A simple test follows:</p>
-
-<p>Perform a number assignment:</p>
-
-
-3.234
-2.00
-0.6172500000000000000000000000000000000000
-1.620089104901
-1.6201
-
-<P>Display a number with at least 3 digits after the decimal point</P>
-
-1234.000
-
-<p>Now use numbers in assignment</p>
-
-
-1257.77
-
-</body>
-</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/boolean-formatting.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/boolean-formatting.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/boolean-formatting.txt
deleted file mode 100644
index 0bab0bc..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/boolean-formatting.txt
+++ /dev/null
@@ -1,31 +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.
- */
-Y Y Y
-N N N
-y y y
-n n n
-y y y
-n n n
-str:n str:n
-nein ja
-theStringValue theStringValue
-
-
-
-

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/boolean.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/boolean.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/boolean.txt
deleted file mode 100644
index 8dc1290..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/boolean.txt
+++ /dev/null
@@ -1,102 +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.
- */
-<html>
-<head>
-<title>FreeMarker: Boolean Values Test</title>
-</head>
-<body>
-
-<p>A simple test follows:</p>
-
-<p>Hello, world!</p>
-
-
-<p>Now perform scalar boolean tests:</p>
-
-<p>
-    b is true.<br />
-</p>
-
-<p>    This makes sense.<br />
-</p>
-
-<p>
-    boolean3 succeeded.<br />
-</p>
-
-<p>
-    boolean4 succeeded.<br />
-</p>
-
-<p>
-    boolean4 || boolean5 succeeded.<br />
-</p>
-
-<p>
-    boolean5 || boolean4 || boolean5 succeeded.<br />
-</p>
-
-<p>    boolean4 && boolean5 failed.<br />
-</p>
- 
-<p>Now test list models:</p>
-
-<p>
-    list1 succeeded.<br />
-</p>
-
-<p>
-    list2 succeeded.<br />
-</p>
-
-<p>Test hash models:</p>
-
-<p>
-    hash1 succeeded: Hello, world.<br />
-</p>
-
-<p>
-    hash2 succeeded.<br />
-</p>
-
-<p>Test not operator:</p>
-
-<p>
-   Not boolean1 succeeded
-</p>
-
-<p>
-   Not boolean1 succeeded
-</p>
-
-<p>   Not boolean2 failed
-</p>
-
-<p>   Not boolean2 failed
-</p>
-
-<p>
-   Message is "Hello, world!"
-</p>
-
-<p>   Message is "Hello, world!"
-</p>
-
-</body>
-</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/charset-in-header.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/charset-in-header.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/charset-in-header.txt
deleted file mode 100644
index 4532027..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/charset-in-header.txt
+++ /dev/null
@@ -1,26 +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.
- */
-<head>
-  <meta http-equiv="Content-type" content="text/html; charset=UTF-8">
-</head>
-<body>
-éáőű
-õÕûÛ
-őŐűŰ
-</body>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/comment.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/comment.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/comment.txt
deleted file mode 100644
index d5902e3..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/comment.txt
+++ /dev/null
@@ -1,34 +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.
- */
-<html>
-<head>
-<title>FreeMarker: Comment Test</title>
-</head>
-<body>
-	<p>Message exists!
-	</p>
-
-a  b
-a  b
-
-6
-7
-8
-</body>
-</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/comparisons.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/comparisons.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/comparisons.txt
deleted file mode 100644
index 8d9d372..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/comparisons.txt
+++ /dev/null
@@ -1,93 +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.
- */
-<html>
-<head>
-<title>FreeMarker: Numeric Operations Test</title>
-</head>
-<body>
-
-<p>A simple test follows:</p>
-
-<p>Hello, world!</p>
-
-<p>Start with the increment operator:</p>
-<p>a1 = 0</p>
-<p>a1 = 1</p>
-<p>a1 = 2</p>
-
-<p>Now the decrement operator:</p>
-<p>a2 = 5</p>
-<p>a2 = 4</p>
-<p>a2 = 3</p>
-<p>a2 = 2</p>
-<p>a2 = 1</p>
-<p>a2 = 0</p>
-<p>a2 = -1</p>
-
-<p>Now the add operator:</p>
-<p>op1 = 5, op2 = 3, op3 = 8</p>
-<p>op3 = 11</p>
-
-<p>And the subtract operator:</p>
-<p>op1 = 5, op2 = 3, op3 = 2</p>
-<p>op3 = -1</p>
-
-<p>The comparison operators:</p>
-   <p>Item is: 0</p>
-   <p>Item is less than five.</p>
-   <p>Item is less than or equals to seven.</p>
-   <p>Item is: 1</p>
-   <p>Item is less than five.</p>
-   <p>Item is less than or equals to seven.</p>
-   <p>Item is: 2</p>
-   <p>Item is less than five.</p>
-   <p>Item is less than or equals to seven.</p>
-   <p>Item is: 3</p>
-   <p>Item is less than five.</p>
-   <p>Item is less than or equals to seven.</p>
-   <p>Item is greater than two.</p>
-   <p>Item is: 4</p>
-   <p>Item is less than five.</p>
-   <p>Item is less than or equals to seven.</p>
-   <p>Item is greater than two.</p>
-   <p>Item is: 5</p>
-   <p>Item is less than or equals to seven.</p>
-   <p>Item is greater than two.</p>
-   <p>Item is: 6</p>
-   <p>Item is less than or equals to seven.</p>
-   <p>Item is greater than two.</p>
-   <p>Item is: 7</p>
-   <p>Item is less than or equals to seven.</p>
-   <p>Item is greater than two.</p>
-   <p>Item is: 8</p>
-   <p>Item is greater than two.</p>
-   <p>Item is: 9</p>
-   <p>Item is greater than two.</p>
-   <p>Item is: 10</p>
-   <p>Item is greater than two.</p>
-   <p>Item is greater than or equal to ten.</p>
-   <p>Item is: 11</p>
-   <p>Item is greater than two.</p>
-   <p>Item is greater than or equal to ten.</p>
-   <p>Item is: 12</p>
-   <p>Item is greater than two.</p>
-   <p>Item is greater than or equal to ten.</p>
-
-</body>
-</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/compress.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/compress.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/compress.txt
deleted file mode 100644
index 43c7eed..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/compress.txt
+++ /dev/null
@@ -1,40 +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.
- */
-<html>
-<head>
-<title>FreeMarker: Compress Test</title>
-</head>
-<body>
-
-<p>A simple test follows:</p>
-
-<p>Hello, world!</p>
-
-<p>This is the same message, using the &quot;compress&quot; tag:</p>
-<p>Hello, world!</p>
-<p>This is the same message, using the &quot;StandardCompress&quot; transform model:</p>
-<p>Hello, world!</p>
-<p>This multi-line message should be compressed to a single line.</p>
-
-<p>An example where the first character is not whitespace but the second character is:</p>
-<p>x y</p>
-
-<p>The end.</p>
-</body>
-</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/dateformat-java.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/dateformat-java.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/dateformat-java.txt
deleted file mode 100644
index 9180262..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/dateformat-java.txt
+++ /dev/null
@@ -1,55 +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.
- */
-Nov 15, 2002 2:54:13 PM
-Nov 15, 2002 2:54:13 PM
-Nov 15, 2002 2:54:13 PM
-Nov 15, 2002 2:54:13 PM
-11/15/02 2:54 PM
-Nov 15, 2002 2:54:13 PM
-November 15, 2002 2:54:13 PM GMT
-11/15/02 2:54 PM
-11/15/02 2:54:13 PM
-11/15/02 2:54:13 PM GMT
-Nov 15, 2002 2:54 PM
-Nov 15, 2002 2:54:13 PM
-Nov 15, 2002 2:54:13 PM GMT
-November 15, 2002 2:54 PM
-November 15, 2002 2:54:13 PM
-November 15, 2002 2:54:13 PM GMT
-Nov 15, 2002
-Nov 15, 2002
-11/15/02
-Nov 15, 2002
-November 15, 2002
-2:54:13 PM
-2:54:13 PM
-2:54 PM
-2:54:13 PM
-2:54:13 PM GMT
-2002. november 15. 14:54:13 GMT
-Fri, 15 Nov 02002 14:54:13 GMT
-Fri, 15 Nov 2002 14:54:13 GMT
-Fri, 15 Nov 2002 14:54:13 GMT
-2002
-
-2002
-2002
-
-2002
-11
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/default-object-wrapper.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/default-object-wrapper.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/default-object-wrapper.txt
deleted file mode 100644
index e015315..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/default-object-wrapper.txt
+++ /dev/null
@@ -1,55 +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.
- */
-array-0
-array-1
-2
-array-0
-array-1
-list-0
-list-1
-list-2
-3
-not empty
-list-0
-value
-objValue
-foo-value
-hasfoo
-nobaz
-bar-value-0
-foo-value
-overloaded-int-1
-overloaded-String-String
-Message
-1974-11-14
-static-method
-static-overloaded-int-1
-static-overloaded-String-String
-static-final-field
-static-field
-ONEx
-TWOx
-THREEx
-true
-false
-false
-42
-1
-m
-

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/default-xmlns.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/default-xmlns.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/default-xmlns.txt
deleted file mode 100644
index 3a52c46..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/default-xmlns.txt
+++ /dev/null
@@ -1,25 +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.
- */
-No NS = No NS
-x NS = x NS
-y NS = y NS
-x NS = x NS
-
-true
-

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/default.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/default.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/default.txt
deleted file mode 100644
index fd48463..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/default.txt
+++ /dev/null
@@ -1,26 +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.
- */
-foo
-
-luck
-
-
-0
-
-   UNDEFINED is undefined.

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/encoding-builtins.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/encoding-builtins.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/encoding-builtins.txt
deleted file mode 100644
index ccfe5c8..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/encoding-builtins.txt
+++ /dev/null
@@ -1,44 +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.
- */
-FreeMarker: Encoding built-in tests
-
-html: [&amp;&lt;&gt;&quot;&#39;{}\a/]
-xml:  [&amp;&lt;&gt;&quot;&apos;{}\a/]
-xhtml: [&amp;&lt;&gt;&quot;&#39;{}\a/]
-rtf:  [&<>"'\{\}\\a/]
-html: [a&amp;a&lt;a&gt;a&quot;a&#39;a{a}a\]
-xml:  [a&amp;a&lt;a&gt;a&quot;a&apos;a{a}a\]
-xhtml: [a&amp;a&lt;a&gt;a&quot;a&#39;a{a}a\]
-rtf:  [a&a<a>a"a'a\{a\}a\\]
-html: [&lt;&lt;&lt;&lt;&lt;]
-xml:  [&lt;&lt;&lt;&lt;&lt;]
-xhtml: [&lt;&lt;&lt;&lt;&lt;]
-rtf:  [\{\{\{\{\{]
-html: []
-xml:  []
-xhtml: []
-rtf:  []
-html: [a]
-xml:  [a]
-xhtml: [a]
-rtf:  [a]
-html: [&amp;]
-xml:  [&amp;]
-xhtml: [&amp;]
-rtf:  [\{]
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/escapes.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/escapes.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/escapes.txt
deleted file mode 100644
index c0a5440..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/escapes.txt
+++ /dev/null
@@ -1,49 +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.
- */
-a
-b
-c
-a
-b
-c
-a
-1
-a
-b
-c
-&lt;&amp;&gt;
-&amp;lt;&amp;amp;&amp;gt;
-&lt;&amp;&gt;
----
-<Mooo> = <Mooo>
-  <MOOO> = <MOOO>
-    &LT;MOOO&GT; = &lt;MOOO&gt;
-      <MOOO> = <MOOO>
-    &LT;MOOO&GT; = &lt;MOOO&gt;
-  <MOOO> = <MOOO>
-    <Mooo> = <Mooo>
-      &lt;Mooo&gt; = &lt;Mooo&gt;
-        <Mooo> = <Mooo>
-      &lt;Mooo&gt; = &lt;Mooo&gt;
-    <Mooo> = <Mooo>
-  <MOOO> = <MOOO>
-  red green blue
----
-  <A&amp;B>[a&b](A&B) <A&amp;B2>[a&b2](A&B2)
-    <{a&amp;b}A&amp;B>[{a&b}a&b]({a&b}A&B) <{a&amp;b2}A&amp;B2>[{a&b2}a&b2]({a&b2}A&B2)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/exception.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/exception.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/exception.txt
deleted file mode 100644
index 0ea4395..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/exception.txt
+++ /dev/null
@@ -1,43 +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.
- */
-<html>
-<head>
-<title>FreeMarker: Exception Test</title>
-</head>
-<body>
-
-<p>A simple test follows:</p>
-
-<p>Hello, world! <br />
-freemarker.template.TemplateModelException: Throwing from ExceptionModel!
-	at freemarker.test.templatesuite.models.ExceptionModel.getAsString(ExceptionModel.java:57)
-	at freemarker.template.compiler.Expression.getStringValue(Expression.java:65)
-	at freemarker.template.compiler.DollarVariable.process(DollarVariable.java:62)
-	at freemarker.template.compiler.NestedTemplateElements.process(NestedTemplateElements.java:76)
-	at freemarker.template.Template.process(Template.java:266)
-	at freemarker.template.Template.process(Template.java:289)
-	at freemarker.test.TestException.runTest(TestException.java:91)
-	at junit.framework.TestCase.runBare(TestCase.java:140)
-	at junit.framework.TestResult$1.protect(TestResult.java:106)
-	at junit.framework.TestResult.runProtected(TestResult.java:124)
-	at junit.framework.TestResult.run(TestResult.java:109)
-	at junit.framework.TestCase.run(TestCase.java:131)
-	at junit.framework.TestSuite.runTest(TestSuite.java:173)
-	at junit.framework.TestSuite.run(TestSuite.java:168)
-	at junit.swingui.TestRunner$17.run(TestRunner.java:644)

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/exception2.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/exception2.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/exception2.txt
deleted file mode 100644
index bf441d3..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/exception2.txt
+++ /dev/null
@@ -1,47 +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.
- */
-<html>
-<head>
-<title>FreeMarker: Exception Test</title>
-</head>
-<body>
-
-<p>A simple test follows:</p>
-
-<p>Hello, world! <br />
-<!-- Template Error: Couldn't get value of variable test: Couldn't read string value of test: freemarker.template.TemplateModelException: Throwing from ExceptionModel!
-	at freemarker.test.templatesuite.models.ExceptionModel.getAsString(ExceptionModel.java:42)
-	at freemarker.template.expression.Variable.getValue(Variable.java:69)
-	at freemarker.template.instruction.VariableInstruction.process(VariableInstruction.java:55)
-	at freemarker.template.compiler.TemplateArrayList.process(TemplateArrayList.java:69)
-	at freemarker.template.Template.process(Template.java:226)
-	at freemarker.test.TestException2.runTest(TestException2.java:83)
-	at junit.framework.TestCase.runBare(TestCase.java:140)
-	at junit.framework.TestResult$1.protect(TestResult.java:106)
-	at junit.framework.TestResult.runProtected(TestResult.java:124)
-	at junit.framework.TestResult.run(TestResult.java:109)
-	at junit.framework.TestCase.run(TestCase.java:131)
-	at junit.framework.TestSuite.runTest(TestSuite.java:173)
-	at junit.framework.TestSuite.run(TestSuite.java:168)
-	at junit.swingui.TestRunner$17.run(TestRunner.java:644)
- -->
-</p>
-
-</body>
-</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/exception3.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/exception3.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/exception3.txt
deleted file mode 100644
index 6089e87..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/exception3.txt
+++ /dev/null
@@ -1,21 +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.
- */
-<html><head></head><body bgcolor="#ffffff">
-Template Compilation Error: Identifier expected at line 10.
-</body></html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/exthash.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/exthash.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/exthash.txt
deleted file mode 100644
index acb1f78..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/exthash.txt
+++ /dev/null
@@ -1,76 +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.
- */
-<html>
-<head>
-<title>FreeMarker: Extended Hash Test</title>
-</head>
-<body>
-
-<p>A simple test follows:</p>
-
-<p>Hello, world!</p>
-
-<p>A hash set of 8 animals follows:</p>
-
-<p>
-  elephant, 
-
-  cat, 
-
-  zebra, 
-
-  dog, 
-
-  aardvark, 
-
-  kiwi, 
-
-  squirrel, 
-
-  gecko.
-</p>
-
-<p>The first animal is an elephant, and the last is a 
-gecko.</p>
-
-<p>A hash set of 8 digits follows:<p>
-
-<p>
-  six, 
-
-  four, 
-
-  eight, 
-
-  five, 
-
-  one, 
-
-  two, 
-
-  seven, 
-
-  three.
-</p>
-
-<p>The zebra number is eight.</p>
-
-<p>The end.</p>
-</body>
-</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/hashconcat.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/hashconcat.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/hashconcat.txt
deleted file mode 100644
index 9736322..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/hashconcat.txt
+++ /dev/null
@@ -1,138 +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.
- */
-
-a:
-  a = 1
-  b = 2
-  c = 3
-  X = 4
-  ---
-  1
-  2
-  3
-  4
-  ---
-
-B:
-  d = 10
-  e = 20
-  f = 30
-  X = 40
-  ---
-  10
-  20
-  30
-  40
-  ---
-
-a + B:
-  a = 1
-  b = 2
-  c = 3
-  X = 40
-  d = 10
-  e = 20
-  f = 30
-  ---
-  1
-  2
-  3
-  40
-  10
-  20
-  30
-  ---
-
-B + a:
-  d = 10
-  e = 20
-  f = 30
-  X = 4
-  a = 1
-  b = 2
-  c = 3
-  ---
-  10
-  20
-  30
-  4
-  1
-  2
-  3
-  ---
-
-a + a:
-  a = 1
-  b = 2
-  c = 3
-  X = 4
-  ---
-  1
-  2
-  3
-  4
-  ---
-
-{} + a:
-  a = 1
-  b = 2
-  c = 3
-  X = 4
-  ---
-  1
-  2
-  3
-  4
-  ---
-
-a + {}:
-  a = 1
-  b = 2
-  c = 3
-  X = 4
-  ---
-  1
-  2
-  3
-  4
-  ---
-
-{} + {}:
-  ---
-  ---
-
-a + b + {} + b + {} + a:
-  a = 1
-  b = 2
-  c = 3
-  X = 4
-  d = 10
-  e = 20
-  f = 30
-  ---
-  1
-  2
-  3
-  4
-  10
-  20
-  30
-  ---
-
-

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/hashliteral.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/hashliteral.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/hashliteral.txt
deleted file mode 100644
index 3af1052..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/hashliteral.txt
+++ /dev/null
@@ -1,74 +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.
- */
-<html>
-<head>
-<title>FreeMarker: Hash Literal Test</title>
-</head>
-<body>
-
-<p>A simple test follows:</p>
-
-<p>Hello, world!</p>
-
-<p>Now perform a hash assignment:</p>
-
-
-test23
-Hello, world!
-hello all
-1
-
-<p>Now update the assignment and repeat:</p>
-
-
-test23
-Hello, world!
-hello all
-
-1
-
-<p>Now reassign the list and repeat:</p>
-
-
-test23
-Hello, world!
-
-
-1
-Temporary
-Temporary
-Temporary
-
-<p>Pathological case: zero item hash:</p>
-
-
-
-<p>Hash of number literals:</p>
-2
-
-<p>Hash concatenation:</p>
-a => 1
-b => 3
-c => 4
-
-<p>Empty hash concatenation:</p>
-foo, bar
-
-</body>
-</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/helloworld.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/helloworld.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/helloworld.txt
deleted file mode 100644
index b1072fd..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/helloworld.txt
+++ /dev/null
@@ -1,31 +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.
- */
-<html>
-<head>
-<title>FreeMarker: Exec Model Test</title>
-</head>
-<body>
-
-<p>A simple test follows:</p>
-
-<p>Hello, world!
-</p>
-
-</body>
-</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/identifier-escaping.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/identifier-escaping.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/identifier-escaping.txt
deleted file mode 100644
index 1c62bd5..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/identifier-escaping.txt
+++ /dev/null
@@ -1,57 +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.
- */
-
-<a-b>red123</a-b>
-
-f-a works
-
-dash-dash-dash etc.
-dash-dash-dash etc.
-propVal
-propVal
-
-List: 123
-
-Switch: OK
-ESCAPED
-
-
-as1
-as2
-as3
-as4
-as5
-
-<catchAll x=1 y=2 a:b.c=5 data-foo=4 z=3 />
-
----.: = dash-dash-dash etc.
-@as@_a = as1
-as/b = as3
-as'c = as4
-as"d = as5
-as-c = as2
-catchAll = ...
-dumpNS = ...
-f-a = ...
-hash = ...
-ls:a = ...
-m/b2 = ...
-m-a = ...
-m-b2 = ...
-sw-a = ...
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/identifier-non-ascii.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/identifier-non-ascii.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/identifier-non-ascii.txt
deleted file mode 100644
index 8a8d04f..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/identifier-non-ascii.txt
+++ /dev/null
@@ -1,19 +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.
- */
-Korean Keyboard

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/if.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/if.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/if.txt
deleted file mode 100644
index 7c9d1d8..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/if.txt
+++ /dev/null
@@ -1,104 +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.
- */
-
-- good
-- good
-- good
-- good
-
-- good
-- good
-
-- good
-- good
-- good
-- good
-
-- good
-- good
-- good
-- good
-
-- good
-- good
-- good
-- good
-
-- good
-- good
-
-- good
-- good
-- good
-- good
-
-- good
-- good
-- good
-- good
-
-- 1
-- 
-- 
-- is 1
-- isn't 2
-- isn't 3
-- Finally, it's: 1
-- 
-- 2
-- 
-- isn't 1
-- is 2
-- isn't 3
-- Finally, it's: 2
-- 
-- 
-- 3
-- isn't 1
-- isn't 2
-- is 3
-- Finally, it's: 3
-- 
-- 
-- 
-- isn't 1
-- isn't 2
-- isn't 3
-- Finally, it's: 4
-
-    1:
-      == 1
-    1:
-      <= 2
-    1:
-      <= 3
-    2:
-      > 1
-    2:
-      == 2
-    2:
-      <= 3
-    3:
-      > 1
-    3:
-      > 2
-    3:
-      == 3
-      End
-

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/import.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/import.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/import.txt
deleted file mode 100644
index b51a4f4..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/import.txt
+++ /dev/null
@@ -1,40 +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.
- */
---
---
-
-
-jsmith@acme.com
-  Test bar.
-  Email: jsmith@acme.com
-
-jsmith@acme.com
-  Test bar.
-  Email: jsmith@acme.com
-    Email in the root: jsmith@other1.com
-
-jsmith@other2.com
-  Test bar.
-  Email: jsmith@other2.com
-    Email in the root: jsmith@other1.com
-
-jsmith@other2.com
-jsmith@other3.com
-
-foobarfoobar
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/include.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/include.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/include.txt
deleted file mode 100644
index c72d69c..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/include.txt
+++ /dev/null
@@ -1,67 +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.
- */
-<html>
-<head>
-<title>FreeMarker: Include Instruction Test</title>
-</head>
-<body>
-
-<p>A simple test follows:</p>
-
-Hello, world!
-
-	<p>Message exists!
-
-<p>Test normal includes:</p>
-<p>A test of included files:</p>
-
-	<p>Message exists!:<br />
-        Hello, world!</p>
-
- Can you see me? 
-
-assigning from included template
-I'm here, mon!
-
-Kilroy
- Can you see me? Kilroy
-
-<p>Test subdir includes:</p>
-<p>This is include-subdir.ftl</p>
-<p>Testing including from same directory</p>
-<p>This is include-subdir2.ftl</p>
-<p>Testing including from relative parent</p>
-<p>A test of included files:</p>
-
-	<p>Message exists!:<br />
-        Hello, world!</p>
-
- Can you see me? 
-<p>Testing including from loader root</p>
-<p>A test of included files:</p>
-
-	<p>Message exists!:<br />
-        Hello, world!</p>
-
- Can you see me? 
-<p>Testing including through acquisition</p>
-<p>This is include-subdir2.ftl</p>
-</body>
-</html>
-

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/include2.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/include2.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/include2.txt
deleted file mode 100644
index b7c43a9..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/include2.txt
+++ /dev/null
@@ -1,28 +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.
- */
-A próba
-A próba
-
-A próba
-A próba
-A próba
-A próba
-
-[]
-[]

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/interpret.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/interpret.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/interpret.txt
deleted file mode 100644
index fe862e6..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/interpret.txt
+++ /dev/null
@@ -1,23 +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.
- */
-abcdef
-abcdef
-abcdef
-
-M
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/iterators.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/iterators.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/iterators.txt
deleted file mode 100644
index fb44def..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/iterators.txt
+++ /dev/null
@@ -1,84 +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.
- */
-<html>
-<head>
-<title>FreeMarker: List Iterator Test</title>
-</head>
-<body>
-
-<p>A simple test follows:</p>
-
-<p>Hello, world!</p>
-
-<p>Now iterate over a list:</p>
-
-<p>one</p>
-<p>two</p>
-<p>three</p>
-<p>four</p>
-<p>five</p>
-
-<p>Now iterate again:</p>
-
-<p>0. one</p>
-<p>1. two</p>
-<p>2. three</p>
-<p>3. four</p>
-<p>4. five</p>
-
-<p>Iterate over a list in a hash:</p>
-
-<p>one</p>
-<p>two</p>
-<p>three</p>
-<p>four</p>
-<p>five</p>
-
-<p>one</p>
-<p>two</p>
-<p>three</p>
-<p>four</p>
-<p>five</p>
-
-<p>one</p>
-<p>two</p>
-<p>three</p>
-<p>four</p>
-<p>five</p>
-
-<p>one</p>
-<p>two</p>
-<p>three</p>
-<p>four</p>
-<p>five</p>
-
-<p>one</p>
-<p>two</p>
-<p>three</p>
-<p>four</p>
-<p>five</p>
-
-<p>one</p>
-<p>two</p>
-<p>three</p>
-<p>four</p>
-<p>five</p>
-
-</body>
-</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/lastcharacter.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/lastcharacter.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/lastcharacter.txt
deleted file mode 100644
index dbe5fd0..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/lastcharacter.txt
+++ /dev/null
@@ -1,31 +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.
- */
-<html>
-<head>
-<title>FreeMarker: Last Character Test</title>
-</head>
-<body>
-
-<p>A simple test follows:</p>
-  
-    13
-    
-    ELLO, WORLD!
-    
-    message: Hello, Worl

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/list-bis.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/list-bis.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/list-bis.txt
deleted file mode 100644
index 3b9b76d..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/list-bis.txt
+++ /dev/null
@@ -1,51 +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.
- */
-    0: a [0:A, 1:B, 2:C]
-    1: b [0:A, 1:B, 2:C]
-    2: c [0:A, 1:B, 2:C]
-
-    0: a 0a/0A, 0a/1B, 0a/2C
-    1: b 1b/0A, 1b/1B, 1b/2C
-    2: c 2c/0A, 2c/1B, 2c/2C
-
-0:a, 1:b, 2:c
-1. a; 2. b; 3. c;
-
-a, b, c
-a, b, c
-
-A, b, c.
-
-true/false false/true true/false
-
-    <td class="oddRow">a</td>
-    <td class="evenRow">b</td>
-    <td class="oddRow">c</td>
-
-    <td class="rowOdd">a</td>
-    <td class="rowEven">b</td>
-    <td class="rowOdd">c</td>
-
-    <td class="R">a</td>
-    <td class="G">b</td>
-    <td class="B">c</td>
-    <td class="R">d</td>
-    <td class="G">e</td>
-    <td class="B">f</td>
-    <td class="R">g</td>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/list.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/list.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/list.txt
deleted file mode 100644
index 05373bd..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/list.txt
+++ /dev/null
@@ -1,51 +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.
- */
-Size: 4
-Items: @0 aardvark, @1 bear, @2 cat, @3 dog.
-
-Size: 1
-Items: @0 aardvark.
-
-Size: 0
-Items: 
-
-Size: 3
-Items: @0 11, @1 22, @2 33.
-
-Size: 3
-Items: @0 11, @1 22, @2 33.
-
-Size: 3
-Items: @0 11, @1 22, @2 33.
-
-Size: failed
-Items: @0 11, @1 22, @2 33.
-
-Size: 0
-Items: 
-
-Size: 0
-Items: 
-
-Size: 0
-Items: 
-
-Size: failed
-Items: 
-

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/list2.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/list2.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/list2.txt
deleted file mode 100644
index cb9e6d4..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/list2.txt
+++ /dev/null
@@ -1,211 +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.
- */
-=== [aardvark, bear, cat, dog] ===
-
--- List+sep:
-    aardvark,
-    bear,
-    cat,
-    dog
--- List+else:
-    aardvark
-    bear
-    cat
-    dog
--- List+items:
-    [
-        aardvark
-        bear
-        cat
-        dog
-    ]
--- List+items+else:
-    [
-        aardvark
-        bear
-        cat
-        dog
-    ]
--- List+items+sep+else:
-    [
-        aardvark,
-        bear,
-        cat,
-        dog
-    ]
---
-
-=== [aardvark] ===
-
--- List+sep:
-    aardvark
--- List+else:
-    aardvark
--- List+items:
-    [
-        aardvark
-    ]
--- List+items+else:
-    [
-        aardvark
-    ]
--- List+items+sep+else:
-    [
-        aardvark
-    ]
---
-
-=== [] ===
-
--- List+sep:
--- List+else:
-    Empty!
--- List+items:
--- List+items+else:
-    Empty!
--- List+items+sep+else:
-    Empty!
---
-
-=== [11, 22, 33] ===
-
--- List+sep:
-    11,
-    22,
-    33
--- List+else:
-    11
-    22
-    33
--- List+items:
-    [
-        11
-        22
-        33
-    ]
--- List+items+else:
-    [
-        11
-        22
-        33
-    ]
--- List+items+sep+else:
-    [
-        11,
-        22,
-        33
-    ]
---
-
-=== [11, 22, 33] ===
-
--- List+sep:
-    11,
-    22,
-    33
--- List+else:
-    11
-    22
-    33
--- List+items:
-    [
-        11
-        22
-        33
-    ]
--- List+items+else:
-    [
-        11
-        22
-        33
-    ]
--- List+items+sep+else:
-    [
-        11,
-        22,
-        33
-    ]
---
-
-=== [11, 22, 33] ===
-
--- List+sep:
-    11,
-    22,
-    33
--- List+else:
-    11
-    22
-    33
--- List+items:
-    [
-        11
-        22
-        33
-    ]
--- List+items+else:
-    [
-        11
-        22
-        33
-    ]
--- List+items+sep+else:
-    [
-        11,
-        22,
-        33
-    ]
---
-
-=== [] ===
-
--- List+sep:
--- List+else:
-    Empty!
--- List+items:
--- List+items+else:
-    Empty!
--- List+items+sep+else:
-    Empty!
---
-
-=== [] ===
-
--- List+sep:
--- List+else:
-    Empty!
--- List+items:
--- List+items+else:
-    Empty!
--- List+items+sep+else:
-    Empty!
---
-
-=== [] ===
-
--- List+sep:
--- List+else:
-    Empty!
--- List+items:
--- List+items+else:
-    Empty!
--- List+items+sep+else:
-    Empty!
---
-

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/list3.txt
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/list3.txt b/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/list3.txt
deleted file mode 100644
index 26fc60d..0000000
--- a/freemarker-core/src/test/resources/org/apache/freemarker/test/templatesuite/expected/list3.txt
+++ /dev/null
@@ -1,57 +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.
- */
-[
-    [(11@0, 11@0), (11@0, 22@1), (11@0, 33@2)],
-    [(22@1, 11@0), (22@1, 22@1), (22@1, 33@2)],
-    [(33@2, 11@0), (33@2, 22@1), (33@2, 33@2)]
-]
-
-
-        <p>2 hits:
-        <div class="hits">
-                        <div class="hit">a</div>
-                        <div class="hit">b</div>
-        </div>
-
-        <p>2 hits:
-        <div class="hits">
-                        <div class="hitOther">a</div>
-                        <div class="hitOther">b</div>
-        </div>
-
-        <p>2 hits:
-        <div class="hits">
-                    ...
-        </div>
-
-        <p>Nothing.
-
-11, 22, ...
-[11, 22, ...]
-
-1, 2, 3
-1 /*first*/, 2, 3
-[1, 2, 3]
-1
-1
-[1]
-Empty
-Empty
-Empty
-



[37/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/templateresolver/TemplateConfigurationFactoryTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/templateresolver/TemplateConfigurationFactoryTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/templateresolver/TemplateConfigurationFactoryTest.java
new file mode 100644
index 0000000..a7259d8
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/templateresolver/TemplateConfigurationFactoryTest.java
@@ -0,0 +1,203 @@
+/*
+ * 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.templateresolver;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.freemarker.core.TemplateConfiguration;
+import org.junit.Test;
+
+public class TemplateConfigurationFactoryTest {
+    
+    @Test
+    public void testCondition1() throws IOException, TemplateConfigurationFactoryException {
+        TemplateConfiguration tc = newTemplateConfiguration(1);
+        
+        TemplateConfigurationFactory tcf = new ConditionalTemplateConfigurationFactory(new FileNameGlobMatcher("*.ftlx"), tc);
+
+        assertNotApplicable(tcf, "x.ftl");
+        assertApplicable(tcf, "x.ftlx", tc);
+    }
+
+    @Test
+    public void testCondition2() throws IOException, TemplateConfigurationFactoryException {
+        TemplateConfiguration tc = newTemplateConfiguration(1);
+        
+        TemplateConfigurationFactory tcf = new ConditionalTemplateConfigurationFactory(
+                new FileNameGlobMatcher("*.ftlx"),
+                new ConditionalTemplateConfigurationFactory(
+                        new FileNameGlobMatcher("x.*"), tc));
+
+        assertNotApplicable(tcf, "x.ftl");
+        assertNotApplicable(tcf, "y.ftlx");
+        assertApplicable(tcf, "x.ftlx", tc);
+    }
+
+    @Test
+    public void testMerging() throws IOException, TemplateConfigurationFactoryException {
+        TemplateConfiguration tc1 = newTemplateConfiguration(1);
+        TemplateConfiguration tc2 = newTemplateConfiguration(2);
+        TemplateConfiguration tc3 = newTemplateConfiguration(3);
+        
+        TemplateConfigurationFactory tcf = new MergingTemplateConfigurationFactory(
+                new ConditionalTemplateConfigurationFactory(new FileNameGlobMatcher("*.ftlx"), tc1),
+                new ConditionalTemplateConfigurationFactory(new FileNameGlobMatcher("*a*.*"), tc2),
+                new ConditionalTemplateConfigurationFactory(new FileNameGlobMatcher("*b*.*"), tc3));
+
+        assertNotApplicable(tcf, "x.ftl");
+        assertApplicable(tcf, "x.ftlx", tc1);
+        assertApplicable(tcf, "a.ftl", tc2);
+        assertApplicable(tcf, "b.ftl", tc3);
+        assertApplicable(tcf, "a.ftlx", tc1, tc2);
+        assertApplicable(tcf, "b.ftlx", tc1, tc3);
+        assertApplicable(tcf, "ab.ftl", tc2, tc3);
+        assertApplicable(tcf, "ab.ftlx", tc1, tc2, tc3);
+        
+        assertNotApplicable(new MergingTemplateConfigurationFactory(), "x.ftl");
+    }
+
+    @Test
+    public void testFirstMatch() throws IOException, TemplateConfigurationFactoryException {
+        TemplateConfiguration tc1 = newTemplateConfiguration(1);
+        TemplateConfiguration tc2 = newTemplateConfiguration(2);
+        TemplateConfiguration tc3 = newTemplateConfiguration(3);
+        
+        FirstMatchTemplateConfigurationFactory tcf = new FirstMatchTemplateConfigurationFactory(
+                new ConditionalTemplateConfigurationFactory(new FileNameGlobMatcher("*.ftlx"), tc1),
+                new ConditionalTemplateConfigurationFactory(new FileNameGlobMatcher("*a*.*"), tc2),
+                new ConditionalTemplateConfigurationFactory(new FileNameGlobMatcher("*b*.*"), tc3));
+
+        try {
+            assertNotApplicable(tcf, "x.ftl");
+        } catch (TemplateConfigurationFactoryException e) {
+            assertThat(e.getMessage(), containsString("x.ftl"));
+        }
+        tcf.setNoMatchErrorDetails("Test details");
+        try {
+            assertNotApplicable(tcf, "x.ftl");
+        } catch (TemplateConfigurationFactoryException e) {
+            assertThat(e.getMessage(), containsString("Test details"));
+        }
+        
+        tcf.setAllowNoMatch(true);
+        
+        assertNotApplicable(tcf, "x.ftl");
+        assertApplicable(tcf, "x.ftlx", tc1);
+        assertApplicable(tcf, "a.ftl", tc2);
+        assertApplicable(tcf, "b.ftl", tc3);
+        assertApplicable(tcf, "a.ftlx", tc1);
+        assertApplicable(tcf, "b.ftlx", tc1);
+        assertApplicable(tcf, "ab.ftl", tc2);
+        assertApplicable(tcf, "ab.ftlx", tc1);
+        
+        assertNotApplicable(new FirstMatchTemplateConfigurationFactory().allowNoMatch(true), "x.ftl");
+    }
+
+    @Test
+    public void testComplex() throws IOException, TemplateConfigurationFactoryException {
+        TemplateConfiguration tcA = newTemplateConfiguration(1);
+        TemplateConfiguration tcBSpec = newTemplateConfiguration(2);
+        TemplateConfiguration tcBCommon = newTemplateConfiguration(3);
+        TemplateConfiguration tcHH = newTemplateConfiguration(4);
+        TemplateConfiguration tcHtml = newTemplateConfiguration(5);
+        TemplateConfiguration tcXml = newTemplateConfiguration(6);
+        TemplateConfiguration tcNWS = newTemplateConfiguration(7);
+        
+        TemplateConfigurationFactory tcf = new MergingTemplateConfigurationFactory(
+                new FirstMatchTemplateConfigurationFactory(
+                        new ConditionalTemplateConfigurationFactory(new PathGlobMatcher("a/**"), tcA),
+                        new ConditionalTemplateConfigurationFactory(new PathGlobMatcher("b/**"),
+                                new MergingTemplateConfigurationFactory(
+                                    new ConditionalTemplateConfigurationFactory(new FileNameGlobMatcher("*"), tcBCommon),
+                                    new ConditionalTemplateConfigurationFactory(new FileNameGlobMatcher("*.s.*"), tcBSpec))))
+                        .allowNoMatch(true),
+                new FirstMatchTemplateConfigurationFactory(
+                        new ConditionalTemplateConfigurationFactory(new FileNameGlobMatcher("*.hh"), tcHH),
+                        new ConditionalTemplateConfigurationFactory(new FileNameGlobMatcher("*.*h"), tcHtml),
+                        new ConditionalTemplateConfigurationFactory(new FileNameGlobMatcher("*.*x"), tcXml))
+                        .allowNoMatch(true),
+                new ConditionalTemplateConfigurationFactory(new FileNameGlobMatcher("*.nws.*"), tcNWS));
+
+        assertNotApplicable(tcf, "x.ftl");
+        assertApplicable(tcf, "b/x.ftl", tcBCommon);
+        assertApplicable(tcf, "b/x.s.ftl", tcBCommon, tcBSpec);
+        assertApplicable(tcf, "b/x.s.ftlh", tcBCommon, tcBSpec, tcHtml);
+        assertApplicable(tcf, "b/x.s.nws.ftlx", tcBCommon, tcBSpec, tcXml, tcNWS);
+        assertApplicable(tcf, "a/x.s.nws.ftlx", tcA, tcXml, tcNWS);
+        assertApplicable(tcf, "a.hh", tcHH);
+        assertApplicable(tcf, "a.nws.hh", tcHH, tcNWS);
+    }
+
+    @SuppressWarnings("boxing")
+    private TemplateConfiguration newTemplateConfiguration(int id) {
+        TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
+        tcb.setCustomAttribute("id", id);
+        tcb.setCustomAttribute("contains" + id, true);
+        return tcb.build();
+    }
+
+    private void assertNotApplicable(TemplateConfigurationFactory tcf, String sourceName)
+            throws IOException, TemplateConfigurationFactoryException {
+        assertNull(tcf.get(sourceName, DummyTemplateLoadingSource.INSTANCE));
+    }
+
+    private void assertApplicable(TemplateConfigurationFactory tcf, String sourceName, TemplateConfiguration... expectedTCs)
+            throws IOException, TemplateConfigurationFactoryException {
+        TemplateConfiguration mergedTC = tcf.get(sourceName, DummyTemplateLoadingSource.INSTANCE);
+        List<Object> mergedTCAttNames = new ArrayList<>(mergedTC.getCustomAttributes().keySet());
+
+        for (TemplateConfiguration expectedTC : expectedTCs) {
+            Integer tcId = (Integer) expectedTC.getCustomAttribute("id");
+            if (tcId == null) {
+                fail("TemplateConfiguration-s must be created with newTemplateConfiguration(id) in this test");
+            }
+            if (!mergedTCAttNames.contains("contains" + tcId)) {
+                fail("TemplateConfiguration with ID " + tcId + " is missing from the asserted value");
+            }
+        }
+        
+        for (Object attKey: mergedTCAttNames) {
+            if (!containsCustomAttr(attKey, expectedTCs)) {
+                fail("The asserted TemplateConfiguration contains an unexpected custom attribute: " + attKey);
+            }
+        }
+        
+        assertEquals(expectedTCs[expectedTCs.length - 1].getCustomAttribute("id"), mergedTC.getCustomAttribute("id"));
+    }
+
+    private boolean containsCustomAttr(Object attKey, TemplateConfiguration... expectedTCs) {
+        for (TemplateConfiguration expectedTC : expectedTCs) {
+            if (expectedTC.getCustomAttribute(attKey) != null) {
+                return true;
+            }
+        }
+        return false;
+    }
+    
+    @SuppressWarnings("serial")
+    private static class DummyTemplateLoadingSource implements TemplateLoadingSource {
+        private static DummyTemplateLoadingSource INSTANCE = new DummyTemplateLoadingSource();
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/templateresolver/TemplateNameFormatTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/templateresolver/TemplateNameFormatTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/templateresolver/TemplateNameFormatTest.java
new file mode 100644
index 0000000..3a24bfc
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/templateresolver/TemplateNameFormatTest.java
@@ -0,0 +1,330 @@
+/*
+ * 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.templateresolver;
+
+import static org.apache.freemarker.test.hamcerst.Matchers.*;
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.util.Locale;
+
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.Template;
+import org.apache.freemarker.core.TemplateNotFoundException;
+import org.apache.freemarker.core.templateresolver.impl.ByteArrayTemplateLoader;
+import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormat;
+import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormatFM2;
+import org.apache.freemarker.test.MonitoredTemplateLoader;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+
+
+public class TemplateNameFormatTest {
+
+    @Test
+    public void testToRootBasedName() throws MalformedTemplateNameException {
+        // Path that are treated the same both in 2.3 and 2.4 format:
+        for (TemplateNameFormat tnf : new TemplateNameFormat[] {
+                DefaultTemplateNameFormatFM2.INSTANCE, DefaultTemplateNameFormat.INSTANCE }) {
+            // Relative paths:
+            // - No scheme:
+            assertEquals("a/b", tnf.toRootBasedName("a/", "b"));
+            assertEquals("/a/b", tnf.toRootBasedName("/a/", "b"));
+            assertEquals("a/b", tnf.toRootBasedName("a/f", "b"));
+            assertEquals("/a/b", tnf.toRootBasedName("/a/f", "b"));
+            // - Scheme:
+            assertEquals("s://a/b", tnf.toRootBasedName("s://a/", "b"));
+            assertEquals("s:///a/b", tnf.toRootBasedName("s:///a/", "b"));
+            assertEquals("s://a/b", tnf.toRootBasedName("s://a/f", "b"));
+            assertEquals("s:///a/b", tnf.toRootBasedName("s:///a/f", "b"));
+            assertEquals("s://b", tnf.toRootBasedName("s://f", "b"));
+            assertEquals("s:///b", tnf.toRootBasedName("s:///f", "b"));
+            
+            // Absolute paths:
+            // - No scheme:
+            assertEquals("b", tnf.toRootBasedName("a/", "/b"));
+            assertEquals("b", tnf.toRootBasedName("/a/", "/b"));
+            assertEquals("b", tnf.toRootBasedName("a/s:/f/", "/b"));
+            // - Scheme:
+            assertEquals("s://b", tnf.toRootBasedName("s://x/", "/b"));
+            assertEquals("s://b", tnf.toRootBasedName("s:///x/", "/b"));
+            
+            // Schemed absolute paths:
+            assertEquals("s://b", tnf.toRootBasedName("a/", "s://b"));
+            assertEquals("s://b", tnf.toRootBasedName("i://a/", "s://b"));
+        }
+        
+        // Scheme names in 2.4 format only:
+        {
+            final TemplateNameFormat tnf = DefaultTemplateNameFormat.INSTANCE;
+            assertEquals("s:b", tnf.toRootBasedName("s:f", "b"));
+            assertEquals("s:/b", tnf.toRootBasedName("s:/f", "b"));
+            assertEquals("s:b", tnf.toRootBasedName("s:f", "/b"));
+            assertEquals("s:b", tnf.toRootBasedName("s:/f", "/b"));
+            assertEquals("s:f/b", tnf.toRootBasedName("s:f/", "b"));
+            assertEquals("s:/f/b", tnf.toRootBasedName("s:/f/", "b"));
+            assertEquals("s:b", tnf.toRootBasedName("s:f/", "/b"));
+            assertEquals("s:b", tnf.toRootBasedName("s:/f/", "/b"));
+            assertEquals("s:b", tnf.toRootBasedName("s:/f/", "/b"));
+            assertEquals("b", tnf.toRootBasedName("a/s://f/", "/b"));
+        }
+        
+        // Scheme names in 2.3 format only:
+        {
+            final TemplateNameFormat tnf = DefaultTemplateNameFormatFM2.INSTANCE;
+            assertEquals("a/s://b", tnf.toRootBasedName("a/s://f/", "/b"));
+        }
+    }
+
+    @Test
+    public void testNormalizeRootBasedName() throws MalformedTemplateNameException {
+        // Normalizations that are the same in legacy and modern format:
+        for (TemplateNameFormat tnf : new TemplateNameFormat[] {
+                DefaultTemplateNameFormatFM2.INSTANCE, DefaultTemplateNameFormat.INSTANCE }) {
+            assertEquals("", tnf.normalizeRootBasedName(""));
+            for (String lead : new String[] { "", "/" }) {
+                assertEquals("foo", tnf.normalizeRootBasedName(lead + "foo"));
+                assertEquals("foo", tnf.normalizeRootBasedName(lead + "./foo"));
+                assertEquals("foo", tnf.normalizeRootBasedName(lead + "./././foo"));
+                assertEquals("foo", tnf.normalizeRootBasedName(lead + "bar/../foo"));
+                assertEquals("a/b/", tnf.normalizeRootBasedName("a/b/"));
+                assertEquals("a/", tnf.normalizeRootBasedName("a/b/../"));
+                assertEquals("a/c../..d/e*/*f", tnf.normalizeRootBasedName("a/c../..d/e*/*f"));
+                assertEquals("", tnf.normalizeRootBasedName(""));
+                assertEquals("foo/bar/*", tnf.normalizeRootBasedName("foo/bar/*"));
+                assertEquals("schema://", tnf.normalizeRootBasedName("schema://"));
+                
+                assertThrowsWithBackingOutException(lead + "bar/../../x/foo", tnf);
+                assertThrowsWithBackingOutException(lead + "../x", tnf);
+                assertThrowsWithBackingOutException(lead + "../../../x", tnf);
+                assertThrowsWithBackingOutException(lead + "../../../x", tnf);
+                assertThrowsWithBackingOutException("x://../../../foo", tnf);
+                
+                {
+                    final String name = lead + "foo\u0000";
+                    try {
+                        tnf.normalizeRootBasedName(name);
+                        fail();
+                    } catch (MalformedTemplateNameException e) {
+                        assertEquals(name, e.getTemplateName());
+
+                        assertThat(e.getMalformednessDescription(), containsStringIgnoringCase("null character"));
+                    }
+                }
+            }
+        }
+        
+        // ".." and "."
+        assertEqualsOn23AndOn24("bar/foo", "foo", "bar/./../foo");
+        
+        // Even number of leading ".."-s bug:
+        assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24("foo", "../../foo");
+        assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24("foo", "../../../../foo");
+        
+        // ".." and "*"
+        assertEqualsOn23AndOn24("a/b/foo", "a/*/foo", "a/b/*/../foo");
+        //
+        assertEqualsOn23AndOn24("a/foo", "foo", "a/b/*/../../foo");
+        //
+        assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24("foo", "a/b/*/../../../foo");
+        //
+        assertEqualsOn23AndOn24("a/b/*/foo", "a/*/foo", "a/b/*/*/../foo");
+        //
+        assertEqualsOn23AndOn24("a/b/*/c/foo", "a/b/*/foo", "a/b/*/c/*/../foo");
+        //
+        assertEqualsOn23AndOn24("a/b/*/c/foo", "a/b/*/foo", "a/b/*/c/d/*/../../foo");
+        //
+        assertEqualsOn23AndOn24("a/*//b/*/c/foo", "a/*/b/*/foo", "a/*//b/*/c/d/*/../../foo");
+        //
+        assertEqualsOn23AndOn24("*", "", "a/../*");
+        //
+        assertEqualsOn23AndOn24("*/", "", "a/../*/");
+        
+        // ".." and "scheme"
+        assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24("x:/foo", "x://../foo");
+        //
+        assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24("foo", "x://../../foo");
+        //
+        assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24("x:../foo", "x:../foo");
+        //
+        assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24("foo", "x:../../foo");
+
+        // Tricky cases with terminating "/":
+        assertEqualsOn23AndOn24("/", "", "/");
+        // Terminating "/.." (produces terminating "/"):
+        assertEqualsOn23AndOn24("foo/bar/..", "foo/", "foo/bar/..");
+        // Terminating "/." (produces terminating "/"):
+        assertEqualsOn23AndOn24("foo/bar/.", "foo/bar/", "foo/bar/.");
+        
+        // Lonely "."
+        assertEqualsOn23AndOn24(".", "", ".");
+        // Lonely ".."
+        assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24("..", "..");
+        // Lonely "*"
+        
+        // Eliminating redundant "//":
+        assertEqualsOn23AndOn24("foo//bar", "foo/bar", "foo//bar");
+        //
+        assertEqualsOn23AndOn24("///foo//bar///baaz////wombat", "foo/bar/baaz/wombat", "////foo//bar///baaz////wombat");
+        //
+        assertEqualsOn23AndOn24("scheme://foo", "scheme://foo", "scheme://foo");
+        //
+        assertEqualsOn23AndOn24("scheme://foo//x/y", "scheme://foo/x/y", "scheme://foo//x/y");
+        //
+        assertEqualsOn23AndOn24("scheme:///foo", "scheme://foo", "scheme:///foo");
+        //
+        assertEqualsOn23AndOn24("scheme:////foo", "scheme://foo", "scheme:////foo");
+        
+        // Eliminating redundant "*"-s:
+        assertEqualsOn23AndOn24("a/*/*/b", "a/*/b", "a/*/*/b");
+        //
+        assertEqualsOn23AndOn24("a/*/*/*/b", "a/*/b", "a/*/*/*/b");
+        //
+        assertEqualsOn23AndOn24("*/*/b", "b", "*/*/b");
+        //
+        assertEqualsOn23AndOn24("*/*/b", "b", "/*/*/b");
+        //
+        assertEqualsOn23AndOn24("b/*/*", "b/*", "b/*/*");
+        //
+        assertEqualsOn23AndOn24("b/*/*/*", "b/*", "b/*/*/*");
+        //
+        assertEqualsOn23AndOn24("*/a/*/b/*/*/c", "a/*/b/*/c", "*/a/*/b/*/*/c");
+        
+        // New kind of scheme handling:
+
+        assertEquals("s:a/b", DefaultTemplateNameFormat.INSTANCE.normalizeRootBasedName("s:a/b"));
+        assertEquals("s:a/b", DefaultTemplateNameFormat.INSTANCE.normalizeRootBasedName("s:/a/b"));
+        assertEquals("s://a/b", DefaultTemplateNameFormat.INSTANCE.normalizeRootBasedName("s://a/b"));
+        assertEquals("s://a/b", DefaultTemplateNameFormat.INSTANCE.normalizeRootBasedName("s:///a/b"));
+        assertEquals("s://a/b", DefaultTemplateNameFormat.INSTANCE.normalizeRootBasedName("s:////a/b"));
+        
+        // Illegal use a of ":":
+        assertNormRBNameThrowsColonExceptionOn24("a/b:c/d");
+        assertNormRBNameThrowsColonExceptionOn24("a/b:/..");
+    }
+    
+    @Test
+    public void assertBackslashNotSpecialWith23() throws IOException {
+        MonitoredTemplateLoader tl = new MonitoredTemplateLoader();
+        tl.putTextTemplate("foo\\bar.ftl", "");
+
+        Configuration cfg = new TestConfigurationBuilder().templateLoader(tl).build();
+
+        {
+            final String name = "foo\\bar.ftl";
+            
+            Template t = cfg.getTemplate(name, Locale.US);
+            assertEquals(name, t.getLookupName());
+            assertEquals(name, t.getSourceName());
+            assertEquals(
+                    ImmutableList.of(
+                            "foo\\bar_en_US.ftl",
+                            "foo\\bar_en.ftl",
+                            name),
+                    tl.getLoadNames());
+            tl.clearEvents();
+        }
+
+        try {
+            cfg.getTemplate("foo\\missing.ftl", Locale.US);
+            fail();
+        } catch (TemplateNotFoundException e) {
+            assertEquals("foo\\missing.ftl", e.getTemplateName());
+            assertEquals(
+                    ImmutableList.of(
+                            "foo\\missing_en_US.ftl",
+                            "foo\\missing_en.ftl",
+                            "foo\\missing.ftl"),
+                    tl.getLoadNames());
+            tl.clearEvents();
+            cfg.clearTemplateCache();
+        }
+        
+        {
+            final String name = "foo/bar\\..\\bar.ftl";
+            try {
+                cfg.getTemplate(name, Locale.US);
+                fail();
+            } catch (TemplateNotFoundException e) {
+                assertEquals(name, e.getTemplateName());
+            }
+        }
+        
+    }
+
+    @Test
+    public void assertBackslashNotAllowed() throws IOException {
+        Configuration cfg = new TestConfigurationBuilder()
+                .templateLoader(new ByteArrayTemplateLoader())
+                .templateNameFormat(DefaultTemplateNameFormat.INSTANCE)
+                .build();
+        try {
+            cfg.getTemplate("././foo\\bar.ftl", Locale.US);
+            fail();
+        } catch (MalformedTemplateNameException e) {
+            assertThat(e.getMessage(), containsStringIgnoringCase("backslash"));
+        }
+        
+    }
+    
+    private void assertEqualsOn23AndOn24(String expected23, String expected24, String name)
+            throws MalformedTemplateNameException {
+        assertEquals(expected23, DefaultTemplateNameFormatFM2.INSTANCE.normalizeRootBasedName(name));
+        assertEquals(expected24, DefaultTemplateNameFormat.INSTANCE.normalizeRootBasedName(name));
+    }
+
+    private void assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24(final String expected23, final String name)
+            throws MalformedTemplateNameException {
+        assertEquals(expected23, DefaultTemplateNameFormatFM2.INSTANCE.normalizeRootBasedName(name));
+        assertThrowsWithBackingOutException(name, DefaultTemplateNameFormat.INSTANCE);
+    }
+
+    private void assertThrowsWithBackingOutException(final String name, final TemplateNameFormat tnf) {
+        try {
+            tnf.normalizeRootBasedName(name);
+            fail();
+        } catch (MalformedTemplateNameException e) {
+            assertEquals(name, e.getTemplateName());
+            assertBackingOutFromRootException(e);
+        }
+    }
+
+    private void assertNormRBNameThrowsColonExceptionOn24(final String name) throws MalformedTemplateNameException {
+        try {
+            DefaultTemplateNameFormat.INSTANCE.normalizeRootBasedName(name);
+            fail();
+        } catch (MalformedTemplateNameException e) {
+            assertEquals(name, e.getTemplateName());
+            assertColonException(e);
+        }
+    }
+    
+    private void assertBackingOutFromRootException(MalformedTemplateNameException e) {
+        assertThat(e.getMessage(), containsStringIgnoringCase("backing out"));
+    }
+
+    private void assertColonException(MalformedTemplateNameException e) {
+        assertThat(e.getMessage(), containsString("':'"));
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/templateresolver/TemplateSourceMatcherTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/templateresolver/TemplateSourceMatcherTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/templateresolver/TemplateSourceMatcherTest.java
new file mode 100644
index 0000000..51273c0
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/templateresolver/TemplateSourceMatcherTest.java
@@ -0,0 +1,188 @@
+/*
+ * 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.templateresolver;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+
+import org.junit.Test;
+
+public class TemplateSourceMatcherTest {
+    
+    @Test
+    public void testPathGlobMatcher() throws IOException {
+        PathGlobMatcher m = new PathGlobMatcher("**/a/?.ftl");
+        assertTrue(m.matches("a/b.ftl", "dummy"));
+        assertTrue(m.matches("x/a/c.ftl", "dummy"));
+        assertFalse(m.matches("a/b.Ftl", "dummy"));
+        assertFalse(m.matches("b.ftl", "dummy"));
+        assertFalse(m.matches("a/bc.ftl", "dummy"));
+        
+        m = new PathGlobMatcher("**/a/?.ftl").caseInsensitive(true);
+        assertTrue(m.matches("A/B.FTL", "dummy"));
+        m.setCaseInsensitive(false);
+        assertFalse(m.matches("A/B.FTL", "dummy"));
+        
+        try {
+            new PathGlobMatcher("/b.ftl");
+            fail();
+        } catch (IllegalArgumentException e) {
+            // Expected
+        }
+    }
+
+    @Test
+    public void testFileNameGlobMatcher() throws IOException {
+        FileNameGlobMatcher m = new FileNameGlobMatcher("a*.ftl");
+        assertTrue(m.matches("ab.ftl", "dummy"));
+        assertTrue(m.matches("dir/ab.ftl", "dummy"));
+        assertTrue(m.matches("/dir/dir/ab.ftl", "dummy"));
+        assertFalse(m.matches("Ab.ftl", "dummy"));
+        assertFalse(m.matches("bb.ftl", "dummy"));
+        assertFalse(m.matches("ab.ftl/x", "dummy"));
+
+        m = new FileNameGlobMatcher("a*.ftl").caseInsensitive(true);
+        assertTrue(m.matches("AB.FTL", "dummy"));
+        m.setCaseInsensitive(false);
+        assertFalse(m.matches("AB.FTL", "dummy"));
+        
+        m = new FileNameGlobMatcher("\u00E1*.ftl").caseInsensitive(true);
+        assertTrue(m.matches("\u00C1b.ftl", "dummy"));
+        
+        try {
+            new FileNameGlobMatcher("dir/a*.ftl");
+            fail();
+        } catch (IllegalArgumentException e) {
+            // Expected
+        }
+    }
+
+    @Test
+    public void testFileExtensionMatcher() throws IOException {
+        FileExtensionMatcher m = new FileExtensionMatcher("ftlx");
+        assertTrue(m.matches("a.ftlx", "dummy"));
+        assertTrue(m.matches(".ftlx", "dummy"));
+        assertTrue(m.matches("b/a.b.ftlx", "dummy"));
+        assertTrue(m.matches("b/a.ftlx", "dummy"));
+        assertTrue(m.matches("c.b/a.ftlx", "dummy"));
+        assertFalse(m.matches("a.ftl", "dummy"));
+        assertFalse(m.matches("ftlx", "dummy"));
+        assertFalse(m.matches("b.ftlx/a.ftl", "dummy"));
+        
+        assertTrue(m.isCaseInsensitive());
+        assertTrue(m.matches("a.fTlX", "dummy"));
+        m.setCaseInsensitive(false);
+        assertFalse(m.matches("a.fTlX", "dummy"));
+        assertTrue(m.matches("A.ftlx", "dummy"));
+        
+        m = new FileExtensionMatcher("");
+        assertTrue(m.matches("a.", "dummy"));
+        assertTrue(m.matches(".", "dummy"));
+        assertFalse(m.matches("a", "dummy"));
+        assertFalse(m.matches("", "dummy"));
+        assertFalse(m.matches("a.x", "dummy"));
+        
+        m = new FileExtensionMatcher("html.t");
+        assertTrue(m.matches("a.html.t", "dummy"));
+        assertFalse(m.matches("a.xhtml.t", "dummy"));
+        assertFalse(m.matches("a.html", "dummy"));
+        assertFalse(m.matches("a.t", "dummy"));
+        
+        try {
+            new FileExtensionMatcher("*.ftlx");
+            fail();
+        } catch (IllegalArgumentException e) {
+            // Expected
+        }
+        try {
+            new FileExtensionMatcher("ftl?");
+            fail();
+        } catch (IllegalArgumentException e) {
+            // Expected
+        }
+        try {
+            new FileExtensionMatcher(".ftlx");
+            fail();
+        } catch (IllegalArgumentException e) {
+            // Expected
+        }
+        try {
+            new FileExtensionMatcher("dir/a.ftl");
+            fail();
+        } catch (IllegalArgumentException e) {
+            // Expected
+        }
+    }
+    
+    @Test
+    public void testPathRegexMatcher() throws IOException {
+        PathRegexMatcher m = new PathRegexMatcher("a/[a-z]+\\.ftl");
+        assertTrue(m.matches("a/b.ftl", "dummy"));
+        assertTrue(m.matches("a/abc.ftl", "dummy"));
+        assertFalse(m.matches("b.ftl", "dummy"));
+        assertFalse(m.matches("b/b.ftl", "dummy"));
+        
+        try {
+            new PathRegexMatcher("/b.ftl");
+            fail();
+        } catch (IllegalArgumentException e) {
+            // Expected
+        }
+    }
+    
+    @Test
+    public void testAndMatcher() throws IOException {
+        AndMatcher m = new AndMatcher(new PathGlobMatcher("a*.*"), new PathGlobMatcher("*.t"));
+        assertTrue(m.matches("ab.t", "dummy"));
+        assertFalse(m.matches("bc.t", "dummy"));
+        assertFalse(m.matches("ab.ftl", "dummy"));
+        
+        try {
+            new AndMatcher();
+            fail();
+        } catch (IllegalArgumentException e) {
+            // Expected
+        }
+    }
+    
+    @Test
+    public void testOrMatcher() throws IOException {
+        OrMatcher m = new OrMatcher(new PathGlobMatcher("a*.*"), new PathGlobMatcher("*.t"));
+        assertTrue(m.matches("ab.t", "dummy"));
+        assertTrue(m.matches("bc.t", "dummy"));
+        assertTrue(m.matches("ab.ftl", "dummy"));
+        assertFalse(m.matches("bc.ftl", "dummy"));
+        
+        try {
+            new OrMatcher();
+            fail();
+        } catch (IllegalArgumentException e) {
+            // Expected
+        }
+    }
+    
+    @Test
+    public void testNotMatcher() throws IOException {
+        NotMatcher m = new NotMatcher(new PathGlobMatcher("a*.*"));
+        assertFalse(m.matches("ab.t", "dummy"));
+        assertTrue(m.matches("bc.t", "dummy"));
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/AppMetaTemplateDateFormatFactory.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/AppMetaTemplateDateFormatFactory.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/AppMetaTemplateDateFormatFactory.java
new file mode 100644
index 0000000..1d69dd8
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/AppMetaTemplateDateFormatFactory.java
@@ -0,0 +1,129 @@
+/*
+ * 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.userpkg;
+
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import org.apache.freemarker.core.Environment;
+import org.apache.freemarker.core.model.TemplateDateModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.valueformat.InvalidFormatParametersException;
+import org.apache.freemarker.core.valueformat.TemplateDateFormat;
+import org.apache.freemarker.core.valueformat.TemplateDateFormatFactory;
+import org.apache.freemarker.core.valueformat.TemplateFormatUtil;
+import org.apache.freemarker.core.valueformat.UnformattableValueException;
+import org.apache.freemarker.core.valueformat.UnknownDateTypeFormattingUnsupportedException;
+import org.apache.freemarker.core.valueformat.UnparsableValueException;
+
+public class AppMetaTemplateDateFormatFactory extends TemplateDateFormatFactory {
+
+    public static final AppMetaTemplateDateFormatFactory INSTANCE = new AppMetaTemplateDateFormatFactory();
+    
+    private AppMetaTemplateDateFormatFactory() {
+        // Defined to decrease visibility
+    }
+    
+    @Override
+    public TemplateDateFormat get(String params, int dateType, Locale locale, TimeZone timeZone, boolean zonelessInput,
+            Environment env) throws UnknownDateTypeFormattingUnsupportedException, InvalidFormatParametersException {
+        TemplateFormatUtil.checkHasNoParameters(params);
+        return AppMetaTemplateDateFormat.INSTANCE;
+    }
+
+    private static class AppMetaTemplateDateFormat extends TemplateDateFormat {
+
+        private static final AppMetaTemplateDateFormat INSTANCE = new AppMetaTemplateDateFormat();
+        
+        private AppMetaTemplateDateFormat() { }
+        
+        @Override
+        public String formatToPlainText(TemplateDateModel dateModel)
+                throws UnformattableValueException, TemplateModelException {
+            String result = String.valueOf(TemplateFormatUtil.getNonNullDate(dateModel).getTime());
+            if (dateModel instanceof AppMetaTemplateDateModel) {
+                result += "/" + ((AppMetaTemplateDateModel) dateModel).getAppMeta(); 
+            }
+            return result;
+        }
+
+        @Override
+        public boolean isLocaleBound() {
+            return false;
+        }
+
+        @Override
+        public boolean isTimeZoneBound() {
+            return false;
+        }
+
+        @Override
+        public Object parse(String s, int dateType) throws UnparsableValueException {
+            int slashIdx = s.indexOf('/');
+            try {
+                if (slashIdx != -1) {
+                    return new AppMetaTemplateDateModel(
+                            new Date(Long.parseLong(s.substring(0,  slashIdx))),
+                            dateType,
+                            s.substring(slashIdx +1));
+                } else {
+                    return new Date(Long.parseLong(s));
+                }
+            } catch (NumberFormatException e) {
+                throw new UnparsableValueException("Malformed long");
+            }
+        }
+
+        @Override
+        public String getDescription() {
+            return "millis since the epoch";
+        }
+        
+    }
+    
+    public static class AppMetaTemplateDateModel implements TemplateDateModel {
+        
+        private final Date date;
+        private final int dateType;
+        private final String appMeta;
+
+        public AppMetaTemplateDateModel(Date date, int dateType, String appMeta) {
+            this.date = date;
+            this.dateType = dateType;
+            this.appMeta = appMeta;
+        }
+
+        @Override
+        public Date getAsDate() throws TemplateModelException {
+            return date;
+        }
+
+        @Override
+        public int getDateType() {
+            return dateType;
+        }
+
+        public String getAppMeta() {
+            return appMeta;
+        }
+        
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/BaseNTemplateNumberFormatFactory.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/BaseNTemplateNumberFormatFactory.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/BaseNTemplateNumberFormatFactory.java
new file mode 100644
index 0000000..e5def77
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/BaseNTemplateNumberFormatFactory.java
@@ -0,0 +1,128 @@
+/*
+ * 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.userpkg;
+
+import java.util.Locale;
+
+import org.apache.freemarker.core.Environment;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateNumberModel;
+import org.apache.freemarker.core.util._NumberUtil;
+import org.apache.freemarker.core.util._StringUtil;
+import org.apache.freemarker.core.valueformat.InvalidFormatParametersException;
+import org.apache.freemarker.core.valueformat.TemplateFormatUtil;
+import org.apache.freemarker.core.valueformat.TemplateNumberFormat;
+import org.apache.freemarker.core.valueformat.TemplateNumberFormatFactory;
+import org.apache.freemarker.core.valueformat.TemplateValueFormatException;
+import org.apache.freemarker.core.valueformat.UnformattableValueException;
+
+/**
+ * Shows a number in base N number system. Can only format numbers that fit into an {@code int},
+ * however, optionally you can specify a fallback format. This format has one required parameter,
+ * the numerical system base. That can be optionally followed by "|" and a fallback format.
+ */
+public class BaseNTemplateNumberFormatFactory extends TemplateNumberFormatFactory {
+
+    public static final BaseNTemplateNumberFormatFactory INSTANCE
+            = new BaseNTemplateNumberFormatFactory();
+    
+    private BaseNTemplateNumberFormatFactory() {
+        // Defined to decrease visibility
+    }
+    
+    @Override
+    public TemplateNumberFormat get(String params, Locale locale, Environment env)
+            throws InvalidFormatParametersException {
+        TemplateNumberFormat fallbackFormat;
+        {
+            int barIdx = params.indexOf('|');
+            if (barIdx != -1) {
+                String fallbackFormatStr = params.substring(barIdx + 1);
+                params = params.substring(0, barIdx);
+                try {
+                    fallbackFormat = env.getTemplateNumberFormat(fallbackFormatStr, locale);
+                } catch (TemplateValueFormatException e) {
+                    throw new InvalidFormatParametersException(
+                            "Couldn't get the fallback number format (specified after the \"|\"), "
+                            + _StringUtil.jQuote(fallbackFormatStr) + ". Reason: " + e.getMessage(),
+                            e);
+                }
+            } else {
+                fallbackFormat = null;
+            }
+        }
+        
+        int base;
+        try {
+            base = Integer.parseInt(params);
+        } catch (NumberFormatException e) {
+            if (params.length() == 0) {
+                throw new InvalidFormatParametersException(
+                        "A format parameter is required to specify the numerical system base.");
+            }
+            throw new InvalidFormatParametersException(
+                    "The format paramter must be an integer, but was (shown quoted): "
+                    + _StringUtil.jQuote(params));
+        }
+        if (base < 2) {
+            throw new InvalidFormatParametersException("A base must be at least 2.");
+        }
+        return new BaseNTemplateNumberFormat(base, fallbackFormat);
+    }
+
+    private static class BaseNTemplateNumberFormat extends TemplateNumberFormat {
+
+        private final int base;
+        private final TemplateNumberFormat fallbackFormat;
+        
+        private BaseNTemplateNumberFormat(int base, TemplateNumberFormat fallbackFormat) {
+            this.base = base;
+            this.fallbackFormat = fallbackFormat;
+        }
+        
+        @Override
+        public String formatToPlainText(TemplateNumberModel numberModel)
+                throws TemplateModelException, TemplateValueFormatException {
+            Number n = TemplateFormatUtil.getNonNullNumber(numberModel);
+            try {
+                return Integer.toString(_NumberUtil.toIntExact(n), base);
+            } catch (ArithmeticException e) {
+                if (fallbackFormat == null) {
+                    throw new UnformattableValueException(
+                            n + " doesn't fit into an int, and there was no fallback format "
+                            + "specified.");
+                } else {
+                    return fallbackFormat.formatToPlainText(numberModel);
+                }
+            }
+        }
+
+        @Override
+        public boolean isLocaleBound() {
+            return false;
+        }
+
+        @Override
+        public String getDescription() {
+            return "base " + base;
+        }
+        
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/CustomHTMLOutputFormat.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/CustomHTMLOutputFormat.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/CustomHTMLOutputFormat.java
new file mode 100644
index 0000000..f570a66
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/CustomHTMLOutputFormat.java
@@ -0,0 +1,72 @@
+/*
+ * 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.userpkg;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.outputformat.CommonMarkupOutputFormat;
+import org.apache.freemarker.core.util._StringUtil;
+
+/**
+ * Represents the HTML output format.
+ * 
+ * @since 2.3.24
+ */
+public final class CustomHTMLOutputFormat extends CommonMarkupOutputFormat<CustomTemplateHTMLModel> {
+
+    public static final CustomHTMLOutputFormat INSTANCE = new CustomHTMLOutputFormat();
+    
+    private CustomHTMLOutputFormat() {
+        // Only to decrease visibility
+    }
+    
+    @Override
+    public String getName() {
+        return "HTML";
+    }
+
+    @Override
+    public String getMimeType() {
+        return "text/html";
+    }
+
+    @Override
+    public void output(String textToEsc, Writer out) throws IOException, TemplateModelException {
+        // This is lazy - don't do it in reality.
+        out.write(escapePlainText(textToEsc));
+    }
+
+    @Override
+    public String escapePlainText(String plainTextContent) {
+        return _StringUtil.XHTMLEnc(plainTextContent.replace('x', 'X'));
+    }
+
+    @Override
+    public boolean isLegacyBuiltInBypassed(String builtInName) {
+        return builtInName.equals("html") || builtInName.equals("xml") || builtInName.equals("xhtml");
+    }
+
+    @Override
+    protected CustomTemplateHTMLModel newTemplateMarkupOutputModel(String plainTextContent, String markupContent) {
+        return new CustomTemplateHTMLModel(plainTextContent, markupContent);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/CustomTemplateHTMLModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/CustomTemplateHTMLModel.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/CustomTemplateHTMLModel.java
new file mode 100644
index 0000000..4cc67be
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/CustomTemplateHTMLModel.java
@@ -0,0 +1,34 @@
+/*
+ * 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.userpkg;
+
+import org.apache.freemarker.core.outputformat.CommonTemplateMarkupOutputModel;
+
+public final class CustomTemplateHTMLModel extends CommonTemplateMarkupOutputModel<CustomTemplateHTMLModel> {
+    
+    CustomTemplateHTMLModel(String plainTextContent, String markupContent) {
+        super(plainTextContent, markupContent);
+    }
+
+    @Override
+    public CustomHTMLOutputFormat getOutputFormat() {
+        return CustomHTMLOutputFormat.INSTANCE;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/DummyOutputFormat.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/DummyOutputFormat.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/DummyOutputFormat.java
new file mode 100644
index 0000000..f368969
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/DummyOutputFormat.java
@@ -0,0 +1,65 @@
+/*
+ * 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.userpkg;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.outputformat.CommonMarkupOutputFormat;
+
+public class DummyOutputFormat extends CommonMarkupOutputFormat<TemplateDummyOutputModel> {
+    
+    public static final DummyOutputFormat INSTANCE = new DummyOutputFormat();
+    
+    private DummyOutputFormat() {
+        // hide
+    }
+
+    @Override
+    public String getName() {
+        return "dummy";
+    }
+
+    @Override
+    public String getMimeType() {
+        return "text/dummy";
+    }
+
+    @Override
+    public void output(String textToEsc, Writer out) throws IOException, TemplateModelException {
+        out.write(escapePlainText(textToEsc));
+    }
+
+    @Override
+    public String escapePlainText(String plainTextContent) {
+        return plainTextContent.replaceAll("(\\.|\\\\)", "\\\\$1");
+    }
+
+    @Override
+    public boolean isLegacyBuiltInBypassed(String builtInName) {
+        return false;
+    }
+
+    @Override
+    protected TemplateDummyOutputModel newTemplateMarkupOutputModel(String plainTextContent, String markupContent) {
+        return new TemplateDummyOutputModel(plainTextContent, markupContent);
+    }
+    
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/EpochMillisDivTemplateDateFormatFactory.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/EpochMillisDivTemplateDateFormatFactory.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/EpochMillisDivTemplateDateFormatFactory.java
new file mode 100644
index 0000000..8799eef
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/EpochMillisDivTemplateDateFormatFactory.java
@@ -0,0 +1,102 @@
+/*
+ * 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.userpkg;
+
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import org.apache.freemarker.core.Environment;
+import org.apache.freemarker.core.model.TemplateDateModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.util._StringUtil;
+import org.apache.freemarker.core.valueformat.InvalidFormatParametersException;
+import org.apache.freemarker.core.valueformat.TemplateDateFormat;
+import org.apache.freemarker.core.valueformat.TemplateDateFormatFactory;
+import org.apache.freemarker.core.valueformat.TemplateFormatUtil;
+import org.apache.freemarker.core.valueformat.UnformattableValueException;
+import org.apache.freemarker.core.valueformat.UnknownDateTypeFormattingUnsupportedException;
+import org.apache.freemarker.core.valueformat.UnparsableValueException;
+
+public class EpochMillisDivTemplateDateFormatFactory extends TemplateDateFormatFactory {
+
+    public static final EpochMillisDivTemplateDateFormatFactory INSTANCE = new EpochMillisDivTemplateDateFormatFactory();
+    
+    private EpochMillisDivTemplateDateFormatFactory() {
+        // Defined to decrease visibility
+    }
+    
+    @Override
+    public TemplateDateFormat get(String params, int dateType, Locale locale, TimeZone timeZone, boolean zonelessInput,
+            Environment env) throws UnknownDateTypeFormattingUnsupportedException, InvalidFormatParametersException {
+        int divisor;
+        try {
+            divisor = Integer.parseInt(params);
+        } catch (NumberFormatException e) {
+            if (params.length() == 0) {
+                throw new InvalidFormatParametersException(
+                        "A format parameter is required, which specifies the divisor.");
+            }
+            throw new InvalidFormatParametersException(
+                    "The format paramter must be an integer, but was (shown quoted): " + _StringUtil.jQuote(params));
+        }
+        return new EpochMillisDivTemplateDateFormat(divisor);
+    }
+
+    private static class EpochMillisDivTemplateDateFormat extends TemplateDateFormat {
+
+        private final int divisor;
+        
+        private EpochMillisDivTemplateDateFormat(int divisor) {
+            this.divisor = divisor;
+        }
+        
+        @Override
+        public String formatToPlainText(TemplateDateModel dateModel)
+                throws UnformattableValueException, TemplateModelException {
+            return String.valueOf(TemplateFormatUtil.getNonNullDate(dateModel).getTime() / divisor);
+        }
+
+        @Override
+        public boolean isLocaleBound() {
+            return false;
+        }
+
+        @Override
+        public boolean isTimeZoneBound() {
+            return false;
+        }
+
+        @Override
+        public Date parse(String s, int dateType) throws UnparsableValueException {
+            try {
+                return new Date(Long.parseLong(s));
+            } catch (NumberFormatException e) {
+                throw new UnparsableValueException("Malformed long");
+            }
+        }
+
+        @Override
+        public String getDescription() {
+            return "millis since the epoch";
+        }
+        
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/EpochMillisTemplateDateFormatFactory.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/EpochMillisTemplateDateFormatFactory.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/EpochMillisTemplateDateFormatFactory.java
new file mode 100644
index 0000000..9f27095
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/EpochMillisTemplateDateFormatFactory.java
@@ -0,0 +1,92 @@
+/*
+ * 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.userpkg;
+
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import org.apache.freemarker.core.Environment;
+import org.apache.freemarker.core.model.TemplateDateModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.valueformat.InvalidFormatParametersException;
+import org.apache.freemarker.core.valueformat.TemplateDateFormat;
+import org.apache.freemarker.core.valueformat.TemplateDateFormatFactory;
+import org.apache.freemarker.core.valueformat.TemplateFormatUtil;
+import org.apache.freemarker.core.valueformat.UnformattableValueException;
+import org.apache.freemarker.core.valueformat.UnparsableValueException;
+
+public class EpochMillisTemplateDateFormatFactory extends TemplateDateFormatFactory {
+
+    public static final EpochMillisTemplateDateFormatFactory INSTANCE
+            = new EpochMillisTemplateDateFormatFactory();
+    
+    private EpochMillisTemplateDateFormatFactory() {
+        // Defined to decrease visibility
+    }
+    
+    @Override
+    public TemplateDateFormat get(String params, int dateType,
+            Locale locale, TimeZone timeZone, boolean zonelessInput,
+            Environment env)
+            throws InvalidFormatParametersException {
+        TemplateFormatUtil.checkHasNoParameters(params);
+        return EpochMillisTemplateDateFormat.INSTANCE;
+    }
+
+    private static class EpochMillisTemplateDateFormat extends TemplateDateFormat {
+
+        private static final EpochMillisTemplateDateFormat INSTANCE
+                = new EpochMillisTemplateDateFormat();
+        
+        private EpochMillisTemplateDateFormat() { }
+        
+        @Override
+        public String formatToPlainText(TemplateDateModel dateModel)
+                throws UnformattableValueException, TemplateModelException {
+            return String.valueOf(TemplateFormatUtil.getNonNullDate(dateModel).getTime());
+        }
+
+        @Override
+        public boolean isLocaleBound() {
+            return false;
+        }
+
+        @Override
+        public boolean isTimeZoneBound() {
+            return false;
+        }
+
+        @Override
+        public Date parse(String s, int dateType) throws UnparsableValueException {
+            try {
+                return new Date(Long.parseLong(s));
+            } catch (NumberFormatException e) {
+                throw new UnparsableValueException("Malformed long");
+            }
+        }
+
+        @Override
+        public String getDescription() {
+            return "millis since the epoch";
+        }
+        
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/HTMLISOTemplateDateFormatFactory.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/HTMLISOTemplateDateFormatFactory.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/HTMLISOTemplateDateFormatFactory.java
new file mode 100644
index 0000000..357034c
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/HTMLISOTemplateDateFormatFactory.java
@@ -0,0 +1,114 @@
+/*
+ * 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.userpkg;
+
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import org.apache.freemarker.core.Environment;
+import org.apache.freemarker.core.model.TemplateDateModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat;
+import org.apache.freemarker.core.util._DateUtil;
+import org.apache.freemarker.core.util._DateUtil.CalendarFieldsToDateConverter;
+import org.apache.freemarker.core.util._DateUtil.DateParseException;
+import org.apache.freemarker.core.valueformat.InvalidFormatParametersException;
+import org.apache.freemarker.core.valueformat.TemplateDateFormat;
+import org.apache.freemarker.core.valueformat.TemplateDateFormatFactory;
+import org.apache.freemarker.core.valueformat.TemplateFormatUtil;
+import org.apache.freemarker.core.valueformat.TemplateValueFormatException;
+import org.apache.freemarker.core.valueformat.UnformattableValueException;
+import org.apache.freemarker.core.valueformat.UnknownDateTypeFormattingUnsupportedException;
+import org.apache.freemarker.core.valueformat.UnparsableValueException;
+
+public class HTMLISOTemplateDateFormatFactory extends TemplateDateFormatFactory {
+
+    public static final HTMLISOTemplateDateFormatFactory INSTANCE = new HTMLISOTemplateDateFormatFactory();
+    
+    private HTMLISOTemplateDateFormatFactory() {
+        // Defined to decrease visibility
+    }
+    
+    @Override
+    public TemplateDateFormat get(String params, int dateType, Locale locale, TimeZone timeZone, boolean zonelessInput,
+            Environment env) throws UnknownDateTypeFormattingUnsupportedException, InvalidFormatParametersException {
+        TemplateFormatUtil.checkHasNoParameters(params);
+        return HTMLISOTemplateDateFormat.INSTANCE;
+    }
+
+    private static class HTMLISOTemplateDateFormat extends TemplateDateFormat {
+
+        private static final HTMLISOTemplateDateFormat INSTANCE = new HTMLISOTemplateDateFormat();
+
+        private _DateUtil.TrivialDateToISO8601CalendarFactory calendarFactory;
+
+        private CalendarFieldsToDateConverter calToDateConverter;
+        
+        private HTMLISOTemplateDateFormat() { }
+        
+        @Override
+        public String formatToPlainText(TemplateDateModel dateModel)
+                throws UnformattableValueException, TemplateModelException {
+            if (calendarFactory == null) {
+                calendarFactory = new _DateUtil.TrivialDateToISO8601CalendarFactory();
+            }
+            return _DateUtil.dateToISO8601String(
+                    TemplateFormatUtil.getNonNullDate(dateModel),
+                    true, true, true, _DateUtil.ACCURACY_SECONDS, _DateUtil.UTC,
+                    calendarFactory);
+        }
+
+        @Override
+        public boolean isLocaleBound() {
+            return false;
+        }
+
+        @Override
+        public boolean isTimeZoneBound() {
+            return false;
+        }
+
+        @Override
+        public Date parse(String s, int dateType) throws UnparsableValueException {
+            try {
+                if (calToDateConverter == null) {
+                    calToDateConverter = new _DateUtil.TrivialCalendarFieldsToDateConverter();
+                }
+                return _DateUtil.parseISO8601DateTime(s, _DateUtil.UTC, calToDateConverter);
+            } catch (DateParseException e) {
+                throw new UnparsableValueException("Malformed ISO date-time", e);
+            }
+        }
+
+        @Override
+        public Object format(TemplateDateModel dateModel) throws TemplateValueFormatException, TemplateModelException {
+            return HTMLOutputFormat.INSTANCE.fromMarkup(
+                    formatToPlainText(dateModel).replace("T", "<span class='T'>T</span>"));
+        }
+
+        @Override
+        public String getDescription() {
+            return "ISO UTC HTML";
+        }
+        
+    }
+
+}
+ 
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/HexTemplateNumberFormatFactory.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/HexTemplateNumberFormatFactory.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/HexTemplateNumberFormatFactory.java
new file mode 100644
index 0000000..6d72c20
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/HexTemplateNumberFormatFactory.java
@@ -0,0 +1,77 @@
+/*
+ * 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.userpkg;
+
+import java.util.Locale;
+
+import org.apache.freemarker.core.Environment;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateNumberModel;
+import org.apache.freemarker.core.util._NumberUtil;
+import org.apache.freemarker.core.valueformat.InvalidFormatParametersException;
+import org.apache.freemarker.core.valueformat.TemplateFormatUtil;
+import org.apache.freemarker.core.valueformat.TemplateNumberFormat;
+import org.apache.freemarker.core.valueformat.TemplateNumberFormatFactory;
+import org.apache.freemarker.core.valueformat.UnformattableValueException;
+
+public class HexTemplateNumberFormatFactory extends TemplateNumberFormatFactory {
+
+    public static final HexTemplateNumberFormatFactory INSTANCE = new HexTemplateNumberFormatFactory();
+    
+    private HexTemplateNumberFormatFactory() {
+        // Defined to decrease visibility
+    }
+    
+    @Override
+    public TemplateNumberFormat get(String params, Locale locale, Environment env)
+            throws InvalidFormatParametersException {
+        TemplateFormatUtil.checkHasNoParameters(params);
+        return HexTemplateNumberFormat.INSTANCE;
+    }
+
+    private static class HexTemplateNumberFormat extends TemplateNumberFormat {
+
+        private static final HexTemplateNumberFormat INSTANCE = new HexTemplateNumberFormat();
+        
+        private HexTemplateNumberFormat() { }
+        
+        @Override
+        public String formatToPlainText(TemplateNumberModel numberModel)
+                throws UnformattableValueException, TemplateModelException {
+            Number n = TemplateFormatUtil.getNonNullNumber(numberModel);
+            try {
+                return Integer.toHexString(_NumberUtil.toIntExact(n));
+            } catch (ArithmeticException e) {
+                throw new UnformattableValueException(n + " doesn't fit into an int");
+            }
+        }
+
+        @Override
+        public boolean isLocaleBound() {
+            return false;
+        }
+
+        @Override
+        public String getDescription() {
+            return "hexadecimal int";
+        }
+        
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/LocAndTZSensitiveTemplateDateFormatFactory.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/LocAndTZSensitiveTemplateDateFormatFactory.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/LocAndTZSensitiveTemplateDateFormatFactory.java
new file mode 100644
index 0000000..42b0401
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/LocAndTZSensitiveTemplateDateFormatFactory.java
@@ -0,0 +1,97 @@
+/*
+ * 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.userpkg;
+
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import org.apache.freemarker.core.Environment;
+import org.apache.freemarker.core.model.TemplateDateModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.valueformat.InvalidFormatParametersException;
+import org.apache.freemarker.core.valueformat.TemplateDateFormat;
+import org.apache.freemarker.core.valueformat.TemplateDateFormatFactory;
+import org.apache.freemarker.core.valueformat.TemplateFormatUtil;
+import org.apache.freemarker.core.valueformat.UnformattableValueException;
+import org.apache.freemarker.core.valueformat.UnknownDateTypeFormattingUnsupportedException;
+import org.apache.freemarker.core.valueformat.UnparsableValueException;
+
+public class LocAndTZSensitiveTemplateDateFormatFactory extends TemplateDateFormatFactory {
+
+    public static final LocAndTZSensitiveTemplateDateFormatFactory INSTANCE = new LocAndTZSensitiveTemplateDateFormatFactory();
+    
+    private LocAndTZSensitiveTemplateDateFormatFactory() {
+        // Defined to decrease visibility
+    }
+    
+    @Override
+    public TemplateDateFormat get(String params, int dateType, Locale locale, TimeZone timeZone, boolean zonelessInput,
+            Environment env) throws UnknownDateTypeFormattingUnsupportedException, InvalidFormatParametersException {
+        TemplateFormatUtil.checkHasNoParameters(params);
+        return new LocAndTZSensitiveTemplateDateFormat(locale, timeZone);
+    }
+
+    private static class LocAndTZSensitiveTemplateDateFormat extends TemplateDateFormat {
+
+        private final Locale locale;
+        private final TimeZone timeZone;
+        
+        public LocAndTZSensitiveTemplateDateFormat(Locale locale, TimeZone timeZone) {
+            this.locale = locale;
+            this.timeZone = timeZone;
+        }
+
+        @Override
+        public String formatToPlainText(TemplateDateModel dateModel)
+                throws UnformattableValueException, TemplateModelException {
+            return String.valueOf(TemplateFormatUtil.getNonNullDate(dateModel).getTime() + "@" + locale + ":" + timeZone.getID());
+        }
+
+        @Override
+        public boolean isLocaleBound() {
+            return true;
+        }
+
+        @Override
+        public boolean isTimeZoneBound() {
+            return true;
+        }
+
+        @Override
+        public Date parse(String s, int dateType) throws UnparsableValueException {
+            try {
+                int atIdx = s.indexOf("@");
+                if (atIdx == -1) {
+                    throw new UnparsableValueException("Missing @");
+                }
+                return new Date(Long.parseLong(s.substring(0, atIdx)));
+            } catch (NumberFormatException e) {
+                throw new UnparsableValueException("Malformed long");
+            }
+        }
+
+        @Override
+        public String getDescription() {
+            return "millis since the epoch";
+        }
+        
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/LocaleSensitiveTemplateNumberFormatFactory.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/LocaleSensitiveTemplateNumberFormatFactory.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/LocaleSensitiveTemplateNumberFormatFactory.java
new file mode 100644
index 0000000..dc3dae0
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/LocaleSensitiveTemplateNumberFormatFactory.java
@@ -0,0 +1,78 @@
+/*
+ * 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.userpkg;
+
+import java.util.Locale;
+
+import org.apache.freemarker.core.Environment;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateNumberModel;
+import org.apache.freemarker.core.valueformat.InvalidFormatParametersException;
+import org.apache.freemarker.core.valueformat.TemplateFormatUtil;
+import org.apache.freemarker.core.valueformat.TemplateNumberFormat;
+import org.apache.freemarker.core.valueformat.TemplateNumberFormatFactory;
+import org.apache.freemarker.core.valueformat.UnformattableValueException;
+
+public class LocaleSensitiveTemplateNumberFormatFactory extends TemplateNumberFormatFactory {
+
+    public static final LocaleSensitiveTemplateNumberFormatFactory INSTANCE = new LocaleSensitiveTemplateNumberFormatFactory();
+    
+    private LocaleSensitiveTemplateNumberFormatFactory() {
+        // Defined to decrease visibility
+    }
+    
+    @Override
+    public TemplateNumberFormat get(String params, Locale locale, Environment env)
+            throws InvalidFormatParametersException {
+        TemplateFormatUtil.checkHasNoParameters(params);
+        return new LocaleSensitiveTemplateNumberFormat(locale);
+    }
+
+    private static class LocaleSensitiveTemplateNumberFormat extends TemplateNumberFormat {
+    
+        private final Locale locale;
+        
+        private LocaleSensitiveTemplateNumberFormat(Locale locale) {
+            this.locale = locale;
+        }
+        
+        @Override
+        public String formatToPlainText(TemplateNumberModel numberModel)
+                throws UnformattableValueException, TemplateModelException {
+            Number n = numberModel.getAsNumber();
+            try {
+                return n + "_" + locale;
+            } catch (ArithmeticException e) {
+                throw new UnformattableValueException(n + " doesn't fit into an int");
+            }
+        }
+    
+        @Override
+        public boolean isLocaleBound() {
+            return true;
+        }
+    
+        @Override
+        public String getDescription() {
+            return "test locale sensitive";
+        }
+        
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PackageVisibleAll.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PackageVisibleAll.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PackageVisibleAll.java
new file mode 100644
index 0000000..f3ebc72
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PackageVisibleAll.java
@@ -0,0 +1,26 @@
+/*
+ * 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.userpkg;
+
+class PackageVisibleAll {
+    
+    PackageVisibleAll() {}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PackageVisibleAllWithBuilder.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PackageVisibleAllWithBuilder.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PackageVisibleAllWithBuilder.java
new file mode 100644
index 0000000..53a89d4
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PackageVisibleAllWithBuilder.java
@@ -0,0 +1,26 @@
+/*
+ * 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.userpkg;
+
+class PackageVisibleAllWithBuilder {
+
+    PackageVisibleAllWithBuilder() {}
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PackageVisibleAllWithBuilderBuilder.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PackageVisibleAllWithBuilderBuilder.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PackageVisibleAllWithBuilderBuilder.java
new file mode 100644
index 0000000..510ecc2
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PackageVisibleAllWithBuilderBuilder.java
@@ -0,0 +1,28 @@
+/*
+ * 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.userpkg;
+
+public class PackageVisibleAllWithBuilderBuilder {
+    
+    public PackageVisibleAllWithBuilder build() {
+        return new PackageVisibleAllWithBuilder();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PackageVisibleWithPublicConstructor.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PackageVisibleWithPublicConstructor.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PackageVisibleWithPublicConstructor.java
new file mode 100644
index 0000000..836e80d
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PackageVisibleWithPublicConstructor.java
@@ -0,0 +1,27 @@
+/*
+ * 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.userpkg;
+
+class PackageVisibleWithPublicConstructor {
+    
+    public PackageVisibleWithPublicConstructor() {
+    }
+
+}


[41/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/CommonSupertypeForUnwrappingHintTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/CommonSupertypeForUnwrappingHintTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/CommonSupertypeForUnwrappingHintTest.java
new file mode 100644
index 0000000..ef15dae
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/CommonSupertypeForUnwrappingHintTest.java
@@ -0,0 +1,129 @@
+/*
+ * 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.model.impl;
+
+import java.io.Serializable;
+import java.util.List;
+
+import org.apache.freemarker.core.model.TemplateModelException;
+
+import junit.framework.TestCase;
+
+public class CommonSupertypeForUnwrappingHintTest extends TestCase {
+    
+    final OverloadedMethodsSubset oms = new DummyOverloadedMethodsSubset();
+
+    public CommonSupertypeForUnwrappingHintTest(String name) {
+        super(name);
+    }
+
+    public void testInterfaces() {
+        assertEquals(Serializable.class, oms.getCommonSupertypeForUnwrappingHint(String.class, Number.class));
+        assertEquals(C1I1.class, oms.getCommonSupertypeForUnwrappingHint(C2ExtC1I1.class, C3ExtC1I1.class));
+        assertEquals(Object.class, oms.getCommonSupertypeForUnwrappingHint(C3I1I2.class, C4I1I2.class));
+        assertEquals(I1.class, oms.getCommonSupertypeForUnwrappingHint(C3I1I2.class, C5I1.class));
+        assertEquals(I1.class, oms.getCommonSupertypeForUnwrappingHint(C3I1I2.class, I1.class));
+        assertEquals(I2.class, oms.getCommonSupertypeForUnwrappingHint(C3I1I2.class, I2.class));
+        assertEquals(I1.class, oms.getCommonSupertypeForUnwrappingHint(I1I2.class, I1.class));
+        assertEquals(I2.class, oms.getCommonSupertypeForUnwrappingHint(I1I2.class, I2.class));
+        assertEquals(CharSequence.class, oms.getCommonSupertypeForUnwrappingHint(String.class, StringBuilder.class));
+        assertEquals(C6.class, oms.getCommonSupertypeForUnwrappingHint(C7ExtC6I1.class, C8ExtC6I1.class));
+    }
+
+    public void testArrayAndOther() {
+        testArrayAndOther(oms);
+    }
+    
+    /** These will be the same with oms and buggy: */
+    private void testArrayAndOther(OverloadedMethodsSubset oms) {
+        assertEquals(Serializable.class, oms.getCommonSupertypeForUnwrappingHint(int[].class, String.class));
+        assertEquals(Serializable.class, oms.getCommonSupertypeForUnwrappingHint(Object[].class, String.class));
+        
+        assertEquals(Object.class, oms.getCommonSupertypeForUnwrappingHint(int[].class, List.class));
+        assertEquals(Object.class, oms.getCommonSupertypeForUnwrappingHint(Object[].class, List.class));
+        
+        assertEquals(int[].class, oms.getCommonSupertypeForUnwrappingHint(int[].class, int[].class));
+        assertEquals(Object[].class, oms.getCommonSupertypeForUnwrappingHint(Object[].class, Object[].class));
+    }
+    
+    public void testArrayAndDifferentArray() {
+        assertEquals(Serializable.class, oms.getCommonSupertypeForUnwrappingHint(int[].class, Object[].class));
+        assertEquals(Serializable.class, oms.getCommonSupertypeForUnwrappingHint(int[].class, long[].class));
+    }
+    
+    public void testPrimitive() {
+        assertEquals(Integer.class, oms.getCommonSupertypeForUnwrappingHint(int.class, Integer.class));
+        assertEquals(Integer.class, oms.getCommonSupertypeForUnwrappingHint(Integer.class, int.class));
+        assertEquals(Number.class, oms.getCommonSupertypeForUnwrappingHint(int.class, Long.class));
+        assertEquals(Number.class, oms.getCommonSupertypeForUnwrappingHint(Long.class, int.class));
+        assertEquals(Number.class, oms.getCommonSupertypeForUnwrappingHint(Integer.class, long.class));
+        assertEquals(Number.class, oms.getCommonSupertypeForUnwrappingHint(long.class, Integer.class));
+        assertEquals(Boolean.class, oms.getCommonSupertypeForUnwrappingHint(boolean.class, Boolean.class));
+        assertEquals(Boolean.class, oms.getCommonSupertypeForUnwrappingHint(Boolean.class, boolean.class));
+        assertEquals(Character.class, oms.getCommonSupertypeForUnwrappingHint(char.class, Character.class));
+        assertEquals(Character.class, oms.getCommonSupertypeForUnwrappingHint(Character.class, char.class));
+        assertEquals(Number.class, oms.getCommonSupertypeForUnwrappingHint(int.class, short.class));
+        assertEquals(Number.class, oms.getCommonSupertypeForUnwrappingHint(short.class, int.class));
+    }
+
+    public void testMisc() {
+        assertEquals(Number.class, oms.getCommonSupertypeForUnwrappingHint(Long.class, Integer.class));
+        assertEquals(char.class, oms.getCommonSupertypeForUnwrappingHint(char.class, char.class));
+        assertEquals(Integer.class, oms.getCommonSupertypeForUnwrappingHint(Integer.class, Integer.class));
+        assertEquals(String.class, oms.getCommonSupertypeForUnwrappingHint(String.class, String.class));
+    }
+    
+    static interface I1 { };
+    static class C1I1 implements I1 { };
+    static class C2ExtC1I1 extends C1I1 { };
+    static class C3ExtC1I1 extends C1I1 { };
+    static interface I2 { };
+    static class C3I1I2 implements I1, I2 { };
+    static class C4I1I2 implements I1, I2 { };
+    static class C5I1 implements I1 { };
+    static interface I1I2 extends I1, I2 { };
+    static class C6 { };
+    static class C7ExtC6I1 extends C6 implements I1 { };
+    static class C8ExtC6I1 extends C6 implements I1 { };
+    
+    private static class DummyOverloadedMethodsSubset extends OverloadedMethodsSubset {
+
+        DummyOverloadedMethodsSubset() {
+            super();
+        }
+
+        @Override
+        Class[] preprocessParameterTypes(CallableMemberDescriptor memberDesc) {
+            return memberDesc.getParamTypes();
+        }
+
+        @Override
+        void afterWideningUnwrappingHints(Class[] paramTypes, int[] paramNumericalTypes) {
+            // Do nothing
+        }
+
+        @Override
+        MaybeEmptyMemberAndArguments getMemberAndArguments(List tmArgs, DefaultObjectWrapper w) throws TemplateModelException {
+            throw new RuntimeException("Not implemented in this dummy.");
+        }
+        
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperDesc.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperDesc.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperDesc.java
new file mode 100644
index 0000000..0ed6e7c
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperDesc.java
@@ -0,0 +1,31 @@
+/*
+ * 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.model.impl;
+
+import org.apache.freemarker.core.Configuration;
+
+public class DefaultObjectWrapperDesc extends DefaultObjectWrapper {
+
+    public DefaultObjectWrapperDesc() {
+        super(new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0)
+                .methodSorter(new AlphabeticalMethodSorter(true)), true);
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperInc.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperInc.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperInc.java
new file mode 100644
index 0000000..eb2cda0
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperInc.java
@@ -0,0 +1,31 @@
+/*
+ * 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.model.impl;
+
+import org.apache.freemarker.core.Configuration;
+
+public class DefaultObjectWrapperInc extends DefaultObjectWrapper {
+
+    public DefaultObjectWrapperInc() {
+        super(new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0)
+                .methodSorter(new AlphabeticalMethodSorter(false)), true);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperModelFactoryRegistrationTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperModelFactoryRegistrationTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperModelFactoryRegistrationTest.java
new file mode 100644
index 0000000..5c2f653
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperModelFactoryRegistrationTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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.model.impl;
+
+import static org.junit.Assert.*;
+
+import java.lang.ref.Reference;
+
+import org.apache.freemarker.core.Configuration;
+import org.junit.Test;
+
+public class DefaultObjectWrapperModelFactoryRegistrationTest {
+
+    @Test
+    public void introspectionSettingChanges() {
+        DefaultObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).usePrivateCaches(true)
+                .build();
+        ClassIntrospector ci1 = ow.getClassIntrospector();
+        checkRegisteredModelFactories(ci1, ow.getStaticModels(), ow.getEnumModels());
+    }
+
+    private void checkRegisteredModelFactories(ClassIntrospector ci, Object... expected) {
+        Object[] actualRefs = ci.getRegisteredModelFactoriesSnapshot();
+
+        scanActuals: for (Object actaulRef : actualRefs) {
+            Object actualItem = ((Reference) actaulRef).get();
+            for (Object expectedItem : expected) {
+                if (actualItem == expectedItem) {
+                    continue scanActuals;
+                }
+            }
+            fail("Actual item " + actualItem + " is not among the expected items");
+        }
+
+        scanExpecteds: for (Object expectedItem : expected) {
+            for (Object ref : actualRefs) {
+                Object actualItem = ((Reference) ref).get();
+                if (actualItem == expectedItem) {
+                    continue scanExpecteds;
+                }
+            }
+            fail("Expected item " + expectedItem + " is not among the actual items");
+        }
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperSingletonsTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperSingletonsTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperSingletonsTest.java
new file mode 100644
index 0000000..d6f8177
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperSingletonsTest.java
@@ -0,0 +1,675 @@
+/*
+ * 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.model.impl;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.lang.ref.Reference;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.Version;
+import org.apache.freemarker.core.model.TemplateDateModel;
+import org.apache.freemarker.core.model.TemplateHashModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateScalarModel;
+import org.apache.freemarker.test.TestUtil;
+
+import junit.framework.TestCase;
+
+public class DefaultObjectWrapperSingletonsTest extends TestCase {
+
+    public DefaultObjectWrapperSingletonsTest(String name) {
+        super(name);
+    }
+    
+    @Override
+    protected void setUp() throws Exception {
+        DefaultObjectWrapper.Builder.clearInstanceCache();
+    }
+
+    public void testBuilderEqualsAndHash() throws Exception {
+        assertEquals(Configuration.VERSION_3_0_0, new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).getIncompatibleImprovements());
+        try {
+            new DefaultObjectWrapper.Builder(TestUtil.getClosestFutureVersion());
+            fail("Maybe you need to update this test for the new FreeMarker version");
+        } catch (IllegalArgumentException e) {
+            assertThat(e.getMessage(), containsString("upgrade"));
+        }
+
+        DefaultObjectWrapper.Builder builder1;
+        DefaultObjectWrapper.Builder builder2;
+        
+        builder1 = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
+        builder2 = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
+        assertEquals(builder1, builder2);
+        
+        builder1.setExposeFields(true);
+        assertNotEquals(builder1, builder2);
+        assertNotEquals(builder1.hashCode(), builder2.hashCode());
+        builder2.setExposeFields(true);
+        assertEquals(builder1, builder2);
+        assertEquals(builder1.hashCode(), builder2.hashCode());
+        
+        builder1.setExposureLevel(0);
+        assertNotEquals(builder1, builder2);
+        assertNotEquals(builder1.hashCode(), builder2.hashCode());
+        builder2.setExposureLevel(0);
+        assertEquals(builder1, builder2);
+        assertEquals(builder1.hashCode(), builder2.hashCode());
+        
+        builder1.setExposureLevel(1);
+        assertNotEquals(builder1, builder2);
+        assertNotEquals(builder1.hashCode(), builder2.hashCode());
+        builder2.setExposureLevel(1);
+        assertEquals(builder1, builder2);
+        assertEquals(builder1.hashCode(), builder2.hashCode());
+        
+        builder1.setDefaultDateType(TemplateDateModel.DATE);
+        assertNotEquals(builder1, builder2);
+        builder2.setDefaultDateType(TemplateDateModel.DATE);
+        assertEquals(builder1, builder2);
+        assertEquals(builder1.hashCode(), builder2.hashCode());
+        
+        builder1.setStrict(true);
+        assertNotEquals(builder1, builder2);
+        assertNotEquals(builder1.hashCode(), builder2.hashCode());
+        builder2.setStrict(true);
+        assertEquals(builder1, builder2);
+        assertEquals(builder1.hashCode(), builder2.hashCode());
+
+        builder1.setUseModelCache(true);
+        assertNotEquals(builder1, builder2);
+        assertNotEquals(builder1.hashCode(), builder2.hashCode());
+        builder2.setUseModelCache(true);
+        assertEquals(builder1, builder2);
+        assertEquals(builder1.hashCode(), builder2.hashCode());
+        
+        AlphabeticalMethodSorter ms = new AlphabeticalMethodSorter(true);
+        builder1.setMethodSorter(ms);
+        assertNotEquals(builder1, builder2);
+        builder2.setMethodSorter(ms);
+        assertEquals(builder1, builder2);
+        assertEquals(builder1.hashCode(), builder2.hashCode());
+
+        MethodAppearanceFineTuner maft = new MethodAppearanceFineTuner() {
+            @Override
+            public void process(DecisionInput in, Decision out) { }
+        };
+        builder1.setMethodAppearanceFineTuner(maft);
+        assertNotEquals(builder1, builder2);
+        builder2.setMethodAppearanceFineTuner(maft);
+        assertEquals(builder1, builder2);
+        assertEquals(builder1.hashCode(), builder2.hashCode());
+    }
+    
+    public void testDefaultObjectWrapperBuilderProducts() throws Exception {
+        List<DefaultObjectWrapper> hardReferences = new LinkedList<>();
+        
+        assertEquals(0, getDefaultObjectWrapperInstanceCacheSize());
+        
+        {
+            DefaultObjectWrapper ow = getDefaultObjectWrapperWithSetting(Configuration.VERSION_3_0_0, true);
+            assertEquals(1, getDefaultObjectWrapperInstanceCacheSize());
+            assertSame(ow.getClass(), DefaultObjectWrapper.class);
+            assertEquals(Configuration.VERSION_3_0_0, ow.getIncompatibleImprovements());
+            assertFalse(ow.isStrict());
+            assertTrue(ow.getUseModelCache());
+            assertEquals(TemplateDateModel.UNKNOWN, ow.getDefaultDateType());
+            assertSame(ow, ow.getOuterIdentity());
+            assertTrue(ow.isClassIntrospectionCacheRestricted());
+            assertNull(ow.getMethodAppearanceFineTuner());
+            assertNull(ow.getMethodSorter());
+
+            assertSame(ow, getDefaultObjectWrapperWithSetting(Configuration.VERSION_3_0_0, true));
+            assertEquals(1, getDefaultObjectWrapperInstanceCacheSize());
+            
+            hardReferences.add(ow);
+        }
+        
+        {
+            DefaultObjectWrapper ow = getDefaultObjectWrapperWithSetting(Configuration.VERSION_3_0_0, false);
+            assertEquals(2, getDefaultObjectWrapperInstanceCacheSize());
+            assertSame(ow.getClass(), DefaultObjectWrapper.class);
+            assertEquals(Configuration.VERSION_3_0_0, ow.getIncompatibleImprovements());
+            assertFalse(ow.getUseModelCache());
+
+            assertSame(ow, getDefaultObjectWrapperWithSetting(Configuration.VERSION_3_0_0, false));
+            
+            hardReferences.add(ow);
+        }
+        
+        {
+            DefaultObjectWrapper.Builder factory = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
+            factory.setExposureLevel(DefaultObjectWrapper.EXPOSE_PROPERTIES_ONLY);
+            DefaultObjectWrapper ow1 = factory.build();
+            DefaultObjectWrapper ow2 = factory.build();
+            assertEquals(3, getDefaultObjectWrapperInstanceCacheSize());
+            assertSame(ow1, ow2);
+            
+            assertSame(ow1.getClass(), DefaultObjectWrapper.class);
+            assertEquals(Configuration.VERSION_3_0_0, ow1.getIncompatibleImprovements());
+            assertEquals(DefaultObjectWrapper.EXPOSE_PROPERTIES_ONLY, ow1.getExposureLevel());
+            assertFalse(ow1.isStrict());
+            assertEquals(TemplateDateModel.UNKNOWN, ow1.getDefaultDateType());
+            assertSame(ow1, ow1.getOuterIdentity());
+            
+            hardReferences.add(ow1);
+        }
+        
+        {
+            DefaultObjectWrapper.Builder factory = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
+            factory.setExposeFields(true);
+            DefaultObjectWrapper ow1 = factory.build();
+            DefaultObjectWrapper ow2 = factory.build();
+            assertEquals(4, getDefaultObjectWrapperInstanceCacheSize());
+            assertSame(ow1, ow2);
+            
+            assertSame(ow1.getClass(), DefaultObjectWrapper.class);
+            assertEquals(Configuration.VERSION_3_0_0, ow1.getIncompatibleImprovements());
+            assertTrue(ow1.isExposeFields());
+            
+            hardReferences.add(ow1);
+        }
+        
+        {
+            DefaultObjectWrapper.Builder factory = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
+            factory.setStrict(true);
+            factory.setDefaultDateType(TemplateDateModel.DATETIME);
+            factory.setOuterIdentity(new RestrictedObjectWrapper.Builder(Configuration.VERSION_3_0_0).build());
+            DefaultObjectWrapper ow = factory.build();
+            assertEquals(5, getDefaultObjectWrapperInstanceCacheSize());
+            assertTrue(ow.isStrict());
+            assertEquals(TemplateDateModel.DATETIME, ow.getDefaultDateType());
+            assertSame(RestrictedObjectWrapper.class, ow.getOuterIdentity().getClass());
+            
+            hardReferences.add(ow);
+        }
+        
+        // Effect of reference and cache clearings:
+        {
+            DefaultObjectWrapper bw1 = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
+            assertEquals(5, getDefaultObjectWrapperInstanceCacheSize());
+            assertEquals(5, getDefaultObjectWrapperNonClearedInstanceCacheSize());
+            
+            clearDefaultObjectWrapperInstanceCacheReferences(false);
+            assertEquals(5, getDefaultObjectWrapperInstanceCacheSize());
+            assertEquals(0, getDefaultObjectWrapperNonClearedInstanceCacheSize());
+            
+            DefaultObjectWrapper bw2 = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
+            assertNotSame(bw1, bw2);
+            assertEquals(5, getDefaultObjectWrapperInstanceCacheSize());
+            assertEquals(1, getDefaultObjectWrapperNonClearedInstanceCacheSize());
+            
+            assertSame(bw2, new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build());
+            assertEquals(1, getDefaultObjectWrapperNonClearedInstanceCacheSize());
+            
+            clearDefaultObjectWrapperInstanceCacheReferences(true);
+            DefaultObjectWrapper bw3 = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
+            assertNotSame(bw2, bw3);
+            assertEquals(1, getDefaultObjectWrapperInstanceCacheSize());
+            assertEquals(1, getDefaultObjectWrapperNonClearedInstanceCacheSize());
+        }
+
+        {
+            DefaultObjectWrapper.Builder factory = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
+            factory.setUseModelCache(true);
+            DefaultObjectWrapper ow = factory.build();
+            assertTrue(ow.getUseModelCache());
+            assertEquals(2, getDefaultObjectWrapperInstanceCacheSize());
+            
+            hardReferences.add(ow);
+        }
+        
+        assertTrue(hardReferences.size() != 0);  // just to save it from GC until this line        
+    }
+    
+    private DefaultObjectWrapper getDefaultObjectWrapperWithSetting(Version ici, boolean useModelCache) {
+        DefaultObjectWrapper.Builder f = new DefaultObjectWrapper.Builder(ici);
+        f.setUseModelCache(useModelCache);
+        return f.build();
+    }
+
+    public void testMultipleTCCLs() {
+        List<DefaultObjectWrapper> hardReferences = new LinkedList<>();
+        
+        assertEquals(0, getDefaultObjectWrapperInstanceCacheSize());
+        
+        DefaultObjectWrapper bw1 = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
+        assertEquals(1, getDefaultObjectWrapperInstanceCacheSize());
+        hardReferences.add(bw1);
+        
+        ClassLoader oldTCCL = Thread.currentThread().getContextClassLoader();
+        // Doesn't mater what, just be different from oldTCCL: 
+        ClassLoader newTCCL = oldTCCL == null ? getClass().getClassLoader() : null;
+        
+        DefaultObjectWrapper bw2;
+        Thread.currentThread().setContextClassLoader(newTCCL);
+        try {
+            bw2 = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
+            assertEquals(2, getDefaultObjectWrapperInstanceCacheSize());
+            hardReferences.add(bw2);
+            
+            assertNotSame(bw1, bw2);
+            assertSame(bw2, new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build());
+        } finally {
+            Thread.currentThread().setContextClassLoader(oldTCCL);
+        }
+        
+        assertSame(bw1, new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build());
+        assertEquals(2, getDefaultObjectWrapperInstanceCacheSize());
+
+        DefaultObjectWrapper bw3;
+        Thread.currentThread().setContextClassLoader(newTCCL);
+        try {
+            assertSame(bw2, new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build());
+            
+            DefaultObjectWrapper.Builder bwb = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
+            bwb.setExposeFields(true);
+            bw3 = bwb.build();
+            assertEquals(3, getDefaultObjectWrapperInstanceCacheSize());
+            hardReferences.add(bw3);
+        } finally {
+            Thread.currentThread().setContextClassLoader(oldTCCL);
+        }
+        
+        {
+            DefaultObjectWrapper.Builder bwb = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
+            bwb.setExposeFields(true);
+            DefaultObjectWrapper bw4 = bwb.build();
+            assertEquals(4, getDefaultObjectWrapperInstanceCacheSize());
+            assertNotSame(bw3, bw4);
+            hardReferences.add(bw4);
+        }
+        
+        assertTrue(hardReferences.size() != 0);  // just to save it from GC until this line        
+    }
+    
+    public void testClassInrospectorCache() throws TemplateModelException {
+        assertFalse(new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0)
+                .usePrivateCaches(true).build().isClassIntrospectionCacheRestricted());
+        assertTrue(new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0)
+                .build().isClassIntrospectionCacheRestricted());
+        
+        ClassIntrospector.Builder.clearInstanceCache();
+        DefaultObjectWrapper.Builder.clearInstanceCache();
+        checkClassIntrospectorCacheSize(0);
+        
+        List<DefaultObjectWrapper> hardReferences = new LinkedList<>();
+        DefaultObjectWrapper.Builder builder;
+
+        {
+            builder = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
+            
+            DefaultObjectWrapper bw1 = builder.build();
+            checkClassIntrospectorCacheSize(1);
+            
+            builder.setExposureLevel(DefaultObjectWrapper.EXPOSE_SAFE);  // this was already set to this
+            builder.setUseModelCache(true);  // this shouldn't matter for the introspection cache
+            DefaultObjectWrapper bw2 = builder.build();
+            checkClassIntrospectorCacheSize(1);
+            
+            assertSame(bw2.getClassIntrospector(), bw1.getClassIntrospector());
+            assertNotSame(bw1, bw2);
+            
+            // Wrapping tests:
+            assertFalse(exposesFields(bw1));
+            assertTrue(exposesProperties(bw1));
+            assertTrue(exposesMethods(bw1));
+            assertFalse(exposesUnsafe(bw1));
+            assertTrue(bw1.isClassIntrospectionCacheRestricted());
+            // Prevent introspection cache GC:
+            hardReferences.add(bw1);
+            hardReferences.add(bw2);
+        }
+        
+        {
+            builder = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
+            builder.setExposeFields(true);
+            DefaultObjectWrapper ow = builder.build();
+            checkClassIntrospectorCacheSize(2);
+            // Wrapping tests:
+            assertTrue(exposesFields(ow));
+            assertTrue(exposesProperties(ow));
+            assertTrue(exposesMethods(ow));
+            assertFalse(exposesUnsafe(ow));
+            // Prevent introspection cache GC:
+            hardReferences.add(ow);
+        }
+
+        {
+            builder.setExposureLevel(DefaultObjectWrapper.EXPOSE_ALL);
+            DefaultObjectWrapper ow = builder.build();
+            checkClassIntrospectorCacheSize(3);
+            // Wrapping tests:
+            assertTrue(exposesFields(ow));
+            assertTrue(exposesProperties(ow));
+            assertTrue(exposesMethods(ow));
+            assertTrue(exposesUnsafe(ow));
+            // Prevent introspection cache GC:
+            hardReferences.add(ow);
+        }
+        
+        {
+            builder.setExposeFields(false);
+            DefaultObjectWrapper ow = builder.build();
+            checkClassIntrospectorCacheSize(4);
+            // Wrapping tests:
+            assertFalse(exposesFields(ow));
+            assertTrue(exposesProperties(ow));
+            assertTrue(exposesMethods(ow));
+            assertTrue(exposesUnsafe(ow));
+            // Prevent introspection cache GC:
+            hardReferences.add(ow);
+        }
+        
+        {
+            builder.setExposureLevel(DefaultObjectWrapper.EXPOSE_NOTHING);
+            DefaultObjectWrapper ow = builder.build();
+            checkClassIntrospectorCacheSize(5);
+            // Wrapping tests:
+            assertFalse(exposesFields(ow));
+            assertFalse(exposesProperties(ow));
+            assertFalse(exposesMethods(ow));
+            assertFalse(exposesUnsafe(ow));
+            // Prevent introspection cache GC:
+            hardReferences.add(ow);
+        }
+
+        {
+            builder.setExposeFields(true);
+            DefaultObjectWrapper ow = builder.build();
+            checkClassIntrospectorCacheSize(6);
+            // Wrapping tests:
+            assertTrue(exposesFields(ow));
+            assertFalse(exposesProperties(ow));
+            assertFalse(exposesMethods(ow));
+            assertFalse(exposesUnsafe(ow));
+            // Prevent introspection cache GC:
+            hardReferences.add(ow);
+        }
+
+        {
+            builder.setExposureLevel(DefaultObjectWrapper.EXPOSE_PROPERTIES_ONLY);
+            DefaultObjectWrapper ow = builder.build();
+            checkClassIntrospectorCacheSize(7);
+            // Wrapping tests:
+            assertTrue(exposesFields(ow));
+            assertTrue(exposesProperties(ow));
+            assertFalse(exposesMethods(ow));
+            assertFalse(exposesUnsafe(ow));
+            // Prevent introspection cache GC:
+            hardReferences.add(ow);
+        }
+        
+        {
+            builder = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
+            builder.setUseModelCache(true);
+            builder.setExposeFields(false);
+            builder.setExposureLevel(DefaultObjectWrapper.EXPOSE_PROPERTIES_ONLY);
+            
+            DefaultObjectWrapper bw1 = builder.build();
+            checkClassIntrospectorCacheSize(8);
+            ClassIntrospector ci1 = bw1.getClassIntrospector();
+            
+            builder.setUseModelCache(false);  // Shouldn't mater for the ClassIntrospector
+            DefaultObjectWrapper bw2 = builder.build();
+            ClassIntrospector ci2 = bw2.getClassIntrospector();
+            checkClassIntrospectorCacheSize(8);
+            
+            assertSame(ci1, ci2);
+            assertNotSame(bw1, bw2);
+            
+            // Wrapping tests:
+            assertFalse(exposesFields(bw1));
+            assertTrue(exposesProperties(bw1));
+            assertFalse(exposesMethods(bw1));
+            assertFalse(exposesUnsafe(bw1));
+
+            // Prevent introspection cache GC:
+            hardReferences.add(bw1);
+            hardReferences.add(bw2);
+        }
+
+        // The ClassInrospector cache couldn't become cleared in reality otherwise:
+        DefaultObjectWrapper.Builder.clearInstanceCache();
+
+        clearClassIntrospectorInstanceCacheReferences(false);
+        checkClassIntrospectorCacheSize(8);
+        assertEquals(0, getClassIntrospectorNonClearedInstanceCacheSize());
+
+        {
+            builder.setExposeFields(false);
+            
+            DefaultObjectWrapper bw1 = builder.build();
+            checkClassIntrospectorCacheSize(8);
+            assertEquals(1, getClassIntrospectorNonClearedInstanceCacheSize());
+            ClassIntrospector ci1 = bw1.getClassIntrospector();
+            
+            builder.setUseModelCache(true);  // Shouldn't mater
+            DefaultObjectWrapper bw2 = builder.build();
+            ClassIntrospector ci2 = bw2.getClassIntrospector();
+            
+            assertSame(ci1, ci2);
+            assertNotSame(bw1, bw2);
+            
+            // Wrapping tests:
+            assertFalse(exposesFields(bw1));
+            assertTrue(exposesProperties(bw1));
+            assertFalse(exposesMethods(bw1));
+            assertFalse(exposesUnsafe(bw1));
+
+            // Prevent introspection cache GC:
+            hardReferences.add(bw1);
+            hardReferences.add(bw2);
+        }
+        
+        {
+            builder = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
+            DefaultObjectWrapper ow = builder.build();
+            checkClassIntrospectorCacheSize(8);
+            assertEquals(2, getClassIntrospectorNonClearedInstanceCacheSize());
+            // Wrapping tests:
+            assertFalse(exposesFields(ow));
+            assertTrue(exposesProperties(ow));
+            assertTrue(exposesMethods(ow));
+            assertFalse(exposesUnsafe(ow));
+            // Prevent introspection cache GC:
+            hardReferences.add(ow);
+        }
+
+        clearClassIntrospectorInstanceCacheReferences(true);
+        checkClassIntrospectorCacheSize(8);
+        assertEquals(0, getClassIntrospectorNonClearedInstanceCacheSize());
+        
+        {
+            builder = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
+            builder.setExposeFields(true);
+            DefaultObjectWrapper ow = builder.build();
+            checkClassIntrospectorCacheSize(1);
+            // Wrapping tests:
+            assertTrue(exposesFields(ow));
+            assertTrue(exposesProperties(ow));
+            assertTrue(exposesMethods(ow));
+            assertFalse(exposesUnsafe(ow));
+            // Prevent introspection cache GC:
+            hardReferences.add(ow);
+        }
+        
+        {
+            builder = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
+            builder.setMethodAppearanceFineTuner(new MethodAppearanceFineTuner() {
+                @Override
+                public void process(DecisionInput in, Decision out) {
+                }
+            });  // spoils ClassIntrospector() sharing
+
+            builder.setUseModelCache(false);
+            DefaultObjectWrapper bw1 = builder.build();
+            assertSame(bw1, builder.build());
+
+            builder.setUseModelCache(true);
+            DefaultObjectWrapper bw2 = builder.build();
+            checkClassIntrospectorCacheSize(1);
+            assertNotSame(bw1, bw2);
+            assertNotSame(bw1.getClassIntrospector(), bw2.getClassIntrospector());
+            assertTrue(bw1.isClassIntrospectionCacheRestricted());
+            assertTrue(bw2.isClassIntrospectionCacheRestricted());
+        }
+
+        {
+            builder = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
+            builder.setMethodAppearanceFineTuner(
+                    GetlessMethodsAsPropertyGettersRule.INSTANCE);  // doesn't spoils sharing
+
+            builder.setUseModelCache(false);
+            DefaultObjectWrapper bw1 = builder.build();
+            assertSame(bw1, builder.build());
+            checkClassIntrospectorCacheSize(2);
+            
+            builder.setUseModelCache(true);
+            DefaultObjectWrapper bw2 = builder.build();
+            checkClassIntrospectorCacheSize(2);
+            
+            assertNotSame(bw1, bw2);
+            assertSame(bw1.getClassIntrospector(), bw2.getClassIntrospector());  // !
+            assertTrue(bw2.isClassIntrospectionCacheRestricted());
+        }
+        
+        assertTrue(hardReferences.size() != 0);  // just to save it from GC until this line        
+    }
+    
+    private void checkClassIntrospectorCacheSize(int expectedSize) {
+        assertEquals(expectedSize, getClassIntrospectorInstanceCacheSize());
+    }
+
+    public class C {
+        
+        public String foo = "FOO";
+        
+        public String getBar() {
+            return "BAR";
+        }
+        
+    }
+
+    private boolean exposesFields(DefaultObjectWrapper ow) throws TemplateModelException {
+        TemplateHashModel thm = (TemplateHashModel) ow.wrap(new C());
+        TemplateScalarModel r = (TemplateScalarModel) thm.get("foo");
+        if (r == null) return false;
+        assertEquals("FOO", r.getAsString());
+        return true;
+    }
+
+    private boolean exposesProperties(DefaultObjectWrapper ow) throws TemplateModelException {
+        TemplateHashModel thm = (TemplateHashModel) ow.wrap(new C());
+        TemplateScalarModel r = (TemplateScalarModel) thm.get("bar");
+        if (r == null) return false;
+        assertEquals("BAR", r.getAsString());
+        return true;
+    }
+
+    private boolean exposesMethods(DefaultObjectWrapper ow) throws TemplateModelException {
+        TemplateHashModel thm = (TemplateHashModel) ow.wrap(new C());
+        return thm.get("getBar") != null;
+    }
+
+    private boolean exposesUnsafe(DefaultObjectWrapper ow) throws TemplateModelException {
+        TemplateHashModel thm = (TemplateHashModel) ow.wrap(new C());
+        return thm.get("wait") != null;
+    }
+    
+    static int getClassIntrospectorInstanceCacheSize() {
+        Map instanceCache = ClassIntrospector.Builder.getInstanceCache();
+        synchronized (instanceCache) {
+            return instanceCache.size();
+        }
+    }
+
+    static int getClassIntrospectorNonClearedInstanceCacheSize() {
+        Map instanceCache = ClassIntrospector.Builder.getInstanceCache();
+        synchronized (instanceCache) {
+            int cnt = 0;
+            for (Iterator it = instanceCache.values().iterator(); it.hasNext(); ) {
+                if (((Reference) it.next()).get() != null) cnt++;
+            }
+            return cnt;
+        }
+    }
+    
+    static void clearClassIntrospectorInstanceCacheReferences(boolean enqueue) {
+        Map instanceCache = ClassIntrospector.Builder.getInstanceCache();
+        synchronized (instanceCache) {
+            for (Iterator it = instanceCache.values().iterator(); it.hasNext(); ) {
+                Reference ref = ((Reference) it.next());
+                ref.clear();
+                if (enqueue) {
+                    ref.enqueue();
+                }
+            }
+        }
+    }
+
+    static int getDefaultObjectWrapperInstanceCacheSize() {
+        Map instanceCache = DefaultObjectWrapper.Builder.getInstanceCache();
+        synchronized (instanceCache) {
+            int size = 0; 
+            for (Iterator it1 = instanceCache.values().iterator(); it1.hasNext(); ) {
+                size += ((Map) it1.next()).size();
+            }
+            return size;
+        }
+    }
+
+    static int getDefaultObjectWrapperNonClearedInstanceCacheSize() {
+        Map instanceCache = DefaultObjectWrapper.Builder.getInstanceCache();
+        synchronized (instanceCache) {
+            int cnt = 0;
+            for (Iterator it1 = instanceCache.values().iterator(); it1.hasNext(); ) {
+                Map tcclScope = (Map) it1.next();
+                for (Iterator it2 = tcclScope.values().iterator(); it2.hasNext(); ) {
+                    if (((Reference) it2.next()).get() != null) cnt++;
+                }
+            }
+            return cnt;
+        }
+    }
+    
+    static void clearDefaultObjectWrapperInstanceCacheReferences(boolean enqueue) {
+        Map instanceCache = DefaultObjectWrapper.Builder.getInstanceCache();
+        synchronized (instanceCache) {
+            for (Iterator it1 = instanceCache.values().iterator(); it1.hasNext(); ) {
+                Map tcclScope = (Map) it1.next();
+                for (Iterator it2 = tcclScope.values().iterator(); it2.hasNext(); ) {
+                    Reference ref = ((Reference) it2.next());
+                    ref.clear();
+                    if (enqueue) {
+                        ref.enqueue();
+                    }
+                }
+            }
+        }
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperTest.java
new file mode 100644
index 0000000..6e9ae25
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperTest.java
@@ -0,0 +1,901 @@
+/*
+ * 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.model.impl;
+
+import static org.apache.freemarker.test.hamcerst.Matchers.*;
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.Vector;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.Template;
+import org.apache.freemarker.core.TemplateException;
+import org.apache.freemarker.core.Version;
+import org.apache.freemarker.core._CoreAPI;
+import org.apache.freemarker.core.model.AdapterTemplateModel;
+import org.apache.freemarker.core.model.ObjectWrapper;
+import org.apache.freemarker.core.model.TemplateBooleanModel;
+import org.apache.freemarker.core.model.TemplateCollectionModel;
+import org.apache.freemarker.core.model.TemplateCollectionModelEx;
+import org.apache.freemarker.core.model.TemplateHashModel;
+import org.apache.freemarker.core.model.TemplateHashModelEx;
+import org.apache.freemarker.core.model.TemplateMethodModelEx;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateModelIterator;
+import org.apache.freemarker.core.model.TemplateModelWithAPISupport;
+import org.apache.freemarker.core.model.TemplateNodeModel;
+import org.apache.freemarker.core.model.TemplateNumberModel;
+import org.apache.freemarker.core.model.TemplateScalarModel;
+import org.apache.freemarker.core.model.TemplateSequenceModel;
+import org.apache.freemarker.core.model.WrapperTemplateModel;
+import org.apache.freemarker.core.model.WrappingTemplateModel;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+import org.junit.Test;
+import org.w3c.dom.Document;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+public class DefaultObjectWrapperTest {
+
+    private final static DefaultObjectWrapper OW = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0)
+            .build();
+
+    // This will make sense if we will have multipe incompatibleImprovement versions.
+    @Test
+    public void testIncompatibleImprovementsVersionBreakPoints() throws Exception {
+        List<Version> expected = new ArrayList<>();
+        expected.add(Configuration.VERSION_3_0_0);
+
+        List<Version> actual = new ArrayList<>();
+        int i = _CoreAPI.VERSION_INT_3_0_0;
+        while (i <= Configuration.getVersion().intValue()) {
+            int major = i / 1000000;
+            int minor = i % 1000000 / 1000;
+            int micro = i % 1000;
+            final Version version = new Version(major, minor, micro);
+            
+            final Version normalizedVersion = DefaultObjectWrapper.normalizeIncompatibleImprovementsVersion(version);
+            actual.add(normalizedVersion);
+
+            final DefaultObjectWrapper.Builder builder = new DefaultObjectWrapper.Builder(version);
+            assertEquals(normalizedVersion, builder.getIncompatibleImprovements());
+            assertEquals(normalizedVersion, builder.build().getIncompatibleImprovements());
+            
+            i++;
+        }
+
+        assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testIncompatibleImprovementsVersionOutOfBounds() throws Exception {
+        try {
+            DefaultObjectWrapper.normalizeIncompatibleImprovementsVersion(new Version(2, 2, 0));
+            fail();
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+
+        Version curVersion = Configuration.getVersion();
+        final Version futureVersion = new Version(curVersion.getMajor(), curVersion.getMicro(),
+                curVersion.getMicro() + 1);
+        try {
+            DefaultObjectWrapper.normalizeIncompatibleImprovementsVersion(futureVersion);
+            fail();
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+        try {
+            new DefaultObjectWrapper.Builder(futureVersion);
+            fail();
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
+    @SuppressWarnings("boxing")
+    @Test
+    public void testBuilder() throws Exception {
+        DefaultObjectWrapper.Builder builder = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
+        DefaultObjectWrapper ow = builder.build();
+        assertSame(ow, builder.build());
+        assertSame(ow.getClass(), DefaultObjectWrapper.class);
+        assertEquals(Configuration.VERSION_3_0_0, ow.getIncompatibleImprovements());
+    }
+
+    @Test
+    public void testWrappedTypes() throws Exception {
+        DefaultObjectWrapper.Builder builder = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
+        DefaultObjectWrapper ow = builder.build();
+
+        assertThat(ow.wrap(new HashMap()), instanceOf(DefaultMapAdapter.class));
+        assertThat(ow.wrap(new ArrayList()), instanceOf(DefaultListAdapter.class));
+        assertThat(ow.wrap(new String[] {}), instanceOf(DefaultArrayAdapter.class));
+        assertThat(ow.wrap(new HashSet()), instanceOf(DefaultNonListCollectionAdapter.class));
+        assertThat(ow.wrap(new PureIterable()), instanceOf(DefaultIterableAdapter.class));
+        assertThat(ow.wrap(new Vector<>().iterator()), instanceOf(DefaultIteratorAdapter.class));
+        assertThat(ow.wrap(new Vector<>().elements()), instanceOf(DefaultEnumerationAdapter.class));
+    }
+    
+    @Test
+    public void testConstructors() throws Exception {
+        {
+            DefaultObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0)
+                    .usePrivateCaches(true).build();
+            assertEquals(Configuration.VERSION_3_0_0, ow.getIncompatibleImprovements());
+        }
+        
+        try {
+            new DefaultObjectWrapper.Builder(new Version(99, 9, 9)).build();
+            fail();
+        } catch (IllegalArgumentException e) {
+            assertThat(e.getMessage(), containsString("version"));
+        }
+    }
+    
+    
+    @Test
+    public void testCustomization() throws TemplateModelException {
+        CustomizedDefaultObjectWrapper ow = new CustomizedDefaultObjectWrapper(Configuration.VERSION_3_0_0);
+        assertEquals(Configuration.VERSION_3_0_0, ow.getIncompatibleImprovements());
+
+        TemplateSequenceModel seq = (TemplateSequenceModel) ow.wrap(new Tupple(11, 22));
+        assertEquals(2, seq.size());
+        assertEquals(11, ow.unwrap(seq.get(0)));
+        assertEquals(22, ow.unwrap(seq.get(1)));
+        
+        assertTrue(ow.wrap("x") instanceof SimpleScalar);
+        assertTrue(ow.wrap(1.5) instanceof SimpleNumber);
+        assertTrue(ow.wrap(new Date()) instanceof SimpleDate);
+        assertEquals(TemplateBooleanModel.TRUE, ow.wrap(true));
+        
+        assertTrue(ow.wrap(Collections.emptyMap()) instanceof DefaultMapAdapter);
+        assertTrue(ow.wrap(Collections.emptyList()) instanceof DefaultListAdapter);
+        assertTrue(ow.wrap(new boolean[] { }) instanceof DefaultArrayAdapter);
+        assertTrue(ow.wrap(new HashSet()) instanceof DefaultNonListCollectionAdapter);
+        assertTrue(ow.wrap('c') instanceof TemplateScalarModel); // BeanAndStringModel right now, but should change later
+        
+        TemplateHashModel bean = (TemplateHashModel) ow.wrap(new TestBean());
+        assertEquals(1, ow.unwrap(bean.get("x")));
+        {
+            // Check method calls, and also if the return value is wrapped with the overidden "wrap".
+            final TemplateModel mr = (TemplateModel) ((TemplateMethodModelEx) bean.get("m")).exec(Collections.emptyList());
+            assertEquals(
+                    Collections.singletonList(1),
+                    ow.unwrap(mr));
+            assertTrue(DefaultListAdapter.class.isInstance(mr));
+        }
+        {
+            // Check custom TM usage and round trip:
+            final TemplateModel mr = (TemplateModel) ((TemplateMethodModelEx) bean.get("incTupple"))
+                    .exec(Collections.singletonList(ow.wrap(new Tupple<>(1, 2))));
+            assertEquals(new Tupple<>(2, 3), ow.unwrap(mr));
+            assertTrue(TuppleAdapter.class.isInstance(mr));
+        }
+    }
+
+    @SuppressWarnings("boxing")
+    @Test
+    public void testCompositeValueWrapping() throws TemplateModelException, ClassNotFoundException {
+        DefaultObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
+
+        final Map hashMap = new HashMap();
+        inintTestMap(hashMap);
+        final Map treeMap = new TreeMap();
+        inintTestMap(treeMap);
+        final Map linkedHashMap = new LinkedHashMap();
+        inintTestMap(linkedHashMap);
+        final Map gMap = ImmutableMap.<String, Object> of("a", 1, "b", 2, "c", 3);
+        final LinkedList linkedList = new LinkedList();
+        linkedList.add("a");
+        linkedList.add("b");
+        linkedList.add("c");
+        final int[] intArray = new int[] { 1, 2, 3 };
+        final String[] stringArray = new String[] { "a", "b", "c" };
+        final PureIterable pureIterable = new PureIterable();
+        final HashSet hashSet = new HashSet();
+
+        assertRoundtrip(ow, linkedHashMap, DefaultMapAdapter.class, LinkedHashMap.class, linkedHashMap.toString());
+        assertRoundtrip(ow, treeMap, DefaultMapAdapter.class, TreeMap.class, treeMap.toString());
+        assertRoundtrip(ow, gMap, DefaultMapAdapter.class, ImmutableMap.class, gMap.toString());
+        assertRoundtrip(ow, linkedList, DefaultListAdapter.class, LinkedList.class, linkedList.toString());
+        assertRoundtrip(ow, intArray, DefaultArrayAdapter.class, int[].class, null);
+        assertRoundtrip(ow, stringArray, DefaultArrayAdapter.class, String[].class, null);
+        assertRoundtrip(ow, pureIterable, DefaultIterableAdapter.class, PureIterable.class, pureIterable.toString());
+        assertRoundtrip(ow, hashSet, DefaultNonListCollectionAdapter.class, HashSet.class, hashSet.toString());
+    }
+
+    @SuppressWarnings("boxing")
+    private void inintTestMap(Map map) {
+        map.put("a", 1);
+        map.put("b", 2);
+        map.put("c", 3);
+    }
+
+    @SuppressWarnings("boxing")
+    @Test
+    public void testMapAdapter() throws TemplateModelException {
+        HashMap<String, Object> testMap = new LinkedHashMap<>();
+        testMap.put("a", 1);
+        testMap.put("b", null);
+        testMap.put("c", "C");
+        testMap.put("d", Collections.singletonList("x"));
+
+        {
+            TemplateHashModelEx hash = (TemplateHashModelEx) OW.wrap(testMap);
+            assertEquals(4, hash.size());
+            assertFalse(hash.isEmpty());
+            assertNull(hash.get("e"));
+            assertEquals(1, ((TemplateNumberModel) hash.get("a")).getAsNumber());
+            assertNull(hash.get("b"));
+            assertEquals("C", ((TemplateScalarModel) hash.get("c")).getAsString());
+            assertTrue(hash.get("d") instanceof DefaultListAdapter);
+
+            assertCollectionTMEquals(hash.keys(), "a", "b", "c", "d");
+            assertCollectionTMEquals(hash.values(), 1, null, "C", Collections.singletonList("x"));
+            
+            assertSizeThroughAPIModel(4, hash);
+        }
+
+        {
+            assertTrue(((TemplateHashModel) OW.wrap(Collections.emptyMap())).isEmpty());
+        }
+    }
+
+    private void assertCollectionTMEquals(TemplateCollectionModel coll, Object... expectedItems)
+            throws TemplateModelException {
+        for (int i = 0; i < 2; i++) { // Run twice to check if we always get a new iterator
+            int idx = 0;
+            TemplateModelIterator it2 = null;
+            for (TemplateModelIterator it = coll.iterator(); it.hasNext(); ) {
+                TemplateModel actualItem = it.next();
+                if (idx >= expectedItems.length) {
+                    fail("Number of items is more than the expected " + expectedItems.length);
+                }
+                assertEquals(expectedItems[idx], OW.unwrap(actualItem));
+                if (i == 1) {
+                    // In the 2nd round we also test with two iterators in parallel.
+                    // This 2nd iterator is also special in that its hasNext() is never called.
+                    if (it2 == null) {
+                        it2 = coll.iterator();
+                    }
+                    assertEquals(expectedItems[idx], OW.unwrap(it2.next()));
+                }
+                idx++;
+            }
+            if (expectedItems.length != idx) {
+                fail("Number of items is " + idx + ", which is less than the expected " + expectedItems.length);
+            }
+        }
+    }
+
+    @SuppressWarnings("boxing")
+    @Test
+    public void testListAdapter() throws TemplateModelException {
+        {
+            List testList = new ArrayList<>();
+            testList.add(1);
+            testList.add(null);
+            testList.add("c");
+            testList.add(new String[] { "x" });
+
+            TemplateSequenceModel seq = (TemplateSequenceModel) OW.wrap(testList);
+            assertTrue(seq instanceof DefaultListAdapter);
+            assertFalse(seq instanceof TemplateCollectionModel); // Maybe changes at 2.4.0
+            assertEquals(4, seq.size());
+            assertNull(seq.get(-1));
+            assertEquals(1, ((TemplateNumberModel) seq.get(0)).getAsNumber());
+            assertNull(seq.get(1));
+            assertEquals("c", ((TemplateScalarModel) seq.get(2)).getAsString());
+            assertTrue(seq.get(3) instanceof DefaultArrayAdapter);
+            assertNull(seq.get(4));
+            
+            assertSizeThroughAPIModel(4, seq);
+        }
+
+        {
+            List testList = new LinkedList<>();
+            testList.add(1);
+            testList.add(null);
+            testList.add("c");
+
+            TemplateSequenceModel seq = (TemplateSequenceModel) OW.wrap(testList);
+            assertTrue(seq instanceof DefaultListAdapter);
+            assertTrue(seq instanceof TemplateCollectionModel); // Maybe changes at 2.4.0
+            assertEquals(3, seq.size());
+            assertNull(seq.get(-1));
+            assertEquals(1, ((TemplateNumberModel) seq.get(0)).getAsNumber());
+            assertNull(seq.get(1));
+            assertEquals("c", ((TemplateScalarModel) seq.get(2)).getAsString());
+            assertNull(seq.get(3));
+
+            assertCollectionTMEquals((TemplateCollectionModel) seq, 1, null, "c");
+
+            TemplateModelIterator it = ((TemplateCollectionModel) seq).iterator();
+            it.next();
+            it.next();
+            it.next();
+            try {
+                it.next();
+                fail();
+            } catch (TemplateModelException e) {
+                assertThat(e.getMessage(), containsString("no more"));
+            }
+        }
+    }
+
+    @Test
+    public void testArrayAdapterTypes() throws TemplateModelException {
+        assertArrayAdapterClass("Object", OW.wrap(new Object[] {}));
+        assertArrayAdapterClass("Object", OW.wrap(new String[] {}));
+        assertArrayAdapterClass("byte", OW.wrap(new byte[] {}));
+        assertArrayAdapterClass("short", OW.wrap(new short[] {}));
+        assertArrayAdapterClass("int", OW.wrap(new int[] {}));
+        assertArrayAdapterClass("long", OW.wrap(new long[] {}));
+        assertArrayAdapterClass("float", OW.wrap(new float[] {}));
+        assertArrayAdapterClass("double", OW.wrap(new double[] {}));
+        assertArrayAdapterClass("boolean", OW.wrap(new boolean[] {}));
+        assertArrayAdapterClass("char", OW.wrap(new char[] {}));
+    }
+
+    private void assertArrayAdapterClass(String adapterCompType, TemplateModel adaptedArray) {
+        assertTrue(adaptedArray instanceof DefaultArrayAdapter);
+        assertThat(adaptedArray.getClass().getName(),
+                containsString("$" + adapterCompType.substring(0, 1).toUpperCase() + adapterCompType.substring(1)));
+    }
+
+    @SuppressWarnings("boxing")
+    @Test
+    public void testArrayAdapters() throws TemplateModelException {
+        {
+            final String[] testArray = new String[] { "a", null, "c" };
+
+            TemplateSequenceModel seq = (TemplateSequenceModel) OW.wrap(testArray);
+            assertEquals(3, seq.size());
+            assertNull(seq.get(-1));
+            assertEquals("a", ((TemplateScalarModel) seq.get(0)).getAsString());
+            assertNull(seq.get(1));
+            assertEquals("c", ((TemplateScalarModel) seq.get(2)).getAsString());
+            assertNull(seq.get(3));
+        }
+
+        {
+            final int[] testArray = new int[] { 11, 22 };
+            TemplateSequenceModel seq = (TemplateSequenceModel) OW.wrap(testArray);
+            assertEquals(2, seq.size());
+            assertNull(seq.get(-1));
+            assertEqualsAndSameClass(Integer.valueOf(11), ((TemplateNumberModel) seq.get(0)).getAsNumber());
+            assertEqualsAndSameClass(Integer.valueOf(22), ((TemplateNumberModel) seq.get(1)).getAsNumber());
+            assertNull(seq.get(2));
+        }
+
+        {
+            final double[] testArray = new double[] { 11, 22 };
+            TemplateSequenceModel seq = (TemplateSequenceModel) OW.wrap(testArray);
+            assertEquals(2, seq.size());
+            assertNull(seq.get(-1));
+            assertEqualsAndSameClass(Double.valueOf(11), ((TemplateNumberModel) seq.get(0)).getAsNumber());
+            assertEqualsAndSameClass(Double.valueOf(22), ((TemplateNumberModel) seq.get(1)).getAsNumber());
+            assertNull(seq.get(2));
+        }
+
+        {
+            final boolean[] testArray = new boolean[] { true, false };
+            TemplateSequenceModel seq = (TemplateSequenceModel) OW.wrap(testArray);
+            assertEquals(2, seq.size());
+            assertNull(seq.get(-1));
+            assertEqualsAndSameClass(Boolean.valueOf(true), ((TemplateBooleanModel) seq.get(0)).getAsBoolean());
+            assertEqualsAndSameClass(Boolean.valueOf(false), ((TemplateBooleanModel) seq.get(1)).getAsBoolean());
+            assertNull(seq.get(2));
+        }
+
+        {
+            final char[] testArray = new char[] { 'a', 'b' };
+            TemplateSequenceModel seq = (TemplateSequenceModel) OW.wrap(testArray);
+            assertEquals(2, seq.size());
+            assertNull(seq.get(-1));
+            assertEquals("a", ((TemplateScalarModel) seq.get(0)).getAsString());
+            assertEquals("b", ((TemplateScalarModel) seq.get(1)).getAsString());
+            assertNull(seq.get(2));
+        }
+    }
+
+    private void assertEqualsAndSameClass(Object expected, Object actual) {
+        assertEquals(expected, actual);
+        if (expected != null) {
+            assertEquals(expected.getClass(), actual.getClass());
+        }
+    }
+
+    private void assertRoundtrip(DefaultObjectWrapper dow, Object obj, Class expectedTMClass,
+            Class expectedPojoClass,
+            String expectedPojoToString)
+            throws TemplateModelException {
+        final TemplateModel objTM = dow.wrap(obj);
+        assertThat(objTM.getClass(), typeCompatibleWith(expectedTMClass));
+
+        final TemplateHashModel testBeanTM = (TemplateHashModel) dow.wrap(new RoundtripTesterBean());
+
+        {
+            TemplateMethodModelEx getClassM = (TemplateMethodModelEx) testBeanTM.get("getClass");
+            Object r = getClassM.exec(Collections.singletonList(objTM));
+            final Class rClass = (Class) ((WrapperTemplateModel) r).getWrappedObject();
+            assertThat(rClass, typeCompatibleWith(expectedPojoClass));
+        }
+
+        if (expectedPojoToString != null) {
+            TemplateMethodModelEx getToStringM = (TemplateMethodModelEx) testBeanTM.get("toString");
+            Object r = getToStringM.exec(Collections.singletonList(objTM));
+            assertEquals(expectedPojoToString, ((TemplateScalarModel) r).getAsString());
+        }
+    }
+
+    @SuppressWarnings("boxing")
+    @Test
+    public void testCollectionAdapterBasics() throws TemplateModelException {
+        {
+            Set set = new TreeSet();
+            set.add("a");
+            set.add("b");
+            set.add("c");
+            TemplateCollectionModelEx coll = (TemplateCollectionModelEx) OW.wrap(set);
+            assertTrue(coll instanceof DefaultNonListCollectionAdapter);
+            assertEquals(3, coll.size());
+            assertFalse(coll.isEmpty());
+            assertCollectionTMEquals(coll, "a", "b", "c");
+
+            assertRoundtrip(OW, set, DefaultNonListCollectionAdapter.class, TreeSet.class, "[a, b, c]");
+            
+            assertSizeThroughAPIModel(3, coll);
+        }
+
+        {
+            Set set = new HashSet();
+            final List<String> list = Collections.singletonList("b");
+            set.add(list);
+            set.add(null);
+            TemplateCollectionModelEx coll = (TemplateCollectionModelEx) OW.wrap(set);
+            TemplateModelIterator it = coll.iterator();
+            final TemplateModel tm1 = it.next();
+            Object obj1 = OW.unwrap(tm1);
+            final TemplateModel tm2 = it.next();
+            Object obj2 = OW.unwrap(tm2);
+            assertTrue(obj1 == null || obj2 == null);
+            assertTrue(obj1 != null && obj1.equals(list) || obj2 != null && obj2.equals(list));
+            assertTrue(tm1 instanceof DefaultListAdapter || tm2 instanceof DefaultListAdapter);
+
+            assertRoundtrip(OW, set, DefaultNonListCollectionAdapter.class, HashSet.class, "[" + obj1 + ", "
+                    + obj2 + "]");
+        }
+    }
+
+    @SuppressWarnings("boxing")
+    @Test
+    public void testCollectionAdapterOutOfBounds() throws TemplateModelException {
+        Set set = Collections.singleton(123);
+
+        TemplateCollectionModelEx coll = (TemplateCollectionModelEx) OW.wrap(set);
+        TemplateModelIterator it = coll.iterator();
+
+        for (int i = 0; i < 3; i++) {
+            assertTrue(it.hasNext());
+        }
+
+        assertEquals(123, OW.unwrap(it.next()));
+
+        for (int i = 0; i < 3; i++) {
+            assertFalse(it.hasNext());
+            try {
+                it.next();
+                fail();
+            } catch (TemplateModelException e) {
+                assertThat(e.getMessage(), containsStringIgnoringCase("no more"));
+            }
+        }
+    }
+
+    @Test
+    public void testCollectionAdapterAndNulls() throws TemplateModelException {
+        Set set = new HashSet();
+        set.add(null);
+
+        TemplateCollectionModelEx coll = (TemplateCollectionModelEx) OW.wrap(set);
+        assertEquals(1, coll.size());
+        assertFalse(coll.isEmpty());
+        assertNull(coll.iterator().next());
+    }
+
+    @Test
+    public void testIteratorWrapping() throws TemplateModelException, ClassNotFoundException {
+        final List<String> list = ImmutableList.of("a", "b", "c");
+        Iterator<String> it = list.iterator();
+        TemplateCollectionModel coll = (TemplateCollectionModel) OW.wrap(it);
+
+        assertRoundtrip(OW, coll, DefaultIteratorAdapter.class, Iterator.class, null);
+
+        TemplateModelIterator itIt = coll.iterator();
+        TemplateModelIterator itIt2 = coll.iterator(); // used later
+        assertTrue(itIt.hasNext());
+        assertEquals("a", OW.unwrap(itIt.next()));
+        assertTrue(itIt.hasNext());
+        assertEquals("b", OW.unwrap(itIt.next()));
+        assertTrue(itIt.hasNext());
+        assertEquals("c", OW.unwrap(itIt.next()));
+        assertFalse(itIt.hasNext());
+        try {
+            itIt.next();
+            fail();
+        } catch (TemplateModelException e) {
+            assertThat(e.getMessage(), containsStringIgnoringCase("no more"));
+        }
+
+        try {
+            itIt2.hasNext();
+            fail();
+        } catch (TemplateModelException e) {
+            assertThat(e.getMessage(), containsString("can be listed only once"));
+        }
+
+        TemplateModelIterator itIt3 = coll.iterator();
+        try {
+            itIt3.hasNext();
+            fail();
+        } catch (TemplateModelException e) {
+            assertThat(e.getMessage(), containsString("can be listed only once"));
+        }
+    }
+
+    @Test
+    public void testIteratorApiSupport() throws TemplateModelException {
+        TemplateModel wrappedIterator = OW.wrap(Collections.emptyIterator());
+        assertThat(wrappedIterator, instanceOf(DefaultIteratorAdapter.class));
+        DefaultIteratorAdapter iteratorAdapter = (DefaultIteratorAdapter) wrappedIterator;
+
+        TemplateHashModel api = (TemplateHashModel) iteratorAdapter.getAPI();
+        assertFalse(((TemplateBooleanModel) ((TemplateMethodModelEx)
+                api.get("hasNext")).exec(Collections.emptyList())).getAsBoolean());
+    }
+
+    @SuppressWarnings("boxing")
+    @Test
+    public void testCharKeyFallback() throws TemplateModelException {
+        Map hashMapS = new HashMap<>();
+        hashMapS.put("a", 1);
+        Map sortedMapS = new TreeMap<>();
+        sortedMapS.put("a", 1);
+        Map hashMapC = new HashMap<>();
+        hashMapC.put('a', 1);
+        Map sortedMapC = new TreeMap<>();
+        sortedMapC.put('a', 1);
+        
+        assertEquals(1, OW.unwrap(((TemplateHashModel) OW.wrap(hashMapS)).get("a")));
+        assertEquals(1, OW.unwrap(((TemplateHashModel) OW.wrap(hashMapC)).get("a")));
+        assertEquals(1, OW.unwrap(((TemplateHashModel) OW.wrap(sortedMapS)).get("a")));
+        try {
+            ((TemplateHashModel) OW.wrap(sortedMapC)).get("a");
+        } catch (TemplateModelException e) {
+            assertThat(e.getMessage(), containsStringIgnoringCase("String key"));
+        }
+        
+        assertNull(((TemplateHashModel) OW.wrap(hashMapS)).get("b"));
+        assertNull(((TemplateHashModel) OW.wrap(hashMapC)).get("b"));
+        assertNull(((TemplateHashModel) OW.wrap(sortedMapS)).get("b"));
+        try {
+            ((TemplateHashModel) OW.wrap(sortedMapC)).get("b");
+        } catch (TemplateModelException e) {
+            assertThat(e.getMessage(), containsStringIgnoringCase("String key"));
+        }
+    }
+    
+    @Test
+    public void testIterableSupport() throws TemplateException, IOException {
+        Iterable<String> iterable = new PureIterable();
+        
+        String listingFTL = "<#list value as x>${x}<#sep>, </#list>";
+        
+        DefaultObjectWrapper ow = OW;
+        TemplateModel tm = ow.wrap(iterable);
+        assertThat(tm, instanceOf(TemplateCollectionModel.class));
+        TemplateCollectionModel iterableTM = (TemplateCollectionModel) tm;
+
+        for (int i = 0; i < 2; i++) {
+            TemplateModelIterator iteratorTM = iterableTM.iterator();
+            assertTrue(iteratorTM.hasNext());
+            assertEquals("a", ow.unwrap(iteratorTM.next()));
+            assertTrue(iteratorTM.hasNext());
+            assertEquals("b", ow.unwrap(iteratorTM.next()));
+            assertTrue(iteratorTM.hasNext());
+            assertEquals("c", ow.unwrap(iteratorTM.next()));
+            assertFalse(iteratorTM.hasNext());
+            try {
+                iteratorTM.next();
+                fail();
+            } catch (TemplateModelException e) {
+                assertThat(e.getMessage(), containsStringIgnoringCase("no more"));
+            }
+        }
+
+        assertTemplateOutput(OW, iterable, listingFTL, "a, b, c");
+    }
+
+    @Test
+    public void testEnumerationAdapter() throws TemplateModelException {
+        Vector<String> vector = new Vector<String>();
+        vector.add("a");
+        vector.add("b");
+
+        TemplateModel wrappedEnumeration = OW.wrap(vector.elements());
+        assertThat(wrappedEnumeration, instanceOf(DefaultEnumerationAdapter.class));
+        DefaultEnumerationAdapter enumAdapter = (DefaultEnumerationAdapter) wrappedEnumeration;
+        TemplateModelIterator iterator = enumAdapter.iterator();
+        assertTrue(iterator.hasNext());
+        assertEquals("a", ((TemplateScalarModel) iterator.next()).getAsString());
+        assertTrue(iterator.hasNext());
+        assertEquals("b", ((TemplateScalarModel) iterator.next()).getAsString());
+        assertFalse(iterator.hasNext());
+
+        iterator = enumAdapter.iterator();
+        try {
+            iterator.hasNext();
+        } catch (TemplateException e) {
+            assertThat(e.getMessage(), containsStringIgnoringCase("only once"));
+        }
+
+        TemplateHashModel api = (TemplateHashModel) enumAdapter.getAPI();
+        assertFalse(((TemplateBooleanModel) ((TemplateMethodModelEx)
+                api.get("hasMoreElements")).exec(Collections.emptyList())).getAsBoolean());
+    }
+
+    @Test
+    public void assertCanWrapDOM() throws SAXException, IOException, ParserConfigurationException,
+            TemplateModelException {
+        DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+        InputSource is = new InputSource();
+        is.setCharacterStream(new StringReader("<doc><sub a='1' /></doc>"));
+        Document doc = db.parse(is);        
+        assertTrue(OW.wrap(doc) instanceof TemplateNodeModel);
+    }
+
+    @Test
+    public void testExposureLevel() throws Exception {
+        TestBean bean = new TestBean();
+
+        {
+            TemplateHashModel tm = wrapWithExposureLevel(bean, DefaultObjectWrapper.EXPOSE_SAFE);
+            assertNotNull(tm.get("hashCode"));
+            assertNotNull(tm.get("class"));
+        }
+
+        {
+            TemplateHashModel tm = wrapWithExposureLevel(bean, DefaultObjectWrapper.EXPOSE_PROPERTIES_ONLY);
+            assertNull(tm.get("hashCode"));
+            assertNotNull(tm.get("class"));
+        }
+
+        {
+            TemplateHashModel tm = wrapWithExposureLevel(bean, DefaultObjectWrapper.EXPOSE_NOTHING);
+            assertNull(tm.get("hashCode"));
+            assertNull(tm.get("class"));
+        }
+
+        {
+            TemplateHashModel tm = wrapWithExposureLevel(bean, DefaultObjectWrapper.EXPOSE_ALL);
+            assertNotNull(tm.get("hashCode"));
+            assertNotNull(tm.get("class"));
+        }
+    }
+
+    private TemplateHashModel wrapWithExposureLevel(Object bean, int exposureLevel) throws TemplateModelException {
+        return (TemplateHashModel) new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0)
+                .exposureLevel(exposureLevel).build()
+                .wrap(bean);
+    }
+
+    private void assertSizeThroughAPIModel(int expectedSize, TemplateModel normalModel) throws TemplateModelException {
+        if (!(normalModel instanceof TemplateModelWithAPISupport)) {
+            fail(); 
+        }
+        TemplateHashModel apiModel = (TemplateHashModel) ((TemplateModelWithAPISupport) normalModel).getAPI();
+        TemplateMethodModelEx sizeMethod = (TemplateMethodModelEx) apiModel.get("size");
+        TemplateNumberModel r = (TemplateNumberModel) sizeMethod.exec(Collections.emptyList());
+        assertEquals(expectedSize, r.getAsNumber().intValue());
+    }
+
+    private void assertTemplateOutput(ObjectWrapper objectWrapper, Object value, String ftl, String expectedOutput)
+            throws TemplateException, IOException {
+        assertEquals(expectedOutput, processTemplate(objectWrapper, value, ftl));
+    }
+
+    private void assertTemplateFails(ObjectWrapper objectWrapper, Object value, String ftl, String expectedMessagePart)
+            throws TemplateException, IOException {
+        try {
+            processTemplate(objectWrapper, value, ftl);
+            fail();
+        } catch (TemplateException e) {
+            assertThat(e.getMessage(), containsString(expectedMessagePart));
+        }
+    }
+    
+    private String processTemplate(ObjectWrapper objectWrapper, Object value, String ftl)
+            throws TemplateException, IOException {
+        Configuration cfg = new TestConfigurationBuilder()
+                .logTemplateExceptions(false)
+                .objectWrapper(objectWrapper)
+                .build();
+        StringWriter out = new StringWriter();
+        new Template(null, ftl, cfg).process(ImmutableMap.of("value", value), out);
+        return out.toString();
+    }
+
+    private static final class PureIterable implements Iterable<String> {
+        @Override
+        public Iterator<String> iterator() {
+            return ImmutableList.of("a", "b", "c").iterator();
+        }
+    }
+
+    public static class RoundtripTesterBean {
+
+        public Class getClass(Object o) {
+            return o.getClass();
+        }
+
+        public String toString(Object o) {
+            return o.toString();
+        }
+
+    }
+    
+    private static class Tupple<E1, E2> {
+        
+        private final E1 e1;
+        private final E2 e2;
+
+        public Tupple(E1 e1, E2 e2) {
+            if (e1 == null || e2 == null) throw new NullPointerException();
+            this.e1 = e1;
+            this.e2 = e2;
+        }
+
+        public E1 getE1() {
+            return e1;
+        }
+
+        public E2 getE2() {
+            return e2;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((e1 == null) ? 0 : e1.hashCode());
+            result = prime * result + ((e2 == null) ? 0 : e2.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) return true;
+            if (obj == null) return false;
+            if (getClass() != obj.getClass()) return false;
+            Tupple other = (Tupple) obj;
+            if (e1 == null) {
+                if (other.e1 != null) return false;
+            } else if (!e1.equals(other.e1)) return false;
+            if (e2 == null) {
+                if (other.e2 != null) return false;
+            } else if (!e2.equals(other.e2)) return false;
+            return true;
+        }
+        
+    }
+    
+    @SuppressWarnings("boxing")
+    public static class TestBean {
+        
+        public int getX() {
+            return 1;
+        }
+        
+        public List<Integer> m() {
+            return Collections.singletonList(1);
+        }
+
+        public Tupple incTupple(Tupple<Integer, Integer> tupple) {
+            return new Tupple(tupple.e1 + 1, tupple.e2 + 1);
+        }
+        
+    }
+    
+    private static class CustomizedDefaultObjectWrapper extends DefaultObjectWrapper {
+
+        private CustomizedDefaultObjectWrapper(Version incompatibleImprovements) {
+            super(new DefaultObjectWrapper.Builder(incompatibleImprovements), true);
+        }
+        
+        @Override
+        protected TemplateModel handleNonBasicTypes(final Object obj) throws TemplateModelException {
+            if (obj instanceof Tupple) {
+                return new TuppleAdapter((Tupple<?, ?>) obj, this);
+            }
+            
+            return super.handleNonBasicTypes(obj);
+        }
+        
+    }
+    
+    private static class TuppleAdapter extends WrappingTemplateModel implements TemplateSequenceModel,
+            AdapterTemplateModel {
+        
+        private final Tupple<?, ?> tupple;
+        
+        public TuppleAdapter(Tupple<?, ?> tupple, ObjectWrapper ow) {
+            super(ow);
+            this.tupple = tupple;
+        }
+
+        @Override
+        public int size() throws TemplateModelException {
+            return 2;
+        }
+        
+        @Override
+        public TemplateModel get(int index) throws TemplateModelException {
+            switch (index) {
+            case 0: return wrap(tupple.getE1());
+            case 1: return wrap(tupple.getE2());
+            default: return null;
+            }
+        }
+
+        @Override
+        public Object getAdaptedObject(Class hint) {
+            return tupple;
+        }
+        
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/EnumModelsTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/EnumModelsTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/EnumModelsTest.java
new file mode 100644
index 0000000..fc19bb7
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/EnumModelsTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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.model.impl;
+
+import static org.junit.Assert.*;
+
+import java.util.ArrayList;
+
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.model.TemplateHashModel;
+import org.apache.freemarker.core.model.TemplateMethodModelEx;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateScalarModel;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class EnumModelsTest {
+    
+    @Test
+    public void modelCaching() throws Exception {
+        DefaultObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).usePrivateCaches(true)
+                .build();
+        TemplateHashModel enums = ow.getEnumModels();
+        TemplateHashModel e = (TemplateHashModel) enums.get(E.class.getName());
+        assertNotNull(e);
+        assertNotNull(e.get("A"));
+        assertNotNull(e.get("B"));
+        assertNull(e.get("C"));
+
+        try {
+            enums.get("no.such.ClassExists");
+            fail();
+        } catch (TemplateModelException ex) {
+            assertTrue(ex.getCause() instanceof ClassNotFoundException);
+        }
+        
+        TemplateModel a = e.get("A");
+        assertTrue(a instanceof TemplateScalarModel);
+        assertTrue(a instanceof TemplateHashModel);
+        assertEquals(((TemplateScalarModel) a).getAsString(), "ts:A");
+        TemplateMethodModelEx nameMethod = (TemplateMethodModelEx) ((TemplateHashModel) a).get("name");
+        assertEquals(((TemplateScalarModel) nameMethod.exec(new ArrayList())).getAsString(), "A");
+        
+        assertSame(e, enums.get(E.class.getName()));
+        
+        ow.clearClassIntrospecitonCache();
+        TemplateHashModel eAfterClean = (TemplateHashModel) enums.get(E.class.getName());
+        assertNotSame(e, eAfterClean);
+        assertSame(eAfterClean, enums.get(E.class.getName()));
+        assertNotNull(eAfterClean.get("A"));
+        assertNotNull(eAfterClean.get("B"));
+        assertNull(eAfterClean.get("C"));
+    }
+    
+    public enum E {
+        A, B;
+
+        @Override
+        public String toString() {
+            return "ts:" + super.toString();
+        }
+        
+    }
+
+}


[44/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/OutputFormatTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/OutputFormatTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/OutputFormatTest.java
new file mode 100644
index 0000000..eedb4d1
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/OutputFormatTest.java
@@ -0,0 +1,1068 @@
+/*
+ * 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.apache.freemarker.core.ParsingConfiguration.*;
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.Collections;
+
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.outputformat.OutputFormat;
+import org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat;
+import org.apache.freemarker.core.outputformat.impl.PlainTextOutputFormat;
+import org.apache.freemarker.core.outputformat.impl.RTFOutputFormat;
+import org.apache.freemarker.core.outputformat.impl.UndefinedOutputFormat;
+import org.apache.freemarker.core.outputformat.impl.XMLOutputFormat;
+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.core.templateresolver.impl.NullCacheStorage;
+import org.apache.freemarker.core.userpkg.CustomHTMLOutputFormat;
+import org.apache.freemarker.core.userpkg.DummyOutputFormat;
+import org.apache.freemarker.core.userpkg.SeldomEscapedOutputFormat;
+import org.apache.freemarker.test.TemplateTest;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+import org.junit.Before;
+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}");
+        
+        TestConfigurationBuilder cfgB = createDefaultConfigurationBuilder();
+        for (OutputFormat cfgOutputFormat
+                : new OutputFormat[] { UndefinedOutputFormat.INSTANCE, RTFOutputFormat.INSTANCE } ) {
+            if (!cfgOutputFormat.equals(UndefinedOutputFormat.INSTANCE)) {
+                cfgB.setOutputFormat(cfgOutputFormat);
+            }
+            setConfiguration(cfgB.build());
+
+            assertEquals(cfgOutputFormat, getConfiguration().getOutputFormat());
+            
+            {
+                Template t = getConfiguration().getTemplate("t");
+                assertEquals(cfgOutputFormat, t.getOutputFormat());
+                assertOutput(t, t.getOutputFormat().getName());
+            }
+            
+            {
+                Template t = getConfiguration().getTemplate("t.xml");
+                assertEquals(XMLOutputFormat.INSTANCE, t.getOutputFormat());
+                assertOutput(t, t.getOutputFormat().getName());
+            }
+            
+            {
+                Template t = getConfiguration().getTemplate("tWithHeader");
+                assertEquals(HTMLOutputFormat.INSTANCE, t.getOutputFormat());
+                assertOutput(t, t.getOutputFormat().getName());
+            }
+            
+            getConfiguration().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);
+        
+        TestConfigurationBuilder cfgB = createDefaultConfigurationBuilder();
+        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;
+                cfgB.setOutputFormat(cfgOutputFormat);
+                ftlhOutputFormat = HTMLOutputFormat.INSTANCE;
+                ftlxOutputFormat = XMLOutputFormat.INSTANCE;
+                break;
+            case 3:
+                cfgOutputFormat = UndefinedOutputFormat.INSTANCE;
+                cfgB.unsetOutputFormat();
+                TemplateConfiguration.Builder tcbXML = new TemplateConfiguration.Builder();
+                tcbXML.setOutputFormat(XMLOutputFormat.INSTANCE);
+                cfgB.setTemplateConfigurations(
+                        new ConditionalTemplateConfigurationFactory(
+                                new OrMatcher(
+                                        new FileNameGlobMatcher("*.ftlh"),
+                                        new FileNameGlobMatcher("*.FTLH"),
+                                        new FileNameGlobMatcher("*.fTlH")),
+                                tcbXML.build()));
+                ftlhOutputFormat = HTMLOutputFormat.INSTANCE; // can't be overidden
+                ftlxOutputFormat = XMLOutputFormat.INSTANCE;
+                break;
+            default:
+                throw new AssertionError();
+            }
+
+            setConfiguration(cfgB.build());
+            assertEquals(cfgOutputFormat, getConfiguration().getOutputFormat());
+            
+            {
+                Template t = getConfiguration().getTemplate("t");
+                assertEquals(cfgOutputFormat, t.getOutputFormat());
+                assertOutput(t, t.getOutputFormat().getName());
+            }
+            
+            {
+                Template t = getConfiguration().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 = getConfiguration().getTemplate(name);
+                assertEquals(ftlhOutputFormat, t.getOutputFormat());
+                assertOutput(t, t.getOutputFormat().getName());
+            }
+            
+            for (String name : new String[] { "t.ftlx", "t.FTLX", "t.fTlX" }) {
+                Template t = getConfiguration().getTemplate(name);
+                assertEquals(ftlxOutputFormat, t.getOutputFormat());
+                assertOutput(t, t.getOutputFormat().getName());
+            }
+
+            {
+                Template t = getConfiguration().getTemplate("tWithHeader.ftlx");
+                assertEquals(HTMLOutputFormat.INSTANCE, t.getOutputFormat());
+                assertOutput(t, t.getOutputFormat().getName());
+            }
+
+            getConfiguration().clearTemplateCache();
+        }
+    }
+    
+    @Test
+    public void testStandardFileExtensionsSettingOverriding() throws Exception {
+        addTemplate("t.ftlx",
+                "${\"'\"} ${\"'\"?esc} ${\"'\"?noEsc}");
+        addTemplate("t.ftl",
+                "${'{}'} ${'{}'?esc} ${'{}'?noEsc}");
+        
+        ConditionalTemplateConfigurationFactory tcfHTML = new ConditionalTemplateConfigurationFactory(
+                new FileNameGlobMatcher("t.*"),
+                new TemplateConfiguration.Builder()
+                        .outputFormat(HTMLOutputFormat.INSTANCE)
+                        .build());
+
+        ConditionalTemplateConfigurationFactory tcfNoAutoEsc = new ConditionalTemplateConfigurationFactory(
+                new FileNameGlobMatcher("t.*"),
+                new TemplateConfiguration.Builder()
+                        .autoEscapingPolicy(DISABLE_AUTO_ESCAPING_POLICY)
+                        .build());
+
+        {
+            TestConfigurationBuilder cfgB = createDefaultConfigurationBuilder();
+
+            setConfiguration(cfgB.outputFormat(HTMLOutputFormat.INSTANCE).build());
+            assertOutputForNamed("t.ftlx", "&apos; &apos; '");  // Can't override it
+            setConfiguration(cfgB.templateConfigurations(tcfHTML).build());
+            assertOutputForNamed("t.ftlx", "&apos; &apos; '");  // Can't override it
+            setConfiguration(cfgB.templateConfigurations(tcfNoAutoEsc).build());
+            assertOutputForNamed("t.ftlx", "&apos; &apos; '");  // Can't override it
+        }
+
+        {
+            TestConfigurationBuilder cfgB = createDefaultConfigurationBuilder();
+
+            setConfiguration(cfgB.recognizeStandardFileExtensions(false).build());
+            assertErrorContainsForNamed("t.ftlx", UndefinedOutputFormat.INSTANCE.getName());
+            setConfiguration(cfgB.outputFormat(HTMLOutputFormat.INSTANCE).build());
+            assertOutputForNamed("t.ftlx", "&#39; &#39; '");
+            setConfiguration(cfgB.outputFormat(XMLOutputFormat.INSTANCE).build());
+            assertOutputForNamed("t.ftlx", "&apos; &apos; '");
+            setConfiguration(cfgB.templateConfigurations(tcfHTML).build());
+            assertOutputForNamed("t.ftlx", "&#39; &#39; '");
+            setConfiguration(cfgB.templateConfigurations(tcfNoAutoEsc).build());
+            assertOutputForNamed("t.ftlx", "' &apos; '");
+        }
+
+        {
+            TestConfigurationBuilder cfgB = createDefaultConfigurationBuilder();
+            cfgB.setRecognizeStandardFileExtensions(true);
+
+            setConfiguration(cfgB.templateConfigurations(tcfHTML).build());
+            assertOutputForNamed("t.ftlx", "&apos; &apos; '");  // Can't override it
+            setConfiguration(cfgB.templateConfigurations(tcfNoAutoEsc).build());
+            assertOutputForNamed("t.ftlx", "&apos; &apos; '");  // Can't override it
+        }
+
+        {
+            TestConfigurationBuilder cfgB = createDefaultConfigurationBuilder();
+
+            setConfiguration(cfgB.templateConfigurations(tcfHTML).build());
+            assertOutputForNamed("t.ftlx", "&apos; &apos; '");  // Can't override it
+            setConfiguration(cfgB.recognizeStandardFileExtensions(false).build());
+            assertOutputForNamed("t.ftlx", "&#39; &#39; '");
+        }
+    }
+
+    @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("&apos;", out.toString());
+        }
+        {
+            Template t = new Template("foo.ftlh", commonFTL, cfg);
+            assertSame(HTMLOutputFormat.INSTANCE, t.getOutputFormat());
+            StringWriter out = new StringWriter();
+            t.process(null, out);
+            assertEquals("&#39;", out.toString());
+        }
+    }
+    
+    @Test
+    public void testStandardFileExtensionsFormatterImplOverriding() throws Exception {
+        addTemplate("t.ftlh", "${'a&x'}");
+
+        assertOutputForNamed("t.ftlh", "a&amp;x");
+
+        setConfiguration(new TestConfigurationBuilder()
+                .registeredCustomOutputFormats(Collections.<OutputFormat>singleton(CustomHTMLOutputFormat.INSTANCE))
+                .build());
+        assertOutputForNamed("t.ftlh", "a&amp;X");
+
+        setConfiguration(new TestConfigurationBuilder()
+                .registeredCustomOutputFormats(Collections.<OutputFormat>emptyList())
+                .build());
+        assertOutputForNamed("t.ftlh", "a&amp;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'}");
+        
+        TestConfigurationBuilder cfgB = createDefaultConfigurationBuilder().outputFormat(XMLOutputFormat.INSTANCE);
+        assertEquals(ENABLE_IF_DEFAULT_AUTO_ESCAPING_POLICY, cfgB.getAutoEscapingPolicy());
+
+        for (boolean cfgAutoEscaping : new boolean[] { true, false }) {
+            if (!cfgAutoEscaping) {
+                cfgB.setAutoEscapingPolicy(DISABLE_AUTO_ESCAPING_POLICY);
+            }
+            setConfiguration(cfgB.build());
+
+            {
+                Template t = getConfiguration().getTemplate("t");
+                if (cfgAutoEscaping) {
+                    assertEquals(ENABLE_IF_DEFAULT_AUTO_ESCAPING_POLICY, t.getAutoEscapingPolicy());
+                    assertOutput(t, "a&amp;b");
+                } else {
+                    assertEquals(DISABLE_AUTO_ESCAPING_POLICY, t.getAutoEscapingPolicy());
+                    assertOutput(t, "a&b");
+                }
+            }
+            
+            {
+                Template t = getConfiguration().getTemplate("tWithHeaderFalse");
+                assertEquals(DISABLE_AUTO_ESCAPING_POLICY, t.getAutoEscapingPolicy());
+                assertOutput(t, "a&b");
+            }
+            
+            {
+                Template t = getConfiguration().getTemplate("tWithHeaderTrue");
+                assertEquals(ENABLE_IF_SUPPORTED_AUTO_ESCAPING_POLICY, t.getAutoEscapingPolicy());
+                assertOutput(t, "a&amp;b");
+            }
+
+            getConfiguration().clearTemplateCache();
+        }
+    }
+    
+    @Test
+    public void testNumericalInterpolation() throws IOException, TemplateException {
+        setConfiguration(new TestConfigurationBuilder()
+                .registeredCustomOutputFormats(Collections.<OutputFormat>singleton(DummyOutputFormat.INSTANCE))
+                .build());
+        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 &lt; {h&#39;}; <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 (boolean cfgAutoEscaping : new boolean[] { true, false }) {
+            String commonAutoEscFtl = "<#ftl outputFormat='HTML'>${'&'}";
+            if (cfgAutoEscaping) {
+                // Cfg default is autoEscaping true
+                assertOutput(commonAutoEscFtl, "&amp;");
+            } else {
+                setConfiguration(createDefaultConfigurationBuilder()
+                        .autoEscapingPolicy(DISABLE_AUTO_ESCAPING_POLICY)
+                        .build());
+                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 &lt; {h&#39;} <p>c "
+                    + "a &lt; {x&#39;} "
+                    + "\\par a &amp; b");
+            assertOutput(
+                    "<#ftl outputFormat='XML'>"
+                    + "${xmlPlain} ${xmlMarkup} "
+                    + "${htmlPlain} "
+                    + "${rtfPlain}",
+                    "a &lt; {x&apos;} <p>c</p> "
+                    + "a &lt; {h&apos;} "
+                    + "\\par a &amp; 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 &lt; {x&apos;} <p>c</p> "
+                        + "a &lt; {h&#39;} <p>c "
+                        + "\\\\par a & b \\par c");
+            }
+        }
+    }
+
+    @Test
+    public void testStringLiteralsUseUndefinedOF() throws IOException, TemplateException {
+        String expectedOut = "&amp; (&) &amp;";
+        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.createPlainTextTemplate("x", content, getConfiguration());
+            Writer sw = new StringWriter();
+            t.process(null, sw);
+            assertEquals(content, sw.toString());
+            assertEquals(UndefinedOutputFormat.INSTANCE, t.getOutputFormat());
+        }
+        
+        {
+            setConfiguration(new TestConfigurationBuilder().outputFormat(HTMLOutputFormat.INSTANCE).build());
+            Template t = Template.createPlainTextTemplate("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 &lt; {x&apos;}");
+        assertOutput("${'${xmlMarkup}'}", "<p>c</p>");
+        assertErrorContains("${'${\"x\"?esc}'}", "?esc", "undefined");
+        assertOutput("<#ftl outputFormat='XML'>${'${xmlMarkup?esc} ${\"<\"?esc} ${\">\"} ${\"&amp;\"?noEsc}'}",
+                "<p>c</p> &lt; &gt; &amp;");
+    }
+    
+    @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}",
+                "&#39;<p>c <p>c&#39; <p>c<p>c");
+        assertOutput(
+                "${'\\'' + htmlPlain} ${htmlPlain + '\\''} ${htmlPlain + htmlPlain}",
+                "&#39;a &lt; {h&#39;} a &lt; {h&#39;}&#39; a &lt; {h&#39;}a &lt; {h&#39;}");
+        assertErrorContains(
+                "<#ftl outputFormat='XML'>${'\\'' + htmlMarkup}",
+                "HTML", "XML", "conversion");
+        assertErrorContains(
+                "${xmlMarkup + htmlMarkup}",
+                "HTML", "XML", "Conversion", "common");
+        assertOutput(
+                "${xmlMarkup + htmlPlain}",
+                "<p>c</p>a &lt; {h&apos;}");
+        assertOutput(
+                "${xmlPlain + htmlMarkup}",
+                "a &lt; {x&#39;}<p>c");
+        assertOutput(
+                "${xmlPlain + htmlPlain}",
+                "a &lt; {x&apos;}a &lt; {h&apos;}");
+        assertOutput(
+                "${xmlPlain + htmlPlain + '\\''}",
+                "a &lt; {x&apos;}a &lt; {h&apos;}&apos;");
+        assertOutput(
+                "${htmlPlain + xmlPlain + '\\''}",
+                "a &lt; {h&#39;}a &lt; {x&#39;}&#39;");
+        assertOutput(
+                "${xmlPlain + htmlPlain + '\\''}",
+                "a &lt; {x&apos;}a &lt; {h&apos;}&apos;");
+        assertOutput(
+                "<#ftl outputFormat='XML'>${htmlPlain + xmlPlain + '\\''}",
+                "a &lt; {h&apos;}a &lt; {x&apos;}&apos;");
+        assertOutput(
+                "<#ftl outputFormat='RTF'>${htmlPlain + xmlPlain + '\\''}",
+                "a < \\{h'\\}a < \\{x'\\}'");
+        assertOutput(
+                "<#ftl outputFormat='XML'>${'\\'' + htmlPlain}",
+                "&apos;a &lt; {h&apos;}");
+        assertOutput(
+                "<#ftl outputFormat='HTML'>${'\\'' + htmlPlain}",
+                "&#39;a &lt; {h&#39;}");
+        assertOutput(
+                "<#ftl outputFormat='HTML'>${'\\'' + xmlPlain}",
+                "&#39;a &lt; {x&#39;}");
+        assertOutput(
+                "<#ftl outputFormat='RTF'>${'\\'' + xmlPlain}",
+                "'a < \\{x'\\}");
+        
+        assertOutput(
+                "<#assign x = '\\''><#assign x += xmlMarkup>${x}",
+                "&apos;<p>c</p>");
+        assertOutput(
+                "<#assign x = xmlMarkup><#assign x += '\\''>${x}",
+                "<p>c</p>&apos;");
+        assertOutput(
+                "<#assign x = xmlMarkup><#assign x += htmlPlain>${x}",
+                "<p>c</p>a &lt; {h&apos;}");
+        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>&amp; &amp; 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", "&lt;x&gt; &lt;x&gt; <x>");
+        assertOutputForNamed("t-noAuto.ftlh", "<x> &lt;x&gt; <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}",
+                "&amp; &amp; & &");
+        
+        for (String bi : new String[] { "esc", "noEsc" } ) {
+            assertOutput(
+                    xmlHdr + "${rtfPlain?" + bi + "}",
+                    "\\par a &amp; b");
+            assertOutput(
+                    xmlHdr + "<#setting numberFormat='0.0'>${1?" + bi + "}",
+                    "1.0");
+            assertOutput(
+                    xmlHdr + "<#setting booleanFormat='&y,&n'>${true?" + bi + "}",
+                    bi.equals("esc") ? "&amp;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 &lt; {h&#39;} <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&#39; XML&apos; HTML&#39; undefined'");
+        assertOutput(
+                "<#ftl output_format='XML'>"
+                + "${.output_format}${'\\''} "
+                + "<#outputformat 'HTML'>${.output_format}${'\\''}</#outputformat> "
+                + "${.output_format}${'\\''}",
+                "XML&apos; HTML&#39; XML&apos;");
+        
+        // Custom format:
+        assertErrorContains(
+                "<#outputFormat 'dummy'></#outputFormat>",
+                "dummy", "nregistered");
+        setConfiguration(new TestConfigurationBuilder()
+                .registeredCustomOutputFormats(Collections.<OutputFormat>singleton(DummyOutputFormat.INSTANCE))
+                .build());
+        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&amp; false& true&amp; false& true&amp;");
+        assertOutput(
+                "<#ftl auto_esc=false output_format='XML'>"
+                + "${.auto_esc?c}${'&'} "
+                + "<#autoesc>${.auto_esc?c}${'&'}</#autoesc> "
+                + "${.auto_esc?c}${'&'}",
+                "false& true&amp; false&");
+        
+        // Bad came case:
+        assertErrorContains(
+                "<#noAutoesc></#noAutoesc>",
+                "Unknown directive");
+        assertErrorContains(
+                "<#noautoEsc></#noautoEsc>",
+                "Unknown directive");
+
+        setConfiguration(new TestConfigurationBuilder()
+                .outputFormat(XMLOutputFormat.INSTANCE)
+                .build());
+        
+        // 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 {
+        TestConfigurationBuilder cfgB = createDefaultConfigurationBuilder();
+        cfgB.setRegisteredCustomOutputFormats(ImmutableList.<OutputFormat>of(
+                SeldomEscapedOutputFormat.INSTANCE, DummyOutputFormat.INSTANCE));
+        assertEquals(ENABLE_IF_DEFAULT_AUTO_ESCAPING_POLICY, cfgB.getAutoEscapingPolicy());
+        
+        String commonFTL = "${'.'} ${.autoEsc?c}";
+        String notEsced = ". false";
+        String esced = "\\. true";
+
+        for (int autoEscPolicy : new int[] {
+                ENABLE_IF_DEFAULT_AUTO_ESCAPING_POLICY,
+                ENABLE_IF_SUPPORTED_AUTO_ESCAPING_POLICY,
+                DISABLE_AUTO_ESCAPING_POLICY }) {
+            cfgB.setAutoEscapingPolicy(autoEscPolicy);
+            
+            String sExpted = autoEscPolicy == ENABLE_IF_SUPPORTED_AUTO_ESCAPING_POLICY ? esced : notEsced;
+            cfgB.setOutputFormat(SeldomEscapedOutputFormat.INSTANCE);
+            setConfiguration(cfgB.build());
+            assertOutput(commonFTL, sExpted);
+            cfgB.setOutputFormat(UndefinedOutputFormat.INSTANCE);
+            setConfiguration(cfgB.build());
+            assertOutput("<#ftl outputFormat='seldomEscaped'>" + commonFTL, sExpted);
+            assertOutput("<#outputFormat 'seldomEscaped'>" + commonFTL + "</#outputFormat>", sExpted);
+            
+            String dExpted = autoEscPolicy == DISABLE_AUTO_ESCAPING_POLICY ? notEsced : esced;
+            cfgB.setOutputFormat(DummyOutputFormat.INSTANCE);
+            setConfiguration(cfgB.build());
+            assertOutput(commonFTL, dExpted);
+            cfgB.setOutputFormat(UndefinedOutputFormat.INSTANCE);
+            setConfiguration(cfgB.build());
+            assertOutput("<#ftl outputFormat='dummy'>" + commonFTL, dExpted);
+            assertOutput("<#outputFormat 'dummy'>" + commonFTL + "</#outputFormat>", dExpted);
+            
+            cfgB.setOutputFormat(DummyOutputFormat.INSTANCE);
+            setConfiguration(cfgB.build());
+            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 ParsingConfiguration of the calling template, and ignore anything
+        // inside the calling template itself. Except, the outputFormat and autoEscapingPolicy 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 {&amp;}");
+        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 {&amp;}");
+        
+        // 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 {&amp;} 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" }) {
+            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 &lt; {h&#39;} <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 &lt; {h&#39;} <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 &lt; {x&apos;} <p>c</p>");
+        assertOutput("${htmlPlain?xml} ${htmlMarkup?xml}", "a &lt; {h&#39;} <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>",
+                "&amp;#39;");
+        assertOutput(
+                "<#outputFormat 'HTML{RTF{XML}}'>${'<a=\\'{}\\' />'}</#outputFormat>",
+                "&amp;lt;a=&amp;apos;\\{\\}&amp;apos; /&amp;gt;");
+        
+        String commonFtl = "${'\\''} <#outputFormat '{HTML}'>${'\\''}</#outputFormat>";
+        String commonOutput = "&apos; &amp;#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");
+    }
+
+    private TestConfigurationBuilder createDefaultConfigurationBuilder() throws TemplateModelException {
+        return new TestConfigurationBuilder()
+                .templateConfigurations(
+                        new ConditionalTemplateConfigurationFactory(
+                                new FileNameGlobMatcher("*.xml"),
+                                new TemplateConfiguration.Builder()
+                                        .outputFormat(XMLOutputFormat.INSTANCE)
+                                        .build()))
+                .cacheStorage(NullCacheStorage.INSTANCE); // Prevent caching as we change the cfgB between build().
+    }
+
+    @Before
+    public void addCommonDataModelVariables() throws TemplateModelException {
+        addToDataModel("rtfPlain", RTFOutputFormat.INSTANCE.fromPlainTextByEscaping("\\par a & b"));
+        addToDataModel("rtfMarkup", RTFOutputFormat.INSTANCE.fromMarkup("\\par c"));
+        addToDataModel("htmlPlain", HTMLOutputFormat.INSTANCE.fromPlainTextByEscaping("a < {h'}"));
+        addToDataModel("htmlMarkup", HTMLOutputFormat.INSTANCE.fromMarkup("<p>c"));
+        addToDataModel("xmlPlain", XMLOutputFormat.INSTANCE.fromPlainTextByEscaping("a < {x'}"));
+        addToDataModel("xmlMarkup", XMLOutputFormat.INSTANCE.fromMarkup("<p>c</p>"));
+    }
+
+    @Override
+    protected Configuration createDefaultConfiguration() throws TemplateModelException {
+        return createDefaultConfigurationBuilder().build();
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/ParseTimeParameterBIErrorMessagesTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/ParseTimeParameterBIErrorMessagesTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ParseTimeParameterBIErrorMessagesTest.java
new file mode 100644
index 0000000..77b46de
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ParseTimeParameterBIErrorMessagesTest.java
@@ -0,0 +1,46 @@
+/*
+ * 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.test.TemplateTest;
+import org.junit.Test;
+
+public class ParseTimeParameterBIErrorMessagesTest extends TemplateTest {
+
+    @Test
+    public void testThen() throws Exception {
+        assertErrorContains("${true?then}", "expecting", "\"(\"");
+        assertErrorContains("${true?then + 1}", "expecting", "\"(\"");
+        assertErrorContains("${true?then()}", "?then", "2 parameters");
+        assertErrorContains("${true?then(1)}", "?then", "2 parameters");
+        assertOutput("${true?then(1, 2)}", "1");
+        assertErrorContains("${true?then(1, 2, 3)}", "?then", "2 parameters");
+    }
+
+    @Test
+    public void testSwitch() throws Exception {
+        assertErrorContains("${true?switch}", "expecting", "\"(\"");
+        assertErrorContains("${true?switch + 1}", "expecting", "\"(\"");
+        assertErrorContains("${true?switch()}", "at least 2 parameters");
+        assertErrorContains("${true?switch(true)}", "at least 2 parameters");
+        assertOutput("${true?switch(true, 1)}", "1");
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/ParsingErrorMessagesTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/ParsingErrorMessagesTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ParsingErrorMessagesTest.java
new file mode 100644
index 0000000..8f20d6c
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ParsingErrorMessagesTest.java
@@ -0,0 +1,116 @@
+/*
+ * 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 org.apache.freemarker.core.util._StringUtil;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+import org.junit.Test;
+
+public class ParsingErrorMessagesTest {
+
+    private Configuration cfg = new TestConfigurationBuilder()
+            .tagSyntax(ParsingConfiguration.AUTO_DETECT_TAG_SYNTAX)
+            .build();
+
+    @Test
+    public void testNeedlessInterpolation() {
+        assertErrorContains("<#if ${x} == 3></#if>", "instead of ${");
+        assertErrorContains("<#if ${x == 3}></#if>", "instead of ${");
+        assertErrorContains("<@foo ${x == 3} />", "instead of ${");
+    }
+
+    @Test
+    public void testWrongDirectiveNames() {
+        assertErrorContains("<#foo />", "nknown directive", "#foo");
+        assertErrorContains("<#set x = 1 />", "nknown directive", "#set", "#assign");
+        assertErrorContains("<#iterator></#iterator>", "nknown directive", "#iterator", "#list");
+    }
+
+    @Test
+    public void testBug402() {
+        assertErrorContains("<#list 1..i as k>${k}<#list>", "existing directive", "malformed", "#list");
+        assertErrorContains("<#assign>", "existing directive", "malformed", "#assign");
+        assertErrorContains("</#if x>", "existing directive", "malformed", "#if");
+        assertErrorContains("<#compress x>", "existing directive", "malformed", "#compress");
+    }
+
+    @Test
+    public void testUnclosedDirectives() {
+        assertErrorContains("<#macro x>", "#macro", "unclosed");
+        assertErrorContains("<#function x>", "#macro", "unclosed");
+        assertErrorContains("<#assign x>", "#assign", "unclosed");
+        assertErrorContains("<#macro m><#local x>", "#local", "unclosed");
+        assertErrorContains("<#global x>", "#global", "unclosed");
+        assertErrorContains("<@foo>", "@...", "unclosed");
+        assertErrorContains("<#list xs as x>", "#list", "unclosed");
+        assertErrorContains("<#list xs as x><#if x>", "#if", "unclosed");
+        assertErrorContains("<#list xs as x><#if x><#if q><#else>", "#if", "unclosed");
+        assertErrorContains("<#list xs as x><#if x><#if q><#else><#macro x>qwe", "#macro", "unclosed");
+        assertErrorContains("${(blah", "\"(\"", "unclosed");
+        assertErrorContains("${blah", "\"{\"", "unclosed");
+    }
+    
+    @Test
+    public void testInterpolatingClosingsErrors() {
+        assertErrorContains("${x", "unclosed");
+        assertErrorContains("<#assign x = x}>", "\"}\"", "open");
+        // TODO assertErrorContains("<#assign x = '${x'>", "unclosed");
+    }
+    
+    private void assertErrorContains(String ftl, String... expectedSubstrings) {
+        assertErrorContains(false, ftl, expectedSubstrings);
+        assertErrorContains(true, ftl, expectedSubstrings);
+    }
+
+    private void assertErrorContains(boolean squareTags, String ftl, String... expectedSubstrings) {
+        try {
+            if (squareTags) {
+                ftl = ftl.replace('<', '[').replace('>', ']');
+            }
+            new Template("adhoc", ftl, cfg);
+            fail("The template had to fail");
+        } catch (ParseException e) {
+            String msg = e.getMessage();
+            for (String needle: expectedSubstrings) {
+                if (needle.startsWith("\\!")) {
+                    String netNeedle = needle.substring(2); 
+                    if (msg.contains(netNeedle)) {
+                        fail("The message shouldn't contain substring " + _StringUtil.jQuote(netNeedle) + ":\n" + msg);
+                    }
+                } else if (!msg.contains(needle)) {
+                    fail("The message didn't contain substring " + _StringUtil.jQuote(needle) + ":\n" + msg);
+                }
+            }
+            showError(e);
+        } catch (IOException e) {
+            // Won't happen
+            throw new RuntimeException(e);
+        }
+    }
+    
+    private void showError(Throwable e) {
+        //System.out.println(e);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/RestrictedObjectWrapperTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/RestrictedObjectWrapperTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/RestrictedObjectWrapperTest.java
new file mode 100644
index 0000000..702a254
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/RestrictedObjectWrapperTest.java
@@ -0,0 +1,72 @@
+/*
+ * 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.apache.freemarker.test.hamcerst.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+
+import javax.annotation.PostConstruct;
+
+import org.apache.freemarker.core.model.TemplateBooleanModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.impl.DefaultArrayAdapter;
+import org.apache.freemarker.core.model.impl.DefaultListAdapter;
+import org.apache.freemarker.core.model.impl.DefaultMapAdapter;
+import org.apache.freemarker.core.model.impl.DefaultNonListCollectionAdapter;
+import org.apache.freemarker.core.model.impl.DefaultObjectWrapperTest.TestBean;
+import org.apache.freemarker.core.model.impl.RestrictedObjectWrapper;
+import org.apache.freemarker.core.model.impl.SimpleDate;
+import org.apache.freemarker.core.model.impl.SimpleNumber;
+import org.apache.freemarker.core.model.impl.SimpleScalar;
+import org.junit.Test;
+
+public class RestrictedObjectWrapperTest {
+
+    @Test
+    public void testBasics() throws TemplateModelException {
+        PostConstruct.class.toString();
+        RestrictedObjectWrapper ow = new RestrictedObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
+        testCustomizationCommonPart(ow);
+        assertTrue(ow.wrap(Collections.emptyMap()) instanceof DefaultMapAdapter);
+        assertTrue(ow.wrap(Collections.emptyList()) instanceof DefaultListAdapter);
+        assertTrue(ow.wrap(new boolean[] { }) instanceof DefaultArrayAdapter);
+        assertTrue(ow.wrap(new HashSet()) instanceof DefaultNonListCollectionAdapter);
+    }
+
+    @SuppressWarnings("boxing")
+    private void testCustomizationCommonPart(RestrictedObjectWrapper ow) throws TemplateModelException {
+        assertTrue(ow.wrap("x") instanceof SimpleScalar);
+        assertTrue(ow.wrap(1.5) instanceof SimpleNumber);
+        assertTrue(ow.wrap(new Date()) instanceof SimpleDate);
+        assertEquals(TemplateBooleanModel.TRUE, ow.wrap(true));
+        
+        try {
+            ow.wrap(new TestBean());
+            fail();
+        } catch (TemplateModelException e) {
+            assertThat(e.getMessage(), containsStringIgnoringCase("type"));
+        }
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/RestrictedObjetWrapperTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/RestrictedObjetWrapperTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/RestrictedObjetWrapperTest.java
new file mode 100644
index 0000000..43ff3bf
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/RestrictedObjetWrapperTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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.File;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.freemarker.core.model.TemplateBooleanModel;
+import org.apache.freemarker.core.model.TemplateCollectionModel;
+import org.apache.freemarker.core.model.TemplateCollectionModelEx;
+import org.apache.freemarker.core.model.TemplateDateModel;
+import org.apache.freemarker.core.model.TemplateHashModelEx2;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateModelWithAPISupport;
+import org.apache.freemarker.core.model.TemplateNumberModel;
+import org.apache.freemarker.core.model.TemplateScalarModel;
+import org.apache.freemarker.core.model.TemplateSequenceModel;
+import org.apache.freemarker.core.model.impl.RestrictedObjectWrapper;
+import org.junit.Test;
+import org.w3c.dom.Document;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+public class RestrictedObjetWrapperTest {
+    
+    @Test
+    public void testDoesNotAllowAPIBuiltin() throws TemplateModelException {
+        RestrictedObjectWrapper sow = new RestrictedObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
+        
+        TemplateModelWithAPISupport map = (TemplateModelWithAPISupport) sow.wrap(new HashMap());
+        try {
+            map.getAPI();
+            fail();
+        } catch (TemplateException e) {
+            assertThat(e.getMessage(), containsString("?api"));
+        }
+    }
+
+    @SuppressWarnings("boxing")
+    @Test
+    public void testCanWrapBasicTypes() throws TemplateModelException {
+        RestrictedObjectWrapper sow = new RestrictedObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
+        assertTrue(sow.wrap("s") instanceof TemplateScalarModel);
+        assertTrue(sow.wrap(1) instanceof TemplateNumberModel);
+        assertTrue(sow.wrap(true) instanceof TemplateBooleanModel);
+        assertTrue(sow.wrap(new Date()) instanceof TemplateDateModel);
+        assertTrue(sow.wrap(new ArrayList()) instanceof TemplateSequenceModel);
+        assertTrue(sow.wrap(new String[0]) instanceof TemplateSequenceModel);
+        assertTrue(sow.wrap(new ArrayList().iterator()) instanceof TemplateCollectionModel);
+        assertTrue(sow.wrap(new HashSet()) instanceof TemplateCollectionModelEx);
+        assertTrue(sow.wrap(new HashMap()) instanceof TemplateHashModelEx2);
+        assertNull(sow.wrap(null));
+    }
+    
+    @Test
+    public void testWontWrapDOM() throws SAXException, IOException, ParserConfigurationException,
+            TemplateModelException {
+        DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+        InputSource is = new InputSource();
+        is.setCharacterStream(new StringReader("<doc><sub a='1' /></doc>"));
+        Document doc = db.parse(is);
+        
+        RestrictedObjectWrapper sow = new RestrictedObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
+        try {
+            sow.wrap(doc);
+            fail();
+        } catch (TemplateModelException e) {
+            assertThat(e.getMessage(), containsString("won't wrap"));
+        }
+    }
+    
+    @Test
+    public void testWontWrapGenericObjects() {
+        RestrictedObjectWrapper sow = new RestrictedObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
+        try {
+            sow.wrap(new File("/x"));
+            fail();
+        } catch (TemplateModelException e) {
+            assertThat(e.getMessage(), containsString("won't wrap"));
+        }
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/SQLTimeZoneTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/SQLTimeZoneTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/SQLTimeZoneTest.java
new file mode 100644
index 0000000..cf14b93
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/SQLTimeZoneTest.java
@@ -0,0 +1,371 @@
+/*
+ * 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.sql.Time;
+import java.sql.Timestamp;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import org.apache.freemarker.core.util._DateUtil;
+import org.apache.freemarker.test.TemplateTest;
+import org.junit.Test;
+
+public class SQLTimeZoneTest extends TemplateTest {
+
+    private final static TimeZone GMT_P02 = TimeZone.getTimeZone("GMT+02");
+    
+    private TimeZone lastDefaultTimeZone;
+
+    private final DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US);
+    {
+        df.setTimeZone(_DateUtil.UTC);
+    }
+    
+    // Values that JDBC in GMT+02 would produce
+    private final java.sql.Date sqlDate = new java.sql.Date(utcToLong("2014-07-11T22:00:00")); // 2014-07-12
+    private final Time sqlTime = new Time(utcToLong("1970-01-01T10:30:05")); // 12:30:05
+    private final Timestamp sqlTimestamp = new Timestamp(utcToLong("2014-07-12T10:30:05")); // 2014-07-12T12:30:05
+    private final Date javaDate = new Date(utcToLong("2014-07-12T10:30:05")); // 2014-07-12T12:30:05
+    private final Date javaDayErrorDate = new Date(utcToLong("2014-07-11T22:00:00")); // 2014-07-12T12:30:05
+    
+    public TimeZone getLastDefaultTimeZone() {
+        return lastDefaultTimeZone;
+    }
+
+    public void setLastDefaultTimeZone(TimeZone lastDefaultTimeZone) {
+        this.lastDefaultTimeZone = lastDefaultTimeZone;
+    }
+
+    public java.sql.Date getSqlDate() {
+        return sqlDate;
+    }
+
+    public Time getSqlTime() {
+        return sqlTime;
+    }
+
+    public Timestamp getSqlTimestamp() {
+        return sqlTimestamp;
+    }
+
+    public Date getJavaDate() {
+        return javaDate;
+    }
+    
+    public Date getJavaDayErrorDate() {
+        return javaDayErrorDate;
+    }
+
+    private static final String FTL =
+            "${sqlDate} ${sqlTime} ${sqlTimestamp} ${javaDate?datetime}\n"
+            + "${sqlDate?string.iso_fz} ${sqlTime?string.iso_fz} "
+            + "${sqlTimestamp?string.iso_fz} ${javaDate?datetime?string.iso_fz}\n"
+            + "${sqlDate?string.xs_fz} ${sqlTime?string.xs_fz} "
+            + "${sqlTimestamp?string.xs_fz} ${javaDate?datetime?string.xs_fz}\n"
+            + "${sqlDate?string.xs} ${sqlTime?string.xs} "
+            + "${sqlTimestamp?string.xs} ${javaDate?datetime?string.xs}\n"
+            + "<#setting time_zone='GMT'>\n"
+            + "${sqlDate} ${sqlTime} ${sqlTimestamp} ${javaDate?datetime}\n"
+            + "${sqlDate?string.iso_fz} ${sqlTime?string.iso_fz} "
+            + "${sqlTimestamp?string.iso_fz} ${javaDate?datetime?string.iso_fz}\n"
+            + "${sqlDate?string.xs_fz} ${sqlTime?string.xs_fz} "
+            + "${sqlTimestamp?string.xs_fz} ${javaDate?datetime?string.xs_fz}\n"
+            + "${sqlDate?string.xs} ${sqlTime?string.xs} "
+            + "${sqlTimestamp?string.xs} ${javaDate?datetime?string.xs}\n";
+
+    private static final String OUTPUT_BEFORE_SETTING_GMT_CFG_GMT2
+            = "2014-07-12 12:30:05 2014-07-12T12:30:05 2014-07-12T12:30:05\n"
+            + "2014-07-12 12:30:05+02:00 2014-07-12T12:30:05+02:00 2014-07-12T12:30:05+02:00\n"
+            + "2014-07-12+02:00 12:30:05+02:00 2014-07-12T12:30:05+02:00 2014-07-12T12:30:05+02:00\n"
+            + "2014-07-12 12:30:05 2014-07-12T12:30:05+02:00 2014-07-12T12:30:05+02:00\n";
+
+    private static final String OUTPUT_BEFORE_SETTING_GMT_CFG_GMT1_SQL_DIFFERENT
+            = "2014-07-12 12:30:05 2014-07-12T11:30:05 2014-07-12T11:30:05\n"
+            + "2014-07-12 12:30:05+02:00 2014-07-12T11:30:05+01:00 2014-07-12T11:30:05+01:00\n"
+            + "2014-07-12+02:00 12:30:05+02:00 2014-07-12T11:30:05+01:00 2014-07-12T11:30:05+01:00\n"
+            + "2014-07-12 12:30:05 2014-07-12T11:30:05+01:00 2014-07-12T11:30:05+01:00\n";
+
+    private static final String OUTPUT_BEFORE_SETTING_GMT_CFG_GMT1_SQL_SAME
+            = "2014-07-11 11:30:05 2014-07-12T11:30:05 2014-07-12T11:30:05\n"
+            + "2014-07-11 11:30:05+01:00 2014-07-12T11:30:05+01:00 2014-07-12T11:30:05+01:00\n"
+            + "2014-07-11+01:00 11:30:05+01:00 2014-07-12T11:30:05+01:00 2014-07-12T11:30:05+01:00\n"
+            + "2014-07-11 11:30:05 2014-07-12T11:30:05+01:00 2014-07-12T11:30:05+01:00\n";
+    
+    private static final String OUTPUT_AFTER_SETTING_GMT_CFG_SQL_SAME
+            = "2014-07-11 10:30:05 2014-07-12T10:30:05 2014-07-12T10:30:05\n"
+            + "2014-07-11 10:30:05Z 2014-07-12T10:30:05Z 2014-07-12T10:30:05Z\n"
+            + "2014-07-11Z 10:30:05Z 2014-07-12T10:30:05Z 2014-07-12T10:30:05Z\n"
+            + "2014-07-11 10:30:05 2014-07-12T10:30:05Z 2014-07-12T10:30:05Z\n";
+    
+    private static final String OUTPUT_AFTER_SETTING_GMT_CFG_SQL_DIFFERENT
+            = "2014-07-12 12:30:05 2014-07-12T10:30:05 2014-07-12T10:30:05\n"
+            + "2014-07-12 12:30:05+02:00 2014-07-12T10:30:05Z 2014-07-12T10:30:05Z\n"
+            + "2014-07-12+02:00 12:30:05+02:00 2014-07-12T10:30:05Z 2014-07-12T10:30:05Z\n"
+            + "2014-07-12 12:30:05 2014-07-12T10:30:05Z 2014-07-12T10:30:05Z\n";
+    
+    @Test
+    public void testWithDefaultTZAndNullSQL() throws Exception {
+        TimeZone prevSysDefTz = TimeZone.getDefault();
+        TimeZone.setDefault(GMT_P02);
+        try {
+            Configuration.ExtendableBuilder<?> cfgB = createConfigurationBuilder();
+            cfgB.unsetTimeZone();
+            setConfiguration(cfgB.build());
+
+            assertNull(getConfiguration().getSQLDateAndTimeTimeZone());
+            assertEquals(TimeZone.getDefault(), getConfiguration().getTimeZone());
+            
+            assertOutput(FTL, OUTPUT_BEFORE_SETTING_GMT_CFG_GMT2 + OUTPUT_AFTER_SETTING_GMT_CFG_SQL_SAME);
+        } finally {
+            TimeZone.setDefault(prevSysDefTz);
+        }
+    }
+
+    @Test
+    public void testWithDefaultTZAndGMT2SQL() throws Exception {
+        TimeZone prevSysDefTz = TimeZone.getDefault();
+        TimeZone.setDefault(GMT_P02);
+        try {
+            Configuration.ExtendableBuilder<?> cfgB = createConfigurationBuilder();
+            cfgB.sqlDateAndTimeTimeZone(GMT_P02).unsetTimeZone();
+            setConfiguration(cfgB.build());
+
+            assertOutput(FTL, OUTPUT_BEFORE_SETTING_GMT_CFG_GMT2 + OUTPUT_AFTER_SETTING_GMT_CFG_SQL_DIFFERENT);
+        } finally {
+            TimeZone.setDefault(prevSysDefTz);
+        }
+    }
+    
+    @Test
+    public void testWithGMT1AndNullSQL() throws Exception {
+        setConfiguration(createConfigurationBuilder()
+                .timeZone(TimeZone.getTimeZone("GMT+01:00"))
+                .build());
+        assertNull(getConfiguration().getSQLDateAndTimeTimeZone());
+
+        assertOutput(FTL, OUTPUT_BEFORE_SETTING_GMT_CFG_GMT1_SQL_SAME + OUTPUT_AFTER_SETTING_GMT_CFG_SQL_SAME);
+    }
+
+    @Test
+    public void testWithGMT1AndGMT2SQL() throws Exception {
+        setConfiguration(createConfigurationBuilder()
+                .sqlDateAndTimeTimeZone(GMT_P02)
+                .timeZone(TimeZone.getTimeZone("GMT+01:00"))
+                .build());
+
+        assertOutput(FTL, OUTPUT_BEFORE_SETTING_GMT_CFG_GMT1_SQL_DIFFERENT + OUTPUT_AFTER_SETTING_GMT_CFG_SQL_DIFFERENT);
+    }
+
+    @Test
+    public void testWithGMT2AndNullSQL() throws Exception {
+        setConfiguration(createConfigurationBuilder()
+                .timeZone(TimeZone.getTimeZone("GMT+02"))
+                .build());
+        assertNull(getConfiguration().getSQLDateAndTimeTimeZone());
+
+        assertOutput(FTL, OUTPUT_BEFORE_SETTING_GMT_CFG_GMT2 + OUTPUT_AFTER_SETTING_GMT_CFG_SQL_SAME);
+    }
+
+    @Test
+    public void testWithGMT2AndGMT2SQL() throws Exception {
+        setConfiguration(createConfigurationBuilder()
+            .sqlDateAndTimeTimeZone(GMT_P02)
+            .timeZone(TimeZone.getTimeZone("GMT+02"))
+            .build());
+        
+        assertOutput(FTL, OUTPUT_BEFORE_SETTING_GMT_CFG_GMT2 + OUTPUT_AFTER_SETTING_GMT_CFG_SQL_DIFFERENT);
+    }
+    
+    @Test
+    public void testCacheFlushings() throws Exception {
+        Configuration.ExtendableBuilder<?> cfgB = createConfigurationBuilder()
+                .timeZone(_DateUtil.UTC)
+                .dateFormat("yyyy-MM-dd E")
+                .timeFormat("HH:mm:ss E")
+                .dateTimeFormat("yyyy-MM-dd'T'HH:mm:ss E");
+
+        setConfiguration(cfgB.build());
+        assertOutput(
+                "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}, ${javaDate?date}, ${javaDate?time}\n"
+                + "<#setting locale='de'>\n"
+                + "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}, ${javaDate?date}, ${javaDate?time}\n",
+                "2014-07-11 Fri, 10:30:05 Thu, 2014-07-12T10:30:05 Sat, 2014-07-12T10:30:05 Sat, 2014-07-12 Sat, 10:30:05 Sat\n"
+                + "2014-07-11 Fr, 10:30:05 Do, 2014-07-12T10:30:05 Sa, 2014-07-12T10:30:05 Sa, 2014-07-12 Sa, 10:30:05 Sa\n");
+        assertOutput(
+                "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}, ${javaDate?date}, ${javaDate?time}\n"
+                + "<#setting date_format='yyyy-MM-dd'>\n"
+                + "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}, ${javaDate?date}, ${javaDate?time}\n",
+                "2014-07-11 Fri, 10:30:05 Thu, 2014-07-12T10:30:05 Sat, 2014-07-12T10:30:05 Sat, 2014-07-12 Sat, 10:30:05 Sat\n"
+                + "2014-07-11, 10:30:05 Thu, 2014-07-12T10:30:05 Sat, 2014-07-12T10:30:05 Sat, 2014-07-12, 10:30:05 Sat\n");
+        assertOutput(
+                "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}, ${javaDate?date}, ${javaDate?time}\n"
+                + "<#setting time_format='HH:mm:ss'>\n"
+                + "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}, ${javaDate?date}, ${javaDate?time}\n",
+                "2014-07-11 Fri, 10:30:05 Thu, 2014-07-12T10:30:05 Sat, 2014-07-12T10:30:05 Sat, 2014-07-12 Sat, 10:30:05 Sat\n"
+                + "2014-07-11 Fri, 10:30:05, 2014-07-12T10:30:05 Sat, 2014-07-12T10:30:05 Sat, 2014-07-12 Sat, 10:30:05\n");
+        assertOutput(
+                "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}, ${javaDate?date}, ${javaDate?time}\n"
+                + "<#setting datetime_format='yyyy-MM-dd\\'T\\'HH:mm:ss'>\n"
+                + "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}, ${javaDate?date}, ${javaDate?time}\n",
+                "2014-07-11 Fri, 10:30:05 Thu, 2014-07-12T10:30:05 Sat, 2014-07-12T10:30:05 Sat, 2014-07-12 Sat, 10:30:05 Sat\n"
+                + "2014-07-11 Fri, 10:30:05 Thu, 2014-07-12T10:30:05, 2014-07-12T10:30:05, 2014-07-12 Sat, 10:30:05 Sat\n");
+
+        setConfiguration(cfgB.sqlDateAndTimeTimeZone(GMT_P02).build());
+        assertOutput(
+                "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}, ${javaDate?date}, ${javaDate?time}\n"
+                + "<#setting locale='de'>\n"
+                + "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}, ${javaDate?date}, ${javaDate?time}\n",
+                "2014-07-12 Sat, 12:30:05 Thu, 2014-07-12T10:30:05 Sat, 2014-07-12T10:30:05 Sat, 2014-07-12 Sat, 10:30:05 Sat\n"
+                + "2014-07-12 Sa, 12:30:05 Do, 2014-07-12T10:30:05 Sa, 2014-07-12T10:30:05 Sa, 2014-07-12 Sa, 10:30:05 Sa\n");
+        assertOutput(
+                "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}, ${javaDate?date}, ${javaDate?time}\n"
+                + "<#setting date_format='yyyy-MM-dd'>\n"
+                + "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}, ${javaDate?date}, ${javaDate?time}\n",
+                "2014-07-12 Sat, 12:30:05 Thu, 2014-07-12T10:30:05 Sat, 2014-07-12T10:30:05 Sat, 2014-07-12 Sat, 10:30:05 Sat\n"
+                + "2014-07-12, 12:30:05 Thu, 2014-07-12T10:30:05 Sat, 2014-07-12T10:30:05 Sat, 2014-07-12, 10:30:05 Sat\n");
+        assertOutput(
+                "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}, ${javaDate?date}, ${javaDate?time}\n"
+                + "<#setting time_format='HH:mm:ss'>\n"
+                + "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}, ${javaDate?date}, ${javaDate?time}\n",
+                "2014-07-12 Sat, 12:30:05 Thu, 2014-07-12T10:30:05 Sat, 2014-07-12T10:30:05 Sat, 2014-07-12 Sat, 10:30:05 Sat\n"
+                + "2014-07-12 Sat, 12:30:05, 2014-07-12T10:30:05 Sat, 2014-07-12T10:30:05 Sat, 2014-07-12 Sat, 10:30:05\n");
+        assertOutput(
+                "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}, ${javaDate?date}, ${javaDate?time}\n"
+                + "<#setting datetime_format='yyyy-MM-dd\\'T\\'HH:mm:ss'>\n"
+                + "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}, ${javaDate?date}, ${javaDate?time}\n",
+                "2014-07-12 Sat, 12:30:05 Thu, 2014-07-12T10:30:05 Sat, 2014-07-12T10:30:05 Sat, 2014-07-12 Sat, 10:30:05 Sat\n"
+                + "2014-07-12 Sat, 12:30:05 Thu, 2014-07-12T10:30:05, 2014-07-12T10:30:05, 2014-07-12 Sat, 10:30:05 Sat\n");
+    }
+
+    @Test
+    public void testDateAndTimeBuiltInsHasNoEffect() throws Exception {
+        setConfiguration(createConfigurationBuilder()
+                .timeZone(_DateUtil.UTC)
+                .sqlDateAndTimeTimeZone(GMT_P02)
+                .build());
+
+        assertOutput(
+                "${javaDayErrorDate?date} ${javaDayErrorDate?time} ${sqlTimestamp?date} ${sqlTimestamp?time} "
+                + "${sqlDate?date} ${sqlTime?time}\n"
+                + "<#setting time_zone='GMT+02'>\n"
+                + "${javaDayErrorDate?date} ${javaDayErrorDate?time} ${sqlTimestamp?date} ${sqlTimestamp?time} "
+                + "${sqlDate?date} ${sqlTime?time}\n"
+                + "<#setting time_zone='GMT-11'>\n"
+                + "${javaDayErrorDate?date} ${javaDayErrorDate?time} ${sqlTimestamp?date} ${sqlTimestamp?time} "
+                + "${sqlDate?date} ${sqlTime?time}\n",
+                "2014-07-11 22:00:00 2014-07-12 10:30:05 2014-07-12 12:30:05\n"
+                + "2014-07-12 00:00:00 2014-07-12 12:30:05 2014-07-12 12:30:05\n"
+                + "2014-07-11 11:00:00 2014-07-11 23:30:05 2014-07-12 12:30:05\n");
+    }
+
+    @Test
+    public void testChangeSettingInTemplate() throws Exception {
+        setConfiguration(createConfigurationBuilder()
+                .timeZone(_DateUtil.UTC)
+                .build());
+
+        assertNull(getConfiguration().getSQLDateAndTimeTimeZone());
+
+        assertOutput(
+                "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}\n"
+                + "<#setting sql_date_and_time_time_zone='GMT+02'>\n"
+                + "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}\n"
+                + "<#setting sql_date_and_time_time_zone='null'>\n"
+                + "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}\n"
+                + "<#setting time_zone='GMT+03'>\n"
+                + "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}\n"
+                + "<#setting sql_date_and_time_time_zone='GMT+02'>\n"
+                + "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}\n"
+                + "<#setting sql_date_and_time_time_zone='GMT-11'>\n"
+                + "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}\n"
+                + "<#setting date_format='xs fz'>\n"
+                + "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}\n"
+                + "<#setting time_format='xs fz'>\n"
+                + "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}\n"
+                + "<#setting datetime_format='iso m'>\n"
+                + "${sqlDate}, ${sqlTime}, ${sqlTimestamp}, ${javaDate?datetime}\n",
+                "2014-07-11, 10:30:05, 2014-07-12T10:30:05, 2014-07-12T10:30:05\n"
+                + "2014-07-12, 12:30:05, 2014-07-12T10:30:05, 2014-07-12T10:30:05\n"
+                + "2014-07-11, 10:30:05, 2014-07-12T10:30:05, 2014-07-12T10:30:05\n"
+                + "2014-07-12, 13:30:05, 2014-07-12T13:30:05, 2014-07-12T13:30:05\n"
+                + "2014-07-12, 12:30:05, 2014-07-12T13:30:05, 2014-07-12T13:30:05\n"
+                + "2014-07-11, 23:30:05, 2014-07-12T13:30:05, 2014-07-12T13:30:05\n"
+                + "2014-07-11-11:00, 23:30:05, 2014-07-12T13:30:05, 2014-07-12T13:30:05\n"
+                + "2014-07-11-11:00, 23:30:05-11:00, 2014-07-12T13:30:05, 2014-07-12T13:30:05\n"
+                + "2014-07-11-11:00, 23:30:05-11:00, 2014-07-12T13:30+03:00, 2014-07-12T13:30+03:00\n");
+    }
+    
+    @Test
+    public void testFormatUTCFlagHasNoEffect() throws Exception {
+        setConfiguration(createConfigurationBuilder()
+                .sqlDateAndTimeTimeZone(GMT_P02)
+                .timeZone(TimeZone.getTimeZone("GMT-01"))
+                .build());
+        
+        assertOutput(
+                "<#setting date_format='xs fz'><#setting time_format='xs fz'>\n"
+                + "${sqlDate}, ${sqlTime}, ${javaDate?time}\n"
+                + "<#setting date_format='xs fz u'><#setting time_format='xs fz u'>\n"
+                + "${sqlDate}, ${sqlTime}, ${javaDate?time}\n"
+                + "<#setting sql_date_and_time_time_zone='GMT+03'>\n"
+                + "${sqlDate}, ${sqlTime}, ${javaDate?time}\n"
+                + "<#setting sql_date_and_time_time_zone='null'>\n"
+                + "${sqlDate}, ${sqlTime}, ${javaDate?time}\n"
+                + "<#setting date_format='xs fz'><#setting time_format='xs fz'>\n"
+                + "${sqlDate}, ${sqlTime}, ${javaDate?time}\n"
+                + "<#setting date_format='xs fz fu'><#setting time_format='xs fz fu'>\n"
+                + "${sqlDate}, ${sqlTime}, ${javaDate?time}\n",
+                "2014-07-12+02:00, 12:30:05+02:00, 09:30:05-01:00\n"
+                + "2014-07-12+02:00, 12:30:05+02:00, 10:30:05Z\n"
+                + "2014-07-12+03:00, 13:30:05+03:00, 10:30:05Z\n"
+                + "2014-07-11-01:00, 09:30:05-01:00, 10:30:05Z\n"
+                + "2014-07-11-01:00, 09:30:05-01:00, 09:30:05-01:00\n"
+                + "2014-07-11Z, 10:30:05Z, 10:30:05Z\n");
+    }
+
+    private Configuration.ExtendableBuilder<?> createConfigurationBuilder() {
+        return new Configuration.Builder(Configuration.VERSION_3_0_0)
+                .locale(Locale.US)
+                .dateFormat("yyyy-MM-dd")
+                .timeFormat("HH:mm:ss")
+                .dateTimeFormat("yyyy-MM-dd'T'HH:mm:ss");
+    }
+
+    @Override
+    protected Object createDataModel() {
+        return this;
+    }
+
+    private long utcToLong(String isoDateTime) {
+        try {
+            return df.parse(isoDateTime).getTime();
+        } catch (ParseException e) {
+            throw new RuntimeException(e);
+        }
+    }
+    
+}


[34/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/manualtest/Product.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/manualtest/Product.java b/freemarker-core-test/src/test/java/org/apache/freemarker/manualtest/Product.java
new file mode 100644
index 0000000..fcb34e8
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/manualtest/Product.java
@@ -0,0 +1,49 @@
+/*
+ * 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.manualtest;
+
+/**
+ * Product bean; note that it must be a public class!
+ */
+public class Product {
+
+    private String url;
+    private String name;
+
+    // As per the JavaBeans spec., this defines the "url" bean property
+    // It must be public!
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    // As per the JavaBean spec., this defines the "name" bean property
+    // It must be public!
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/manualtest/TemplateConfigurationExamples.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/manualtest/TemplateConfigurationExamples.java b/freemarker-core-test/src/test/java/org/apache/freemarker/manualtest/TemplateConfigurationExamples.java
new file mode 100644
index 0000000..8c515bd
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/manualtest/TemplateConfigurationExamples.java
@@ -0,0 +1,191 @@
+/*
+ * 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.manualtest;
+
+import static org.junit.Assert.*;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Date;
+
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.Template;
+import org.apache.freemarker.core.TemplateConfiguration;
+import org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat;
+import org.apache.freemarker.core.outputformat.impl.PlainTextOutputFormat;
+import org.apache.freemarker.core.outputformat.impl.UndefinedOutputFormat;
+import org.apache.freemarker.core.outputformat.impl.XMLOutputFormat;
+import org.apache.freemarker.core.templateresolver.ConditionalTemplateConfigurationFactory;
+import org.apache.freemarker.core.templateresolver.FileExtensionMatcher;
+import org.apache.freemarker.core.templateresolver.FileNameGlobMatcher;
+import org.apache.freemarker.core.templateresolver.FirstMatchTemplateConfigurationFactory;
+import org.apache.freemarker.core.templateresolver.MergingTemplateConfigurationFactory;
+import org.apache.freemarker.core.templateresolver.OrMatcher;
+import org.apache.freemarker.core.templateresolver.PathGlobMatcher;
+import org.apache.freemarker.core.util._DateUtil;
+import org.apache.freemarker.test.TemplateTest;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+import org.junit.Test;
+
+public class TemplateConfigurationExamples extends TemplateTest {
+
+    @Test
+    public void example1JavaCfg() throws Exception {
+        example1(true);
+    }
+
+    @Test
+    public void example1PropertiesCfg() throws Exception {
+        example1(false);
+    }
+
+    private void example1(boolean javaCfg) throws Exception {
+        TestConfigurationBuilder cfgB = new TestConfigurationBuilder(this.getClass());
+        if (javaCfg) {
+            cfgB.setTemplateConfigurations(new ConditionalTemplateConfigurationFactory(
+                    new FileExtensionMatcher("xml"),
+                    new TemplateConfiguration.Builder()
+                            .sourceEncoding(StandardCharsets.UTF_8)
+                            .outputFormat(XMLOutputFormat.INSTANCE)
+                            .build()));
+
+        } else {
+            cfgB.setTemplateConfigurations(null);
+            cfgB.setSettings(loadPropertiesFile("TemplateConfigurationExamples1.properties"));
+        }
+        setConfiguration(cfgB.build());
+
+        addTemplate("t.xml", "");
+
+        Template t = getConfiguration().getTemplate("t.xml");
+        assertEquals(StandardCharsets.UTF_8, t.getActualSourceEncoding());
+        assertEquals(XMLOutputFormat.INSTANCE, t.getOutputFormat());
+    }
+
+    @Test
+    public void example2JavaCfg() throws Exception {
+        example2(true);
+    }
+
+    @Test
+    public void example2PropertiesCfg() throws Exception {
+        example2(false);
+    }
+
+    private void example2(boolean javaCfg) throws Exception {
+        TestConfigurationBuilder cfgB = new TestConfigurationBuilder(this.getClass());
+        if (javaCfg) {
+            cfgB.setTemplateConfigurations(
+                    new ConditionalTemplateConfigurationFactory(
+                            new PathGlobMatcher("mail/**"),
+                            new FirstMatchTemplateConfigurationFactory(
+                                    new ConditionalTemplateConfigurationFactory(
+                                            new FileNameGlobMatcher("*.subject.*"),
+                                            new TemplateConfiguration.Builder()
+                                                    .outputFormat(PlainTextOutputFormat.INSTANCE)
+                                                    .build()),
+                                    new ConditionalTemplateConfigurationFactory(
+                                            new FileNameGlobMatcher("*.body.*"),
+                                            new TemplateConfiguration.Builder()
+                                                    .outputFormat(HTMLOutputFormat.INSTANCE)
+                                                    .build())
+                            )
+                            .noMatchErrorDetails(
+                                    "Mail template names must contain \".subject.\" or \".body.\"!")));
+        } else{
+            cfgB.setSettings(loadPropertiesFile("TemplateConfigurationExamples2.properties"));
+        }
+        setConfiguration(cfgB.build());
+
+        addTemplate("t.subject.ftl", "");
+        addTemplate("mail/t.subject.ftl", "");
+        addTemplate("mail/t.body.ftl", "");
+
+        Configuration cfg = getConfiguration();
+        assertEquals(UndefinedOutputFormat.INSTANCE, cfg.getTemplate("t.subject.ftl").getOutputFormat());
+        assertEquals(PlainTextOutputFormat.INSTANCE, cfg.getTemplate("mail/t.subject.ftl").getOutputFormat());
+        assertEquals(HTMLOutputFormat.INSTANCE, cfg.getTemplate("mail/t.body.ftl").getOutputFormat());
+    }
+
+    @Test
+    public void example3JavaCfg() throws Exception {
+        example3(true);
+    }
+
+    @Test
+    public void example3PropertiesCfg() throws Exception {
+        example3(false);
+    }
+
+    private void example3(boolean javaCfg) throws Exception {
+        TestConfigurationBuilder cfgB = new TestConfigurationBuilder(this.getClass())
+                .sourceEncoding(StandardCharsets.ISO_8859_1);
+        if (javaCfg) {
+            cfgB.setTemplateConfigurations(
+                    new MergingTemplateConfigurationFactory(
+                            new ConditionalTemplateConfigurationFactory(
+                                    new FileNameGlobMatcher("*.stats.*"),
+                                    new TemplateConfiguration.Builder()
+                                            .dateTimeFormat("iso")
+                                            .dateFormat("iso")
+                                            .timeFormat("iso")
+                                            .timeZone(_DateUtil.UTC)
+                                            .build()),
+                            new ConditionalTemplateConfigurationFactory(
+                                    new PathGlobMatcher("mail/**"),
+                                    new TemplateConfiguration.Builder()
+                                            .sourceEncoding(StandardCharsets.UTF_8)
+                                            .build()),
+                            new FirstMatchTemplateConfigurationFactory(
+                                    new ConditionalTemplateConfigurationFactory(
+                                            new FileExtensionMatcher("xml"),
+                                            new TemplateConfiguration.Builder()
+                                                    .outputFormat(XMLOutputFormat.INSTANCE)
+                                                    .build()),
+                                    new ConditionalTemplateConfigurationFactory(
+                                            new OrMatcher(
+                                                    new FileExtensionMatcher("html"),
+                                                    new FileExtensionMatcher("htm")),
+                                            new TemplateConfiguration.Builder()
+                                                    .outputFormat(HTMLOutputFormat.INSTANCE)
+                                                    .build())
+                            ).allowNoMatch(true)));
+        } else {
+            cfgB.setSettings(loadPropertiesFile("TemplateConfigurationExamples3.properties"));
+        }
+        setConfiguration(cfgB.build());
+
+        addTemplate("t.stats.html", "${ts?datetime} ${ts?date} ${ts?time}");
+        addTemplate("t.html", "");
+        addTemplate("t.htm", "");
+        addTemplate("t.xml", "");
+        addTemplate("mail/t.html", "");
+
+        addToDataModel("ts", new Date(1440431606011L));
+
+        Configuration cfg = getConfiguration();
+        assertEquals(HTMLOutputFormat.INSTANCE, cfg.getTemplate("t.html").getOutputFormat());
+        assertEquals(StandardCharsets.ISO_8859_1, cfg.getTemplate("t.html").getActualSourceEncoding());
+        assertEquals(HTMLOutputFormat.INSTANCE, cfg.getTemplate("t.htm").getOutputFormat());
+        assertEquals(XMLOutputFormat.INSTANCE, cfg.getTemplate("t.xml").getOutputFormat());
+        assertEquals(HTMLOutputFormat.INSTANCE, cfg.getTemplate("t.stats.html").getOutputFormat());
+        assertOutputForNamed("t.stats.html", "2015-08-24T15:53:26.011Z 2015-08-24 15:53:26.011Z");
+        assertEquals(StandardCharsets.UTF_8, cfg.getTemplate("mail/t.html").getActualSourceEncoding());
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/manualtest/UnitAwareTemplateNumberFormatFactory.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/manualtest/UnitAwareTemplateNumberFormatFactory.java b/freemarker-core-test/src/test/java/org/apache/freemarker/manualtest/UnitAwareTemplateNumberFormatFactory.java
new file mode 100644
index 0000000..89f20fa
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/manualtest/UnitAwareTemplateNumberFormatFactory.java
@@ -0,0 +1,80 @@
+/*
+ * 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.manualtest;
+
+import java.util.Locale;
+
+import org.apache.freemarker.core.Environment;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateNumberModel;
+import org.apache.freemarker.core.valueformat.TemplateNumberFormat;
+import org.apache.freemarker.core.valueformat.TemplateNumberFormatFactory;
+import org.apache.freemarker.core.valueformat.TemplateValueFormatException;
+
+/**
+ * A number format that takes any other number format as parameter (specified as a string, as
+ * usual in FreeMarker), then if the model is a {@link UnitAwareTemplateNumberModel}, it  shows
+ * the unit after the number formatted with the other format, otherwise it just shows the formatted
+ * number without unit.
+ */
+public class UnitAwareTemplateNumberFormatFactory extends TemplateNumberFormatFactory {
+
+    public static final UnitAwareTemplateNumberFormatFactory INSTANCE
+            = new UnitAwareTemplateNumberFormatFactory();
+
+    private UnitAwareTemplateNumberFormatFactory() {
+        // Defined to decrease visibility
+    }
+
+    @Override
+    public TemplateNumberFormat get(String params, Locale locale, Environment env)
+            throws TemplateValueFormatException {
+        return new UnitAwareNumberFormat(env.getTemplateNumberFormat(params, locale));
+    }
+
+    private static class UnitAwareNumberFormat extends TemplateNumberFormat {
+
+        private final TemplateNumberFormat innerFormat;
+
+        private UnitAwareNumberFormat(TemplateNumberFormat innerFormat) {
+            this.innerFormat = innerFormat;
+        }
+
+        @Override
+        public String formatToPlainText(TemplateNumberModel numberModel)
+                throws TemplateModelException, TemplateValueFormatException {
+            String innerResult = innerFormat.formatToPlainText(numberModel);
+            return numberModel instanceof UnitAwareTemplateNumberModel
+                    ? innerResult + " " + ((UnitAwareTemplateNumberModel) numberModel).getUnit()
+                    : innerResult;
+        }
+
+        @Override
+        public boolean isLocaleBound() {
+            return innerFormat.isLocaleBound();
+        }
+
+        @Override
+        public String getDescription() {
+            return "unit-aware " + innerFormat.getDescription();
+        }
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/manualtest/UnitAwareTemplateNumberModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/manualtest/UnitAwareTemplateNumberModel.java b/freemarker-core-test/src/test/java/org/apache/freemarker/manualtest/UnitAwareTemplateNumberModel.java
new file mode 100644
index 0000000..1e54254
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/manualtest/UnitAwareTemplateNumberModel.java
@@ -0,0 +1,43 @@
+/*
+ * 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.manualtest;
+
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateNumberModel;
+
+public class UnitAwareTemplateNumberModel implements TemplateNumberModel {
+
+    private final Number value;
+    private final String unit;
+    
+    public UnitAwareTemplateNumberModel(Number value, String unit) {
+        this.value = value;
+        this.unit = unit;
+    }
+
+    @Override
+    public Number getAsNumber() throws TemplateModelException {
+        return value;
+    }
+
+    public String getUnit() {
+        return unit;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/TemplateTestCase.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/TemplateTestCase.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/TemplateTestCase.java
new file mode 100644
index 0000000..cf3c0f7
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/TemplateTestCase.java
@@ -0,0 +1,515 @@
+/*
+ * 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.test.templatesuite;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.ResourceBundle;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.TimeZone;
+import java.util.TreeSet;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.apache.freemarker.core.ASTPrinter;
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.ConfigurationException;
+import org.apache.freemarker.core.Template;
+import org.apache.freemarker.core.TemplateException;
+import org.apache.freemarker.core.Version;
+import org.apache.freemarker.core.model.TemplateBooleanModel;
+import org.apache.freemarker.core.model.TemplateDateModel;
+import org.apache.freemarker.core.model.TemplateMethodModel;
+import org.apache.freemarker.core.model.TemplateNodeModel;
+import org.apache.freemarker.core.model.TemplateScalarModel;
+import org.apache.freemarker.core.model.TemplateSequenceModel;
+import org.apache.freemarker.core.model.impl.DefaultNonListCollectionAdapter;
+import org.apache.freemarker.core.model.impl.DefaultObjectWrapper;
+import org.apache.freemarker.core.model.impl.ResourceBundleModel;
+import org.apache.freemarker.core.model.impl.SimpleCollection;
+import org.apache.freemarker.core.model.impl.SimpleDate;
+import org.apache.freemarker.core.model.impl.SimpleNumber;
+import org.apache.freemarker.core.templateresolver.impl.ClassTemplateLoader;
+import org.apache.freemarker.core.util._NullArgumentException;
+import org.apache.freemarker.core.util._NullWriter;
+import org.apache.freemarker.core.util._StringUtil;
+import org.apache.freemarker.dom.NodeModel;
+import org.apache.freemarker.test.CopyrightCommentRemoverTemplateLoader;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+import org.apache.freemarker.test.templatesuite.models.BooleanAndStringTemplateModel;
+import org.apache.freemarker.test.templatesuite.models.BooleanHash1;
+import org.apache.freemarker.test.templatesuite.models.BooleanHash2;
+import org.apache.freemarker.test.templatesuite.models.BooleanList1;
+import org.apache.freemarker.test.templatesuite.models.BooleanList2;
+import org.apache.freemarker.test.templatesuite.models.BooleanVsStringMethods;
+import org.apache.freemarker.test.templatesuite.models.JavaObjectInfo;
+import org.apache.freemarker.test.templatesuite.models.Listables;
+import org.apache.freemarker.test.templatesuite.models.MultiModel1;
+import org.apache.freemarker.test.templatesuite.models.OverloadedMethods2;
+import org.apache.freemarker.test.templatesuite.models.VarArgTestModel;
+import org.apache.freemarker.test.templateutil.AssertDirective;
+import org.apache.freemarker.test.templateutil.AssertEqualsDirective;
+import org.apache.freemarker.test.templateutil.AssertFailsDirective;
+import org.apache.freemarker.test.FileTestCase;
+import org.apache.freemarker.test.templateutil.NoOutputDirective;
+import org.apache.freemarker.test.XMLLoader;
+import org.junit.Ignore;
+import org.xml.sax.InputSource;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+import junit.framework.AssertionFailedError;
+
+/**
+ * Instances of this are created and called by {@link TemplateTestSuite}. (It's on "Ignore" so that Eclipse doesn't try
+ * to run this alone.) 
+ */
+@Ignore
+public class TemplateTestCase extends FileTestCase {
+    
+    // Name of variables exposed to all test FTL-s:
+    private static final String ICI_INT_VALUE_VAR_NAME = "iciIntValue";
+    private static final String TEST_NAME_VAR_NAME = "testName";
+    private static final String JAVA_OBJECT_INFO_VAR_NAME = "javaObjectInfo";
+    private static final String NO_OUTPUT_VAR_NAME = "noOutput";
+    private static final String ASSERT_FAILS_VAR_NAME = "assertFails";
+    private static final String ASSERT_EQUALS_VAR_NAME = "assertEquals";
+    private static final String ASSERT_VAR_NAME = "assert";
+    
+    private final String simpleTestName;
+    private final String templateName;
+    private final String expectedFileName;
+    private final boolean noOutput;
+    
+    private final Configuration.ExtendableBuilder confB;
+    private final HashMap<String, Object> dataModel = new HashMap<>();
+    
+    public TemplateTestCase(String testName, String simpleTestName, String templateName, String expectedFileName, boolean noOutput,
+            Version incompatibleImprovements) {
+        super(testName);
+        _NullArgumentException.check("testName", testName);
+        
+        _NullArgumentException.check("simpleTestName", simpleTestName);
+        this.simpleTestName = simpleTestName;
+        
+        _NullArgumentException.check("templateName", templateName);
+        this.templateName = templateName;
+        
+        _NullArgumentException.check("expectedFileName", expectedFileName);
+        this.expectedFileName = expectedFileName;
+        
+        this.noOutput = noOutput;
+
+        confB = new TestConfigurationBuilder(incompatibleImprovements);
+    }
+    
+    public void setSetting(String param, String value) throws IOException {
+        if ("auto_import".equals(param)) {
+            StringTokenizer st = new StringTokenizer(value);
+            if (!st.hasMoreTokens()) fail("Expecting libname");
+            String libname = st.nextToken();
+            if (!st.hasMoreTokens()) fail("Expecting 'as <alias>' in autoimport");
+            String as = st.nextToken();
+            if (!as.equals("as")) fail("Expecting 'as <alias>' in autoimport");
+            if (!st.hasMoreTokens()) fail("Expecting alias after 'as' in autoimport");
+            String alias = st.nextToken();
+            confB.addAutoImport(alias, libname);
+        } else if ("source_encoding".equals(param)) {
+            confB.setSourceEncoding(Charset.forName(value));
+        // INCOMPATIBLE_IMPROVEMENTS is a list here, and was already set in the constructor.
+        } else if (!Configuration.ExtendableBuilder.INCOMPATIBLE_IMPROVEMENTS_KEY.equals(param)) {
+            try {
+                confB.setSetting(param, value);
+            } catch (ConfigurationException e) {
+                throw new RuntimeException(
+                        "Failed to set setting " +
+                        _StringUtil.jQuote(param) + " to " +
+                        _StringUtil.jQuote(value) + "; see cause exception.",
+                        e);
+            }
+        }
+    }
+    
+    /*
+     * This method just contains all the code to seed the data model 
+     * ported over from the individual classes. This seems ugly and unnecessary.
+     * We really might as well just expose pretty much 
+     * the same tree to all our tests. (JR)
+     */
+    @Override
+    @SuppressWarnings("boxing")
+    public void setUp() throws Exception {
+        confB.setTemplateLoader(
+                new CopyrightCommentRemoverTemplateLoader(
+                        new ClassTemplateLoader(TemplateTestCase.class, "templates")));
+        
+        DefaultObjectWrapper dow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
+        
+        dataModel.put(ASSERT_VAR_NAME, AssertDirective.INSTANCE);
+        dataModel.put(ASSERT_EQUALS_VAR_NAME, AssertEqualsDirective.INSTANCE);
+        dataModel.put(ASSERT_FAILS_VAR_NAME, AssertFailsDirective.INSTANCE);
+        dataModel.put(NO_OUTPUT_VAR_NAME, NoOutputDirective.INSTANCE);
+
+        dataModel.put(JAVA_OBJECT_INFO_VAR_NAME, JavaObjectInfo.INSTANCE);
+        dataModel.put(TEST_NAME_VAR_NAME, simpleTestName);
+        dataModel.put(ICI_INT_VALUE_VAR_NAME, confB.getIncompatibleImprovements().intValue());
+        
+        dataModel.put("message", "Hello, world!");
+
+        if (simpleTestName.startsWith("api-builtin")) {
+            dataModel.put("map", ImmutableMap.of(1, "a", 2, "b", 3, "c"));
+            dataModel.put("list", ImmutableList.of(1, 2, 3));
+            dataModel.put("set", ImmutableSet.of("a", "b", "c"));
+            dataModel.put("s", "test");
+        } else if (simpleTestName.equals("default-object-wrapper")) {
+            dataModel.put("array", new String[] { "array-0", "array-1"});
+            dataModel.put("list", Arrays.asList("list-0", "list-1", "list-2"));
+            Map<Object, Object> tmap = new HashMap<>();
+            tmap.put("key", "value");
+            Object objKey = new Object();
+            tmap.put(objKey, "objValue");
+            dataModel.put("map", tmap);
+            dataModel.put("objKey", objKey);
+            dataModel.put("obj", new org.apache.freemarker.test.templatesuite.models.BeanTestClass());
+            dataModel.put("resourceBundle",
+                    new ResourceBundleModel(ResourceBundle.getBundle(
+                            "org.apache.freemarker.test.templatesuite.models.BeansTestResources"), dow));
+            dataModel.put("date", new GregorianCalendar(1974, 10, 14).getTime());
+            dataModel.put("statics", dow.getStaticModels());
+            dataModel.put("enums", dow.getEnumModels());
+        } else if (simpleTestName.equals("boolean")) {
+            dataModel.put( "boolean1", TemplateBooleanModel.FALSE);
+            dataModel.put( "boolean2", TemplateBooleanModel.TRUE);
+            dataModel.put( "boolean3", TemplateBooleanModel.TRUE);
+            dataModel.put( "boolean4", TemplateBooleanModel.TRUE);
+            dataModel.put( "boolean5", TemplateBooleanModel.FALSE);
+            
+            dataModel.put( "list1", new BooleanList1(dow) );
+            dataModel.put( "list2", new BooleanList2(dow) );
+    
+            dataModel.put( "hash1", new BooleanHash1() );
+            dataModel.put( "hash2", new BooleanHash2() );
+        } else if (simpleTestName.startsWith("dateformat")) {
+            GregorianCalendar cal = new GregorianCalendar(2002, 10, 15, 14, 54, 13);
+            cal.setTimeZone(TimeZone.getTimeZone("GMT"));
+            dataModel.put("date", new SimpleDate(cal.getTime(), TemplateDateModel.DATETIME));
+            dataModel.put("unknownDate", new SimpleDate(cal.getTime(), TemplateDateModel.UNKNOWN));
+            dataModel.put("javaGMT02", TimeZone.getTimeZone("GMT+02"));
+            dataModel.put("javaUTC", TimeZone.getTimeZone("UTC"));
+            dataModel.put("adaptedToStringScalar", new Object() {
+                @Override
+                public String toString() {
+                    return "GMT+02";
+                }
+            });
+            dataModel.put("sqlDate", new java.sql.Date(1273955885023L));
+            dataModel.put("sqlTime", new java.sql.Time(74285023L));
+        } else if (
+                templateName.equals("list.ftl") || templateName.equals("list2.ftl") || templateName.equals("list3.ftl")
+                || simpleTestName.equals("listhash")) {
+            dataModel.put("listables", new Listables());
+        } else if (simpleTestName.startsWith("number-format")) {
+            dataModel.put("int", new SimpleNumber(Integer.valueOf(1)));
+            dataModel.put("double", new SimpleNumber(Double.valueOf(1.0)));
+            dataModel.put("double2", new SimpleNumber(Double.valueOf(1 + 1e-15)));
+            dataModel.put("double3", new SimpleNumber(Double.valueOf(1e-16)));
+            dataModel.put("double4", new SimpleNumber(Double.valueOf(-1e-16)));
+            dataModel.put("bigDecimal", new SimpleNumber(java.math.BigDecimal.valueOf(1)));
+            dataModel.put("bigDecimal2", new SimpleNumber(java.math.BigDecimal.valueOf(1, 16)));
+        } else if (simpleTestName.equals("simplehash-char-key")) {
+            HashMap<String, String> mStringC = new HashMap<>();
+            mStringC.put("c", "string");
+            dataModel.put("mStringC", mStringC);
+            
+            HashMap<String, String> mStringCNull = new HashMap<>();
+            mStringCNull.put("c", null);
+            dataModel.put("mStringCNull", mStringCNull);
+            
+            HashMap<Character, String> mCharC = new HashMap<>();
+            mCharC.put(Character.valueOf('c'), "char");
+            dataModel.put("mCharC", mCharC);
+            
+            HashMap<String, String> mCharCNull = new HashMap<>();
+            mCharCNull.put("c", null);
+            dataModel.put("mCharCNull", mCharCNull);
+            
+            HashMap<Object, String> mMixed = new HashMap<>();
+            mMixed.put(Character.valueOf('c'), "char");
+            mMixed.put("s", "string");
+            mMixed.put("s2", "string2");
+            mMixed.put("s2n", null);
+            dataModel.put("mMixed", mMixed);
+        } else if (simpleTestName.equals("default-xmlns")) {
+            InputSource is = new InputSource(getClass().getResourceAsStream("models/defaultxmlns1.xml"));
+            NodeModel nm = XMLLoader.toModel(is);
+            dataModel.put("doc", nm);
+        } else if (simpleTestName.equals("multimodels")) {
+            dataModel.put("test", "selftest");
+            dataModel.put("self", "self");
+            dataModel.put("zero", Integer.valueOf(0));
+            dataModel.put("data", new MultiModel1());
+        } else if (simpleTestName.equals("stringbimethods")) {
+            dataModel.put("multi", new TestBoolean());
+        } else if (simpleTestName.startsWith("type-builtins")) {
+            dataModel.put("testmethod", new TestMethod());
+            dataModel.put("testnode", new TestNode());
+            dataModel.put("testcollection", new SimpleCollection(new ArrayList<>(), dow));
+            dataModel.put("testcollectionEx", DefaultNonListCollectionAdapter.adapt(new HashSet<>(), dow));
+            dataModel.put("bean", new TestBean());
+        } else if (simpleTestName.equals("date-type-builtins")) {
+            GregorianCalendar cal = new GregorianCalendar(2003, 4 - 1, 5, 6, 7, 8);
+            cal.setTimeZone(TimeZone.getTimeZone("UTC"));
+            Date d = cal.getTime();
+            dataModel.put("unknown", d);
+            dataModel.put("timeOnly", new java.sql.Time(d.getTime()));
+            dataModel.put("dateOnly", new java.sql.Date(d.getTime()));
+            dataModel.put("dateTime", new java.sql.Timestamp(d.getTime()));
+        } else if (simpleTestName.equals("var-layers")) {
+            dataModel.put("x", Integer.valueOf(4));
+            dataModel.put("z", Integer.valueOf(4));
+            confB.setSharedVariable("y", Integer.valueOf(7));
+        } else if (simpleTestName.equals("xml-fragment")) {
+            DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
+            f.setNamespaceAware(true);
+            DocumentBuilder db = f.newDocumentBuilder();
+            org.w3c.dom.Document doc = db.parse(new InputSource(getClass().getResourceAsStream("models/xmlfragment.xml")));
+            NodeModel.simplify(doc);
+            dataModel.put("node", NodeModel.wrap(doc.getDocumentElement().getFirstChild().getFirstChild()));
+        } else if (simpleTestName.equals("xmlns1")) {
+            InputSource is = new InputSource(getClass().getResourceAsStream("models/xmlns.xml"));
+            NodeModel nm = XMLLoader.toModel(is);
+            dataModel.put("doc", nm);
+        } else if (simpleTestName.equals("xmlns2")) {
+            InputSource is = new InputSource(getClass().getResourceAsStream("models/xmlns2.xml"));
+            NodeModel nm = XMLLoader.toModel(is);
+            dataModel.put("doc", nm);
+        } else if (simpleTestName.equals("xmlns3") || simpleTestName.equals("xmlns4")) {
+            InputSource is = new InputSource(getClass().getResourceAsStream("models/xmlns3.xml"));
+            NodeModel nm = XMLLoader.toModel(is);
+            dataModel.put("doc", nm);
+        } else if (simpleTestName.equals("xmlns5")) {
+            InputSource is = new InputSource(getClass().getResourceAsStream("models/defaultxmlns1.xml"));
+            NodeModel nm = XMLLoader.toModel(is);
+            dataModel.put("doc", nm);
+        } else if (simpleTestName.equals("xml-ns_prefix-scope")) {
+            InputSource is = new InputSource(getClass().getResourceAsStream("models/xml-ns_prefix-scope.xml"));
+            NodeModel nm = XMLLoader.toModel(is);
+            dataModel.put("doc", nm);
+        } else if (simpleTestName.startsWith("sequence-builtins")) {
+            Set<String> abcSet = new TreeSet<>();
+            abcSet.add("a");
+            abcSet.add("b");
+            abcSet.add("c");
+            dataModel.put("abcSet", abcSet);
+            dataModel.put("abcSetNonSeq", DefaultNonListCollectionAdapter.adapt(abcSet, dow));
+            
+            List<String> listWithNull = new ArrayList<>();
+            listWithNull.add("a");
+            listWithNull.add(null);
+            listWithNull.add("c");
+            dataModel.put("listWithNull", listWithNull);
+            
+            List<String> listWithNullsOnly = new ArrayList<>();
+            listWithNull.add(null);
+            listWithNull.add(null);
+            listWithNull.add(null);
+            dataModel.put("listWithNullsOnly", listWithNullsOnly);
+            
+            dataModel.put("abcCollection", new SimpleCollection(abcSet, dow));
+            
+            Set<String> set = new HashSet<>();
+            set.add("a");
+            set.add("b");
+            set.add("c");
+            dataModel.put("set", set);
+        } else if (simpleTestName.equals("number-to-date")) {
+          dataModel.put("bigInteger", new BigInteger("1305575275540"));
+          dataModel.put("bigDecimal", new BigDecimal("1305575275539.5"));
+        } else if (simpleTestName.equals("varargs")) {
+          dataModel.put("m", new VarArgTestModel());
+        } else if (simpleTestName.startsWith("boolean-formatting")) {
+          dataModel.put("booleanAndString", new BooleanAndStringTemplateModel());
+          dataModel.put("booleanVsStringMethods", new BooleanVsStringMethods());
+        } else if (simpleTestName.startsWith("number-math-builtins")) {
+            dataModel.put("fNan", Float.valueOf(Float.NaN));
+            dataModel.put("dNan", Double.valueOf(Double.NaN));
+            dataModel.put("fNinf", Float.valueOf(Float.NEGATIVE_INFINITY));
+            dataModel.put("dPinf", Double.valueOf(Double.POSITIVE_INFINITY));
+            
+            dataModel.put("fn", Float.valueOf(-0.05f));
+            dataModel.put("dn", Double.valueOf(-0.05));
+            dataModel.put("ineg", Integer.valueOf(-5));
+            dataModel.put("ln", Long.valueOf(-5));
+            dataModel.put("sn", Short.valueOf((short) -5));
+            dataModel.put("bn", Byte.valueOf((byte) -5));
+            dataModel.put("bin", BigInteger.valueOf(5));
+            dataModel.put("bdn", BigDecimal.valueOf(-0.05));
+            
+            dataModel.put("fp", Float.valueOf(0.05f));
+            dataModel.put("dp", Double.valueOf(0.05));
+            dataModel.put("ip", Integer.valueOf(5));
+            dataModel.put("lp", Long.valueOf(5));
+            dataModel.put("sp", Short.valueOf((short) 5));
+            dataModel.put("bp", Byte.valueOf((byte) 5));
+            dataModel.put("bip", BigInteger.valueOf(5));
+            dataModel.put("bdp", BigDecimal.valueOf(0.05));
+        } else if (simpleTestName.startsWith("overloaded-methods")) {
+            dataModel.put("obj", new OverloadedMethods2());
+        }
+    }
+    
+    @Override
+    public void runTest() throws IOException, ConfigurationException {
+        Template template;
+        try {
+            template = confB.build().getTemplate(templateName);
+        } catch (IOException e) {
+            throw new AssertionFailedError(
+                    "Could not load template " + _StringUtil.jQuote(templateName) + ":\n" + getStackTrace(e));
+        }
+        ASTPrinter.validateAST(template);
+        
+        StringWriter out = noOutput ? null : new StringWriter();
+        try {
+            template.process(dataModel, out != null ? out : _NullWriter.INSTANCE);
+        } catch (TemplateException e) {
+            throw new AssertionFailedError("Template " + _StringUtil.jQuote(templateName) + " has stopped with error:\n"
+                        + getStackTrace(e));
+        }
+        
+        if (out != null) {
+            assertExpectedFileEqualsString(expectedFileName, out.toString());
+        }
+    }
+
+    private String getStackTrace(Throwable e) {
+        StringWriter sw = new StringWriter();
+        e.printStackTrace(new PrintWriter(sw));
+        return sw.toString();
+    }
+
+    @Override
+    protected String getExpectedContentFileDirectoryResourcePath() throws IOException {
+        return joinResourcePaths(super.getExpectedContentFileDirectoryResourcePath(), "expected");
+    }
+
+    @Override
+    protected Charset getTestResourceDefaultCharset() {
+        return confB.getOutputEncoding() != null ? confB.getOutputEncoding() : StandardCharsets.UTF_8;
+    }
+
+    static class TestBoolean implements TemplateBooleanModel, TemplateScalarModel {
+        @Override
+        public boolean getAsBoolean() {
+            return true;
+        }
+        
+        @Override
+        public String getAsString() {
+            return "de";
+        }
+    }
+
+    static class TestMethod implements TemplateMethodModel {
+        @Override
+        public Object exec(List arguments) {
+            return "x";
+        }
+    }
+
+    static class TestNode implements TemplateNodeModel {
+
+        @Override
+        public String getNodeName() {
+            return "name";
+        }
+
+        @Override
+        public TemplateNodeModel getParentNode() {
+            return null;
+        }
+
+        @Override
+        public String getNodeType() {
+            return "element";
+        }
+
+        @Override
+        public TemplateSequenceModel getChildNodes() {
+            return null;
+        }
+
+        @Override
+        public String getNodeNamespace() {
+            return null;
+        }
+    }
+
+   public Object getTestMapBean() {
+        Map<String, Object> testBean = new TestMapBean();
+        testBean.put("name", "Chris");
+        testBean.put("location", "San Francisco");
+        testBean.put("age", Integer.valueOf(27));
+        return testBean;
+    }
+
+    public static class TestMapBean extends HashMap<String, Object> {
+        public String getName() {
+            return "Christopher";
+        }
+        public int getLuckyNumber() {
+            return 7;
+        }
+    }
+
+    public static class TestBean {
+
+        public int m(int n) {
+            return n * 10;
+        }
+
+        public int mOverloaded(int n) {
+            return n * 10;
+        }
+
+        public String mOverloaded(String s) {
+            return s.toUpperCase();
+        }
+        
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/TemplateTestSuite.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/TemplateTestSuite.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/TemplateTestSuite.java
new file mode 100644
index 0000000..0edae99
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/TemplateTestSuite.java
@@ -0,0 +1,298 @@
+/*
+ * 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.test.templatesuite;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.Version;
+import org.apache.freemarker.core.util._StringUtil;
+import org.apache.freemarker.dom.NodeModel;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import junit.framework.TestSuite;
+
+/**
+ * Test suite where the test cases are defined in testcases.xml, and usually process
+ * templates and compare their output with the expected output.
+ * 
+ * If you only want to run certain tests, you can specify a regular expression for
+ * the test name in the {@link #TEST_FILTER_PROPERTY_NAME} system property.
+ */
+public class TemplateTestSuite extends TestSuite {
+    
+    private static final String ELEM_TEST_CASE = "testCase";
+
+    private static final String ELEM_SETTING = "setting";
+
+    private static final String ATTR_NO_OUTPUT = "noOutput";
+
+    private static final String ATTR_EXPECTED = "expected";
+
+    private static final String ATTR_TEMPLATE = "template";
+
+    private static final String END_TEMPLATE_NAME_MARK = "[#endTN]";
+
+    public static final String CONFIGURATION_XML_FILE_NAME = "testcases.xml";
+
+    /**
+     * When setting this system property, only the tests whose name matches the
+     * given regular expression will be executed.
+     */
+    public static final String TEST_FILTER_PROPERTY_NAME = "freemareker.templateTestSuite.testFilter";
+    
+    /**
+     * Comma separated list of "incompatible improvements" versions to run the test cases with.
+     */
+    public static final String INCOMPATIBLE_IMPROVEMENTS_PROPERTY_NAME
+            = "freemareker.templateTestSuite.incompatibleImprovements";
+    
+    private final Map<String, String> testSuiteSettings = new LinkedHashMap<>();
+
+    private final ArrayList<Version> testSuiteIcis;
+
+    private final Pattern testCaseNameFilter;
+    
+    public static TestSuite suite() throws Exception {
+        return new TemplateTestSuite();
+    }
+    
+    public TemplateTestSuite() throws Exception {
+        NodeModel.useJaxenXPathSupport();
+        
+        String filterStr = System.getProperty(TEST_FILTER_PROPERTY_NAME);
+        testCaseNameFilter = filterStr != null ? Pattern.compile(filterStr) : null;
+        if (testCaseNameFilter != null) {
+            System.out.println("Note: " + TEST_FILTER_PROPERTY_NAME + " is " + _StringUtil.jQuote(testCaseNameFilter));
+        }
+        
+        testSuiteIcis = new ArrayList<>();
+        String testedIcIsStr = System.getProperty(INCOMPATIBLE_IMPROVEMENTS_PROPERTY_NAME);
+        if (testedIcIsStr != null) {
+            for (String iciStr : testedIcIsStr.split(",")) {
+                iciStr = iciStr.trim();
+                if (iciStr.length() != 0) {
+                    testSuiteIcis.add(new Version(iciStr));
+                }
+            }
+        }
+        if (testSuiteIcis.isEmpty()) {
+            testSuiteIcis.add(getMinIcIVersion());
+            testSuiteIcis.add(getMaxIcIVersion());
+        }
+        
+        java.net.URL url = TemplateTestSuite.class.getResource(CONFIGURATION_XML_FILE_NAME);
+        if (url == null) {
+            throw new IOException("Resource not found: "
+                    + TemplateTestSuite.class.getName() + ", " + CONFIGURATION_XML_FILE_NAME);
+        }
+        processConfigXML(url.toURI());
+    }
+    
+    /**
+     * Read the test case configurations file and build up the test suite.
+     */
+    public void processConfigXML(URI uri) throws Exception {
+        Element testCasesElem = loadXMLFromURL(uri);
+        
+        NodeList children = testCasesElem.getChildNodes();
+        for (int childIdx = 0; childIdx < children.getLength(); childIdx++) {
+            Node n = children.item(childIdx);
+            if (n.getNodeType() == Node.ELEMENT_NODE) {
+                final String nodeName = n.getNodeName();
+                if (nodeName.equals(ELEM_SETTING)) {
+                    NamedNodeMap attrs = n.getAttributes();
+                    for (int attrIdx = 0; attrIdx < attrs.getLength(); attrIdx++) {
+                        Attr attr = (Attr) attrs.item(attrIdx);
+                        testSuiteSettings.put(attr.getName(), attr.getValue());
+                    }
+                } else if (nodeName.equals(ELEM_TEST_CASE)) {
+                    for (TemplateTestCase testCase : createTestCasesFromElement((Element) n)) {
+                        addTest(testCase);
+                    }
+                }
+            }
+        }
+    }
+
+    private Element loadXMLFromURL(URI uri) throws ParserConfigurationException, SAXException, IOException {
+        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+        // dbf.setValidating(true);
+        DocumentBuilder db = dbf.newDocumentBuilder();
+        Document d = db.parse(uri.toString());
+        return d.getDocumentElement();
+    }
+    
+    String getTextInElement(Element e) {
+        StringBuilder buf = new StringBuilder();
+        NodeList children = e.getChildNodes();
+        for (int i = 0; i < children.getLength(); i++) {
+            Node n = children.item(i);
+            short type = n.getNodeType();
+            if (type == Node.TEXT_NODE || type == Node.CDATA_SECTION_NODE) {
+                buf.append(n.getNodeValue());
+            }
+        }
+        return buf.toString();
+    }
+    
+    /**
+     * Returns the list of test cases generated from the {@link #ELEM_TEST_CASE} element.
+     * There can be multiple generated test cases because of "incompatible improvements" variations, or none because
+     * of the {@code nameFilter}.
+     */
+    private List<TemplateTestCase> createTestCasesFromElement(Element testCaseElem)
+            throws Exception {
+        final String caseName = _StringUtil.emptyToNull(testCaseElem.getAttribute("name"));
+        if (caseName == null) throw new Exception("Invalid XML: the \"name\" attribute is mandatory.");
+        
+        if (testCaseNameFilter != null
+                && !testCaseNameFilter.matcher(caseName).matches()) {
+            return Collections.emptyList();
+        }
+        
+        final String templateName;
+        final String expectedFileName;
+        {
+            final String beforeEndTN;
+            final String afterEndTN;
+            {
+                int tBNameSep = caseName.indexOf(END_TEMPLATE_NAME_MARK);
+                beforeEndTN = tBNameSep == -1 ? caseName : caseName.substring(0, tBNameSep);
+                afterEndTN = tBNameSep == -1
+                        ? "" : caseName.substring(tBNameSep + END_TEMPLATE_NAME_MARK.length());
+            }
+            
+            {
+                String s = _StringUtil.emptyToNull(testCaseElem.getAttribute(ATTR_TEMPLATE));
+                templateName = s != null ? s : beforeEndTN + ".ftl";
+            }
+    
+            {
+                String s = _StringUtil.emptyToNull(testCaseElem.getAttribute(ATTR_EXPECTED));
+                expectedFileName = s != null ? s : beforeEndTN + afterEndTN + ".txt";
+            }
+        }
+        
+        final boolean noOutput;
+        {
+            String s = _StringUtil.emptyToNull(testCaseElem.getAttribute(ATTR_NO_OUTPUT));
+            noOutput = s != null && _StringUtil.getYesNo(s);
+        }
+
+        final Map<String, String> testCaseSettings = getCaseFMSettings(testCaseElem);
+        
+        final List<Version> icisToTest;
+        {
+            final String testCaseIcis = testCaseSettings.get(Configuration.ExtendableBuilder.INCOMPATIBLE_IMPROVEMENTS_KEY);
+                    
+            icisToTest = testCaseIcis != null ? parseVersionList(testCaseIcis) : testSuiteIcis;
+            if (icisToTest.isEmpty()) {
+                throw new Exception("The incompatible_improvement list was empty");
+            }
+        }
+
+        List<TemplateTestCase> result = new ArrayList<>();
+        for (Version iciToTest : icisToTest) {
+            TemplateTestCase testCase = new TemplateTestCase(
+                    caseName + "(ici=" + iciToTest + ")", caseName,
+                    templateName, expectedFileName, noOutput, iciToTest);
+            for (Map.Entry<String, String> setting : testSuiteSettings.entrySet()) {
+                testCase.setSetting(setting.getKey(), setting.getValue());
+            }
+            for (Map.Entry<String, String> setting : testCaseSettings.entrySet()) {
+                testCase.setSetting(setting.getKey(), setting.getValue());
+            }
+            
+            result.add(testCase);
+        }
+        
+        return result;
+    }
+
+    private List<Version> parseVersionList(String versionsStr) {
+        List<Version> versions = new ArrayList<>();
+        for (String versionStr : versionsStr.split(",")) {
+            versionStr = versionStr.trim();
+            if (versionStr.length() != 0) {
+                final Version v;
+                if ("min".equals(versionStr)) {
+                    v = getMinIcIVersion();
+                } else if ("max".equals(versionStr)) {
+                    v = getMaxIcIVersion();
+                } else {
+                    v = new Version(versionStr);
+                }
+                if (!versions.contains(v)) {
+                    versions.add(v);
+                }
+            }
+        }
+        return versions;
+    }
+
+    private Version getMaxIcIVersion() {
+        Version v = Configuration.getVersion();
+        // Remove nightly, RC and such:
+        return new Version(v.getMajor(), v.getMinor(), v.getMicro());
+    }
+
+    private Version getMinIcIVersion() {
+        return Configuration.VERSION_3_0_0;
+    }
+
+    private Map<String, String> getCaseFMSettings(Element e) {
+        final Map<String, String> caseFMSettings;
+        caseFMSettings = new LinkedHashMap<>();
+        NodeList settingElems = e.getElementsByTagName(ELEM_SETTING);
+        for (int elemIdx = 0; elemIdx < settingElems.getLength(); elemIdx++) {
+            NamedNodeMap attrs = settingElems.item(elemIdx).getAttributes();
+            for (int attrIdx = 0; attrIdx < attrs.getLength(); attrIdx++) {
+                Attr attr = (Attr) attrs.item(attrIdx);
+
+                final String settingName = attr.getName();
+                caseFMSettings.put(settingName, attr.getValue());
+            }
+        }
+        return caseFMSettings;
+    }
+    
+    public static void main (String[] args) throws Exception {
+        junit.textui.TestRunner.run(new TemplateTestSuite());
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/AllTemplateModels.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/AllTemplateModels.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/AllTemplateModels.java
new file mode 100644
index 0000000..974b3f9
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/AllTemplateModels.java
@@ -0,0 +1,128 @@
+/*
+ * 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.test.templatesuite.models;
+
+import java.util.Date;
+
+import org.apache.freemarker.core.model.TemplateBooleanModel;
+import org.apache.freemarker.core.model.TemplateCollectionModel;
+import org.apache.freemarker.core.model.TemplateDateModel;
+import org.apache.freemarker.core.model.TemplateHashModelEx;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateModelIterator;
+import org.apache.freemarker.core.model.TemplateNumberModel;
+import org.apache.freemarker.core.model.TemplateScalarModel;
+import org.apache.freemarker.core.model.TemplateSequenceModel;
+import org.apache.freemarker.core.model.impl.SimpleScalar;
+
+/**
+ * Implements all template models that are interesting when calling overloaded Java methods.
+ */
+public class AllTemplateModels implements
+        TemplateScalarModel, TemplateNumberModel, TemplateDateModel, TemplateBooleanModel,
+        TemplateHashModelEx, TemplateSequenceModel, TemplateCollectionModel {
+
+    public static final AllTemplateModels INSTANCE = new AllTemplateModels();
+    
+    private final TemplateModelIterator EMPTY_ITERATOR = new TemplateModelIterator() {
+
+        @Override
+        public TemplateModel next() throws TemplateModelException {
+            return null;
+        }
+
+        @Override
+        public boolean hasNext() throws TemplateModelException {
+            return false;
+        }
+        
+    };
+    
+    private final TemplateCollectionModel EMPTY_COLLECTION = new TemplateCollectionModel() {
+
+        @Override
+        public TemplateModelIterator iterator() throws TemplateModelException {
+            return EMPTY_ITERATOR;
+        }
+    };
+    
+    @Override
+    public TemplateModel get(String key) throws TemplateModelException {
+        return new SimpleScalar("value for key " + key);
+    }
+
+    @Override
+    public boolean isEmpty() throws TemplateModelException {
+        return true;
+    }
+
+    @Override
+    public TemplateModelIterator iterator() throws TemplateModelException {
+        return EMPTY_ITERATOR;
+    }
+
+    @Override
+    public TemplateModel get(int index) throws TemplateModelException {
+        return null;
+    }
+
+    @Override
+    public int size() throws TemplateModelException {
+        return 0;
+    }
+
+    @Override
+    public TemplateCollectionModel keys() throws TemplateModelException {
+        return EMPTY_COLLECTION;
+    }
+
+    @Override
+    public TemplateCollectionModel values() throws TemplateModelException {
+        return EMPTY_COLLECTION;
+    }
+
+    @Override
+    public boolean getAsBoolean() throws TemplateModelException {
+        return true;
+    }
+
+    @Override
+    public Date getAsDate() throws TemplateModelException {
+        return new Date(0);
+    }
+
+    @Override
+    public int getDateType() {
+        return TemplateDateModel.DATETIME;
+    }
+
+    @Override
+    @SuppressWarnings("boxing")
+    public Number getAsNumber() throws TemplateModelException {
+        return 1;
+    }
+
+    @Override
+    public String getAsString() throws TemplateModelException {
+        return "s";
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BeanTestClass.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BeanTestClass.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BeanTestClass.java
new file mode 100644
index 0000000..7e7fa82
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BeanTestClass.java
@@ -0,0 +1,93 @@
+/*
+ * 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.test.templatesuite.models;
+
+/**
+ */
+public class BeanTestClass extends BeanTestSuperclass implements BeanTestInterface<Integer> {
+    public static final String STATIC_FINAL_FIELD = "static-final-field";
+    public static String STATIC_FIELD = "static-field";
+    
+	public String getFoo() {
+	    return "foo-value";
+	}
+	
+	public String getBar(int index) {
+	    return "bar-value-" + index;
+	}
+
+	public String[] getBar() {
+		return new String[] { "bar-value-0", "bar-value-1", "bar-value-2" };
+	}
+
+	public String overloaded(int i) {
+	    return "overloaded-int-" + i;
+	}
+	
+	public String overloaded(String s) {
+	    return "overloaded-String-" + s;
+	}
+	
+	public static String staticMethod() {
+	    return "static-method";
+	}
+	
+	public static String staticOverloaded(int i) {
+	    return "static-overloaded-int-" + i;
+	}
+
+	public static String staticOverloaded(String s) {
+	    return "static-overloaded-String-" + s;
+	}
+	
+	public PrivateInner getPrivateInner() {
+	    return new PrivateInner();
+	}
+
+        public PublicInner getPublicInner() {
+            return new PublicInner();
+        }
+	
+        public class PublicInner {
+            
+            public int getX() {
+                return 1;
+            }
+            
+            public String m() {
+                return "m";
+            }
+            
+        }
+        
+        @SuppressWarnings("unused")
+	private class PrivateInner {
+	    
+            public int getX() {
+	        return 2;
+	    }
+	    
+	    public String m() {
+	        return "M";
+	    }
+	    
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BeanTestInterface.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BeanTestInterface.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BeanTestInterface.java
new file mode 100644
index 0000000..6737b87
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BeanTestInterface.java
@@ -0,0 +1,25 @@
+/*
+ * 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.test.templatesuite.models;
+
+public interface BeanTestInterface<T> {
+    T getSomething();
+    void setSomething(T s);
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BeanTestSuperclass.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BeanTestSuperclass.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BeanTestSuperclass.java
new file mode 100644
index 0000000..b462e9a
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BeanTestSuperclass.java
@@ -0,0 +1,30 @@
+/*
+ * 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.test.templatesuite.models;
+
+public class BeanTestSuperclass {
+    public Integer getSomething() {
+        return 42;
+    }
+    
+    public void setSomething(Integer x) {
+        
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanAndScalarModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanAndScalarModel.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanAndScalarModel.java
new file mode 100644
index 0000000..4af030e
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanAndScalarModel.java
@@ -0,0 +1,40 @@
+/*
+ * 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.test.templatesuite.models;
+
+import org.apache.freemarker.core.model.TemplateBooleanModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateScalarModel;
+
+public class BooleanAndScalarModel implements TemplateBooleanModel, TemplateScalarModel {
+
+    public static final BooleanAndScalarModel INSTANCE = new BooleanAndScalarModel();
+
+    @Override
+    public String getAsString() throws TemplateModelException {
+        return "s";
+    }
+
+    @Override
+    public boolean getAsBoolean() throws TemplateModelException {
+        return true;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanAndStringTemplateModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanAndStringTemplateModel.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanAndStringTemplateModel.java
new file mode 100644
index 0000000..d87b65c
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanAndStringTemplateModel.java
@@ -0,0 +1,38 @@
+/*
+ * 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.test.templatesuite.models;
+
+import org.apache.freemarker.core.model.TemplateBooleanModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateScalarModel;
+
+public class BooleanAndStringTemplateModel implements TemplateBooleanModel, TemplateScalarModel {
+
+    @Override
+    public String getAsString() throws TemplateModelException {
+        return "theStringValue";
+    }
+
+    @Override
+    public boolean getAsBoolean() throws TemplateModelException {
+        return true;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanHash1.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanHash1.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanHash1.java
new file mode 100644
index 0000000..524d003
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanHash1.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.test.templatesuite.models;
+
+import org.apache.freemarker.core.model.TemplateBooleanModel;
+import org.apache.freemarker.core.model.TemplateHashModel;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.impl.SimpleScalar;
+
+/**
+ * Tests the impact that the isEmpty() has on template hash models.
+ */
+public class BooleanHash1 implements TemplateHashModel {
+
+    /**
+     * Gets a <tt>TemplateModel</tt> from the hash.
+     *
+     * @param key the name by which the <tt>TemplateModel</tt>
+     * is identified in the template.
+     * @return the <tt>TemplateModel</tt> referred to by the key,
+     * or null if not found.
+     */
+    @Override
+    public TemplateModel get(String key) {
+        if ( key.equals( "temp" )) {
+            return new SimpleScalar( "Hello, world." );
+        } else if ( key.equals( "boolean" )) {
+            return TemplateBooleanModel.FALSE;
+        } else {
+            return new SimpleScalar( "Just another key..." );
+        }
+    }
+
+    /**
+     * @return true if this object is empty.
+     */
+    @Override
+    public boolean isEmpty() {
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanHash2.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanHash2.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanHash2.java
new file mode 100644
index 0000000..8bae7ab
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanHash2.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.test.templatesuite.models;
+
+import org.apache.freemarker.core.model.TemplateHashModel;
+import org.apache.freemarker.core.model.TemplateModel;
+
+/**
+ * Tests the impact that the isEmpty() has on template hash models.
+ */
+public class BooleanHash2 implements TemplateHashModel {
+
+    /**
+     * Gets a <tt>TemplateModel</tt> from the hash.
+     *
+     * @param key the name by which the <tt>TemplateModel</tt>
+     * is identified in the template.
+     * @return the <tt>TemplateModel</tt> referred to by the key,
+     * or null if not found.
+     */
+    @Override
+    public TemplateModel get(String key) {
+        return null;
+    }
+
+    /**
+     * @return true if this object is empty.
+     */
+    @Override
+    public boolean isEmpty() {
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanList1.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanList1.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanList1.java
new file mode 100644
index 0000000..3e0a69c
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanList1.java
@@ -0,0 +1,62 @@
+/*
+ * 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.test.templatesuite.models;
+
+import org.apache.freemarker.core.model.ObjectWrapper;
+import org.apache.freemarker.core.model.TemplateBooleanModel;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateSequenceModel;
+import org.apache.freemarker.core.model.impl.SimpleSequence;
+
+/**
+ * Model for testing the impact of isEmpty() on template list models. Every
+ * other method simply delegates to a SimpleList model.
+ */
+public class BooleanList1 implements TemplateSequenceModel {
+
+    private SimpleSequence cList;
+
+    /** Creates new BooleanList1 */
+    public BooleanList1(ObjectWrapper ow) {
+        cList = new SimpleSequence(ow);
+        cList.add( "false" );
+        cList.add( "0" );
+        cList.add(TemplateBooleanModel.FALSE);
+        cList.add(TemplateBooleanModel.TRUE);
+        cList.add(TemplateBooleanModel.TRUE);
+        cList.add(TemplateBooleanModel.TRUE);
+        cList.add(TemplateBooleanModel.FALSE);
+    }
+
+    /**
+     * @return the specified index in the list
+     */
+    @Override
+    public TemplateModel get(int i) throws TemplateModelException {
+        return cList.get(i);
+    }
+
+    @Override
+    public int size() {
+        return cList.size();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanList2.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanList2.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanList2.java
new file mode 100644
index 0000000..939fb5f
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanList2.java
@@ -0,0 +1,53 @@
+/*
+ * 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.test.templatesuite.models;
+
+import org.apache.freemarker.core.model.ObjectWrapper;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateSequenceModel;
+import org.apache.freemarker.core.model.impl.SimpleSequence;
+
+/**
+ * Model for testing list models. Every
+ * other method simply delegates to a SimpleList model.
+ */
+public class BooleanList2 implements TemplateSequenceModel {
+
+    private SimpleSequence cList;
+
+    /** Creates new BooleanList2 */
+    public BooleanList2(ObjectWrapper ow) {
+        cList = new SimpleSequence(ow);
+    }
+
+    /**
+     * @return the specified index in the list
+     */
+    @Override
+    public TemplateModel get(int i) throws TemplateModelException {
+        return cList.get(i);
+    }
+
+    @Override
+    public int size() {
+        return cList.size();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanVsStringMethods.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanVsStringMethods.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanVsStringMethods.java
new file mode 100644
index 0000000..3e13623
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/BooleanVsStringMethods.java
@@ -0,0 +1,40 @@
+/*
+ * 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.test.templatesuite.models;
+
+public class BooleanVsStringMethods {
+    
+    public String expectsString(String s) {
+        return s;
+    }
+
+    public boolean expectsBoolean(boolean b) {
+        return b;
+    }
+    
+    public String overloaded(String s) {
+        return "String " + s;
+    }
+    
+    public String overloaded(boolean s) {
+        return "boolean " + s;
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/EnumTestClass.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/EnumTestClass.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/EnumTestClass.java
new file mode 100644
index 0000000..359e4a4
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/EnumTestClass.java
@@ -0,0 +1,34 @@
+/*
+ * 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.test.templatesuite.models;
+
+/**
+ */
+public enum EnumTestClass
+{
+    ONE, 
+    TWO, 
+    THREE;
+    
+    @Override
+    public String toString() {
+        return name() + "x";
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/ExceptionModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/ExceptionModel.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/ExceptionModel.java
new file mode 100644
index 0000000..ca0f9be
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/ExceptionModel.java
@@ -0,0 +1,39 @@
+/*
+ * 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.test.templatesuite.models;
+
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateScalarModel;
+
+/**
+ * A template that always throws an exception whenever we call getAsString()
+ */
+public class ExceptionModel implements TemplateScalarModel {
+
+    /**
+     * Returns the scalar's value as a String.
+     *
+     * @return the String value of this scalar.
+     */
+    @Override
+    public String getAsString () throws TemplateModelException {
+        throw new TemplateModelException( "Throwing from ExceptionModel!" );
+    }
+}


[29/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/macros2.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/macros2.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/macros2.txt
new file mode 100644
index 0000000..1b4e007
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/macros2.txt
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+1 1
+2 2
+4
+m3 with d="4" Failed!

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/multimodels.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/multimodels.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/multimodels.txt
new file mode 100644
index 0000000..54ec68d
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/multimodels.txt
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+<html>
+<head>
+<title>FreeMarker: Test of Multiple Model implementations</title>
+</head>
+<body>
+
+<p>Let's begin with a simple model:</p>
+<p>Hello, world!</p>
+
+<p>Cool, now get into the first model. This implements a scalar, list, and
+hash as a single class. Let's try some tests...</p>
+
+<p>MultiModel1 as a string!</p>
+
+<p>Now as a list...</p>
+
+Model1 value: 0<br />
+Model1 value: 1<br />
+Model1 value: 2<br />
+Model1 value: 3<br />
+Model1 value: 4<br />
+Model1 value: 5<br />
+Model1 value: 6<br />
+Model1 value: 7<br />
+Model1 value: 8<br />
+Model1 value: 9<br />
+Model3 is alive!<br />
+
+<p>Index into a list...</p>
+<p>Model1 value: 1</p>
+<p>List size is: Nasty!</p>
+<p>List size is: Nasty!</p>
+
+<p>Now, again, as a hash. First using dot notation, then using [] notation:</p>
+
+<p>Selftest of a hash from MultiModel1</p>
+<p>Selftest of a hash from MultiModel1</p>
+
+<p>Now for the tricky stuff... use a model to index into another model...</p>
+<p>selftest</p>
+<p>Selftest of a hash from MultiModel1</p>
+<p>self</p>
+<p>Selftest of a hash from MultiModel1</p>
+
+<p>Same thing, this time a List index...</p>
+<p>0</p>
+<p>Model1 value: 0</p>
+<p>Model1 value: 1</p>
+
+<p>Now, do the same recursively...</p>
+<p>MultiModel1 as a string!</p>
+<p>Model2 is alive!</p>
+<p>Arguments are:<br />test<br /></p>
+<p>Arguments are:<br />MultiModel1 as a string!<br />Selftest of a hash from MultiModel1<br />Hello, world!<br /></p>
+
+<p>Does this really not work?</p>
+<p>Model3 is alive!</p>
+<p>Selftest from MultiModel3!</p>
+<p>Hello world from MultiModel3!</p>
+
+<p>(Again, with Hashes)</p>
+<p>Model3 is alive!</p>
+<p>Selftest from MultiModel3!</p>
+
+<p>Model3 is alive!</p>
+<p>Selftest from MultiModel3!</p>
+<p>Selftest from MultiModel3!</p>
+
+<p>As I suspected! (Manual on Expressions needs updating.)</p>
+
+<p>Second test on list size</p>
+<p>Key size, not the listSize method.</p>
+<p>Key size, not the listSize method.</p>
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/nested.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/nested.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/nested.txt
new file mode 100644
index 0000000..bcfb104
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/nested.txt
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+    test 3/1: undefined undefined undefined 
+    test 3/2: undefined undefined undefined 
+    test 3/3: undefined undefined undefined 
+
+    test 3/1: Y X Count 1 
+    test 3/2: Y X Count 2 
+    test 3/3: Y X Count 3 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/new-allowsnothing.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/new-allowsnothing.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/new-allowsnothing.txt
new file mode 100644
index 0000000..b8384c7
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/new-allowsnothing.txt
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+fails
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/new-defaultresolver.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/new-defaultresolver.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/new-defaultresolver.txt
new file mode 100644
index 0000000..35e7a3e
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/new-defaultresolver.txt
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+works
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/new-optin.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/new-optin.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/new-optin.txt
new file mode 100644
index 0000000..9d8e883
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/new-optin.txt
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+works
+fails
+
+works
+works
+
+works
+fails
+
+works
+fails
+
+works
+works
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/newlines1.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/newlines1.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/newlines1.txt
new file mode 100644
index 0000000..bc58731
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/newlines1.txt
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+<html>
+<head>
+<title>FreeMarker: Newlines Test</title>
+</head>
+<body>
+<p>A simple test follows:</p>
+
+<p>Hello, world!</p>
+
+</body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/newlines2.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/newlines2.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/newlines2.txt
new file mode 100644
index 0000000..c131421
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/newlines2.txt
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+<html>
+<head>
+<title>FreeMarker: Newlines the Second Test</title>
+</head>
+<body>
+<p>A simple test follows:</p>
+
+<p>Hello, world!
+</p>
+
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/noparse.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/noparse.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/noparse.txt
new file mode 100644
index 0000000..5e8486c
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/noparse.txt
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+<html>
+<head>
+<title>FreeMarker: NoParse Test</title>
+</head>
+<body>
+
+A simple test follows:
+
+${message}
+
+A more rigorous test, showing that we're not faking it:
+
+${message@#$%&}
+
+	<p>Message exists!
+		...and even generates output!
+		<#if message>
+			Nested statements are ok, too.
+		</#if>
+	</p>
+
+Here's another edge case, this time, trying to output a &lt;noparse&gt;
+inside another &lt;noparse&gt;
+
+
+This is what the noparse instruction looks like:
+
+<#noparse>This part of the template wont be parsed by the 
+FreeMarker parser. Instead, it will be treated as verbatim text information,
+and output as such.</#noparse>
+
+The rest of the template appears here.
+
+Simple.
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/number-format.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/number-format.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/number-format.txt
new file mode 100644
index 0000000..a6f8475
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/number-format.txt
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+1
+1
+1 234 567,89
+1234567.886
+1,00
+1
+1234567,89
+1234567.886
+1
+1
+1.000000000000001
+0.0000000000000001
+-0.0000000000000001
+1
+0.0000000000000001

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/number-literal.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/number-literal.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/number-literal.txt
new file mode 100644
index 0000000..b80bc85
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/number-literal.txt
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+<html>
+<head>
+<title>FreeMarker: Number Literal Test</title>
+</head>
+<body>
+
+<p>A simple test follows:</p>
+
+<p>Hello, world!</p>
+
+<p>Now perform a number assignment:</p>
+
+1,3
+
+
+My number is: 1,8
+My float is: 1.800000
+The int part is: 1
+
+
+1.83
+
+<p>Now use numbers in assignment</p>
+
+6
+
+8
+
+<p>Try numbers in tests</p>
+
+MyMessage is not 152, its: 8.
+
+<if (mymessage > 5)>
+   MyMessage is greater than five.
+</if
+
+		MyMessage is: 8.
+
+<p>Now for numbers in dynamic keys:</p>
+
+
+one
+three
+
+<p>Numbers in hashes:</p>
+
+twelve
+twelve
+twelve
+
+
+<p>Numbers in method calls:</p>
+
+Single argument value is: 1
+Single argument value is: 1
+Single argument value is: 12
+Single argument value is: 3
+Single argument value is: 3
+
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/number-to-date.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/number-to-date.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/number-to-date.txt
new file mode 100644
index 0000000..bc8a10e
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/number-to-date.txt
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+2011-05-16T19:47:55.54Z == 2011-05-16T19:47:55.54Z
+2011-05-16 == 2011-05-16
+19:47:55.54Z == 19:47:55.54Z
+
+2011-05-16T19:47:55.54Z == 2011-05-16T19:47:55.54Z
+2011-05-16T19:47:55.54Z == 2011-05-16T19:47:55.54Z
+2011-05-16T19:47:55.54Z == 2011-05-16T19:47:55.54Z
+2011-05-16T19:47:55.54Z == 2011-05-16T19:47:55.54Z
+1970-01-01T00:00:01Z == 1970-01-01T00:00:01Z
+1970-01-01T00:00:01Z == 1970-01-01T00:00:01Z
+1970-01-01T00:00:00Z == 1970-01-01T00:00:00Z
+
+failed

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/numerical-cast.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/numerical-cast.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/numerical-cast.txt
new file mode 100644
index 0000000..3bf6cd0
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/numerical-cast.txt
@@ -0,0 +1,462 @@
+/*
+ * 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.
+ */
+
+?int:
+    0?int=0
+    1?int=1
+    -1?int=-1
+    0.5?int=0
+    1.5?int=1
+    -0.5?int=0
+    -1.5?int=-1
+    0.25?int=0
+    -0.25?int=0
+    1.75?int=1
+    -1.75?int=-1
+    1.01?int=1
+    -1.01?int=-1
+    0.01?int=0
+    -0.01?int=0
+    127?int=127
+    128?int=128
+    -127?int=-127
+    -128?int=-128
+    32767?int=32767
+    32768?int=32768
+    -32767?int=-32767
+    -32768?int=-32768
+    2147483647?int=2147483647
+    2147483648?int=-2147483648
+    -2147483647?int=-2147483647
+    -2147483648?int=-2147483648
+    4294967295?int=-1
+    4294967296?int=0
+    -4294967295?int=1
+    -4294967296?int=0
+    2147483647.1?int=2147483647
+    2147483648.1?int=-2147483648
+    -2147483647.1?int=-2147483647
+    -2147483648.1?int=-2147483648
+    4294967295.1?int=-1
+    4294967296.1?int=0
+    -4294967295.1?int=1
+    -4294967296.1?int=0
+    2147483647.5?int=2147483647
+    2147483648.5?int=-2147483648
+    -2147483647.5?int=-2147483647
+    -2147483648.5?int=-2147483648
+    4294967295.5?int=-1
+    4294967296.5?int=0
+    -4294967295.5?int=1
+    -4294967296.5?int=0
+
+?double
+    0?double=0
+    1?double=1
+    -1?double=-1
+    0.5?double=0.5
+    1.5?double=1.5
+    -0.5?double=-0.5
+    -1.5?double=-1.5
+    0.25?double=0.25
+    -0.25?double=-0.25
+    1.75?double=1.75
+    -1.75?double=-1.75
+    1.01?double=1.01
+    -1.01?double=-1.01
+    0.01?double=0.01
+    -0.01?double=-0.01
+    127?double=127
+    128?double=128
+    -127?double=-127
+    -128?double=-128
+    32767?double=32767
+    32768?double=32768
+    -32767?double=-32767
+    -32768?double=-32768
+    2147483647?double=2147483647
+    2147483648?double=2147483648
+    -2147483647?double=-2147483647
+    -2147483648?double=-2147483648
+    4294967295?double=4294967295
+    4294967296?double=4294967296
+    -4294967295?double=-4294967295
+    -4294967296?double=-4294967296
+    2147483647.1?double=2147483647.1
+    2147483648.1?double=2147483648.1
+    -2147483647.1?double=-2147483647.1
+    -2147483648.1?double=-2147483648.1
+    4294967295.1?double=4294967295.1
+    4294967296.1?double=4294967296.1
+    -4294967295.1?double=-4294967295.1
+    -4294967296.1?double=-4294967296.1
+    2147483647.5?double=2147483647.5
+    2147483648.5?double=2147483648.5
+    -2147483647.5?double=-2147483647.5
+    -2147483648.5?double=-2147483648.5
+    4294967295.5?double=4294967295.5
+    4294967296.5?double=4294967296.5
+    -4294967295.5?double=-4294967295.5
+    -4294967296.5?double=-4294967296.5
+
+?long
+    0?long=0
+    1?long=1
+    -1?long=-1
+    0.5?long=0
+    1.5?long=1
+    -0.5?long=0
+    -1.5?long=-1
+    0.25?long=0
+    -0.25?long=0
+    1.75?long=1
+    -1.75?long=-1
+    1.01?long=1
+    -1.01?long=-1
+    0.01?long=0
+    -0.01?long=0
+    127?long=127
+    128?long=128
+    -127?long=-127
+    -128?long=-128
+    32767?long=32767
+    32768?long=32768
+    -32767?long=-32767
+    -32768?long=-32768
+    2147483647?long=2147483647
+    2147483648?long=2147483648
+    -2147483647?long=-2147483647
+    -2147483648?long=-2147483648
+    4294967295?long=4294967295
+    4294967296?long=4294967296
+    -4294967295?long=-4294967295
+    -4294967296?long=-4294967296
+    2147483647.1?long=2147483647
+    2147483648.1?long=2147483648
+    -2147483647.1?long=-2147483647
+    -2147483648.1?long=-2147483648
+    4294967295.1?long=4294967295
+    4294967296.1?long=4294967296
+    -4294967295.1?long=-4294967295
+    -4294967296.1?long=-4294967296
+    2147483647.5?long=2147483647
+    2147483648.5?long=2147483648
+    -2147483647.5?long=-2147483647
+    -2147483648.5?long=-2147483648
+    4294967295.5?long=4294967295
+    4294967296.5?long=4294967296
+    -4294967295.5?long=-4294967295
+    -4294967296.5?long=-4294967296
+
+?long from date
+    1304877615000 = 1304877615000
+
+?float
+    0?float=0
+    1?float=1
+    -1?float=-1
+    0.5?float=0.5
+    1.5?float=1.5
+    -0.5?float=-0.5
+    -1.5?float=-1.5
+    0.25?float=0.25
+    -0.25?float=-0.25
+    1.75?float=1.75
+    -1.75?float=-1.75
+    1.01?float=1.00999999
+    -1.01?float=-1.00999999
+    0.01?float=0.01
+    -0.01?float=-0.01
+    127?float=127
+    128?float=128
+    -127?float=-127
+    -128?float=-128
+    32767?float=32767
+    32768?float=32768
+    -32767?float=-32767
+    -32768?float=-32768
+    2147483647?float=2147483648
+    2147483648?float=2147483648
+    -2147483647?float=-2147483648
+    -2147483648?float=-2147483648
+    4294967295?float=4294967296
+    4294967296?float=4294967296
+    -4294967295?float=-4294967296
+    -4294967296?float=-4294967296
+    2147483647.1?float=2147483648
+    2147483648.1?float=2147483648
+    -2147483647.1?float=-2147483648
+    -2147483648.1?float=-2147483648
+    4294967295.1?float=4294967296
+    4294967296.1?float=4294967296
+    -4294967295.1?float=-4294967296
+    -4294967296.1?float=-4294967296
+    2147483647.5?float=2147483648
+    2147483648.5?float=2147483648
+    -2147483647.5?float=-2147483648
+    -2147483648.5?float=-2147483648
+    4294967295.5?float=4294967296
+    4294967296.5?float=4294967296
+    -4294967295.5?float=-4294967296
+    -4294967296.5?float=-4294967296
+
+?byte
+    0?byte=0
+    1?byte=1
+    -1?byte=-1
+    0.5?byte=0
+    1.5?byte=1
+    -0.5?byte=0
+    -1.5?byte=-1
+    0.25?byte=0
+    -0.25?byte=0
+    1.75?byte=1
+    -1.75?byte=-1
+    1.01?byte=1
+    -1.01?byte=-1
+    0.01?byte=0
+    -0.01?byte=0
+    127?byte=127
+    128?byte=-128
+    -127?byte=-127
+    -128?byte=-128
+    32767?byte=-1
+    32768?byte=0
+    -32767?byte=1
+    -32768?byte=0
+    2147483647?byte=-1
+    2147483648?byte=0
+    -2147483647?byte=1
+    -2147483648?byte=0
+    4294967295?byte=-1
+    4294967296?byte=0
+    -4294967295?byte=1
+    -4294967296?byte=0
+    2147483647.1?byte=-1
+    2147483648.1?byte=0
+    -2147483647.1?byte=1
+    -2147483648.1?byte=0
+    4294967295.1?byte=-1
+    4294967296.1?byte=0
+    -4294967295.1?byte=1
+    -4294967296.1?byte=0
+    2147483647.5?byte=-1
+    2147483648.5?byte=0
+    -2147483647.5?byte=1
+    -2147483648.5?byte=0
+    4294967295.5?byte=-1
+    4294967296.5?byte=0
+    -4294967295.5?byte=1
+    -4294967296.5?byte=0
+
+?short
+    0?short=0
+    1?short=1
+    -1?short=-1
+    0.5?short=0
+    1.5?short=1
+    -0.5?short=0
+    -1.5?short=-1
+    0.25?short=0
+    -0.25?short=0
+    1.75?short=1
+    -1.75?short=-1
+    1.01?short=1
+    -1.01?short=-1
+    0.01?short=0
+    -0.01?short=0
+    127?short=127
+    128?short=128
+    -127?short=-127
+    -128?short=-128
+    32767?short=32767
+    32768?short=-32768
+    -32767?short=-32767
+    -32768?short=-32768
+    2147483647?short=-1
+    2147483648?short=0
+    -2147483647?short=1
+    -2147483648?short=0
+    4294967295?short=-1
+    4294967296?short=0
+    -4294967295?short=1
+    -4294967296?short=0
+    2147483647.1?short=-1
+    2147483648.1?short=0
+    -2147483647.1?short=1
+    -2147483648.1?short=0
+    4294967295.1?short=-1
+    4294967296.1?short=0
+    -4294967295.1?short=1
+    -4294967296.1?short=0
+    2147483647.5?short=-1
+    2147483648.5?short=0
+    -2147483647.5?short=1
+    -2147483648.5?short=0
+    4294967295.5?short=-1
+    4294967296.5?short=0
+    -4294967295.5?short=1
+    -4294967296.5?short=0
+
+?floor
+    0?floor=0
+    1?floor=1
+    -1?floor=-1
+    0.5?floor=0
+    1.5?floor=1
+    -0.5?floor=-1
+    -1.5?floor=-2
+    0.25?floor=0
+    -0.25?floor=-1
+    1.75?floor=1
+    -1.75?floor=-2
+    1.01?floor=1
+    -1.01?floor=-2
+    0.01?floor=0
+    -0.01?floor=-1
+    127?floor=127
+    128?floor=128
+    -127?floor=-127
+    -128?floor=-128
+    32767?floor=32767
+    32768?floor=32768
+    -32767?floor=-32767
+    -32768?floor=-32768
+    2147483647?floor=2147483647
+    2147483648?floor=2147483648
+    -2147483647?floor=-2147483647
+    -2147483648?floor=-2147483648
+    4294967295?floor=4294967295
+    4294967296?floor=4294967296
+    -4294967295?floor=-4294967295
+    -4294967296?floor=-4294967296
+    2147483647.1?floor=2147483647
+    2147483648.1?floor=2147483648
+    -2147483647.1?floor=-2147483648
+    -2147483648.1?floor=-2147483649
+    4294967295.1?floor=4294967295
+    4294967296.1?floor=4294967296
+    -4294967295.1?floor=-4294967296
+    -4294967296.1?floor=-4294967297
+    2147483647.5?floor=2147483647
+    2147483648.5?floor=2147483648
+    -2147483647.5?floor=-2147483648
+    -2147483648.5?floor=-2147483649
+    4294967295.5?floor=4294967295
+    4294967296.5?floor=4294967296
+    -4294967295.5?floor=-4294967296
+    -4294967296.5?floor=-4294967297
+
+?ceiling
+    0?ceiling=0
+    1?ceiling=1
+    -1?ceiling=-1
+    0.5?ceiling=1
+    1.5?ceiling=2
+    -0.5?ceiling=0
+    -1.5?ceiling=-1
+    0.25?ceiling=1
+    -0.25?ceiling=0
+    1.75?ceiling=2
+    -1.75?ceiling=-1
+    1.01?ceiling=2
+    -1.01?ceiling=-1
+    0.01?ceiling=1
+    -0.01?ceiling=0
+    127?ceiling=127
+    128?ceiling=128
+    -127?ceiling=-127
+    -128?ceiling=-128
+    32767?ceiling=32767
+    32768?ceiling=32768
+    -32767?ceiling=-32767
+    -32768?ceiling=-32768
+    2147483647?ceiling=2147483647
+    2147483648?ceiling=2147483648
+    -2147483647?ceiling=-2147483647
+    -2147483648?ceiling=-2147483648
+    4294967295?ceiling=4294967295
+    4294967296?ceiling=4294967296
+    -4294967295?ceiling=-4294967295
+    -4294967296?ceiling=-4294967296
+    2147483647.1?ceiling=2147483648
+    2147483648.1?ceiling=2147483649
+    -2147483647.1?ceiling=-2147483647
+    -2147483648.1?ceiling=-2147483648
+    4294967295.1?ceiling=4294967296
+    4294967296.1?ceiling=4294967297
+    -4294967295.1?ceiling=-4294967295
+    -4294967296.1?ceiling=-4294967296
+    2147483647.5?ceiling=2147483648
+    2147483648.5?ceiling=2147483649
+    -2147483647.5?ceiling=-2147483647
+    -2147483648.5?ceiling=-2147483648
+    4294967295.5?ceiling=4294967296
+    4294967296.5?ceiling=4294967297
+    -4294967295.5?ceiling=-4294967295
+    -4294967296.5?ceiling=-4294967296
+
+?round
+    0?round=0
+    1?round=1
+    -1?round=-1
+    0.5?round=1
+    1.5?round=2
+    -0.5?round=0
+    -1.5?round=-1
+    0.25?round=0
+    -0.25?round=0
+    1.75?round=2
+    -1.75?round=-2
+    1.01?round=1
+    -1.01?round=-1
+    0.01?round=0
+    -0.01?round=0
+    127?round=127
+    128?round=128
+    -127?round=-127
+    -128?round=-128
+    32767?round=32767
+    32768?round=32768
+    -32767?round=-32767
+    -32768?round=-32768
+    2147483647?round=2147483647
+    2147483648?round=2147483648
+    -2147483647?round=-2147483647
+    -2147483648?round=-2147483648
+    4294967295?round=4294967295
+    4294967296?round=4294967296
+    -4294967295?round=-4294967295
+    -4294967296?round=-4294967296
+    2147483647.1?round=2147483647
+    2147483648.1?round=2147483648
+    -2147483647.1?round=-2147483647
+    -2147483648.1?round=-2147483648
+    4294967295.1?round=4294967295
+    4294967296.1?round=4294967296
+    -4294967295.1?round=-4294967295
+    -4294967296.1?round=-4294967296
+    2147483647.5?round=2147483648
+    2147483648.5?round=2147483649
+    -2147483647.5?round=-2147483647
+    -2147483648.5?round=-2147483648
+    4294967295.5?round=4294967296
+    4294967296.5?round=4294967297
+    -4294967295.5?round=-4294967295
+    -4294967296.5?round=-4294967296

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/output-encoding1.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/output-encoding1.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/output-encoding1.txt
new file mode 100644
index 0000000..3b5215a
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/output-encoding1.txt
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+Output charset: UTF-8
+URL escaping charset: undefined
+
+a%FE%FF%00%2F%00%25b
+a%FE%FF%00%2F%00%25b
+a%2F%25b
+a%2F%25b
+a%FE%FF%00%2F%00%25b
+a%2F%25b
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/output-encoding2.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/output-encoding2.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/output-encoding2.txt
new file mode 100644
index 0000000..6956b6c
Binary files /dev/null and b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/output-encoding2.txt differ

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/output-encoding3.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/output-encoding3.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/output-encoding3.txt
new file mode 100644
index 0000000..c0369f6
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/output-encoding3.txt
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+Output charset: ISO-8859-1
+URL escaping charset: UTF-16
+
+UTF-16: a%FE%FF%00%2F%00%25b
+ISO-8859-1: a%2F%25b
+UTF-16: a%FE%FF%00%2F%00%25b
+ISO-8859-1: a%2F%25b
+ISO-8859-1: a%2F%25b
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/precedence.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/precedence.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/precedence.txt
new file mode 100644
index 0000000..b19cb31
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/precedence.txt
@@ -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.
+ */
+<html>
+<head>
+<title>FreeMarker: Operator Precedence Test</title>
+</head>
+<body>
+
+@@@@@@@@@@@
+
+<br />
+<br />
+
+##########
+
+<br />
+<br />
+
+&&&&&&&&&&&
+
+<br />
+<br />
+
+!!!!!!!!!!!
+
+<br />
+<br />
+
+$$$$$$$$$$$
+
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/recover.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/recover.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/recover.txt
new file mode 100644
index 0000000..880cea3
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/recover.txt
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+ Hello, World
+ Well, that did not work.
+ Now we nest another attempt/recover here:
+   Oops...
+   Remember, freeMarker sequences are zero-based! Hello, World
+ Now we check the current error message.
+  The template is not currently available
+  The included template had a problem.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/root.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/root.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/root.txt
new file mode 100644
index 0000000..041222c
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/root.txt
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+<html>
+<head>
+<title>FreeMarker: Root Lookup Test</title>
+</head>
+<body>
+
+<p>A simple test follows:</p>
+
+<p>Hello, world!</p>
+
+<p>Access the same variable via the root variable (dot syntax):</p>
+
+<p>Hello, world!</p>
+
+<p>Access the same variable via the root variable (bracket syntax):</p>
+
+<p>Hello, world!</p>
+
+<p>Ensure that root lookups are unaffected by local variables:</p>
+
+
+  Hello, world!
+  Hello, world! Part Deux
+
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/sequence-builtins.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/sequence-builtins.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/sequence-builtins.txt
new file mode 100644
index 0000000..4f7796a
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/sequence-builtins.txt
@@ -0,0 +1,404 @@
+/*
+ * 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.
+ */
+Sorting scalars:
+----------------
+
+String order:
+- aardvark
+- Barbara
+- beetroot
+- whale
+- zeppelin
+
+First: aardvark
+Last: zeppelin
+Size 5
+
+Numerical order:
+- -324
+- -34
+- 0
+- 0.1
+- 0.11
+- 1
+- 5
+- 111
+- 123
+- 543
+
+First: -324
+Last: 543
+Size 10
+
+Date/time order:
+- 06:05
+- 08:05
+- 08:15
+- 18:00
+
+Boolean order:
+- false
+- false
+- true
+- true
+
+
+Sorting hashes:
+---------------
+
+Order by name:
+- aardvark: 30
+- Barbara: 53
+- beetroot: 0.3
+- whale: 2000
+- zeppelin: -200
+
+Order by weight:
+- zeppelin: -200
+- beetroot: 0.3
+- aardvark: 30
+- Barbara: 53
+- whale: 2000
+
+Order by a.x.v:
+- aqweqw
+- dfgdf
+- qweqw
+- utyu
+
+Order by a.y, which is a date:
+- 1998-02-20
+- 1999-01-20
+- 1999-04-19
+- 1999-04-20
+
+Reverse:
+--------
+
+Order by weight desc:
+- whale: 2000
+- Barbara: 53
+- aardvark: 30
+- beetroot: 0.3
+- zeppelin: -200
+
+Order by weight desc desc:
+- zeppelin: -200
+- beetroot: 0.3
+- aardvark: 30
+- Barbara: 53
+- whale: 2000
+
+Order by weight desc desc desc:
+- whale: 2000
+- Barbara: 53
+- aardvark: 30
+- beetroot: 0.3
+- zeppelin: -200
+
+Contains:
+---------
+
+True:
+true
+true
+true
+true
+true
+true
+true
+
+False:
+false
+false
+false
+false
+false
+false
+false
+
+False: false
+
+Index_of:
+---------
+
+0 = 0
+1 = 1
+2 = 2
+6 = 6
+0 = 0
+1 = 1
+2 = 2
+
+-1 = -1
+-1 = -1
+-1 = -1
+-1 = -1
+-1 = -1
+-1 = -1
+-1 = -1
+
+-1 = -1
+
+Last_index_of:
+--------------
+
+6 = 6
+1 = 1
+2 = 2
+7 = 7
+-1 = -1
+0 = 0
+1 = 1
+2 = 2
+-1 = -1
+
+Index_of and last_index_of with starting indices
+------------------------------------------------
+
+seq_index_of "Joe":
+0 = 0
+0 = 0
+0 = 0
+2 = 2
+2 = 2
+-1 = -1
+-1 = -1
+ 
+seq_last_index_of "Joe":
+-1 = -1
+-1 = -1
+0 = 0
+0 = 0
+2 = 2
+2 = 2
+2 = 2
+ 
+seq_index_of "Susan":
+3 = 3
+3 = 3
+3 = 3
+3 = 3
+3 = 3
+3 = 3
+-1 = -1
+ 
+seq_last_index_of "Susan":
+-1 = -1
+-1 = -1
+-1 = -1
+-1 = -1
+-1 = -1
+3 = 3
+3 = 3
+
+seq_index_of "a":
+0 = 0
+0 = 0
+0 = 0
+-1 = -1
+-1 = -1
+-1 = -1
+-1 = -1
+
+seq_index_of "b":
+1 = 1
+1 = 1
+1 = 1
+1 = 1
+-1 = -1
+-1 = -1
+
+seq_index_of "c":
+2 = 2
+2 = 2
+2 = 2
+2 = 2
+2 = 2
+-1 = -1
+ 
+seq_last_index_of "a":
+-1 = -1
+-1 = -1
+0 = 0
+0 = 0
+0 = 0
+0 = 0
+0 = 0
+
+seq_last_index_of "b":
+-1 = -1
+-1 = -1
+-1 = -1
+1 = 1
+1 = 1
+1 = 1
+
+seq_last_index_of "c":
+-1 = -1
+-1 = -1
+-1 = -1
+-1 = -1
+2 = 2
+2 = 2
+
+Sequence builtins ignoring nulls
+--------------------------------
+
+true = true
+2 = 2
+0 = 0
+
+These should throw exception, but for BC they don't:
+false = false
+-1 = -1
+-1 = -1
+
+Sequence built-ins failing on date-type mismatch
+------------------------------------------------
+
+
+Chunk
+-----
+
+columns = 1, fill = NULL:
+  Rows: 7
+    a   <-- Columns: 1
+    b   <-- Columns: 1
+    c   <-- Columns: 1
+    d   <-- Columns: 1
+    e   <-- Columns: 1
+    f   <-- Columns: 1
+    g   <-- Columns: 1
+  
+columns = 2, fill = NULL:
+  Rows: 4
+    a b   <-- Columns: 2
+    c d   <-- Columns: 2
+    e f   <-- Columns: 2
+    g   <-- Columns: 1
+  
+columns = 3, fill = NULL:
+  Rows: 3
+    a b c   <-- Columns: 3
+    d e f   <-- Columns: 3
+    g   <-- Columns: 1
+  
+columns = 4, fill = NULL:
+  Rows: 2
+    a b c d   <-- Columns: 4
+    e f g   <-- Columns: 3
+  
+columns = 5, fill = NULL:
+  Rows: 2
+    a b c d e   <-- Columns: 5
+    f g   <-- Columns: 2
+  
+columns = 10, fill = NULL:
+  Rows: 1
+    a b c d e f g   <-- Columns: 7
+  
+columns = 1, fill = -:
+  Rows: 7
+    a   <-- Columns: 1
+    b   <-- Columns: 1
+    c   <-- Columns: 1
+    d   <-- Columns: 1
+    e   <-- Columns: 1
+    f   <-- Columns: 1
+    g   <-- Columns: 1
+  
+columns = 2, fill = -:
+  Rows: 4
+    a b   <-- Columns: 2
+    c d   <-- Columns: 2
+    e f   <-- Columns: 2
+    g -   <-- Columns: 2
+  
+columns = 3, fill = -:
+  Rows: 3
+    a b c   <-- Columns: 3
+    d e f   <-- Columns: 3
+    g - -   <-- Columns: 3
+  
+columns = 4, fill = -:
+  Rows: 2
+    a b c d   <-- Columns: 4
+    e f g -   <-- Columns: 4
+  
+columns = 5, fill = -:
+  Rows: 2
+    a b c d e   <-- Columns: 5
+    f g - - -   <-- Columns: 5
+  
+columns = 10, fill = -:
+  Rows: 1
+    a b c d e f g - - -   <-- Columns: 10
+  
+columns = 3, fill = NULL:
+  Rows: 3
+    1 2 3   <-- Columns: 3
+    4 5 6   <-- Columns: 3
+    7 8 9   <-- Columns: 3
+  
+columns = 3, fill = -:
+  Rows: 3
+    1 2 3   <-- Columns: 3
+    4 5 6   <-- Columns: 3
+    7 8 9   <-- Columns: 3
+  
+columns = 3, fill = NULL:
+  Rows: 1
+    1   <-- Columns: 1
+  
+columns = 3, fill = -:
+  Rows: 1
+    1 - -   <-- Columns: 3
+  
+columns = 3, fill = NULL:
+  Rows: 0
+  
+columns = 3, fill = -:
+  Rows: 0
+  
+
+
+
+Join
+----
+
+- 1, two, three, 4
+- 
+- 1, two, three, 4.
+- (empty)
+- a, c
+- a, c
+- a, c.
+- 
+- (empty)
+- (empty)
+- a, b, c.
+- a, b, c.
+
+
+Misc
+----
+
+First of set 1: a
+First of set 2: a
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/specialvars.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/specialvars.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/specialvars.txt
new file mode 100644
index 0000000..e2fa13e
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/specialvars.txt
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+en == en
+en_US == en_US
+utf-8 == utf-8
+specialvars.ftl == specialvars.ftl
+iso-8859-1 == iso-8859-1
+x == x
+true == true
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/string-builtins-regexps-matches.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/string-builtins-regexps-matches.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/string-builtins-regexps-matches.txt
new file mode 100644
index 0000000..ba14e7f
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/string-builtins-regexps-matches.txt
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+List mode:
+Size: 4
+[L16][L27][L38][L49]
+[L16][L27][L38][L49]
+
+Iterator mode:
+[L16][L27][L38][L49]
+[L16(L16, L27, L38, L49)][L27(L16, L27, L38, L49)][L38(L16, L27, L38, L49)][L49(L16, L27, L38, L49)]
+[L16][L27][L38][L49]
+
+Iterator mode changes to list mode:
+[L16]/4[L27]/4[L38]/4[L49]/4
+[L16][L27][L38][L49]
+
+Iterator mode changes to list mode 2:
+[L16][L27][L38][L49]
+[L16]/4[L27]/4[L38]/4[L49]/4
+
+List mode with embedded iteration:
+[L16(L16, L27, L38, L49)][L27(L16, L27, L38, L49)][L38(L16, L27, L38, L49)][L49(L16, L27, L38, L49)]
+
+Entire input match:
+- M: L16
+    - G: L16
+    - G: 1
+    - G: 6
+- M: L27
+    - G: L27
+    - G: 2
+    - G: 7
+- M: L38
+    - G: L38
+    - G: 3
+    - G: 8
+- M: L49
+    - G: L49
+    - G: 4
+    - G: 9
+firstGS was: L16, 1, 6
+
+Entire input match 2:
+Matches: true
+- G: x12
+- G: 1
+- G: 2
+As list:
+- M: x12
+    - G: x12
+    - G: 1
+    - G: 2
+Groups again:
+- G: x12
+- G: 1
+- G: 2
+
+Entire input match 3:
+Matches: false
+
+Entire input match 4:
+Matches: true
+- G: x12
+- G: 1
+- G: 2
+
+Substring match nested into entire input match:
+- G: x12 ([x12{x12, 1, 2}])
+- G: 1 ([x12{x12, 1, 2}])
+- G: 2 ([x12{x12, 1, 2}])
+
+Different entire input and substring matches:
+123, 123
+- M: 1 (Gs: 1, 1)
+- M: 2 (Gs: 2, 2)
+- M: 3 (Gs: 3, 3)
+
+Different entire input and substring matches 2:
+123
+- M: 1 (Gs: 1)
+- M: 2 (Gs: 2)
+- M: 3 (Gs: 3)

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/string-builtins-regexps.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/string-builtins-regexps.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/string-builtins-regexps.txt
new file mode 100644
index 0000000..c54dc96
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/string-builtins-regexps.txt
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+true == true
+true == true
+
+false == false
+true == true
+
+false == false
+true == true
+
+false == false
+true == true
+
+false == false
+false == false
+false == false
+true == true
+true == true
+true == true
+
+false == false
+false == false
+true == true
+true == true
+true == true
+true == true
+
+
+Lower 'c'-words:
+- coverage
+- considered
+
+Any 'c'-words:
+- Code
+- coverage
+- considered
+
+Lower line-last words:
+- coverage
+
+Any line-last words:
+- coverage
+- BROKEN
+
+Any last words:
+- BROKEN
+
+c-word with follower:
+- "Code without"
+  Groups: "Code without", "Code", "without"
+- "coverage\nis"
+  Groups: "coverage\nis", "coverage", "is"
+- "considered to"
+  Groups: "considered to", "considered", "to"
+
+c-word with follower in the same line:
+- Code without
+- considered to
+
+Lower c-word with follower in the same line:
+- considered to
+
+  Ignored but logged in 2.3: False == False
+  Ignored but logged in 2.3: False == False
+
+FOObar == FOObar
+Foobar == Foobar
+FOObar == FOObar
+FOObarFOO == FOObarFOO
+FOObarfOO == FOObarfOO
+FOObarfOO == FOObarfOO
+Foobar == Foobar
+FOObar == FOObar
+FOObarFOO == FOObarFOO
+FOObarfOO == FOObarfOO
+FOObarfOO == FOObarfOO
+foobar == foobar
+foobar == foobar
+FOObar == FOObar
+FOObarFOO == FOObarFOO
+FOObarfOo == FOObarfOo
+FAlse == FAlse
+FAlse == FAlse
+
+  Ignored but logged in 2.3: FOObar
+
+[foo, barxbaaz] == [foo, barxbaaz]
+[foo, barxbaaz] == [foo, barxbaaz]
+[foo, bar, baaz] == [foo, bar, baaz]
+[foo, barxbaaz] == [foo, barxbaaz]
+[foo, bar, baaz] == [foo, bar, baaz]
+[fooXXbarxxbaaz] == [fooXXbarxxbaaz]
+[foo, bar, baaz] == [foo, bar, baaz]
+[F, ls] == [F, ls]
+[Fals, ] == [Fals, ]
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/string-builtins1.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/string-builtins1.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/string-builtins1.txt
new file mode 100644
index 0000000..6e689ac
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/string-builtins1.txt
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+FreeMarker: Encoding string built-in tests
+
+  
+cap_first:    DieBugsDie! * vazzZE 123456 --cdc-- --<<--@ x ${"kigyo"?upper_case}  
+uncap_first:  dieBugsDie! * vazzZE 123456 --cdc-- --<<--@ x ${"kigyo"?upper_case}  
+uncap_first:blah
+capitalize:   Diebugsdie! * Vazzze 123456 --cdc-- --<<--@ X ${"kigyo"?upper_case}  
+html:         dieBugsDie! * vazzZE 123456 --cdc-- --&lt;&lt;--@ x ${&quot;kigyo&quot;?upper_case}  
+length:     71
+lower_case:   diebugsdie! * vazzze 123456 --cdc-- --<<--@ x ${"kigyo"?upper_case}  
+rtf:          dieBugsDie! * vazzZE 123456 --cdc-- --<<--@ x $\{"kigyo"?upper_case\}  
+trim:       dieBugsDie! * vazzZE 123456 --cdc-- --<<--@ x ${"kigyo"?upper_case}
+trim2:      foo bar
+trim3:      foo bar
+trim4:      foo bar
+upper_case:   DIEBUGSDIE! * VAZZZE 123456 --CDC-- --<<--@ X ${"KIGYO"?UPPER_CASE}  
+xml:          dieBugsDie! * vazzZE 123456 --cdc-- --&lt;&lt;--@ x ${&quot;kigyo&quot;?upper_case}  
+xhtml:      &quot;Blah&#39;s is &gt; 1 &amp; &lt; 2&quot;
+
+word_list:
+- dieBugsDie!
+- *
+- vazzZE
+- 123456
+- --cdc--
+- --<<--@
+- x
+- ${"kigyo"?upper_case}
+
+interpret:   dieBugsDie! * vazzZE 123456 --cdc-- --<<--@ x KIGYO  
+number: -122,35
+1500
+5
+0
+0
+true
+true
+true
+true
+true
+
+default constructor
+1
+xxx
+xxx:yyy
+
+
+In The Sacred, Holy beginning, God created The Sacred, Holy Heavens and The Sacred, Holy Earth. 
+In the very beginning, God created the Heavens and The Earth. 
+|I|n| |t|h|e| |b|e|g|i|n|n|i|n|g|,| |G|o|d| |c|r|e|a|t|e|d| |t|h|e| |H|e|a|v|e|n|s| |a|n|d| |T|h|e| |E|a|r|t|h|.| 
+|In the beginning, God created the Heavens and The Earth. 
+
+In the beginning, God created the sky and The Earth. 
+
+matches
+
+  the beginning
+  the sacred beginning
+  the Heavens
+  the sacred Heavens
+  The Earth
+  The sacred Earth
+
+In the beginning, God created the Heavens and The Earth.
+beginning
+the Heavens and The Earth.
+
+   foo
+   bar
+   baz
+       foobar
+
+
+FOOBAR
+
+[a] = [a]
+[a\\'x'\nb] = [a\\'x'\nb]
+[\u0001\u001a ] = [\u0001\u001a ]
+
+[a] = [a]
+[a\\\'x\'\nb] = [a\\\'x\'\nb]
+[\x01\x1A ] = [\x01\x1A ]
+[\x3C![CDATA[] = [\x3C![CDATA[]
+[]]\>] = []]\>]
+
+[a] = [a]
+[a\\'x'\nb] = [a\\'x'\nb]
+[\u0001\u001A ] = [\u0001\u001A ]
+[\n\r\t\f\b\"] = [\n\r\t\f\b\"]
+[\/] = [\/]
+[a/b] = [a/b]
+[<\/script>] = [<\/script>]
+[\u003C![CDATA[] = [\u003C![CDATA[]
+[]]\u003E] = []]\u003E]

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/string-builtins2.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/string-builtins2.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/string-builtins2.txt
new file mode 100644
index 0000000..f5eebd9
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/string-builtins2.txt
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ */
+--
+1 = 1
+5 = 5
+0 = 0
+--
+5 = 5
+1 = 1
+7 = 7
+--
+true = true
+false = false
+true = true
+--
+true = true
+false = false
+true = true
+--
+true = true
+true = true
+true = true
+false = false
+true = true
+--
+[abbcdbb] = [abbcdbb]
+[qwe] = [qwe]
+[qwe] = [qwe]
+[qwe] = [qwe]
+[qwe
+] = [qwe
+]
+[qwe
+] = [qwe
+]
+--
+[abbcdbb] = [abbcdbb]
+[abb-dbb] = [abb-dbb]
+[a-=*cd-=*] = [a-=*cd-=*]
+--
+[a][][cd][][] == [a][][cd][][]
+[][die][maggots][!] == [][die][maggots][!]
+[Die maggots!] == [Die maggots!]
+--
+[     ]
+[    a]
+[   ab]
+[  abc]
+[ abcd]
+[abcde]
+[abcdef]
+[abcdefg]
+[abcdefgh]
+[-----]
+[----a]
+[---ab]
+[--abc]
+[-abcd]
+[abcde]
+[abcdef]
+[abcdefg]
+[abcdefgh]
+[.oO.oO.o]
+[.oO.oO.a]
+[.oO.oOab]
+[.oO.oabc]
+[.oO.abcd]
+[.oOabcde]
+[.oabcdef]
+[.abcdefg]
+[abcdefgh]
+[abcdefghi]
+[abcdefghij]
+[]
+[/]
+[/\]
+[/\_]
+[/\_/]
+[/\_/\]
+[/\_/\_]
+[/\_/\_/]
+--
+[     ]
+[a    ]
+[ab   ]
+[abc  ]
+[abcd ]
+[abcde]
+[abcdef]
+[abcdefg]
+[abcdefgh]
+[-----]
+[a----]
+[ab---]
+[abc--]
+[abcd-]
+[abcde]
+[abcdef]
+[abcdefg]
+[abcdefgh]
+[.oO.oO.o]
+[aoO.oO.o]
+[abO.oO.o]
+[abc.oO.o]
+[abcdoO.o]
+[abcdeO.o]
+[abcdef.o]
+[abcdefgo]
+[abcdefgh]
+[abcdefghi]
+[abcdefghij]
+[]
+[/]
+[/\]
+[/\_]
+[/\_/]
+[/\_/\]
+[/\_/\_]
+[/\_/\_/]
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/stringbimethods.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/stringbimethods.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/stringbimethods.txt
new file mode 100644
index 0000000..8ef415d
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/stringbimethods.txt
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+3.00
+3.00
+01:02:03.000
+01:02:03.000
+---
+de
+true false
+yes no
+igen nem
+0.0 1.0
+true true
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/stringliteral.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/stringliteral.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/stringliteral.txt
new file mode 100644
index 0000000..3d9d4c9
Binary files /dev/null and b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/stringliteral.txt differ

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/switch.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/switch.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/switch.txt
new file mode 100644
index 0000000..5d42785
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/switch.txt
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+<html>
+<head>
+<title>FreeMarker: Switch-Case Test</title>
+</head>
+<body>
+
+<p>Here we iterate over a list of animals.</p>
+
+<p>Animal is: aardvark.<br />
+        This is the HTML for other animals.
+</p>
+<p>Animal is: kiwi.<br />
+        This is the HTML for the user's favorite animal.
+</p>
+<p>Animal is: gecko.<br />
+        This is the HTML for small animals.
+</p>
+<p>Animal is: cat.<br />
+        This is the HTML for other animals.
+</p>
+<p>Animal is: dog.<br />
+        This is the HTML for other animals.
+</p>
+<p>Animal is: elephant.<br />
+        This is the HTML for large animals.
+</p>
+<p>Animal is: squirrel.<br />
+        This is the HTML for small animals.
+</p>
+<p>Animal is: zebra.<br />
+        This is the HTML for a large stripey animal.
+        This is the HTML for large animals.
+</p>
+
+      1
+          i2
+      2
+          i4
+          ft
+      ft
+      3
+          i4
+      3
+          i6
+
+[]
+
+  ""
+  "1234"
+  "234"
+  "34"
+  "4"
+
+  "12default45"
+  "2default45"
+  "default"
+  "45"
+  "5"
+
+
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/transforms.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/transforms.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/transforms.txt
new file mode 100644
index 0000000..6b7f986
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/transforms.txt
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+<html>
+<head>
+<title>FreeMarker: Transformation Test</title>
+</head>
+<body>
+
+<p>A simple test follows:</p>
+
+<p>Hello, world!</p>
+
+&lt;p&gt;Hello, world!&lt;/p&gt;
+
+<P>Now try the Utility package:</p>
+<p>Utility transformations</p>
+
+&lt;p&gt;Utility transformations&lt;/p&gt;
+
+<p>Now some nested transforms:</p>
+<p >This tests the compress transformation</p >&lt;p &gt;This tests the compress transformation&lt;/p &gt;&lt;p &gt;This tests the compress transformation&lt;/p &gt;
+<p>Now try method and transform interactions:</p>
+&lt;p&gt;This isn&apos;t a valid XML string.&lt;/p&gt;
+&lt;p&gt;This isn't a valid HTML string.&lt;/p&gt;
+
+<p>A more advanced interaction involves getting a TemplateMethodModel
+to initialise a TemplateTransformModel, as follow:</p>
+
+Comment: This is a comment
+
+A test string containing quotes: "This isn't a test".
+A test string containing amps: Fish & Chips.
+A test string containing tags: <p>Fish &amp; Chips.</p>
+
+Comment: This is a second comment
+
+A test string containing quotes: &quot;This isn&apos;t a test&quot;.
+A test string containing amps: Fish & Chips.
+A test string containing tags: <p>Fish &amp; Chips.</p>
+Comment: This is a third comment
+
+A test string containing quotes: &quot;This isn&apos;t a test&quot;.
+A test string containing amps: Fish &amp; Chips.
+A test string containing tags: <p>Fish &amp;amp; Chips.</p>
+Comment: Utility transformations
+
+A test string containing quotes: "This isn't a test".
+A test string containing amps: Fish & Chips.
+A test string containing tags: &lt;p&gt;Fish &amp; Chips.&lt;/p&gt;
+
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/type-builtins.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/type-builtins.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/type-builtins.txt
new file mode 100644
index 0000000..0b4e23a
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/type-builtins.txt
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+StNuBoMeTaMaHaHxSeCoCxEnInDiNo
+1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 1 0 0 0 0 0 0 0 0 1 0
+0 0 0 0 0 1 0 0 0 0 0 0 0 1 0
+0 0 0 0 0 0 1 1 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 1 0 0 1 1 0 0
+0 0 0 0 0 0 0 0 0 1 0 1 0 0 0
+0 0 0 0 0 0 0 0 0 1 1 1 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
+1 0 0 0 0 0 1 1 0 0 0 0 0 0 0
+0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 1 0 0 0 0 0 0 0 0 0 0 0

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/var-layers.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/var-layers.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/var-layers.txt
new file mode 100644
index 0000000..5fd6e2e
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/var-layers.txt
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+  1 = 1
+  2 = 2
+  3 = 3
+4 = 4 = 4
+5 = 5 = 5
+6 but 4 = 4
+7 = 7 = 7
+Invisiblity test 1.: passed
+Invisiblity test 2.: passed
+Invisiblity test 3.: passed
+--
+  1 = 1
+  2 = 2
+  3 = 3
+  4 = 4 = 4 = 4
+  5
+  6 == 6
+  7 == 7 == 7
+--

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/varargs.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/varargs.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/varargs.txt
new file mode 100644
index 0000000..a310855
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/varargs.txt
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+0 == 0
+0 == 0
+11 == 11
+11 == 11
+1122 == 1122
+1122 == 1122
+112233 == 112233
+112233 == 112233
+
+-22334411 == -22334411
+-223311 == -223311
+-2211 == -2211
+-11 == -11
+
+0 == 0
+-11 == -11
+1122 == 1122
+-112233 == -112233
+-11223344 == -11223344
+-1122334455 == -1122334455
+
+1122 == 1122
+-1122 == -1122
+
+string, true, 123, 1000000 == string, true, 123, 1000000

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/variables.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/variables.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/variables.txt
new file mode 100644
index 0000000..5365b07
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/variables.txt
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+<html>
+<head>
+<title>FreeMarker: Variable Test</title>
+</head>
+<body>
+
+<p>A simple test follows:</p>
+
+<p>Hello, world!</p>
+
+<p>Now get into variable nesting:</p>
+
+<p>My message.</p>
+<p>My message.</p>
+<p>My message.</p>
+<p>My message.</p>
+<p>My message.</p>
+<p>My message.</p>
+<p>My message.</p>
+<p>My message.</p>
+
+<p>More deep nesting...</p>
+
+<p>My message.</p>
+<p>one</p>
+<p>one</p>
+
+
+<p>Nesting inside nesting...</p>
+
+<p>two</p>
+<p>two</p>
+<p>two</p>
+<p>two</p>
+
+<p>Test underscores...</p>
+
+<p>out</p>
+<p>out</p>
+
+SAVE
+
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/whitespace-trim.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/whitespace-trim.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/whitespace-trim.txt
new file mode 100644
index 0000000..e74163a
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/whitespace-trim.txt
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+LB
+LB
+LB
+LB
+  IB
+  IC1  IC2C1C2  ICS CS1 CS2 C3C1C2
+B
+B
+C1CB
+C1
+C2  ICB
+  IC  ICB
+  ICCB
+--
+LB
+LB
+LB
+LB
+  IB
+  IC1  IC2C1C2  ICS CS1 CS2 C3C1C2
+B
+B
+C1CB
+C1
+C2  ICB
+  IC  ICB
+  ICCB
+--
+  IB
+  IC1C2  IB
+12
+---
+1 23
+  4
+  5  6
+---
+a
+bc
+---
+foo
+---
+foo

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/wstrip-in-header.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/wstrip-in-header.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/wstrip-in-header.txt
new file mode 100644
index 0000000..2cb2913
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/wstrip-in-header.txt
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+a
+
+b
+a
+b
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/wstripping.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/wstripping.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/wstripping.txt
new file mode 100644
index 0000000..2aae297
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/wstripping.txt
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+a
+b
+c 
+d
+e2
+f
+g
+x
+  x
+    x
+  y
+y
+x
+y
+x
+y
+a
+  x
+b
+  x
+c
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/xml-fragment.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/xml-fragment.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/xml-fragment.txt
new file mode 100644
index 0000000..cb0da5f
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/xml-fragment.txt
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+b = b
+@document = @document
+@document = @document
+
+C<>&"']]> = C<>&"']]>
+
+<root xmlns:n="http://x"><a><b><n:c>C&lt;>&amp;"']]&gt;</n:c></b></a></root>
\ No newline at end of file



[48/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/ConfigurationTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/ConfigurationTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ConfigurationTest.java
new file mode 100644
index 0000000..dcefa3f
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ConfigurationTest.java
@@ -0,0 +1,1486 @@
+/*
+ * 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.apache.freemarker.test.hamcerst.Matchers.*;
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.io.StringWriter;
+import java.lang.reflect.Field;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.TimeZone;
+
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateScalarModel;
+import org.apache.freemarker.core.model.impl.DefaultObjectWrapper;
+import org.apache.freemarker.core.model.impl.RestrictedObjectWrapper;
+import org.apache.freemarker.core.model.impl.SimpleScalar;
+import org.apache.freemarker.core.outputformat.MarkupOutputFormat;
+import org.apache.freemarker.core.outputformat.OutputFormat;
+import org.apache.freemarker.core.outputformat.UnregisteredOutputFormatException;
+import org.apache.freemarker.core.outputformat.impl.CombinedMarkupOutputFormat;
+import org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat;
+import org.apache.freemarker.core.outputformat.impl.RTFOutputFormat;
+import org.apache.freemarker.core.outputformat.impl.UndefinedOutputFormat;
+import org.apache.freemarker.core.outputformat.impl.XMLOutputFormat;
+import org.apache.freemarker.core.templateresolver.CacheStorageWithGetSize;
+import org.apache.freemarker.core.templateresolver.ConditionalTemplateConfigurationFactory;
+import org.apache.freemarker.core.templateresolver.FileNameGlobMatcher;
+import org.apache.freemarker.core.templateresolver.TemplateLookupContext;
+import org.apache.freemarker.core.templateresolver.TemplateLookupResult;
+import org.apache.freemarker.core.templateresolver.TemplateLookupStrategy;
+import org.apache.freemarker.core.templateresolver.impl.ByteArrayTemplateLoader;
+import org.apache.freemarker.core.templateresolver.impl.ClassTemplateLoader;
+import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateLookupStrategy;
+import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormat;
+import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormatFM2;
+import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateResolver;
+import org.apache.freemarker.core.templateresolver.impl.NullCacheStorage;
+import org.apache.freemarker.core.templateresolver.impl.SoftCacheStorage;
+import org.apache.freemarker.core.templateresolver.impl.StringTemplateLoader;
+import org.apache.freemarker.core.templateresolver.impl.StrongCacheStorage;
+import org.apache.freemarker.core.userpkg.BaseNTemplateNumberFormatFactory;
+import org.apache.freemarker.core.userpkg.CustomHTMLOutputFormat;
+import org.apache.freemarker.core.userpkg.DummyOutputFormat;
+import org.apache.freemarker.core.userpkg.EpochMillisDivTemplateDateFormatFactory;
+import org.apache.freemarker.core.userpkg.EpochMillisTemplateDateFormatFactory;
+import org.apache.freemarker.core.userpkg.HexTemplateNumberFormatFactory;
+import org.apache.freemarker.core.util._DateUtil;
+import org.apache.freemarker.core.util._NullArgumentException;
+import org.apache.freemarker.core.util._NullWriter;
+import org.apache.freemarker.core.util._StringUtil;
+import org.apache.freemarker.core.valueformat.TemplateDateFormatFactory;
+import org.apache.freemarker.core.valueformat.TemplateNumberFormatFactory;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import junit.framework.TestCase;
+
+public class ConfigurationTest extends TestCase {
+
+    private static final Charset ISO_8859_2 = Charset.forName("ISO-8859-2");
+
+    public ConfigurationTest(String name) {
+        super(name);
+    }
+
+    public void testUnsetAndIsSet() throws Exception {
+        Configuration.ExtendableBuilder<?> cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
+        
+        assertFalse(cfgB.isLogTemplateExceptionsSet());
+        assertFalse(cfgB.getLogTemplateExceptions());
+        //
+        cfgB.setLogTemplateExceptions(true);
+        {
+            Configuration cfg = cfgB.build();
+            assertTrue(cfgB.isLogTemplateExceptionsSet());
+            assertTrue(cfg.isLogTemplateExceptionsSet());
+            assertTrue(cfgB.getLogTemplateExceptions());
+            assertTrue(cfg.getLogTemplateExceptions());
+        }
+        //
+        for (int i = 0; i < 2; i++) {
+            cfgB.unsetLogTemplateExceptions();
+            Configuration cfg = cfgB.build();
+            assertFalse(cfgB.isLogTemplateExceptionsSet());
+            assertTrue(cfg.isLogTemplateExceptionsSet());
+            assertFalse(cfgB.getLogTemplateExceptions());
+            assertFalse(cfg.getLogTemplateExceptions());
+        }
+
+        DefaultObjectWrapper dow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
+        assertFalse(cfgB.isObjectWrapperSet());
+        assertSame(dow, cfgB.getObjectWrapper());
+        //
+        RestrictedObjectWrapper ow = new RestrictedObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
+        cfgB.setObjectWrapper(ow);
+        assertTrue(cfgB.isObjectWrapperSet());
+        assertSame(ow, cfgB.getObjectWrapper());
+        //
+        for (int i = 0; i < 2; i++) {
+            cfgB.unsetObjectWrapper();
+            assertFalse(cfgB.isObjectWrapperSet());
+            assertSame(dow, cfgB.getObjectWrapper());
+        }
+        
+        assertFalse(cfgB.isTemplateExceptionHandlerSet());
+        assertSame(TemplateExceptionHandler.DEBUG_HANDLER, cfgB.getTemplateExceptionHandler());
+        //
+        cfgB.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
+        assertTrue(cfgB.isTemplateExceptionHandlerSet());
+        assertSame(TemplateExceptionHandler.RETHROW_HANDLER, cfgB.getTemplateExceptionHandler());
+        //
+        for (int i = 0; i < 2; i++) {
+            cfgB.unsetTemplateExceptionHandler();
+            assertFalse(cfgB.isTemplateExceptionHandlerSet());
+            assertSame(TemplateExceptionHandler.DEBUG_HANDLER, cfgB.getTemplateExceptionHandler());
+        }
+        
+        assertFalse(cfgB.isTemplateLoaderSet());
+        assertNull(cfgB.getTemplateLoader());
+        //
+        cfgB.setTemplateLoader(null);
+        assertTrue(cfgB.isTemplateLoaderSet());
+        assertNull(cfgB.getTemplateLoader());
+        //
+        for (int i = 0; i < 3; i++) {
+            if (i == 2) {
+                cfgB.setTemplateLoader(new StringTemplateLoader());
+            }
+            cfgB.unsetTemplateLoader();
+            assertFalse(cfgB.isTemplateLoaderSet());
+            assertNull(cfgB.getTemplateLoader());
+        }
+        
+        assertFalse(cfgB.isTemplateLookupStrategySet());
+        assertSame(DefaultTemplateLookupStrategy.INSTANCE, cfgB.getTemplateLookupStrategy());
+        //
+        cfgB.setTemplateLookupStrategy(DefaultTemplateLookupStrategy.INSTANCE);
+        assertTrue(cfgB.isTemplateLookupStrategySet());
+        //
+        for (int i = 0; i < 2; i++) {
+            cfgB.unsetTemplateLookupStrategy();
+            assertFalse(cfgB.isTemplateLookupStrategySet());
+        }
+        
+        assertFalse(cfgB.isTemplateNameFormatSet());
+        assertSame(DefaultTemplateNameFormatFM2.INSTANCE, cfgB.getTemplateNameFormat());
+        //
+        cfgB.setTemplateNameFormat(DefaultTemplateNameFormat.INSTANCE);
+        assertTrue(cfgB.isTemplateNameFormatSet());
+        assertSame(DefaultTemplateNameFormat.INSTANCE, cfgB.getTemplateNameFormat());
+        //
+        for (int i = 0; i < 2; i++) {
+            cfgB.unsetTemplateNameFormat();
+            assertFalse(cfgB.isTemplateNameFormatSet());
+            assertSame(DefaultTemplateNameFormatFM2.INSTANCE, cfgB.getTemplateNameFormat());
+        }
+        
+        assertFalse(cfgB.isCacheStorageSet());
+        assertTrue(cfgB.getCacheStorage() instanceof SoftCacheStorage);
+        //
+        cfgB.setCacheStorage(NullCacheStorage.INSTANCE);
+        assertTrue(cfgB.isCacheStorageSet());
+        assertSame(NullCacheStorage.INSTANCE, cfgB.getCacheStorage());
+        //
+        for (int i = 0; i < 3; i++) {
+            if (i == 2) {
+                cfgB.setCacheStorage(cfgB.getCacheStorage());
+            }
+            cfgB.unsetCacheStorage();
+            assertFalse(cfgB.isCacheStorageSet());
+            assertTrue(cfgB.getCacheStorage() instanceof SoftCacheStorage);
+        }
+    }
+    
+    public void testTemplateLoadingErrors() throws Exception {
+        Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0)
+                .templateLoader(new ClassTemplateLoader(getClass(), "nosuchpackage"))
+                .build();
+        try {
+            cfg.getTemplate("missing.ftl");
+            fail();
+        } catch (TemplateNotFoundException e) {
+            assertThat(e.getMessage(), not(containsString("wasn't set")));
+        }
+    }
+    
+    public void testVersion() {
+        Version v = Configuration.getVersion();
+        assertTrue(v.intValue() >= _CoreAPI.VERSION_INT_3_0_0);
+        
+        try {
+            new Configuration.Builder(new Version(999, 1, 2));
+        } catch (IllegalArgumentException e) {
+            assertThat(e.getMessage(), containsString("upgrade"));
+        }
+        
+        try {
+            new Configuration.Builder(new Version(2, 3, 0));
+        } catch (IllegalArgumentException e) {
+            assertThat(e.getMessage(), containsString("3.0.0"));
+        }
+    }
+    
+    public void testShowErrorTips() throws Exception {
+        try {
+            Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0).build();
+            new Template(null, "${x}", cfg).process(null, _NullWriter.INSTANCE);
+            fail();
+        } catch (TemplateException e) {
+            assertThat(e.getMessage(), containsString("Tip:"));
+        }
+
+        try {
+            Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0).showErrorTips(false).build();
+            new Template(null, "${x}", cfg).process(null, _NullWriter.INSTANCE);
+            fail();
+        } catch (TemplateException e) {
+            assertThat(e.getMessage(), not(containsString("Tip:")));
+        }
+    }
+    
+    @Test
+    @SuppressWarnings("boxing")
+    public void testGetTemplateOverloads() throws Exception {
+        final Locale hu = new Locale("hu", "HU");
+        final String tFtl = "t.ftl";
+        final String tHuFtl = "t_hu.ftl";
+        final String tEnFtl = "t_en.ftl";
+        final String tUtf8Ftl = "utf8.ftl";
+        final Serializable custLookupCond = 12345;
+
+        ByteArrayTemplateLoader tl = new ByteArrayTemplateLoader();
+        tl.putTemplate(tFtl, "${1}".getBytes(StandardCharsets.UTF_8));
+        tl.putTemplate(tEnFtl, "${1}".getBytes(StandardCharsets.UTF_8));
+        tl.putTemplate(tHuFtl, "${1}".getBytes(StandardCharsets.UTF_8));
+        tl.putTemplate(tUtf8Ftl, "<#ftl encoding='utf-8'>".getBytes(StandardCharsets.UTF_8));
+
+        Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0)
+                .locale(Locale.GERMAN)
+                .sourceEncoding(StandardCharsets.ISO_8859_1)
+                .templateLoader(tl)
+                .templateConfigurations(
+                        new ConditionalTemplateConfigurationFactory(
+                                new FileNameGlobMatcher("*_hu.*"),
+                                new TemplateConfiguration.Builder().sourceEncoding(ISO_8859_2).build()))
+                .build();
+
+        // 1 args:
+        {
+            Template t = cfg.getTemplate(tFtl);
+            assertEquals(tFtl, t.getLookupName());
+            assertEquals(tFtl, t.getSourceName());
+            assertEquals(Locale.GERMAN, t.getLocale());
+            assertNull(t.getCustomLookupCondition());
+            assertEquals(StandardCharsets.ISO_8859_1, t.getActualSourceEncoding());
+        }
+        {
+            Template t = cfg.getTemplate(tUtf8Ftl);
+            assertEquals(tUtf8Ftl, t.getLookupName());
+            assertEquals(tUtf8Ftl, t.getSourceName());
+            assertEquals(Locale.GERMAN, t.getLocale());
+            assertNull(t.getCustomLookupCondition());
+            assertEquals(StandardCharsets.UTF_8, t.getActualSourceEncoding());
+        }
+        
+        // 2 args:
+        {
+            Template t = cfg.getTemplate(tFtl, Locale.GERMAN);
+            assertEquals(tFtl, t.getLookupName());
+            assertEquals(tFtl, t.getSourceName());
+            assertEquals(Locale.GERMAN, t.getLocale());
+            assertNull(t.getCustomLookupCondition());
+            assertEquals(StandardCharsets.ISO_8859_1, t.getActualSourceEncoding());
+        }
+        {
+            Template t = cfg.getTemplate(tFtl, (Locale) null);
+            assertEquals(tFtl, t.getLookupName());
+            assertEquals(tFtl, t.getSourceName());
+            assertEquals(Locale.GERMAN, t.getLocale());
+            assertNull(t.getCustomLookupCondition());
+            assertEquals(StandardCharsets.ISO_8859_1, t.getActualSourceEncoding());
+        }
+        {
+            Template t = cfg.getTemplate(tFtl, Locale.US);
+            assertEquals(tFtl, t.getLookupName());
+            assertEquals(tEnFtl, t.getSourceName());
+            assertEquals(Locale.US, t.getLocale());
+            assertNull(t.getCustomLookupCondition());
+            assertEquals(StandardCharsets.ISO_8859_1, t.getActualSourceEncoding());
+        }
+        {
+            Template t = cfg.getTemplate(tUtf8Ftl, Locale.US);
+            assertEquals(tUtf8Ftl, t.getLookupName());
+            assertEquals(tUtf8Ftl, t.getSourceName());
+            assertEquals(Locale.US, t.getLocale());
+            assertNull(t.getCustomLookupCondition());
+            assertEquals(StandardCharsets.UTF_8, t.getActualSourceEncoding());
+        }
+        {
+            Template t = cfg.getTemplate(tFtl, hu);
+            assertEquals(tFtl, t.getLookupName());
+            assertEquals(tHuFtl, t.getSourceName());
+            assertEquals(hu, t.getLocale());
+            assertNull(t.getCustomLookupCondition());
+            assertEquals(ISO_8859_2, t.getActualSourceEncoding());
+        }
+        {
+            Template t = cfg.getTemplate(tUtf8Ftl, hu);
+            assertEquals(tUtf8Ftl, t.getLookupName());
+            assertEquals(tUtf8Ftl, t.getSourceName());
+            assertEquals(hu, t.getLocale());
+            assertNull(t.getCustomLookupCondition());
+            assertEquals(StandardCharsets.UTF_8, t.getActualSourceEncoding());
+        }
+
+        // 4 args:
+        try {
+            cfg.getTemplate("missing.ftl", hu, custLookupCond, false);
+            fail();
+        } catch (TemplateNotFoundException e) {
+            // Expected
+        }
+        assertNull(cfg.getTemplate("missing.ftl", hu, custLookupCond, true));
+        {
+            Template t = cfg.getTemplate(tFtl, hu, custLookupCond, false);
+            assertEquals(tFtl, t.getLookupName());
+            assertEquals(tHuFtl, t.getSourceName());
+            assertEquals(hu, t.getLocale());
+            assertEquals(custLookupCond, t.getCustomLookupCondition());
+            assertEquals(ISO_8859_2, t.getActualSourceEncoding());
+            assertOutputEquals("1", t);
+        }
+        {
+            Template t = cfg.getTemplate(tFtl, null, custLookupCond, false);
+            assertEquals(tFtl, t.getLookupName());
+            assertEquals(tFtl, t.getSourceName());
+            assertEquals(Locale.GERMAN, t.getLocale());
+            assertEquals(custLookupCond, t.getCustomLookupCondition());
+            assertEquals(StandardCharsets.ISO_8859_1, t.getActualSourceEncoding());
+            assertOutputEquals("1", t);
+        }
+    }
+
+    private void assertOutputEquals(final String expectedContent, final Template t) throws ConfigurationException,
+            IOException, TemplateException {
+        StringWriter sw = new StringWriter();
+        t.process(null, sw);
+        assertEquals(expectedContent, sw.toString());
+    }
+    
+    public void testTemplateResolverCache() throws Exception {
+        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
+        
+        CacheStorageWithGetSize cache = (CacheStorageWithGetSize) cfgB.getCacheStorage();
+        assertEquals(0, cache.getSize());
+        cfgB.setCacheStorage(new StrongCacheStorage());
+        cache = (CacheStorageWithGetSize) cfgB.getCacheStorage();
+        assertEquals(0, cache.getSize());
+        cfgB.setTemplateLoader(new ClassTemplateLoader(ConfigurationTest.class, ""));
+        Configuration cfg = cfgB.build();
+        assertEquals(0, cache.getSize());
+        cfg.getTemplate("toCache1.ftl");
+        assertEquals(1, cache.getSize());
+        cfg.getTemplate("toCache2.ftl");
+        assertEquals(2, cache.getSize());
+        cfg.clearTemplateCache();
+        assertEquals(0, cache.getSize());
+        cfg.getTemplate("toCache1.ftl");
+        assertEquals(1, cache.getSize());
+        cfgB.setTemplateLoader(cfgB.getTemplateLoader());
+        assertEquals(1, cache.getSize());
+    }
+
+    public void testTemplateNameFormat() throws Exception {
+        StringTemplateLoader tl = new StringTemplateLoader();
+        tl.putTemplate("a/b.ftl", "In a/b.ftl");
+        tl.putTemplate("b.ftl", "In b.ftl");
+
+        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0)
+                .templateLoader(tl);
+
+        {
+            cfgB.setTemplateNameFormat(DefaultTemplateNameFormatFM2.INSTANCE);
+            final Template template = cfgB.build().getTemplate("a/./../b.ftl");
+            assertEquals("a/b.ftl", template.getLookupName());
+            assertEquals("a/b.ftl", template.getSourceName());
+            assertEquals("In a/b.ftl", template.toString());
+        }
+        
+        {
+            cfgB.setTemplateNameFormat(DefaultTemplateNameFormat.INSTANCE);
+            final Template template = cfgB.build().getTemplate("a/./../b.ftl");
+            assertEquals("b.ftl", template.getLookupName());
+            assertEquals("b.ftl", template.getSourceName());
+            assertEquals("In b.ftl", template.toString());
+        }
+    }
+
+    public void testTemplateNameFormatSetSetting() throws Exception {
+        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
+        assertSame(DefaultTemplateNameFormatFM2.INSTANCE, cfgB.getTemplateNameFormat());
+        cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_NAME_FORMAT_KEY, "defAult_2_4_0");
+        assertSame(DefaultTemplateNameFormat.INSTANCE, cfgB.getTemplateNameFormat());
+        cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_NAME_FORMAT_KEY, "defaUlt_2_3_0");
+        assertSame(DefaultTemplateNameFormatFM2.INSTANCE, cfgB.getTemplateNameFormat());
+        assertTrue(cfgB.isTemplateNameFormatSet());
+        cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_NAME_FORMAT_KEY, "defauLt");
+        assertFalse(cfgB.isTemplateNameFormatSet());
+    }
+
+    public void testObjectWrapperSetSetting() throws Exception {
+        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
+        {
+            cfgB.setSetting(MutableProcessingConfiguration.OBJECT_WRAPPER_KEY, "defAult");
+            DefaultObjectWrapper dow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
+            assertSame(dow, cfgB.getObjectWrapper());
+            assertEquals(Configuration.VERSION_3_0_0, dow.getIncompatibleImprovements());
+        }
+        
+        {
+            cfgB.setSetting(MutableProcessingConfiguration.OBJECT_WRAPPER_KEY, "restricted");
+            assertThat(cfgB.getObjectWrapper(), instanceOf(RestrictedObjectWrapper.class));
+        }
+    }
+    
+    public void testTemplateLookupStrategyDefaultAndSet() throws Exception {
+        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
+        assertSame(DefaultTemplateLookupStrategy.INSTANCE, cfgB.getTemplateLookupStrategy());
+        assertSame(DefaultTemplateLookupStrategy.INSTANCE, cfgB.build().getTemplateLookupStrategy());
+
+        cfgB.setTemplateLoader(new ClassTemplateLoader(ConfigurationTest.class, ""));
+        assertSame(DefaultTemplateLookupStrategy.INSTANCE, cfgB.getTemplateLookupStrategy());
+        Configuration cfg = cfgB.build();
+        assertSame(DefaultTemplateLookupStrategy.INSTANCE, cfg.getTemplateLookupStrategy());
+        cfg.getTemplate("toCache1.ftl");
+
+        final TemplateLookupStrategy myStrategy = new TemplateLookupStrategy() {
+            @Override
+            public TemplateLookupResult lookup(TemplateLookupContext ctx) throws IOException {
+                return ctx.lookupWithAcquisitionStrategy("toCache2.ftl");
+            }
+        };
+        cfgB.setTemplateLookupStrategy(myStrategy);
+        assertSame(myStrategy, cfgB.getTemplateLookupStrategy());
+        cfg = cfgB.build();
+        cfg.clearTemplateCache();
+        assertSame(myStrategy, cfg.getTemplateLookupStrategy());
+        Template template = cfg.getTemplate("toCache1.ftl");
+        assertEquals("toCache2.ftl", template.getSourceName());
+    }
+    
+    public void testSetTemplateConfigurations() throws Exception {
+        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
+        assertNull(cfgB.getTemplateConfigurations());
+
+        StringTemplateLoader tl = new StringTemplateLoader();
+        tl.putTemplate("t.de.ftlh", "");
+        tl.putTemplate("t.fr.ftlx", "");
+        tl.putTemplate("t.ftlx", "");
+        tl.putTemplate("Stat/t.de.ftlx", "");
+        cfgB.setTemplateLoader(tl);
+        
+        cfgB.setTimeZone(TimeZone.getTimeZone("GMT+09"));
+        
+        cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_CONFIGURATIONS_KEY,
+                "MergingTemplateConfigurationFactory("
+                    + "FirstMatchTemplateConfigurationFactory("
+                        + "ConditionalTemplateConfigurationFactory("
+                            + "FileNameGlobMatcher('*.de.*'), TemplateConfiguration(timeZone=TimeZone('GMT+01'))), "
+                        + "ConditionalTemplateConfigurationFactory("
+                            + "FileNameGlobMatcher('*.fr.*'), TemplateConfiguration(timeZone=TimeZone('GMT'))), "
+                        + "allowNoMatch=true"
+                    + "), "
+                    + "FirstMatchTemplateConfigurationFactory("
+                        + "ConditionalTemplateConfigurationFactory("
+                            + "FileExtensionMatcher('ftlh'), TemplateConfiguration(booleanFormat='TODO,HTML')), "
+                        + "ConditionalTemplateConfigurationFactory("
+                            + "FileExtensionMatcher('ftlx'), TemplateConfiguration(booleanFormat='TODO,XML')), "
+                        + "noMatchErrorDetails='Unrecognized template file extension'"
+                    + "), "
+                    + "ConditionalTemplateConfigurationFactory("
+                        + "PathGlobMatcher('stat/**', caseInsensitive=true), "
+                        + "TemplateConfiguration(timeZone=TimeZone('UTC'))"
+                    + ")"
+                + ")");
+
+        Configuration cfg = cfgB.build();
+        {
+            Template t = cfg.getTemplate("t.de.ftlh");
+            assertEquals("TODO,HTML", t.getBooleanFormat());
+            assertEquals(TimeZone.getTimeZone("GMT+01"), t.getTimeZone());
+        }
+        {
+            Template t = cfg.getTemplate("t.fr.ftlx");
+            assertEquals("TODO,XML", t.getBooleanFormat());
+            assertEquals(TimeZone.getTimeZone("GMT"), t.getTimeZone());
+        }
+        {
+            Template t = cfg.getTemplate("t.ftlx");
+            assertEquals("TODO,XML", t.getBooleanFormat());
+            assertEquals(TimeZone.getTimeZone("GMT+09"), t.getTimeZone());
+        }
+        {
+            Template t = cfg.getTemplate("Stat/t.de.ftlx");
+            assertEquals("TODO,XML", t.getBooleanFormat());
+            assertEquals(_DateUtil.UTC, t.getTimeZone());
+        }
+        
+        assertNotNull(cfgB.getTemplateConfigurations());
+        cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_CONFIGURATIONS_KEY, "null");
+        assertNull(cfgB.getTemplateConfigurations());
+    }
+
+    public void testSetAutoEscaping() throws Exception {
+       Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
+    
+       assertEquals(ParsingConfiguration.ENABLE_IF_DEFAULT_AUTO_ESCAPING_POLICY, cfgB.getAutoEscapingPolicy());
+
+       cfgB.setAutoEscapingPolicy(ParsingConfiguration.ENABLE_IF_SUPPORTED_AUTO_ESCAPING_POLICY);
+       assertEquals(ParsingConfiguration.ENABLE_IF_SUPPORTED_AUTO_ESCAPING_POLICY, cfgB.getAutoEscapingPolicy());
+
+       cfgB.setAutoEscapingPolicy(ParsingConfiguration.ENABLE_IF_DEFAULT_AUTO_ESCAPING_POLICY);
+       assertEquals(ParsingConfiguration.ENABLE_IF_DEFAULT_AUTO_ESCAPING_POLICY, cfgB.getAutoEscapingPolicy());
+
+       cfgB.setAutoEscapingPolicy(ParsingConfiguration.DISABLE_AUTO_ESCAPING_POLICY);
+       assertEquals(ParsingConfiguration.DISABLE_AUTO_ESCAPING_POLICY, cfgB.getAutoEscapingPolicy());
+       
+       cfgB.setSetting(Configuration.ExtendableBuilder.AUTO_ESCAPING_POLICY_KEY_CAMEL_CASE, "enableIfSupported");
+       assertEquals(ParsingConfiguration.ENABLE_IF_SUPPORTED_AUTO_ESCAPING_POLICY, cfgB.getAutoEscapingPolicy());
+
+       cfgB.setSetting(Configuration.ExtendableBuilder.AUTO_ESCAPING_POLICY_KEY_CAMEL_CASE, "enable_if_supported");
+       assertEquals(ParsingConfiguration.ENABLE_IF_SUPPORTED_AUTO_ESCAPING_POLICY, cfgB.getAutoEscapingPolicy());
+       
+       cfgB.setSetting(Configuration.ExtendableBuilder.AUTO_ESCAPING_POLICY_KEY_CAMEL_CASE, "enableIfDefault");
+       assertEquals(ParsingConfiguration.ENABLE_IF_DEFAULT_AUTO_ESCAPING_POLICY, cfgB.getAutoEscapingPolicy());
+
+       cfgB.setSetting(Configuration.ExtendableBuilder.AUTO_ESCAPING_POLICY_KEY_CAMEL_CASE, "enable_if_default");
+       assertEquals(ParsingConfiguration.ENABLE_IF_DEFAULT_AUTO_ESCAPING_POLICY, cfgB.getAutoEscapingPolicy());
+       
+       cfgB.setSetting(Configuration.ExtendableBuilder.AUTO_ESCAPING_POLICY_KEY_CAMEL_CASE, "disable");
+       assertEquals(ParsingConfiguration.DISABLE_AUTO_ESCAPING_POLICY, cfgB.getAutoEscapingPolicy());
+       
+       try {
+           cfgB.setAutoEscapingPolicy(ParsingConfiguration.CAMEL_CASE_NAMING_CONVENTION);
+           fail();
+       } catch (IllegalArgumentException e) {
+           // Expected
+       }
+    }
+
+    public void testSetOutputFormat() throws Exception {
+       Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
+       
+       assertEquals(UndefinedOutputFormat.INSTANCE, cfgB.getOutputFormat());
+       assertFalse(cfgB.isOutputFormatSet());
+       
+       try {
+           cfgB.setOutputFormat(null);
+           fail();
+       } catch (_NullArgumentException e) {
+           // Expected
+       }
+       
+       assertFalse(cfgB.isOutputFormatSet());
+       
+       cfgB.setSetting(Configuration.ExtendableBuilder.OUTPUT_FORMAT_KEY_CAMEL_CASE, XMLOutputFormat.class.getSimpleName());
+       assertEquals(XMLOutputFormat.INSTANCE, cfgB.getOutputFormat());
+       
+       cfgB.setSetting(Configuration.ExtendableBuilder.OUTPUT_FORMAT_KEY_SNAKE_CASE, HTMLOutputFormat.class.getSimpleName());
+       assertEquals(HTMLOutputFormat.INSTANCE, cfgB.getOutputFormat());
+       
+       cfgB.unsetOutputFormat();
+       assertEquals(UndefinedOutputFormat.INSTANCE, cfgB.getOutputFormat());
+       assertFalse(cfgB.isOutputFormatSet());
+       
+       cfgB.setOutputFormat(UndefinedOutputFormat.INSTANCE);
+       assertTrue(cfgB.isOutputFormatSet());
+       cfgB.setSetting(Configuration.ExtendableBuilder.OUTPUT_FORMAT_KEY_CAMEL_CASE, "default");
+       assertFalse(cfgB.isOutputFormatSet());
+       
+       try {
+           cfgB.setSetting(Configuration.ExtendableBuilder.OUTPUT_FORMAT_KEY, "null");
+       } catch (ConfigurationSettingValueException e) {
+           assertThat(e.getCause().getMessage(), containsString(UndefinedOutputFormat.class.getSimpleName()));
+       }
+    }
+    
+    @Test
+    public void testGetOutputFormatByName() throws Exception {
+        Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0).build();
+        
+        assertSame(HTMLOutputFormat.INSTANCE, cfg.getOutputFormat(HTMLOutputFormat.INSTANCE.getName()));
+        
+        try {
+            cfg.getOutputFormat("noSuchFormat");
+            fail();
+        } catch (UnregisteredOutputFormatException e) {
+            assertThat(e.getMessage(), containsString("noSuchFormat"));
+        }
+        
+        try {
+            cfg.getOutputFormat("HTML}");
+            fail();
+        } catch (IllegalArgumentException e) {
+            assertThat(e.getMessage(), containsString("'{'"));
+        }
+        
+        {
+            OutputFormat of = cfg.getOutputFormat("HTML{RTF}");
+            assertThat(of, instanceOf(CombinedMarkupOutputFormat.class));
+            CombinedMarkupOutputFormat combinedOF = (CombinedMarkupOutputFormat) of;
+            assertSame(HTMLOutputFormat.INSTANCE, combinedOF.getOuterOutputFormat());
+            assertSame(RTFOutputFormat.INSTANCE, combinedOF.getInnerOutputFormat());
+        }
+
+        {
+            OutputFormat of = cfg.getOutputFormat("XML{HTML{RTF}}");
+            assertThat(of, instanceOf(CombinedMarkupOutputFormat.class));
+            CombinedMarkupOutputFormat combinedOF = (CombinedMarkupOutputFormat) of;
+            assertSame(XMLOutputFormat.INSTANCE, combinedOF.getOuterOutputFormat());
+            MarkupOutputFormat innerOF = combinedOF.getInnerOutputFormat();
+            assertThat(innerOF, instanceOf(CombinedMarkupOutputFormat.class));
+            CombinedMarkupOutputFormat innerCombinedOF = (CombinedMarkupOutputFormat) innerOF; 
+            assertSame(HTMLOutputFormat.INSTANCE, innerCombinedOF.getOuterOutputFormat());
+            assertSame(RTFOutputFormat.INSTANCE, innerCombinedOF.getInnerOutputFormat());
+        }
+        
+        try {
+            cfg.getOutputFormat("plainText{HTML}");
+            fail();
+        } catch (IllegalArgumentException e) {
+            assertThat(e.getMessage(), allOf(containsString("plainText"), containsString("markup")));
+        }
+        try {
+            cfg.getOutputFormat("HTML{plainText}");
+            fail();
+        } catch (IllegalArgumentException e) {
+            assertThat(e.getMessage(), allOf(containsString("plainText"), containsString("markup")));
+        }
+    }
+
+    public void testSetRegisteredCustomOutputFormats() throws Exception {
+        Configuration.Builder cfg = new Configuration.Builder(Configuration.VERSION_3_0_0);
+        
+        assertTrue(cfg.getRegisteredCustomOutputFormats().isEmpty());
+        
+        cfg.setSetting(Configuration.ExtendableBuilder.REGISTERED_CUSTOM_OUTPUT_FORMATS_KEY_CAMEL_CASE,
+                "[org.apache.freemarker.core.userpkg.CustomHTMLOutputFormat(), "
+                + "org.apache.freemarker.core.userpkg.DummyOutputFormat()]");
+        assertEquals(
+                ImmutableList.of(CustomHTMLOutputFormat.INSTANCE, DummyOutputFormat.INSTANCE),
+                new ArrayList(cfg.getRegisteredCustomOutputFormats()));
+        
+        try {
+            cfg.setSetting(Configuration.ExtendableBuilder.REGISTERED_CUSTOM_OUTPUT_FORMATS_KEY_SNAKE_CASE, "[TemplateConfiguration()]");
+            fail();
+        } catch (ConfigurationSettingValueException e) {
+            assertThat(e.getMessage(), containsString(OutputFormat.class.getSimpleName()));
+        }
+    }
+
+    public void testSetRecognizeStandardFileExtensions() throws Exception {
+        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
+     
+        assertTrue(cfgB.getRecognizeStandardFileExtensions());
+        assertFalse(cfgB.isRecognizeStandardFileExtensionsSet());
+
+        cfgB.setRecognizeStandardFileExtensions(false);
+        assertFalse(cfgB.getRecognizeStandardFileExtensions());
+        assertTrue(cfgB.isRecognizeStandardFileExtensionsSet());
+     
+        cfgB.unsetRecognizeStandardFileExtensions();
+        assertTrue(cfgB.getRecognizeStandardFileExtensions());
+        assertFalse(cfgB.isRecognizeStandardFileExtensionsSet());
+        
+        cfgB.setRecognizeStandardFileExtensions(true);
+        assertTrue(cfgB.getRecognizeStandardFileExtensions());
+        assertTrue(cfgB.isRecognizeStandardFileExtensionsSet());
+     
+        cfgB.setSetting(Configuration.ExtendableBuilder.RECOGNIZE_STANDARD_FILE_EXTENSIONS_KEY_CAMEL_CASE, "false");
+        assertFalse(cfgB.getRecognizeStandardFileExtensions());
+        assertTrue(cfgB.isRecognizeStandardFileExtensionsSet());
+        
+        cfgB.setSetting(Configuration.ExtendableBuilder.RECOGNIZE_STANDARD_FILE_EXTENSIONS_KEY_SNAKE_CASE, "default");
+        assertTrue(cfgB.getRecognizeStandardFileExtensions());
+        assertFalse(cfgB.isRecognizeStandardFileExtensionsSet());
+     }
+    
+    public void testSetTimeZone() throws ConfigurationException {
+        TimeZone origSysDefTZ = TimeZone.getDefault();
+        try {
+            TimeZone sysDefTZ = TimeZone.getTimeZone("GMT-01");
+            TimeZone.setDefault(sysDefTZ);
+            
+            Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
+            assertEquals(sysDefTZ, cfgB.getTimeZone());
+            cfgB.setSetting(MutableProcessingConfiguration.TIME_ZONE_KEY, "JVM default");
+            assertEquals(sysDefTZ, cfgB.getTimeZone());
+            
+            TimeZone newSysDefTZ = TimeZone.getTimeZone("GMT+09");
+            TimeZone.setDefault(newSysDefTZ);
+            assertEquals(sysDefTZ, cfgB.getTimeZone());
+            cfgB.setSetting(MutableProcessingConfiguration.TIME_ZONE_KEY, "JVM default");
+            assertEquals(newSysDefTZ, cfgB.getTimeZone());
+        } finally {
+            TimeZone.setDefault(origSysDefTZ);
+        }
+    }
+    
+    public void testSetSQLDateAndTimeTimeZone() throws ConfigurationException {
+        TimeZone origSysDefTZ = TimeZone.getDefault();
+        try {
+            TimeZone sysDefTZ = TimeZone.getTimeZone("GMT-01");
+            TimeZone.setDefault(sysDefTZ);
+            
+            Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
+            assertNull(cfgB.getSQLDateAndTimeTimeZone());
+            
+            cfgB.setSQLDateAndTimeTimeZone(null);
+            assertNull(cfgB.getSQLDateAndTimeTimeZone());
+            
+            cfgB.setSetting(MutableProcessingConfiguration.SQL_DATE_AND_TIME_TIME_ZONE_KEY, "JVM default");
+            assertEquals(sysDefTZ, cfgB.getSQLDateAndTimeTimeZone());
+            
+            cfgB.setSetting(MutableProcessingConfiguration.SQL_DATE_AND_TIME_TIME_ZONE_KEY, "null");
+            assertNull(cfgB.getSQLDateAndTimeTimeZone());
+        } finally {
+            TimeZone.setDefault(origSysDefTZ);
+        }
+    }
+
+    public void testTimeZoneLayers() throws Exception {
+        TimeZone localTZ = TimeZone.getTimeZone("Europe/Brussels");
+
+        {
+            Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0).build();
+            Template t = new Template(null, "", cfg);
+            Environment env1 = t.createProcessingEnvironment(null, new StringWriter());
+            Environment env2 = t.createProcessingEnvironment(null, new StringWriter());
+
+            // cfg:
+            assertEquals(TimeZone.getDefault(), cfg.getTimeZone());
+            assertNull(cfg.getSQLDateAndTimeTimeZone());
+            // env:
+            assertEquals(TimeZone.getDefault(), env1.getTimeZone());
+            assertNull(env1.getSQLDateAndTimeTimeZone());
+            // env 2:
+            assertEquals(TimeZone.getDefault(), env2.getTimeZone());
+            assertNull(env2.getSQLDateAndTimeTimeZone());
+
+            env1.setSQLDateAndTimeTimeZone(_DateUtil.UTC);
+            // cfg:
+            assertEquals(TimeZone.getDefault(), cfg.getTimeZone());
+            assertNull(cfg.getSQLDateAndTimeTimeZone());
+            // env:
+            assertEquals(TimeZone.getDefault(), env1.getTimeZone());
+            assertEquals(_DateUtil.UTC, env1.getSQLDateAndTimeTimeZone());
+
+            env1.setTimeZone(localTZ);
+            // cfg:
+            assertEquals(TimeZone.getDefault(), cfg.getTimeZone());
+            assertNull(cfg.getSQLDateAndTimeTimeZone());
+            // env:
+            assertEquals(localTZ, env1.getTimeZone());
+            assertEquals(_DateUtil.UTC, env1.getSQLDateAndTimeTimeZone());
+            // env 2:
+            assertEquals(TimeZone.getDefault(), env2.getTimeZone());
+            assertNull(env2.getSQLDateAndTimeTimeZone());
+        }
+
+        {
+            TimeZone otherTZ1 = TimeZone.getTimeZone("GMT+05");
+            TimeZone otherTZ2 = TimeZone.getTimeZone("GMT+06");
+            Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0)
+                    .timeZone(otherTZ1)
+                    .sqlDateAndTimeTimeZone(otherTZ2)
+                    .build();
+
+            Template t = new Template(null, "", cfg);
+            Environment env1 = t.createProcessingEnvironment(null, new StringWriter());
+            Environment env2 = t.createProcessingEnvironment(null, new StringWriter());
+
+            env1.setTimeZone(localTZ);
+            env1.setSQLDateAndTimeTimeZone(_DateUtil.UTC);
+
+            // cfg:
+            assertEquals(otherTZ1, cfg.getTimeZone());
+            assertEquals(otherTZ2, cfg.getSQLDateAndTimeTimeZone());
+            // env:
+            assertEquals(localTZ, env1.getTimeZone());
+            assertEquals(_DateUtil.UTC, env1.getSQLDateAndTimeTimeZone());
+            // env 2:
+            assertEquals(otherTZ1, env2.getTimeZone());
+            assertEquals(otherTZ2, env2.getSQLDateAndTimeTimeZone());
+
+            try {
+                setTimeZoneToNull(env2);
+                fail();
+            } catch (IllegalArgumentException e) {
+                // expected
+            }
+            env2.setSQLDateAndTimeTimeZone(null);
+            assertEquals(otherTZ1, env2.getTimeZone());
+            assertNull(env2.getSQLDateAndTimeTimeZone());
+        }
+    }
+
+    @SuppressFBWarnings(value="NP_NULL_PARAM_DEREF_ALL_TARGETS_DANGEROUS", justification="Expected to fail")
+    private void setTimeZoneToNull(Environment env2) {
+        env2.setTimeZone(null);
+    }
+    
+    public void testSetICIViaSetSettingAPI() throws ConfigurationException {
+        Configuration.Builder cfg = new Configuration.Builder(Configuration.VERSION_3_0_0);
+        assertEquals(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS, cfg.getIncompatibleImprovements());
+        // This is the only valid value ATM:
+        cfg.setSetting(Configuration.ExtendableBuilder.INCOMPATIBLE_IMPROVEMENTS_KEY, "3.0.0");
+        assertEquals(Configuration.VERSION_3_0_0, cfg.getIncompatibleImprovements());
+    }
+
+    public void testSetLogTemplateExceptionsViaSetSettingAPI() throws ConfigurationException {
+        Configuration.Builder cfg = new Configuration.Builder(Configuration.VERSION_3_0_0);
+        assertFalse(cfg.getLogTemplateExceptions());
+        cfg.setSetting(MutableProcessingConfiguration.LOG_TEMPLATE_EXCEPTIONS_KEY, "true");
+        assertTrue(cfg.getLogTemplateExceptions());
+    }
+    
+    public void testSharedVariables() throws TemplateException, IOException {
+        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
+
+        Map<String, Object> vars = new HashMap<>();
+        vars.put("a", "aa");
+        vars.put("b", "bb");
+        vars.put("c", new MyScalarModel());
+        cfgB.setSharedVariables(vars);
+
+        assertNull(cfgB.getSharedVariable("erased"));
+        
+        {
+            Configuration cfg = cfgB.build();
+
+            TemplateScalarModel aVal = (TemplateScalarModel) cfg.getWrappedSharedVariable("a");
+            assertEquals("aa", aVal.getAsString());
+            assertEquals(SimpleScalar.class, aVal.getClass());
+
+            TemplateScalarModel bVal = (TemplateScalarModel) cfg.getWrappedSharedVariable("b");
+            assertEquals("bb", bVal.getAsString());
+            assertEquals(SimpleScalar.class, bVal.getClass());
+            
+            TemplateScalarModel cVal = (TemplateScalarModel) cfg.getWrappedSharedVariable("c");
+            assertEquals("my", cVal.getAsString());
+            assertEquals(MyScalarModel.class, cfg.getWrappedSharedVariable("c").getClass());
+
+            // See if it actually works in templates:
+            StringWriter sw = new StringWriter();
+            new Template(null, "${a} ${b}", cfg)
+                    .process(ImmutableMap.of("a", "aaDM"), sw);
+            assertEquals("aaDM bb", sw.toString());
+        }
+        
+        cfgB.setSharedVariable("b", "bbLegacy");
+        
+        {
+            Configuration cfg = cfgB.build();
+
+            TemplateScalarModel aVal = (TemplateScalarModel) cfg.getWrappedSharedVariable("a");
+            assertEquals("aa", aVal.getAsString());
+            assertEquals(SimpleScalar.class, aVal.getClass());
+            
+            TemplateScalarModel bVal = (TemplateScalarModel) cfg.getWrappedSharedVariable("b");
+            assertEquals("bbLegacy", bVal.getAsString());
+            assertEquals(SimpleScalar.class, bVal.getClass());
+        }
+    }
+
+    @Test
+    public void testApiBuiltinEnabled() throws Exception {
+        try {
+            new Template(
+                    null, "${1?api}",
+                    new Configuration.Builder(Configuration.VERSION_3_0_0).build())
+                    .process(null, _NullWriter.INSTANCE);
+            fail();
+        } catch (TemplateException e) {
+            assertThat(e.getMessage(), containsString(MutableProcessingConfiguration.API_BUILTIN_ENABLED_KEY));
+        }
+            
+        new Template(
+                null, "${m?api.hashCode()}",
+                new Configuration.Builder(Configuration.VERSION_3_0_0).apiBuiltinEnabled(true).build())
+                .process(Collections.singletonMap("m", new HashMap()), _NullWriter.INSTANCE);
+    }
+
+    @Test
+    public void testTemplateUpdateDelay() throws Exception {
+        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
+
+        assertEquals(DefaultTemplateResolver.DEFAULT_TEMPLATE_UPDATE_DELAY_MILLIS, cfgB.getTemplateUpdateDelayMilliseconds());
+        
+        cfgB.setTemplateUpdateDelayMilliseconds(4000);
+        assertEquals(4000L, cfgB.getTemplateUpdateDelayMilliseconds());
+        
+        cfgB.setTemplateUpdateDelayMilliseconds(100);
+        assertEquals(100L, cfgB.getTemplateUpdateDelayMilliseconds());
+        
+        try {
+            cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_UPDATE_DELAY_KEY, "5");
+            assertEquals(5000L, cfgB.getTemplateUpdateDelayMilliseconds());
+        } catch (ConfigurationSettingValueException e) {
+            assertThat(e.getMessage(), containsStringIgnoringCase("unit must be specified"));
+        }
+        cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_UPDATE_DELAY_KEY, "0");
+        assertEquals(0L, cfgB.getTemplateUpdateDelayMilliseconds());
+        try {
+            cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_UPDATE_DELAY_KEY, "5 foo");
+            assertEquals(5000L, cfgB.getTemplateUpdateDelayMilliseconds());
+        } catch (ConfigurationSettingValueException e) {
+            assertThat(e.getMessage(), containsStringIgnoringCase("\"foo\""));
+        }
+        
+        cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_UPDATE_DELAY_KEY, "3 ms");
+        assertEquals(3L, cfgB.getTemplateUpdateDelayMilliseconds());
+        cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_UPDATE_DELAY_KEY, "4ms");
+        assertEquals(4L, cfgB.getTemplateUpdateDelayMilliseconds());
+        
+        cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_UPDATE_DELAY_KEY, "3 s");
+        assertEquals(3000L, cfgB.getTemplateUpdateDelayMilliseconds());
+        cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_UPDATE_DELAY_KEY, "4s");
+        assertEquals(4000L, cfgB.getTemplateUpdateDelayMilliseconds());
+        
+        cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_UPDATE_DELAY_KEY, "3 m");
+        assertEquals(1000L * 60 * 3, cfgB.getTemplateUpdateDelayMilliseconds());
+        cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_UPDATE_DELAY_KEY, "4m");
+        assertEquals(1000L * 60 * 4, cfgB.getTemplateUpdateDelayMilliseconds());
+
+        cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_UPDATE_DELAY_KEY, "1 h");
+        assertEquals(1000L * 60 * 60, cfgB.getTemplateUpdateDelayMilliseconds());
+        cfgB.setSetting(Configuration.ExtendableBuilder.TEMPLATE_UPDATE_DELAY_KEY, "2h");
+        assertEquals(1000L * 60 * 60 * 2, cfgB.getTemplateUpdateDelayMilliseconds());
+    }
+    
+    @Test
+    @SuppressFBWarnings(value = "NP_NULL_PARAM_DEREF_ALL_TARGETS_DANGEROUS ", justification = "Testing wrong args")
+    public void testSetCustomNumberFormat() throws Exception {
+        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
+        
+        try {
+            cfgB.setCustomNumberFormats(null);
+            fail();
+        } catch (IllegalArgumentException e) {
+            assertThat(e.getMessage(), containsString("null"));
+        }
+
+        try {
+            cfgB.setCustomNumberFormats(Collections.<String, TemplateNumberFormatFactory>singletonMap(
+                    "", HexTemplateNumberFormatFactory.INSTANCE));
+            fail();
+        } catch (IllegalArgumentException e) {
+            assertThat(e.getMessage(), containsString("0 length"));
+        }
+
+        try {
+            cfgB.setCustomNumberFormats(Collections.<String, TemplateNumberFormatFactory>singletonMap(
+                    "a_b", HexTemplateNumberFormatFactory.INSTANCE));
+            fail();
+        } catch (IllegalArgumentException e) {
+            assertThat(e.getMessage(), containsString("a_b"));
+        }
+
+        try {
+            cfgB.setCustomNumberFormats(Collections.<String, TemplateNumberFormatFactory>singletonMap(
+                    "a b", HexTemplateNumberFormatFactory.INSTANCE));
+            fail();
+        } catch (IllegalArgumentException e) {
+            assertThat(e.getMessage(), containsString("a b"));
+        }
+        
+        try {
+            cfgB.setCustomNumberFormats(ImmutableMap.<String, TemplateNumberFormatFactory>of(
+                    "a", HexTemplateNumberFormatFactory.INSTANCE,
+                    "@wrong", HexTemplateNumberFormatFactory.INSTANCE));
+            fail();
+        } catch (IllegalArgumentException e) {
+            assertThat(e.getMessage(), containsString("@wrong"));
+        }
+        
+        cfgB.setSetting(MutableProcessingConfiguration.CUSTOM_NUMBER_FORMATS_KEY_CAMEL_CASE,
+                "{ 'base': " + BaseNTemplateNumberFormatFactory.class.getName() + "() }");
+        assertEquals(
+                Collections.singletonMap("base", BaseNTemplateNumberFormatFactory.INSTANCE),
+                cfgB.getCustomNumberFormats());
+        
+        cfgB.setSetting(MutableProcessingConfiguration.CUSTOM_NUMBER_FORMATS_KEY_SNAKE_CASE,
+                "{ "
+                + "'base': " + BaseNTemplateNumberFormatFactory.class.getName() + "(), "
+                + "'hex': " + HexTemplateNumberFormatFactory.class.getName() + "()"
+                + " }");
+        assertEquals(
+                ImmutableMap.of(
+                        "base", BaseNTemplateNumberFormatFactory.INSTANCE,
+                        "hex", HexTemplateNumberFormatFactory.INSTANCE),
+                cfgB.getCustomNumberFormats());
+        
+        cfgB.setSetting(MutableProcessingConfiguration.CUSTOM_NUMBER_FORMATS_KEY, "{}");
+        assertEquals(Collections.emptyMap(), cfgB.getCustomNumberFormats());
+        
+        try {
+            cfgB.setSetting(MutableProcessingConfiguration.CUSTOM_NUMBER_FORMATS_KEY_CAMEL_CASE,
+                    "{ 'x': " + EpochMillisTemplateDateFormatFactory.class.getName() + "() }");
+            fail();
+        } catch (ConfigurationException e) {
+            assertThat(e.getCause().getMessage(), allOf(
+                    containsString(EpochMillisTemplateDateFormatFactory.class.getName()),
+                    containsString(TemplateNumberFormatFactory.class.getName())));
+        }
+    }
+
+    @Test
+    public void testSetTabSize() throws Exception {
+        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
+        
+        String ftl = "${\t}";
+        
+        try {
+            new Template(null, ftl, cfgB.build());
+            fail();
+        } catch (ParseException e) {
+            assertEquals(9, e.getColumnNumber());
+        }
+        
+        cfgB.setTabSize(1);
+        try {
+            new Template(null, ftl, cfgB.build());
+            fail();
+        } catch (ParseException e) {
+            assertEquals(4, e.getColumnNumber());
+        }
+        
+        try {
+            cfgB.setTabSize(0);
+            fail();
+        } catch (IllegalArgumentException e) {
+            // Expected
+        }
+        
+        try {
+            cfgB.setTabSize(257);
+            fail();
+        } catch (IllegalArgumentException e) {
+            // Expected
+        }
+    }
+
+    @Test
+    public void testTabSizeSetting() throws Exception {
+        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
+        assertEquals(8, cfgB.getTabSize());
+        cfgB.setSetting(Configuration.ExtendableBuilder.TAB_SIZE_KEY_CAMEL_CASE, "4");
+        assertEquals(4, cfgB.getTabSize());
+        cfgB.setSetting(Configuration.ExtendableBuilder.TAB_SIZE_KEY_SNAKE_CASE, "1");
+        assertEquals(1, cfgB.getTabSize());
+        
+        try {
+            cfgB.setSetting(Configuration.ExtendableBuilder.TAB_SIZE_KEY_SNAKE_CASE, "x");
+            fail();
+        } catch (ConfigurationException e) {
+            assertThat(e.getCause(), instanceOf(NumberFormatException.class));
+        }
+    }
+    
+    @SuppressFBWarnings(value="NP_NULL_PARAM_DEREF_ALL_TARGETS_DANGEROUS", justification="We test failures")
+    @Test
+    public void testSetCustomDateFormat() throws Exception {
+        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
+        
+        try {
+            cfgB.setCustomDateFormats(null);
+            fail();
+        } catch (IllegalArgumentException e) {
+            assertThat(e.getMessage(), containsString("null"));
+        }
+        
+        try {
+            cfgB.setCustomDateFormats(Collections.<String, TemplateDateFormatFactory>singletonMap(
+                    "", EpochMillisTemplateDateFormatFactory.INSTANCE));
+            fail();
+        } catch (IllegalArgumentException e) {
+            assertThat(e.getMessage(), containsString("0 length"));
+        }
+
+        try {
+            cfgB.setCustomDateFormats(Collections.<String, TemplateDateFormatFactory>singletonMap(
+                    "a_b", EpochMillisTemplateDateFormatFactory.INSTANCE));
+            fail();
+        } catch (IllegalArgumentException e) {
+            assertThat(e.getMessage(), containsString("a_b"));
+        }
+
+        try {
+            cfgB.setCustomDateFormats(Collections.<String, TemplateDateFormatFactory>singletonMap(
+                    "a b", EpochMillisTemplateDateFormatFactory.INSTANCE));
+            fail();
+        } catch (IllegalArgumentException e) {
+            assertThat(e.getMessage(), containsString("a b"));
+        }
+        
+        try {
+            cfgB.setCustomDateFormats(ImmutableMap.<String, TemplateDateFormatFactory>of(
+                    "a", EpochMillisTemplateDateFormatFactory.INSTANCE,
+                    "@wrong", EpochMillisTemplateDateFormatFactory.INSTANCE));
+            fail();
+        } catch (IllegalArgumentException e) {
+            assertThat(e.getMessage(), containsString("@wrong"));
+        }
+        
+        cfgB.setSetting(MutableProcessingConfiguration.CUSTOM_DATE_FORMATS_KEY_CAMEL_CASE,
+                "{ 'epoch': " + EpochMillisTemplateDateFormatFactory.class.getName() + "() }");
+        assertEquals(
+                Collections.singletonMap("epoch", EpochMillisTemplateDateFormatFactory.INSTANCE),
+                cfgB.getCustomDateFormats());
+        
+        cfgB.setSetting(MutableProcessingConfiguration.CUSTOM_DATE_FORMATS_KEY_SNAKE_CASE,
+                "{ "
+                + "'epoch': " + EpochMillisTemplateDateFormatFactory.class.getName() + "(), "
+                + "'epochDiv': " + EpochMillisDivTemplateDateFormatFactory.class.getName() + "()"
+                + " }");
+        assertEquals(
+                ImmutableMap.of(
+                        "epoch", EpochMillisTemplateDateFormatFactory.INSTANCE,
+                        "epochDiv", EpochMillisDivTemplateDateFormatFactory.INSTANCE),
+                cfgB.getCustomDateFormats());
+        
+        cfgB.setSetting(MutableProcessingConfiguration.CUSTOM_DATE_FORMATS_KEY, "{}");
+        assertEquals(Collections.emptyMap(), cfgB.getCustomDateFormats());
+        
+        try {
+            cfgB.setSetting(MutableProcessingConfiguration.CUSTOM_DATE_FORMATS_KEY_CAMEL_CASE,
+                    "{ 'x': " + HexTemplateNumberFormatFactory.class.getName() + "() }");
+            fail();
+        } catch (ConfigurationException e) {
+            assertThat(e.getCause().getMessage(), allOf(
+                    containsString(HexTemplateNumberFormatFactory.class.getName()),
+                    containsString(TemplateDateFormatFactory.class.getName())));
+        }
+    }
+
+    public void testNamingConventionSetSetting() throws ConfigurationException {
+        Configuration.Builder cfg = new Configuration.Builder(Configuration.VERSION_3_0_0);
+
+        assertEquals(ParsingConfiguration.AUTO_DETECT_NAMING_CONVENTION, cfg.getNamingConvention());
+        
+        cfg.setSetting("naming_convention", "legacy");
+        assertEquals(ParsingConfiguration.LEGACY_NAMING_CONVENTION, cfg.getNamingConvention());
+        
+        cfg.setSetting("naming_convention", "camel_case");
+        assertEquals(ParsingConfiguration.CAMEL_CASE_NAMING_CONVENTION, cfg.getNamingConvention());
+        
+        cfg.setSetting("naming_convention", "auto_detect");
+        assertEquals(ParsingConfiguration.AUTO_DETECT_NAMING_CONVENTION, cfg.getNamingConvention());
+    }
+
+    public void testLazyImportsSetSetting() throws ConfigurationException {
+        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
+
+        assertFalse(cfgB.getLazyImports());
+        assertFalse(cfgB.isLazyImportsSet());
+        cfgB.setSetting("lazy_imports", "true");
+        assertTrue(cfgB.getLazyImports());
+        cfgB.setSetting("lazyImports", "false");
+        assertFalse(cfgB.getLazyImports());
+        assertTrue(cfgB.isLazyImportsSet());
+    }
+    
+    public void testLazyAutoImportsSetSetting() throws ConfigurationException {
+        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
+
+        assertNull(cfgB.getLazyAutoImports());
+        assertFalse(cfgB.isLazyAutoImportsSet());
+        cfgB.setSetting("lazy_auto_imports", "true");
+        assertEquals(Boolean.TRUE, cfgB.getLazyAutoImports());
+        assertTrue(cfgB.isLazyAutoImportsSet());
+        cfgB.setSetting("lazyAutoImports", "false");
+        assertEquals(Boolean.FALSE, cfgB.getLazyAutoImports());
+        cfgB.setSetting("lazyAutoImports", "null");
+        assertNull(cfgB.getLazyAutoImports());
+        assertTrue(cfgB.isLazyAutoImportsSet());
+        cfgB.unsetLazyAutoImports();
+        assertNull(cfgB.getLazyAutoImports());
+        assertFalse(cfgB.isLazyAutoImportsSet());
+    }
+
+    public void testLocaleSetting() throws TemplateException, ConfigurationException {
+        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
+
+        assertEquals(Locale.getDefault(), cfgB.getLocale());
+        assertFalse(cfgB.isLocaleSet());
+
+        Locale nonDefault = Locale.getDefault().equals(Locale.GERMANY) ? Locale.FRANCE : Locale.GERMANY;
+        cfgB.setLocale(nonDefault);
+        assertTrue(cfgB.isLocaleSet());
+        assertEquals(nonDefault, cfgB.getLocale());
+
+        cfgB.unsetLocale();
+        assertEquals(Locale.getDefault(), cfgB.getLocale());
+        assertFalse(cfgB.isLocaleSet());
+
+        cfgB.setSetting(Configuration.ExtendableBuilder.LOCALE_KEY, "JVM default");
+        assertEquals(Locale.getDefault(), cfgB.getLocale());
+        assertTrue(cfgB.isLocaleSet());
+    }
+
+    public void testDefaultEncodingSetting() throws TemplateException, ConfigurationException {
+        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
+
+        assertEquals(Charset.defaultCharset(), cfgB.getSourceEncoding());
+        assertFalse(cfgB.isSourceEncodingSet());
+
+        Charset nonDefault = Charset.defaultCharset().equals(StandardCharsets.UTF_8) ? StandardCharsets.ISO_8859_1
+                : StandardCharsets.UTF_8;
+        cfgB.setSourceEncoding(nonDefault);
+        assertTrue(cfgB.isSourceEncodingSet());
+        assertEquals(nonDefault, cfgB.getSourceEncoding());
+
+        cfgB.unsetSourceEncoding();
+        assertEquals(Charset.defaultCharset(), cfgB.getSourceEncoding());
+        assertFalse(cfgB.isSourceEncodingSet());
+
+        cfgB.setSetting(Configuration.ExtendableBuilder.SOURCE_ENCODING_KEY, "JVM default");
+        assertEquals(Charset.defaultCharset(), cfgB.getSourceEncoding());
+        assertTrue(cfgB.isSourceEncodingSet());
+    }
+
+    public void testTimeZoneSetting() throws TemplateException, ConfigurationException {
+        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
+
+        assertEquals(TimeZone.getDefault(), cfgB.getTimeZone());
+        assertFalse(cfgB.isTimeZoneSet());
+
+        TimeZone nonDefault = TimeZone.getDefault().equals(_DateUtil.UTC) ? TimeZone.getTimeZone("PST") : _DateUtil.UTC;
+        cfgB.setTimeZone(nonDefault);
+        assertTrue(cfgB.isTimeZoneSet());
+        assertEquals(nonDefault, cfgB.getTimeZone());
+
+        cfgB.unsetTimeZone();
+        assertEquals(TimeZone.getDefault(), cfgB.getTimeZone());
+        assertFalse(cfgB.isTimeZoneSet());
+
+        cfgB.setSetting(Configuration.ExtendableBuilder.TIME_ZONE_KEY, "JVM default");
+        assertEquals(TimeZone.getDefault(), cfgB.getTimeZone());
+        assertTrue(cfgB.isTimeZoneSet());
+    }
+
+    @Test
+    public void testGetSettingNamesAreSorted() throws Exception {
+        Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0).build();
+        for (boolean camelCase : new boolean[] { false, true }) {
+            List<String> names = new ArrayList<>(Configuration.Builder.getSettingNames(camelCase));
+            List<String> procCfgNames = new ArrayList<>(new Template(null, "", cfg)
+                    .createProcessingEnvironment(null, _NullWriter.INSTANCE)
+                    .getSettingNames(camelCase));
+            assertStartsWith(names, procCfgNames);
+            
+            String prevName = null;
+            for (int i = procCfgNames.size(); i < names.size(); i++) {
+                String name = names.get(i);
+                if (prevName != null) {
+                    assertThat(name, greaterThan(prevName));
+                }
+                prevName = name;
+            }
+        }
+    }
+
+    @Test
+    @SuppressFBWarnings("DLS_DEAD_LOCAL_STORE")
+    public void testGetSettingNamesNameConventionsContainTheSame() throws Exception {
+        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
+        ConfigurableTest.testGetSettingNamesNameConventionsContainTheSame(
+                new ArrayList<>(cfgB.getSettingNames(false)),
+                new ArrayList<>(cfgB.getSettingNames(true)));
+    }
+
+    @Test
+    @SuppressFBWarnings("DLS_DEAD_LOCAL_STORE")
+    public void testStaticFieldKeysCoverAllGetSettingNames() throws Exception {
+        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
+        List<String> names = new ArrayList<>(cfgB.getSettingNames(false));
+        List<String> cfgableNames = new ArrayList<>(cfgB.getSettingNames(false));
+        assertStartsWith(names, cfgableNames);
+        
+        for (int i = cfgableNames.size(); i < names.size(); i++) {
+            String name = names.get(i);
+            assertTrue("No field was found for " + name, keyFieldExists(name));
+        }
+    }
+    
+    @Test
+    public void testGetSettingNamesCoversAllStaticKeyFields() throws Exception {
+        Collection<String> names = new Configuration.Builder(Configuration.VERSION_3_0_0).getSettingNames(false);
+        
+        for (Class<? extends MutableProcessingConfiguration> cfgableClass : new Class[] { Configuration.class, MutableProcessingConfiguration.class }) {
+            for (Field f : cfgableClass.getFields()) {
+                if (f.getName().endsWith("_KEY")) {
+                    final Object name = f.get(null);
+                    assertTrue("Missing setting name: " + name, names.contains(name));
+                }
+            }
+        }
+    }
+    
+    @Test
+    public void testKeyStaticFieldsHasAllVariationsAndCorrectFormat() throws IllegalArgumentException, IllegalAccessException {
+        ConfigurableTest.testKeyStaticFieldsHasAllVariationsAndCorrectFormat(Configuration.ExtendableBuilder.class);
+    }
+
+    @Test
+    public void testGetSettingNamesCoversAllSettingNames() throws Exception {
+        Collection<String> names = new Configuration.Builder(Configuration.VERSION_3_0_0).getSettingNames(false);
+        
+        for (Field f : MutableProcessingConfiguration.class.getFields()) {
+            if (f.getName().endsWith("_KEY")) {
+                final Object name = f.get(null);
+                assertTrue("Missing setting name: " + name, names.contains(name));
+            }
+        }
+    }
+
+    @Test
+    public void testSetSettingSupportsBothNamingConventions() throws Exception {
+        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
+        
+        cfgB.setSetting(Configuration.ExtendableBuilder.SOURCE_ENCODING_KEY_CAMEL_CASE, StandardCharsets.UTF_16LE.name());
+        assertEquals(StandardCharsets.UTF_16LE, cfgB.getSourceEncoding());
+        cfgB.setSetting(Configuration.ExtendableBuilder.SOURCE_ENCODING_KEY_SNAKE_CASE, StandardCharsets.UTF_8.name());
+        assertEquals(StandardCharsets.UTF_8, cfgB.getSourceEncoding());
+        
+        for (String nameCC : cfgB.getSettingNames(true)) {
+            for (String value : new String[] { "1", "default", "true" }) {
+                Exception resultCC = null;
+                try {
+                    cfgB.setSetting(nameCC, value);
+                } catch (Exception e) {
+                    assertThat(e, not(instanceOf(UnknownConfigurationSettingException.class)));
+                    resultCC = e;
+                }
+                
+                String nameSC = _StringUtil.camelCaseToUnderscored(nameCC);
+                Exception resultSC = null;
+                try {
+                    cfgB.setSetting(nameSC, value);
+                } catch (Exception e) {
+                    assertThat(e, not(instanceOf(UnknownConfigurationSettingException.class)));
+                    resultSC = e;
+                }
+                
+                if (resultCC == null) {
+                    assertNull(resultSC);
+                } else {
+                    assertNotNull(resultSC);
+                    assertEquals(resultCC.getClass(), resultSC.getClass());
+                }
+            }
+        }
+    }
+    
+    @Test
+    public void testGetSupportedBuiltInDirectiveNames() {
+        Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0).build();
+        
+        Set<String> allNames = cfg.getSupportedBuiltInDirectiveNames(ParsingConfiguration.AUTO_DETECT_NAMING_CONVENTION);
+        Set<String> lNames = cfg.getSupportedBuiltInDirectiveNames(ParsingConfiguration.LEGACY_NAMING_CONVENTION);
+        Set<String> cNames = cfg.getSupportedBuiltInDirectiveNames(ParsingConfiguration.CAMEL_CASE_NAMING_CONVENTION);
+        
+        checkNamingConventionNameSets(allNames, lNames, cNames);
+        
+        for (String name : cNames) {
+            assertThat(name.toLowerCase(), isIn(lNames));
+        }
+    }
+
+    @Test
+    public void testGetSupportedBuiltInNames() {
+        Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0).build();
+        
+        Set<String> allNames = cfg.getSupportedBuiltInNames(ParsingConfiguration.AUTO_DETECT_NAMING_CONVENTION);
+        Set<String> lNames = cfg.getSupportedBuiltInNames(ParsingConfiguration.LEGACY_NAMING_CONVENTION);
+        Set<String> cNames = cfg.getSupportedBuiltInNames(ParsingConfiguration.CAMEL_CASE_NAMING_CONVENTION);
+        
+        checkNamingConventionNameSets(allNames, lNames, cNames);
+    }
+
+    private void checkNamingConventionNameSets(Set<String> allNames, Set<String> lNames, Set<String> cNames) {
+        for (String name : lNames) {
+            assertThat(allNames, hasItem(name));
+            assertTrue("Should be all-lowercase: " + name, name.equals(name.toLowerCase()));
+        }
+        for (String name : cNames) {
+            assertThat(allNames, hasItem(name));
+        }
+        for (String name : allNames) {
+            assertThat(name, anyOf(isIn(lNames), isIn(cNames)));
+        }
+        assertEquals(lNames.size(), cNames.size());
+    }
+    
+    @Test
+    public void testRemovedSettings() {
+        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
+        try {
+            cfgB.setSetting("classic_compatible", "true");
+            fail();
+        } catch (ConfigurationException e) {
+            assertThat(e.getMessage(), allOf(containsString("removed"), containsString("3.0.0")));
+        }
+        try {
+            cfgB.setSetting("strict_syntax", "true");
+            fail();
+        } catch (ConfigurationException e) {
+            assertThat(e.getMessage(), allOf(containsString("removed"), containsString("3.0.0")));
+        }
+    }
+    
+    @SuppressWarnings("boxing")
+    private void assertStartsWith(List<String> list, List<String> headList) {
+        int index = 0;
+        for (String name : headList) {
+            assertThat(index, lessThan(list.size()));
+            assertEquals(name, list.get(index));
+            index++;
+        }
+    }
+
+    private boolean keyFieldExists(String name) throws Exception {
+        Field field;
+        try {
+            field = Configuration.class.getField(name.toUpperCase() + "_KEY");
+        } catch (NoSuchFieldException e) {
+            return false;
+        }
+        assertEquals(name, field.get(null));
+        return true;
+    }
+    
+    private static class MyScalarModel implements TemplateScalarModel {
+
+        @Override
+        public String getAsString() throws TemplateModelException {
+            return "my";
+        }
+        
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/CoreLocaleUtilsTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/CoreLocaleUtilsTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/CoreLocaleUtilsTest.java
new file mode 100644
index 0000000..6714fc3
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/CoreLocaleUtilsTest.java
@@ -0,0 +1,73 @@
+/*
+ * 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.util.Locale;
+
+import org.apache.freemarker.core.util._LocaleUtil;
+import org.junit.Test;
+
+public class CoreLocaleUtilsTest {
+
+    @Test
+    public void testGetLessSpecificLocale() {
+        Locale locale;
+        
+        locale = new Locale("ru", "RU", "Linux");
+        assertEquals("ru_RU_Linux", locale.toString());
+        locale = _LocaleUtil.getLessSpecificLocale(locale);
+        assertEquals("ru_RU", locale.toString());
+        locale = _LocaleUtil.getLessSpecificLocale(locale);
+        assertEquals("ru", locale.toString());
+        locale = _LocaleUtil.getLessSpecificLocale(locale);
+        assertNull(locale);
+        
+        locale = new Locale("ch", "CH");
+        assertEquals("ch_CH", locale.toString());
+        locale = _LocaleUtil.getLessSpecificLocale(locale);
+        assertEquals("ch", locale.toString());
+        locale = _LocaleUtil.getLessSpecificLocale(locale);
+        assertNull(locale);
+        
+        locale = new Locale("ja");
+        assertEquals("ja", locale.toString());
+        locale = _LocaleUtil.getLessSpecificLocale(locale);
+        assertNull(locale);
+
+        locale = new Locale("ja", "", "");
+        assertEquals("ja", locale.toString());
+        locale = _LocaleUtil.getLessSpecificLocale(locale);
+        assertNull(locale);
+        
+        locale = new Locale("");
+        assertEquals("", locale.toString());
+        locale = _LocaleUtil.getLessSpecificLocale(locale);
+        assertNull(locale);
+        
+        locale = new Locale("hu", "", "Linux");
+        assertEquals("hu__Linux", locale.toString());
+        locale = _LocaleUtil.getLessSpecificLocale(locale);
+        assertEquals("hu", locale.toString());
+        locale = _LocaleUtil.getLessSpecificLocale(locale);
+        assertNull(locale);
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/CustomAttributeTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/CustomAttributeTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/CustomAttributeTest.java
new file mode 100644
index 0000000..726a20c
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/CustomAttributeTest.java
@@ -0,0 +1,163 @@
+/*
+ * 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.math.BigDecimal;
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+@SuppressWarnings("boxing")
+public class CustomAttributeTest {
+    
+    private static final String KEY_1 = "key1";
+    private static final String KEY_2 = "key2";
+    private static final String KEY_3 = "key3";
+    private static final Integer KEY_4 = 4;
+
+    private static final Integer VALUE_1 = 1; // Serializable
+    private static final Object VALUE_2 = new Object();
+    private static final Object VALUE_3 = new Object();
+    private static final Object VALUE_4 = new Object();
+    private static final Object VALUE_LIST = ImmutableList.<Object>of(
+            "s", BigDecimal.valueOf(2), Boolean.TRUE, ImmutableMap.of("a", "A"));
+    private static final Object VALUE_BIGDECIMAL = BigDecimal.valueOf(22);
+
+    private static final Object CUST_ATT_KEY = new Object();
+
+    @Test
+    public void testStringKey() throws Exception {
+        // Need some MutableProcessingConfiguration:
+        TemplateConfiguration.Builder mpc = new TemplateConfiguration.Builder();
+
+        assertEquals(0, mpc.getCustomAttributeNames().length);
+        assertNull(mpc.getCustomAttribute(KEY_1));
+        
+        mpc.setCustomAttribute(KEY_1, VALUE_1);
+        assertArrayEquals(new String[] { KEY_1 }, mpc.getCustomAttributeNames());
+        assertSame(VALUE_1, mpc.getCustomAttribute(KEY_1));
+        
+        mpc.setCustomAttribute(KEY_2, VALUE_2);
+        assertArrayEquals(new String[] { KEY_1, KEY_2 }, sort(mpc.getCustomAttributeNames()));
+        assertSame(VALUE_1, mpc.getCustomAttribute(KEY_1));
+        assertSame(VALUE_2, mpc.getCustomAttribute(KEY_2));
+
+        mpc.setCustomAttribute(KEY_1, VALUE_2);
+        assertArrayEquals(new String[] { KEY_1, KEY_2 }, sort(mpc.getCustomAttributeNames()));
+        assertSame(VALUE_2, mpc.getCustomAttribute(KEY_1));
+        assertSame(VALUE_2, mpc.getCustomAttribute(KEY_2));
+
+        mpc.setCustomAttribute(KEY_1, null);
+        assertArrayEquals(new String[] { KEY_1, KEY_2 }, sort(mpc.getCustomAttributeNames()));
+        assertNull(mpc.getCustomAttribute(KEY_1));
+        assertSame(VALUE_2, mpc.getCustomAttribute(KEY_2));
+
+        mpc.removeCustomAttribute(KEY_1);
+        assertArrayEquals(new String[] { KEY_2 }, mpc.getCustomAttributeNames());
+        assertNull(mpc.getCustomAttribute(KEY_1));
+        assertSame(VALUE_2, mpc.getCustomAttribute(KEY_2));
+    }
+
+    @Test
+    public void testRemoveFromEmptySet() throws Exception {
+        // Need some MutableProcessingConfiguration:
+        TemplateConfiguration.Builder mpc = new TemplateConfiguration.Builder();
+
+        mpc.removeCustomAttribute(KEY_1);
+        assertEquals(0, mpc.getCustomAttributeNames().length);
+        assertNull(mpc.getCustomAttribute(KEY_1));
+
+        mpc.setCustomAttribute(KEY_1, VALUE_1);
+        assertArrayEquals(new String[] { KEY_1 }, mpc.getCustomAttributeNames());
+        assertSame(VALUE_1, mpc.getCustomAttribute(KEY_1));
+    }
+
+    @Test
+    public void testAttrsFromFtlHeaderOnly() throws Exception {
+        Template t = new Template(null, "<#ftl attributes={"
+                + "'" + KEY_1 + "': [ 's', 2, true, {  'a': 'A' } ], "
+                + "'" + KEY_2 + "': " + VALUE_BIGDECIMAL + " "
+                + "}>",
+                new Configuration.Builder(Configuration.VERSION_3_0_0).build());
+
+        assertEquals(ImmutableSet.of(KEY_1, KEY_2), t.getCustomAttributes().keySet());
+        assertEquals(VALUE_LIST, t.getCustomAttribute(KEY_1));
+        assertEquals(VALUE_BIGDECIMAL, t.getCustomAttribute(KEY_2));
+
+        t.setCustomAttribute(KEY_1, VALUE_1);
+        assertEquals(VALUE_1, t.getCustomAttribute(KEY_1));
+        assertEquals(VALUE_BIGDECIMAL, t.getCustomAttribute(KEY_2));
+
+        t.setCustomAttribute(KEY_1, null);
+        assertEquals(ImmutableSet.of(KEY_1, KEY_2), t.getCustomAttributes().keySet());
+        assertNull(t.getCustomAttribute(KEY_1));
+    }
+
+    @Test
+    public void testAttrsFromFtlHeaderAndFromTemplateConfiguration() throws Exception {
+        TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
+        tcb.setCustomAttribute(KEY_3, VALUE_3);
+        tcb.setCustomAttribute(KEY_4, VALUE_4);
+        Template t = new Template(null, "<#ftl attributes={"
+                + "'" + KEY_1 + "': 'a', "
+                + "'" + KEY_2 + "': 'b', "
+                + "'" + KEY_3 + "': 'c' "
+                + "}>",
+                new Configuration.Builder(Configuration.VERSION_3_0_0).build(),
+                tcb.build());
+
+        assertEquals(ImmutableSet.of(KEY_1, KEY_2, KEY_3, KEY_4), t.getCustomAttributes().keySet());
+        assertEquals("a", t.getCustomAttribute(KEY_1));
+        assertEquals("b", t.getCustomAttribute(KEY_2));
+        assertEquals("c", t.getCustomAttribute(KEY_3)); // Has overridden TC attribute
+        assertEquals(VALUE_4, t.getCustomAttribute(KEY_4)); // Inherited TC attribute
+
+        t.setCustomAttribute(KEY_3, null);
+        assertEquals(ImmutableSet.of(KEY_1, KEY_2, KEY_3, KEY_4), t.getCustomAttributes().keySet());
+        assertNull("null value shouldn't cause fallback to TC attribute", t.getCustomAttribute(KEY_3));
+    }
+
+
+    @Test
+    public void testAttrsFromTemplateConfigurationOnly() throws Exception {
+        TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
+        tcb.setCustomAttribute(KEY_3, VALUE_3);
+        tcb.setCustomAttribute(KEY_4, VALUE_4);
+        Template t = new Template(null, "",
+                new Configuration.Builder(Configuration.VERSION_3_0_0).build(),
+                tcb.build());
+
+        assertEquals(ImmutableSet.of(KEY_3, KEY_4), t.getCustomAttributes().keySet());
+        assertEquals(VALUE_3, t.getCustomAttribute(KEY_3));
+        assertEquals(VALUE_4, t.getCustomAttribute(KEY_4));
+    }
+
+    private Object[] sort(String[] customAttributeNames) {
+        Arrays.sort(customAttributeNames);
+        return customAttributeNames;
+    }
+
+}


[17/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/SettingDirectiveTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/SettingDirectiveTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/SettingDirectiveTest.java
deleted file mode 100644
index 3b59e78..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/SettingDirectiveTest.java
+++ /dev/null
@@ -1,40 +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;
-
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
-import org.junit.Test;
-
-public class SettingDirectiveTest {
-
-    @Test
-    public void testGetSettingNamesSorted() throws Exception {
-        String prevName = null;
-        for (String name : ASTDirSetting.SETTING_NAMES) {
-            if (prevName != null) {
-                assertThat(name, greaterThan(prevName));
-            }
-            prevName = name;
-        }
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/SpecialVariableTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/SpecialVariableTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/SpecialVariableTest.java
deleted file mode 100644
index 7e17fc7..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/SpecialVariableTest.java
+++ /dev/null
@@ -1,114 +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;
-
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
-import org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat;
-import org.apache.freemarker.core.outputformat.impl.PlainTextOutputFormat;
-import org.apache.freemarker.core.outputformat.impl.UndefinedOutputFormat;
-import org.apache.freemarker.test.TemplateTest;
-import org.junit.Test;
-
-public class SpecialVariableTest extends TemplateTest {
-
-    @Test
-    public void testNamesSorted() throws Exception {
-        String prevName = null;
-        for (String name : ASTExpBuiltInVariable.SPEC_VAR_NAMES) {
-            if (prevName != null) {
-                assertThat(name, greaterThan(prevName));
-            }
-            prevName = name;
-        }
-    }
-    
-    @Test
-    public void testVersion() throws Exception {
-        String versionStr = Configuration.getVersion().toString();
-        assertOutput("${.version}", versionStr);
-    }
-
-    @Test
-    public void testIncompationImprovements() throws Exception {
-        setConfiguration(new Configuration.Builder(Configuration.VERSION_3_0_0).build());
-        assertOutput(
-                "${.incompatibleImprovements}",
-                getConfiguration().getIncompatibleImprovements().toString());
-        
-        setConfiguration(new Configuration.Builder(Configuration.getVersion()).build());
-        assertOutput(
-                "${.incompatible_improvements}",
-                getConfiguration().getIncompatibleImprovements().toString());
-    }
-
-    @Test
-    public void testAutoEsc() throws Exception {
-        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
-
-        for (int autoEscaping : new int[] {
-                ParsingConfiguration.ENABLE_IF_DEFAULT_AUTO_ESCAPING_POLICY, ParsingConfiguration.ENABLE_IF_SUPPORTED_AUTO_ESCAPING_POLICY }) {
-            cfgB.setAutoEscapingPolicy(autoEscaping);
-            cfgB.setOutputFormat(HTMLOutputFormat.INSTANCE);
-            setConfiguration(cfgB.build());
-            assertOutput("${.autoEsc?c}", "true");
-            assertOutput("<#ftl autoEsc=false>${.autoEsc?c}", "false");
-
-            cfgB.setOutputFormat(PlainTextOutputFormat.INSTANCE);
-            setConfiguration(cfgB.build());
-            assertOutput("${.autoEsc?c}", "false");
-
-            cfgB.setOutputFormat(UndefinedOutputFormat.INSTANCE);
-            setConfiguration(cfgB.build());
-            assertOutput("${.autoEsc?c}", "false");
-        }
-        
-        cfgB.setAutoEscapingPolicy(ParsingConfiguration.DISABLE_AUTO_ESCAPING_POLICY);
-        cfgB.setOutputFormat(HTMLOutputFormat.INSTANCE);
-        setConfiguration(cfgB.build());
-        assertOutput("${.autoEsc?c}", "false");
-        assertOutput("<#ftl autoEsc=true>${.autoEsc?c}", "true");
-
-        cfgB.setOutputFormat(PlainTextOutputFormat.INSTANCE);
-        setConfiguration(cfgB.build());
-        assertOutput("${.autoEsc?c}", "false");
-
-        cfgB.setOutputFormat(UndefinedOutputFormat.INSTANCE);
-        setConfiguration(cfgB.build());
-        assertOutput("${.autoEsc?c}", "false");
-
-        cfgB.setAutoEscapingPolicy(ParsingConfiguration.ENABLE_IF_DEFAULT_AUTO_ESCAPING_POLICY);
-        setConfiguration(cfgB.build());
-        assertOutput(
-                "${.autoEsc?c} "
-                + "<#outputFormat 'HTML'>${.autoEsc?c}</#outputFormat> "
-                + "<#outputFormat 'undefined'>${.autoEsc?c}</#outputFormat> "
-                + "<#outputFormat 'HTML'>"
-                + "${.autoEsc?c} <#noAutoEsc>${.autoEsc?c} "
-                + "<#autoEsc>${.autoEsc?c}</#autoEsc> ${.autoEsc?c}</#noAutoEsc> ${.autoEsc?c}"
-                + "</#outputFormat>",
-                "false true false "
-                + "true false true false true");
-        
-        assertErrorContains("${.autoEscaping}", "You may meant: \"autoEsc\"");
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/StringLiteralInterpolationTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/StringLiteralInterpolationTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/StringLiteralInterpolationTest.java
deleted file mode 100644
index ae72dac..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/StringLiteralInterpolationTest.java
+++ /dev/null
@@ -1,135 +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;
-
-import java.io.IOException;
-import java.util.Collections;
-
-import org.apache.freemarker.core.outputformat.impl.RTFOutputFormat;
-import org.apache.freemarker.core.userpkg.PrintfGTemplateNumberFormatFactory;
-import org.apache.freemarker.core.valueformat.TemplateNumberFormatFactory;
-import org.apache.freemarker.test.TemplateTest;
-import org.apache.freemarker.test.TestConfigurationBuilder;
-import org.junit.Test;
-
-@SuppressWarnings("boxing")
-public class StringLiteralInterpolationTest extends TemplateTest {
-
-    @Test
-    public void basics() throws IOException, TemplateException {
-        addToDataModel("x", 1);
-        assertOutput("${'${x}'}", "1");
-        assertOutput("${'#{x}'}", "1");
-        assertOutput("${'a${x}b${x*2}c'}", "a1b2c");
-        assertOutput("${'a#{x}b#{x*2}c'}", "a1b2c");
-        assertOutput("${'a#{x; m2}'}", "a1.00");
-        assertOutput("${'${x} ${x}'}", "1 1");
-        assertOutput("${'$\\{x}'}", "${x}");
-        assertOutput("${'$\\{x} $\\{x}'}", "${x} ${x}");
-        assertOutput("${'<#-- not a comment -->${x}'}", "<#-- not a comment -->1");
-        assertOutput("${'<#-- not a comment -->$\\{x}'}", "<#-- not a comment -->${x}");
-        assertOutput("${'<#assign x = 2> ${x} <#assign x = 2>'}", "<#assign x = 2> 1 <#assign x = 2>");
-        assertOutput("${'<#assign x = 2> $\\{x} <#assign x = 2>'}", "<#assign x = 2> ${x} <#assign x = 2>");
-        assertOutput("${'<@x/>${x}<@x/>'}", "<@x/>1<@x/>");
-        assertOutput("${'<@x/>$\\{x}<@x/>'}", "<@x/>${x}<@x/>");
-        assertOutput("${'<@ ${x}<@'}", "<@ 1<@");
-        assertOutput("${'<@ $\\{x}<@'}", "<@ ${x}<@");
-        assertOutput("${'</...@x>${x}'}", "</...@x>1");
-        assertOutput("${'</...@x>$\\{x}'}", "</...@x>${x}");
-        assertOutput("${'</@ ${x}</@'}", "</@ 1</@");
-        assertOutput("${'</@ $\\{x}</@'}", "</@ ${x}</@");
-        assertOutput("${'[@ ${x}'}", "[@ 1");
-        assertOutput("${'[@ $\\{x}'}", "[@ ${x}");
-    }
-
-    /**
-     * Broken behavior for backward compatibility.
-     */
-    @Test
-    public void legacyEscapingBugStillPresent() throws IOException, TemplateException {
-        addToDataModel("x", 1);
-        assertOutput("${'$\\{x} ${x}'}", "1 1");
-        assertOutput("${'${x} $\\{x}'}", "1 1");
-    }
-    
-    @Test
-    public void legacyLengthGlitch() throws IOException, TemplateException {
-        assertOutput("${'${'}", "${");
-        assertOutput("${'${1'}", "${1");
-        assertOutput("${'${}'}", "${}");
-        assertOutput("${'${1}'}", "1");
-        assertErrorContains("${'${  '}", "");
-    }
-    
-    @Test
-    public void testErrors() {
-        addToDataModel("x", 1);
-        assertErrorContains("${'${noSuchVar}'}", InvalidReferenceException.class, "missing", "noSuchVar");
-        assertErrorContains("${'${x/0}'}", ArithmeticException.class, "zero");
-    }
-
-    @Test
-    public void escaping() throws IOException, TemplateException {
-        assertOutput("<#escape x as x?html><#assign x = '&'>${x} ${'${x}'}</#escape> ${x}", "&amp; &amp; &");
-    }
-    
-    // We couldn't test this on 3.0.0, as nothing was fixed there with IcI yet
-    /*-
-    @Test
-    public void iciInheritanceBugFixed() throws Exception {
-        // Broken behavior emulated:
-        getConfiguration().setIncompatibleImprovements(Configuration.VERSION_2_3_23);
-        assertOutput("${'&\\''?html} ${\"${'&\\\\\\''?html}\"}", "&amp;&#39; &amp;'");
-        
-        // Fix enabled:
-        getConfiguration().setIncompatibleImprovements(Configuration.VERSION_2_3_24);
-        assertOutput("${'&\\''?html} ${\"${'&\\\\\\''?html}\"}", "&amp;&#39; &amp;&#39;");
-    }
-    */
-    
-    @Test
-    public void markup() throws IOException, TemplateException {
-        setConfiguration(new TestConfigurationBuilder()
-                .customNumberFormats(Collections.<String, TemplateNumberFormatFactory>singletonMap(
-                        "G", PrintfGTemplateNumberFormatFactory.INSTANCE))
-                .numberFormat("@G 3")
-                .build());
-
-        assertOutput("${\"${1000}\"}", "1.00*10<sup>3</sup>");
-        assertOutput("${\"&_${1000}\"}", "&amp;_1.00*10<sup>3</sup>");
-        assertOutput("${\"${1000}_&\"}", "1.00*10<sup>3</sup>_&amp;");
-        assertOutput("${\"${1000}, ${2000}\"}", "1.00*10<sup>3</sup>, 2.00*10<sup>3</sup>");
-        assertOutput("${\"& ${'x'}, ${2000}\"}", "&amp; x, 2.00*10<sup>3</sup>");
-        assertOutput("${\"& ${'x'}, #{2000}\"}", "& x, 2000");
-        
-        assertOutput("${\"${2000}\"?isMarkupOutput?c}", "true");
-        assertOutput("${\"x ${2000}\"?isMarkupOutput?c}", "true");
-        assertOutput("${\"${2000} x\"?isMarkupOutput?c}", "true");
-        assertOutput("${\"#{2000}\"?isMarkupOutput?c}", "false");
-        assertOutput("${\"${'x'}\"?isMarkupOutput?c}", "false");
-        assertOutput("${\"x ${'x'}\"?isMarkupOutput?c}", "false");
-        assertOutput("${\"${'x'} x\"?isMarkupOutput?c}", "false");
-        
-        addToDataModel("rtf", RTFOutputFormat.INSTANCE.fromMarkup("\\p"));
-        assertOutput("${\"${rtf}\"?isMarkupOutput?c}", "true");
-        assertErrorContains("${\"${1000}${rtf}\"}", TemplateException.class, "HTML", "RTF", "onversion");
-        assertErrorContains("x${\"${1000}${rtf}\"}", TemplateException.class, "HTML", "RTF", "onversion");
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/TabSizeTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/TabSizeTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/TabSizeTest.java
deleted file mode 100644
index 7945b5e..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/TabSizeTest.java
+++ /dev/null
@@ -1,91 +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;
-
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-
-import org.apache.freemarker.test.TemplateTest;
-import org.apache.freemarker.test.TestConfigurationBuilder;
-import org.junit.Test;
-
-public class TabSizeTest extends TemplateTest {
-
-    @Override
-    protected Configuration createDefaultConfiguration() throws Exception {
-        return super.createDefaultConfiguration();
-    }
-
-    @Test
-    public void testBasics() throws Exception {
-        assertErrorColumnNumber(3, "${*}");
-        assertErrorColumnNumber(8 + 3, "\t${*}");
-        assertErrorColumnNumber(16 + 3, "\t\t${*}");
-        assertErrorColumnNumber(16 + 3, "  \t  \t${*}");
-
-        setConfiguration(new TestConfigurationBuilder().tabSize(1).build());
-        assertErrorColumnNumber(3, "${*}");
-        assertErrorColumnNumber(1 + 3, "\t${*}");
-        assertErrorColumnNumber(2 + 3, "\t\t${*}");
-        assertErrorColumnNumber(6 + 3, "  \t  \t${*}");
-    }
-    
-    @Test
-    public void testEvalBI() throws Exception {
-        assertErrorContains("${r'\t~'?eval}", "column 9");
-        setConfiguration(new TestConfigurationBuilder().tabSize(4).build());
-        assertErrorContains("${r'\t~'?eval}", "column 5");
-    }
-
-    @Test
-    public void testInterpretBI() throws Exception {
-        assertErrorContains("<@'\\t$\\{*}'?interpret />", "column 11");
-        setConfiguration(new TestConfigurationBuilder().tabSize(4).build());
-        assertErrorContains("<@'\\t$\\{*}'?interpret />", "column 7");
-    }
-    
-    @Test
-    public void testStringLiteralInterpolation() throws Exception {
-        assertErrorColumnNumber(6, "${'${*}'}");
-        assertErrorColumnNumber(9, "${'${\t*}'}");
-        setConfiguration(new TestConfigurationBuilder().tabSize(16).build());
-        assertErrorColumnNumber(17, "${'${\t*}'}");
-    }
-
-    protected void assertErrorColumnNumber(int expectedColumn, String templateSource)
-            throws IOException {
-        addTemplate("t", templateSource);
-        try {
-            getConfiguration().getTemplate("t");
-            fail();
-        } catch (ParseException e) {
-            assertEquals(expectedColumn, e.getColumnNumber());
-        }
-        getConfiguration().clearTemplateCache();
-        
-        try {
-            new Template(null, templateSource, getConfiguration());
-            fail();
-        } catch (ParseException e) {
-            assertEquals(expectedColumn, e.getColumnNumber());
-        }
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/TagSyntaxVariationsTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/TagSyntaxVariationsTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/TagSyntaxVariationsTest.java
deleted file mode 100644
index fa21c76..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/TagSyntaxVariationsTest.java
+++ /dev/null
@@ -1,186 +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;
-
-import java.io.IOException;
-import java.io.StringReader;
-import java.io.StringWriter;
-
-import org.apache.freemarker.core.util._StringUtil;
-import org.apache.freemarker.test.TestConfigurationBuilder;
-
-import junit.framework.TestCase;
-
-/**
- * Test various generated templates (permutations), including some deliberately
- * wrong ones, with various tag_syntax settings.  
- */
-public class TagSyntaxVariationsTest extends TestCase {
-    
-    private static final String HDR_ANG = "<#ftl>";
-    private static final String HDR_SQU = squarify(HDR_ANG);
-    private static final String IF_ANG = "<#if true>i</#if>";
-    private static final String IF_SQU = squarify(IF_ANG);
-    private static final String IF_OUT = "i";
-    private static final String ASSIGN_ANG = "<#assign x = 1>a";
-    private static final String ASSIGN_SQU = squarify(ASSIGN_ANG);
-    private static final String ASSIGN_OUT = "a";
-    private static final String WRONG_ANG = "<#wrong>";
-    private static final String WRONG_SQU = squarify(WRONG_ANG);
-    private static final String WRONGC_ANG = "</#wrong>";
-    private static final String WRONGC_SQU = squarify(WRONGC_ANG );
-    private static final String CUST_ANG = "<@compress> z </@>";
-    private static final String CUST_SQU = squarify(CUST_ANG);
-    private static final String CUST_OUT = "z";
-    
-    public TagSyntaxVariationsTest(String name) {
-        super(name);
-    }
-    
-    private static String squarify(String s) {
-        return s.replace('<', '[').replace('>', ']');
-    }
-
-    public final void test()
-            throws TemplateException, IOException {
-        // Permutations
-        for (int ifOrAssign = 0; ifOrAssign < 2; ifOrAssign++) {
-            String dir_ang = ifOrAssign == 0 ? IF_ANG : ASSIGN_ANG;
-            String dir_squ = ifOrAssign == 0 ? IF_SQU : ASSIGN_SQU;
-            String dir_out = ifOrAssign == 0 ? IF_OUT : ASSIGN_OUT;
-
-            // Permutations 
-            for (int angOrSqu = 0; angOrSqu < 2; angOrSqu++) {
-                Configuration cfg = new TestConfigurationBuilder()
-                        .tagSyntax(angOrSqu == 0
-                                ? ParsingConfiguration.ANGLE_BRACKET_TAG_SYNTAX
-                                : ParsingConfiguration.SQUARE_BRACKET_TAG_SYNTAX)
-                        .build();
-
-                String dir_xxx = angOrSqu == 0 ? dir_ang : dir_squ;
-                String cust_xxx = angOrSqu == 0 ? CUST_ANG : CUST_SQU;
-                String hdr_xxx = angOrSqu == 0 ? HDR_ANG : HDR_SQU;
-                String wrong_xxx = angOrSqu == 0 ? WRONG_ANG : WRONG_SQU;
-                String wrongc_xxx = angOrSqu == 0 ? WRONGC_ANG : WRONGC_SQU;
-
-                test(cfg,
-                        dir_xxx + cust_xxx,
-                        dir_out + CUST_OUT);
-
-                // Permutations 
-                for (int wrongOrWrongc = 0; wrongOrWrongc < 2; wrongOrWrongc++) {
-                    String wrongx_xxx = wrongOrWrongc == 0 ? wrong_xxx : wrongc_xxx;
-
-                    test(cfg,
-                            wrongx_xxx + dir_xxx,
-                            null);
-
-                    test(cfg,
-                            dir_xxx + wrongx_xxx,
-                            null);
-
-                    test(cfg,
-                            hdr_xxx + wrongx_xxx,
-                            null);
-
-                    test(cfg,
-                            cust_xxx + wrongx_xxx + dir_xxx,
-                            null);
-                } // for wrongc
-            } // for squ
-
-            {
-                Configuration cfg = new TestConfigurationBuilder()
-                        .tagSyntax(ParsingConfiguration.AUTO_DETECT_TAG_SYNTAX)
-                        .build();
-                for (int perm = 0; perm < 4; perm++) {
-                    // All 4 permutations
-                    String wrong_xxx = (perm & 1) == 0 ? WRONG_ANG : WRONG_SQU;
-                    String dir_xxx = (perm & 2) == 0 ? dir_ang : dir_squ;
-
-                    test(cfg,
-                            wrong_xxx + dir_xxx,
-                            null);
-                } // for perm
-            }
-
-            {
-                Configuration cfg = new TestConfigurationBuilder()
-                        .tagSyntax(ParsingConfiguration.AUTO_DETECT_TAG_SYNTAX)
-                        .build();
-                // Permutations
-                for (int angOrSquStart = 0; angOrSquStart < 2; angOrSquStart++) {
-                    String hdr_xxx = angOrSquStart == 0 ? HDR_ANG : HDR_SQU;
-                    String cust_xxx = angOrSquStart == 0 ? CUST_ANG : CUST_SQU;
-                    String wrong_yyy = angOrSquStart != 0 ? WRONG_ANG : WRONG_SQU;
-                    String dir_xxx = angOrSquStart == 0 ? dir_ang : dir_squ;
-                    String dir_yyy = angOrSquStart != 0 ? dir_ang : dir_squ;
-
-                    test(cfg,
-                            cust_xxx + wrong_yyy + dir_xxx,
-                            CUST_OUT + wrong_yyy + dir_out);
-
-                    test(cfg,
-                            hdr_xxx + wrong_yyy + dir_xxx,
-                            wrong_yyy + dir_out);
-
-                    test(cfg,
-                            cust_xxx + wrong_yyy + dir_yyy,
-                            CUST_OUT + wrong_yyy + dir_yyy);
-
-                    test(cfg,
-                            hdr_xxx + wrong_yyy + dir_yyy,
-                            wrong_yyy + dir_yyy);
-
-                    test(cfg,
-                            dir_xxx + wrong_yyy + dir_yyy,
-                            dir_out + wrong_yyy + dir_yyy);
-                } // for squStart
-            } // for assign
-        }
-    }
-    
-    /**
-     * @param expected the expected output or <tt>null</tt> if we expect
-     * a parsing error.
-     */
-    private static void test(
-            Configuration cfg, String template, String expected)
-            throws TemplateException, IOException {
-        Template t = null;
-        try {
-            t = new Template("string", new StringReader(template), cfg);
-        } catch (ParseException e) {
-            if (expected != null) {
-                fail("Couldn't invoke Template from "
-                        + _StringUtil.jQuote(template) + ": " + e);
-            } else {
-                return;
-            }
-        }
-        if (expected == null) fail("Template parsing should have fail for "
-                + _StringUtil.jQuote(template));
-        
-        StringWriter out = new StringWriter();
-        t.process(new Object(), out);
-        assertEquals(expected, out.toString());
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/TemplateConfigurationTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/TemplateConfigurationTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/TemplateConfigurationTest.java
deleted file mode 100644
index 5b1cda9..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/TemplateConfigurationTest.java
+++ /dev/null
@@ -1,909 +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;
-
-import static org.junit.Assert.*;
-
-import java.beans.BeanInfo;
-import java.beans.IntrospectionException;
-import java.beans.Introspector;
-import java.beans.PropertyDescriptor;
-import java.io.IOException;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-import java.util.TimeZone;
-
-import org.apache.commons.collections.ListUtils;
-import org.apache.freemarker.core.arithmetic.ArithmeticEngine;
-import org.apache.freemarker.core.arithmetic.impl.ConservativeArithmeticEngine;
-import org.apache.freemarker.core.model.impl.RestrictedObjectWrapper;
-import org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat;
-import org.apache.freemarker.core.outputformat.impl.UndefinedOutputFormat;
-import org.apache.freemarker.core.outputformat.impl.XMLOutputFormat;
-import org.apache.freemarker.core.templateresolver.ConditionalTemplateConfigurationFactory;
-import org.apache.freemarker.core.templateresolver.FileExtensionMatcher;
-import org.apache.freemarker.core.templateresolver.FileNameGlobMatcher;
-import org.apache.freemarker.core.templateresolver.impl.StringTemplateLoader;
-import org.apache.freemarker.core.userpkg.BaseNTemplateNumberFormatFactory;
-import org.apache.freemarker.core.userpkg.EpochMillisDivTemplateDateFormatFactory;
-import org.apache.freemarker.core.userpkg.EpochMillisTemplateDateFormatFactory;
-import org.apache.freemarker.core.userpkg.HexTemplateNumberFormatFactory;
-import org.apache.freemarker.core.userpkg.LocAndTZSensitiveTemplateDateFormatFactory;
-import org.apache.freemarker.core.userpkg.LocaleSensitiveTemplateNumberFormatFactory;
-import org.apache.freemarker.core.valueformat.TemplateDateFormatFactory;
-import org.apache.freemarker.core.valueformat.TemplateNumberFormatFactory;
-import org.apache.freemarker.test.MonitoredTemplateLoader;
-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 TemplateConfigurationTest {
-
-    private static final Charset ISO_8859_2 = Charset.forName("ISO-8859-2");
-
-    private final class DummyArithmeticEngine extends ArithmeticEngine {
-
-        @Override
-        public int compareNumbers(Number first, Number second) throws TemplateException {
-            return 0;
-        }
-
-        @Override
-        public Number add(Number first, Number second) throws TemplateException {
-            return 22;
-        }
-
-        @Override
-        public Number subtract(Number first, Number second) throws TemplateException {
-            return null;
-        }
-
-        @Override
-        public Number multiply(Number first, Number second) throws TemplateException {
-            return 33;
-        }
-
-        @Override
-        public Number divide(Number first, Number second) throws TemplateException {
-            return null;
-        }
-
-        @Override
-        public Number modulus(Number first, Number second) throws TemplateException {
-            return null;
-        }
-
-        @Override
-        public Number toNumber(String s) {
-            return 11;
-        }
-    }
-
-    private static final Configuration DEFAULT_CFG;
-    static {
-        TestConfigurationBuilder cfgB = new TestConfigurationBuilder();
-        StringTemplateLoader stl = new StringTemplateLoader();
-        stl.putTemplate("t1.ftl", "<#global loaded = (loaded!) + 't1;'>In t1;");
-        stl.putTemplate("t2.ftl", "<#global loaded = (loaded!) + 't2;'>In t2;");
-        stl.putTemplate("t3.ftl", "<#global loaded = (loaded!) + 't3;'>In t3;");
-        try {
-            DEFAULT_CFG = cfgB.templateLoader(stl).build();
-        } catch (ConfigurationException e) {
-            throw new IllegalStateException("Faild to create default configuration", e);
-        }
-    }
-
-    private static final TimeZone NON_DEFAULT_TZ;
-    static {
-        TimeZone defaultTZ = DEFAULT_CFG.getTimeZone();
-        TimeZone tz = TimeZone.getTimeZone("UTC");
-        if (tz.equals(defaultTZ)) {
-            tz = TimeZone.getTimeZone("GMT+01");
-            if (tz.equals(defaultTZ)) {
-                throw new AssertionError("Couldn't chose a non-default time zone");
-            }
-        }
-        NON_DEFAULT_TZ = tz;
-    }
-
-    private static final Locale NON_DEFAULT_LOCALE =
-            DEFAULT_CFG.getLocale().equals(Locale.US) ? Locale.GERMAN : Locale.US;
-
-    private static final Charset NON_DEFAULT_ENCODING =
-            DEFAULT_CFG.getSourceEncoding().equals(StandardCharsets.UTF_8) ? StandardCharsets.UTF_16LE
-                    : StandardCharsets.UTF_8;
-
-    private static final Map<String, Object> SETTING_ASSIGNMENTS;
-
-    static {
-        SETTING_ASSIGNMENTS = new HashMap<>();
-
-        // "MutableProcessingConfiguration" settings:
-        SETTING_ASSIGNMENTS.put("APIBuiltinEnabled", true);
-        SETTING_ASSIGNMENTS.put("SQLDateAndTimeTimeZone", NON_DEFAULT_TZ);
-        SETTING_ASSIGNMENTS.put("URLEscapingCharset", StandardCharsets.UTF_16);
-        SETTING_ASSIGNMENTS.put("autoFlush", false);
-        SETTING_ASSIGNMENTS.put("booleanFormat", "J,N");
-        SETTING_ASSIGNMENTS.put("dateFormat", "yyyy-#DDD");
-        SETTING_ASSIGNMENTS.put("dateTimeFormat", "yyyy-#DDD-@HH:mm");
-        SETTING_ASSIGNMENTS.put("locale", NON_DEFAULT_LOCALE);
-        SETTING_ASSIGNMENTS.put("logTemplateExceptions", true);
-        SETTING_ASSIGNMENTS.put("newBuiltinClassResolver", TemplateClassResolver.ALLOWS_NOTHING_RESOLVER);
-        SETTING_ASSIGNMENTS.put("numberFormat", "0.0000");
-        SETTING_ASSIGNMENTS.put("objectWrapper",
-                new RestrictedObjectWrapper.Builder(Configuration.VERSION_3_0_0).build());
-        SETTING_ASSIGNMENTS.put("outputEncoding", StandardCharsets.UTF_16);
-        SETTING_ASSIGNMENTS.put("showErrorTips", false);
-        SETTING_ASSIGNMENTS.put("templateExceptionHandler", TemplateExceptionHandler.IGNORE_HANDLER);
-        SETTING_ASSIGNMENTS.put("timeFormat", "@HH:mm");
-        SETTING_ASSIGNMENTS.put("timeZone", NON_DEFAULT_TZ);
-        SETTING_ASSIGNMENTS.put("arithmeticEngine", ConservativeArithmeticEngine.INSTANCE);
-        SETTING_ASSIGNMENTS.put("customNumberFormats",
-                ImmutableMap.of("dummy", HexTemplateNumberFormatFactory.INSTANCE));
-        SETTING_ASSIGNMENTS.put("customDateFormats",
-                ImmutableMap.of("dummy", EpochMillisTemplateDateFormatFactory.INSTANCE));
-        SETTING_ASSIGNMENTS.put("customAttributes", ImmutableMap.of("dummy", 123));
-
-        // Parser-only settings:
-        SETTING_ASSIGNMENTS.put("templateLanguage", TemplateLanguage.STATIC_TEXT);
-        SETTING_ASSIGNMENTS.put("tagSyntax", ParsingConfiguration.SQUARE_BRACKET_TAG_SYNTAX);
-        SETTING_ASSIGNMENTS.put("namingConvention", ParsingConfiguration.LEGACY_NAMING_CONVENTION);
-        SETTING_ASSIGNMENTS.put("whitespaceStripping", false);
-        SETTING_ASSIGNMENTS.put("strictSyntaxMode", false);
-        SETTING_ASSIGNMENTS.put("autoEscapingPolicy", ParsingConfiguration.DISABLE_AUTO_ESCAPING_POLICY);
-        SETTING_ASSIGNMENTS.put("outputFormat", HTMLOutputFormat.INSTANCE);
-        SETTING_ASSIGNMENTS.put("recognizeStandardFileExtensions", false);
-        SETTING_ASSIGNMENTS.put("tabSize", 1);
-        SETTING_ASSIGNMENTS.put("lazyImports", Boolean.TRUE);
-        SETTING_ASSIGNMENTS.put("lazyAutoImports", Boolean.FALSE);
-        SETTING_ASSIGNMENTS.put("autoImports", ImmutableMap.of("a", "/lib/a.ftl"));
-        SETTING_ASSIGNMENTS.put("autoIncludes", ImmutableList.of("/lib/b.ftl"));
-        
-        // Special settings:
-        SETTING_ASSIGNMENTS.put("sourceEncoding", NON_DEFAULT_ENCODING);
-    }
-    
-    public static String getIsSetMethodName(String readMethodName) {
-        return (readMethodName.startsWith("get") ? "is" + readMethodName.substring(3)
-                : readMethodName)
-                + "Set";
-    }
-
-    public static List<PropertyDescriptor> getTemplateConfigurationSettingPropDescs(
-            Class<? extends ProcessingConfiguration> confClass, boolean includeCompilerSettings)
-            throws IntrospectionException {
-        List<PropertyDescriptor> settingPropDescs = new ArrayList<>();
-
-        BeanInfo beanInfo = Introspector.getBeanInfo(confClass);
-        for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
-            String name = pd.getName();
-            if (pd.getWriteMethod() != null && !IGNORED_PROP_NAMES.contains(name)
-                    && (includeCompilerSettings
-                            || (CONFIGURABLE_PROP_NAMES.contains(name) || !PARSER_PROP_NAMES.contains(name)))) {
-                if (pd.getReadMethod() == null) {
-                    throw new AssertionError("Property has no read method: " + pd);
-                }
-                settingPropDescs.add(pd);
-            }
-        }
-
-        Collections.sort(settingPropDescs, new Comparator<PropertyDescriptor>() {
-            @Override
-            public int compare(PropertyDescriptor o1, PropertyDescriptor o2) {
-                return o1.getName().compareToIgnoreCase(o2.getName());
-            }
-        });
-
-        return settingPropDescs;
-    }
-
-    private static final Set<String> IGNORED_PROP_NAMES;
-
-    static {
-        IGNORED_PROP_NAMES = new HashSet();
-        IGNORED_PROP_NAMES.add("class");
-        IGNORED_PROP_NAMES.add("strictBeanModels");
-        IGNORED_PROP_NAMES.add("parentConfiguration");
-        IGNORED_PROP_NAMES.add("settings");
-    }
-
-    private static final Set<String> CONFIGURABLE_PROP_NAMES;
-    static {
-        CONFIGURABLE_PROP_NAMES = new HashSet<>();
-        try {
-            for (PropertyDescriptor propDesc : Introspector.getBeanInfo(MutableProcessingConfiguration.class).getPropertyDescriptors()) {
-                String propName = propDesc.getName();
-                if (!IGNORED_PROP_NAMES.contains(propName)) {
-                    CONFIGURABLE_PROP_NAMES.add(propName);
-                }
-            }
-        } catch (IntrospectionException e) {
-            throw new IllegalStateException("Failed to init static field", e);
-        }
-    }
-    
-    private static final Set<String> PARSER_PROP_NAMES;
-    static {
-        PARSER_PROP_NAMES = new HashSet<>();
-        // It's an interface; can't use standard Inrospector
-        for (Method m : ParsingConfiguration.class.getMethods()) {
-            String propertyName;
-            String name = m.getName();
-            if (name.startsWith("get")) {
-                propertyName = name.substring(3);
-            } else if (name.startsWith("is") && !name.endsWith("Set")) {
-                propertyName = name.substring(2);
-            } else {
-                propertyName = null;
-            }
-            if (propertyName != null) {
-                if (!Character.isUpperCase(propertyName.charAt(1))) {
-                    propertyName = Character.toLowerCase(propertyName.charAt(0)) + propertyName.substring(1);
-                }
-                PARSER_PROP_NAMES.add(propertyName);
-            }
-        }
-    }
-
-    private static final Object CA1 = new Object();
-    private static final String CA2 = "ca2";
-    private static final String CA3 = "ca3";
-    private static final String CA4 = "ca4";
-
-    @Test
-    public void testMergeBasicFunctionality() throws Exception {
-        for (PropertyDescriptor propDesc1 : getTemplateConfigurationSettingPropDescs(
-                TemplateConfiguration.Builder.class, true)) {
-            for (PropertyDescriptor propDesc2 : getTemplateConfigurationSettingPropDescs(
-                    TemplateConfiguration.Builder.class, true)) {
-                TemplateConfiguration.Builder tcb1 = new TemplateConfiguration.Builder();
-                TemplateConfiguration.Builder tcb2 = new TemplateConfiguration.Builder();
-
-                Object value1 = SETTING_ASSIGNMENTS.get(propDesc1.getName());
-                propDesc1.getWriteMethod().invoke(tcb1, value1);
-                Object value2 = SETTING_ASSIGNMENTS.get(propDesc2.getName());
-                propDesc2.getWriteMethod().invoke(tcb2, value2);
-
-                tcb1.merge(tcb2);
-                if (propDesc1.getName().equals(propDesc2.getName()) && value1 instanceof List
-                        && !propDesc1.getName().equals("autoIncludes")) {
-                    assertEquals("For " + propDesc1.getName(),
-                            ListUtils.union((List) value1, (List) value1), propDesc1.getReadMethod().invoke(tcb1));
-                } else { // Values of the same setting merged
-                    assertEquals("For " + propDesc1.getName(), value1, propDesc1.getReadMethod().invoke(tcb1));
-                    assertEquals("For " + propDesc2.getName(), value2, propDesc2.getReadMethod().invoke(tcb1));
-                }
-            }
-        }
-    }
-    
-    @Test
-    public void testMergeMapSettings() throws Exception {
-        TemplateConfiguration.Builder tc1 = new TemplateConfiguration.Builder();
-        tc1.setCustomDateFormats(ImmutableMap.of(
-                "epoch", EpochMillisTemplateDateFormatFactory.INSTANCE,
-                "x", LocAndTZSensitiveTemplateDateFormatFactory.INSTANCE));
-        tc1.setCustomNumberFormats(ImmutableMap.of(
-                "hex", HexTemplateNumberFormatFactory.INSTANCE,
-                "x", LocaleSensitiveTemplateNumberFormatFactory.INSTANCE));
-        tc1.setAutoImports(ImmutableMap.of("a", "a1.ftl", "b", "b1.ftl"));
-        
-        TemplateConfiguration.Builder tc2 = new TemplateConfiguration.Builder();
-        tc2.setCustomDateFormats(ImmutableMap.of(
-                "loc", LocAndTZSensitiveTemplateDateFormatFactory.INSTANCE,
-                "x", EpochMillisDivTemplateDateFormatFactory.INSTANCE));
-        tc2.setCustomNumberFormats(ImmutableMap.of(
-                "loc", LocaleSensitiveTemplateNumberFormatFactory.INSTANCE,
-                "x", BaseNTemplateNumberFormatFactory.INSTANCE));
-        tc2.setAutoImports(ImmutableMap.of("b", "b2.ftl", "c", "c2.ftl"));
-        
-        tc1.merge(tc2);
-        
-        Map<String, ? extends TemplateDateFormatFactory> mergedCustomDateFormats = tc1.getCustomDateFormats();
-        assertEquals(EpochMillisTemplateDateFormatFactory.INSTANCE, mergedCustomDateFormats.get("epoch"));
-        assertEquals(LocAndTZSensitiveTemplateDateFormatFactory.INSTANCE, mergedCustomDateFormats.get("loc"));
-        assertEquals(EpochMillisDivTemplateDateFormatFactory.INSTANCE, mergedCustomDateFormats.get("x"));
-        
-        Map<String, ? extends TemplateNumberFormatFactory> mergedCustomNumberFormats = tc1.getCustomNumberFormats();
-        assertEquals(HexTemplateNumberFormatFactory.INSTANCE, mergedCustomNumberFormats.get("hex"));
-        assertEquals(LocaleSensitiveTemplateNumberFormatFactory.INSTANCE, mergedCustomNumberFormats.get("loc"));
-        assertEquals(BaseNTemplateNumberFormatFactory.INSTANCE, mergedCustomNumberFormats.get("x"));
-
-        Map<String, String> mergedAutoImports = tc1.getAutoImports();
-        assertEquals("a1.ftl", mergedAutoImports.get("a"));
-        assertEquals("b2.ftl", mergedAutoImports.get("b"));
-        assertEquals("c2.ftl", mergedAutoImports.get("c"));
-        
-        // Empty map merging optimization:
-        tc1.merge(new TemplateConfiguration.Builder());
-        assertSame(mergedCustomDateFormats, tc1.getCustomDateFormats());
-        assertSame(mergedCustomNumberFormats, tc1.getCustomNumberFormats());
-        
-        // Empty map merging optimization:
-        TemplateConfiguration.Builder tc3 = new TemplateConfiguration.Builder();
-        tc3.merge(tc1);
-        assertSame(mergedCustomDateFormats, tc3.getCustomDateFormats());
-        assertSame(mergedCustomNumberFormats, tc3.getCustomNumberFormats());
-    }
-    
-    @Test
-    public void testMergeListSettings() throws Exception {
-        TemplateConfiguration.Builder tc1 = new TemplateConfiguration.Builder();
-        tc1.setAutoIncludes(ImmutableList.of("a.ftl", "x.ftl", "b.ftl"));
-        
-        TemplateConfiguration.Builder tc2 = new TemplateConfiguration.Builder();
-        tc2.setAutoIncludes(ImmutableList.of("c.ftl", "x.ftl", "d.ftl"));
-        
-        tc1.merge(tc2);
-        
-        assertEquals(ImmutableList.of("a.ftl", "b.ftl", "c.ftl", "x.ftl", "d.ftl"), tc1.getAutoIncludes());
-    }
-    
-    @Test
-    public void testMergePriority() throws Exception {
-        TemplateConfiguration.Builder tc1 = new TemplateConfiguration.Builder();
-        tc1.setDateFormat("1");
-        tc1.setTimeFormat("1");
-        tc1.setDateTimeFormat("1");
-
-        TemplateConfiguration.Builder tc2 = new TemplateConfiguration.Builder();
-        tc2.setDateFormat("2");
-        tc2.setTimeFormat("2");
-
-        TemplateConfiguration.Builder tc3 = new TemplateConfiguration.Builder();
-        tc3.setDateFormat("3");
-
-        tc1.merge(tc2);
-        tc1.merge(tc3);
-
-        assertEquals("3", tc1.getDateFormat());
-        assertEquals("2", tc1.getTimeFormat());
-        assertEquals("1", tc1.getDateTimeFormat());
-    }
-    
-    @Test
-    public void testMergeCustomAttributes() throws Exception {
-        TemplateConfiguration.Builder tc1 = new TemplateConfiguration.Builder();
-        tc1.setCustomAttribute("k1", "v1");
-        tc1.setCustomAttribute("k2", "v1");
-        tc1.setCustomAttribute("k3", "v1");
-        tc1.setCustomAttribute(CA1, "V1");
-        tc1.setCustomAttribute(CA2, "V1");
-        tc1.setCustomAttribute(CA3, "V1");
-
-        TemplateConfiguration.Builder tc2 = new TemplateConfiguration.Builder();
-        tc2.setCustomAttribute("k1", "v2");
-        tc2.setCustomAttribute("k2", "v2");
-        tc2.setCustomAttribute(CA1, "V2");
-        tc2.setCustomAttribute(CA2, "V2");
-
-        TemplateConfiguration.Builder tc3 = new TemplateConfiguration.Builder();
-        tc3.setCustomAttribute("k1", "v3");
-        tc3.setCustomAttribute(CA1, "V3");
-
-        tc1.merge(tc2);
-        tc1.merge(tc3);
-
-        assertEquals("v3", tc1.getCustomAttribute("k1"));
-        assertEquals("v2", tc1.getCustomAttribute("k2"));
-        assertEquals("v1", tc1.getCustomAttribute("k3"));
-        assertEquals("V3", tc1.getCustomAttribute(CA1));
-        assertEquals("V2", tc1.getCustomAttribute(CA2));
-        assertEquals("V1", tc1.getCustomAttribute(CA3));
-    }
-
-    @Test
-    public void testMergeNullCustomAttributes() throws Exception {
-        TemplateConfiguration.Builder tc1 = new TemplateConfiguration.Builder();
-        tc1.setCustomAttribute("k1", "v1");
-        tc1.setCustomAttribute("k2", "v1");
-        tc1.setCustomAttribute(CA1, "V1");
-        tc1.setCustomAttribute(CA2,"V1");
-
-        assertEquals("v1", tc1.getCustomAttribute("k1"));
-        assertEquals("v1", tc1.getCustomAttribute("k2"));
-        assertNull("v1", tc1.getCustomAttribute("k3"));
-        assertEquals("V1", tc1.getCustomAttribute(CA1));
-        assertEquals("V1", tc1.getCustomAttribute(CA2));
-        assertNull(tc1.getCustomAttribute(CA3));
-
-        TemplateConfiguration.Builder tc2 = new TemplateConfiguration.Builder();
-        tc2.setCustomAttribute("k1", "v2");
-        tc2.setCustomAttribute("k2", null);
-        tc2.setCustomAttribute(CA1, "V2");
-        tc2.setCustomAttribute(CA2, null);
-
-        TemplateConfiguration.Builder tc3 = new TemplateConfiguration.Builder();
-        tc3.setCustomAttribute("k1", null);
-        tc2.setCustomAttribute(CA1, null);
-
-        tc1.merge(tc2);
-        tc1.merge(tc3);
-
-        assertNull(tc1.getCustomAttribute("k1"));
-        assertNull(tc1.getCustomAttribute("k2"));
-        assertNull(tc1.getCustomAttribute("k3"));
-        assertNull(tc1.getCustomAttribute(CA1));
-        assertNull(tc1.getCustomAttribute(CA2));
-        assertNull(tc1.getCustomAttribute(CA3));
-
-        TemplateConfiguration.Builder tc4 = new TemplateConfiguration.Builder();
-        tc4.setCustomAttribute("k1", "v4");
-        tc4.setCustomAttribute(CA1, "V4");
-
-        tc1.merge(tc4);
-
-        assertEquals("v4", tc1.getCustomAttribute("k1"));
-        assertNull(tc1.getCustomAttribute("k2"));
-        assertNull(tc1.getCustomAttribute("k3"));
-        assertEquals("V4", tc1.getCustomAttribute(CA1));
-        assertNull(tc1.getCustomAttribute(CA2));
-        assertNull(tc1.getCustomAttribute(CA3));
-    }
-
-    @Test
-    public void testConfigureNonParserConfig() throws Exception {
-        for (PropertyDescriptor pd : getTemplateConfigurationSettingPropDescs(
-                TemplateConfiguration.Builder.class, false)) {
-            TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
-
-            Object newValue = SETTING_ASSIGNMENTS.get(pd.getName());
-            pd.getWriteMethod().invoke(tcb, newValue);
-            
-            TemplateConfiguration tc = tcb.build();
-
-            Method tReaderMethod = Template.class.getMethod(pd.getReadMethod().getName());
-
-            // Without TC
-            assertNotEquals("For \"" + pd.getName() + "\"",
-                    tReaderMethod.invoke(new Template(null, "", DEFAULT_CFG)));
-            // With TC
-            assertEquals("For \"" + pd.getName() + "\"", newValue,
-                    tReaderMethod.invoke(new Template(null, "", DEFAULT_CFG, tc)));
-        }
-    }
-    
-    @Test
-    public void testConfigureCustomAttributes() throws Exception {
-        Configuration cfg = new TestConfigurationBuilder()
-                .customAttribute("k1", "c")
-                .customAttribute("k2", "c")
-                .customAttribute("k3", "c")
-                .build();
-
-        TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
-        tcb.setCustomAttribute("k2", "tc");
-        tcb.setCustomAttribute("k3", null);
-        tcb.setCustomAttribute("k4", "tc");
-        tcb.setCustomAttribute("k5", "tc");
-        tcb.setCustomAttribute("k6", "tc");
-        tcb.setCustomAttribute(CA1, "tc");
-        tcb.setCustomAttribute(CA2,"tc");
-        tcb.setCustomAttribute(CA3,"tc");
-
-        TemplateConfiguration tc = tcb.build();
-        Template t = new Template(null, "", cfg, tc);
-        t.setCustomAttribute("k5", "t");
-        t.setCustomAttribute("k6", null);
-        t.setCustomAttribute("k7", "t");
-        t.setCustomAttribute(CA2, "t");
-        t.setCustomAttribute(CA3, null);
-        t.setCustomAttribute(CA4, "t");
-
-        assertEquals("c", t.getCustomAttribute("k1"));
-        assertEquals("tc", t.getCustomAttribute("k2"));
-        assertNull(t.getCustomAttribute("k3"));
-        assertEquals("tc", t.getCustomAttribute("k4"));
-        assertEquals("t", t.getCustomAttribute("k5"));
-        assertNull(t.getCustomAttribute("k6"));
-        assertEquals("t", t.getCustomAttribute("k7"));
-        assertEquals("tc", t.getCustomAttribute(CA1));
-        assertEquals("t", t.getCustomAttribute(CA2));
-        assertNull(t.getCustomAttribute(CA3));
-        assertEquals("t", t.getCustomAttribute(CA4));
-    }
-    
-    @Test
-    public void testConfigureParser() throws Exception {
-        Set<String> testedProps = new HashSet<>();
-        
-        {
-            TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
-            tcb.setTagSyntax(ParsingConfiguration.SQUARE_BRACKET_TAG_SYNTAX);
-            TemplateConfiguration tc = tcb.build();
-            assertOutputWithoutAndWithTC(tc, "[#if true]y[/#if]", "[#if true]y[/#if]", "y");
-            testedProps.add(Configuration.ExtendableBuilder.TAG_SYNTAX_KEY_CAMEL_CASE);
-        }
-        
-        {
-            TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
-            tcb.setNamingConvention(ParsingConfiguration.CAMEL_CASE_NAMING_CONVENTION);
-            TemplateConfiguration tc = tcb.build();
-            assertOutputWithoutAndWithTC(tc, "<#if true>y<#elseif false>n</#if>", "y", null);
-            testedProps.add(Configuration.ExtendableBuilder.NAMING_CONVENTION_KEY_CAMEL_CASE);
-        }
-        
-        {
-            TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
-            tcb.setWhitespaceStripping(false);
-            TemplateConfiguration tc = tcb.build();
-            assertOutputWithoutAndWithTC(tc, "<#if true>\nx\n</#if>\n", "x\n", "\nx\n\n");
-            testedProps.add(Configuration.ExtendableBuilder.WHITESPACE_STRIPPING_KEY_CAMEL_CASE);
-        }
-
-        {
-            TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
-            tcb.setArithmeticEngine(new DummyArithmeticEngine());
-            TemplateConfiguration tc = tcb.build();
-            assertOutputWithoutAndWithTC(tc, "${1} ${1+1}", "1 2", "11 22");
-            testedProps.add(Configuration.ExtendableBuilder.ARITHMETIC_ENGINE_KEY_CAMEL_CASE);
-        }
-
-        {
-            TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
-            tcb.setOutputFormat(XMLOutputFormat.INSTANCE);
-            TemplateConfiguration tc = tcb.build();
-            assertOutputWithoutAndWithTC(tc, "${.outputFormat} ${\"a'b\"}",
-                    UndefinedOutputFormat.INSTANCE.getName() + " a'b",
-                    XMLOutputFormat.INSTANCE.getName() + " a&apos;b");
-            testedProps.add(Configuration.ExtendableBuilder.OUTPUT_FORMAT_KEY_CAMEL_CASE);
-        }
-
-        {
-            TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
-            tcb.setOutputFormat(XMLOutputFormat.INSTANCE);
-            tcb.setAutoEscapingPolicy(ParsingConfiguration.DISABLE_AUTO_ESCAPING_POLICY);
-            TemplateConfiguration tc = tcb.build();
-            assertOutputWithoutAndWithTC(tc, "${'a&b'}", "a&b", "a&b");
-            testedProps.add(Configuration.ExtendableBuilder.AUTO_ESCAPING_POLICY_KEY_CAMEL_CASE);
-        }
-        
-        {
-            TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
-            /* Can't test this now, as the only valid value is 3.0.0. [FM3.0.1]
-            TemplateConfiguration tc = tcb.build();
-            tc.setParentConfiguration(new Configuration(new Version(2, 3, 0)));
-            assertOutputWithoutAndWithTC(tc, "<#foo>", null, "<#foo>");
-            */
-            testedProps.add(Configuration.ExtendableBuilder.INCOMPATIBLE_IMPROVEMENTS_KEY_CAMEL_CASE);
-        }
-
-        {
-            TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
-            tcb.setRecognizeStandardFileExtensions(false);
-            TemplateConfiguration tc = tcb.build();
-            assertOutputWithoutAndWithTC(tc, "adhoc.ftlh", "${.outputFormat}",
-                    HTMLOutputFormat.INSTANCE.getName(), UndefinedOutputFormat.INSTANCE.getName());
-            testedProps.add(Configuration.ExtendableBuilder.RECOGNIZE_STANDARD_FILE_EXTENSIONS_KEY_CAMEL_CASE);
-        }
-
-        {
-            TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
-            tcb.setLogTemplateExceptions(false);
-            tcb.setTabSize(3);
-            TemplateConfiguration tc = tcb.build();
-            assertOutputWithoutAndWithTC(tc,
-                    "<#attempt><@'\\t$\\{1+}'?interpret/><#recover>"
-                    + "${.error?replace('(?s).*?column ([0-9]+).*', '$1', 'r')}"
-                    + "</#attempt>",
-                    "13", "8");
-            testedProps.add(Configuration.ExtendableBuilder.TAB_SIZE_KEY_CAMEL_CASE);
-        }
-
-        {
-            // As the TemplateLanguage-based parser selection happens in the TemplateResolver, we can't use
-            // assertOutput here, as that hard-coded to create an FTL Template.
-
-            TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
-            tcb.setTemplateLanguage(TemplateLanguage.STATIC_TEXT);
-
-            TestConfigurationBuilder cfgB = new TestConfigurationBuilder();
-            cfgB.setTemplateConfigurations(
-                    new ConditionalTemplateConfigurationFactory(new FileExtensionMatcher("txt"), tcb.build()));
-
-            StringTemplateLoader templateLoader = new StringTemplateLoader();
-            templateLoader.putTemplate("adhoc.ftl", "${1+1}");
-            templateLoader.putTemplate("adhoc.txt", "${1+1}");
-            cfgB.setTemplateLoader(templateLoader);
-
-            Configuration cfg = cfgB.build();
-            
-            {
-                StringWriter out = new StringWriter();
-                cfg.getTemplate("adhoc.ftl").process(null, out);
-                assertEquals("2", out.toString());
-            }
-            {
-                StringWriter out = new StringWriter();
-                cfg.getTemplate("adhoc.txt").process(null, out);
-                assertEquals("${1+1}", out.toString());
-            }
-
-            testedProps.add(Configuration.ExtendableBuilder.TEMPLATE_LANGUAGE_KEY_CAMEL_CASE);
-        }
-
-        {
-            // As the TemplateLanguage-based parser selection happens in the TemplateResolver, we can't use
-            // assertOutput here, as that hard-coded to create an FTL Template.
-
-            TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
-            tcb.setSourceEncoding(StandardCharsets.ISO_8859_1);
-
-            TestConfigurationBuilder cfgB = new TestConfigurationBuilder();
-            cfgB.setSourceEncoding(StandardCharsets.UTF_8);
-            cfgB.setTemplateConfigurations(new ConditionalTemplateConfigurationFactory(
-                    new FileNameGlobMatcher("latin1.ftl"), tcb.build()));
-
-            MonitoredTemplateLoader templateLoader = new MonitoredTemplateLoader();
-            templateLoader.putBinaryTemplate("utf8.ftl", "próba", StandardCharsets.UTF_8, 1);
-            templateLoader.putBinaryTemplate("latin1.ftl", "próba", StandardCharsets.ISO_8859_1, 1);
-            cfgB.setTemplateLoader(templateLoader);
-
-            Configuration cfg = cfgB.build();
-            
-            {
-                StringWriter out = new StringWriter();
-                cfg.getTemplate("utf8.ftl").process(null, out);
-                assertEquals("próba", out.toString());
-            }
-            {
-                StringWriter out = new StringWriter();
-                cfg.getTemplate("latin1.ftl").process(null, out);
-                assertEquals("próba", out.toString());
-            }
-
-            testedProps.add(Configuration.ExtendableBuilder.SOURCE_ENCODING_KEY_CAMEL_CASE);
-        }
-
-        if (!PARSER_PROP_NAMES.equals(testedProps)) {
-            Set<String> diff = new HashSet<>(PARSER_PROP_NAMES);
-            diff.removeAll(testedProps);
-            fail("Some settings weren't checked: " + diff);
-        }
-    }
-    
-    @Test
-    public void testArithmeticEngine() throws TemplateException, IOException {
-        TemplateConfiguration tc = new TemplateConfiguration.Builder()
-                .arithmeticEngine(new DummyArithmeticEngine())
-                .build();
-        assertOutputWithoutAndWithTC(tc,
-                "<#setting locale='en_US'>${1} ${1+1} ${1*3} <#assign x = 1>${x + x} ${x * 3}",
-                "1 2 3 2 3", "11 22 33 22 33");
-        
-        // Does affect template.arithmeticEngine (unlike in FM2)
-        Template t = new Template(null, null, new StringReader(""), DEFAULT_CFG, tc, null);
-        assertEquals(tc.getArithmeticEngine(), t.getArithmeticEngine());
-    }
-
-    @Test
-    public void testAutoImport() throws TemplateException, IOException {
-        TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
-        tcb.setAutoImports(ImmutableMap.of("t1", "t1.ftl", "t2", "t2.ftl"));
-        TemplateConfiguration tc = tcb.build();
-        assertOutputWithoutAndWithTC(tc, "<#import 't3.ftl' as t3>${loaded}", "t3;", "t1;t2;t3;");
-    }
-
-    @Test
-    public void testAutoIncludes() throws TemplateException, IOException {
-        TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
-        tcb.setAutoIncludes(ImmutableList.of("t1.ftl", "t2.ftl"));
-        TemplateConfiguration tc = tcb.build();
-        assertOutputWithoutAndWithTC(tc, "<#include 't3.ftl'>", "In t3;", "In t1;In t2;In t3;");
-    }
-    
-    @Test
-    public void testStringInterpolate() throws TemplateException, IOException {
-        TemplateConfiguration tc = new TemplateConfiguration.Builder()
-                .arithmeticEngine(new DummyArithmeticEngine())
-                .build();
-        assertOutputWithoutAndWithTC(tc,
-                "<#setting locale='en_US'>${'${1} ${1+1} ${1*3}'} <#assign x = 1>${'${x + x} ${x * 3}'}",
-                "1 2 3 2 3", "11 22 33 22 33");
-        
-        // Does affect template.arithmeticEngine (unlike in FM2):
-        Template t = new Template(null, null, new StringReader(""), DEFAULT_CFG, tc, null);
-        assertEquals(tc.getArithmeticEngine(), t.getArithmeticEngine());
-    }
-    
-    @Test
-    public void testInterpret() throws TemplateException, IOException {
-        TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
-        tcb.setArithmeticEngine(new DummyArithmeticEngine());
-        {
-            TemplateConfiguration tc = tcb.build();
-            assertOutputWithoutAndWithTC(tc,
-                    "<#setting locale='en_US'><#assign src = r'${1} <#assign x = 1>${x + x}'><@src?interpret />",
-                    "1 2", "11 22");
-        }
-        tcb.setWhitespaceStripping(false);
-        {
-            TemplateConfiguration tc = tcb.build();
-            assertOutputWithoutAndWithTC(tc,
-                    "<#if true>\nX</#if><#assign src = r'<#if true>\nY</#if>'><@src?interpret />",
-                    "XY", "\nX\nY");
-        }
-    }
-
-    @Test
-    public void testEval() throws TemplateException, IOException {
-        {
-            TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
-            tcb.setArithmeticEngine(new DummyArithmeticEngine());
-            TemplateConfiguration tc = tcb.build();
-            assertOutputWithoutAndWithTC(tc,
-                    "<#assign x = 1>${r'1 + x'?eval?c}",
-                    "2", "22");
-            assertOutputWithoutAndWithTC(tc,
-                    "${r'1?c'?eval}",
-                    "1", "11");
-        }
-        
-        {
-            TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
-            Charset outputEncoding = ISO_8859_2;
-            tcb.setOutputEncoding(outputEncoding);
-
-            String legacyNCFtl = "${r'.output_encoding!\"null\"'?eval}";
-            String camelCaseNCFtl = "${r'.outputEncoding!\"null\"'?eval}";
-
-            {
-                TemplateConfiguration tc = tcb.build();
-
-                // Default is re-auto-detecting in ?eval:
-                assertOutputWithoutAndWithTC(tc, legacyNCFtl, "null", outputEncoding.name());
-                assertOutputWithoutAndWithTC(tc, camelCaseNCFtl, "null", outputEncoding.name());
-            }
-
-            {
-                // Force camelCase:
-                tcb.setNamingConvention(ParsingConfiguration.CAMEL_CASE_NAMING_CONVENTION);
-
-                TemplateConfiguration tc = tcb.build();
-
-                assertOutputWithoutAndWithTC(tc, legacyNCFtl, "null", null);
-                assertOutputWithoutAndWithTC(tc, camelCaseNCFtl, "null", outputEncoding.name());
-            }
-
-            {
-                // Force legacy:
-                tcb.setNamingConvention(ParsingConfiguration.LEGACY_NAMING_CONVENTION);
-
-                TemplateConfiguration tc = tcb.build();
-
-                assertOutputWithoutAndWithTC(tc, legacyNCFtl, "null", outputEncoding.name());
-                assertOutputWithoutAndWithTC(tc, camelCaseNCFtl, "null", null);
-            }
-        }
-    }
-    
-    private void assertOutputWithoutAndWithTC(
-            TemplateConfiguration tc, String ftl, String expectedDefaultOutput,
-            String expectedConfiguredOutput) throws TemplateException, IOException {
-        assertOutputWithoutAndWithTC(tc, null, ftl, expectedDefaultOutput, expectedConfiguredOutput);
-    }
-    
-    private void assertOutputWithoutAndWithTC(
-            TemplateConfiguration tc, String templateName, String ftl, String expectedDefaultOutput,
-            String expectedConfiguredOutput) throws TemplateException, IOException {
-        if (templateName == null) {
-            templateName = "adhoc.ftl";
-        }
-        assertOutput(null, templateName, ftl, expectedDefaultOutput);
-        assertOutput(tc, templateName, ftl, expectedConfiguredOutput);
-    }
-
-    private void assertOutput(TemplateConfiguration tc, String templateName, String ftl, String
-            expectedConfiguredOutput)
-            throws TemplateException, IOException {
-        StringWriter sw = new StringWriter();
-        try {
-            Template t = new Template(templateName, null, new StringReader(ftl), DEFAULT_CFG, tc, null);
-            t.process(null, sw);
-            if (expectedConfiguredOutput == null) {
-                fail("Template should have fail.");
-            }
-        } catch (TemplateException|ParseException e) {
-            if (expectedConfiguredOutput != null) {
-                throw e;
-            }
-        }
-        if (expectedConfiguredOutput != null) {
-            assertEquals(expectedConfiguredOutput, sw.toString());
-        }
-    }
-
-    @Test
-    public void testIsSet() throws Exception {
-        for (PropertyDescriptor pd : getTemplateConfigurationSettingPropDescs(
-                TemplateConfiguration.Builder.class, true)) {
-            TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
-            checkAllIsSetFalseExcept(tcb.build(), null);
-            pd.getWriteMethod().invoke(tcb, SETTING_ASSIGNMENTS.get(pd.getName()));
-            checkAllIsSetFalseExcept(tcb.build(), pd.getName());
-        }
-    }
-
-    private void checkAllIsSetFalseExcept(TemplateConfiguration tc, String setSetting)
-            throws SecurityException, IntrospectionException,
-            IllegalArgumentException, IllegalAccessException, InvocationTargetException {
-        for (PropertyDescriptor pd : getTemplateConfigurationSettingPropDescs(TemplateConfiguration.class, true)) {
-            String isSetMethodName = getIsSetMethodName(pd.getReadMethod().getName());
-            Method isSetMethod;
-            try {
-                isSetMethod = tc.getClass().getMethod(isSetMethodName);
-            } catch (NoSuchMethodException e) {
-                fail("Missing " + isSetMethodName + " method for \"" + pd.getName() + "\".");
-                return;
-            }
-            if (pd.getName().equals(setSetting)) {
-                assertTrue(isSetMethod + " should return true", (Boolean) (isSetMethod.invoke(tc)));
-            } else {
-                assertFalse(isSetMethod + " should return false", (Boolean) (isSetMethod.invoke(tc)));
-            }
-        }
-    }
-
-    /**
-     * Test case self-check.
-     */
-    @Test
-    public void checkTestAssignments() throws Exception {
-        for (PropertyDescriptor pd : getTemplateConfigurationSettingPropDescs(
-                TemplateConfiguration.Builder.class, true)) {
-            String propName = pd.getName();
-            if (!SETTING_ASSIGNMENTS.containsKey(propName)) {
-                fail("Test case doesn't cover all settings in SETTING_ASSIGNMENTS. Missing: " + propName);
-            }
-            Method readMethod = pd.getReadMethod();
-            String cfgMethodName = readMethod.getName();
-            Method cfgMethod = DEFAULT_CFG.getClass().getMethod(cfgMethodName, readMethod.getParameterTypes());
-            Object defaultSettingValue = cfgMethod.invoke(DEFAULT_CFG);
-            Object assignedValue = SETTING_ASSIGNMENTS.get(propName);
-            assertNotEquals("SETTING_ASSIGNMENTS must contain a non-default value for " + propName,
-                    assignedValue, defaultSettingValue);
-
-            TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
-            try {
-                pd.getWriteMethod().invoke(tcb, assignedValue);
-            } catch (Exception e) {
-                throw new IllegalStateException("For setting \"" + propName + "\" and assigned value of type "
-                        + (assignedValue != null ? assignedValue.getClass().getName() : "Null"),
-                        e);
-            }
-        }
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/TemplateConfigurationWithDefaultTemplateResolverTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/TemplateConfigurationWithDefaultTemplateResolverTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/TemplateConfigurationWithDefaultTemplateResolverTest.java
deleted file mode 100644
index 4cd50eb..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/TemplateConfigurationWithDefaultTemplateResolverTest.java
+++ /dev/null
@@ -1,267 +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;
-
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.io.StringWriter;
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.util.Locale;
-
-import org.apache.freemarker.core.templateresolver.ConditionalTemplateConfigurationFactory;
-import org.apache.freemarker.core.templateresolver.FileNameGlobMatcher;
-import org.apache.freemarker.core.templateresolver.FirstMatchTemplateConfigurationFactory;
-import org.apache.freemarker.core.templateresolver.MergingTemplateConfigurationFactory;
-import org.apache.freemarker.core.templateresolver.impl.ByteArrayTemplateLoader;
-import org.apache.freemarker.core.templateresolver.impl.StringTemplateLoader;
-import org.apache.freemarker.test.TestConfigurationBuilder;
-import org.junit.Test;
-
-public class TemplateConfigurationWithDefaultTemplateResolverTest {
-
-    private static final String TEXT_WITH_ACCENTS = "pr\u00F3ba";
-
-    private static final Object CUST_ATT_1 = new Object();
-    private static final Object CUST_ATT_2 = new Object();
-
-    private static final Charset ISO_8859_2 = Charset.forName("ISO-8859-2");
-
-    @Test
-    public void testEncoding() throws Exception {
-        Configuration cfg = createCommonEncodingTesterConfig();
-        
-        {
-            Template t = cfg.getTemplate("utf8.ftl");
-            assertEquals(StandardCharsets.UTF_8, t.getActualSourceEncoding());
-            assertEquals(TEXT_WITH_ACCENTS, getTemplateOutput(t));
-        }
-        {
-            Template t = cfg.getTemplate("utf16.ftl");
-            assertEquals(StandardCharsets.UTF_16LE, t.getActualSourceEncoding());
-            assertEquals(TEXT_WITH_ACCENTS, getTemplateOutput(t));
-        }
-        {
-            Template t = cfg.getTemplate("default.ftl");
-            assertEquals(StandardCharsets.ISO_8859_1, t.getActualSourceEncoding());
-            assertEquals(TEXT_WITH_ACCENTS, getTemplateOutput(t));
-        }
-        {
-            Template t = cfg.getTemplate("utf8-latin2.ftl");
-            assertEquals(ISO_8859_2, t.getActualSourceEncoding());
-            assertEquals(TEXT_WITH_ACCENTS, getTemplateOutput(t));
-        }
-        {
-            Template t = cfg.getTemplate("default-latin2.ftl");
-            assertEquals(ISO_8859_2, t.getActualSourceEncoding());
-            assertEquals(TEXT_WITH_ACCENTS, getTemplateOutput(t));
-        }
-    }
-    
-    @Test
-    public void testIncludeAndEncoding() throws Exception {
-        Configuration cfg = createCommonEncodingTesterConfig();
-        ByteArrayTemplateLoader tl = (ByteArrayTemplateLoader) cfg.getTemplateLoader();
-        tl.putTemplate("main.ftl", (
-                        "<#include 'utf8.ftl'>"
-                        + "<#include 'utf16.ftl'>"
-                        + "<#include 'default.ftl'>"
-                        + "<#include 'utf8-latin2.ftl'>"
-                ).getBytes(StandardCharsets.ISO_8859_1));
-        assertEquals(
-                TEXT_WITH_ACCENTS + TEXT_WITH_ACCENTS + TEXT_WITH_ACCENTS + TEXT_WITH_ACCENTS,
-                getTemplateOutput(cfg.getTemplate("main.ftl")));
-    }
-
-    @Test
-    public void testLocale() throws Exception {
-        StringTemplateLoader loader = new StringTemplateLoader();
-        loader.putTemplate("(de).ftl", "${.locale}");
-        loader.putTemplate("default.ftl", "${.locale}");
-        loader.putTemplate("(de)-fr.ftl",
-                ("<#ftl locale='fr_FR'>${.locale}"));
-        loader.putTemplate("default-fr.ftl",
-                ("<#ftl locale='fr_FR'>${.locale}"));
-
-        Configuration cfg = new TestConfigurationBuilder()
-                .templateLoader(loader)
-                .templateConfigurations(
-                        new ConditionalTemplateConfigurationFactory(
-                                new FileNameGlobMatcher("*(de)*"),
-                                new TemplateConfiguration.Builder()
-                                        .locale(Locale.GERMANY)
-                                        .build()))
-                .build();
-
-        {
-            Template t = cfg.getTemplate("(de).ftl");
-            assertEquals(Locale.GERMANY, t.getLocale());
-            assertEquals("de_DE", getTemplateOutput(t));
-        }
-        {
-            Template t = cfg.getTemplate("(de).ftl", Locale.ITALY);
-            assertEquals(Locale.GERMANY, t.getLocale());
-            assertEquals("de_DE", getTemplateOutput(t));
-        }
-        {
-            Template t = cfg.getTemplate("default.ftl");
-            assertEquals(Locale.US, t.getLocale());
-            assertEquals("en_US", getTemplateOutput(t));
-        }
-        {
-            Template t = cfg.getTemplate("default.ftl", Locale.ITALY);
-            assertEquals(Locale.ITALY, t.getLocale());
-            assertEquals("it_IT", getTemplateOutput(t));
-        }
-    }
-
-    @Test
-    public void testConfigurableSettings() throws Exception {
-        String commonFTL = "${.locale} ${true?string} ${1.2}";
-        StringTemplateLoader loader = new StringTemplateLoader();
-        loader.putTemplate("default", commonFTL);
-        loader.putTemplate("(fr)", commonFTL);
-        loader.putTemplate("(yn)(00)", commonFTL);
-        loader.putTemplate("(00)(fr)", commonFTL);
-
-        Configuration cfg = new TestConfigurationBuilder()
-                .templateConfigurations(
-                        new MergingTemplateConfigurationFactory(
-                                new ConditionalTemplateConfigurationFactory(
-                                        new FileNameGlobMatcher("*(fr)*"),
-                                        new TemplateConfiguration.Builder().locale(Locale.FRANCE).build()),
-                                new ConditionalTemplateConfigurationFactory(
-                                        new FileNameGlobMatcher("*(yn)*"),
-                                        new TemplateConfiguration.Builder().booleanFormat("Y,N").build()),
-                                new ConditionalTemplateConfigurationFactory(
-                                        new FileNameGlobMatcher("*(00)*"),
-                                        new TemplateConfiguration.Builder().numberFormat("0.00").build())))
-                .templateLoader(loader)
-                .build();
-
-        assertEquals("en_US true 1.2", getTemplateOutput(cfg.getTemplate("default")));
-        assertEquals("fr_FR true 1,2", getTemplateOutput(cfg.getTemplate("(fr)")));
-        assertEquals("en_US Y 1.20", getTemplateOutput(cfg.getTemplate("(yn)(00)")));
-        assertEquals("fr_FR true 1,20", getTemplateOutput(cfg.getTemplate("(00)(fr)")));
-    }
-    
-    @Test
-    public void testCustomAttributes() throws Exception {
-        String commonFTL = "<#ftl attributes={ 'a3': 'a3temp' }>";
-        StringTemplateLoader tl = new StringTemplateLoader();
-        tl.putTemplate("(tc1)", commonFTL);
-        tl.putTemplate("(tc1)noHeader", "");
-        tl.putTemplate("(tc2)", commonFTL);
-        tl.putTemplate("(tc1)(tc2)", commonFTL);
-
-        Configuration cfg = new TestConfigurationBuilder()
-                .templateConfigurations(
-                        new MergingTemplateConfigurationFactory(
-                                new ConditionalTemplateConfigurationFactory(
-                                        new FileNameGlobMatcher("*(tc1)*"),
-                                        new TemplateConfiguration.Builder()
-                                                .customAttribute("a1", "a1tc1")
-                                                .customAttribute("a2", "a2tc1")
-                                                .customAttribute("a3", "a3tc1")
-                                                .customAttribute(CUST_ATT_1, "ca1tc1")
-                                                .customAttribute(CUST_ATT_2, "ca2tc1")
-                                                .build()),
-                                new ConditionalTemplateConfigurationFactory(
-                                        new FileNameGlobMatcher("*(tc2)*"),
-                                        new TemplateConfiguration.Builder()
-                                                .customAttribute("a1", "a1tc2")
-                                                .customAttribute(CUST_ATT_1, "ca1tc2")
-                                                .build())))
-                .templateLoader(tl)
-                .build();
-
-        {
-            Template t = cfg.getTemplate("(tc1)");
-            assertEquals("a1tc1", t.getCustomAttribute("a1"));
-            assertEquals("a2tc1", t.getCustomAttribute("a2"));
-            assertEquals("a3temp", t.getCustomAttribute("a3"));
-            assertEquals("ca1tc1", t.getCustomAttribute(CUST_ATT_1));
-            assertEquals("ca2tc1", t.getCustomAttribute(CUST_ATT_2));
-        }
-        {
-            Template t = cfg.getTemplate("(tc1)noHeader");
-            assertEquals("a1tc1", t.getCustomAttribute("a1"));
-            assertEquals("a2tc1", t.getCustomAttribute("a2"));
-            assertEquals("a3tc1", t.getCustomAttribute("a3"));
-            assertEquals("ca1tc1", t.getCustomAttribute(CUST_ATT_1));
-            assertEquals("ca2tc1", t.getCustomAttribute(CUST_ATT_2));
-        }
-        {
-            Template t = cfg.getTemplate("(tc2)");
-            assertEquals("a1tc2", t.getCustomAttribute("a1"));
-            assertNull(t.getCustomAttribute("a2"));
-            assertEquals("a3temp", t.getCustomAttribute("a3"));
-            assertEquals("ca1tc2", t.getCustomAttribute(CUST_ATT_1));
-            assertNull(t.getCustomAttribute(CUST_ATT_2));
-        }
-        {
-            Template t = cfg.getTemplate("(tc1)(tc2)");
-            assertEquals("a1tc2", t.getCustomAttribute("a1"));
-            assertEquals("a2tc1", t.getCustomAttribute("a2"));
-            assertEquals("a3temp", t.getCustomAttribute("a3"));
-            assertEquals("ca1tc2", t.getCustomAttribute(CUST_ATT_1));
-            assertEquals("ca2tc1", t.getCustomAttribute(CUST_ATT_2));
-        }
-    }
-    
-    private String getTemplateOutput(Template t) throws TemplateException, IOException {
-        StringWriter sw = new StringWriter();
-        t.process(null, sw);
-        return sw.toString();
-    }
-
-    private Configuration createCommonEncodingTesterConfig() throws UnsupportedEncodingException {
-        ByteArrayTemplateLoader tl = new ByteArrayTemplateLoader();
-        tl.putTemplate("utf8.ftl", TEXT_WITH_ACCENTS.getBytes(StandardCharsets.UTF_8));
-        tl.putTemplate("utf16.ftl", TEXT_WITH_ACCENTS.getBytes(StandardCharsets.UTF_16LE));
-        tl.putTemplate("default.ftl", TEXT_WITH_ACCENTS.getBytes(ISO_8859_2));
-        tl.putTemplate("utf8-latin2.ftl",
-                ("<#ftl encoding='iso-8859-2'>" + TEXT_WITH_ACCENTS).getBytes(ISO_8859_2));
-        tl.putTemplate("default-latin2.ftl",
-                ("<#ftl encoding='iso-8859-2'>" + TEXT_WITH_ACCENTS).getBytes(ISO_8859_2));
-
-        return new TestConfigurationBuilder()
-                .sourceEncoding(StandardCharsets.ISO_8859_1)
-                .locale(Locale.US)
-                .templateLoader(tl)
-                .templateConfigurations(
-                        new FirstMatchTemplateConfigurationFactory(
-                                new ConditionalTemplateConfigurationFactory(
-                                        new FileNameGlobMatcher("*utf8*"),
-                                        new TemplateConfiguration.Builder()
-                                                .sourceEncoding(StandardCharsets.UTF_8)
-                                                .build()),
-                                new ConditionalTemplateConfigurationFactory(
-                                        new FileNameGlobMatcher("*utf16*"),
-                                        new TemplateConfiguration.Builder()
-                                                .sourceEncoding(StandardCharsets.UTF_16LE)
-                                                .build())
-                        )
-                        .allowNoMatch(true))
-                .build();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/TemplateConstructorsTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/TemplateConstructorsTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/TemplateConstructorsTest.java
deleted file mode 100644
index 97c43ad..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/TemplateConstructorsTest.java
+++ /dev/null
@@ -1,113 +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;
-
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.io.Reader;
-import java.io.StringReader;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-
-import org.apache.freemarker.test.TestConfigurationBuilder;
-import org.junit.Test;
-public class TemplateConstructorsTest {
-
-    private static final String CONTENT = "From a reader...";
-    private static final String CONTENT_FORCE_UTF8 = "<#ftl encoding='utf-8'>From a reader...";
-    
-    @Test
-    public void test() throws IOException {
-        final Configuration cfg = new TestConfigurationBuilder().sourceEncoding(StandardCharsets.ISO_8859_1).build();
-        
-        final String name = "foo/bar.ftl";
-        final String sourceName = "foo/bar_de.ftl";
-        final Charset sourceEncoding = StandardCharsets.UTF_16LE;
-        {
-            Template t = new Template(name, createReader(), cfg);
-            assertEquals(name, t.getLookupName());
-            assertNull(t.getSourceName());
-            assertEquals(CONTENT, t.toString());
-            assertNull(t.getActualSourceEncoding());
-        }
-        {
-            Template t = new Template(name, CONTENT, cfg);
-            assertEquals(name, t.getLookupName());
-            assertNull(t.getSourceName());
-            assertEquals(CONTENT, t.toString());
-            assertNull(t.getActualSourceEncoding());
-        }
-        {
-            Template t = new Template(name, CONTENT_FORCE_UTF8, cfg);
-            assertEquals(name, t.getLookupName());
-            assertNull(t.getSourceName());
-            // assertEquals(CONTENT_FORCE_UTF8, t.toString()); // FIXME the #ftl header is missing from the dump, why?
-            assertNull(t.getActualSourceEncoding()); // Because it was created from a String
-        }
-        {
-            Template t = new Template(name, createReader(), cfg, sourceEncoding);
-            assertEquals(name, t.getLookupName());
-            assertNull(t.getSourceName());
-            assertEquals(CONTENT, t.toString());
-            assertEquals(StandardCharsets.UTF_16LE, t.getActualSourceEncoding());
-        }
-        {
-            Template t = new Template(name, sourceName, createReader(), cfg);
-            assertEquals(name, t.getLookupName());
-            assertEquals(sourceName, t.getSourceName());
-            assertEquals(CONTENT, t.toString());
-            assertNull(t.getActualSourceEncoding());
-        }
-        {
-            Template t = new Template(name, sourceName, createReader(), cfg, sourceEncoding);
-            assertEquals(name, t.getLookupName());
-            assertEquals(sourceName, t.getSourceName());
-            assertEquals(CONTENT, t.toString());
-            assertEquals(StandardCharsets.UTF_16LE, t.getActualSourceEncoding());
-        }
-        {
-            Template t = Template.createPlainTextTemplate(name, CONTENT, cfg);
-            assertEquals(name, t.getLookupName());
-            assertNull(t.getSourceName());
-            assertEquals(CONTENT, t.toString());
-            assertNull(t.getActualSourceEncoding());
-        }
-        {
-            try {
-                new Template(name, sourceName, createReaderForceUTF8(), cfg, sourceEncoding);
-                fail();
-            } catch (WrongTemplateCharsetException e) {
-                assertThat(e.getMessage(), containsString(StandardCharsets.UTF_8.name()));
-                assertThat(e.getMessage(), containsString(sourceEncoding.name()));
-            }
-        }
-    }
-    
-    private Reader createReader() {
-        return new StringReader(CONTENT);
-    }
-
-    private Reader createReaderForceUTF8() {
-        return new StringReader(CONTENT_FORCE_UTF8);
-    }
-    
-}


[20/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/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
deleted file mode 100644
index ff5897f..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/InterpretAndEvalTemplateNameTest.java
+++ /dev/null
@@ -1,70 +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;
-
-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/28a276c8/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
deleted file mode 100644
index 2d061d7..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/InterpretSettingInheritanceTest.java
+++ /dev/null
@@ -1,104 +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;
-
-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/28a276c8/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
deleted file mode 100644
index 08fcee2..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/IteratorIssuesTest.java
+++ /dev/null
@@ -1,64 +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;
-
-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/28a276c8/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
deleted file mode 100644
index 0fa3f79..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/JavaCCExceptionAsEOFFixTest.java
+++ /dev/null
@@ -1,126 +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;
-
-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/28a276c8/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
deleted file mode 100644
index 05bac4f..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/ListErrorsTest.java
+++ /dev/null
@@ -1,130 +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;
-
-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/28a276c8/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
deleted file mode 100644
index 1903e05..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/MiscErrorMessagesTest.java
+++ /dev/null
@@ -1,48 +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;
-
-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/28a276c8/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
deleted file mode 100644
index 5fcee97..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/MistakenlyPublicImportAPIsTest.java
+++ /dev/null
@@ -1,104 +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;
-
-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/28a276c8/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
deleted file mode 100644
index 9c87e61..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/MistakenlyPublicMacroAPIsTest.java
+++ /dev/null
@@ -1,88 +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;
-
-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/28a276c8/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
deleted file mode 100644
index d865deb..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/NewBiObjectWrapperRestrictionTest.java
+++ /dev/null
@@ -1,50 +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;
-
-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");
-    }
-
-}



[11/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/templateresolver/TemplateConfigurationFactoryTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/templateresolver/TemplateConfigurationFactoryTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/templateresolver/TemplateConfigurationFactoryTest.java
deleted file mode 100644
index a7259d8..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/templateresolver/TemplateConfigurationFactoryTest.java
+++ /dev/null
@@ -1,203 +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.templateresolver;
-
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.freemarker.core.TemplateConfiguration;
-import org.junit.Test;
-
-public class TemplateConfigurationFactoryTest {
-    
-    @Test
-    public void testCondition1() throws IOException, TemplateConfigurationFactoryException {
-        TemplateConfiguration tc = newTemplateConfiguration(1);
-        
-        TemplateConfigurationFactory tcf = new ConditionalTemplateConfigurationFactory(new FileNameGlobMatcher("*.ftlx"), tc);
-
-        assertNotApplicable(tcf, "x.ftl");
-        assertApplicable(tcf, "x.ftlx", tc);
-    }
-
-    @Test
-    public void testCondition2() throws IOException, TemplateConfigurationFactoryException {
-        TemplateConfiguration tc = newTemplateConfiguration(1);
-        
-        TemplateConfigurationFactory tcf = new ConditionalTemplateConfigurationFactory(
-                new FileNameGlobMatcher("*.ftlx"),
-                new ConditionalTemplateConfigurationFactory(
-                        new FileNameGlobMatcher("x.*"), tc));
-
-        assertNotApplicable(tcf, "x.ftl");
-        assertNotApplicable(tcf, "y.ftlx");
-        assertApplicable(tcf, "x.ftlx", tc);
-    }
-
-    @Test
-    public void testMerging() throws IOException, TemplateConfigurationFactoryException {
-        TemplateConfiguration tc1 = newTemplateConfiguration(1);
-        TemplateConfiguration tc2 = newTemplateConfiguration(2);
-        TemplateConfiguration tc3 = newTemplateConfiguration(3);
-        
-        TemplateConfigurationFactory tcf = new MergingTemplateConfigurationFactory(
-                new ConditionalTemplateConfigurationFactory(new FileNameGlobMatcher("*.ftlx"), tc1),
-                new ConditionalTemplateConfigurationFactory(new FileNameGlobMatcher("*a*.*"), tc2),
-                new ConditionalTemplateConfigurationFactory(new FileNameGlobMatcher("*b*.*"), tc3));
-
-        assertNotApplicable(tcf, "x.ftl");
-        assertApplicable(tcf, "x.ftlx", tc1);
-        assertApplicable(tcf, "a.ftl", tc2);
-        assertApplicable(tcf, "b.ftl", tc3);
-        assertApplicable(tcf, "a.ftlx", tc1, tc2);
-        assertApplicable(tcf, "b.ftlx", tc1, tc3);
-        assertApplicable(tcf, "ab.ftl", tc2, tc3);
-        assertApplicable(tcf, "ab.ftlx", tc1, tc2, tc3);
-        
-        assertNotApplicable(new MergingTemplateConfigurationFactory(), "x.ftl");
-    }
-
-    @Test
-    public void testFirstMatch() throws IOException, TemplateConfigurationFactoryException {
-        TemplateConfiguration tc1 = newTemplateConfiguration(1);
-        TemplateConfiguration tc2 = newTemplateConfiguration(2);
-        TemplateConfiguration tc3 = newTemplateConfiguration(3);
-        
-        FirstMatchTemplateConfigurationFactory tcf = new FirstMatchTemplateConfigurationFactory(
-                new ConditionalTemplateConfigurationFactory(new FileNameGlobMatcher("*.ftlx"), tc1),
-                new ConditionalTemplateConfigurationFactory(new FileNameGlobMatcher("*a*.*"), tc2),
-                new ConditionalTemplateConfigurationFactory(new FileNameGlobMatcher("*b*.*"), tc3));
-
-        try {
-            assertNotApplicable(tcf, "x.ftl");
-        } catch (TemplateConfigurationFactoryException e) {
-            assertThat(e.getMessage(), containsString("x.ftl"));
-        }
-        tcf.setNoMatchErrorDetails("Test details");
-        try {
-            assertNotApplicable(tcf, "x.ftl");
-        } catch (TemplateConfigurationFactoryException e) {
-            assertThat(e.getMessage(), containsString("Test details"));
-        }
-        
-        tcf.setAllowNoMatch(true);
-        
-        assertNotApplicable(tcf, "x.ftl");
-        assertApplicable(tcf, "x.ftlx", tc1);
-        assertApplicable(tcf, "a.ftl", tc2);
-        assertApplicable(tcf, "b.ftl", tc3);
-        assertApplicable(tcf, "a.ftlx", tc1);
-        assertApplicable(tcf, "b.ftlx", tc1);
-        assertApplicable(tcf, "ab.ftl", tc2);
-        assertApplicable(tcf, "ab.ftlx", tc1);
-        
-        assertNotApplicable(new FirstMatchTemplateConfigurationFactory().allowNoMatch(true), "x.ftl");
-    }
-
-    @Test
-    public void testComplex() throws IOException, TemplateConfigurationFactoryException {
-        TemplateConfiguration tcA = newTemplateConfiguration(1);
-        TemplateConfiguration tcBSpec = newTemplateConfiguration(2);
-        TemplateConfiguration tcBCommon = newTemplateConfiguration(3);
-        TemplateConfiguration tcHH = newTemplateConfiguration(4);
-        TemplateConfiguration tcHtml = newTemplateConfiguration(5);
-        TemplateConfiguration tcXml = newTemplateConfiguration(6);
-        TemplateConfiguration tcNWS = newTemplateConfiguration(7);
-        
-        TemplateConfigurationFactory tcf = new MergingTemplateConfigurationFactory(
-                new FirstMatchTemplateConfigurationFactory(
-                        new ConditionalTemplateConfigurationFactory(new PathGlobMatcher("a/**"), tcA),
-                        new ConditionalTemplateConfigurationFactory(new PathGlobMatcher("b/**"),
-                                new MergingTemplateConfigurationFactory(
-                                    new ConditionalTemplateConfigurationFactory(new FileNameGlobMatcher("*"), tcBCommon),
-                                    new ConditionalTemplateConfigurationFactory(new FileNameGlobMatcher("*.s.*"), tcBSpec))))
-                        .allowNoMatch(true),
-                new FirstMatchTemplateConfigurationFactory(
-                        new ConditionalTemplateConfigurationFactory(new FileNameGlobMatcher("*.hh"), tcHH),
-                        new ConditionalTemplateConfigurationFactory(new FileNameGlobMatcher("*.*h"), tcHtml),
-                        new ConditionalTemplateConfigurationFactory(new FileNameGlobMatcher("*.*x"), tcXml))
-                        .allowNoMatch(true),
-                new ConditionalTemplateConfigurationFactory(new FileNameGlobMatcher("*.nws.*"), tcNWS));
-
-        assertNotApplicable(tcf, "x.ftl");
-        assertApplicable(tcf, "b/x.ftl", tcBCommon);
-        assertApplicable(tcf, "b/x.s.ftl", tcBCommon, tcBSpec);
-        assertApplicable(tcf, "b/x.s.ftlh", tcBCommon, tcBSpec, tcHtml);
-        assertApplicable(tcf, "b/x.s.nws.ftlx", tcBCommon, tcBSpec, tcXml, tcNWS);
-        assertApplicable(tcf, "a/x.s.nws.ftlx", tcA, tcXml, tcNWS);
-        assertApplicable(tcf, "a.hh", tcHH);
-        assertApplicable(tcf, "a.nws.hh", tcHH, tcNWS);
-    }
-
-    @SuppressWarnings("boxing")
-    private TemplateConfiguration newTemplateConfiguration(int id) {
-        TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
-        tcb.setCustomAttribute("id", id);
-        tcb.setCustomAttribute("contains" + id, true);
-        return tcb.build();
-    }
-
-    private void assertNotApplicable(TemplateConfigurationFactory tcf, String sourceName)
-            throws IOException, TemplateConfigurationFactoryException {
-        assertNull(tcf.get(sourceName, DummyTemplateLoadingSource.INSTANCE));
-    }
-
-    private void assertApplicable(TemplateConfigurationFactory tcf, String sourceName, TemplateConfiguration... expectedTCs)
-            throws IOException, TemplateConfigurationFactoryException {
-        TemplateConfiguration mergedTC = tcf.get(sourceName, DummyTemplateLoadingSource.INSTANCE);
-        List<Object> mergedTCAttNames = new ArrayList<>(mergedTC.getCustomAttributes().keySet());
-
-        for (TemplateConfiguration expectedTC : expectedTCs) {
-            Integer tcId = (Integer) expectedTC.getCustomAttribute("id");
-            if (tcId == null) {
-                fail("TemplateConfiguration-s must be created with newTemplateConfiguration(id) in this test");
-            }
-            if (!mergedTCAttNames.contains("contains" + tcId)) {
-                fail("TemplateConfiguration with ID " + tcId + " is missing from the asserted value");
-            }
-        }
-        
-        for (Object attKey: mergedTCAttNames) {
-            if (!containsCustomAttr(attKey, expectedTCs)) {
-                fail("The asserted TemplateConfiguration contains an unexpected custom attribute: " + attKey);
-            }
-        }
-        
-        assertEquals(expectedTCs[expectedTCs.length - 1].getCustomAttribute("id"), mergedTC.getCustomAttribute("id"));
-    }
-
-    private boolean containsCustomAttr(Object attKey, TemplateConfiguration... expectedTCs) {
-        for (TemplateConfiguration expectedTC : expectedTCs) {
-            if (expectedTC.getCustomAttribute(attKey) != null) {
-                return true;
-            }
-        }
-        return false;
-    }
-    
-    @SuppressWarnings("serial")
-    private static class DummyTemplateLoadingSource implements TemplateLoadingSource {
-        private static DummyTemplateLoadingSource INSTANCE = new DummyTemplateLoadingSource();
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/templateresolver/TemplateNameFormatTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/templateresolver/TemplateNameFormatTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/templateresolver/TemplateNameFormatTest.java
deleted file mode 100644
index 3a24bfc..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/templateresolver/TemplateNameFormatTest.java
+++ /dev/null
@@ -1,330 +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.templateresolver;
-
-import static org.apache.freemarker.test.hamcerst.Matchers.*;
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.util.Locale;
-
-import org.apache.freemarker.core.Configuration;
-import org.apache.freemarker.core.Template;
-import org.apache.freemarker.core.TemplateNotFoundException;
-import org.apache.freemarker.core.templateresolver.impl.ByteArrayTemplateLoader;
-import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormat;
-import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormatFM2;
-import org.apache.freemarker.test.MonitoredTemplateLoader;
-import org.apache.freemarker.test.TestConfigurationBuilder;
-import org.junit.Test;
-
-import com.google.common.collect.ImmutableList;
-
-
-public class TemplateNameFormatTest {
-
-    @Test
-    public void testToRootBasedName() throws MalformedTemplateNameException {
-        // Path that are treated the same both in 2.3 and 2.4 format:
-        for (TemplateNameFormat tnf : new TemplateNameFormat[] {
-                DefaultTemplateNameFormatFM2.INSTANCE, DefaultTemplateNameFormat.INSTANCE }) {
-            // Relative paths:
-            // - No scheme:
-            assertEquals("a/b", tnf.toRootBasedName("a/", "b"));
-            assertEquals("/a/b", tnf.toRootBasedName("/a/", "b"));
-            assertEquals("a/b", tnf.toRootBasedName("a/f", "b"));
-            assertEquals("/a/b", tnf.toRootBasedName("/a/f", "b"));
-            // - Scheme:
-            assertEquals("s://a/b", tnf.toRootBasedName("s://a/", "b"));
-            assertEquals("s:///a/b", tnf.toRootBasedName("s:///a/", "b"));
-            assertEquals("s://a/b", tnf.toRootBasedName("s://a/f", "b"));
-            assertEquals("s:///a/b", tnf.toRootBasedName("s:///a/f", "b"));
-            assertEquals("s://b", tnf.toRootBasedName("s://f", "b"));
-            assertEquals("s:///b", tnf.toRootBasedName("s:///f", "b"));
-            
-            // Absolute paths:
-            // - No scheme:
-            assertEquals("b", tnf.toRootBasedName("a/", "/b"));
-            assertEquals("b", tnf.toRootBasedName("/a/", "/b"));
-            assertEquals("b", tnf.toRootBasedName("a/s:/f/", "/b"));
-            // - Scheme:
-            assertEquals("s://b", tnf.toRootBasedName("s://x/", "/b"));
-            assertEquals("s://b", tnf.toRootBasedName("s:///x/", "/b"));
-            
-            // Schemed absolute paths:
-            assertEquals("s://b", tnf.toRootBasedName("a/", "s://b"));
-            assertEquals("s://b", tnf.toRootBasedName("i://a/", "s://b"));
-        }
-        
-        // Scheme names in 2.4 format only:
-        {
-            final TemplateNameFormat tnf = DefaultTemplateNameFormat.INSTANCE;
-            assertEquals("s:b", tnf.toRootBasedName("s:f", "b"));
-            assertEquals("s:/b", tnf.toRootBasedName("s:/f", "b"));
-            assertEquals("s:b", tnf.toRootBasedName("s:f", "/b"));
-            assertEquals("s:b", tnf.toRootBasedName("s:/f", "/b"));
-            assertEquals("s:f/b", tnf.toRootBasedName("s:f/", "b"));
-            assertEquals("s:/f/b", tnf.toRootBasedName("s:/f/", "b"));
-            assertEquals("s:b", tnf.toRootBasedName("s:f/", "/b"));
-            assertEquals("s:b", tnf.toRootBasedName("s:/f/", "/b"));
-            assertEquals("s:b", tnf.toRootBasedName("s:/f/", "/b"));
-            assertEquals("b", tnf.toRootBasedName("a/s://f/", "/b"));
-        }
-        
-        // Scheme names in 2.3 format only:
-        {
-            final TemplateNameFormat tnf = DefaultTemplateNameFormatFM2.INSTANCE;
-            assertEquals("a/s://b", tnf.toRootBasedName("a/s://f/", "/b"));
-        }
-    }
-
-    @Test
-    public void testNormalizeRootBasedName() throws MalformedTemplateNameException {
-        // Normalizations that are the same in legacy and modern format:
-        for (TemplateNameFormat tnf : new TemplateNameFormat[] {
-                DefaultTemplateNameFormatFM2.INSTANCE, DefaultTemplateNameFormat.INSTANCE }) {
-            assertEquals("", tnf.normalizeRootBasedName(""));
-            for (String lead : new String[] { "", "/" }) {
-                assertEquals("foo", tnf.normalizeRootBasedName(lead + "foo"));
-                assertEquals("foo", tnf.normalizeRootBasedName(lead + "./foo"));
-                assertEquals("foo", tnf.normalizeRootBasedName(lead + "./././foo"));
-                assertEquals("foo", tnf.normalizeRootBasedName(lead + "bar/../foo"));
-                assertEquals("a/b/", tnf.normalizeRootBasedName("a/b/"));
-                assertEquals("a/", tnf.normalizeRootBasedName("a/b/../"));
-                assertEquals("a/c../..d/e*/*f", tnf.normalizeRootBasedName("a/c../..d/e*/*f"));
-                assertEquals("", tnf.normalizeRootBasedName(""));
-                assertEquals("foo/bar/*", tnf.normalizeRootBasedName("foo/bar/*"));
-                assertEquals("schema://", tnf.normalizeRootBasedName("schema://"));
-                
-                assertThrowsWithBackingOutException(lead + "bar/../../x/foo", tnf);
-                assertThrowsWithBackingOutException(lead + "../x", tnf);
-                assertThrowsWithBackingOutException(lead + "../../../x", tnf);
-                assertThrowsWithBackingOutException(lead + "../../../x", tnf);
-                assertThrowsWithBackingOutException("x://../../../foo", tnf);
-                
-                {
-                    final String name = lead + "foo\u0000";
-                    try {
-                        tnf.normalizeRootBasedName(name);
-                        fail();
-                    } catch (MalformedTemplateNameException e) {
-                        assertEquals(name, e.getTemplateName());
-
-                        assertThat(e.getMalformednessDescription(), containsStringIgnoringCase("null character"));
-                    }
-                }
-            }
-        }
-        
-        // ".." and "."
-        assertEqualsOn23AndOn24("bar/foo", "foo", "bar/./../foo");
-        
-        // Even number of leading ".."-s bug:
-        assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24("foo", "../../foo");
-        assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24("foo", "../../../../foo");
-        
-        // ".." and "*"
-        assertEqualsOn23AndOn24("a/b/foo", "a/*/foo", "a/b/*/../foo");
-        //
-        assertEqualsOn23AndOn24("a/foo", "foo", "a/b/*/../../foo");
-        //
-        assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24("foo", "a/b/*/../../../foo");
-        //
-        assertEqualsOn23AndOn24("a/b/*/foo", "a/*/foo", "a/b/*/*/../foo");
-        //
-        assertEqualsOn23AndOn24("a/b/*/c/foo", "a/b/*/foo", "a/b/*/c/*/../foo");
-        //
-        assertEqualsOn23AndOn24("a/b/*/c/foo", "a/b/*/foo", "a/b/*/c/d/*/../../foo");
-        //
-        assertEqualsOn23AndOn24("a/*//b/*/c/foo", "a/*/b/*/foo", "a/*//b/*/c/d/*/../../foo");
-        //
-        assertEqualsOn23AndOn24("*", "", "a/../*");
-        //
-        assertEqualsOn23AndOn24("*/", "", "a/../*/");
-        
-        // ".." and "scheme"
-        assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24("x:/foo", "x://../foo");
-        //
-        assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24("foo", "x://../../foo");
-        //
-        assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24("x:../foo", "x:../foo");
-        //
-        assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24("foo", "x:../../foo");
-
-        // Tricky cases with terminating "/":
-        assertEqualsOn23AndOn24("/", "", "/");
-        // Terminating "/.." (produces terminating "/"):
-        assertEqualsOn23AndOn24("foo/bar/..", "foo/", "foo/bar/..");
-        // Terminating "/." (produces terminating "/"):
-        assertEqualsOn23AndOn24("foo/bar/.", "foo/bar/", "foo/bar/.");
-        
-        // Lonely "."
-        assertEqualsOn23AndOn24(".", "", ".");
-        // Lonely ".."
-        assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24("..", "..");
-        // Lonely "*"
-        
-        // Eliminating redundant "//":
-        assertEqualsOn23AndOn24("foo//bar", "foo/bar", "foo//bar");
-        //
-        assertEqualsOn23AndOn24("///foo//bar///baaz////wombat", "foo/bar/baaz/wombat", "////foo//bar///baaz////wombat");
-        //
-        assertEqualsOn23AndOn24("scheme://foo", "scheme://foo", "scheme://foo");
-        //
-        assertEqualsOn23AndOn24("scheme://foo//x/y", "scheme://foo/x/y", "scheme://foo//x/y");
-        //
-        assertEqualsOn23AndOn24("scheme:///foo", "scheme://foo", "scheme:///foo");
-        //
-        assertEqualsOn23AndOn24("scheme:////foo", "scheme://foo", "scheme:////foo");
-        
-        // Eliminating redundant "*"-s:
-        assertEqualsOn23AndOn24("a/*/*/b", "a/*/b", "a/*/*/b");
-        //
-        assertEqualsOn23AndOn24("a/*/*/*/b", "a/*/b", "a/*/*/*/b");
-        //
-        assertEqualsOn23AndOn24("*/*/b", "b", "*/*/b");
-        //
-        assertEqualsOn23AndOn24("*/*/b", "b", "/*/*/b");
-        //
-        assertEqualsOn23AndOn24("b/*/*", "b/*", "b/*/*");
-        //
-        assertEqualsOn23AndOn24("b/*/*/*", "b/*", "b/*/*/*");
-        //
-        assertEqualsOn23AndOn24("*/a/*/b/*/*/c", "a/*/b/*/c", "*/a/*/b/*/*/c");
-        
-        // New kind of scheme handling:
-
-        assertEquals("s:a/b", DefaultTemplateNameFormat.INSTANCE.normalizeRootBasedName("s:a/b"));
-        assertEquals("s:a/b", DefaultTemplateNameFormat.INSTANCE.normalizeRootBasedName("s:/a/b"));
-        assertEquals("s://a/b", DefaultTemplateNameFormat.INSTANCE.normalizeRootBasedName("s://a/b"));
-        assertEquals("s://a/b", DefaultTemplateNameFormat.INSTANCE.normalizeRootBasedName("s:///a/b"));
-        assertEquals("s://a/b", DefaultTemplateNameFormat.INSTANCE.normalizeRootBasedName("s:////a/b"));
-        
-        // Illegal use a of ":":
-        assertNormRBNameThrowsColonExceptionOn24("a/b:c/d");
-        assertNormRBNameThrowsColonExceptionOn24("a/b:/..");
-    }
-    
-    @Test
-    public void assertBackslashNotSpecialWith23() throws IOException {
-        MonitoredTemplateLoader tl = new MonitoredTemplateLoader();
-        tl.putTextTemplate("foo\\bar.ftl", "");
-
-        Configuration cfg = new TestConfigurationBuilder().templateLoader(tl).build();
-
-        {
-            final String name = "foo\\bar.ftl";
-            
-            Template t = cfg.getTemplate(name, Locale.US);
-            assertEquals(name, t.getLookupName());
-            assertEquals(name, t.getSourceName());
-            assertEquals(
-                    ImmutableList.of(
-                            "foo\\bar_en_US.ftl",
-                            "foo\\bar_en.ftl",
-                            name),
-                    tl.getLoadNames());
-            tl.clearEvents();
-        }
-
-        try {
-            cfg.getTemplate("foo\\missing.ftl", Locale.US);
-            fail();
-        } catch (TemplateNotFoundException e) {
-            assertEquals("foo\\missing.ftl", e.getTemplateName());
-            assertEquals(
-                    ImmutableList.of(
-                            "foo\\missing_en_US.ftl",
-                            "foo\\missing_en.ftl",
-                            "foo\\missing.ftl"),
-                    tl.getLoadNames());
-            tl.clearEvents();
-            cfg.clearTemplateCache();
-        }
-        
-        {
-            final String name = "foo/bar\\..\\bar.ftl";
-            try {
-                cfg.getTemplate(name, Locale.US);
-                fail();
-            } catch (TemplateNotFoundException e) {
-                assertEquals(name, e.getTemplateName());
-            }
-        }
-        
-    }
-
-    @Test
-    public void assertBackslashNotAllowed() throws IOException {
-        Configuration cfg = new TestConfigurationBuilder()
-                .templateLoader(new ByteArrayTemplateLoader())
-                .templateNameFormat(DefaultTemplateNameFormat.INSTANCE)
-                .build();
-        try {
-            cfg.getTemplate("././foo\\bar.ftl", Locale.US);
-            fail();
-        } catch (MalformedTemplateNameException e) {
-            assertThat(e.getMessage(), containsStringIgnoringCase("backslash"));
-        }
-        
-    }
-    
-    private void assertEqualsOn23AndOn24(String expected23, String expected24, String name)
-            throws MalformedTemplateNameException {
-        assertEquals(expected23, DefaultTemplateNameFormatFM2.INSTANCE.normalizeRootBasedName(name));
-        assertEquals(expected24, DefaultTemplateNameFormat.INSTANCE.normalizeRootBasedName(name));
-    }
-
-    private void assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24(final String expected23, final String name)
-            throws MalformedTemplateNameException {
-        assertEquals(expected23, DefaultTemplateNameFormatFM2.INSTANCE.normalizeRootBasedName(name));
-        assertThrowsWithBackingOutException(name, DefaultTemplateNameFormat.INSTANCE);
-    }
-
-    private void assertThrowsWithBackingOutException(final String name, final TemplateNameFormat tnf) {
-        try {
-            tnf.normalizeRootBasedName(name);
-            fail();
-        } catch (MalformedTemplateNameException e) {
-            assertEquals(name, e.getTemplateName());
-            assertBackingOutFromRootException(e);
-        }
-    }
-
-    private void assertNormRBNameThrowsColonExceptionOn24(final String name) throws MalformedTemplateNameException {
-        try {
-            DefaultTemplateNameFormat.INSTANCE.normalizeRootBasedName(name);
-            fail();
-        } catch (MalformedTemplateNameException e) {
-            assertEquals(name, e.getTemplateName());
-            assertColonException(e);
-        }
-    }
-    
-    private void assertBackingOutFromRootException(MalformedTemplateNameException e) {
-        assertThat(e.getMessage(), containsStringIgnoringCase("backing out"));
-    }
-
-    private void assertColonException(MalformedTemplateNameException e) {
-        assertThat(e.getMessage(), containsString("':'"));
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/templateresolver/TemplateSourceMatcherTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/templateresolver/TemplateSourceMatcherTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/templateresolver/TemplateSourceMatcherTest.java
deleted file mode 100644
index 51273c0..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/templateresolver/TemplateSourceMatcherTest.java
+++ /dev/null
@@ -1,188 +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.templateresolver;
-
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-
-import org.junit.Test;
-
-public class TemplateSourceMatcherTest {
-    
-    @Test
-    public void testPathGlobMatcher() throws IOException {
-        PathGlobMatcher m = new PathGlobMatcher("**/a/?.ftl");
-        assertTrue(m.matches("a/b.ftl", "dummy"));
-        assertTrue(m.matches("x/a/c.ftl", "dummy"));
-        assertFalse(m.matches("a/b.Ftl", "dummy"));
-        assertFalse(m.matches("b.ftl", "dummy"));
-        assertFalse(m.matches("a/bc.ftl", "dummy"));
-        
-        m = new PathGlobMatcher("**/a/?.ftl").caseInsensitive(true);
-        assertTrue(m.matches("A/B.FTL", "dummy"));
-        m.setCaseInsensitive(false);
-        assertFalse(m.matches("A/B.FTL", "dummy"));
-        
-        try {
-            new PathGlobMatcher("/b.ftl");
-            fail();
-        } catch (IllegalArgumentException e) {
-            // Expected
-        }
-    }
-
-    @Test
-    public void testFileNameGlobMatcher() throws IOException {
-        FileNameGlobMatcher m = new FileNameGlobMatcher("a*.ftl");
-        assertTrue(m.matches("ab.ftl", "dummy"));
-        assertTrue(m.matches("dir/ab.ftl", "dummy"));
-        assertTrue(m.matches("/dir/dir/ab.ftl", "dummy"));
-        assertFalse(m.matches("Ab.ftl", "dummy"));
-        assertFalse(m.matches("bb.ftl", "dummy"));
-        assertFalse(m.matches("ab.ftl/x", "dummy"));
-
-        m = new FileNameGlobMatcher("a*.ftl").caseInsensitive(true);
-        assertTrue(m.matches("AB.FTL", "dummy"));
-        m.setCaseInsensitive(false);
-        assertFalse(m.matches("AB.FTL", "dummy"));
-        
-        m = new FileNameGlobMatcher("\u00E1*.ftl").caseInsensitive(true);
-        assertTrue(m.matches("\u00C1b.ftl", "dummy"));
-        
-        try {
-            new FileNameGlobMatcher("dir/a*.ftl");
-            fail();
-        } catch (IllegalArgumentException e) {
-            // Expected
-        }
-    }
-
-    @Test
-    public void testFileExtensionMatcher() throws IOException {
-        FileExtensionMatcher m = new FileExtensionMatcher("ftlx");
-        assertTrue(m.matches("a.ftlx", "dummy"));
-        assertTrue(m.matches(".ftlx", "dummy"));
-        assertTrue(m.matches("b/a.b.ftlx", "dummy"));
-        assertTrue(m.matches("b/a.ftlx", "dummy"));
-        assertTrue(m.matches("c.b/a.ftlx", "dummy"));
-        assertFalse(m.matches("a.ftl", "dummy"));
-        assertFalse(m.matches("ftlx", "dummy"));
-        assertFalse(m.matches("b.ftlx/a.ftl", "dummy"));
-        
-        assertTrue(m.isCaseInsensitive());
-        assertTrue(m.matches("a.fTlX", "dummy"));
-        m.setCaseInsensitive(false);
-        assertFalse(m.matches("a.fTlX", "dummy"));
-        assertTrue(m.matches("A.ftlx", "dummy"));
-        
-        m = new FileExtensionMatcher("");
-        assertTrue(m.matches("a.", "dummy"));
-        assertTrue(m.matches(".", "dummy"));
-        assertFalse(m.matches("a", "dummy"));
-        assertFalse(m.matches("", "dummy"));
-        assertFalse(m.matches("a.x", "dummy"));
-        
-        m = new FileExtensionMatcher("html.t");
-        assertTrue(m.matches("a.html.t", "dummy"));
-        assertFalse(m.matches("a.xhtml.t", "dummy"));
-        assertFalse(m.matches("a.html", "dummy"));
-        assertFalse(m.matches("a.t", "dummy"));
-        
-        try {
-            new FileExtensionMatcher("*.ftlx");
-            fail();
-        } catch (IllegalArgumentException e) {
-            // Expected
-        }
-        try {
-            new FileExtensionMatcher("ftl?");
-            fail();
-        } catch (IllegalArgumentException e) {
-            // Expected
-        }
-        try {
-            new FileExtensionMatcher(".ftlx");
-            fail();
-        } catch (IllegalArgumentException e) {
-            // Expected
-        }
-        try {
-            new FileExtensionMatcher("dir/a.ftl");
-            fail();
-        } catch (IllegalArgumentException e) {
-            // Expected
-        }
-    }
-    
-    @Test
-    public void testPathRegexMatcher() throws IOException {
-        PathRegexMatcher m = new PathRegexMatcher("a/[a-z]+\\.ftl");
-        assertTrue(m.matches("a/b.ftl", "dummy"));
-        assertTrue(m.matches("a/abc.ftl", "dummy"));
-        assertFalse(m.matches("b.ftl", "dummy"));
-        assertFalse(m.matches("b/b.ftl", "dummy"));
-        
-        try {
-            new PathRegexMatcher("/b.ftl");
-            fail();
-        } catch (IllegalArgumentException e) {
-            // Expected
-        }
-    }
-    
-    @Test
-    public void testAndMatcher() throws IOException {
-        AndMatcher m = new AndMatcher(new PathGlobMatcher("a*.*"), new PathGlobMatcher("*.t"));
-        assertTrue(m.matches("ab.t", "dummy"));
-        assertFalse(m.matches("bc.t", "dummy"));
-        assertFalse(m.matches("ab.ftl", "dummy"));
-        
-        try {
-            new AndMatcher();
-            fail();
-        } catch (IllegalArgumentException e) {
-            // Expected
-        }
-    }
-    
-    @Test
-    public void testOrMatcher() throws IOException {
-        OrMatcher m = new OrMatcher(new PathGlobMatcher("a*.*"), new PathGlobMatcher("*.t"));
-        assertTrue(m.matches("ab.t", "dummy"));
-        assertTrue(m.matches("bc.t", "dummy"));
-        assertTrue(m.matches("ab.ftl", "dummy"));
-        assertFalse(m.matches("bc.ftl", "dummy"));
-        
-        try {
-            new OrMatcher();
-            fail();
-        } catch (IllegalArgumentException e) {
-            // Expected
-        }
-    }
-    
-    @Test
-    public void testNotMatcher() throws IOException {
-        NotMatcher m = new NotMatcher(new PathGlobMatcher("a*.*"));
-        assertFalse(m.matches("ab.t", "dummy"));
-        assertTrue(m.matches("bc.t", "dummy"));
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/AppMetaTemplateDateFormatFactory.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/AppMetaTemplateDateFormatFactory.java b/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/AppMetaTemplateDateFormatFactory.java
deleted file mode 100644
index 1d69dd8..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/AppMetaTemplateDateFormatFactory.java
+++ /dev/null
@@ -1,129 +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.userpkg;
-
-import java.util.Date;
-import java.util.Locale;
-import java.util.TimeZone;
-
-import org.apache.freemarker.core.Environment;
-import org.apache.freemarker.core.model.TemplateDateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.valueformat.InvalidFormatParametersException;
-import org.apache.freemarker.core.valueformat.TemplateDateFormat;
-import org.apache.freemarker.core.valueformat.TemplateDateFormatFactory;
-import org.apache.freemarker.core.valueformat.TemplateFormatUtil;
-import org.apache.freemarker.core.valueformat.UnformattableValueException;
-import org.apache.freemarker.core.valueformat.UnknownDateTypeFormattingUnsupportedException;
-import org.apache.freemarker.core.valueformat.UnparsableValueException;
-
-public class AppMetaTemplateDateFormatFactory extends TemplateDateFormatFactory {
-
-    public static final AppMetaTemplateDateFormatFactory INSTANCE = new AppMetaTemplateDateFormatFactory();
-    
-    private AppMetaTemplateDateFormatFactory() {
-        // Defined to decrease visibility
-    }
-    
-    @Override
-    public TemplateDateFormat get(String params, int dateType, Locale locale, TimeZone timeZone, boolean zonelessInput,
-            Environment env) throws UnknownDateTypeFormattingUnsupportedException, InvalidFormatParametersException {
-        TemplateFormatUtil.checkHasNoParameters(params);
-        return AppMetaTemplateDateFormat.INSTANCE;
-    }
-
-    private static class AppMetaTemplateDateFormat extends TemplateDateFormat {
-
-        private static final AppMetaTemplateDateFormat INSTANCE = new AppMetaTemplateDateFormat();
-        
-        private AppMetaTemplateDateFormat() { }
-        
-        @Override
-        public String formatToPlainText(TemplateDateModel dateModel)
-                throws UnformattableValueException, TemplateModelException {
-            String result = String.valueOf(TemplateFormatUtil.getNonNullDate(dateModel).getTime());
-            if (dateModel instanceof AppMetaTemplateDateModel) {
-                result += "/" + ((AppMetaTemplateDateModel) dateModel).getAppMeta(); 
-            }
-            return result;
-        }
-
-        @Override
-        public boolean isLocaleBound() {
-            return false;
-        }
-
-        @Override
-        public boolean isTimeZoneBound() {
-            return false;
-        }
-
-        @Override
-        public Object parse(String s, int dateType) throws UnparsableValueException {
-            int slashIdx = s.indexOf('/');
-            try {
-                if (slashIdx != -1) {
-                    return new AppMetaTemplateDateModel(
-                            new Date(Long.parseLong(s.substring(0,  slashIdx))),
-                            dateType,
-                            s.substring(slashIdx +1));
-                } else {
-                    return new Date(Long.parseLong(s));
-                }
-            } catch (NumberFormatException e) {
-                throw new UnparsableValueException("Malformed long");
-            }
-        }
-
-        @Override
-        public String getDescription() {
-            return "millis since the epoch";
-        }
-        
-    }
-    
-    public static class AppMetaTemplateDateModel implements TemplateDateModel {
-        
-        private final Date date;
-        private final int dateType;
-        private final String appMeta;
-
-        public AppMetaTemplateDateModel(Date date, int dateType, String appMeta) {
-            this.date = date;
-            this.dateType = dateType;
-            this.appMeta = appMeta;
-        }
-
-        @Override
-        public Date getAsDate() throws TemplateModelException {
-            return date;
-        }
-
-        @Override
-        public int getDateType() {
-            return dateType;
-        }
-
-        public String getAppMeta() {
-            return appMeta;
-        }
-        
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/BaseNTemplateNumberFormatFactory.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/BaseNTemplateNumberFormatFactory.java b/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/BaseNTemplateNumberFormatFactory.java
deleted file mode 100644
index e5def77..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/BaseNTemplateNumberFormatFactory.java
+++ /dev/null
@@ -1,128 +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.userpkg;
-
-import java.util.Locale;
-
-import org.apache.freemarker.core.Environment;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateNumberModel;
-import org.apache.freemarker.core.util._NumberUtil;
-import org.apache.freemarker.core.util._StringUtil;
-import org.apache.freemarker.core.valueformat.InvalidFormatParametersException;
-import org.apache.freemarker.core.valueformat.TemplateFormatUtil;
-import org.apache.freemarker.core.valueformat.TemplateNumberFormat;
-import org.apache.freemarker.core.valueformat.TemplateNumberFormatFactory;
-import org.apache.freemarker.core.valueformat.TemplateValueFormatException;
-import org.apache.freemarker.core.valueformat.UnformattableValueException;
-
-/**
- * Shows a number in base N number system. Can only format numbers that fit into an {@code int},
- * however, optionally you can specify a fallback format. This format has one required parameter,
- * the numerical system base. That can be optionally followed by "|" and a fallback format.
- */
-public class BaseNTemplateNumberFormatFactory extends TemplateNumberFormatFactory {
-
-    public static final BaseNTemplateNumberFormatFactory INSTANCE
-            = new BaseNTemplateNumberFormatFactory();
-    
-    private BaseNTemplateNumberFormatFactory() {
-        // Defined to decrease visibility
-    }
-    
-    @Override
-    public TemplateNumberFormat get(String params, Locale locale, Environment env)
-            throws InvalidFormatParametersException {
-        TemplateNumberFormat fallbackFormat;
-        {
-            int barIdx = params.indexOf('|');
-            if (barIdx != -1) {
-                String fallbackFormatStr = params.substring(barIdx + 1);
-                params = params.substring(0, barIdx);
-                try {
-                    fallbackFormat = env.getTemplateNumberFormat(fallbackFormatStr, locale);
-                } catch (TemplateValueFormatException e) {
-                    throw new InvalidFormatParametersException(
-                            "Couldn't get the fallback number format (specified after the \"|\"), "
-                            + _StringUtil.jQuote(fallbackFormatStr) + ". Reason: " + e.getMessage(),
-                            e);
-                }
-            } else {
-                fallbackFormat = null;
-            }
-        }
-        
-        int base;
-        try {
-            base = Integer.parseInt(params);
-        } catch (NumberFormatException e) {
-            if (params.length() == 0) {
-                throw new InvalidFormatParametersException(
-                        "A format parameter is required to specify the numerical system base.");
-            }
-            throw new InvalidFormatParametersException(
-                    "The format paramter must be an integer, but was (shown quoted): "
-                    + _StringUtil.jQuote(params));
-        }
-        if (base < 2) {
-            throw new InvalidFormatParametersException("A base must be at least 2.");
-        }
-        return new BaseNTemplateNumberFormat(base, fallbackFormat);
-    }
-
-    private static class BaseNTemplateNumberFormat extends TemplateNumberFormat {
-
-        private final int base;
-        private final TemplateNumberFormat fallbackFormat;
-        
-        private BaseNTemplateNumberFormat(int base, TemplateNumberFormat fallbackFormat) {
-            this.base = base;
-            this.fallbackFormat = fallbackFormat;
-        }
-        
-        @Override
-        public String formatToPlainText(TemplateNumberModel numberModel)
-                throws TemplateModelException, TemplateValueFormatException {
-            Number n = TemplateFormatUtil.getNonNullNumber(numberModel);
-            try {
-                return Integer.toString(_NumberUtil.toIntExact(n), base);
-            } catch (ArithmeticException e) {
-                if (fallbackFormat == null) {
-                    throw new UnformattableValueException(
-                            n + " doesn't fit into an int, and there was no fallback format "
-                            + "specified.");
-                } else {
-                    return fallbackFormat.formatToPlainText(numberModel);
-                }
-            }
-        }
-
-        @Override
-        public boolean isLocaleBound() {
-            return false;
-        }
-
-        @Override
-        public String getDescription() {
-            return "base " + base;
-        }
-        
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/CustomHTMLOutputFormat.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/CustomHTMLOutputFormat.java b/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/CustomHTMLOutputFormat.java
deleted file mode 100644
index f570a66..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/CustomHTMLOutputFormat.java
+++ /dev/null
@@ -1,72 +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.userpkg;
-
-import java.io.IOException;
-import java.io.Writer;
-
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.outputformat.CommonMarkupOutputFormat;
-import org.apache.freemarker.core.util._StringUtil;
-
-/**
- * Represents the HTML output format.
- * 
- * @since 2.3.24
- */
-public final class CustomHTMLOutputFormat extends CommonMarkupOutputFormat<CustomTemplateHTMLModel> {
-
-    public static final CustomHTMLOutputFormat INSTANCE = new CustomHTMLOutputFormat();
-    
-    private CustomHTMLOutputFormat() {
-        // Only to decrease visibility
-    }
-    
-    @Override
-    public String getName() {
-        return "HTML";
-    }
-
-    @Override
-    public String getMimeType() {
-        return "text/html";
-    }
-
-    @Override
-    public void output(String textToEsc, Writer out) throws IOException, TemplateModelException {
-        // This is lazy - don't do it in reality.
-        out.write(escapePlainText(textToEsc));
-    }
-
-    @Override
-    public String escapePlainText(String plainTextContent) {
-        return _StringUtil.XHTMLEnc(plainTextContent.replace('x', 'X'));
-    }
-
-    @Override
-    public boolean isLegacyBuiltInBypassed(String builtInName) {
-        return builtInName.equals("html") || builtInName.equals("xml") || builtInName.equals("xhtml");
-    }
-
-    @Override
-    protected CustomTemplateHTMLModel newTemplateMarkupOutputModel(String plainTextContent, String markupContent) {
-        return new CustomTemplateHTMLModel(plainTextContent, markupContent);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/CustomTemplateHTMLModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/CustomTemplateHTMLModel.java b/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/CustomTemplateHTMLModel.java
deleted file mode 100644
index 4cc67be..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/CustomTemplateHTMLModel.java
+++ /dev/null
@@ -1,34 +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.userpkg;
-
-import org.apache.freemarker.core.outputformat.CommonTemplateMarkupOutputModel;
-
-public final class CustomTemplateHTMLModel extends CommonTemplateMarkupOutputModel<CustomTemplateHTMLModel> {
-    
-    CustomTemplateHTMLModel(String plainTextContent, String markupContent) {
-        super(plainTextContent, markupContent);
-    }
-
-    @Override
-    public CustomHTMLOutputFormat getOutputFormat() {
-        return CustomHTMLOutputFormat.INSTANCE;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/DummyOutputFormat.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/DummyOutputFormat.java b/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/DummyOutputFormat.java
deleted file mode 100644
index f368969..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/DummyOutputFormat.java
+++ /dev/null
@@ -1,65 +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.userpkg;
-
-import java.io.IOException;
-import java.io.Writer;
-
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.outputformat.CommonMarkupOutputFormat;
-
-public class DummyOutputFormat extends CommonMarkupOutputFormat<TemplateDummyOutputModel> {
-    
-    public static final DummyOutputFormat INSTANCE = new DummyOutputFormat();
-    
-    private DummyOutputFormat() {
-        // hide
-    }
-
-    @Override
-    public String getName() {
-        return "dummy";
-    }
-
-    @Override
-    public String getMimeType() {
-        return "text/dummy";
-    }
-
-    @Override
-    public void output(String textToEsc, Writer out) throws IOException, TemplateModelException {
-        out.write(escapePlainText(textToEsc));
-    }
-
-    @Override
-    public String escapePlainText(String plainTextContent) {
-        return plainTextContent.replaceAll("(\\.|\\\\)", "\\\\$1");
-    }
-
-    @Override
-    public boolean isLegacyBuiltInBypassed(String builtInName) {
-        return false;
-    }
-
-    @Override
-    protected TemplateDummyOutputModel newTemplateMarkupOutputModel(String plainTextContent, String markupContent) {
-        return new TemplateDummyOutputModel(plainTextContent, markupContent);
-    }
-    
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/EpochMillisDivTemplateDateFormatFactory.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/EpochMillisDivTemplateDateFormatFactory.java b/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/EpochMillisDivTemplateDateFormatFactory.java
deleted file mode 100644
index 8799eef..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/EpochMillisDivTemplateDateFormatFactory.java
+++ /dev/null
@@ -1,102 +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.userpkg;
-
-import java.util.Date;
-import java.util.Locale;
-import java.util.TimeZone;
-
-import org.apache.freemarker.core.Environment;
-import org.apache.freemarker.core.model.TemplateDateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.util._StringUtil;
-import org.apache.freemarker.core.valueformat.InvalidFormatParametersException;
-import org.apache.freemarker.core.valueformat.TemplateDateFormat;
-import org.apache.freemarker.core.valueformat.TemplateDateFormatFactory;
-import org.apache.freemarker.core.valueformat.TemplateFormatUtil;
-import org.apache.freemarker.core.valueformat.UnformattableValueException;
-import org.apache.freemarker.core.valueformat.UnknownDateTypeFormattingUnsupportedException;
-import org.apache.freemarker.core.valueformat.UnparsableValueException;
-
-public class EpochMillisDivTemplateDateFormatFactory extends TemplateDateFormatFactory {
-
-    public static final EpochMillisDivTemplateDateFormatFactory INSTANCE = new EpochMillisDivTemplateDateFormatFactory();
-    
-    private EpochMillisDivTemplateDateFormatFactory() {
-        // Defined to decrease visibility
-    }
-    
-    @Override
-    public TemplateDateFormat get(String params, int dateType, Locale locale, TimeZone timeZone, boolean zonelessInput,
-            Environment env) throws UnknownDateTypeFormattingUnsupportedException, InvalidFormatParametersException {
-        int divisor;
-        try {
-            divisor = Integer.parseInt(params);
-        } catch (NumberFormatException e) {
-            if (params.length() == 0) {
-                throw new InvalidFormatParametersException(
-                        "A format parameter is required, which specifies the divisor.");
-            }
-            throw new InvalidFormatParametersException(
-                    "The format paramter must be an integer, but was (shown quoted): " + _StringUtil.jQuote(params));
-        }
-        return new EpochMillisDivTemplateDateFormat(divisor);
-    }
-
-    private static class EpochMillisDivTemplateDateFormat extends TemplateDateFormat {
-
-        private final int divisor;
-        
-        private EpochMillisDivTemplateDateFormat(int divisor) {
-            this.divisor = divisor;
-        }
-        
-        @Override
-        public String formatToPlainText(TemplateDateModel dateModel)
-                throws UnformattableValueException, TemplateModelException {
-            return String.valueOf(TemplateFormatUtil.getNonNullDate(dateModel).getTime() / divisor);
-        }
-
-        @Override
-        public boolean isLocaleBound() {
-            return false;
-        }
-
-        @Override
-        public boolean isTimeZoneBound() {
-            return false;
-        }
-
-        @Override
-        public Date parse(String s, int dateType) throws UnparsableValueException {
-            try {
-                return new Date(Long.parseLong(s));
-            } catch (NumberFormatException e) {
-                throw new UnparsableValueException("Malformed long");
-            }
-        }
-
-        @Override
-        public String getDescription() {
-            return "millis since the epoch";
-        }
-        
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/EpochMillisTemplateDateFormatFactory.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/EpochMillisTemplateDateFormatFactory.java b/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/EpochMillisTemplateDateFormatFactory.java
deleted file mode 100644
index 9f27095..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/EpochMillisTemplateDateFormatFactory.java
+++ /dev/null
@@ -1,92 +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.userpkg;
-
-import java.util.Date;
-import java.util.Locale;
-import java.util.TimeZone;
-
-import org.apache.freemarker.core.Environment;
-import org.apache.freemarker.core.model.TemplateDateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.valueformat.InvalidFormatParametersException;
-import org.apache.freemarker.core.valueformat.TemplateDateFormat;
-import org.apache.freemarker.core.valueformat.TemplateDateFormatFactory;
-import org.apache.freemarker.core.valueformat.TemplateFormatUtil;
-import org.apache.freemarker.core.valueformat.UnformattableValueException;
-import org.apache.freemarker.core.valueformat.UnparsableValueException;
-
-public class EpochMillisTemplateDateFormatFactory extends TemplateDateFormatFactory {
-
-    public static final EpochMillisTemplateDateFormatFactory INSTANCE
-            = new EpochMillisTemplateDateFormatFactory();
-    
-    private EpochMillisTemplateDateFormatFactory() {
-        // Defined to decrease visibility
-    }
-    
-    @Override
-    public TemplateDateFormat get(String params, int dateType,
-            Locale locale, TimeZone timeZone, boolean zonelessInput,
-            Environment env)
-            throws InvalidFormatParametersException {
-        TemplateFormatUtil.checkHasNoParameters(params);
-        return EpochMillisTemplateDateFormat.INSTANCE;
-    }
-
-    private static class EpochMillisTemplateDateFormat extends TemplateDateFormat {
-
-        private static final EpochMillisTemplateDateFormat INSTANCE
-                = new EpochMillisTemplateDateFormat();
-        
-        private EpochMillisTemplateDateFormat() { }
-        
-        @Override
-        public String formatToPlainText(TemplateDateModel dateModel)
-                throws UnformattableValueException, TemplateModelException {
-            return String.valueOf(TemplateFormatUtil.getNonNullDate(dateModel).getTime());
-        }
-
-        @Override
-        public boolean isLocaleBound() {
-            return false;
-        }
-
-        @Override
-        public boolean isTimeZoneBound() {
-            return false;
-        }
-
-        @Override
-        public Date parse(String s, int dateType) throws UnparsableValueException {
-            try {
-                return new Date(Long.parseLong(s));
-            } catch (NumberFormatException e) {
-                throw new UnparsableValueException("Malformed long");
-            }
-        }
-
-        @Override
-        public String getDescription() {
-            return "millis since the epoch";
-        }
-        
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/HTMLISOTemplateDateFormatFactory.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/HTMLISOTemplateDateFormatFactory.java b/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/HTMLISOTemplateDateFormatFactory.java
deleted file mode 100644
index 357034c..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/HTMLISOTemplateDateFormatFactory.java
+++ /dev/null
@@ -1,114 +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.userpkg;
-
-import java.util.Date;
-import java.util.Locale;
-import java.util.TimeZone;
-
-import org.apache.freemarker.core.Environment;
-import org.apache.freemarker.core.model.TemplateDateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat;
-import org.apache.freemarker.core.util._DateUtil;
-import org.apache.freemarker.core.util._DateUtil.CalendarFieldsToDateConverter;
-import org.apache.freemarker.core.util._DateUtil.DateParseException;
-import org.apache.freemarker.core.valueformat.InvalidFormatParametersException;
-import org.apache.freemarker.core.valueformat.TemplateDateFormat;
-import org.apache.freemarker.core.valueformat.TemplateDateFormatFactory;
-import org.apache.freemarker.core.valueformat.TemplateFormatUtil;
-import org.apache.freemarker.core.valueformat.TemplateValueFormatException;
-import org.apache.freemarker.core.valueformat.UnformattableValueException;
-import org.apache.freemarker.core.valueformat.UnknownDateTypeFormattingUnsupportedException;
-import org.apache.freemarker.core.valueformat.UnparsableValueException;
-
-public class HTMLISOTemplateDateFormatFactory extends TemplateDateFormatFactory {
-
-    public static final HTMLISOTemplateDateFormatFactory INSTANCE = new HTMLISOTemplateDateFormatFactory();
-    
-    private HTMLISOTemplateDateFormatFactory() {
-        // Defined to decrease visibility
-    }
-    
-    @Override
-    public TemplateDateFormat get(String params, int dateType, Locale locale, TimeZone timeZone, boolean zonelessInput,
-            Environment env) throws UnknownDateTypeFormattingUnsupportedException, InvalidFormatParametersException {
-        TemplateFormatUtil.checkHasNoParameters(params);
-        return HTMLISOTemplateDateFormat.INSTANCE;
-    }
-
-    private static class HTMLISOTemplateDateFormat extends TemplateDateFormat {
-
-        private static final HTMLISOTemplateDateFormat INSTANCE = new HTMLISOTemplateDateFormat();
-
-        private _DateUtil.TrivialDateToISO8601CalendarFactory calendarFactory;
-
-        private CalendarFieldsToDateConverter calToDateConverter;
-        
-        private HTMLISOTemplateDateFormat() { }
-        
-        @Override
-        public String formatToPlainText(TemplateDateModel dateModel)
-                throws UnformattableValueException, TemplateModelException {
-            if (calendarFactory == null) {
-                calendarFactory = new _DateUtil.TrivialDateToISO8601CalendarFactory();
-            }
-            return _DateUtil.dateToISO8601String(
-                    TemplateFormatUtil.getNonNullDate(dateModel),
-                    true, true, true, _DateUtil.ACCURACY_SECONDS, _DateUtil.UTC,
-                    calendarFactory);
-        }
-
-        @Override
-        public boolean isLocaleBound() {
-            return false;
-        }
-
-        @Override
-        public boolean isTimeZoneBound() {
-            return false;
-        }
-
-        @Override
-        public Date parse(String s, int dateType) throws UnparsableValueException {
-            try {
-                if (calToDateConverter == null) {
-                    calToDateConverter = new _DateUtil.TrivialCalendarFieldsToDateConverter();
-                }
-                return _DateUtil.parseISO8601DateTime(s, _DateUtil.UTC, calToDateConverter);
-            } catch (DateParseException e) {
-                throw new UnparsableValueException("Malformed ISO date-time", e);
-            }
-        }
-
-        @Override
-        public Object format(TemplateDateModel dateModel) throws TemplateValueFormatException, TemplateModelException {
-            return HTMLOutputFormat.INSTANCE.fromMarkup(
-                    formatToPlainText(dateModel).replace("T", "<span class='T'>T</span>"));
-        }
-
-        @Override
-        public String getDescription() {
-            return "ISO UTC HTML";
-        }
-        
-    }
-
-}
- 
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/HexTemplateNumberFormatFactory.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/HexTemplateNumberFormatFactory.java b/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/HexTemplateNumberFormatFactory.java
deleted file mode 100644
index 6d72c20..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/HexTemplateNumberFormatFactory.java
+++ /dev/null
@@ -1,77 +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.userpkg;
-
-import java.util.Locale;
-
-import org.apache.freemarker.core.Environment;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateNumberModel;
-import org.apache.freemarker.core.util._NumberUtil;
-import org.apache.freemarker.core.valueformat.InvalidFormatParametersException;
-import org.apache.freemarker.core.valueformat.TemplateFormatUtil;
-import org.apache.freemarker.core.valueformat.TemplateNumberFormat;
-import org.apache.freemarker.core.valueformat.TemplateNumberFormatFactory;
-import org.apache.freemarker.core.valueformat.UnformattableValueException;
-
-public class HexTemplateNumberFormatFactory extends TemplateNumberFormatFactory {
-
-    public static final HexTemplateNumberFormatFactory INSTANCE = new HexTemplateNumberFormatFactory();
-    
-    private HexTemplateNumberFormatFactory() {
-        // Defined to decrease visibility
-    }
-    
-    @Override
-    public TemplateNumberFormat get(String params, Locale locale, Environment env)
-            throws InvalidFormatParametersException {
-        TemplateFormatUtil.checkHasNoParameters(params);
-        return HexTemplateNumberFormat.INSTANCE;
-    }
-
-    private static class HexTemplateNumberFormat extends TemplateNumberFormat {
-
-        private static final HexTemplateNumberFormat INSTANCE = new HexTemplateNumberFormat();
-        
-        private HexTemplateNumberFormat() { }
-        
-        @Override
-        public String formatToPlainText(TemplateNumberModel numberModel)
-                throws UnformattableValueException, TemplateModelException {
-            Number n = TemplateFormatUtil.getNonNullNumber(numberModel);
-            try {
-                return Integer.toHexString(_NumberUtil.toIntExact(n));
-            } catch (ArithmeticException e) {
-                throw new UnformattableValueException(n + " doesn't fit into an int");
-            }
-        }
-
-        @Override
-        public boolean isLocaleBound() {
-            return false;
-        }
-
-        @Override
-        public String getDescription() {
-            return "hexadecimal int";
-        }
-        
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/LocAndTZSensitiveTemplateDateFormatFactory.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/LocAndTZSensitiveTemplateDateFormatFactory.java b/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/LocAndTZSensitiveTemplateDateFormatFactory.java
deleted file mode 100644
index 42b0401..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/LocAndTZSensitiveTemplateDateFormatFactory.java
+++ /dev/null
@@ -1,97 +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.userpkg;
-
-import java.util.Date;
-import java.util.Locale;
-import java.util.TimeZone;
-
-import org.apache.freemarker.core.Environment;
-import org.apache.freemarker.core.model.TemplateDateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.valueformat.InvalidFormatParametersException;
-import org.apache.freemarker.core.valueformat.TemplateDateFormat;
-import org.apache.freemarker.core.valueformat.TemplateDateFormatFactory;
-import org.apache.freemarker.core.valueformat.TemplateFormatUtil;
-import org.apache.freemarker.core.valueformat.UnformattableValueException;
-import org.apache.freemarker.core.valueformat.UnknownDateTypeFormattingUnsupportedException;
-import org.apache.freemarker.core.valueformat.UnparsableValueException;
-
-public class LocAndTZSensitiveTemplateDateFormatFactory extends TemplateDateFormatFactory {
-
-    public static final LocAndTZSensitiveTemplateDateFormatFactory INSTANCE = new LocAndTZSensitiveTemplateDateFormatFactory();
-    
-    private LocAndTZSensitiveTemplateDateFormatFactory() {
-        // Defined to decrease visibility
-    }
-    
-    @Override
-    public TemplateDateFormat get(String params, int dateType, Locale locale, TimeZone timeZone, boolean zonelessInput,
-            Environment env) throws UnknownDateTypeFormattingUnsupportedException, InvalidFormatParametersException {
-        TemplateFormatUtil.checkHasNoParameters(params);
-        return new LocAndTZSensitiveTemplateDateFormat(locale, timeZone);
-    }
-
-    private static class LocAndTZSensitiveTemplateDateFormat extends TemplateDateFormat {
-
-        private final Locale locale;
-        private final TimeZone timeZone;
-        
-        public LocAndTZSensitiveTemplateDateFormat(Locale locale, TimeZone timeZone) {
-            this.locale = locale;
-            this.timeZone = timeZone;
-        }
-
-        @Override
-        public String formatToPlainText(TemplateDateModel dateModel)
-                throws UnformattableValueException, TemplateModelException {
-            return String.valueOf(TemplateFormatUtil.getNonNullDate(dateModel).getTime() + "@" + locale + ":" + timeZone.getID());
-        }
-
-        @Override
-        public boolean isLocaleBound() {
-            return true;
-        }
-
-        @Override
-        public boolean isTimeZoneBound() {
-            return true;
-        }
-
-        @Override
-        public Date parse(String s, int dateType) throws UnparsableValueException {
-            try {
-                int atIdx = s.indexOf("@");
-                if (atIdx == -1) {
-                    throw new UnparsableValueException("Missing @");
-                }
-                return new Date(Long.parseLong(s.substring(0, atIdx)));
-            } catch (NumberFormatException e) {
-                throw new UnparsableValueException("Malformed long");
-            }
-        }
-
-        @Override
-        public String getDescription() {
-            return "millis since the epoch";
-        }
-        
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/LocaleSensitiveTemplateNumberFormatFactory.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/LocaleSensitiveTemplateNumberFormatFactory.java b/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/LocaleSensitiveTemplateNumberFormatFactory.java
deleted file mode 100644
index dc3dae0..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/LocaleSensitiveTemplateNumberFormatFactory.java
+++ /dev/null
@@ -1,78 +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.userpkg;
-
-import java.util.Locale;
-
-import org.apache.freemarker.core.Environment;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateNumberModel;
-import org.apache.freemarker.core.valueformat.InvalidFormatParametersException;
-import org.apache.freemarker.core.valueformat.TemplateFormatUtil;
-import org.apache.freemarker.core.valueformat.TemplateNumberFormat;
-import org.apache.freemarker.core.valueformat.TemplateNumberFormatFactory;
-import org.apache.freemarker.core.valueformat.UnformattableValueException;
-
-public class LocaleSensitiveTemplateNumberFormatFactory extends TemplateNumberFormatFactory {
-
-    public static final LocaleSensitiveTemplateNumberFormatFactory INSTANCE = new LocaleSensitiveTemplateNumberFormatFactory();
-    
-    private LocaleSensitiveTemplateNumberFormatFactory() {
-        // Defined to decrease visibility
-    }
-    
-    @Override
-    public TemplateNumberFormat get(String params, Locale locale, Environment env)
-            throws InvalidFormatParametersException {
-        TemplateFormatUtil.checkHasNoParameters(params);
-        return new LocaleSensitiveTemplateNumberFormat(locale);
-    }
-
-    private static class LocaleSensitiveTemplateNumberFormat extends TemplateNumberFormat {
-    
-        private final Locale locale;
-        
-        private LocaleSensitiveTemplateNumberFormat(Locale locale) {
-            this.locale = locale;
-        }
-        
-        @Override
-        public String formatToPlainText(TemplateNumberModel numberModel)
-                throws UnformattableValueException, TemplateModelException {
-            Number n = numberModel.getAsNumber();
-            try {
-                return n + "_" + locale;
-            } catch (ArithmeticException e) {
-                throw new UnformattableValueException(n + " doesn't fit into an int");
-            }
-        }
-    
-        @Override
-        public boolean isLocaleBound() {
-            return true;
-        }
-    
-        @Override
-        public String getDescription() {
-            return "test locale sensitive";
-        }
-        
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/PackageVisibleAll.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/PackageVisibleAll.java b/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/PackageVisibleAll.java
deleted file mode 100644
index f3ebc72..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/PackageVisibleAll.java
+++ /dev/null
@@ -1,26 +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.userpkg;
-
-class PackageVisibleAll {
-    
-    PackageVisibleAll() {}
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/PackageVisibleAllWithBuilder.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/PackageVisibleAllWithBuilder.java b/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/PackageVisibleAllWithBuilder.java
deleted file mode 100644
index 53a89d4..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/PackageVisibleAllWithBuilder.java
+++ /dev/null
@@ -1,26 +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.userpkg;
-
-class PackageVisibleAllWithBuilder {
-
-    PackageVisibleAllWithBuilder() {}
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/PackageVisibleAllWithBuilderBuilder.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/PackageVisibleAllWithBuilderBuilder.java b/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/PackageVisibleAllWithBuilderBuilder.java
deleted file mode 100644
index 510ecc2..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/PackageVisibleAllWithBuilderBuilder.java
+++ /dev/null
@@ -1,28 +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.userpkg;
-
-public class PackageVisibleAllWithBuilderBuilder {
-    
-    public PackageVisibleAllWithBuilder build() {
-        return new PackageVisibleAllWithBuilder();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/PackageVisibleWithPublicConstructor.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/PackageVisibleWithPublicConstructor.java b/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/PackageVisibleWithPublicConstructor.java
deleted file mode 100644
index 836e80d..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/PackageVisibleWithPublicConstructor.java
+++ /dev/null
@@ -1,27 +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.userpkg;
-
-class PackageVisibleWithPublicConstructor {
-    
-    public PackageVisibleWithPublicConstructor() {
-    }
-
-}


[46/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/InterpretAndEvalTemplateNameTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/InterpretAndEvalTemplateNameTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/InterpretAndEvalTemplateNameTest.java
new file mode 100644
index 0000000..ff5897f
--- /dev/null
+++ b/freemarker-core-test/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/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/InterpretSettingInheritanceTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/InterpretSettingInheritanceTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/InterpretSettingInheritanceTest.java
new file mode 100644
index 0000000..2d061d7
--- /dev/null
+++ b/freemarker-core-test/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/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/IteratorIssuesTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/IteratorIssuesTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/IteratorIssuesTest.java
new file mode 100644
index 0000000..08fcee2
--- /dev/null
+++ b/freemarker-core-test/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/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/JavaCCExceptionAsEOFFixTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/JavaCCExceptionAsEOFFixTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/JavaCCExceptionAsEOFFixTest.java
new file mode 100644
index 0000000..0fa3f79
--- /dev/null
+++ b/freemarker-core-test/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/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/ListErrorsTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/ListErrorsTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ListErrorsTest.java
new file mode 100644
index 0000000..05bac4f
--- /dev/null
+++ b/freemarker-core-test/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/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/MiscErrorMessagesTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/MiscErrorMessagesTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/MiscErrorMessagesTest.java
new file mode 100644
index 0000000..1903e05
--- /dev/null
+++ b/freemarker-core-test/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/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/MistakenlyPublicImportAPIsTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/MistakenlyPublicImportAPIsTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/MistakenlyPublicImportAPIsTest.java
new file mode 100644
index 0000000..5fcee97
--- /dev/null
+++ b/freemarker-core-test/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/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/MistakenlyPublicMacroAPIsTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/MistakenlyPublicMacroAPIsTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/MistakenlyPublicMacroAPIsTest.java
new file mode 100644
index 0000000..9c87e61
--- /dev/null
+++ b/freemarker-core-test/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/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/NewBiObjectWrapperRestrictionTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/NewBiObjectWrapperRestrictionTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/NewBiObjectWrapperRestrictionTest.java
new file mode 100644
index 0000000..506101d
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/NewBiObjectWrapperRestrictionTest.java
@@ -0,0 +1,117 @@
+/*
+ * 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.util.Arrays;
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.freemarker.core.model.ObjectWrapper;
+import org.apache.freemarker.core.model.TemplateBooleanModel;
+import org.apache.freemarker.core.model.TemplateDateModel;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateModelAdapter;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.impl.DefaultObjectWrapper;
+import org.apache.freemarker.core.model.impl.SimpleDate;
+import org.apache.freemarker.core.model.impl.SimpleHash;
+import org.apache.freemarker.core.model.impl.SimpleNumber;
+import org.apache.freemarker.core.model.impl.SimpleScalar;
+import org.apache.freemarker.core.model.impl.SimpleSequence;
+import org.apache.freemarker.test.TemplateTest;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+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");
+    }
+
+    /**
+     * An object wrapper that doesn't extend {@link DefaultObjectWrapper}.
+     */
+    public static class EntirelyCustomObjectWrapper implements ObjectWrapper {
+
+        @Override
+        public TemplateModel wrap(Object obj) throws TemplateModelException {
+            if (obj == null) {
+                return null;
+            }
+
+            if (obj instanceof TemplateModel) {
+                return (TemplateModel) obj;
+            }
+            if (obj instanceof TemplateModelAdapter) {
+                return ((TemplateModelAdapter) obj).getTemplateModel();
+            }
+
+            if (obj instanceof String) {
+                return new SimpleScalar((String) obj);
+            }
+            if (obj instanceof Number) {
+                return new SimpleNumber((Number) obj);
+            }
+            if (obj instanceof Boolean) {
+                return obj.equals(Boolean.TRUE) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
+            }
+            if (obj instanceof java.util.Date) {
+                if (obj instanceof java.sql.Date) {
+                    return new SimpleDate((java.sql.Date) obj);
+                }
+                if (obj instanceof java.sql.Time) {
+                    return new SimpleDate((java.sql.Time) obj);
+                }
+                if (obj instanceof java.sql.Timestamp) {
+                    return new SimpleDate((java.sql.Timestamp) obj);
+                }
+                return new SimpleDate((java.util.Date) obj, TemplateDateModel.UNKNOWN);
+            }
+
+            if (obj.getClass().isArray()) {
+                obj = Arrays.asList((Object[]) obj);
+            }
+            if (obj instanceof Collection) {
+                return new SimpleSequence((Collection<?>) obj, this);
+            }
+            if (obj instanceof Map) {
+                return new SimpleHash((Map<?, ?>) obj, this);
+            }
+
+            return null;
+        }
+    }
+}



[09/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/util/StringUtilTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/util/StringUtilTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/util/StringUtilTest.java
deleted file mode 100644
index 2a0ae9d..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/util/StringUtilTest.java
+++ /dev/null
@@ -1,403 +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.util;
-
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.io.StringWriter;
-import java.util.regex.Pattern;
-
-import org.hamcrest.Matchers;
-import org.junit.Test;
-
-public class StringUtilTest {
-
-    @Test
-    public void testV2319() {
-        assertEquals("\\n\\r\\f\\b\\t\\x00\\x19", _StringUtil.javaScriptStringEnc("\n\r\f\b\t\u0000\u0019"));
-    }
-
-    @Test
-    public void testControlChars() {
-        assertEsc(
-                "\n\r\f\b\t \u0000\u0019\u001F \u007F\u0080\u009F \u2028\u2029",
-                "\\n\\r\\f\\b\\t \\x00\\x19\\x1F \\x7F\\x80\\x9F \\u2028\\u2029",
-                "\\n\\r\\f\\b\\t \\u0000\\u0019\\u001F \\u007F\\u0080\\u009F \\u2028\\u2029");
-    }
-
-    @Test
-    public void testHtmlChars() {
-        assertEsc(
-                "<safe>/>->]> </foo> <!-- --> <![CDATA[ ]]> <?php?>",
-                "<safe>/>->]> <\\/foo> \\x3C!-- --\\> \\x3C![CDATA[ ]]\\> \\x3C?php?>",
-                "<safe>/>->]> <\\/foo> \\u003C!-- --\\u003E \\u003C![CDATA[ ]]\\u003E \\u003C?php?>");
-        assertEsc("<!c", "\\x3C!c", "\\u003C!c");
-        assertEsc("c<!", "c\\x3C!", "c\\u003C!");
-        assertEsc("c<", "c\\x3C", "c\\u003C");
-        assertEsc("c<c", "c<c", "c<c");
-        assertEsc("<c", "<c", "<c");
-        assertEsc(">", "\\>", "\\u003E");
-        assertEsc("->", "-\\>", "-\\u003E");
-        assertEsc("-->", "--\\>", "--\\u003E");
-        assertEsc("c-->", "c--\\>", "c--\\u003E");
-        assertEsc("-->c", "--\\>c", "--\\u003Ec");
-        assertEsc("]>", "]\\>", "]\\u003E");
-        assertEsc("]]>", "]]\\>", "]]\\u003E");
-        assertEsc("c]]>", "c]]\\>", "c]]\\u003E");
-        assertEsc("]]>c", "]]\\>c", "]]\\u003Ec");
-        assertEsc("c->", "c->", "c->");
-        assertEsc("c>", "c>", "c>");
-        assertEsc("-->", "--\\>", "--\\u003E");
-        assertEsc("/", "\\/", "\\/");
-        assertEsc("/c", "\\/c", "\\/c");
-        assertEsc("</", "<\\/", "<\\/");
-        assertEsc("</c", "<\\/c", "<\\/c");
-        assertEsc("c/", "c/", "c/");
-    }
-
-    @Test
-    public void testJSChars() {
-        assertEsc("\"", "\\\"", "\\\"");
-        assertEsc("'", "\\'", "'");
-        assertEsc("\\", "\\\\", "\\\\");
-    }
-
-    @Test
-    public void testSameStringsReturned() {
-        String s = "==> I/m <safe>!";
-        assertTrue(s == _StringUtil.jsStringEnc(s, false));  // "==" because is must return the same object
-        assertTrue(s == _StringUtil.jsStringEnc(s, true));
-
-        s = "";
-        assertTrue(s == _StringUtil.jsStringEnc(s, false));
-        assertTrue(s == _StringUtil.jsStringEnc(s, true));
-
-        s = "\u00E1rv\u00EDzt\u0171r\u0151 \u3020";
-        assertEquals(s, _StringUtil.jsStringEnc(s, false));
-        assertTrue(s == _StringUtil.jsStringEnc(s, false));
-        assertTrue(s == _StringUtil.jsStringEnc(s, true));
-    }
-
-    @Test
-    public void testOneOffs() {
-        assertEsc("c\"c\"cc\"\"c", "c\\\"c\\\"cc\\\"\\\"c", "c\\\"c\\\"cc\\\"\\\"c");
-        assertEsc("\"c\"cc\"", "\\\"c\\\"cc\\\"", "\\\"c\\\"cc\\\"");
-        assertEsc("c/c/cc//c", "c/c/cc//c", "c/c/cc//c");
-        assertEsc("c<c<cc<<c", "c<c<cc<<c", "c<c<cc<<c");
-        assertEsc("/<", "\\/\\x3C", "\\/\\u003C");
-        assertEsc(">", "\\>", "\\u003E");
-        assertEsc("]>", "]\\>", "]\\u003E");
-        assertEsc("->", "-\\>", "-\\u003E");
-    }
-
-    private void assertEsc(String s, String javaScript, String json) {
-        assertEquals(javaScript, _StringUtil.jsStringEnc(s, false));
-        assertEquals(json, _StringUtil.jsStringEnc(s, true));
-    }
-
-    @Test
-    public void testTrim() {
-        assertSame(_CollectionUtil.EMPTY_CHAR_ARRAY, _StringUtil.trim(_CollectionUtil.EMPTY_CHAR_ARRAY));
-        assertSame(_CollectionUtil.EMPTY_CHAR_ARRAY, _StringUtil.trim(" \t\u0001 ".toCharArray()));
-        {
-            char[] cs = "foo".toCharArray();
-            assertSame(cs, cs);
-        }
-        assertArrayEquals("foo".toCharArray(), _StringUtil.trim("foo ".toCharArray()));
-        assertArrayEquals("foo".toCharArray(), _StringUtil.trim(" foo".toCharArray()));
-        assertArrayEquals("foo".toCharArray(), _StringUtil.trim(" foo ".toCharArray()));
-        assertArrayEquals("foo".toCharArray(), _StringUtil.trim("\t\tfoo \r\n".toCharArray()));
-        assertArrayEquals("x".toCharArray(), _StringUtil.trim(" x ".toCharArray()));
-        assertArrayEquals("x y z".toCharArray(), _StringUtil.trim(" x y z ".toCharArray()));
-    }
-
-    @Test
-    public void testIsTrimmedToEmpty() {
-        assertTrue(_StringUtil.isTrimmableToEmpty("".toCharArray()));
-        assertTrue(_StringUtil.isTrimmableToEmpty("\r\r\n\u0001".toCharArray()));
-        assertFalse(_StringUtil.isTrimmableToEmpty("x".toCharArray()));
-        assertFalse(_StringUtil.isTrimmableToEmpty("  x  ".toCharArray()));
-    }
-    
-    @Test
-    public void testJQuote() {
-        assertEquals("null", _StringUtil.jQuote(null));
-        assertEquals("\"foo\"", _StringUtil.jQuote("foo"));
-        assertEquals("\"123\"", _StringUtil.jQuote(Integer.valueOf(123)));
-        assertEquals("\"foo's \\\"bar\\\"\"",
-                _StringUtil.jQuote("foo's \"bar\""));
-        assertEquals("\"\\n\\r\\t\\u0001\"",
-                _StringUtil.jQuote("\n\r\t\u0001"));
-        assertEquals("\"<\\nb\\rc\\td\\u0001>\"",
-                _StringUtil.jQuote("<\nb\rc\td\u0001>"));
-    }
-
-    @Test
-    public void testJQuoteNoXSS() {
-        assertEquals("null", _StringUtil.jQuoteNoXSS(null));
-        assertEquals("\"foo\"", _StringUtil.jQuoteNoXSS("foo"));
-        assertEquals("\"123\"", _StringUtil.jQuoteNoXSS(Integer.valueOf(123)));
-        assertEquals("\"foo's \\\"bar\\\"\"",
-                _StringUtil.jQuoteNoXSS("foo's \"bar\""));
-        assertEquals("\"\\n\\r\\t\\u0001\"",
-                _StringUtil.jQuoteNoXSS("\n\r\t\u0001"));
-        assertEquals("\"\\u003C\\nb\\rc\\td\\u0001>\"",
-                _StringUtil.jQuoteNoXSS("<\nb\rc\td\u0001>"));
-        assertEquals("\"\\u003C\\nb\\rc\\td\\u0001>\"",
-                _StringUtil.jQuoteNoXSS((Object) "<\nb\rc\td\u0001>"));
-    }
-
-    @Test
-    public void testGlobToRegularExpression() {
-        assertGlobMatches("a/b/c.ftl", "a/b/c.ftl");
-        assertGlobDoesNotMatch("/a/b/cxftl", "/a/b/c.ftl", "a/b/C.ftl");
-        
-        assertGlobMatches("a/b/*.ftl", "a/b/.ftl", "a/b/x.ftl", "a/b/xx.ftl");
-        assertGlobDoesNotMatch("a/b/*.ftl", "a/c/x.ftl", "a/b/c/x.ftl", "/a/b/x.ftl", "a/b/xxftl");
-        
-        assertGlobMatches("a/b/?.ftl", "a/b/x.ftl");
-        assertGlobDoesNotMatch("a/b/?.ftl", "a/c/x.ftl", "a/b/.ftl", "a/b/xx.ftl", "a/b/xxftl");
-        
-        assertGlobMatches("a/**/c.ftl", "a/b/c.ftl", "a/c.ftl", "a/b/b2/b3/c.ftl", "a//c.ftl");
-        assertGlobDoesNotMatch("a/**/c.ftl", "x/b/c.ftl", "a/b/x.ftl");
-        
-        assertGlobMatches("**/c.ftl", "a/b/c.ftl", "c.ftl", "/c.ftl", "///c.ftl");
-        assertGlobDoesNotMatch("**/c.ftl", "a/b/x.ftl");
-
-        assertGlobMatches("a/b/**", "a/b/c.ftl", "a/b/c2/c.ftl", "a/b/", "a/b/c/");
-        assertGlobDoesNotMatch("a/b.ftl");
-
-        assertGlobMatches("**", "a/b/c.ftl", "");
-
-        assertGlobMatches("\\[\\{\\*\\?\\}\\]\\\\", "[{*?}]\\");
-        assertGlobDoesNotMatch("\\[\\{\\*\\?\\}\\]\\\\", "[{xx}]\\");
-
-        assertGlobMatches("a/b/\\?.ftl", "a/b/?.ftl");
-        assertGlobDoesNotMatch("a/b/\\?.ftl", "a/b/x.ftl");
-
-        assertGlobMatches("\\?\\?.ftl", "??.ftl");
-        assertGlobMatches("\\\\\\\\", "\\\\");
-        assertGlobMatches("\\\\\\\\?", "\\\\x");
-        assertGlobMatches("x\\", "x");
-
-        assertGlobMatches("???*", "123", "1234", "12345");
-        assertGlobDoesNotMatch("???*", "12", "1", "");
-
-        assertGlobMatches("**/a??/b*.ftl", "a11/b1.ftl", "x/a11/b123.ftl", "x/y/a11/b.ftl");
-        assertGlobDoesNotMatch("**/a??/b*.ftl", "a1/b1.ftl", "x/a11/c123.ftl");
-        
-        assertFalse(_StringUtil.globToRegularExpression("ab*").matcher("aBc").matches());
-        assertTrue(_StringUtil.globToRegularExpression("ab*", true).matcher("aBc").matches());
-        assertTrue(_StringUtil.globToRegularExpression("ab", true).matcher("aB").matches());
-        assertTrue(_StringUtil.globToRegularExpression("\u00E1b*", true).matcher("\u00C1bc").matches());
-        
-        try {
-            _StringUtil.globToRegularExpression("x**/y");
-            fail();
-        } catch (IllegalArgumentException e) {
-            assertThat(e.getMessage(), Matchers.containsString("**"));
-        }
-        
-        try {
-            _StringUtil.globToRegularExpression("**y");
-            fail();
-        } catch (IllegalArgumentException e) {
-            assertThat(e.getMessage(), Matchers.containsString("**"));
-        }
-        
-        try {
-            _StringUtil.globToRegularExpression("[ab]c");
-            fail();
-        } catch (IllegalArgumentException e) {
-            assertThat(e.getMessage(), Matchers.containsString("unsupported"));
-        }
-        
-        try {
-            _StringUtil.globToRegularExpression("{aa,bb}c");
-            fail();
-        } catch (IllegalArgumentException e) {
-            assertThat(e.getMessage(), Matchers.containsString("unsupported"));
-        }
-    }
-    
-    private void assertGlobMatches(String glob, String... ss) {
-        Pattern pattern = _StringUtil.globToRegularExpression(glob);
-        for (String s : ss) {
-            if (!pattern.matcher(s).matches()) {
-                fail("Glob " + glob + " (regexp: " + pattern + ") doesn't match " + s);
-            }
-        }
-    }
-
-    private void assertGlobDoesNotMatch(String glob, String... ss) {
-        Pattern pattern = _StringUtil.globToRegularExpression(glob);
-        for (String s : ss) {
-            if (pattern.matcher(s).matches()) {
-                fail("Glob " + glob + " (regexp: " + pattern + ") matches " + s);
-            }
-        }
-    }
-    
-    @Test
-    public void testHTMLEnc() {
-        String s = "";
-        assertSame(s, _StringUtil.XMLEncNA(s));
-        
-        s = "asd";
-        assertSame(s, _StringUtil.XMLEncNA(s));
-        
-        assertEquals("a&amp;b&lt;c&gt;d&quot;e'f", _StringUtil.XMLEncNA("a&b<c>d\"e'f"));
-        assertEquals("&lt;", _StringUtil.XMLEncNA("<"));
-        assertEquals("&lt;a", _StringUtil.XMLEncNA("<a"));
-        assertEquals("&lt;a&gt;", _StringUtil.XMLEncNA("<a>"));
-        assertEquals("a&gt;", _StringUtil.XMLEncNA("a>"));
-        assertEquals("&lt;&gt;", _StringUtil.XMLEncNA("<>"));
-        assertEquals("a&lt;&gt;b", _StringUtil.XMLEncNA("a<>b"));
-    }
-
-    @Test
-    public void testXHTMLEnc() throws IOException {
-        String s = "";
-        assertSame(s, _StringUtil.XHTMLEnc(s));
-        
-        s = "asd";
-        assertSame(s, _StringUtil.XHTMLEnc(s));
-        
-        testXHTMLEnc("a&amp;b&lt;c&gt;d&quot;e&#39;f", "a&b<c>d\"e'f");
-        testXHTMLEnc("&lt;", "<");
-        testXHTMLEnc("&lt;a", "<a");
-        testXHTMLEnc("&lt;a&gt;", "<a>");
-        testXHTMLEnc("a&gt;", "a>");
-        testXHTMLEnc("&lt;&gt;", "<>");
-        testXHTMLEnc("a&lt;&gt;b", "a<>b");
-    }
-    
-    private void testXHTMLEnc(String expected, String in) throws IOException {
-        assertEquals(expected, _StringUtil.XHTMLEnc(in));
-        
-        StringWriter sw = new StringWriter();
-        _StringUtil.XHTMLEnc(in, sw);
-        assertEquals(expected, sw.toString());
-    }
-
-    @Test
-    public void testXMLEnc() throws IOException {
-        String s = "";
-        assertSame(s, _StringUtil.XMLEnc(s));
-        
-        s = "asd";
-        assertSame(s, _StringUtil.XMLEnc(s));
-        
-        testXMLEnc("a&amp;b&lt;c&gt;d&quot;e&apos;f", "a&b<c>d\"e'f");
-        testXMLEnc("&lt;", "<");
-        testXMLEnc("&lt;a", "<a");
-        testXMLEnc("&lt;a&gt;", "<a>");
-        testXMLEnc("a&gt;", "a>");
-        testXMLEnc("&lt;&gt;", "<>");
-        testXMLEnc("a&lt;&gt;b", "a<>b");
-    }
-    
-    private void testXMLEnc(String expected, String in) throws IOException {
-        assertEquals(expected, _StringUtil.XMLEnc(in));
-        
-        StringWriter sw = new StringWriter();
-        _StringUtil.XMLEnc(in, sw);
-        assertEquals(expected, sw.toString());
-    }
-
-    @Test
-    public void testXMLEncQAttr() throws IOException {
-        String s = "";
-        assertSame(s, _StringUtil.XMLEncQAttr(s));
-        
-        s = "asd";
-        assertSame(s, _StringUtil.XMLEncQAttr(s));
-        
-        assertEquals("a&amp;b&lt;c>d&quot;e'f", _StringUtil.XMLEncQAttr("a&b<c>d\"e'f"));
-        assertEquals("&lt;", _StringUtil.XMLEncQAttr("<"));
-        assertEquals("&lt;a", _StringUtil.XMLEncQAttr("<a"));
-        assertEquals("&lt;a>", _StringUtil.XMLEncQAttr("<a>"));
-        assertEquals("a>", _StringUtil.XMLEncQAttr("a>"));
-        assertEquals("&lt;>", _StringUtil.XMLEncQAttr("<>"));
-        assertEquals("a&lt;>b", _StringUtil.XMLEncQAttr("a<>b"));
-    }
-    
-    @Test
-    public void testXMLEncNQG() throws IOException {
-        String s = "";
-        assertSame(s, _StringUtil.XMLEncNQG(s));
-        
-        s = "asd";
-        assertSame(s, _StringUtil.XMLEncNQG(s));
-        
-        assertEquals("a&amp;b&lt;c>d\"e'f", _StringUtil.XMLEncNQG("a&b<c>d\"e'f"));
-        assertEquals("&lt;", _StringUtil.XMLEncNQG("<"));
-        assertEquals("&lt;a", _StringUtil.XMLEncNQG("<a"));
-        assertEquals("&lt;a>", _StringUtil.XMLEncNQG("<a>"));
-        assertEquals("a>", _StringUtil.XMLEncNQG("a>"));
-        assertEquals("&lt;>", _StringUtil.XMLEncNQG("<>"));
-        assertEquals("a&lt;>b", _StringUtil.XMLEncNQG("a<>b"));
-        
-        assertEquals("&gt;", _StringUtil.XMLEncNQG(">"));
-        assertEquals("]&gt;", _StringUtil.XMLEncNQG("]>"));
-        assertEquals("]]&gt;", _StringUtil.XMLEncNQG("]]>"));
-        assertEquals("x]]&gt;", _StringUtil.XMLEncNQG("x]]>"));
-        assertEquals("x]>", _StringUtil.XMLEncNQG("x]>"));
-        assertEquals("]x>", _StringUtil.XMLEncNQG("]x>"));
-    }
-
-    @Test
-    public void testRTFEnc() throws IOException {
-        String s = "";
-        assertSame(s, _StringUtil.RTFEnc(s));
-        
-        s = "asd";
-        assertSame(s, _StringUtil.RTFEnc(s));
-        
-        testRTFEnc("a\\{b\\}c\\\\d", "a{b}c\\d");
-        testRTFEnc("\\{", "{");
-        testRTFEnc("\\{a", "{a");
-        testRTFEnc("\\{a\\}", "{a}");
-        testRTFEnc("a\\}", "a}");
-        testRTFEnc("\\{\\}", "{}");
-        testRTFEnc("a\\{\\}b", "a{}b");
-    }
-
-    private void testRTFEnc(String expected, String in) throws IOException {
-        assertEquals(expected, _StringUtil.RTFEnc(in));
-        
-        StringWriter sw = new StringWriter();
-        _StringUtil.RTFEnc(in, sw);
-        assertEquals(expected, sw.toString());
-    }
-
-    @Test
-    public void testNormalizeEOLs() {
-        assertNull(_StringUtil.normalizeEOLs(null));
-        assertEquals("", _StringUtil.normalizeEOLs(""));
-        assertEquals("x", _StringUtil.normalizeEOLs("x"));
-        assertEquals("x\ny", _StringUtil.normalizeEOLs("x\ny"));
-        assertEquals("x\ny", _StringUtil.normalizeEOLs("x\r\ny"));
-        assertEquals("x\ny", _StringUtil.normalizeEOLs("x\ry"));
-        assertEquals("\n\n\n\n\n\n", _StringUtil.normalizeEOLs("\n\r\r\r\n\r\n\r"));
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/valueformat/NumberFormatTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/valueformat/NumberFormatTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/valueformat/NumberFormatTest.java
deleted file mode 100644
index 8900d2b..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/valueformat/NumberFormatTest.java
+++ /dev/null
@@ -1,365 +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.valueformat;
-
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.Collections;
-import java.util.Locale;
-import java.util.Map;
-
-import org.apache.freemarker.core.Configuration;
-import org.apache.freemarker.core.Environment;
-import org.apache.freemarker.core.Template;
-import org.apache.freemarker.core.TemplateConfiguration;
-import org.apache.freemarker.core.TemplateException;
-import org.apache.freemarker.core.model.TemplateDirectiveBody;
-import org.apache.freemarker.core.model.TemplateDirectiveModel;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateNumberModel;
-import org.apache.freemarker.core.model.impl.SimpleNumber;
-import org.apache.freemarker.core.templateresolver.ConditionalTemplateConfigurationFactory;
-import org.apache.freemarker.core.templateresolver.FileNameGlobMatcher;
-import org.apache.freemarker.core.templateresolver.TemplateConfigurationFactory;
-import org.apache.freemarker.core.userpkg.BaseNTemplateNumberFormatFactory;
-import org.apache.freemarker.core.userpkg.HexTemplateNumberFormatFactory;
-import org.apache.freemarker.core.userpkg.LocaleSensitiveTemplateNumberFormatFactory;
-import org.apache.freemarker.core.userpkg.PrintfGTemplateNumberFormatFactory;
-import org.apache.freemarker.core.valueformat.impl.AliasTemplateNumberFormatFactory;
-import org.apache.freemarker.test.TemplateTest;
-import org.apache.freemarker.test.TestConfigurationBuilder;
-import org.junit.Ignore;
-import org.junit.Test;
-
-import com.google.common.collect.ImmutableMap;
-
-@SuppressWarnings("boxing")
-public class NumberFormatTest extends TemplateTest {
-    
-    @Test
-    public void testUnknownCustomFormat() throws Exception {
-        {
-            setConfigurationWithNumberFormat("@noSuchFormat");
-            Throwable exc = assertErrorContains("${1}", "\"@noSuchFormat\"", "\"noSuchFormat\"");
-            assertThat(exc.getCause(), instanceOf(UndefinedCustomFormatException.class));
-        }
-
-        {
-            setConfigurationWithNumberFormat("number");
-            Throwable exc = assertErrorContains("${1?string('@noSuchFormat2')}",
-                    "\"@noSuchFormat2\"", "\"noSuchFormat2\"");
-            assertThat(exc.getCause(), instanceOf(UndefinedCustomFormatException.class));
-        }
-    }
-    
-    @Test
-    public void testStringBI() throws Exception {
-        setConfigurationWithNumberFormat(null);
-        assertOutput("${11} ${11?string.@hex} ${12} ${12?string.@hex}", "11 b 12 c");
-    }
-
-    @Test
-    public void testSetting() throws Exception {
-        setConfigurationWithNumberFormat("@hex");
-        assertOutput("${11?string.number} ${11} ${12?string.number} ${12}", "11 b 12 c");
-    }
-
-    @Test
-    public void testSetting2() throws Exception {
-        setConfigurationWithNumberFormat(null);
-        assertOutput(
-                "<#setting numberFormat='@hex'>${11?string.number} ${11} ${12?string.number} ${12} ${13?string}"
-                + "<#setting numberFormat='@loc'>${11?string.number} ${11} ${12?string.number} ${12} ${13?string}",
-                "11 b 12 c d"
-                + "11 11_en_US 12 12_en_US 13_en_US");
-    }
-    
-    @Test
-    public void testUnformattableNumber() throws Exception {
-        setConfigurationWithNumberFormat("@hex");
-        assertErrorContains("${1.1}", "hexadecimal int", "doesn't fit into an int");
-    }
-
-    @Test
-    public void testLocaleSensitive() throws Exception {
-        setConfigurationWithNumberFormat("@loc");
-        assertOutput("${1.1}", "1.1_en_US");
-        setConfigurationWithNumberFormat("@loc", null, null, Locale.GERMANY);
-        assertOutput("${1.1}", "1.1_de_DE");
-    }
-
-    @Test
-    public void testLocaleSensitive2() throws Exception {
-        setConfigurationWithNumberFormat("@loc");
-        assertOutput("${1.1} <#setting locale='de_DE'>${1.1}", "1.1_en_US 1.1_de_DE");
-    }
-
-    @Test
-    public void testCustomParameterized() throws Exception {
-        setConfigurationWithNumberFormat("@base 2");
-        assertOutput("${11}", "1011");
-        assertOutput("${11?string}", "1011");
-        assertOutput("${11?string.@base_3}", "102");
-        
-        assertErrorContains("${11?string.@base_xyz}", "\"@base_xyz\"", "\"xyz\"");
-        setConfigurationWithNumberFormat("@base");
-        assertErrorContains("${11}", "\"@base\"", "format parameter is required");
-    }
-
-    @Test
-    public void testCustomWithFallback() throws Exception {
-        Configuration cfg = getConfiguration();
-        setConfigurationWithNumberFormat("@base 2|0.0#");
-        assertOutput("${11}", "1011");
-        assertOutput("${11.34}", "11.34");
-        assertOutput("${11?string('@base 3|0.00')}", "102");
-        assertOutput("${11.2?string('@base 3|0.00')}", "11.20");
-    }
-
-    @Test
-    public void testEnvironmentGetters() throws Exception {
-        setConfigurationWithNumberFormat(null);
-
-        Template t = new Template(null, "", getConfiguration());
-        Environment env = t.createProcessingEnvironment(null, null);
-        
-        TemplateNumberFormat defF = env.getTemplateNumberFormat();
-        //
-        TemplateNumberFormat explF = env.getTemplateNumberFormat("0.00");
-        assertEquals("1.25", explF.formatToPlainText(new SimpleNumber(1.25)));
-        //
-        TemplateNumberFormat expl2F = env.getTemplateNumberFormat("@loc");
-        assertEquals("1.25_en_US", expl2F.formatToPlainText(new SimpleNumber(1.25)));
-        
-        TemplateNumberFormat explFFr = env.getTemplateNumberFormat("0.00", Locale.FRANCE);
-        assertNotSame(explF, explFFr);
-        assertEquals("1,25", explFFr.formatToPlainText(new SimpleNumber(1.25)));
-        //
-        TemplateNumberFormat expl2FFr = env.getTemplateNumberFormat("@loc", Locale.FRANCE);
-        assertEquals("1.25_fr_FR", expl2FFr.formatToPlainText(new SimpleNumber(1.25)));
-        
-        assertSame(env.getTemplateNumberFormat(), defF);
-        //
-        assertSame(env.getTemplateNumberFormat("0.00"), explF);
-        //
-        assertSame(env.getTemplateNumberFormat("@loc"), expl2F);
-    }
-    
-    /**
-     * ?string formats lazily (at least in 2.3.x), so it must make a snapshot of the format inputs when it's called.
-     */
-    @Test
-    @Ignore // [FM3] We want to rework BI-s so that lazy evaluation won't be needed. Then this will go away too.
-    public void testStringBIDoesSnapshot() throws Exception {
-        // TemplateNumberModel-s shouldn't change, but we have to keep BC when that still happens.
-        final MutableTemplateNumberModel nm = new MutableTemplateNumberModel();
-        nm.setNumber(123);
-        addToDataModel("n", nm);
-        addToDataModel("incN", new TemplateDirectiveModel() {
-            
-            @Override
-            public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
-                    throws TemplateException, IOException {
-                nm.setNumber(nm.getAsNumber().intValue() + 1);
-            }
-        });
-        assertOutput(
-                "<#assign s1 = n?string>"
-                + "<#setting numberFormat='@loc'>"
-                + "<#assign s2 = n?string>"
-                + "<#setting numberFormat='@hex'>"
-                + "<#assign s3 = n?string>"
-                + "${s1} ${s2} ${s3}",
-                "123 123_en_US 7b");
-        assertOutput(
-                "<#assign s1 = n?string>"
-                + "<@incN />"
-                + "<#assign s2 = n?string>"
-                + "${s1} ${s2}",
-                "123 124");
-    }
-
-    @Test
-    public void testNullInModel() throws Exception {
-        addToDataModel("n", new MutableTemplateNumberModel());
-        assertErrorContains("${n}", "nothing inside it");
-        assertErrorContains("${n?string}", "nothing inside it");
-    }
-    
-    @Test
-    public void testAtPrefix() throws Exception {
-        Configuration cfg = getConfiguration();
-
-        setConfigurationWithNumberFormat("@hex");
-        assertOutput("${10}", "a");
-        setConfigurationWithNumberFormat("'@'0");
-        assertOutput("${10}", "@10");
-        setConfigurationWithNumberFormat("@@0");
-        assertOutput("${10}", "@@10");
-
-        setConfigurationWithNumberFormat(
-                "@hex", Collections.<String, TemplateNumberFormatFactory>emptyMap());
-        assertErrorContains("${10}", "custom", "\"hex\"");
-
-        setConfigurationWithNumberFormat(
-                "'@'0", Collections.<String, TemplateNumberFormatFactory>emptyMap());
-        assertOutput("${10}", "@10");
-
-        setConfigurationWithNumberFormat(
-                "@@0", Collections.<String, TemplateNumberFormatFactory>emptyMap());
-        assertOutput("${10}", "@@10");
-    }
-
-    @Test
-    public void testAlieses() throws Exception {
-        setConfigurationWithNumberFormat(
-                "'@'0",
-                ImmutableMap.of(
-                        "f", new AliasTemplateNumberFormatFactory("0.#'f'"),
-                        "d", new AliasTemplateNumberFormatFactory("0.0#"),
-                        "hex", HexTemplateNumberFormatFactory.INSTANCE),
-                new ConditionalTemplateConfigurationFactory(
-                        new FileNameGlobMatcher("*2*"),
-                        new TemplateConfiguration.Builder()
-                                .customNumberFormats(ImmutableMap.<String, TemplateNumberFormatFactory>of(
-                                        "d", new AliasTemplateNumberFormatFactory("0.#'d'"),
-                                        "i", new AliasTemplateNumberFormatFactory("@hex")))
-                                .build()));
-
-        String commonFtl = "${1?string.@f} ${1?string.@d} "
-                + "<#setting locale='fr_FR'>${1.5?string.@d} "
-                + "<#attempt>${10?string.@i}<#recover>E</#attempt>";
-        addTemplate("t1.ftl", commonFtl);
-        addTemplate("t2.ftl", commonFtl);
-        
-        assertOutputForNamed("t1.ftl", "1f 1.0 1,5 E");
-        assertOutputForNamed("t2.ftl", "1f 1d 1,5d a");
-    }
-
-    @Test
-    public void testAlieses2() throws Exception {
-        setConfigurationWithNumberFormat(
-                "@n",
-                ImmutableMap.<String, TemplateNumberFormatFactory>of(
-                        "n", new AliasTemplateNumberFormatFactory("0.0",
-                                ImmutableMap.of(
-                                        new Locale("en"), "0.0'_en'",
-                                        Locale.UK, "0.0'_en_GB'",
-                                        Locale.FRANCE, "0.0'_fr_FR'"))));
-        assertOutput(
-                "<#setting locale='en_US'>${1} "
-                + "<#setting locale='en_GB'>${1} "
-                + "<#setting locale='en_GB_Win'>${1} "
-                + "<#setting locale='fr_FR'>${1} "
-                + "<#setting locale='hu_HU'>${1}",
-                "1.0_en 1.0_en_GB 1.0_en_GB 1,0_fr_FR 1,0");
-    }
-    
-    @Test
-    public void testMarkupFormat() throws IOException, TemplateException {
-        setConfigurationWithNumberFormat("@printfG_3");
-
-        String commonFTL = "${1234567} ${'cat:' + 1234567} ${0.0000123}";
-        String commonOutput = "1.23*10<sup>6</sup> cat:1.23*10<sup>6</sup> 1.23*10<sup>-5</sup>";
-        assertOutput(commonFTL, commonOutput);
-        assertOutput("<#ftl outputFormat='HTML'>" + commonFTL, commonOutput);
-        assertOutput("<#escape x as x?html>" + commonFTL + "</#escape>", commonOutput);
-        assertOutput("<#escape x as x?xhtml>" + commonFTL + "</#escape>", commonOutput);
-        assertOutput("<#escape x as x?xml>" + commonFTL + "</#escape>", commonOutput);
-        assertOutput("${\"" + commonFTL + "\"}", "1.23*10<sup>6</sup> cat:1.23*10<sup>6</sup> 1.23*10<sup>-5</sup>");
-        assertErrorContains("<#ftl outputFormat='plainText'>" + commonFTL, "HTML", "plainText", "conversion");
-    }
-
-    @Test
-    public void testPrintG() throws IOException, TemplateException {
-        setConfigurationWithNumberFormat(null);
-        for (Number n : new Number[] {
-                1234567, 1234567L, 1234567d, 1234567f, BigInteger.valueOf(1234567), BigDecimal.valueOf(1234567) }) {
-            addToDataModel("n", n);
-            
-            assertOutput("${n?string.@printfG}", "1.23457E+06");
-            assertOutput("${n?string.@printfG_3}", "1.23E+06");
-            assertOutput("${n?string.@printfG_7}", "1234567");
-            assertOutput("${0.0000123?string.@printfG}", "1.23000E-05");
-        }
-    }
-
-    private void setConfigurationWithNumberFormat(
-            String numberFormat,
-            Map<String, TemplateNumberFormatFactory> customNumberFormats,
-            TemplateConfigurationFactory templateConfigurationFactory,
-            Locale locale) {
-        TestConfigurationBuilder cfgB = new TestConfigurationBuilder(Configuration.VERSION_3_0_0);
-
-        if (numberFormat != null) {
-            cfgB.setNumberFormat(numberFormat);
-        }
-        cfgB.setCustomNumberFormats(
-                customNumberFormats != null ? customNumberFormats
-                        : ImmutableMap.of(
-                                "hex", HexTemplateNumberFormatFactory.INSTANCE,
-                                "loc", LocaleSensitiveTemplateNumberFormatFactory.INSTANCE,
-                                "base", BaseNTemplateNumberFormatFactory.INSTANCE,
-                                "printfG", PrintfGTemplateNumberFormatFactory.INSTANCE));
-        if (locale != null) {
-            cfgB.setLocale(locale);
-        }
-        if (templateConfigurationFactory != null) {
-            cfgB.setTemplateConfigurations(templateConfigurationFactory);
-        }
-
-        setConfiguration(cfgB.build());
-    }
-
-    private void setConfigurationWithNumberFormat(String numberFormat) {
-        setConfigurationWithNumberFormat(numberFormat, null, null, null);
-    }
-
-    private void setConfigurationWithNumberFormat(
-            String numberFormat, Map<String, TemplateNumberFormatFactory> customNumberFormats) {
-        setConfigurationWithNumberFormat(numberFormat, customNumberFormats, null, null);
-    }
-
-    private void setConfigurationWithNumberFormat(
-            String numberFormat, Map<String, TemplateNumberFormatFactory> customNumberFormats,
-            TemplateConfigurationFactory templateConfigurationFactory) {
-        setConfigurationWithNumberFormat(numberFormat, customNumberFormats, templateConfigurationFactory, null);
-    }
-
-    private static class MutableTemplateNumberModel implements TemplateNumberModel {
-        
-        private Number number;
-
-        public void setNumber(Number number) {
-            this.number = number;
-        }
-
-        @Override
-        public Number getAsNumber() throws TemplateModelException {
-            return number;
-        }
-        
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/valueformat/impl/ExtendedDecimalFormatTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/valueformat/impl/ExtendedDecimalFormatTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/valueformat/impl/ExtendedDecimalFormatTest.java
deleted file mode 100644
index 76c0bfc..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/valueformat/impl/ExtendedDecimalFormatTest.java
+++ /dev/null
@@ -1,343 +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.valueformat.impl;
-
-import static org.apache.freemarker.test.hamcerst.Matchers.*;
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.text.DecimalFormat;
-import java.text.DecimalFormatSymbols;
-import java.text.ParseException;
-import java.util.Locale;
-
-import org.apache.freemarker.core.TemplateException;
-import org.apache.freemarker.test.TemplateTest;
-import org.apache.freemarker.test.TestConfigurationBuilder;
-import org.junit.Test;
-
-public class ExtendedDecimalFormatTest extends TemplateTest {
-    
-    private static final Locale LOC = Locale.US;
-    private static final DecimalFormatSymbols SYMS = DecimalFormatSymbols.getInstance(LOC);
-
-    @Test
-    public void testNonExtended() throws ParseException {
-        for (String fStr : new String[] { "0.00", "0.###", "#,#0.###", "#0.####", "0.0;m", "0.0;",
-                "0'x'", "0'x';'m'", "0';'", "0';';m", "0';';'#'m';'", "0';;'", "" }) {
-            assertFormatsEquivalent(new DecimalFormat(fStr, SYMS), ExtendedDecimalFormatParser.parse(fStr, LOC));
-        }
-        
-        try {
-            new DecimalFormat(";");
-            fail();
-        } catch (IllegalArgumentException e) {
-            // Expected
-        }
-        try {
-            ExtendedDecimalFormatParser.parse(";", LOC);
-        } catch (ParseException e) {
-            // Expected
-        }
-    }
-
-    @Test
-    public void testNonExtended2() throws ParseException {
-        assertFormatsEquivalent(new DecimalFormat("0.0", SYMS), ExtendedDecimalFormatParser.parse("0.0;", LOC));
-        assertFormatsEquivalent(new DecimalFormat("0.0", SYMS), ExtendedDecimalFormatParser.parse("0.0;;", LOC));
-        assertFormatsEquivalent(new DecimalFormat("0.0;m", SYMS), ExtendedDecimalFormatParser.parse("0.0;m;", LOC));
-        assertFormatsEquivalent(new DecimalFormat("", SYMS), ExtendedDecimalFormatParser.parse(";;", LOC));
-        assertFormatsEquivalent(new DecimalFormat("0'x'", SYMS), ExtendedDecimalFormatParser.parse("0'x';;", LOC));
-        assertFormatsEquivalent(new DecimalFormat("0'x';'m'", SYMS),
-                ExtendedDecimalFormatParser.parse("0'x';'m';", LOC));
-        assertFormatsEquivalent(new DecimalFormat("0';'", SYMS), ExtendedDecimalFormatParser.parse("0';';;", LOC));
-        assertFormatsEquivalent(new DecimalFormat("0';';m", SYMS), ExtendedDecimalFormatParser.parse("0';';m;", LOC));
-        assertFormatsEquivalent(new DecimalFormat("0';';'#'m';'", SYMS),
-                ExtendedDecimalFormatParser.parse("0';';'#'m';';", LOC));
-        assertFormatsEquivalent(new DecimalFormat("0';;'", SYMS),
-                ExtendedDecimalFormatParser.parse("0';;';;", LOC));
-
-        try {
-            new DecimalFormat(";m");
-            fail();
-        } catch (IllegalArgumentException e) {
-            // Expected
-        }
-        try {
-            new DecimalFormat("; ;");
-            fail();
-        } catch (IllegalArgumentException e) {
-            // Expected
-        }
-        try {
-            ExtendedDecimalFormatParser.parse("; ;", LOC);
-            fail();
-        } catch (ParseException e) {
-            // Expected
-        }
-        try {
-            ExtendedDecimalFormatParser.parse(";m", LOC);
-            fail();
-        } catch (ParseException e) {
-            // Expected
-        }
-        try {
-            ExtendedDecimalFormatParser.parse(";m;", LOC);
-            fail();
-        } catch (ParseException e) {
-            // Expected
-        }
-    }
-    
-    @SuppressWarnings("boxing")
-    @Test
-    public void testExtendedParamsParsing() throws ParseException {
-        for (String fs : new String[] {
-                "00.##;; decimalSeparator='D'",
-                "00.##;;decimalSeparator=D",
-                "00.##;;  decimalSeparator  =  D ", "00.##;; decimalSeparator = 'D' " }) {
-            assertFormatted(fs, 1.125, "01D12");
-        }
-        for (String fs : new String[] {
-                ",#0.0;; decimalSeparator=D, groupingSeparator=_",
-                ",#0.0;;decimalSeparator=D,groupingSeparator=_",
-                ",#0.0;; decimalSeparator = D , groupingSeparator = _ ",
-                ",#0.0;; decimalSeparator='D', groupingSeparator='_'"
-                }) {
-            assertFormatted(fs, 12345, "1_23_45D0");
-        }
-        
-        assertFormatted("0.0;;infinity=infinity", Double.POSITIVE_INFINITY, "infinity");
-        assertFormatted("0.0;;infinity='infinity'", Double.POSITIVE_INFINITY, "infinity");
-        assertFormatted("0.0;;infinity=\"infinity\"", Double.POSITIVE_INFINITY, "infinity");
-        assertFormatted("0.0;;infinity=''", Double.POSITIVE_INFINITY, "");
-        assertFormatted("0.0;;infinity=\"\"", Double.POSITIVE_INFINITY, "");
-        assertFormatted("0.0;;infinity='x''y'", Double.POSITIVE_INFINITY, "x'y");
-        assertFormatted("0.0;;infinity=\"x'y\"", Double.POSITIVE_INFINITY, "x'y");
-        assertFormatted("0.0;;infinity='x\"\"y'", Double.POSITIVE_INFINITY, "x\"\"y");
-        assertFormatted("0.0;;infinity=\"x''y\"", Double.POSITIVE_INFINITY, "x''y");
-        assertFormatted("0.0;;decimalSeparator=''''", 1, "1'0");
-        assertFormatted("0.0;;decimalSeparator=\"'\"", 1, "1'0");
-        assertFormatted("0.0;;decimalSeparator='\"'", 1, "1\"0");
-        assertFormatted("0.0;;decimalSeparator=\"\"\"\"", 1, "1\"0");
-        
-        try {
-            ExtendedDecimalFormatParser.parse(";;decimalSeparator=D,", LOC);
-            fail();
-        } catch (java.text.ParseException e) {
-            assertThat(e.getMessage(),
-                    allOf(containsStringIgnoringCase("expected a(n) name"), containsString(" end of ")));
-        }
-        try {
-            ExtendedDecimalFormatParser.parse(";;foo=D,", LOC);
-            fail();
-        } catch (java.text.ParseException e) {
-            assertThat(e.getMessage(),
-                    allOf(containsString("\"foo\""), containsString("name")));
-        }
-        try {
-            ExtendedDecimalFormatParser.parse(";;decimalSeparator='D", LOC);
-            fail();
-        } catch (java.text.ParseException e) {
-            assertThat(e.getMessage(),
-                    allOf(containsString("quotation"), containsString("closed")));
-        }
-        try {
-            ExtendedDecimalFormatParser.parse(";;decimalSeparator=\"D", LOC);
-            fail();
-        } catch (java.text.ParseException e) {
-            assertThat(e.getMessage(),
-                    allOf(containsString("quotation"), containsString("closed")));
-        }
-        try {
-            ExtendedDecimalFormatParser.parse(";;decimalSeparator='D'groupingSeparator=G", LOC);
-            fail();
-        } catch (java.text.ParseException e) {
-            assertThat(e.getMessage(), allOf(
-                    containsString("separator"), containsString("whitespace"), containsString("comma")));
-        }
-        try {
-            ExtendedDecimalFormatParser.parse(";;decimalSeparator=., groupingSeparator=G", LOC);
-            fail();
-        } catch (java.text.ParseException e) {
-            assertThat(e.getMessage(), allOf(
-                    containsStringIgnoringCase("expected a(n) value"), containsString("., gr[...]")));
-        }
-        try {
-            ExtendedDecimalFormatParser.parse("0.0;;decimalSeparator=''", LOC);
-            fail();
-        } catch (java.text.ParseException e) {
-            assertThat(e.getMessage(), allOf(
-                    containsStringIgnoringCase("\"decimalSeparator\""), containsString("exactly 1 char")));
-        }
-        try {
-            ExtendedDecimalFormatParser.parse("0.0;;multipier=ten", LOC);
-            fail();
-        } catch (java.text.ParseException e) {
-            assertThat(e.getMessage(), allOf(
-                    containsString("\"multipier\""), containsString("\"ten\""), containsString("integer")));
-        }
-    }
-    
-    @SuppressWarnings("boxing")
-    @Test
-    public void testExtendedParamsEffect() throws ParseException {
-        assertFormatted("0",
-                1.5, "2", 2.5, "2", 3.5, "4", 1.4, "1", 1.6, "2", -1.4, "-1", -1.5, "-2", -2.5, "-2", -1.6, "-2");
-        assertFormatted("0;; roundingMode=halfEven",
-                1.5, "2", 2.5, "2", 3.5, "4", 1.4, "1", 1.6, "2", -1.4, "-1", -1.5, "-2", -2.5, "-2", -1.6, "-2");
-        assertFormatted("0;; roundingMode=halfUp",
-                1.5, "2", 2.5, "3", 3.5, "4", 1.4, "1", 1.6, "2", -1.4, "-1", -1.5, "-2", -2.5, "-3", -1.6, "-2");
-        assertFormatted("0;; roundingMode=halfDown",
-                1.5, "1", 2.5, "2", 3.5, "3", 1.4, "1", 1.6, "2", -1.4, "-1", -1.5, "-1", -2.5, "-2", -1.6, "-2");
-        assertFormatted("0;; roundingMode=floor",
-                1.5, "1", 2.5, "2", 3.5, "3", 1.4, "1", 1.6, "1", -1.4, "-2", -1.5, "-2", -2.5, "-3", -1.6, "-2");
-        assertFormatted("0;; roundingMode=ceiling",
-                1.5, "2", 2.5, "3", 3.5, "4", 1.4, "2", 1.6, "2", -1.4, "-1", -1.5, "-1", -2.5, "-2", -1.6, "-1");
-        assertFormatted("0;; roundingMode=up",
-                1.5, "2", 2.5, "3", 3.5, "4", 1.4, "2", 1.6, "2", -1.4, "-2", -1.5, "-2", -2.5, "-3", -1.6, "-2");
-        assertFormatted("0;; roundingMode=down",
-                1.5, "1", 2.5, "2", 3.5, "3", 1.4, "1", 1.6, "1", -1.4, "-1", -1.5, "-1", -2.5, "-2", -1.6, "-1");
-        assertFormatted("0;; roundingMode=unnecessary", 2, "2");
-        try {
-            assertFormatted("0;; roundingMode=unnecessary", 2.5, "2");
-            fail();
-        } catch (ArithmeticException e) {
-            // Expected
-        }
-
-        assertFormatted("0.##;; multipier=100", 12.345, "1234.5");
-        assertFormatted("0.##;; multipier=1000", 12.345, "12345");
-        
-        assertFormatted(",##0.##;; groupingSeparator=_ decimalSeparator=D", 12345.1, "12_345D1", 1, "1");
-        
-        assertFormatted("0.##E0;; exponentSeparator='*10^'", 12345.1, "1.23*10^4");
-        
-        assertFormatted("0.##;; minusSign=m", -1, "m1", 1, "1");
-        
-        assertFormatted("0.##;; infinity=foo", Double.POSITIVE_INFINITY, "foo", Double.NEGATIVE_INFINITY, "-foo");
-        
-        assertFormatted("0.##;; nan=foo", Double.NaN, "foo");
-        
-        assertFormatted("0%;; percent='c'", 0.75, "75c");
-        
-        assertFormatted("0\u2030;; perMill='m'", 0.75, "750m");
-        
-        assertFormatted("0.00;; zeroDigit='@'", 10.5, "A@.E@");
-        
-        assertFormatted("0;; currencyCode=USD", 10, "10");
-        assertFormatted("0 \u00A4;; currencyCode=USD", 10, "10 $");
-        assertFormatted("0 \u00A4\u00A4;; currencyCode=USD", 10, "10 USD");
-        assertFormatted(Locale.GERMANY, "0 \u00A4;; currencyCode=EUR", 10, "10 \u20AC");
-        assertFormatted(Locale.GERMANY, "0 \u00A4\u00A4;; currencyCode=EUR", 10, "10 EUR");
-        try {
-            assertFormatted("0;; currencyCode=USDX", 10, "10");
-        } catch (ParseException e) {
-            assertThat(e.getMessage(), containsString("ISO 4217"));
-        }
-        assertFormatted("0 \u00A4;; currencyCode=USD currencySymbol=bucks", 10, "10 bucks");
-     // Order doesn't mater:
-        assertFormatted("0 \u00A4;; currencySymbol=bucks currencyCode=USD", 10, "10 bucks");
-        // International symbol isn't affected:
-        assertFormatted("0 \u00A4\u00A4;; currencyCode=USD currencySymbol=bucks", 10, "10 USD");
-        
-        assertFormatted("0.0 \u00A4;; monetaryDecimalSeparator=m", 10.5, "10m5 $");
-        assertFormatted("0.0 kg;; monetaryDecimalSeparator=m", 10.5, "10.5 kg");
-        assertFormatted("0.0 \u00A4;; decimalSeparator=d", 10.5, "10.5 $");
-        assertFormatted("0.0 kg;; decimalSeparator=d", 10.5, "10d5 kg");
-        assertFormatted("0.0 \u00A4;; monetaryDecimalSeparator=m decimalSeparator=d", 10.5, "10m5 $");
-        assertFormatted("0.0 kg;; monetaryDecimalSeparator=m decimalSeparator=d", 10.5, "10d5 kg");
-    }
-    
-    @Test
-    public void testLocale() throws ParseException {
-        assertEquals("1000.0", ExtendedDecimalFormatParser.parse("0.0", Locale.US).format(1000));
-        assertEquals("1000,0", ExtendedDecimalFormatParser.parse("0.0", Locale.FRANCE).format(1000));
-        assertEquals("1_000.0", ExtendedDecimalFormatParser.parse(",000.0;;groupingSeparator=_", Locale.US).format(1000));
-        assertEquals("1_000,0", ExtendedDecimalFormatParser.parse(",000.0;;groupingSeparator=_", Locale.FRANCE).format(1000));
-    }
-    
-    @Test
-    public void testTemplates() throws IOException, TemplateException {
-        TestConfigurationBuilder cfgB = new TestConfigurationBuilder();
-
-        setConfiguration(cfgB.numberFormat(",000.#").build());
-        assertOutput("${1000.15} ${1000.25}", "1,000.2 1,000.2");
-        setConfiguration(cfgB.numberFormat(",000.#;; roundingMode=halfUp groupingSeparator=_").build());;
-        assertOutput("${1000.15} ${1000.25}", "1_000.2 1_000.3");
-        setConfiguration(cfgB.locale(Locale.GERMANY).build());;
-        assertOutput("${1000.15} ${1000.25}", "1_000,2 1_000,3");
-        setConfiguration(cfgB.locale(Locale.US).build());;
-        assertOutput(
-                "${1000.15}; "
-                + "${1000.15?string(',##.#;;groupingSeparator=\" \"')}; "
-                + "<#setting locale='de_DE'>${1000.15}; "
-                + "<#setting numberFormat='0.0;;roundingMode=down'>${1000.15}",
-                "1_000.2; 10 00.2; 1_000,2; 1000,1");
-        assertErrorContains("${1?string('#E')}",
-                TemplateException.class, "\"#E\"", "format string", "exponential");
-        assertErrorContains("<#setting numberFormat='#E'>${1}",
-                TemplateException.class, "\"#E\"", "format string", "exponential");
-        assertErrorContains("<#setting numberFormat=';;foo=bar'>${1}",
-                TemplateException.class, "\"foo\"", "supported");
-        assertErrorContains("<#setting numberFormat='0;;roundingMode=unnecessary'>${1.5}",
-                TemplateException.class, "can't format", "1.5", "UNNECESSARY");
-    }
-
-    private void assertFormatted(String formatString, Object... numberAndExpectedOutput) throws ParseException {
-        assertFormatted(LOC, formatString, numberAndExpectedOutput);
-    }
-    
-    private void assertFormatted(Locale loc, String formatString, Object... numberAndExpectedOutput) throws ParseException {
-        if (numberAndExpectedOutput.length % 2 != 0) {
-            throw new IllegalArgumentException();
-        }
-        
-        DecimalFormat df = ExtendedDecimalFormatParser.parse(formatString, loc);
-        Number num = null;
-        for (int i = 0; i < numberAndExpectedOutput.length; i++) {
-            if (i % 2 == 0) {
-                num = (Number) numberAndExpectedOutput[i];
-            } else {
-                assertEquals(numberAndExpectedOutput[i], df.format(num));
-            }
-        }
-    }
-    
-    private void assertFormatsEquivalent(DecimalFormat dfExpected, DecimalFormat dfActual) {
-        for (int signum : new int[] { 1, -1 }) {
-            assertFormatsEquivalent(dfExpected, dfActual, 0);
-            assertFormatsEquivalent(dfExpected, dfActual, signum * 0.5);
-            assertFormatsEquivalent(dfExpected, dfActual, signum * 0.25);
-            assertFormatsEquivalent(dfExpected, dfActual, signum * 0.125);
-            assertFormatsEquivalent(dfExpected, dfActual, signum);
-            assertFormatsEquivalent(dfExpected, dfActual, signum * 10);
-            assertFormatsEquivalent(dfExpected, dfActual, signum * 100);
-            assertFormatsEquivalent(dfExpected, dfActual, signum * 1000);
-            assertFormatsEquivalent(dfExpected, dfActual, signum * 10000);
-            assertFormatsEquivalent(dfExpected, dfActual, signum * 100000);
-        }
-    }
-
-    private void assertFormatsEquivalent(DecimalFormat dfExpected, DecimalFormat dfActual, double n) {
-        assertEquals(dfExpected.format(n), dfActual.format(n));
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/dom/DOMSiblingTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/dom/DOMSiblingTest.java b/freemarker-core/src/test/java/org/apache/freemarker/dom/DOMSiblingTest.java
deleted file mode 100644
index 1707756..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/dom/DOMSiblingTest.java
+++ /dev/null
@@ -1,99 +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.dom;
-
-import java.io.IOException;
-
-import javax.xml.parsers.ParserConfigurationException;
-
-import org.apache.freemarker.core.TemplateException;
-import org.apache.freemarker.test.TemplateTest;
-import org.apache.freemarker.test.util.XMLLoader;
-import org.junit.Before;
-import org.junit.Test;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-
-public class DOMSiblingTest extends TemplateTest {
-
-    @Before
-    public void setUp() throws SAXException, IOException, ParserConfigurationException {
-        InputSource is = new InputSource(getClass().getResourceAsStream("DOMSiblingTest.xml"));
-        addToDataModel("doc", XMLLoader.toModel(is));
-    }
-
-    @Test
-    public void testBlankPreviousSibling() throws IOException, TemplateException {
-        assertOutput("${doc.person.name?previousSibling}", "\n    ");
-        assertOutput("${doc.person.name?previous_sibling}", "\n    ");
-    }
-
-    @Test
-    public void testNonBlankPreviousSibling() throws IOException, TemplateException {
-        assertOutput("${doc.person.address?previousSibling}", "12th August");
-    }
-
-    @Test
-    public void testBlankNextSibling() throws IOException, TemplateException {
-        assertOutput("${doc.person.name?nextSibling}", "\n    ");
-        assertOutput("${doc.person.name?next_sibling}", "\n    ");
-    }
-
-    @Test
-    public void testNonBlankNextSibling() throws IOException, TemplateException {
-        assertOutput("${doc.person.dob?nextSibling}", "Chennai, India");
-    }
-
-    @Test
-    public void testNullPreviousSibling() throws IOException, TemplateException {
-        assertOutput("${doc.person?previousSibling?? ?c}", "false");
-    }
-
-    @Test
-    public void testSignificantPreviousSibling() throws IOException, TemplateException {
-        assertOutput("${doc.person.name.@@previous_sibling_element}", "male");
-    }
-
-    @Test
-    public void testSignificantNextSibling() throws IOException, TemplateException {
-        assertOutput("${doc.person.name.@@next_sibling_element}", "12th August");
-    }
-
-    @Test
-    public void testNullSignificantPreviousSibling() throws IOException, TemplateException {
-        assertOutput("${doc.person.phone.@@next_sibling_element?size}", "0");
-    }
-
-    @Test
-    public void testSkippingCommentNode() throws IOException, TemplateException {
-        assertOutput("${doc.person.profession.@@previous_sibling_element}", "Chennai, India");
-    }
-
-    @Test
-    public void testSkippingEmptyCDataNode() throws IOException, TemplateException {
-        assertOutput("${doc.person.hobby.@@previous_sibling_element}", "Software Engineer");
-    }
-
-    @Test
-    public void testValidCDataNode() throws IOException, TemplateException {
-        assertOutput("${doc.person.phone.@@previous_sibling_element?size}", "0");
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/dom/DOMSimplifiersTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/dom/DOMSimplifiersTest.java b/freemarker-core/src/test/java/org/apache/freemarker/dom/DOMSimplifiersTest.java
deleted file mode 100644
index fec62fd..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/dom/DOMSimplifiersTest.java
+++ /dev/null
@@ -1,201 +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.dom;
-
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-
-import javax.xml.parsers.ParserConfigurationException;
-
-import org.apache.freemarker.test.util.XMLLoader;
-import org.junit.Test;
-import org.w3c.dom.CDATASection;
-import org.w3c.dom.Comment;
-import org.w3c.dom.Document;
-import org.w3c.dom.DocumentType;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.ProcessingInstruction;
-import org.w3c.dom.Text;
-import org.xml.sax.SAXException;
-
-public class DOMSimplifiersTest {
-
-    private static final String COMMON_TEST_XML
-            = "<!DOCTYPE a []><?p?><a>x<![CDATA[y]]><!--c--><?p?>z<?p?><b><!--c--></b><c></c>"
-              + "<d>a<e>c</e>b<!--c--><!--c--><!--c--><?p?><?p?><?p?></d>"
-              + "<f><![CDATA[1]]>2</f></a><!--c-->";
-
-    private static final String TEXT_MERGE_CONTENT =
-            "<a>"
-            + "a<!--c--><s/>"
-            + "<!--c-->a<s/>"
-            + "a<!--c-->b<s/>"
-            + "<!--c-->a<!--c-->b<!--c--><s/>"
-            + "a<b>b</b>c<s/>"
-            + "a<b>b</b><!--c-->c<s/>"
-            + "a<!--c-->1<b>b<!--c--></b>c<!--c-->1<s/>"
-            + "a<!--c-->1<b>b<!--c-->c</b>d<!--c-->1<s/>"
-            + "a<!--c-->1<b>b<!--c-->c</b>d<!--c-->1<s/>"
-            + "a<!--c-->1<b>b<!--c-->1<e>c<!--c-->1</e>d<!--c-->1</b>e<!--c-->1<s/>"
-            + "</a>";
-    private static final String TEXT_MERGE_EXPECTED =
-            "<a>"
-            + "%a<s/>"
-            + "%a<s/>"
-            + "%ab<s/>"
-            + "%ab<s/>"
-            + "%a<b>%b</b>%c<s/>"
-            + "%a<b>%b</b>%c<s/>"
-            + "%a1<b>%b</b>%c1<s/>"
-            + "%a1<b>%bc</b>%d1<s/>"
-            + "%a1<b>%bc</b>%d1<s/>"
-            + "%a1<b>%b1<e>%c1</e>%d1</b>%e1<s/>"
-            + "</a>";
-    
-    @Test
-    public void testTest() throws Exception {
-        String expected = "<!DOCTYPE ...><?p?><a>%x<![CDATA[y]]><!--c--><?p?>%z<?p?><b><!--c--></b><c/>"
-                   + "<d>%a<e>%c</e>%b<!--c--><!--c--><!--c--><?p?><?p?><?p?></d>"
-                   + "<f><![CDATA[1]]>%2</f></a><!--c-->";
-        assertEquals(expected, toString(XMLLoader.toDOM(COMMON_TEST_XML)));
-    }
-
-    @Test
-    public void testMergeAdjacentText() throws Exception {
-        Document dom = XMLLoader.toDOM(COMMON_TEST_XML);
-        NodeModel.mergeAdjacentText(dom);
-        assertEquals(
-                "<!DOCTYPE ...><?p?><a>%xy<!--c--><?p?>%z<?p?><b><!--c--></b><c/>"
-                + "<d>%a<e>%c</e>%b<!--c--><!--c--><!--c--><?p?><?p?><?p?></d>"
-                + "<f><![CDATA[12]]></f></a><!--c-->",
-                toString(dom));
-    }
-
-    @Test
-    public void testRemoveComments() throws Exception {
-        Document dom = XMLLoader.toDOM(COMMON_TEST_XML);
-        NodeModel.removeComments(dom);
-        assertEquals(
-                "<!DOCTYPE ...><?p?><a>%x<![CDATA[y]]><?p?>%z<?p?><b/><c/>"
-                + "<d>%a<e>%c</e>%b<?p?><?p?><?p?></d>"
-                + "<f><![CDATA[1]]>%2</f></a>",
-                toString(dom));
-    }
-
-    @Test
-    public void testRemovePIs() throws Exception {
-        Document dom = XMLLoader.toDOM(COMMON_TEST_XML);
-        NodeModel.removePIs(dom);
-        assertEquals(
-                "<!DOCTYPE ...><a>%x<![CDATA[y]]><!--c-->%z<b><!--c--></b><c/>"
-                + "<d>%a<e>%c</e>%b<!--c--><!--c--><!--c--></d>"
-                + "<f><![CDATA[1]]>%2</f></a><!--c-->",
-                toString(dom));
-    }
-    
-    @Test
-    public void testSimplify() throws Exception {
-        testSimplify(
-                "<!DOCTYPE ...><a>%xyz<b/><c/>"
-                + "<d>%a<e>%c</e>%b</d><f><![CDATA[12]]></f></a>",
-                COMMON_TEST_XML);
-    }
-
-    @Test
-    public void testSimplify2() throws Exception {
-        testSimplify(TEXT_MERGE_EXPECTED, TEXT_MERGE_CONTENT);
-    }
-
-    @Test
-    public void testSimplify3() throws Exception {
-        testSimplify("<a/>", "<a/>");
-    }
-    
-    private void testSimplify(String expected, String content)
-            throws SAXException, IOException, ParserConfigurationException {
-        {
-            Document dom = XMLLoader.toDOM(content);
-            NodeModel.simplify(dom);
-            assertEquals(expected, toString(dom));
-        }
-        
-        // Must be equivalent:
-        {
-            Document dom = XMLLoader.toDOM(content);
-            NodeModel.removeComments(dom);
-            NodeModel.removePIs(dom);
-            NodeModel.mergeAdjacentText(dom);
-            assertEquals(expected, toString(dom));
-        }
-        
-        // Must be equivalent:
-        {
-            Document dom = XMLLoader.toDOM(content);
-            NodeModel.removeComments(dom);
-            NodeModel.removePIs(dom);
-            NodeModel.simplify(dom);
-            assertEquals(expected, toString(dom));
-        }
-    }
-
-    private String toString(Document doc) {
-        StringBuilder sb = new StringBuilder();
-        toString(doc, sb);
-        return sb.toString();
-    }
-
-    private void toString(Node node, StringBuilder sb) {
-        if (node instanceof Document) {
-            childrenToString(node, sb);
-        } else if (node instanceof Element) {
-            if (node.hasChildNodes()) {
-                sb.append("<").append(node.getNodeName()).append(">");
-                childrenToString(node, sb);
-                sb.append("</").append(node.getNodeName()).append(">");
-            } else {
-                sb.append("<").append(node.getNodeName()).append("/>");
-            }
-        } else if (node instanceof Text) {
-            if (node instanceof CDATASection) {
-                sb.append("<![CDATA[").append(node.getNodeValue()).append("]]>");
-            } else {
-                sb.append("%").append(node.getNodeValue());
-            }
-        } else if (node instanceof Comment) {
-            sb.append("<!--").append(node.getNodeValue()).append("-->");
-        } else if (node instanceof ProcessingInstruction) {
-            sb.append("<?").append(node.getNodeName()).append("?>");
-        } else if (node instanceof DocumentType) {
-            sb.append("<!DOCTYPE ...>");
-        } else {
-            throw new IllegalStateException("Unhandled node type: " + node.getClass().getName());
-        }
-    }
-
-    private void childrenToString(Node node, StringBuilder sb) {
-        Node child = node.getFirstChild();
-        while (child != null) {
-            toString(child, sb);
-            child = child.getNextSibling();
-        }
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/dom/DOMTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/dom/DOMTest.java b/freemarker-core/src/test/java/org/apache/freemarker/dom/DOMTest.java
deleted file mode 100644
index e9ecf87..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/dom/DOMTest.java
+++ /dev/null
@@ -1,159 +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.dom;
-
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.io.StringReader;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-
-import org.apache.freemarker.core.TemplateException;
-import org.apache.freemarker.test.TemplateTest;
-import org.apache.freemarker.test.util.XMLLoader;
-import org.junit.Test;
-import org.w3c.dom.Document;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-
-public class DOMTest extends TemplateTest {
-
-    @Test
-    public void xpathDetectionBugfix() throws Exception {
-        addDocToDataModel("<root><a>A</a><b>B</b><c>C</c></root>");
-        assertOutput("${doc.root.b['following-sibling::c']}", "C");
-        assertOutput("${doc.root.b['following-sibling::*']}", "C");
-    }
-
-    @Test
-    public void xmlnsPrefixes() throws Exception {
-        addDocToDataModel("<root xmlns='http://example.com/ns1' xmlns:ns2='http://example.com/ns2'>"
-                + "<a>A</a><ns2:b>B</ns2:b><c a1='1' ns2:a2='2'/></root>");
-
-        String ftlHeader = "<#ftl ns_prefixes={'D':'http://example.com/ns1', 'n2':'http://example.com/ns2'}>";
-        
-        // @@markup:
-        assertOutput("${doc.@@markup}",
-                "<a:root xmlns:a=\"http://example.com/ns1\" xmlns:b=\"http://example.com/ns2\">"
-                + "<a:a>A</a:a><b:b>B</b:b><a:c a1=\"1\" b:a2=\"2\" />"
-                + "</a:root>");
-        assertOutput(ftlHeader
-                + "${doc.@@markup}",
-                "<root xmlns=\"http://example.com/ns1\" xmlns:n2=\"http://example.com/ns2\">"
-                + "<a>A</a><n2:b>B</n2:b><c a1=\"1\" n2:a2=\"2\" /></root>");
-        assertOutput("<#ftl ns_prefixes={'D':'http://example.com/ns1'}>"
-                + "${doc.@@markup}",
-                "<root xmlns=\"http://example.com/ns1\" xmlns:a=\"http://example.com/ns2\">"
-                + "<a>A</a><a:b>B</a:b><c a1=\"1\" a:a2=\"2\" /></root>");
-        
-        // When there's no matching prefix declared via the #ftl header, return null for qname:
-        assertOutput("${doc?children[0].@@qname!'null'}", "null");
-        assertOutput("${doc?children[0]?children[1].@@qname!'null'}", "null");
-        assertOutput("${doc?children[0]?children[2]['@*'][1].@@qname!'null'}", "null");
-        
-        // When we have prefix declared in the #ftl header:
-        assertOutput(ftlHeader + "${doc?children[0].@@qname}", "root");
-        assertOutput(ftlHeader + "${doc?children[0]?children[1].@@qname}", "n2:b");
-        assertOutput(ftlHeader + "${doc?children[0]?children[2].@@qname}", "c");
-        assertOutput(ftlHeader + "${doc?children[0]?children[2]['@*'][0].@@qname}", "a1");
-        assertOutput(ftlHeader + "${doc?children[0]?children[2]['@*'][1].@@qname}", "n2:a2");
-        // Unfortunately these include the xmlns attributes, but that would be non-BC to fix now:
-        assertThat(getOutput(ftlHeader + "${doc?children[0].@@start_tag}"), startsWith("<root"));
-        assertThat(getOutput(ftlHeader + "${doc?children[0]?children[1].@@start_tag}"), startsWith("<n2:b"));
-    }
-    
-    @Test
-    public void namespaceUnaware() throws Exception {
-        addNSUnawareDocToDataModel("<root><x:a>A</x:a><:>B</:><xyz::c>C</xyz::c></root>");
-        assertOutput("${doc.root['x:a']}", "A");
-        assertOutput("${doc.root[':']}", "B");
-        try {
-            assertOutput("${doc.root['xyz::c']}", "C");
-            fail();
-        } catch (TemplateException e) {
-            assertThat(e.getMessage(), containsString("xyz"));
-        }
-    }
-    
-    private void addDocToDataModel(String xml) throws SAXException, IOException, ParserConfigurationException {
-        addToDataModel("doc", XMLLoader.toModel(new InputSource(new StringReader(xml))));
-    }
-
-    private void addDocToDataModelNoSimplification(String xml) throws SAXException, IOException, ParserConfigurationException {
-        addToDataModel("doc", XMLLoader.toModel(new InputSource(new StringReader(xml)), false));
-    }
-    
-    private void addNSUnawareDocToDataModel(String xml) throws ParserConfigurationException, SAXException, IOException {
-        DocumentBuilderFactory newFactory = DocumentBuilderFactory.newInstance();
-        newFactory.setNamespaceAware(false);
-        DocumentBuilder builder = newFactory.newDocumentBuilder();
-        Document doc = builder.parse(new InputSource(new StringReader(xml)));
-        addToDataModel("doc", doc);
-    }
-
-    @Test
-    public void testInvalidAtAtKeyErrors() throws Exception {
-        addDocToDataModel("<r><multipleMatches /><multipleMatches /></r>");
-        assertErrorContains("${doc.r.@@invalid_key}", "Unsupported @@ key", "@invalid_key");
-        assertErrorContains("${doc.@@start_tag}", "@@start_tag", "not supported", "document");
-        assertErrorContains("${doc.@@}", "\"@@\"", "not supported", "document");
-        assertErrorContains("${doc.r.noMatch.@@invalid_key}", "Unsupported @@ key", "@invalid_key");
-        assertErrorContains("${doc.r.multipleMatches.@@invalid_key}", "Unsupported @@ key", "@invalid_key");
-        assertErrorContains("${doc.r.noMatch.@@attributes_markup}", "single XML node", "@@attributes_markup");
-        assertErrorContains("${doc.r.multipleMatches.@@attributes_markup}", "single XML node", "@@attributes_markup");
-    }
-    
-    @Test
-    public void testAtAtSiblingElement() throws Exception {
-        addDocToDataModel("<r><a/><b/></r>");
-        assertOutput("${doc.r.@@previous_sibling_element?size}", "0");
-        assertOutput("${doc.r.@@next_sibling_element?size}", "0");
-        assertOutput("${doc.r.a.@@previous_sibling_element?size}", "0");
-        assertOutput("${doc.r.a.@@next_sibling_element.@@qname}", "b");
-        assertOutput("${doc.r.b.@@previous_sibling_element.@@qname}", "a");
-        assertOutput("${doc.r.b.@@next_sibling_element?size}", "0");
-        
-        addDocToDataModel("<r>\r\n\t <a/>\r\n\t <b/>\r\n\t </r>");
-        assertOutput("${doc.r.@@previous_sibling_element?size}", "0");
-        assertOutput("${doc.r.@@next_sibling_element?size}", "0");
-        assertOutput("${doc.r.a.@@previous_sibling_element?size}", "0");
-        assertOutput("${doc.r.a.@@next_sibling_element.@@qname}", "b");
-        assertOutput("${doc.r.b.@@previous_sibling_element.@@qname}", "a");
-        assertOutput("${doc.r.b.@@next_sibling_element?size}", "0");
-        
-        addDocToDataModel("<r>t<a/>t<b/>t</r>");
-        assertOutput("${doc.r.a.@@previous_sibling_element?size}", "0");
-        assertOutput("${doc.r.a.@@next_sibling_element?size}", "0");
-        assertOutput("${doc.r.b.@@previous_sibling_element?size}", "0");
-        assertOutput("${doc.r.b.@@next_sibling_element?size}", "0");
-        
-        addDocToDataModelNoSimplification("<r><a/> <!-- --><?pi?>&#x20;<b/></r>");
-        assertOutput("${doc.r.a.@@next_sibling_element.@@qname}", "b");
-        assertOutput("${doc.r.b.@@previous_sibling_element.@@qname}", "a");
-        
-        addDocToDataModelNoSimplification("<r><a/> <!-- -->t<!-- --> <b/></r>");
-        assertOutput("${doc.r.a.@@next_sibling_element?size}", "0");
-        assertOutput("${doc.r.b.@@previous_sibling_element?size}", "0");
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/manualtest/AutoEscapingExample.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/manualtest/AutoEscapingExample.java b/freemarker-core/src/test/java/org/apache/freemarker/manualtest/AutoEscapingExample.java
deleted file mode 100644
index 036bace..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/manualtest/AutoEscapingExample.java
+++ /dev/null
@@ -1,72 +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.manualtest;
-
-import org.apache.freemarker.core.Configuration;
-import org.apache.freemarker.test.TemplateTest;
-import org.apache.freemarker.test.TestConfigurationBuilder;
-import org.junit.Test;
-
-public class AutoEscapingExample extends TemplateTest {
-
-    @Test
-    public void testInfoBox() throws Exception {
-        assertOutputForNamed("AutoEscapingExample-infoBox.ftlh");
-    }
-
-    @Test
-    public void testCapture() throws Exception {
-        assertOutputForNamed("AutoEscapingExample-capture.ftlh");
-    }
-
-    @Test
-    public void testMarkup() throws Exception {
-        assertOutputForNamed("AutoEscapingExample-markup.ftlh");
-    }
-
-    @Test
-    public void testConvert() throws Exception {
-        assertOutputForNamed("AutoEscapingExample-convert.ftlh");
-    }
-
-    @Test
-    public void testConvert2() throws Exception {
-        assertOutputForNamed("AutoEscapingExample-convert2.ftl");
-    }
-
-    @Test
-    public void testStringLiteral() throws Exception {
-        assertOutputForNamed("AutoEscapingExample-stringLiteral.ftlh");
-    }
-
-    @Test
-    public void testStringLiteral2() throws Exception {
-        assertOutputForNamed("AutoEscapingExample-stringLiteral2.ftlh");
-    }
-
-    @Test
-    public void testStringConcat() throws Exception {
-        assertOutputForNamed("AutoEscapingExample-stringConcat.ftlh");
-    }
-
-    @Override
-    protected Configuration createDefaultConfiguration() throws Exception {
-        return new TestConfigurationBuilder(AutoEscapingExample.class).build();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/manualtest/ConfigureOutputFormatExamples.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/manualtest/ConfigureOutputFormatExamples.java b/freemarker-core/src/test/java/org/apache/freemarker/manualtest/ConfigureOutputFormatExamples.java
deleted file mode 100644
index 40c1297..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/manualtest/ConfigureOutputFormatExamples.java
+++ /dev/null
@@ -1,105 +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.manualtest;
-
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-
-import org.apache.freemarker.core.TemplateConfiguration;
-import org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat;
-import org.apache.freemarker.core.outputformat.impl.RTFOutputFormat;
-import org.apache.freemarker.core.outputformat.impl.XMLOutputFormat;
-import org.apache.freemarker.core.templateresolver.ConditionalTemplateConfigurationFactory;
-import org.apache.freemarker.core.templateresolver.FileExtensionMatcher;
-import org.apache.freemarker.core.templateresolver.FirstMatchTemplateConfigurationFactory;
-import org.apache.freemarker.core.templateresolver.OrMatcher;
-import org.apache.freemarker.core.templateresolver.PathGlobMatcher;
-import org.apache.freemarker.test.TemplateTest;
-import org.apache.freemarker.test.TestConfigurationBuilder;
-import org.junit.Test;
-
-public class ConfigureOutputFormatExamples extends TemplateTest {
-    
-    @Test
-    public void test() throws Exception {
-        addTemplate("mail/t.ftl", "");
-        addTemplate("t.html", "");
-        addTemplate("t.htm", "");
-        addTemplate("t.xml", "");
-        addTemplate("t.rtf", "");
-
-        example2(true);
-        example2(false);
-        example3(true);
-        example3(false);
-    }
-
-    private void example2(boolean javaCfg) throws IOException {
-        setConfiguration(
-                javaCfg
-                        ? new TestConfigurationBuilder()
-                                .templateConfigurations(
-                                        new ConditionalTemplateConfigurationFactory(
-                                                new PathGlobMatcher("mail/**"),
-                                                new TemplateConfiguration.Builder()
-                                                        .outputFormat(HTMLOutputFormat.INSTANCE)
-                                                        .build()))
-                                .build()
-                        : new TestConfigurationBuilder()
-                                .settings(loadPropertiesFile("ConfigureOutputFormatExamples1.properties"))
-                                .build());
-        assertEquals(HTMLOutputFormat.INSTANCE, getConfiguration().getTemplate("mail/t.ftl").getOutputFormat());
-    }
-
-    private void example3(boolean javaCfg) throws IOException {
-        setConfiguration(
-                javaCfg
-                        ? new TestConfigurationBuilder()
-                                .templateConfigurations(
-                                        new FirstMatchTemplateConfigurationFactory(
-                                                new ConditionalTemplateConfigurationFactory(
-                                                        new FileExtensionMatcher("xml"),
-                                                        new TemplateConfiguration.Builder()
-                                                                .outputFormat(XMLOutputFormat.INSTANCE)
-                                                                .build()),
-                                                new ConditionalTemplateConfigurationFactory(
-                                                        new OrMatcher(
-                                                                new FileExtensionMatcher("html"),
-                                                                new FileExtensionMatcher("htm")),
-                                                        new TemplateConfiguration.Builder()
-                                                                .outputFormat(HTMLOutputFormat.INSTANCE)
-                                                                .build()),
-                                                new ConditionalTemplateConfigurationFactory(
-                                                        new FileExtensionMatcher("rtf"),
-                                                        new TemplateConfiguration.Builder()
-                                                                .outputFormat(RTFOutputFormat.INSTANCE)
-                                                                .build()))
-                                        .allowNoMatch(true))
-                                .build()
-                        : new TestConfigurationBuilder()
-                                .settings(loadPropertiesFile("ConfigureOutputFormatExamples2.properties"))
-                                .build());
-        assertEquals(HTMLOutputFormat.INSTANCE, getConfiguration().getTemplate("t.html").getOutputFormat());
-        assertEquals(HTMLOutputFormat.INSTANCE, getConfiguration().getTemplate("t.htm").getOutputFormat());
-        assertEquals(XMLOutputFormat.INSTANCE, getConfiguration().getTemplate("t.xml").getOutputFormat());
-        assertEquals(RTFOutputFormat.INSTANCE, getConfiguration().getTemplate("t.rtf").getOutputFormat());
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/manualtest/CustomFormatsExample.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/manualtest/CustomFormatsExample.java b/freemarker-core/src/test/java/org/apache/freemarker/manualtest/CustomFormatsExample.java
deleted file mode 100644
index f38bb14..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/manualtest/CustomFormatsExample.java
+++ /dev/null
@@ -1,84 +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.manualtest;
-
-import java.io.IOException;
-import java.math.BigDecimal;
-import java.util.Date;
-
-import org.apache.freemarker.core.TemplateException;
-import org.apache.freemarker.core.userpkg.BaseNTemplateNumberFormatFactory;
-import org.apache.freemarker.core.valueformat.TemplateDateFormatFactory;
-import org.apache.freemarker.core.valueformat.TemplateNumberFormatFactory;
-import org.apache.freemarker.core.valueformat.impl.AliasTemplateDateFormatFactory;
-import org.apache.freemarker.core.valueformat.impl.AliasTemplateNumberFormatFactory;
-import org.apache.freemarker.test.TemplateTest;
-import org.apache.freemarker.test.TestConfigurationBuilder;
-import org.junit.Test;
-
-import com.google.common.collect.ImmutableMap;
-
-@SuppressWarnings("boxing")
-public class CustomFormatsExample extends TemplateTest {
-
-    @Test
-    public void aliases1() throws IOException, TemplateException {
-        setConfiguration(new TestConfigurationBuilder(this.getClass())
-            .customNumberFormats(ImmutableMap.<String, TemplateNumberFormatFactory>of(
-                    "price", new AliasTemplateNumberFormatFactory(",000.00"),
-                    "weight", new AliasTemplateNumberFormatFactory("0.##;; roundingMode=halfUp")))
-            .customDateFormats(ImmutableMap.<String, TemplateDateFormatFactory>of(
-                    "fileDate", new AliasTemplateDateFormatFactory("dd/MMM/yy hh:mm a"),
-                    "logEventTime", new AliasTemplateDateFormatFactory("iso ms u")
-                    ))
-            .build());
-
-        addToDataModel("p", 10000);
-        addToDataModel("w", new BigDecimal("10.305"));
-        addToDataModel("fd", new Date(1450904944213L));
-        addToDataModel("let", new Date(1450904944213L));
-        
-        assertOutputForNamed("CustomFormatsExample-alias1.ftlh");
-    }
-
-    @Test
-    public void aliases2() throws IOException, TemplateException {
-        setConfiguration(new TestConfigurationBuilder(this.getClass())
-                .customNumberFormats(ImmutableMap.of(
-                        "base", BaseNTemplateNumberFormatFactory.INSTANCE,
-                        "oct", new AliasTemplateNumberFormatFactory("@base 8")))
-                .build());
-
-        assertOutputForNamed("CustomFormatsExample-alias2.ftlh");
-    }
-
-    @Test
-    public void modelAware() throws IOException, TemplateException {
-        setConfiguration(new TestConfigurationBuilder(this.getClass())
-                .customNumberFormats(ImmutableMap.<String, TemplateNumberFormatFactory>of(
-                        "ua", UnitAwareTemplateNumberFormatFactory.INSTANCE))
-                .numberFormat("@ua 0.####;; roundingMode=halfUp")
-                .build());
-
-        addToDataModel("weight", new UnitAwareTemplateNumberModel(1.5, "kg"));
-        
-        assertOutputForNamed("CustomFormatsExample-modelAware.ftlh");
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/manualtest/GettingStartedExample.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/manualtest/GettingStartedExample.java b/freemarker-core/src/test/java/org/apache/freemarker/manualtest/GettingStartedExample.java
deleted file mode 100644
index a676bc4..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/manualtest/GettingStartedExample.java
+++ /dev/null
@@ -1,69 +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.manualtest;
-
-import java.io.OutputStreamWriter;
-import java.io.Writer;
-import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.freemarker.core.Configuration;
-import org.apache.freemarker.core.Template;
-import org.apache.freemarker.core.TemplateExceptionHandler;
-import org.apache.freemarker.core.templateresolver.impl.ClassTemplateLoader;
-import org.junit.Test;
-
-public class GettingStartedExample {
-
-    @Test
-    public void main() throws Exception {
-        /* ------------------------------------------------------------------------ */    
-        /* You should do this ONLY ONCE in the whole application life-cycle:        */    
-    
-        /* Create the configuration singleton (using builder pattern) */
-        Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0)
-                .templateLoader(new ClassTemplateLoader(GettingStartedExample.class, ""))
-                .sourceEncoding(StandardCharsets.UTF_8)
-                .templateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER)
-                .logTemplateExceptions(false)
-                .build();
-
-        /* ------------------------------------------------------------------------ */    
-        /* You usually do these for MULTIPLE TIMES in the application life-cycle:   */    
-
-        /* Create a data-model */
-        Map<String, Object> root = new HashMap();
-        root.put("user", "Big Joe");
-        Product latest = new Product();
-        latest.setUrl("products/greenmouse.html");
-        latest.setName("green mouse");
-        root.put("latestProduct", latest);
-
-        /* Get the template (uses cache internally) */
-        Template temp = cfg.getTemplate("test.ftlh");
-
-        /* Merge data-model with template */
-        Writer out = new OutputStreamWriter(System.out);
-        temp.process(root, out);
-        // Note: Depending on what `out` is, you may need to call `out.close()`.
-        // This is usually the case for file output, but not for servlet output.
-    }
-    
-}



[21/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/DateFormatTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/DateFormatTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/DateFormatTest.java
deleted file mode 100644
index 4ad5937..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/DateFormatTest.java
+++ /dev/null
@@ -1,464 +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;
-
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.sql.Time;
-import java.sql.Timestamp;
-import java.util.Collections;
-import java.util.Date;
-import java.util.Locale;
-import java.util.TimeZone;
-
-import org.apache.freemarker.core.model.TemplateDateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.impl.SimpleDate;
-import org.apache.freemarker.core.templateresolver.ConditionalTemplateConfigurationFactory;
-import org.apache.freemarker.core.templateresolver.FileNameGlobMatcher;
-import org.apache.freemarker.core.userpkg.AppMetaTemplateDateFormatFactory;
-import org.apache.freemarker.core.userpkg.EpochMillisDivTemplateDateFormatFactory;
-import org.apache.freemarker.core.userpkg.EpochMillisTemplateDateFormatFactory;
-import org.apache.freemarker.core.userpkg.HTMLISOTemplateDateFormatFactory;
-import org.apache.freemarker.core.userpkg.LocAndTZSensitiveTemplateDateFormatFactory;
-import org.apache.freemarker.core.valueformat.TemplateDateFormat;
-import org.apache.freemarker.core.valueformat.TemplateDateFormatFactory;
-import org.apache.freemarker.core.valueformat.UndefinedCustomFormatException;
-import org.apache.freemarker.core.valueformat.impl.AliasTemplateDateFormatFactory;
-import org.apache.freemarker.test.TemplateTest;
-import org.apache.freemarker.test.TestConfigurationBuilder;
-import org.junit.Test;
-
-import com.google.common.collect.ImmutableMap;
-
-public class DateFormatTest extends TemplateTest {
-    
-    /** 2015-09-06T12:00:00Z */
-    private static long T = 1441540800000L;
-    private static TemplateDateModel TM = new SimpleDate(new Date(T), TemplateDateModel.DATETIME);
-    
-    private TestConfigurationBuilder createConfigurationBuilder() {
-        return new TestConfigurationBuilder()
-                .locale(Locale.US)
-                .timeZone(TimeZone.getTimeZone("GMT+01:00"))
-                .sqlDateAndTimeTimeZone(TimeZone.getTimeZone("UTC"))
-                .customDateFormats(ImmutableMap.of(
-                        "epoch", EpochMillisTemplateDateFormatFactory.INSTANCE,
-                        "loc", LocAndTZSensitiveTemplateDateFormatFactory.INSTANCE,
-                        "div", EpochMillisDivTemplateDateFormatFactory.INSTANCE,
-                        "appMeta", AppMetaTemplateDateFormatFactory.INSTANCE,
-                        "htmlIso", HTMLISOTemplateDateFormatFactory.INSTANCE));
-    }
-
-    @Override
-    protected Configuration createDefaultConfiguration() throws Exception {
-        return createConfigurationBuilder().build();
-    }
-
-    @Test
-    public void testCustomFormat() throws Exception {
-        addToDataModel("d", new Date(123456789));
-        assertOutput(
-                "${d?string.@epoch} ${d?string.@epoch} <#setting locale='de_DE'>${d?string.@epoch}",
-                "123456789 123456789 123456789");
-
-        setConfigurationWithDateTimeFormat("@epoch");
-        assertOutput(
-                "<#assign d = d?datetime>"
-                + "${d} ${d?string} <#setting locale='de_DE'>${d}",
-                "123456789 123456789 123456789");
-
-        setConfigurationWithDateTimeFormat("@htmlIso");
-        assertOutput(
-                "<#assign d = d?datetime>"
-                + "${d} ${d?string} <#setting locale='de_DE'>${d}",
-                "1970-01-02<span class='T'>T</span>10:17:36Z "
-                + "1970-01-02T10:17:36Z "
-                + "1970-01-02<span class='T'>T</span>10:17:36Z");
-    }
-
-    @Test
-    public void testLocaleChange() throws Exception {
-        addToDataModel("d", new Date(123456789));
-        assertOutput(
-                "${d?string.@loc} ${d?string.@loc} "
-                + "<#setting locale='de_DE'>"
-                + "${d?string.@loc} ${d?string.@loc} "
-                + "<#setting locale='en_US'>"
-                + "${d?string.@loc} ${d?string.@loc}",
-                "123456789@en_US:GMT+01:00 123456789@en_US:GMT+01:00 "
-                + "123456789@de_DE:GMT+01:00 123456789@de_DE:GMT+01:00 "
-                + "123456789@en_US:GMT+01:00 123456789@en_US:GMT+01:00");
-
-        setConfigurationWithDateTimeFormat("@loc");
-        assertOutput(
-                "<#assign d = d?datetime>"
-                + "${d} ${d?string} "
-                + "<#setting locale='de_DE'>"
-                + "${d} ${d?string} "
-                + "<#setting locale='en_US'>"
-                + "${d} ${d?string}",
-                "123456789@en_US:GMT+01:00 123456789@en_US:GMT+01:00 "
-                + "123456789@de_DE:GMT+01:00 123456789@de_DE:GMT+01:00 "
-                + "123456789@en_US:GMT+01:00 123456789@en_US:GMT+01:00");
-    }
-
-    @Test
-    public void testTimeZoneChange() throws Exception {
-        addToDataModel("d", new Date(123456789));
-        setConfigurationWithDateTimeFormat("iso");
-        assertOutput(
-                "${d?string.@loc} ${d?string.@loc} ${d?datetime?isoLocal} "
-                + "<#setting timeZone='GMT+02:00'>"
-                + "${d?string.@loc} ${d?string.@loc} ${d?datetime?isoLocal} "
-                + "<#setting timeZone='GMT+01:00'>"
-                + "${d?string.@loc} ${d?string.@loc} ${d?datetime?isoLocal}",
-                "123456789@en_US:GMT+01:00 123456789@en_US:GMT+01:00 1970-01-02T11:17:36+01:00 "
-                + "123456789@en_US:GMT+02:00 123456789@en_US:GMT+02:00 1970-01-02T12:17:36+02:00 "
-                + "123456789@en_US:GMT+01:00 123456789@en_US:GMT+01:00 1970-01-02T11:17:36+01:00");
-
-        setConfigurationWithDateTimeFormat("@loc");
-        assertOutput(
-                "<#assign d = d?datetime>"
-                + "${d} ${d?string} "
-                + "<#setting timeZone='GMT+02:00'>"
-                + "${d} ${d?string} "
-                + "<#setting timeZone='GMT+01:00'>"
-                + "${d} ${d?string}",
-                "123456789@en_US:GMT+01:00 123456789@en_US:GMT+01:00 "
-                + "123456789@en_US:GMT+02:00 123456789@en_US:GMT+02:00 "
-                + "123456789@en_US:GMT+01:00 123456789@en_US:GMT+01:00");
-    }
-    
-    @Test
-    public void testWrongFormatStrings() throws Exception {
-        setConfigurationWithDateTimeFormat("x1");
-        assertErrorContains("${.now}", "\"x1\"", "'x'");
-        assertErrorContains("${.now?string}", "\"x1\"", "'x'");
-        setConfigurationWithDateTimeFormat("short");
-        assertErrorContains("${.now?string('x2')}", "\"x2\"", "'x'");
-        assertErrorContains("${.now?string('[wrong]')}", "format string", "[wrong]");
-
-        setConfiguration(createConfigurationBuilder()
-                .dateFormat("[wrong d]")
-                .dateTimeFormat("[wrong dt]")
-                .timeFormat("[wrong t]")
-                .build());
-        assertErrorContains("${.now?date}", "\"date_format\"", "[wrong d]");
-        assertErrorContains("${.now?datetime}", "\"datetime_format\"", "[wrong dt]");
-        assertErrorContains("${.now?time}", "\"time_format\"", "[wrong t]");
-    }
-
-    @Test
-    public void testCustomParameterized() throws Exception {
-        Configuration cfg = getConfiguration();
-        addToDataModel("d", new SimpleDate(new Date(12345678L), TemplateDateModel.DATETIME));
-        setConfigurationWithDateTimeFormat("@div 1000");
-        assertOutput("${d}", "12345");
-        assertOutput("${d?string}", "12345");
-        assertOutput("${d?string.@div_100}", "123456");
-        
-        assertErrorContains("${d?string.@div_xyz}", "\"@div_xyz\"", "\"xyz\"");
-        setConfigurationWithDateTimeFormat("@div");
-        assertErrorContains("${d}", "\"datetime_format\"", "\"@div\"", "format parameter is required");
-    }
-    
-    @Test
-    public void testUnknownCustomFormat() throws Exception {
-        {
-            setConfigurationWithDateTimeFormat("@noSuchFormat");
-            Throwable exc = assertErrorContains(
-                    "${.now}",
-                    "\"@noSuchFormat\"", "\"noSuchFormat\"", "\"datetime_format\"");
-            assertThat(exc.getCause(), instanceOf(UndefinedCustomFormatException.class));
-            
-        }
-        {
-            setConfiguration(createConfigurationBuilder().dateFormat("@noSuchFormatD").build());
-            assertErrorContains(
-                    "${.now?date}",
-                    "\"@noSuchFormatD\"", "\"noSuchFormatD\"", "\"date_format\"");
-        }
-        {
-            setConfiguration(createConfigurationBuilder().timeFormat("@noSuchFormatT").build());
-            assertErrorContains(
-                    "${.now?time}",
-                    "\"@noSuchFormatT\"", "\"noSuchFormatT\"", "\"time_format\"");
-        }
-
-        {
-            setConfigurationWithDateTimeFormat("");
-            Throwable exc = assertErrorContains("${.now?string('@noSuchFormat2')}",
-                    "\"@noSuchFormat2\"", "\"noSuchFormat2\"");
-            assertThat(exc.getCause(), instanceOf(UndefinedCustomFormatException.class));
-        }
-    }
-
-    private void setConfigurationWithDateTimeFormat(String formatString) {
-        setConfiguration(createConfigurationBuilder().dateTimeFormat(formatString).build());
-    }
-
-    @Test
-    public void testNullInModel() throws Exception {
-        addToDataModel("d", new MutableTemplateDateModel());
-        assertErrorContains("${d}", "nothing inside it");
-        assertErrorContains("${d?string}", "nothing inside it");
-    }
-    
-    @Test
-    public void testIcIAndEscaping() throws Exception {
-        addToDataModel("d", new SimpleDate(new Date(12345678L), TemplateDateModel.DATETIME));
-        
-        setConfigurationWithDateTimeFormat("@epoch");
-        assertOutput("${d}", "12345678");
-        setConfigurationWithDateTimeFormat("'@'yyyy");
-        assertOutput("${d}", "@1970");
-        setConfigurationWithDateTimeFormat("@@yyyy");
-        assertOutput("${d}", "@@1970");
-
-        setConfiguration(createConfigurationBuilder()
-                .customDateFormats(Collections.<String, TemplateDateFormatFactory>emptyMap())
-                .dateTimeFormat("@epoch")
-                .build());
-        assertErrorContains("${d}", "custom", "\"epoch\"");
-    }
-
-    @Test
-    public void testEnvironmentGetters() throws Exception {
-        String dateFormatStr = "yyyy.MM.dd. (Z)";
-        String timeFormatStr = "HH:mm";
-        String dateTimeFormatStr = "yyyy.MM.dd. HH:mm";
-
-        setConfiguration(createConfigurationBuilder()
-                .dateFormat(dateFormatStr)
-                .timeFormat(timeFormatStr)
-                .dateTimeFormat(dateTimeFormatStr)
-                .build());
-
-        Configuration cfg = getConfiguration();
-
-        Template t = new Template(null, "", cfg);
-        Environment env = t.createProcessingEnvironment(null, null);
-        
-        // Test that values are coming from the cache if possible
-        for (Class dateClass : new Class[] { Date.class, Timestamp.class, java.sql.Date.class, Time.class } ) {
-            for (int dateType
-                    : new int[] { TemplateDateModel.DATE, TemplateDateModel.TIME, TemplateDateModel.DATETIME }) {
-                String formatString =
-                        dateType == TemplateDateModel.DATE ? cfg.getDateFormat() :
-                        (dateType == TemplateDateModel.TIME ? cfg.getTimeFormat()
-                        : cfg.getDateTimeFormat());
-                TemplateDateFormat expectedF = env.getTemplateDateFormat(formatString, dateType, dateClass);
-                assertSame(expectedF, env.getTemplateDateFormat(dateType, dateClass)); // Note: Only reads the cache
-                assertSame(expectedF, env.getTemplateDateFormat(formatString, dateType, dateClass));
-                assertSame(expectedF, env.getTemplateDateFormat(formatString, dateType, dateClass, cfg.getLocale()));
-                assertSame(expectedF, env.getTemplateDateFormat(formatString, dateType, dateClass, cfg.getLocale(),
-                        cfg.getTimeZone(), cfg.getSQLDateAndTimeTimeZone()));
-            }
-        }
-
-        String dateFormatStr2 = dateFormatStr + "'!'";
-        String timeFormatStr2 = timeFormatStr + "'!'";
-        String dateTimeFormatStr2 = dateTimeFormatStr + "'!'";
-        
-        assertEquals("2015.09.06. 13:00",
-                env.getTemplateDateFormat(TemplateDateModel.DATETIME, Date.class).formatToPlainText(TM));
-        assertEquals("2015.09.06. 13:00!",
-                env.getTemplateDateFormat(dateTimeFormatStr2, TemplateDateModel.DATETIME, Date.class).formatToPlainText(TM));
-        
-        assertEquals("2015.09.06. (+0100)",
-                env.getTemplateDateFormat(TemplateDateModel.DATE, Date.class).formatToPlainText(TM));
-        assertEquals("2015.09.06. (+0100)!",
-                env.getTemplateDateFormat(dateFormatStr2, TemplateDateModel.DATE, Date.class).formatToPlainText(TM));
-        
-        assertEquals("13:00",
-                env.getTemplateDateFormat(TemplateDateModel.TIME, Date.class).formatToPlainText(TM));
-        assertEquals("13:00!",
-                env.getTemplateDateFormat(timeFormatStr2, TemplateDateModel.TIME, Date.class).formatToPlainText(TM));
-        
-        assertEquals("2015.09.06. 13:00",
-                env.getTemplateDateFormat(TemplateDateModel.DATETIME, Timestamp.class).formatToPlainText(TM));
-        assertEquals("2015.09.06. 13:00!",
-                env.getTemplateDateFormat(dateTimeFormatStr2, TemplateDateModel.DATETIME, Timestamp.class).formatToPlainText(TM));
-
-        assertEquals("2015.09.06. (+0000)",
-                env.getTemplateDateFormat(TemplateDateModel.DATE, java.sql.Date.class).formatToPlainText(TM));
-        assertEquals("2015.09.06. (+0000)!",
-                env.getTemplateDateFormat(dateFormatStr2, TemplateDateModel.DATE, java.sql.Date.class).formatToPlainText(TM));
-
-        assertEquals("12:00",
-                env.getTemplateDateFormat(TemplateDateModel.TIME, Time.class).formatToPlainText(TM));
-        assertEquals("12:00!",
-                env.getTemplateDateFormat(timeFormatStr2, TemplateDateModel.TIME, Time.class).formatToPlainText(TM));
-
-        {
-            String dateTimeFormatStrLoc = dateTimeFormatStr + " EEEE";
-            // Gets into cache:
-            TemplateDateFormat format1
-                    = env.getTemplateDateFormat(dateTimeFormatStrLoc, TemplateDateModel.DATETIME, Date.class);
-            assertEquals("2015.09.06. 13:00 Sunday", format1.formatToPlainText(TM));
-            // Different locale (not cached):
-            assertEquals("2015.09.06. 13:00 Sonntag",
-                    env.getTemplateDateFormat(dateTimeFormatStrLoc, TemplateDateModel.DATETIME, Date.class,
-                            Locale.GERMANY).formatToPlainText(TM));
-            // Different locale and zone (not cached):
-            assertEquals("2015.09.06. 14:00 Sonntag",
-                    env.getTemplateDateFormat(dateTimeFormatStrLoc, TemplateDateModel.DATETIME, Date.class,
-                            Locale.GERMANY, TimeZone.getTimeZone("GMT+02"), TimeZone.getTimeZone("GMT+03")).formatToPlainText(TM));
-            // Different locale and zone (not cached):
-            assertEquals("2015.09.06. 15:00 Sonntag",
-                    env.getTemplateDateFormat(dateTimeFormatStrLoc, TemplateDateModel.DATETIME, java.sql.Date.class,
-                            Locale.GERMANY, TimeZone.getTimeZone("GMT+02"), TimeZone.getTimeZone("GMT+03")).formatToPlainText(TM));
-            // Check for corrupted cache:
-            TemplateDateFormat format2
-                    = env.getTemplateDateFormat(dateTimeFormatStrLoc, TemplateDateModel.DATETIME, Date.class);
-            assertEquals("2015.09.06. 13:00 Sunday", format2.formatToPlainText(TM));
-            assertSame(format1, format2);
-        }
-    }
-
-    @Test
-    public void testAliases() throws Exception {
-        setConfiguration(createConfigurationBuilder()
-                .customDateFormats(ImmutableMap.of(
-                        "d", new AliasTemplateDateFormatFactory("yyyy-MMM-dd"),
-                        "m", new AliasTemplateDateFormatFactory("yyyy-MMM"),
-                        "epoch", EpochMillisTemplateDateFormatFactory.INSTANCE))
-                .templateConfigurations(
-                        new ConditionalTemplateConfigurationFactory(
-                                new FileNameGlobMatcher("*2*"),
-                                new TemplateConfiguration.Builder()
-                                        .customDateFormats(ImmutableMap.<String, TemplateDateFormatFactory>of(
-                                                "m", new AliasTemplateDateFormatFactory("yyyy-MMMM"),
-                                                "i", new AliasTemplateDateFormatFactory("@epoch")))
-                                        .build()))
-                .build());
-
-        addToDataModel("d", TM);
-        String commonFtl = "${d?string.@d} ${d?string.@m} "
-                + "<#setting locale='fr_FR'>${d?string.@m} "
-                + "<#attempt>${d?string.@i}<#recover>E</#attempt>";
-        addTemplate("t1.ftl", commonFtl);
-        addTemplate("t2.ftl", commonFtl);
-        
-        // 2015-09-06T12:00:00Z
-        assertOutputForNamed("t1.ftl", "2015-Sep-06 2015-Sep 2015-sept. E");
-        assertOutputForNamed("t2.ftl", "2015-Sep-06 2015-September 2015-septembre " + T);
-    }
-    
-    @Test
-    public void testAliases2() throws Exception {
-        setConfiguration(
-                createConfigurationBuilder()
-                .customDateFormats(ImmutableMap.<String, TemplateDateFormatFactory>of(
-                        "d", new AliasTemplateDateFormatFactory("yyyy-MMM",
-                                ImmutableMap.of(
-                                        new Locale("en"), "yyyy-MMM'_en'",
-                                        Locale.UK, "yyyy-MMM'_en_GB'",
-                                        Locale.FRANCE, "yyyy-MMM'_fr_FR'"))))
-                .dateTimeFormat("@d")
-                .build());
-        addToDataModel("d", TM);
-        assertOutput(
-                "<#setting locale='en_US'>${d} "
-                + "<#setting locale='en_GB'>${d} "
-                + "<#setting locale='en_GB_Win'>${d} "
-                + "<#setting locale='fr_FR'>${d} "
-                + "<#setting locale='hu_HU'>${d}",
-                "2015-Sep_en 2015-Sep_en_GB 2015-Sep_en_GB 2015-sept._fr_FR 2015-szept.");
-    }
-    
-    /**
-     * ?date() and such are new in 2.3.24.
-     */
-    @Test
-    public void testZeroArgDateBI() throws IOException, TemplateException {
-        setConfiguration(
-                createConfigurationBuilder()
-                .dateFormat("@epoch")
-                .dateTimeFormat("@epoch")
-                .timeFormat("@epoch")
-                .build());
-
-        addToDataModel("t", String.valueOf(T));
-        
-        assertOutput(
-                "${t?date?string.xs_u} ${t?date()?string.xs_u}",
-                "2015-09-06Z 2015-09-06Z");
-        assertOutput(
-                "${t?time?string.xs_u} ${t?time()?string.xs_u}",
-                "12:00:00Z 12:00:00Z");
-        assertOutput(
-                "${t?datetime?string.xs_u} ${t?datetime()?string.xs_u}",
-                "2015-09-06T12:00:00Z 2015-09-06T12:00:00Z");
-    }
-
-    @Test
-    public void testAppMetaRoundtrip() throws IOException, TemplateException {
-        setConfiguration(
-                createConfigurationBuilder()
-                .dateFormat("@appMeta")
-                .dateTimeFormat("@appMeta")
-                .timeFormat("@appMeta")
-                .build());
-
-        addToDataModel("t", String.valueOf(T) + "/foo");
-        
-        assertOutput(
-                "${t?date} ${t?date()}",
-                T + " " + T + "/foo");
-        assertOutput(
-                "${t?time} ${t?time()}",
-                T + " " + T + "/foo");
-        assertOutput(
-                "${t?datetime} ${t?datetime()}",
-                T + " " + T + "/foo");
-    }
-    
-    @Test
-    public void testUnknownDateType() throws IOException, TemplateException {
-        addToDataModel("u", new Date(T));
-        assertErrorContains("${u?string}", "isn't known");
-        assertOutput("${u?string('yyyy')}", "2015");
-        assertOutput("<#assign s = u?string>${s('yyyy')}", "2015");
-    }
-    
-    private static class MutableTemplateDateModel implements TemplateDateModel {
-        
-        private Date date;
-
-        public void setDate(Date date) {
-            this.date = date;
-        }
-
-        @Override
-        public Date getAsDate() throws TemplateModelException {
-            return date;
-        }
-
-        @Override
-        public int getDateType() {
-            return DATETIME;
-        }
-        
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/DirectiveCallPlaceTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/DirectiveCallPlaceTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/DirectiveCallPlaceTest.java
deleted file mode 100644
index 29220c4..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/DirectiveCallPlaceTest.java
+++ /dev/null
@@ -1,249 +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;
-
-import java.io.IOException;
-import java.io.StringWriter;
-import java.io.Writer;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.apache.freemarker.core.model.TemplateDirectiveBody;
-import org.apache.freemarker.core.model.TemplateDirectiveModel;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateScalarModel;
-import org.apache.freemarker.core.util.ObjectFactory;
-import org.apache.freemarker.test.TemplateTest;
-import org.junit.Test;
-
-public class DirectiveCallPlaceTest extends TemplateTest {
-
-    @Test
-    public void testCustomDataBasics() throws IOException, TemplateException {
-        addTemplate(
-                "customDataBasics.ftl",
-                "<@u...@uc> <@u...@uc> <@uc>Ab<#-- -->c</...@uc> <@l...@lc> <@l...@lc>");
-        
-        CachingTextConverterDirective.resetCacheRecreationCount();
-        for (int i = 0; i < 3; i++) {
-            assertOutputForNamed(
-                    "customDataBasics.ftl",
-                    "ABC[cached 1] X=123 ABC[cached 2]  abc[cached 3]");
-        }
-    }
-
-    @Test
-    public void testCustomDataProviderMismatch() throws IOException, TemplateException {
-        addTemplate(
-                "customDataProviderMismatch.ftl",
-                "<#list [uc, lc, uc] as d><#list 1..2 as _><@d...@d></#list></#list>");
-        
-        CachingTextConverterDirective.resetCacheRecreationCount();
-        assertOutputForNamed(
-                "customDataProviderMismatch.ftl",
-                "ABC[cached 1]ABC[cached 1]abc[cached 2]abc[cached 2]ABC[cached 3]ABC[cached 3]");
-        assertOutputForNamed(
-                "customDataProviderMismatch.ftl",
-                "ABC[cached 3]ABC[cached 3]abc[cached 4]abc[cached 4]ABC[cached 5]ABC[cached 5]");
-    }
-    
-    @Test
-    public void testPositions() throws IOException, TemplateException {
-        addTemplate(
-                "positions.ftl",
-                "<@pa />\n"
-                + "..<@pa\n"
-                + "/><@pa>xxx</@>\n"
-                + "<@pa>{<@pa/> <@pa/>}</@>\n"
-                + "${curDirLine}<@argP p=curDirLine?string>${curDirLine}</...@argP>${curDirLine}\n"
-                + "<#macro m p>(p=${p}){<#nested>}</#macro>\n"
-                + "${curDirLine}<@m p=curDirLine?string>${curDirLine}</...@m>${curDirLine}");
-        
-        assertOutputForNamed(
-                "positions.ftl",
-                "[positions.ftl:1:1-1:7]"
-                + "..[positions.ftl:2:3-3:2]"
-                + "[positions.ftl:3:3-3:14]xxx\n"
-                + "[positions.ftl:4:1-4:24]{[positions.ftl:4:7-4:12] [positions.ftl:4:14-4:19]}\n"
-                + "-(p=5){-}-\n"
-                + "-(p=7){-}-"
-                );
-    }
-    
-    @SuppressWarnings("boxing")
-    @Override
-    protected Object createDataModel() {
-        Map<String, Object> dm = new HashMap<>();
-        dm.put("uc", new CachingUpperCaseDirective());
-        dm.put("lc", new CachingLowerCaseDirective());
-        dm.put("pa", new PositionAwareDirective());
-        dm.put("argP", new ArgPrinterDirective());
-        dm.put("curDirLine", new CurDirLineScalar());
-        dm.put("x", 123);
-        return dm;
-    }
-
-    private abstract static class CachingTextConverterDirective implements TemplateDirectiveModel {
-
-        /** Only needed for testing. */
-        private static AtomicInteger cacheRecreationCount = new AtomicInteger();
-        
-        /** Only needed for testing. */
-        static void resetCacheRecreationCount() {
-            cacheRecreationCount.set(0);
-        }
-        
-        @Override
-        public void execute(Environment env, Map params, TemplateModel[] loopVars, final TemplateDirectiveBody body)
-                throws TemplateException, IOException {
-            if (body == null) {
-                return;
-            }
-            
-            final String convertedText;
-
-            final DirectiveCallPlace callPlace = env.getCurrentDirectiveCallPlace();
-            if (callPlace.isNestedOutputCacheable()) {
-                try {
-                    convertedText = (String) callPlace.getOrCreateCustomData(
-                            getTextConversionIdentity(), new ObjectFactory<String>() {
-
-                                @Override
-                                public String createObject() throws TemplateException, IOException {
-                                    return convertBodyText(body)
-                                            + "[cached " + cacheRecreationCount.incrementAndGet() + "]";
-                                }
-
-                            });
-                } catch (CallPlaceCustomDataInitializationException e) {
-                    throw new TemplateModelException("Failed to pre-render nested content", e);
-                }
-            } else {
-                convertedText = convertBodyText(body);
-            }
-
-            env.getOut().write(convertedText);
-        }
-
-        protected abstract Class getTextConversionIdentity();
-
-        private String convertBodyText(TemplateDirectiveBody body) throws TemplateException,
-                IOException {
-            StringWriter sw = new StringWriter();
-            body.render(sw);
-            return convertText(sw.toString());
-        }
-        
-        protected abstract String convertText(String s);
-
-    }
-    
-    private static class CachingUpperCaseDirective extends CachingTextConverterDirective {
-
-        @Override
-        protected String convertText(String s) {
-            return s.toUpperCase();
-        }
-        
-        @Override
-        protected Class getTextConversionIdentity() {
-            return CachingUpperCaseDirective.class;
-        }
-        
-    }
-
-    private static class CachingLowerCaseDirective extends CachingTextConverterDirective {
-
-        @Override
-        protected String convertText(String s) {
-            return s.toLowerCase();
-        }
-
-        @Override
-        protected Class getTextConversionIdentity() {
-            return CachingLowerCaseDirective.class;
-        }
-        
-    }
-    
-    private static class PositionAwareDirective implements TemplateDirectiveModel {
-
-        @Override
-        public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
-                throws TemplateException, IOException {
-            Writer out = env.getOut();
-            DirectiveCallPlace callPlace = env.getCurrentDirectiveCallPlace();
-            out.write("[");
-            out.write(getTemplateSourceName(callPlace));
-            out.write(":");
-            out.write(Integer.toString(callPlace.getBeginLine()));
-            out.write(":");
-            out.write(Integer.toString(callPlace.getBeginColumn()));
-            out.write("-");
-            out.write(Integer.toString(callPlace.getEndLine()));
-            out.write(":");
-            out.write(Integer.toString(callPlace.getEndColumn()));
-            out.write("]");
-            if (body != null) {
-                body.render(out);
-            }
-        }
-
-        private String getTemplateSourceName(DirectiveCallPlace callPlace) {
-            return ((ASTDirUserDefined) callPlace).getTemplate().getSourceName();
-        }
-        
-    }
-
-    private static class ArgPrinterDirective implements TemplateDirectiveModel {
-
-        @Override
-        public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
-                throws TemplateException, IOException {
-            final Writer out = env.getOut();
-            if (params.size() > 0) {
-                out.write("(p=");
-                out.write(((TemplateScalarModel) params.get("p")).getAsString());
-                out.write(")");
-            }
-            if (body != null) {
-                out.write("{");
-                body.render(out);
-                out.write("}");
-            }
-        }
-        
-    }
-    
-    private static class CurDirLineScalar implements TemplateScalarModel {
-
-        @Override
-        public String getAsString() throws TemplateModelException {
-            DirectiveCallPlace callPlace = Environment.getCurrentEnvironment().getCurrentDirectiveCallPlace();
-            return callPlace != null
-                    ? String.valueOf(Environment.getCurrentEnvironment().getCurrentDirectiveCallPlace().getBeginLine())
-                    : "-";
-        }
-        
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/EncodingOverrideTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/EncodingOverrideTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/EncodingOverrideTest.java
deleted file mode 100644
index b1acead..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/EncodingOverrideTest.java
+++ /dev/null
@@ -1,62 +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;
-
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.io.StringWriter;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.util.Collections;
-
-import org.apache.freemarker.core.templateresolver.impl.ClassTemplateLoader;
-import org.junit.Test;
-
-public class EncodingOverrideTest {
-
-    @Test
-    public void testMarchingCharset() throws Exception {
-        Template t = createConfig(StandardCharsets.UTF_8).getTemplate("encodingOverride-UTF-8.ftl");
-        assertEquals(StandardCharsets.UTF_8, t.getActualSourceEncoding());
-        checkTemplateOutput(t);
-    }
-
-    @Test
-    public void testDifferentCharset() throws Exception {
-        Template t = createConfig(StandardCharsets.UTF_8).getTemplate("encodingOverride-ISO-8859-1.ftl");
-        assertEquals(StandardCharsets.ISO_8859_1, t.getActualSourceEncoding());
-        checkTemplateOutput(t);
-    }
-
-    private void checkTemplateOutput(Template t) throws TemplateException, IOException {
-        StringWriter out = new StringWriter(); 
-        t.process(Collections.emptyMap(), out);
-        assertEquals("Béka", out.toString());
-    }
-    
-    private Configuration createConfig(Charset charset) {
-       return new Configuration.Builder(Configuration.VERSION_3_0_0)
-               .templateLoader(new ClassTemplateLoader(EncodingOverrideTest.class, ""))
-               .sourceEncoding(charset)
-               .build();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/EnvironmentGetTemplateVariantsTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/EnvironmentGetTemplateVariantsTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/EnvironmentGetTemplateVariantsTest.java
deleted file mode 100644
index b79559c..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/EnvironmentGetTemplateVariantsTest.java
+++ /dev/null
@@ -1,214 +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;
-
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.io.Writer;
-import java.util.Collections;
-import java.util.Map;
-
-import org.apache.freemarker.core.model.TemplateDirectiveBody;
-import org.apache.freemarker.core.model.TemplateDirectiveModel;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.impl.SimpleScalar;
-import org.apache.freemarker.core.templateresolver.impl.StringTemplateLoader;
-import org.apache.freemarker.test.TemplateTest;
-import org.apache.freemarker.test.TestConfigurationBuilder;
-import org.junit.Test;
-
-public class EnvironmentGetTemplateVariantsTest extends TemplateTest {
-
-    private static final StringTemplateLoader TEMPLATES = new StringTemplateLoader();
-    static {
-        TEMPLATES.putTemplate("main",
-                "<@tNames />\n"
-                + "---1---\n"
-                + "[imp: <#import 'imp' as i>${i.impIni}]\n"
-                + "---2---\n"
-                + "<@i.impM>"
-                    + "<@tNames />"
-                + "</@>\n"
-                + "---3---\n"
-                + "[inc: <#include 'inc'>]\n"
-                + "---4---\n"
-                + "<@incM>"
-                    + "<@tNames />"
-                + "</@>\n"
-                + "---5---\n"
-                + "[inc2: <#include 'inc2'>]\n"
-                + "---6---\n"
-                + "<#import 'imp2' as i2>"
-                + "<@i.impM2><@tNames /></@>\n"
-                + "---7---\n"
-                + "<#macro mainM>"
-                    + "[mainM: <@tNames /> {<#nested>} <@tNames />]"
-                + "</#macro>"
-                + "[inc3: <#include 'inc3'>]\n"
-                + "<@mainM><@tNames /> <#include 'inc4'> <@tNames /></@>\n"
-                + "<@tNames />\n"
-                + "---8---\n"
-                + "<#function mainF>"
-                    + "<@tNames />"
-                    + "<#return lastTNamesResult>"
-                + "</#function>"
-                + "mainF: ${mainF()}, impF: ${i.impF()}, incF: ${incF()}\n"
-                );
-        TEMPLATES.putTemplate("inc",
-                "<@tNames />\n"
-                + "<#macro incM>"
-                    + "[incM: <@tNames /> {<#nested>}]"
-                + "</#macro>"
-                + "<#function incF>"
-                    + "<@tNames />"
-                    + "<#return lastTNamesResult>"
-                + "</#function>"
-                + "<@incM><@tNames /></@>\n"
-                + "<#if !included!false>[incInc: <#assign included=true><#include 'inc'>]\n</#if>"
-                );
-        TEMPLATES.putTemplate("imp",
-                "<#assign impIni><@tNames /></#assign>\n"
-                + "<#macro impM>"
-                    + "[impM: <@tNames />\n"
-                        + "{<#nested>}\n"
-                        + "[inc: <#include 'inc'>]\n"
-                        + "<@incM><@tNames /></@>\n"
-                    + "]"
-                + "</#macro>"
-                + "<#macro impM2>"
-                    + "[impM2: <@tNames />\n"
-                    + "{<#nested>}\n"
-                    + "<@i2.imp2M><@tNames /></@>\n"
-                    + "]"
-                + "</#macro>"
-                + "<#function impF>"
-                    + "<@tNames />"
-                    + "<#return lastTNamesResult>"
-                + "</#function>"
-                );
-        TEMPLATES.putTemplate("inc2",
-                "<@tNames />\n"
-                + "<@i.impM><@tNames /></@>\n"
-                );
-        TEMPLATES.putTemplate("imp2",
-                "<#macro imp2M>"
-                    + "[imp2M: <@tNames /> {<#nested>}]"
-                + "</#macro>");
-        TEMPLATES.putTemplate("inc3",
-                "<@tNames />\n"
-                + "<@mainM><@tNames /></@>\n"
-                );
-        TEMPLATES.putTemplate("inc4",
-                "<@tNames />"
-                );
-    }
-    
-    @Test
-    public void test() throws IOException, TemplateException {
-        setConfiguration(createConfiguration(Configuration.VERSION_3_0_0));
-        assertOutputForNamed(
-                "main",
-                "<ct=main mt=main>\n"
-                + "---1---\n"
-                + "[imp: <ct=imp mt=main>]\n"
-                + "---2---\n"
-                + "[impM: <ct=imp mt=main>\n"
-                    + "{<ct=main mt=main>}\n"
-                    + "[inc: <ct=inc mt=main>\n"
-                        + "[incM: <ct=inc mt=main> {<ct=inc mt=main>}]\n"
-                        + "[incInc: <ct=inc mt=main>\n"
-                            + "[incM: <ct=inc mt=main> {<ct=inc mt=main>}]\n"
-                        + "]\n"
-                    + "]\n"
-                    + "[incM: <ct=inc mt=main> {<ct=imp mt=main>}]\n"
-                + "]\n"
-                + "---3---\n"
-                + "[inc: <ct=inc mt=main>\n"
-                    + "[incM: <ct=inc mt=main> {<ct=inc mt=main>}]\n"
-                    + "[incInc: <ct=inc mt=main>\n"
-                        + "[incM: <ct=inc mt=main> {<ct=inc mt=main>}]\n"
-                    + "]\n"
-                + "]\n"
-                + "---4---\n"
-                + "[incM: <ct=inc mt=main> {<ct=main mt=main>}]\n"
-                + "---5---\n"
-                + "[inc2: <ct=inc2 mt=main>\n"
-                    + "[impM: <ct=imp mt=main>\n"
-                        + "{<ct=inc2 mt=main>}\n"
-                        + "[inc: <ct=inc mt=main>\n"
-                            + "[incM: <ct=inc mt=main> {<ct=inc mt=main>}]\n"
-                        + "]\n"
-                        + "[incM: <ct=inc mt=main> {<ct=imp mt=main>}]\n"
-                    + "]\n"
-                + "]\n"
-                + "---6---\n"
-                + "[impM2: <ct=imp mt=main>\n"
-                    + "{<ct=main mt=main>}\n"
-                    + "[imp2M: <ct=imp2 mt=main> {<ct=imp mt=main>}]\n"
-                + "]\n"
-                + "---7---\n"
-                + "[inc3: <ct=inc3 mt=main>\n"
-                    + "[mainM: <ct=main mt=main> {<ct=inc3 mt=main>} <ct=main mt=main>]\n"
-                + "]\n"
-                + "[mainM: "
-                    + "<ct=main mt=main> "
-                    + "{<ct=main mt=main> <ct=inc4 mt=main> <ct=main mt=main>} "
-                    + "<ct=main mt=main>"
-                + "]\n"
-                + "<ct=main mt=main>\n"
-                + "---8---\n"
-                + "mainF: <ct=main mt=main>, impF: <ct=imp mt=main>, incF: <ct=inc mt=main>\n"
-                .replaceAll("<t=\\w+", "<t=main"));
-    }
-
-    @Test
-    public void testNotStarted() throws IOException, TemplateException {
-        Template t = new Template("foo", "", createConfiguration(Configuration.VERSION_3_0_0));
-        final Environment env = t.createProcessingEnvironment(null, null);
-        assertSame(t, env.getMainTemplate());
-        assertSame(t, env.getCurrentTemplate());
-    }
-    
-    private Configuration createConfiguration(Version iciVersion) {
-        return new TestConfigurationBuilder(iciVersion)
-                .templateLoader(TEMPLATES)
-                .whitespaceStripping(false)
-                .build();
-    }
-
-    @Override
-    protected Object createDataModel() {
-        return Collections.singletonMap("tNames", new TemplateDirectiveModel() {
-
-            @Override
-            public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
-                    throws TemplateException, IOException {
-                Writer out = env.getOut();
-                final String r = "<ct=" + env.getCurrentTemplate().getLookupName() + " mt="
-                        + env.getMainTemplate().getLookupName() + ">";
-                out.write(r);
-                env.setGlobalVariable("lastTNamesResult", new SimpleScalar(r));
-            }
-            
-        });
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/ExceptionTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/ExceptionTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/ExceptionTest.java
deleted file mode 100644
index 19c3b6e..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/ExceptionTest.java
+++ /dev/null
@@ -1,115 +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;
-
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.util.Collections;
-import java.util.Locale;
-
-import org.apache.freemarker.core.templateresolver.impl.StringTemplateLoader;
-import org.apache.freemarker.core.util._NullWriter;
-import org.apache.freemarker.test.TestConfigurationBuilder;
-
-import junit.framework.TestCase;
-public class ExceptionTest extends TestCase {
-    
-    public ExceptionTest(String name) {
-        super(name);
-    }
-
-    public void testParseExceptionSerializable() throws IOException, ClassNotFoundException {
-        try {
-            new Template(null, new StringReader("<@>"), new TestConfigurationBuilder().build());
-            fail();
-        } catch (ParseException e) {
-            ByteArrayOutputStream out = new ByteArrayOutputStream();
-            new ObjectOutputStream(out).writeObject(e);
-            new ObjectInputStream(new ByteArrayInputStream(out.toByteArray())).readObject();
-        }
-    }
-
-    public void testTemplateErrorSerializable() throws IOException, ClassNotFoundException {
-        Template tmp = new Template(null, new StringReader("${noSuchVar}"),
-                new TestConfigurationBuilder().build());
-        try {
-            tmp.process(Collections.EMPTY_MAP, new StringWriter());
-            fail();
-        } catch (TemplateException e) {
-            ByteArrayOutputStream out = new ByteArrayOutputStream();
-            new ObjectOutputStream(out).writeObject(e);
-            new ObjectInputStream(new ByteArrayInputStream(out.toByteArray())).readObject();
-        }
-    }
-    
-    @SuppressWarnings("boxing")
-    public void testTemplateExceptionLocationInformation() throws IOException {
-        StringTemplateLoader tl = new StringTemplateLoader();
-        tl.putTemplate("foo_en.ftl", "\n\nxxx${noSuchVariable}");
-
-        Template t = new TestConfigurationBuilder().templateLoader(tl).build()
-                .getTemplate("foo.ftl", Locale.US);
-        try {
-            t.process(null, _NullWriter.INSTANCE);
-            fail();
-        } catch (TemplateException e) {
-            assertEquals("foo.ftl", t.getLookupName());
-            assertEquals("foo.ftl", e.getTemplateLookupName());
-            assertEquals("foo_en.ftl", e.getTemplateSourceName());
-            assertEquals(3, (int) e.getLineNumber());
-            assertEquals(6, (int) e.getColumnNumber());
-            assertEquals(3, (int) e.getEndLineNumber());
-            assertEquals(19, (int) e.getEndColumnNumber());
-            assertThat(e.getMessage(), containsString("foo_en.ftl"));
-            assertThat(e.getMessage(), containsString("noSuchVariable"));
-        }
-    }
-
-    @SuppressWarnings("cast")
-    public void testParseExceptionLocationInformation() throws IOException {
-        StringTemplateLoader tl = new StringTemplateLoader();
-        tl.putTemplate("foo_en.ftl", "\n\nxxx<#noSuchDirective>");
-
-        try {
-            new TestConfigurationBuilder().templateLoader(tl).build()
-                    .getTemplate("foo.ftl", Locale.US);
-            fail();
-        } catch (ParseException e) {
-            System.out.println(e.getMessage());
-            assertEquals("foo_en.ftl", e.getTemplateSourceName());
-            assertEquals("foo.ftl", e.getTemplateLookupName());
-            assertEquals(3, e.getLineNumber());
-            assertEquals(5, e.getColumnNumber());
-            assertEquals(3, e.getEndLineNumber());
-            assertEquals(20, e.getEndColumnNumber());
-            assertThat(e.getMessage(), containsString("foo_en.ftl"));
-            assertThat(e.getMessage(), containsString("noSuchDirective"));
-        }
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/GetSourceTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/GetSourceTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/GetSourceTest.java
deleted file mode 100644
index 1462bfc..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/GetSourceTest.java
+++ /dev/null
@@ -1,52 +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;
-
-import static org.junit.Assert.*;
-
-import org.apache.freemarker.test.TestConfigurationBuilder;
-import org.junit.Test;
-
-public class GetSourceTest {
-
-    @Test
-    public void testGetSource() throws Exception {
-        {
-            // Note: Default tab size is 8.
-            Template t = new Template(null, "a\n\tb\nc",
-                    new TestConfigurationBuilder().build());
-            // A historical quirk we keep for B.C.: it repaces tabs with spaces.
-            assertEquals("a\n        b\nc", t.getSource(1, 1, 1, 3));
-        }
-        
-        {
-            Template t = new Template(null, "a\n\tb\nc",
-                    new TestConfigurationBuilder().tabSize(4).build());
-            assertEquals("a\n    b\nc", t.getSource(1, 1, 1, 3));
-        }
-        
-        {
-            Template t = new Template(null, "a\n\tb\nc",
-                    new TestConfigurationBuilder().tabSize(1).build());
-            // If tab size is 1, it behaves as it always should have: it keeps the tab.
-            assertEquals("a\n\tb\nc", t.getSource(1, 1, 1, 3));
-        }
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/HeaderParsingTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/HeaderParsingTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/HeaderParsingTest.java
deleted file mode 100644
index 6f8851d..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/HeaderParsingTest.java
+++ /dev/null
@@ -1,60 +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;
-
-import java.io.IOException;
-
-import org.apache.freemarker.test.TemplateTest;
-import org.apache.freemarker.test.TestConfigurationBuilder;
-import org.junit.Test;
-
-public class HeaderParsingTest extends TemplateTest {
-
-    private final Configuration cfgStripWS = new TestConfigurationBuilder().build();
-    private final Configuration cfgNoStripWS = new TestConfigurationBuilder().whitespaceStripping(false).build();
-
-    @Test
-    public void test() throws IOException, TemplateException {
-        assertOutput("<#ftl>text", "text", "text");
-        assertOutput(" <#ftl> text", " text", " text");
-        assertOutput("\n<#ftl>\ntext", "text", "text");
-        assertOutput("\n \n\n<#ftl> \ntext", "text", "text");
-        assertOutput("\n \n\n<#ftl>\n\ntext", "\ntext", "\ntext");
-    }
-    
-    private void assertOutput(final String ftl, String expectedOutStripped, String expectedOutNonStripped)
-            throws IOException, TemplateException {
-        for (int i = 0; i < 4; i++) {
-            String ftlPermutation = ftl;
-            if ((i & 1) == 1) {
-                ftlPermutation = ftlPermutation.replace("<#ftl>", "<#ftl encoding='utf-8'>");
-            }
-            if ((i & 2) == 2) {
-                ftlPermutation = ftlPermutation.replace('<', '[').replace('>', ']');
-            }
-            
-            setConfiguration(cfgStripWS);
-            assertOutput(ftlPermutation, expectedOutStripped);
-            setConfiguration(cfgNoStripWS);
-            assertOutput(ftlPermutation, expectedOutNonStripped);
-        }
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/IncludeAndImportConfigurableLayersTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/IncludeAndImportConfigurableLayersTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/IncludeAndImportConfigurableLayersTest.java
deleted file mode 100644
index 738b4de..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/IncludeAndImportConfigurableLayersTest.java
+++ /dev/null
@@ -1,354 +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;
-
-import static org.junit.Assert.*;
-
-import java.io.StringWriter;
-
-import org.apache.freemarker.core.templateresolver.ConditionalTemplateConfigurationFactory;
-import org.apache.freemarker.core.templateresolver.FileNameGlobMatcher;
-import org.apache.freemarker.core.templateresolver.impl.StringTemplateLoader;
-import org.apache.freemarker.test.TestConfigurationBuilder;
-import org.junit.Test;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-
-public class IncludeAndImportConfigurableLayersTest {
-
-    @Test
-    public void test3LayerImportNoClashes() throws Exception {
-        TestConfigurationBuilder cfgB = createConfigurationBuilder()
-                .autoImports(ImmutableMap.of("t1", "t1.ftl"))
-                .templateConfigurations(
-                        new ConditionalTemplateConfigurationFactory(
-                                new FileNameGlobMatcher("main.ftl"),
-                                new TemplateConfiguration.Builder()
-                                        .autoImports(ImmutableMap.of("t2", "t2.ftl"))
-                                        .build()));
-        Configuration cfg = cfgB.build();
-
-        {
-            Template t = cfg.getTemplate("main.ftl");
-            StringWriter sw = new StringWriter();
-            Environment env = t.createProcessingEnvironment(null, sw);
-            env.addAutoImport("t3", "t3.ftl");
-    
-            env.process();
-            assertEquals("In main: t1;t2;t3;", sw.toString());
-        }
-
-        {
-            Template t = cfg.getTemplate("main.ftl");
-            StringWriter sw = new StringWriter();
-            Environment env = t.createProcessingEnvironment(null, sw);
-    
-            env.process();
-            assertEquals("In main: t1;t2;", sw.toString());
-        }
-        
-        {
-            Template t = cfg.getTemplate("main2.ftl");
-            StringWriter sw = new StringWriter();
-            Environment env = t.createProcessingEnvironment(null, sw);
-            env.addAutoImport("t3", "t3.ftl");
-    
-            env.process();
-            assertEquals("In main2: t1;t3;", sw.toString());
-        }
-        
-        cfgB.removeAutoImport("t1");
-        cfg = cfgB.build();
-
-        {
-            Template t = cfg.getTemplate("main.ftl");
-            StringWriter sw = new StringWriter();
-            Environment env = t.createProcessingEnvironment(null, sw);
-            env.addAutoImport("t3", "t3.ftl");
-    
-            env.process();
-            assertEquals("In main: t2;t3;", sw.toString());
-        }
-    }
-    
-    @Test
-    public void test3LayerImportClashes() throws Exception {
-        Configuration cfg = createConfigurationBuilder()
-                .autoImports(ImmutableMap.of(
-                        "t1", "t1.ftl",
-                        "t2", "t2.ftl",
-                        "t3", "t3.ftl"))
-                .templateConfigurations(
-                        new ConditionalTemplateConfigurationFactory(
-                                new FileNameGlobMatcher("main.ftl"),
-                                new TemplateConfiguration.Builder()
-                                        .autoImports(ImmutableMap.of("t2", "t2b.ftl"))
-                                        .build()))
-                .build();
-
-        {
-            Template t = cfg.getTemplate("main.ftl");
-            StringWriter sw = new StringWriter();
-            Environment env = t.createProcessingEnvironment(null, sw);
-            env.addAutoImport("t3", "t3b.ftl");
-    
-            env.process();
-            assertEquals("In main: t1;t2b;t3b;", sw.toString());
-        }
-        
-        {
-            Template t = cfg.getTemplate("main2.ftl");
-            StringWriter sw = new StringWriter();
-            Environment env = t.createProcessingEnvironment(null, sw);
-            env.addAutoImport("t3", "t3b.ftl");
-    
-            env.process();
-            assertEquals("In main2: t1;t2;t3b;", sw.toString());
-        }
-        
-        {
-            Template t = cfg.getTemplate("main.ftl");
-            StringWriter sw = new StringWriter();
-            Environment env = t.createProcessingEnvironment(null, sw);
-    
-            env.process();
-            assertEquals("In main: t1;t3;t2b;", sw.toString());
-        }
-    }
-
-    @Test
-    public void test3LayerIncludesNoClashes() throws Exception {
-        TestConfigurationBuilder cfgB = createConfigurationBuilder()
-                .autoIncludes(ImmutableList.of("t1.ftl"))
-                .templateConfigurations(
-                        new ConditionalTemplateConfigurationFactory(
-                                new FileNameGlobMatcher("main.ftl"),
-                                new TemplateConfiguration.Builder()
-                                        .autoIncludes(ImmutableList.of("t2.ftl"))
-                                        .build()));
-
-        Configuration cfg = cfgB.build();
-
-        {
-            Template t = cfg.getTemplate("main.ftl");
-            StringWriter sw = new StringWriter();
-            Environment env = t.createProcessingEnvironment(null, sw);
-            env.addAutoInclude("t3.ftl");
-    
-            env.process();
-            assertEquals("T1;T2;T3;In main: t1;t2;t3;", sw.toString());
-        }
-
-        {
-            Template t = cfg.getTemplate("main.ftl");
-            StringWriter sw = new StringWriter();
-            Environment env = t.createProcessingEnvironment(null, sw);
-    
-            env.process();
-            assertEquals("T1;T2;In main: t1;t2;", sw.toString());
-        }
-        
-        {
-            Template t = cfg.getTemplate("main2.ftl");
-            StringWriter sw = new StringWriter();
-            Environment env = t.createProcessingEnvironment(null, sw);
-            env.addAutoInclude("t3.ftl");
-    
-            env.process();
-            assertEquals("T1;T3;In main2: t1;t3;", sw.toString());
-        }
-        
-        cfgB.removeAutoInclude("t1.ftl");
-        cfg = cfgB.build();
-
-        {
-            Template t = cfg.getTemplate("main.ftl");
-            StringWriter sw = new StringWriter();
-            Environment env = t.createProcessingEnvironment(null, sw);
-            env.addAutoInclude("t3.ftl");
-    
-            env.process();
-            assertEquals("T2;T3;In main: t2;t3;", sw.toString());
-        }
-    }
-
-    @Test
-    public void test3LayerIncludeClashes() throws Exception {
-        Configuration cfg = createConfigurationBuilder()
-                .autoIncludes(ImmutableList.of(
-                        "t1.ftl",
-                        "t2.ftl",
-                        "t3.ftl"))
-                .templateConfigurations(new ConditionalTemplateConfigurationFactory(
-                        new FileNameGlobMatcher("main.ftl"),
-                        new TemplateConfiguration.Builder()
-                                .autoIncludes(ImmutableList.of("t2.ftl"))
-                                .build()))
-                .build();
-
-        {
-            Template t = cfg.getTemplate("main.ftl");
-            StringWriter sw = new StringWriter();
-            Environment env = t.createProcessingEnvironment(null, sw);
-            env.addAutoInclude("t3.ftl");
-    
-            env.process();
-            assertEquals("T1;T2;T3;In main: t1;t2;t3;", sw.toString());
-        }
-        
-        {
-            Template t = cfg.getTemplate("main2.ftl");
-            StringWriter sw = new StringWriter();
-            Environment env = t.createProcessingEnvironment(null, sw);
-            env.addAutoInclude("t3.ftl");
-    
-            env.process();
-            assertEquals("T1;T2;T3;In main2: t1;t2;t3;", sw.toString());
-        }
-        
-        {
-            Template t = cfg.getTemplate("main.ftl");
-            StringWriter sw = new StringWriter();
-            Environment env = t.createProcessingEnvironment(null, sw);
-    
-            env.process();
-            assertEquals("T1;T3;T2;In main: t1;t3;t2;", sw.toString());
-        }
-        
-        {
-            Template t = cfg.getTemplate("main.ftl");
-            StringWriter sw = new StringWriter();
-            Environment env = t.createProcessingEnvironment(null, sw);
-            env.addAutoInclude("t1.ftl");
-    
-            env.process();
-            assertEquals("T3;T2;T1;In main: t3;t2;t1;", sw.toString());
-        }
-    }
-    
-    @Test
-    public void test3LayerIncludesClashes2() throws Exception {
-        Configuration cfg = createConfigurationBuilder()
-                .autoIncludes(ImmutableList.of("t1.ftl", "t1.ftl"))
-                .templateConfigurations(
-                        new ConditionalTemplateConfigurationFactory(
-                                new FileNameGlobMatcher("main.ftl"),
-                                new TemplateConfiguration.Builder()
-                                        .autoIncludes(ImmutableList.of("t2.ftl", "t2.ftl"))
-                                        .build()))
-                .build();
-
-        {
-            Template t = cfg.getTemplate("main.ftl");
-            StringWriter sw = new StringWriter();
-            Environment env = t.createProcessingEnvironment(null, sw);
-            env.addAutoInclude("t3.ftl");
-            env.addAutoInclude("t3.ftl");
-            env.addAutoInclude("t1.ftl");
-            env.addAutoInclude("t1.ftl");
-    
-            env.process();
-            assertEquals("T2;T3;T1;In main: t2;t3;t1;", sw.toString());
-        }
-    }
-    
-    @Test
-    public void test3LayerLaziness() throws Exception {
-        for (Class<?> layer : new Class<?>[] { Configuration.class, Template.class, Environment.class }) {
-            test3LayerLaziness(layer, null, null, false, "t1;t2;");
-            test3LayerLaziness(layer, null, null, true, "t1;t2;");
-            test3LayerLaziness(layer, null, false, true, "t1;t2;");
-            test3LayerLaziness(layer, null, true, true, "t2;");
-            
-            test3LayerLaziness(layer, false, null, false, "t1;t2;");
-            test3LayerLaziness(layer, false, null, true, "t1;t2;");
-            test3LayerLaziness(layer, false, false, true, "t1;t2;");
-            test3LayerLaziness(layer, false, true, true, "t2;");
-
-            test3LayerLaziness(layer, true, null, false, "");
-            test3LayerLaziness(layer, true, null, true, "");
-            test3LayerLaziness(layer, true, false, true, "t1;");
-            test3LayerLaziness(layer, true, true, true, "");
-        }
-    }
-    
-    private void test3LayerLaziness(
-            Class<?> layer,
-            Boolean lazyImports,
-            Boolean lazyAutoImports, boolean setLazyAutoImports,
-            String expectedOutput)
-            throws Exception {
-        Configuration cfg;
-        {
-            TestConfigurationBuilder cfgB = createConfigurationBuilder()
-                    .autoImports(ImmutableMap.of("t1", "t1.ftl"));
-            if (layer == Configuration.class) {
-                setLazinessOfConfigurable(cfgB, lazyImports, lazyAutoImports, setLazyAutoImports);
-            }
-            cfg = cfgB.build();
-        }
-
-        TemplateConfiguration tc;
-        if (layer == Template.class) {
-            TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
-            setLazinessOfConfigurable(tcb, lazyImports, lazyAutoImports, setLazyAutoImports);
-            tc = tcb.build();
-        } else {
-            tc = null;
-        }
-
-        Template t = new Template(null, "<#import 't2.ftl' as t2>${loaded!}", cfg, tc);
-        StringWriter sw = new StringWriter();
-
-        Environment env = t.createProcessingEnvironment(null, sw);
-        if (layer == Environment.class) {
-            setLazinessOfConfigurable(env, lazyImports, lazyAutoImports, setLazyAutoImports);
-        }
-
-        env.process();
-        assertEquals(expectedOutput, sw.toString());
-    }
-
-    private void setLazinessOfConfigurable(
-            MutableProcessingConfiguration<?> cfg,
-            Boolean lazyImports, Boolean lazyAutoImports, boolean setLazyAutoImports) {
-        if (lazyImports != null) {
-            cfg.setLazyImports(lazyImports);
-        }
-        if (setLazyAutoImports) {
-            cfg.setLazyAutoImports(lazyAutoImports);
-        }
-    }
-    
-    private TestConfigurationBuilder createConfigurationBuilder() {
-        StringTemplateLoader loader = new StringTemplateLoader();
-        loader.putTemplate("main.ftl", "In main: ${loaded}");
-        loader.putTemplate("main2.ftl", "In main2: ${loaded}");
-        loader.putTemplate("t1.ftl", "<#global loaded = (loaded!) + 't1;'>T1;");
-        loader.putTemplate("t2.ftl", "<#global loaded = (loaded!) + 't2;'>T2;");
-        loader.putTemplate("t3.ftl", "<#global loaded = (loaded!) + 't3;'>T3;");
-        loader.putTemplate("t1b.ftl", "<#global loaded = (loaded!) + 't1b;'>T1b;");
-        loader.putTemplate("t2b.ftl", "<#global loaded = (loaded!) + 't2b;'>T2b;");
-        loader.putTemplate("t3b.ftl", "<#global loaded = (loaded!) + 't3b;'>T3b;");
-
-        return new TestConfigurationBuilder().templateLoader(loader);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/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
deleted file mode 100644
index fa767ff..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/IncludeAndImportTest.java
+++ /dev/null
@@ -1,270 +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;
-
-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/28a276c8/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
deleted file mode 100644
index f4908b8..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/IncudeFromNamelessTest.java
+++ /dev/null
@@ -1,58 +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;
-
-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());
-    }
-
-}


[30/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/servlet/web.xml
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/servlet/web.xml b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/servlet/web.xml
new file mode 100644
index 0000000..e406b1a
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/servlet/web.xml
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!--
+  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.
+-->
+
+<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
+	version="2.4">
+
+	<servlet>
+		<servlet-name>controller</servlet-name>
+		<servlet-class>com.example.Model2ControllerServlet</servlet-class>
+	</servlet>
+
+	<servlet-mapping>
+		<servlet-name>controller</servlet-name>
+		<url-pattern>*.c</url-pattern>
+    </servlet-mapping>
+    <servlet-mapping>
+        <servlet-name>controller</servlet-name>
+        <url-pattern>/</url-pattern>
+	</servlet-mapping>
+
+	<servlet>
+		<servlet-name>freemarker</servlet-name>
+		<servlet-class>org.apache.freemarker.servlet.FreemarkerServlet</servlet-class>
+
+		<!-- FreemarkerServlet settings: -->
+		<init-param>
+			<param-name>TemplatePath</param-name>
+			<param-value>/</param-value>
+		</init-param>
+		<init-param>
+			<param-name>NoCache</param-name>
+			<param-value>true</param-value>
+		</init-param>
+		<init-param>
+			<param-name>ContentType</param-name>
+			<param-value>text/html; charset=UTF-8</param-value> <!-- Forces UTF-8 output encoding! -->
+		</init-param>
+
+		<!-- FreeMarker settings: -->
+		<init-param>
+			<param-name>incompatible_improvements</param-name>
+			<param-value>3.0.0</param-value>
+		</init-param>
+		<init-param>
+			<param-name>template_exception_handler</param-name>
+			<!-- Some may prefer "html_debug" for development. -->
+			<param-value>rethrow</param-value>
+		</init-param>
+		<init-param>
+			<param-name>template_update_delay</param-name>
+			<param-value>0</param-value> <!-- 0 is for development only! Use higher value otherwise. -->
+		</init-param>
+		<init-param>
+			<param-name>sourceEncoding</param-name>
+			<param-value>UTF-8</param-value> <!-- The encoding of the template files. -->
+		</init-param>
+		<init-param>
+			<param-name>number_format</param-name>
+			<param-value>0.##########</param-value>
+		</init-param>
+
+		<load-on-startup>1</load-on-startup>
+	</servlet>
+
+	<servlet-mapping>
+		<servlet-name>freemarker</servlet-name>
+		<url-pattern>*.ftl</url-pattern>
+	</servlet-mapping>
+
+	<!-- Prevent the visiting of MVC Views from outside the servlet container. 
+		RequestDispatcher.forward/include should and will still work. Removing this 
+		may open security holes! -->
+	<security-constraint>
+		<web-resource-collection>
+			<web-resource-name>FreeMarker MVC Views</web-resource-name>
+			<url-pattern>*.ftl</url-pattern>
+		</web-resource-collection>
+		<auth-constraint>
+			<!-- Nobody is allowed to visit these -->
+		</auth-constraint>
+	</security-constraint>
+
+</web-app>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/arithmetic.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/arithmetic.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/arithmetic.txt
new file mode 100644
index 0000000..33a7186
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/arithmetic.txt
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+<html>
+<head>
+<title>FreeMarker: Arithmetic Test</title>
+</head>
+<body>
+
+<p>A simple test follows:</p>
+
+<p>Perform a number assignment:</p>
+
+
+3.234
+2.00
+0.6172500000000000000000000000000000000000
+1.620089104901
+1.6201
+
+<P>Display a number with at least 3 digits after the decimal point</P>
+
+1234.000
+
+<p>Now use numbers in assignment</p>
+
+
+1257.77
+
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/boolean-formatting.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/boolean-formatting.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/boolean-formatting.txt
new file mode 100644
index 0000000..0bab0bc
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/boolean-formatting.txt
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+Y Y Y
+N N N
+y y y
+n n n
+y y y
+n n n
+str:n str:n
+nein ja
+theStringValue theStringValue
+
+
+
+

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/boolean.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/boolean.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/boolean.txt
new file mode 100644
index 0000000..8dc1290
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/boolean.txt
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+<html>
+<head>
+<title>FreeMarker: Boolean Values Test</title>
+</head>
+<body>
+
+<p>A simple test follows:</p>
+
+<p>Hello, world!</p>
+
+
+<p>Now perform scalar boolean tests:</p>
+
+<p>
+    b is true.<br />
+</p>
+
+<p>    This makes sense.<br />
+</p>
+
+<p>
+    boolean3 succeeded.<br />
+</p>
+
+<p>
+    boolean4 succeeded.<br />
+</p>
+
+<p>
+    boolean4 || boolean5 succeeded.<br />
+</p>
+
+<p>
+    boolean5 || boolean4 || boolean5 succeeded.<br />
+</p>
+
+<p>    boolean4 && boolean5 failed.<br />
+</p>
+ 
+<p>Now test list models:</p>
+
+<p>
+    list1 succeeded.<br />
+</p>
+
+<p>
+    list2 succeeded.<br />
+</p>
+
+<p>Test hash models:</p>
+
+<p>
+    hash1 succeeded: Hello, world.<br />
+</p>
+
+<p>
+    hash2 succeeded.<br />
+</p>
+
+<p>Test not operator:</p>
+
+<p>
+   Not boolean1 succeeded
+</p>
+
+<p>
+   Not boolean1 succeeded
+</p>
+
+<p>   Not boolean2 failed
+</p>
+
+<p>   Not boolean2 failed
+</p>
+
+<p>
+   Message is "Hello, world!"
+</p>
+
+<p>   Message is "Hello, world!"
+</p>
+
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/charset-in-header.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/charset-in-header.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/charset-in-header.txt
new file mode 100644
index 0000000..4532027
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/charset-in-header.txt
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+<head>
+  <meta http-equiv="Content-type" content="text/html; charset=UTF-8">
+</head>
+<body>
+éáőű
+õÕûÛ
+őŐűŰ
+</body>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/comment.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/comment.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/comment.txt
new file mode 100644
index 0000000..d5902e3
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/comment.txt
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+<html>
+<head>
+<title>FreeMarker: Comment Test</title>
+</head>
+<body>
+	<p>Message exists!
+	</p>
+
+a  b
+a  b
+
+6
+7
+8
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/comparisons.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/comparisons.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/comparisons.txt
new file mode 100644
index 0000000..8d9d372
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/comparisons.txt
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+<html>
+<head>
+<title>FreeMarker: Numeric Operations Test</title>
+</head>
+<body>
+
+<p>A simple test follows:</p>
+
+<p>Hello, world!</p>
+
+<p>Start with the increment operator:</p>
+<p>a1 = 0</p>
+<p>a1 = 1</p>
+<p>a1 = 2</p>
+
+<p>Now the decrement operator:</p>
+<p>a2 = 5</p>
+<p>a2 = 4</p>
+<p>a2 = 3</p>
+<p>a2 = 2</p>
+<p>a2 = 1</p>
+<p>a2 = 0</p>
+<p>a2 = -1</p>
+
+<p>Now the add operator:</p>
+<p>op1 = 5, op2 = 3, op3 = 8</p>
+<p>op3 = 11</p>
+
+<p>And the subtract operator:</p>
+<p>op1 = 5, op2 = 3, op3 = 2</p>
+<p>op3 = -1</p>
+
+<p>The comparison operators:</p>
+   <p>Item is: 0</p>
+   <p>Item is less than five.</p>
+   <p>Item is less than or equals to seven.</p>
+   <p>Item is: 1</p>
+   <p>Item is less than five.</p>
+   <p>Item is less than or equals to seven.</p>
+   <p>Item is: 2</p>
+   <p>Item is less than five.</p>
+   <p>Item is less than or equals to seven.</p>
+   <p>Item is: 3</p>
+   <p>Item is less than five.</p>
+   <p>Item is less than or equals to seven.</p>
+   <p>Item is greater than two.</p>
+   <p>Item is: 4</p>
+   <p>Item is less than five.</p>
+   <p>Item is less than or equals to seven.</p>
+   <p>Item is greater than two.</p>
+   <p>Item is: 5</p>
+   <p>Item is less than or equals to seven.</p>
+   <p>Item is greater than two.</p>
+   <p>Item is: 6</p>
+   <p>Item is less than or equals to seven.</p>
+   <p>Item is greater than two.</p>
+   <p>Item is: 7</p>
+   <p>Item is less than or equals to seven.</p>
+   <p>Item is greater than two.</p>
+   <p>Item is: 8</p>
+   <p>Item is greater than two.</p>
+   <p>Item is: 9</p>
+   <p>Item is greater than two.</p>
+   <p>Item is: 10</p>
+   <p>Item is greater than two.</p>
+   <p>Item is greater than or equal to ten.</p>
+   <p>Item is: 11</p>
+   <p>Item is greater than two.</p>
+   <p>Item is greater than or equal to ten.</p>
+   <p>Item is: 12</p>
+   <p>Item is greater than two.</p>
+   <p>Item is greater than or equal to ten.</p>
+
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/compress.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/compress.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/compress.txt
new file mode 100644
index 0000000..43c7eed
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/compress.txt
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+<html>
+<head>
+<title>FreeMarker: Compress Test</title>
+</head>
+<body>
+
+<p>A simple test follows:</p>
+
+<p>Hello, world!</p>
+
+<p>This is the same message, using the &quot;compress&quot; tag:</p>
+<p>Hello, world!</p>
+<p>This is the same message, using the &quot;StandardCompress&quot; transform model:</p>
+<p>Hello, world!</p>
+<p>This multi-line message should be compressed to a single line.</p>
+
+<p>An example where the first character is not whitespace but the second character is:</p>
+<p>x y</p>
+
+<p>The end.</p>
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/dateformat-java.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/dateformat-java.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/dateformat-java.txt
new file mode 100644
index 0000000..9180262
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/dateformat-java.txt
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+Nov 15, 2002 2:54:13 PM
+Nov 15, 2002 2:54:13 PM
+Nov 15, 2002 2:54:13 PM
+Nov 15, 2002 2:54:13 PM
+11/15/02 2:54 PM
+Nov 15, 2002 2:54:13 PM
+November 15, 2002 2:54:13 PM GMT
+11/15/02 2:54 PM
+11/15/02 2:54:13 PM
+11/15/02 2:54:13 PM GMT
+Nov 15, 2002 2:54 PM
+Nov 15, 2002 2:54:13 PM
+Nov 15, 2002 2:54:13 PM GMT
+November 15, 2002 2:54 PM
+November 15, 2002 2:54:13 PM
+November 15, 2002 2:54:13 PM GMT
+Nov 15, 2002
+Nov 15, 2002
+11/15/02
+Nov 15, 2002
+November 15, 2002
+2:54:13 PM
+2:54:13 PM
+2:54 PM
+2:54:13 PM
+2:54:13 PM GMT
+2002. november 15. 14:54:13 GMT
+Fri, 15 Nov 02002 14:54:13 GMT
+Fri, 15 Nov 2002 14:54:13 GMT
+Fri, 15 Nov 2002 14:54:13 GMT
+2002
+
+2002
+2002
+
+2002
+11
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/default-object-wrapper.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/default-object-wrapper.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/default-object-wrapper.txt
new file mode 100644
index 0000000..e015315
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/default-object-wrapper.txt
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+array-0
+array-1
+2
+array-0
+array-1
+list-0
+list-1
+list-2
+3
+not empty
+list-0
+value
+objValue
+foo-value
+hasfoo
+nobaz
+bar-value-0
+foo-value
+overloaded-int-1
+overloaded-String-String
+Message
+1974-11-14
+static-method
+static-overloaded-int-1
+static-overloaded-String-String
+static-final-field
+static-field
+ONEx
+TWOx
+THREEx
+true
+false
+false
+42
+1
+m
+

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/default-xmlns.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/default-xmlns.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/default-xmlns.txt
new file mode 100644
index 0000000..3a52c46
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/default-xmlns.txt
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+No NS = No NS
+x NS = x NS
+y NS = y NS
+x NS = x NS
+
+true
+

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/default.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/default.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/default.txt
new file mode 100644
index 0000000..fd48463
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/default.txt
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+foo
+
+luck
+
+
+0
+
+   UNDEFINED is undefined.

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/encoding-builtins.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/encoding-builtins.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/encoding-builtins.txt
new file mode 100644
index 0000000..ccfe5c8
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/encoding-builtins.txt
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+FreeMarker: Encoding built-in tests
+
+html: [&amp;&lt;&gt;&quot;&#39;{}\a/]
+xml:  [&amp;&lt;&gt;&quot;&apos;{}\a/]
+xhtml: [&amp;&lt;&gt;&quot;&#39;{}\a/]
+rtf:  [&<>"'\{\}\\a/]
+html: [a&amp;a&lt;a&gt;a&quot;a&#39;a{a}a\]
+xml:  [a&amp;a&lt;a&gt;a&quot;a&apos;a{a}a\]
+xhtml: [a&amp;a&lt;a&gt;a&quot;a&#39;a{a}a\]
+rtf:  [a&a<a>a"a'a\{a\}a\\]
+html: [&lt;&lt;&lt;&lt;&lt;]
+xml:  [&lt;&lt;&lt;&lt;&lt;]
+xhtml: [&lt;&lt;&lt;&lt;&lt;]
+rtf:  [\{\{\{\{\{]
+html: []
+xml:  []
+xhtml: []
+rtf:  []
+html: [a]
+xml:  [a]
+xhtml: [a]
+rtf:  [a]
+html: [&amp;]
+xml:  [&amp;]
+xhtml: [&amp;]
+rtf:  [\{]
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/escapes.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/escapes.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/escapes.txt
new file mode 100644
index 0000000..c0a5440
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/escapes.txt
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+a
+b
+c
+a
+b
+c
+a
+1
+a
+b
+c
+&lt;&amp;&gt;
+&amp;lt;&amp;amp;&amp;gt;
+&lt;&amp;&gt;
+---
+<Mooo> = <Mooo>
+  <MOOO> = <MOOO>
+    &LT;MOOO&GT; = &lt;MOOO&gt;
+      <MOOO> = <MOOO>
+    &LT;MOOO&GT; = &lt;MOOO&gt;
+  <MOOO> = <MOOO>
+    <Mooo> = <Mooo>
+      &lt;Mooo&gt; = &lt;Mooo&gt;
+        <Mooo> = <Mooo>
+      &lt;Mooo&gt; = &lt;Mooo&gt;
+    <Mooo> = <Mooo>
+  <MOOO> = <MOOO>
+  red green blue
+---
+  <A&amp;B>[a&b](A&B) <A&amp;B2>[a&b2](A&B2)
+    <{a&amp;b}A&amp;B>[{a&b}a&b]({a&b}A&B) <{a&amp;b2}A&amp;B2>[{a&b2}a&b2]({a&b2}A&B2)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/exception.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/exception.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/exception.txt
new file mode 100644
index 0000000..0ea4395
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/exception.txt
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+<html>
+<head>
+<title>FreeMarker: Exception Test</title>
+</head>
+<body>
+
+<p>A simple test follows:</p>
+
+<p>Hello, world! <br />
+freemarker.template.TemplateModelException: Throwing from ExceptionModel!
+	at freemarker.test.templatesuite.models.ExceptionModel.getAsString(ExceptionModel.java:57)
+	at freemarker.template.compiler.Expression.getStringValue(Expression.java:65)
+	at freemarker.template.compiler.DollarVariable.process(DollarVariable.java:62)
+	at freemarker.template.compiler.NestedTemplateElements.process(NestedTemplateElements.java:76)
+	at freemarker.template.Template.process(Template.java:266)
+	at freemarker.template.Template.process(Template.java:289)
+	at freemarker.test.TestException.runTest(TestException.java:91)
+	at junit.framework.TestCase.runBare(TestCase.java:140)
+	at junit.framework.TestResult$1.protect(TestResult.java:106)
+	at junit.framework.TestResult.runProtected(TestResult.java:124)
+	at junit.framework.TestResult.run(TestResult.java:109)
+	at junit.framework.TestCase.run(TestCase.java:131)
+	at junit.framework.TestSuite.runTest(TestSuite.java:173)
+	at junit.framework.TestSuite.run(TestSuite.java:168)
+	at junit.swingui.TestRunner$17.run(TestRunner.java:644)

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/exception2.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/exception2.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/exception2.txt
new file mode 100644
index 0000000..bf441d3
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/exception2.txt
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+<html>
+<head>
+<title>FreeMarker: Exception Test</title>
+</head>
+<body>
+
+<p>A simple test follows:</p>
+
+<p>Hello, world! <br />
+<!-- Template Error: Couldn't get value of variable test: Couldn't read string value of test: freemarker.template.TemplateModelException: Throwing from ExceptionModel!
+	at freemarker.test.templatesuite.models.ExceptionModel.getAsString(ExceptionModel.java:42)
+	at freemarker.template.expression.Variable.getValue(Variable.java:69)
+	at freemarker.template.instruction.VariableInstruction.process(VariableInstruction.java:55)
+	at freemarker.template.compiler.TemplateArrayList.process(TemplateArrayList.java:69)
+	at freemarker.template.Template.process(Template.java:226)
+	at freemarker.test.TestException2.runTest(TestException2.java:83)
+	at junit.framework.TestCase.runBare(TestCase.java:140)
+	at junit.framework.TestResult$1.protect(TestResult.java:106)
+	at junit.framework.TestResult.runProtected(TestResult.java:124)
+	at junit.framework.TestResult.run(TestResult.java:109)
+	at junit.framework.TestCase.run(TestCase.java:131)
+	at junit.framework.TestSuite.runTest(TestSuite.java:173)
+	at junit.framework.TestSuite.run(TestSuite.java:168)
+	at junit.swingui.TestRunner$17.run(TestRunner.java:644)
+ -->
+</p>
+
+</body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/exception3.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/exception3.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/exception3.txt
new file mode 100644
index 0000000..6089e87
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/exception3.txt
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+<html><head></head><body bgcolor="#ffffff">
+Template Compilation Error: Identifier expected at line 10.
+</body></html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/exthash.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/exthash.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/exthash.txt
new file mode 100644
index 0000000..acb1f78
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/exthash.txt
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+<html>
+<head>
+<title>FreeMarker: Extended Hash Test</title>
+</head>
+<body>
+
+<p>A simple test follows:</p>
+
+<p>Hello, world!</p>
+
+<p>A hash set of 8 animals follows:</p>
+
+<p>
+  elephant, 
+
+  cat, 
+
+  zebra, 
+
+  dog, 
+
+  aardvark, 
+
+  kiwi, 
+
+  squirrel, 
+
+  gecko.
+</p>
+
+<p>The first animal is an elephant, and the last is a 
+gecko.</p>
+
+<p>A hash set of 8 digits follows:<p>
+
+<p>
+  six, 
+
+  four, 
+
+  eight, 
+
+  five, 
+
+  one, 
+
+  two, 
+
+  seven, 
+
+  three.
+</p>
+
+<p>The zebra number is eight.</p>
+
+<p>The end.</p>
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/hashconcat.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/hashconcat.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/hashconcat.txt
new file mode 100644
index 0000000..9736322
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/hashconcat.txt
@@ -0,0 +1,138 @@
+/*
+ * 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.
+ */
+
+a:
+  a = 1
+  b = 2
+  c = 3
+  X = 4
+  ---
+  1
+  2
+  3
+  4
+  ---
+
+B:
+  d = 10
+  e = 20
+  f = 30
+  X = 40
+  ---
+  10
+  20
+  30
+  40
+  ---
+
+a + B:
+  a = 1
+  b = 2
+  c = 3
+  X = 40
+  d = 10
+  e = 20
+  f = 30
+  ---
+  1
+  2
+  3
+  40
+  10
+  20
+  30
+  ---
+
+B + a:
+  d = 10
+  e = 20
+  f = 30
+  X = 4
+  a = 1
+  b = 2
+  c = 3
+  ---
+  10
+  20
+  30
+  4
+  1
+  2
+  3
+  ---
+
+a + a:
+  a = 1
+  b = 2
+  c = 3
+  X = 4
+  ---
+  1
+  2
+  3
+  4
+  ---
+
+{} + a:
+  a = 1
+  b = 2
+  c = 3
+  X = 4
+  ---
+  1
+  2
+  3
+  4
+  ---
+
+a + {}:
+  a = 1
+  b = 2
+  c = 3
+  X = 4
+  ---
+  1
+  2
+  3
+  4
+  ---
+
+{} + {}:
+  ---
+  ---
+
+a + b + {} + b + {} + a:
+  a = 1
+  b = 2
+  c = 3
+  X = 4
+  d = 10
+  e = 20
+  f = 30
+  ---
+  1
+  2
+  3
+  4
+  10
+  20
+  30
+  ---
+
+

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/hashliteral.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/hashliteral.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/hashliteral.txt
new file mode 100644
index 0000000..3af1052
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/hashliteral.txt
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+<html>
+<head>
+<title>FreeMarker: Hash Literal Test</title>
+</head>
+<body>
+
+<p>A simple test follows:</p>
+
+<p>Hello, world!</p>
+
+<p>Now perform a hash assignment:</p>
+
+
+test23
+Hello, world!
+hello all
+1
+
+<p>Now update the assignment and repeat:</p>
+
+
+test23
+Hello, world!
+hello all
+
+1
+
+<p>Now reassign the list and repeat:</p>
+
+
+test23
+Hello, world!
+
+
+1
+Temporary
+Temporary
+Temporary
+
+<p>Pathological case: zero item hash:</p>
+
+
+
+<p>Hash of number literals:</p>
+2
+
+<p>Hash concatenation:</p>
+a => 1
+b => 3
+c => 4
+
+<p>Empty hash concatenation:</p>
+foo, bar
+
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/helloworld.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/helloworld.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/helloworld.txt
new file mode 100644
index 0000000..b1072fd
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/helloworld.txt
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+<html>
+<head>
+<title>FreeMarker: Exec Model Test</title>
+</head>
+<body>
+
+<p>A simple test follows:</p>
+
+<p>Hello, world!
+</p>
+
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/identifier-escaping.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/identifier-escaping.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/identifier-escaping.txt
new file mode 100644
index 0000000..1c62bd5
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/identifier-escaping.txt
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+<a-b>red123</a-b>
+
+f-a works
+
+dash-dash-dash etc.
+dash-dash-dash etc.
+propVal
+propVal
+
+List: 123
+
+Switch: OK
+ESCAPED
+
+
+as1
+as2
+as3
+as4
+as5
+
+<catchAll x=1 y=2 a:b.c=5 data-foo=4 z=3 />
+
+---.: = dash-dash-dash etc.
+@as@_a = as1
+as/b = as3
+as'c = as4
+as"d = as5
+as-c = as2
+catchAll = ...
+dumpNS = ...
+f-a = ...
+hash = ...
+ls:a = ...
+m/b2 = ...
+m-a = ...
+m-b2 = ...
+sw-a = ...
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/identifier-non-ascii.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/identifier-non-ascii.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/identifier-non-ascii.txt
new file mode 100644
index 0000000..8a8d04f
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/identifier-non-ascii.txt
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+Korean Keyboard

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/if.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/if.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/if.txt
new file mode 100644
index 0000000..7c9d1d8
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/if.txt
@@ -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.
+ */
+
+- good
+- good
+- good
+- good
+
+- good
+- good
+
+- good
+- good
+- good
+- good
+
+- good
+- good
+- good
+- good
+
+- good
+- good
+- good
+- good
+
+- good
+- good
+
+- good
+- good
+- good
+- good
+
+- good
+- good
+- good
+- good
+
+- 1
+- 
+- 
+- is 1
+- isn't 2
+- isn't 3
+- Finally, it's: 1
+- 
+- 2
+- 
+- isn't 1
+- is 2
+- isn't 3
+- Finally, it's: 2
+- 
+- 
+- 3
+- isn't 1
+- isn't 2
+- is 3
+- Finally, it's: 3
+- 
+- 
+- 
+- isn't 1
+- isn't 2
+- isn't 3
+- Finally, it's: 4
+
+    1:
+      == 1
+    1:
+      <= 2
+    1:
+      <= 3
+    2:
+      > 1
+    2:
+      == 2
+    2:
+      <= 3
+    3:
+      > 1
+    3:
+      > 2
+    3:
+      == 3
+      End
+

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/import.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/import.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/import.txt
new file mode 100644
index 0000000..b51a4f4
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/import.txt
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+--
+--
+
+
+jsmith@acme.com
+  Test bar.
+  Email: jsmith@acme.com
+
+jsmith@acme.com
+  Test bar.
+  Email: jsmith@acme.com
+    Email in the root: jsmith@other1.com
+
+jsmith@other2.com
+  Test bar.
+  Email: jsmith@other2.com
+    Email in the root: jsmith@other1.com
+
+jsmith@other2.com
+jsmith@other3.com
+
+foobarfoobar
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/include.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/include.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/include.txt
new file mode 100644
index 0000000..c72d69c
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/include.txt
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+<html>
+<head>
+<title>FreeMarker: Include Instruction Test</title>
+</head>
+<body>
+
+<p>A simple test follows:</p>
+
+Hello, world!
+
+	<p>Message exists!
+
+<p>Test normal includes:</p>
+<p>A test of included files:</p>
+
+	<p>Message exists!:<br />
+        Hello, world!</p>
+
+ Can you see me? 
+
+assigning from included template
+I'm here, mon!
+
+Kilroy
+ Can you see me? Kilroy
+
+<p>Test subdir includes:</p>
+<p>This is include-subdir.ftl</p>
+<p>Testing including from same directory</p>
+<p>This is include-subdir2.ftl</p>
+<p>Testing including from relative parent</p>
+<p>A test of included files:</p>
+
+	<p>Message exists!:<br />
+        Hello, world!</p>
+
+ Can you see me? 
+<p>Testing including from loader root</p>
+<p>A test of included files:</p>
+
+	<p>Message exists!:<br />
+        Hello, world!</p>
+
+ Can you see me? 
+<p>Testing including through acquisition</p>
+<p>This is include-subdir2.ftl</p>
+</body>
+</html>
+

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/include2.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/include2.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/include2.txt
new file mode 100644
index 0000000..b7c43a9
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/include2.txt
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+A próba
+A próba
+
+A próba
+A próba
+A próba
+A próba
+
+[]
+[]

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/interpret.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/interpret.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/interpret.txt
new file mode 100644
index 0000000..fe862e6
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/interpret.txt
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+abcdef
+abcdef
+abcdef
+
+M
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/iterators.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/iterators.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/iterators.txt
new file mode 100644
index 0000000..fb44def
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/iterators.txt
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+<html>
+<head>
+<title>FreeMarker: List Iterator Test</title>
+</head>
+<body>
+
+<p>A simple test follows:</p>
+
+<p>Hello, world!</p>
+
+<p>Now iterate over a list:</p>
+
+<p>one</p>
+<p>two</p>
+<p>three</p>
+<p>four</p>
+<p>five</p>
+
+<p>Now iterate again:</p>
+
+<p>0. one</p>
+<p>1. two</p>
+<p>2. three</p>
+<p>3. four</p>
+<p>4. five</p>
+
+<p>Iterate over a list in a hash:</p>
+
+<p>one</p>
+<p>two</p>
+<p>three</p>
+<p>four</p>
+<p>five</p>
+
+<p>one</p>
+<p>two</p>
+<p>three</p>
+<p>four</p>
+<p>five</p>
+
+<p>one</p>
+<p>two</p>
+<p>three</p>
+<p>four</p>
+<p>five</p>
+
+<p>one</p>
+<p>two</p>
+<p>three</p>
+<p>four</p>
+<p>five</p>
+
+<p>one</p>
+<p>two</p>
+<p>three</p>
+<p>four</p>
+<p>five</p>
+
+<p>one</p>
+<p>two</p>
+<p>three</p>
+<p>four</p>
+<p>five</p>
+
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/lastcharacter.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/lastcharacter.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/lastcharacter.txt
new file mode 100644
index 0000000..dbe5fd0
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/lastcharacter.txt
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+<html>
+<head>
+<title>FreeMarker: Last Character Test</title>
+</head>
+<body>
+
+<p>A simple test follows:</p>
+  
+    13
+    
+    ELLO, WORLD!
+    
+    message: Hello, Worl

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/list-bis.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/list-bis.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/list-bis.txt
new file mode 100644
index 0000000..3b9b76d
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/list-bis.txt
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+    0: a [0:A, 1:B, 2:C]
+    1: b [0:A, 1:B, 2:C]
+    2: c [0:A, 1:B, 2:C]
+
+    0: a 0a/0A, 0a/1B, 0a/2C
+    1: b 1b/0A, 1b/1B, 1b/2C
+    2: c 2c/0A, 2c/1B, 2c/2C
+
+0:a, 1:b, 2:c
+1. a; 2. b; 3. c;
+
+a, b, c
+a, b, c
+
+A, b, c.
+
+true/false false/true true/false
+
+    <td class="oddRow">a</td>
+    <td class="evenRow">b</td>
+    <td class="oddRow">c</td>
+
+    <td class="rowOdd">a</td>
+    <td class="rowEven">b</td>
+    <td class="rowOdd">c</td>
+
+    <td class="R">a</td>
+    <td class="G">b</td>
+    <td class="B">c</td>
+    <td class="R">d</td>
+    <td class="G">e</td>
+    <td class="B">f</td>
+    <td class="R">g</td>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/list.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/list.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/list.txt
new file mode 100644
index 0000000..05373bd
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/list.txt
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+Size: 4
+Items: @0 aardvark, @1 bear, @2 cat, @3 dog.
+
+Size: 1
+Items: @0 aardvark.
+
+Size: 0
+Items: 
+
+Size: 3
+Items: @0 11, @1 22, @2 33.
+
+Size: 3
+Items: @0 11, @1 22, @2 33.
+
+Size: 3
+Items: @0 11, @1 22, @2 33.
+
+Size: failed
+Items: @0 11, @1 22, @2 33.
+
+Size: 0
+Items: 
+
+Size: 0
+Items: 
+
+Size: 0
+Items: 
+
+Size: failed
+Items: 
+

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/list2.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/list2.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/list2.txt
new file mode 100644
index 0000000..cb9e6d4
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/list2.txt
@@ -0,0 +1,211 @@
+/*
+ * 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.
+ */
+=== [aardvark, bear, cat, dog] ===
+
+-- List+sep:
+    aardvark,
+    bear,
+    cat,
+    dog
+-- List+else:
+    aardvark
+    bear
+    cat
+    dog
+-- List+items:
+    [
+        aardvark
+        bear
+        cat
+        dog
+    ]
+-- List+items+else:
+    [
+        aardvark
+        bear
+        cat
+        dog
+    ]
+-- List+items+sep+else:
+    [
+        aardvark,
+        bear,
+        cat,
+        dog
+    ]
+--
+
+=== [aardvark] ===
+
+-- List+sep:
+    aardvark
+-- List+else:
+    aardvark
+-- List+items:
+    [
+        aardvark
+    ]
+-- List+items+else:
+    [
+        aardvark
+    ]
+-- List+items+sep+else:
+    [
+        aardvark
+    ]
+--
+
+=== [] ===
+
+-- List+sep:
+-- List+else:
+    Empty!
+-- List+items:
+-- List+items+else:
+    Empty!
+-- List+items+sep+else:
+    Empty!
+--
+
+=== [11, 22, 33] ===
+
+-- List+sep:
+    11,
+    22,
+    33
+-- List+else:
+    11
+    22
+    33
+-- List+items:
+    [
+        11
+        22
+        33
+    ]
+-- List+items+else:
+    [
+        11
+        22
+        33
+    ]
+-- List+items+sep+else:
+    [
+        11,
+        22,
+        33
+    ]
+--
+
+=== [11, 22, 33] ===
+
+-- List+sep:
+    11,
+    22,
+    33
+-- List+else:
+    11
+    22
+    33
+-- List+items:
+    [
+        11
+        22
+        33
+    ]
+-- List+items+else:
+    [
+        11
+        22
+        33
+    ]
+-- List+items+sep+else:
+    [
+        11,
+        22,
+        33
+    ]
+--
+
+=== [11, 22, 33] ===
+
+-- List+sep:
+    11,
+    22,
+    33
+-- List+else:
+    11
+    22
+    33
+-- List+items:
+    [
+        11
+        22
+        33
+    ]
+-- List+items+else:
+    [
+        11
+        22
+        33
+    ]
+-- List+items+sep+else:
+    [
+        11,
+        22,
+        33
+    ]
+--
+
+=== [] ===
+
+-- List+sep:
+-- List+else:
+    Empty!
+-- List+items:
+-- List+items+else:
+    Empty!
+-- List+items+sep+else:
+    Empty!
+--
+
+=== [] ===
+
+-- List+sep:
+-- List+else:
+    Empty!
+-- List+items:
+-- List+items+else:
+    Empty!
+-- List+items+sep+else:
+    Empty!
+--
+
+=== [] ===
+
+-- List+sep:
+-- List+else:
+    Empty!
+-- List+items:
+-- List+items+else:
+    Empty!
+-- List+items+sep+else:
+    Empty!
+--
+

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/list3.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/list3.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/list3.txt
new file mode 100644
index 0000000..26fc60d
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/list3.txt
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+[
+    [(11@0, 11@0), (11@0, 22@1), (11@0, 33@2)],
+    [(22@1, 11@0), (22@1, 22@1), (22@1, 33@2)],
+    [(33@2, 11@0), (33@2, 22@1), (33@2, 33@2)]
+]
+
+
+        <p>2 hits:
+        <div class="hits">
+                        <div class="hit">a</div>
+                        <div class="hit">b</div>
+        </div>
+
+        <p>2 hits:
+        <div class="hits">
+                        <div class="hitOther">a</div>
+                        <div class="hitOther">b</div>
+        </div>
+
+        <p>2 hits:
+        <div class="hits">
+                    ...
+        </div>
+
+        <p>Nothing.
+
+11, 22, ...
+[11, 22, ...]
+
+1, 2, 3
+1 /*first*/, 2, 3
+[1, 2, 3]
+1
+1
+[1]
+Empty
+Empty
+Empty
+

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/listhash.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/listhash.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/listhash.txt
new file mode 100644
index 0000000..e251238
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/listhash.txt
@@ -0,0 +1,157 @@
+/*
+ * 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.
+ */
+
+Non-empty maps:
+
+    Map:
+    
+    [
+      k1 = v1
+      2 = v2
+      k3 = v3
+      null = v4
+      Y = v5
+      N = null
+    ]
+  
+    [
+      k1 = v1; // @0=@0; odd=odd; Y=Y
+      2 = v2; // @1=@1; even=even; Y=Y
+      k3 = v3; // @2=@2; odd=odd; Y=Y
+      null = v4; // @3=@3; even=even; Y=Y
+      Y = v5; // @4=@4; odd=odd; Y=Y
+      N = null // @5=@5; even=even; N=N
+    ]
+  
+    {
+      [
+        k1 = v1; // @0=@0; odd=odd; Y=Y
+        2 = v2; // @1=@1; even=even; Y=Y
+        k3 = v3; // @2=@2; odd=odd; Y=Y
+        null = v4; // @3=@3; even=even; Y=Y
+        Y = v5; // @4=@4; odd=odd; Y=Y
+        N = null // @5=@5; even=even; N=N
+      ]
+    }
+
+    Map:
+    
+    [
+      k1 = v1
+      2 = v2
+      k3 = v3
+      null = v4
+      Y = v5
+      N = null
+    ]
+  
+    [
+      k1 = v1; // @0=@0; odd=odd; Y=Y
+      2 = v2; // @1=@1; even=even; Y=Y
+      k3 = v3; // @2=@2; odd=odd; Y=Y
+      null = v4; // @3=@3; even=even; Y=Y
+      Y = v5; // @4=@4; odd=odd; Y=Y
+      N = null // @5=@5; even=even; N=N
+    ]
+  
+    {
+      [
+        k1 = v1; // @0=@0; odd=odd; Y=Y
+        2 = v2; // @1=@1; even=even; Y=Y
+        k3 = v3; // @2=@2; odd=odd; Y=Y
+        null = v4; // @3=@3; even=even; Y=Y
+        Y = v5; // @4=@4; odd=odd; Y=Y
+        N = null // @5=@5; even=even; N=N
+      ]
+    }
+
+    Map:
+    
+    [
+      k1 = 11
+      k2 = 22
+    ]
+  
+    [
+      k1 = 11; // @0=@0; odd=odd; Y=Y
+      k2 = 22 // @1=@1; even=even; N=N
+    ]
+  
+    {
+      [
+        k1 = 11; // @0=@0; odd=odd; Y=Y
+        k2 = 22 // @1=@1; even=even; N=N
+      ]
+    }
+
+
+Empty maps:
+
+    Map:
+    
+    [
+    ]
+  
+    [
+      Empty
+    ]
+  
+    {
+      Empty
+    }
+
+    Map:
+    
+    [
+    ]
+  
+    [
+      Empty
+    ]
+  
+    {
+      Empty
+    }
+
+    Map:
+    
+    [
+    ]
+  
+    [
+      Empty
+    ]
+  
+    {
+      Empty
+    }
+
+
+  a @ 0, 1
+    aa = 11  @ 0 // inside a @ 0, 1
+  a @ 0, 1
+  --
+  b @ 1, 2
+    ba = 21  @ 0 // inside b @ 1, 2
+    bb = 22  @ 1 // inside b @ 1, 2
+  b @ 1, 2
+  --
+  c @ 2, 0
+  c @ 2, 0
+  --

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/listhashliteral.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/listhashliteral.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/listhashliteral.txt
new file mode 100644
index 0000000..937f0ea
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/listhashliteral.txt
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+  KVPs:
+    a = 3
+    b = 2
+  
+  Keys:
+    a
+    b
+  
+  Values:
+    3
+    2
+
+  KVPs:
+  
+  Keys:
+  
+  Values:
+

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/listliteral.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/listliteral.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/listliteral.txt
new file mode 100644
index 0000000..2048ac5
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/listliteral.txt
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+<html>
+<head>
+<title>FreeMarker: List Literal Test</title>
+</head>
+<body>
+
+<p>A simple test follows:</p>
+
+<p>Hello, world!</p>
+
+<p>Now perform a list assignment:</p>
+
+
+The list contains 5 items.
+
+<p>test1</p>
+<p>test23</p>
+<p>test45</p>
+<p>Hello, world!</p>
+<p>hello</p>
+
+<p>Now update the assignment and repeat:</p>
+
+
+<p>test1</p>
+<p>test23</p>
+<p>test45</p>
+<p>Hello, world!</p>
+<p>hello</p>
+
+<p>Now reassign the list and repeat:</p>
+
+
+<p>bar</p>
+<p>Temporary</p>
+<p>test1</p>
+<p>test23</p>
+
+<p>Silly, but necessary tests, for one and zero element lists:</p>
+
+
+<p>Hello, world</p>
+
+<p>Zero item test:</p>
+
+
+
+<p>Dumb test for number literals -- these weren't working as expected:</p>
+
+
+<p>1</p>
+<p>2</p>
+<p>3</p>
+<p>5</p>
+
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/localization.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/localization.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/localization.txt
new file mode 100644
index 0000000..bd3c87d
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/localization.txt
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+<html>
+<head>
+<title>FreeMarker: Localization Test</title>
+</head>
+<body>
+
+<p>A simple test follows:</p>
+
+<p>Hello, world!</p>
+
+<p>G'day, mate!</p>
+
+</body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/logging.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/logging.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/logging.txt
new file mode 100644
index 0000000..4fa6b2a
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/logging.txt
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+<html>
+<head>
+<title>FreeMarker: Logging Test</title>
+</head>
+<body>
+
+A simple test follows:
+
+ERROR [org.apache.freemarker.core.Template]: message is not a TemplateHashModel, it's a freemarker.template.SimpleScalar.

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/loopvariable.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/loopvariable.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/loopvariable.txt
new file mode 100644
index 0000000..25c20ac
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/loopvariable.txt
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+---
+  2
+  -     L1 1
+  -       L2 1: 1; 2; 3; 
+  -       L2 2: 1; 2; 3; 
+*
+  -     L1 2
+  -       L2 1: 1; 2; 3; 
+  -       L2 2: 1; 2; 3; 
+*
+  -     L1 3
+  -       L2 1: 1; 2; 3; 
+  -       L2 2: 1; 2; 3; 
+*
+*
+  1
+  -     L1 1
+  -       L2 1: 1; 2; 3; 
+  -       L2 2: 1; 2; 3; 
+*
+  -     L1 2
+  -       L2 1: 1; 2; 3; 
+  -       L2 2: 1; 2; 3; 
+*
+  -     L1 3
+  -       L2 1: 1; 2; 3; 
+  -       L2 2: 1; 2; 3; 
+*
+*
+---
+  1 0.5
+  2 1
+  3 1.5
+  4 2 Last!
+123.4
+---
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/macros-return.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/macros-return.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/macros-return.txt
new file mode 100644
index 0000000..5aa47ff
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/macros-return.txt
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+m{
+m{
+m{
+b{
+m:b{
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/macros.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/macros.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/macros.txt
new file mode 100644
index 0000000..680a08e
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/macros.txt
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+<html>
+<head>
+<title>FreeMarker: Function Test</title>
+</head>
+<body>
+
+<p>A simple test follows:</p>
+
+<p>Hello, world!</p>
+
+<p>Now perform function tests:</p>
+
+
+<p>Function is defined, now let's call it:</p>
+
+    <a href="/home.html">
+        <img src="/images/home.png" border="0" alt="Home">
+    </a>
+    Kilroy was here.
+
+<p>Again, but with different parameters:</p>
+
+    <a href="/about.html">
+        <img src="/image/about-us.jpeg" border="0" alt="About Us">
+    </a>
+    Kilroy was here.
+
+   Good.
+
+<p>A recursive function call:</p>
+
+
+    0
+    1
+    2
+    3
+
+<p>Test "catch-all" macro parameter:</p>
+
+
+foo=a baz=[]
+foo=a baz=[bar=b]
+foo=a baz=[bar=b, baz=c]
+
+
+Hello World! Today is Monday.
+
+</body>
+</html>



[08/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/manualtest/Product.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/manualtest/Product.java b/freemarker-core/src/test/java/org/apache/freemarker/manualtest/Product.java
deleted file mode 100644
index fcb34e8..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/manualtest/Product.java
+++ /dev/null
@@ -1,49 +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.manualtest;
-
-/**
- * Product bean; note that it must be a public class!
- */
-public class Product {
-
-    private String url;
-    private String name;
-
-    // As per the JavaBeans spec., this defines the "url" bean property
-    // It must be public!
-    public String getUrl() {
-        return url;
-    }
-
-    public void setUrl(String url) {
-        this.url = url;
-    }
-
-    // As per the JavaBean spec., this defines the "name" bean property
-    // It must be public!
-    public String getName() {
-        return name;
-    }
-
-    public void setName(String name) {
-        this.name = name;
-    }
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/manualtest/TemplateConfigurationExamples.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/manualtest/TemplateConfigurationExamples.java b/freemarker-core/src/test/java/org/apache/freemarker/manualtest/TemplateConfigurationExamples.java
deleted file mode 100644
index 8c515bd..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/manualtest/TemplateConfigurationExamples.java
+++ /dev/null
@@ -1,191 +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.manualtest;
-
-import static org.junit.Assert.*;
-
-import java.nio.charset.StandardCharsets;
-import java.util.Date;
-
-import org.apache.freemarker.core.Configuration;
-import org.apache.freemarker.core.Template;
-import org.apache.freemarker.core.TemplateConfiguration;
-import org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat;
-import org.apache.freemarker.core.outputformat.impl.PlainTextOutputFormat;
-import org.apache.freemarker.core.outputformat.impl.UndefinedOutputFormat;
-import org.apache.freemarker.core.outputformat.impl.XMLOutputFormat;
-import org.apache.freemarker.core.templateresolver.ConditionalTemplateConfigurationFactory;
-import org.apache.freemarker.core.templateresolver.FileExtensionMatcher;
-import org.apache.freemarker.core.templateresolver.FileNameGlobMatcher;
-import org.apache.freemarker.core.templateresolver.FirstMatchTemplateConfigurationFactory;
-import org.apache.freemarker.core.templateresolver.MergingTemplateConfigurationFactory;
-import org.apache.freemarker.core.templateresolver.OrMatcher;
-import org.apache.freemarker.core.templateresolver.PathGlobMatcher;
-import org.apache.freemarker.core.util._DateUtil;
-import org.apache.freemarker.test.TemplateTest;
-import org.apache.freemarker.test.TestConfigurationBuilder;
-import org.junit.Test;
-
-public class TemplateConfigurationExamples extends TemplateTest {
-
-    @Test
-    public void example1JavaCfg() throws Exception {
-        example1(true);
-    }
-
-    @Test
-    public void example1PropertiesCfg() throws Exception {
-        example1(false);
-    }
-
-    private void example1(boolean javaCfg) throws Exception {
-        TestConfigurationBuilder cfgB = new TestConfigurationBuilder(this.getClass());
-        if (javaCfg) {
-            cfgB.setTemplateConfigurations(new ConditionalTemplateConfigurationFactory(
-                    new FileExtensionMatcher("xml"),
-                    new TemplateConfiguration.Builder()
-                            .sourceEncoding(StandardCharsets.UTF_8)
-                            .outputFormat(XMLOutputFormat.INSTANCE)
-                            .build()));
-
-        } else {
-            cfgB.setTemplateConfigurations(null);
-            cfgB.setSettings(loadPropertiesFile("TemplateConfigurationExamples1.properties"));
-        }
-        setConfiguration(cfgB.build());
-
-        addTemplate("t.xml", "");
-
-        Template t = getConfiguration().getTemplate("t.xml");
-        assertEquals(StandardCharsets.UTF_8, t.getActualSourceEncoding());
-        assertEquals(XMLOutputFormat.INSTANCE, t.getOutputFormat());
-    }
-
-    @Test
-    public void example2JavaCfg() throws Exception {
-        example2(true);
-    }
-
-    @Test
-    public void example2PropertiesCfg() throws Exception {
-        example2(false);
-    }
-
-    private void example2(boolean javaCfg) throws Exception {
-        TestConfigurationBuilder cfgB = new TestConfigurationBuilder(this.getClass());
-        if (javaCfg) {
-            cfgB.setTemplateConfigurations(
-                    new ConditionalTemplateConfigurationFactory(
-                            new PathGlobMatcher("mail/**"),
-                            new FirstMatchTemplateConfigurationFactory(
-                                    new ConditionalTemplateConfigurationFactory(
-                                            new FileNameGlobMatcher("*.subject.*"),
-                                            new TemplateConfiguration.Builder()
-                                                    .outputFormat(PlainTextOutputFormat.INSTANCE)
-                                                    .build()),
-                                    new ConditionalTemplateConfigurationFactory(
-                                            new FileNameGlobMatcher("*.body.*"),
-                                            new TemplateConfiguration.Builder()
-                                                    .outputFormat(HTMLOutputFormat.INSTANCE)
-                                                    .build())
-                            )
-                            .noMatchErrorDetails(
-                                    "Mail template names must contain \".subject.\" or \".body.\"!")));
-        } else{
-            cfgB.setSettings(loadPropertiesFile("TemplateConfigurationExamples2.properties"));
-        }
-        setConfiguration(cfgB.build());
-
-        addTemplate("t.subject.ftl", "");
-        addTemplate("mail/t.subject.ftl", "");
-        addTemplate("mail/t.body.ftl", "");
-
-        Configuration cfg = getConfiguration();
-        assertEquals(UndefinedOutputFormat.INSTANCE, cfg.getTemplate("t.subject.ftl").getOutputFormat());
-        assertEquals(PlainTextOutputFormat.INSTANCE, cfg.getTemplate("mail/t.subject.ftl").getOutputFormat());
-        assertEquals(HTMLOutputFormat.INSTANCE, cfg.getTemplate("mail/t.body.ftl").getOutputFormat());
-    }
-
-    @Test
-    public void example3JavaCfg() throws Exception {
-        example3(true);
-    }
-
-    @Test
-    public void example3PropertiesCfg() throws Exception {
-        example3(false);
-    }
-
-    private void example3(boolean javaCfg) throws Exception {
-        TestConfigurationBuilder cfgB = new TestConfigurationBuilder(this.getClass())
-                .sourceEncoding(StandardCharsets.ISO_8859_1);
-        if (javaCfg) {
-            cfgB.setTemplateConfigurations(
-                    new MergingTemplateConfigurationFactory(
-                            new ConditionalTemplateConfigurationFactory(
-                                    new FileNameGlobMatcher("*.stats.*"),
-                                    new TemplateConfiguration.Builder()
-                                            .dateTimeFormat("iso")
-                                            .dateFormat("iso")
-                                            .timeFormat("iso")
-                                            .timeZone(_DateUtil.UTC)
-                                            .build()),
-                            new ConditionalTemplateConfigurationFactory(
-                                    new PathGlobMatcher("mail/**"),
-                                    new TemplateConfiguration.Builder()
-                                            .sourceEncoding(StandardCharsets.UTF_8)
-                                            .build()),
-                            new FirstMatchTemplateConfigurationFactory(
-                                    new ConditionalTemplateConfigurationFactory(
-                                            new FileExtensionMatcher("xml"),
-                                            new TemplateConfiguration.Builder()
-                                                    .outputFormat(XMLOutputFormat.INSTANCE)
-                                                    .build()),
-                                    new ConditionalTemplateConfigurationFactory(
-                                            new OrMatcher(
-                                                    new FileExtensionMatcher("html"),
-                                                    new FileExtensionMatcher("htm")),
-                                            new TemplateConfiguration.Builder()
-                                                    .outputFormat(HTMLOutputFormat.INSTANCE)
-                                                    .build())
-                            ).allowNoMatch(true)));
-        } else {
-            cfgB.setSettings(loadPropertiesFile("TemplateConfigurationExamples3.properties"));
-        }
-        setConfiguration(cfgB.build());
-
-        addTemplate("t.stats.html", "${ts?datetime} ${ts?date} ${ts?time}");
-        addTemplate("t.html", "");
-        addTemplate("t.htm", "");
-        addTemplate("t.xml", "");
-        addTemplate("mail/t.html", "");
-
-        addToDataModel("ts", new Date(1440431606011L));
-
-        Configuration cfg = getConfiguration();
-        assertEquals(HTMLOutputFormat.INSTANCE, cfg.getTemplate("t.html").getOutputFormat());
-        assertEquals(StandardCharsets.ISO_8859_1, cfg.getTemplate("t.html").getActualSourceEncoding());
-        assertEquals(HTMLOutputFormat.INSTANCE, cfg.getTemplate("t.htm").getOutputFormat());
-        assertEquals(XMLOutputFormat.INSTANCE, cfg.getTemplate("t.xml").getOutputFormat());
-        assertEquals(HTMLOutputFormat.INSTANCE, cfg.getTemplate("t.stats.html").getOutputFormat());
-        assertOutputForNamed("t.stats.html", "2015-08-24T15:53:26.011Z 2015-08-24 15:53:26.011Z");
-        assertEquals(StandardCharsets.UTF_8, cfg.getTemplate("mail/t.html").getActualSourceEncoding());
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/manualtest/UnitAwareTemplateNumberFormatFactory.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/manualtest/UnitAwareTemplateNumberFormatFactory.java b/freemarker-core/src/test/java/org/apache/freemarker/manualtest/UnitAwareTemplateNumberFormatFactory.java
deleted file mode 100644
index 89f20fa..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/manualtest/UnitAwareTemplateNumberFormatFactory.java
+++ /dev/null
@@ -1,80 +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.manualtest;
-
-import java.util.Locale;
-
-import org.apache.freemarker.core.Environment;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateNumberModel;
-import org.apache.freemarker.core.valueformat.TemplateNumberFormat;
-import org.apache.freemarker.core.valueformat.TemplateNumberFormatFactory;
-import org.apache.freemarker.core.valueformat.TemplateValueFormatException;
-
-/**
- * A number format that takes any other number format as parameter (specified as a string, as
- * usual in FreeMarker), then if the model is a {@link UnitAwareTemplateNumberModel}, it  shows
- * the unit after the number formatted with the other format, otherwise it just shows the formatted
- * number without unit.
- */
-public class UnitAwareTemplateNumberFormatFactory extends TemplateNumberFormatFactory {
-
-    public static final UnitAwareTemplateNumberFormatFactory INSTANCE
-            = new UnitAwareTemplateNumberFormatFactory();
-
-    private UnitAwareTemplateNumberFormatFactory() {
-        // Defined to decrease visibility
-    }
-
-    @Override
-    public TemplateNumberFormat get(String params, Locale locale, Environment env)
-            throws TemplateValueFormatException {
-        return new UnitAwareNumberFormat(env.getTemplateNumberFormat(params, locale));
-    }
-
-    private static class UnitAwareNumberFormat extends TemplateNumberFormat {
-
-        private final TemplateNumberFormat innerFormat;
-
-        private UnitAwareNumberFormat(TemplateNumberFormat innerFormat) {
-            this.innerFormat = innerFormat;
-        }
-
-        @Override
-        public String formatToPlainText(TemplateNumberModel numberModel)
-                throws TemplateModelException, TemplateValueFormatException {
-            String innerResult = innerFormat.formatToPlainText(numberModel);
-            return numberModel instanceof UnitAwareTemplateNumberModel
-                    ? innerResult + " " + ((UnitAwareTemplateNumberModel) numberModel).getUnit()
-                    : innerResult;
-        }
-
-        @Override
-        public boolean isLocaleBound() {
-            return innerFormat.isLocaleBound();
-        }
-
-        @Override
-        public String getDescription() {
-            return "unit-aware " + innerFormat.getDescription();
-        }
-
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/manualtest/UnitAwareTemplateNumberModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/manualtest/UnitAwareTemplateNumberModel.java b/freemarker-core/src/test/java/org/apache/freemarker/manualtest/UnitAwareTemplateNumberModel.java
deleted file mode 100644
index 1e54254..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/manualtest/UnitAwareTemplateNumberModel.java
+++ /dev/null
@@ -1,43 +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.manualtest;
-
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateNumberModel;
-
-public class UnitAwareTemplateNumberModel implements TemplateNumberModel {
-
-    private final Number value;
-    private final String unit;
-    
-    public UnitAwareTemplateNumberModel(Number value, String unit) {
-        this.value = value;
-        this.unit = unit;
-    }
-
-    @Override
-    public Number getAsNumber() throws TemplateModelException {
-        return value;
-    }
-
-    public String getUnit() {
-        return unit;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/CopyrightCommentRemoverTemplateLoader.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/CopyrightCommentRemoverTemplateLoader.java b/freemarker-core/src/test/java/org/apache/freemarker/test/CopyrightCommentRemoverTemplateLoader.java
deleted file mode 100644
index 3b1f1ee..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/CopyrightCommentRemoverTemplateLoader.java
+++ /dev/null
@@ -1,104 +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.test;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.Reader;
-import java.io.Serializable;
-import java.io.StringReader;
-import java.nio.charset.StandardCharsets;
-
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.io.input.ReaderInputStream;
-import org.apache.freemarker.core.templateresolver.TemplateLoader;
-import org.apache.freemarker.core.templateresolver.TemplateLoaderSession;
-import org.apache.freemarker.core.templateresolver.TemplateLoadingResult;
-import org.apache.freemarker.core.templateresolver.TemplateLoadingResultStatus;
-import org.apache.freemarker.core.templateresolver.TemplateLoadingSource;
-
-/**
- * Removes the Apache copyright boiler plate from the beginning of the template, so that they don't mess up the expected
- * template output. This can interfere with tests that try to test I/O errors and such low level things, so use with
- * care. 
- */
-public class CopyrightCommentRemoverTemplateLoader implements TemplateLoader {
-
-    private final TemplateLoader innerTemplateLoader;
-
-    public CopyrightCommentRemoverTemplateLoader(TemplateLoader innerTemplateLoader) {
-        this.innerTemplateLoader = innerTemplateLoader;
-    }
-
-    @Override
-    public TemplateLoaderSession createSession() {
-        return null;
-    }
-
-    @Override
-    public TemplateLoadingResult load(String name, TemplateLoadingSource ifSourceDiffersFrom,
-            Serializable ifVersionDiffersFrom, TemplateLoaderSession session) throws IOException {
-        TemplateLoadingResult result = innerTemplateLoader.load(name, ifSourceDiffersFrom, ifVersionDiffersFrom, session);
-        if (result.getStatus() != TemplateLoadingResultStatus.OPENED) {
-            return result;
-        }
-        if (result.getInputStream() != null) {
-            return new TemplateLoadingResult(
-                    result.getSource(), result.getVersion(), getWithoutCopyrightHeader(result.getInputStream()),
-                    result.getTemplateConfiguration());
-        } else {
-            return new TemplateLoadingResult(
-                    result.getSource(), result.getVersion(), getWithoutCopyrightHeader(result.getReader()),
-                    result.getTemplateConfiguration());
-        }
-    }
-
-    @Override
-    public void resetState() {
-        // Do nothing
-    }
-
-    private Reader getWithoutCopyrightHeader(Reader reader) throws IOException {
-        if (reader == null) {
-            return null;
-        }
-        try {
-            String content = IOUtils.toString(reader);
-            return new StringReader(TestUtil.removeFTLCopyrightComment(content));
-        } finally {
-            reader.close();
-        }
-    }
-
-    private InputStream getWithoutCopyrightHeader(InputStream in) throws IOException {
-        if (in == null) {
-            return null;
-        }
-        try {
-            // Encoding then decosing in ISO-8859-1 is binary loseless
-            String content = IOUtils.toString(in, StandardCharsets.ISO_8859_1.name());
-            return new ReaderInputStream(
-                    new StringReader(TestUtil.removeFTLCopyrightComment(content)),
-                    StandardCharsets.ISO_8859_1);
-        } finally {
-            in.close();
-        }
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/MonitoredTemplateLoader.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/MonitoredTemplateLoader.java b/freemarker-core/src/test/java/org/apache/freemarker/test/MonitoredTemplateLoader.java
deleted file mode 100644
index 0ab2922..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/MonitoredTemplateLoader.java
+++ /dev/null
@@ -1,325 +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.test;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.Serializable;
-import java.io.StringReader;
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.apache.freemarker.core.templateresolver.TemplateLoader;
-import org.apache.freemarker.core.templateresolver.TemplateLoaderSession;
-import org.apache.freemarker.core.templateresolver.TemplateLoadingResult;
-import org.apache.freemarker.core.templateresolver.TemplateLoadingResultStatus;
-import org.apache.freemarker.core.templateresolver.TemplateLoadingSource;
-
-import com.google.common.base.Objects;
-
-public class MonitoredTemplateLoader implements TemplateLoader {
-
-    private final List<AbstractTemplateLoader2Event> events
-            = Collections.synchronizedList(new ArrayList<AbstractTemplateLoader2Event>());
-    
-    private Map<String, StoredTemplate> templates
-            = new ConcurrentHashMap<>();
-
-    @Override
-    public TemplateLoaderSession createSession() {
-        events.add(CreateSessionEvent.INSTANCE);
-        return new MonitoredTemplateLoader2Session();
-    }
-
-    @Override
-    public TemplateLoadingResult load(String name, TemplateLoadingSource ifSourceDiffersFrom, Serializable ifVersionDiffersFrom,
-            TemplateLoaderSession session)
-            throws IOException {
-        TemplateLoadingResult result = loadInner(name, ifSourceDiffersFrom, ifVersionDiffersFrom, session);
-        events.add(new LoadEvent(name, result.getStatus()));
-        return result;
-    }
-
-    private TemplateLoadingResult loadInner(String name, TemplateLoadingSource ifSourceDiffersFrom,
-            Serializable ifVersionDiffersFrom, TemplateLoaderSession session) throws UnsupportedEncodingException {
-        if (session.isClosed()) {
-            throw new IllegalArgumentException("Template loader session is already closed.");
-        }
-        
-        StoredTemplate storedTemplate = templates.get(name);
-        if (storedTemplate == null) {
-            return TemplateLoadingResult.NOT_FOUND;
-        }
-        
-        TemplateLoadingSource source = storedTemplate.getSource();
-        Serializable version = storedTemplate.getVersion();
-        if (ifSourceDiffersFrom != null
-                && ifSourceDiffersFrom.equals(source)
-                && Objects.equal(ifVersionDiffersFrom, version)) {
-            return TemplateLoadingResult.NOT_MODIFIED;
-        }
-        
-        String content = storedTemplate.getContent();
-        return storedTemplate.inputStreamEncoding == null
-                ? new TemplateLoadingResult(source, version, new StringReader(content), null)
-                : new TemplateLoadingResult(source, version,
-                        new ByteArrayInputStream(content.getBytes(storedTemplate.inputStreamEncoding)), null);
-    }
-    
-    @Override
-    public void resetState() {
-        events.add(ResetStateEvent.INSTANCE);
-    }
-
-    public StoredTemplate putTextTemplate(String name, String content) {
-        return putTextTemplate(name, "v1", content);
-    }
-    
-    public StoredTemplate putTextTemplate(String name, Serializable version, String content) {
-        StoredTemplate storedTemplate = new StoredTemplate(name, version, content, null);
-        templates.put(name, storedTemplate);
-        return storedTemplate;
-    }
-
-    public StoredTemplate putBinaryTemplate(String name, String content) {
-        return putBinaryTemplate(name, content, "v1");
-    }
-    
-    public StoredTemplate putBinaryTemplate(String name, String content, Serializable version) {
-        return putBinaryTemplate(name, content, null, version);
-    }
-    
-    public StoredTemplate putBinaryTemplate(String name, String content,
-            Charset inputStreamEncoding, Serializable version) {
-        StoredTemplate storedTemplate = new StoredTemplate(name, version, content,
-                inputStreamEncoding != null ? inputStreamEncoding : StandardCharsets.UTF_8);
-        templates.put(name, storedTemplate);
-        return storedTemplate;
-    }
-
-    public List<AbstractTemplateLoader2Event> getEvents() {
-        return events;
-    }
-
-    /**
-     * Gets a filtered event list.
-     */
-    @SuppressWarnings("unchecked")
-    public <E extends AbstractTemplateLoader2Event> List<E> getEvents(Class<E> eventClass) {
-        List<E> result = new ArrayList<>();
-        for (AbstractTemplateLoader2Event event : events) {
-            if (eventClass.isInstance(event)) {
-                result.add((E) event);
-            }
-        }
-        return result;
-    }
-    
-    /**
-     * Extract from the {@link #getEvents()} the template names for which {@link TemplateLoader#load} was called.
-     */
-    public List<String> getLoadNames() {
-        List<String> result = new ArrayList<>();
-        for (AbstractTemplateLoader2Event event : events) {
-            if (event instanceof LoadEvent) {
-                result.add(((LoadEvent) event).name);
-            }
-        }
-        return result;
-    }
-
-    public void clearEvents() {
-        events.clear();
-    }
-
-    @SuppressWarnings("serial")
-    public static class StoredTemplate implements TemplateLoadingSource {
-        private String name;
-        private Serializable version;
-        private String content;
-        private Charset inputStreamEncoding; 
-        
-        private StoredTemplate(String name, Serializable version, String content, Charset inputStreamEncoding) {
-            this.name = name;
-            this.version = version;
-            this.content = content;
-            this.inputStreamEncoding = inputStreamEncoding;
-        }
-    
-        public String getName() {
-            return name;
-        }
-    
-        public void setName(String name) {
-            this.name = name;
-        }
-    
-        public TemplateLoadingSource getSource() {
-            return this;
-        }
-    
-        public Serializable getVersion() {
-            return version;
-        }
-    
-        public void setVersion(Serializable version) {
-            this.version = version;
-        }
-    
-        public String getContent() {
-            return content;
-        }
-    
-        public void setContent(String content) {
-            this.content = content;
-        }
-    
-        public Charset getInputStreamEncoding() {
-            return inputStreamEncoding;
-        }
-    
-        public void setInputStreamEncoding(Charset inputStreamEncoding) {
-            this.inputStreamEncoding = inputStreamEncoding;
-        }
-        
-    }
-
-    public abstract static class AbstractTemplateLoader2Event {
-        // empty
-    }
-
-    public static class LoadEvent extends AbstractTemplateLoader2Event {
-        private final String name;
-        private final TemplateLoadingResultStatus resultStatus;
-        
-        public LoadEvent(String name, TemplateLoadingResultStatus resultStatus) {
-            this.name = name;
-            this.resultStatus = resultStatus;
-        }
-    
-        public String getName() {
-            return name;
-        }
-        
-        public TemplateLoadingResultStatus getResultStatus() {
-            return resultStatus;
-        }
-    
-        @Override
-        public String toString() {
-            return "LoadEvent [name=" + name + ", resultStatus=" + resultStatus + "]";
-        }
-    
-        @Override
-        public int hashCode() {
-            final int prime = 31;
-            int result = 1;
-            result = prime * result + ((name == null) ? 0 : name.hashCode());
-            result = prime * result + ((resultStatus == null) ? 0 : resultStatus.hashCode());
-            return result;
-        }
-    
-        @Override
-        public boolean equals(Object obj) {
-            if (this == obj)
-                return true;
-            if (obj == null)
-                return false;
-            if (getClass() != obj.getClass())
-                return false;
-            LoadEvent other = (LoadEvent) obj;
-            if (name == null) {
-                if (other.name != null)
-                    return false;
-            } else if (!name.equals(other.name))
-                return false;
-            return resultStatus == other.resultStatus;
-        }
-        
-    }
-
-    public static class ResetStateEvent extends AbstractTemplateLoader2Event {
-    
-        public static ResetStateEvent INSTANCE = new ResetStateEvent();
-        
-        private ResetStateEvent() {
-            //
-        }
-        
-        @Override
-        public String toString() {
-            return "ResetStateEvent []";
-        }
-        
-    }
-
-    public static class CreateSessionEvent extends AbstractTemplateLoader2Event {
-        
-        public static CreateSessionEvent INSTANCE = new CreateSessionEvent();
-        
-        private CreateSessionEvent() {
-            //
-        }
-
-        @Override
-        public String toString() {
-            return "CreateSessionEvent []";
-        }
-        
-    }
-
-    public static class CloseSessionEvent extends AbstractTemplateLoader2Event {
-
-        public static CloseSessionEvent INSTANCE = new CloseSessionEvent();
-        
-        private CloseSessionEvent() {
-            //
-        }
-        
-        @Override
-        public String toString() {
-            return "CloseSessionEvent []";
-        }
-        
-    }
-
-    public class MonitoredTemplateLoader2Session implements TemplateLoaderSession {
-        
-        private boolean closed;
-
-        @Override
-        public void close() {
-            closed = true;
-            events.add(CloseSessionEvent.INSTANCE);
-        }
-
-        @Override
-        public boolean isClosed() {
-            return closed;
-        }
-        
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/TemplateTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/TemplateTest.java b/freemarker-core/src/test/java/org/apache/freemarker/test/TemplateTest.java
deleted file mode 100644
index 566cc90..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/TemplateTest.java
+++ /dev/null
@@ -1,341 +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.test;
-
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.StringWriter;
-import java.nio.charset.StandardCharsets;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Properties;
-
-import org.apache.commons.io.IOUtils;
-import org.apache.freemarker.core.Configuration;
-import org.apache.freemarker.core.ParseException;
-import org.apache.freemarker.core.Template;
-import org.apache.freemarker.core.TemplateException;
-import org.apache.freemarker.core.templateresolver.TemplateLoader;
-import org.apache.freemarker.core.templateresolver.impl.ByteArrayTemplateLoader;
-import org.apache.freemarker.core.templateresolver.impl.MultiTemplateLoader;
-import org.apache.freemarker.core.util._NullArgumentException;
-import org.apache.freemarker.core.util._StringUtil;
-import org.apache.freemarker.test.templatesuite.TemplateTestSuite;
-import org.junit.Ignore;
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-
-/**
- * Superclass of JUnit tests that process templates but aren't practical to implement via {@link TemplateTestSuite}. 
- */
-@Ignore
-public abstract class TemplateTest {
-    
-    private Configuration configuration;
-    private boolean dataModelCreated;
-    private Object dataModel;
-    private Map<String, String> addedTemplates = new HashMap<>();
-
-    /**
-     * Gets the {@link Configuration} used, automaticlly creating and setting if it wasn't yet.
-     */
-    protected final Configuration getConfiguration() {
-        if (configuration == null) {
-            try {
-                setConfiguration(createDefaultConfiguration());
-            } catch (Exception e) {
-                throw new RuntimeException("Failed to create configuration", e);
-            }
-        }
-        return configuration;
-    }
-
-    /**
-     * @param configuration Usually should be built using {@link TestConfigurationBuilder}; not {@code null}.
-     */
-    protected final void setConfiguration(Configuration configuration) {
-        _NullArgumentException.check("configuration", configuration);
-        if (this.configuration == configuration) {
-            return;
-        }
-
-        this.configuration = configuration;
-        afterConfigurationSet();
-    }
-
-    protected void assertOutput(String ftl, String expectedOut) throws IOException, TemplateException {
-        assertOutput(createTemplate(ftl), expectedOut, false);
-    }
-
-    private Template createTemplate(String ftl) throws IOException {
-        return new Template(null, ftl, getConfiguration());
-    }
-
-    protected void assertOutputForNamed(String name, String expectedOut) throws IOException, TemplateException {
-        assertOutput(getConfiguration().getTemplate(name), expectedOut, false);
-    }
-
-    @SuppressFBWarnings(value="UI_INHERITANCE_UNSAFE_GETRESOURCE", justification="By design relative to subclass")
-    protected void assertOutputForNamed(String name) throws IOException, TemplateException {
-        String expectedOut;
-        {
-            String resName = name + ".out";
-            InputStream in = getClass().getResourceAsStream(resName);
-            if (in == null) {
-                throw new IOException("Reference output resource not found: " + getClass() + ", " + resName);
-            }
-            try {
-                expectedOut = TestUtil.removeTxtCopyrightComment(IOUtils.toString(in, StandardCharsets.UTF_8.name()));
-            } finally {
-                in.close();
-            }
-        }
-        assertOutput(getConfiguration().getTemplate(name), expectedOut, true);
-    }
-
-    protected void assertOutput(Template t, String expectedOut) throws TemplateException, IOException {
-        assertOutput(t, expectedOut, false);
-    }
-    
-    protected void assertOutput(Template t, String expectedOut, boolean normalizeNewlines)
-            throws TemplateException, IOException {
-        String actualOut = getOutput(t);
-        
-        if (normalizeNewlines) {
-            expectedOut = normalizeNewLines(expectedOut);
-            actualOut = normalizeNewLines(actualOut);
-        }
-        assertEquals(expectedOut, actualOut);
-    }
-
-    protected String getOutput(String ftl) throws IOException, TemplateException {
-        return getOutput(createTemplate(ftl));
-    }
-    
-    protected String getOutput(Template t) throws TemplateException, IOException {
-        StringWriter out = new StringWriter();
-        t.process(getDataModel(), out);
-        return out.toString();
-    }
-    
-    protected Configuration createDefaultConfiguration() throws Exception {
-        return new TestConfigurationBuilder().build();
-    }
-
-    private void afterConfigurationSet() {
-        ensureAddedTemplatesPresent();
-        addCommonTemplates();
-    }
-
-    private void ensureAddedTemplatesPresent() {
-        for (Map.Entry<String, String> ent : addedTemplates.entrySet()) {
-            addTemplate(ent.getKey(), ent.getValue());
-        }
-    }
-
-    protected void addCommonTemplates() {
-        //
-    }
-
-    protected Object getDataModel() {
-        if (!dataModelCreated) {
-            dataModel = createDataModel();
-            dataModelCreated = true;
-        }
-        return dataModel;
-    }
-    
-    protected Object createDataModel() {
-        return null;
-    }
-    
-    @SuppressWarnings("boxing")
-    protected Map<String, Object> createCommonTestValuesDataModel() {
-        Map<String, Object> dataModel = new HashMap<>();
-        dataModel.put("map", Collections.singletonMap("key", "value"));
-        dataModel.put("list", Collections.singletonList("item"));
-        dataModel.put("s", "text");
-        dataModel.put("n", 1);
-        dataModel.put("b", true);
-        dataModel.put("bean", new TestBean());
-        return dataModel;
-    }
-
-    protected void addTemplate(String name, String content) {
-        Configuration cfg = getConfiguration();
-        TemplateLoader tl = cfg.getTemplateLoader();
-        ByteArrayTemplateLoader btl;
-        btl = extractByteArrayTemplateLoader(tl);
-        btl.putTemplate(name, content.getBytes(StandardCharsets.UTF_8));
-        addedTemplates.put(name, content);
-    }
-
-    private ByteArrayTemplateLoader extractByteArrayTemplateLoader(TemplateLoader tl) {
-        if (tl instanceof MultiTemplateLoader) {
-            MultiTemplateLoader mtl = (MultiTemplateLoader) tl;
-            for (int i = 0; i < mtl.getTemplateLoaderCount(); i++) {
-                TemplateLoader tli = mtl.getTemplateLoader(i);
-                if (tli instanceof ByteArrayTemplateLoader) {
-                    return (ByteArrayTemplateLoader) tli;
-                }
-            }
-            throw new IllegalStateException(
-                    "The template loader was a MultiTemplateLoader that didn't contain ByteArrayTemplateLoader: "
-                            + tl);
-        } else if (tl instanceof ByteArrayTemplateLoader) {
-            return (ByteArrayTemplateLoader) tl;
-        } else if (tl == null) {
-            throw new IllegalStateException("The templateLoader was null in the configuration");
-        } else {
-            throw new IllegalStateException(
-                    "The template loader was already set to a non-ByteArrayTemplateLoader non-MultiTemplateLoader: "
-                            + tl);
-        }
-    }
-
-    protected void addToDataModel(String name, Object value) {
-        Object dm = getDataModel();
-        if (dm == null) {
-            dm = new HashMap<String, Object>();
-            dataModel = dm;
-        }
-        if (dm instanceof Map) {
-            ((Map) dm).put(name, value);
-        } else {
-            throw new IllegalStateException("Can't add to non-Map data-model: " + dm);
-        }
-    }
-
-    protected Properties loadPropertiesFile(String name) throws IOException {
-        Properties props = new Properties();
-        InputStream in = getClass().getResourceAsStream(name);
-        try {
-            props.load(in);
-        } finally {
-            in.close();
-        }
-        return props;
-    }
-
-    protected Throwable assertErrorContains(String ftl, String... expectedSubstrings) {
-        return assertErrorContains(null, ftl, null, expectedSubstrings);
-    }
-
-    protected Throwable assertErrorContains(String ftl, Class<? extends Throwable> exceptionClass,
-            String... expectedSubstrings) {
-        return assertErrorContains(null, ftl, exceptionClass, expectedSubstrings);
-    }
-
-    protected void assertErrorContainsForNamed(String name, String... expectedSubstrings) {
-        assertErrorContains(name, null, null, expectedSubstrings);
-    }
-
-    protected void assertErrorContainsForNamed(String name, Class<? extends Throwable> exceptionClass,
-            String... expectedSubstrings) {
-        assertErrorContains(name, null, exceptionClass, expectedSubstrings);
-    }
-    
-    private Throwable assertErrorContains(String name, String ftl, Class<? extends Throwable> exceptionClass,
-            String... expectedSubstrings) {
-        try {
-            Template t;
-            if (ftl == null) {
-                t = getConfiguration().getTemplate(name);
-            } else {
-                t = new Template("adhoc", ftl, getConfiguration());
-            }
-            t.process(getDataModel(), new StringWriter());
-            fail("The tempalte had to fail");
-            return null;
-        } catch (TemplateException e) {
-            if (exceptionClass != null) {
-                assertThat(e, instanceOf(exceptionClass));
-            }
-            assertContainsAll(e.getMessageWithoutStackTop(), expectedSubstrings);
-            return e;
-        } catch (ParseException e) {
-            if (exceptionClass != null) {
-                assertThat(e, instanceOf(exceptionClass));
-            }
-            assertContainsAll(e.getEditorMessage(), expectedSubstrings);
-            return e;
-        } catch (Exception e) {
-            if (exceptionClass != null) {
-                assertThat(e, instanceOf(exceptionClass));
-                return e;
-            } else {
-                throw new RuntimeException("Unexpected exception class: " + e.getClass().getName(), e);
-            }
-        }
-    }
-    
-    private void assertContainsAll(String msg, String... expectedSubstrings) {
-        for (String needle: expectedSubstrings) {
-            if (needle.startsWith("\\!")) {
-                String netNeedle = needle.substring(2); 
-                if (msg.contains(netNeedle)) {
-                    fail("The message shouldn't contain substring " + _StringUtil.jQuote(netNeedle) + ":\n" + msg);
-                }
-            } else if (!msg.contains(needle)) {
-                fail("The message didn't contain substring " + _StringUtil.jQuote(needle) + ":\n" + msg);
-            }
-        }
-    }
-    
-    private String normalizeNewLines(String s) {
-        return _StringUtil.replace(s, "\r\n", "\n").replace('\r', '\n');
-    }
-
-    public static class TestBean {
-        private int x;
-        private boolean b;
-        
-        public int getX() {
-            return x;
-        }
-        public void setX(int x) {
-            this.x = x;
-        }
-        public boolean isB() {
-            return b;
-        }
-        public void setB(boolean b) {
-            this.b = b;
-        }
-
-        public int intM() {
-            return 1;
-        }
-
-        public int intMP(int x) {
-            return x;
-        }
-        
-        public void voidM() {
-            
-        }
-        
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/TestConfigurationBuilder.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/TestConfigurationBuilder.java b/freemarker-core/src/test/java/org/apache/freemarker/test/TestConfigurationBuilder.java
deleted file mode 100644
index 7f869db..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/TestConfigurationBuilder.java
+++ /dev/null
@@ -1,92 +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.test;
-
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.util.Locale;
-import java.util.TimeZone;
-
-import org.apache.freemarker.core.Configuration;
-import org.apache.freemarker.core.Configuration.Builder;
-import org.apache.freemarker.core.Version;
-import org.apache.freemarker.core.templateresolver.TemplateLoader;
-import org.apache.freemarker.core.templateresolver.impl.ByteArrayTemplateLoader;
-import org.apache.freemarker.core.templateresolver.impl.ClassTemplateLoader;
-import org.apache.freemarker.core.templateresolver.impl.MultiTemplateLoader;
-
-/**
- * Configuration builder you should use instead of {@link Builder} in unit tests.
- * It tries to make the behavior of the tests independent of the environment where we run them. For convenience, it
- * has a {@link ByteArrayTemplateLoader} as the default template loader.
- */
-public class TestConfigurationBuilder extends Configuration.ExtendableBuilder<TestConfigurationBuilder> {
-
-    private static final TimeZone DEFAULT_TIME_ZONE = TimeZone.getTimeZone("GMT+1");
-    private final Class<?> classTemplateLoaderBase;
-    private TemplateLoader defaultTemplateLoader;
-
-    public TestConfigurationBuilder() {
-        this((Version) null);
-    }
-
-    public TestConfigurationBuilder(Class<?> classTemplateLoaderBase) {
-        this(null, classTemplateLoaderBase);
-    }
-
-    public TestConfigurationBuilder(Version incompatibleImprovements) {
-        this(incompatibleImprovements, null);
-    }
-
-    public TestConfigurationBuilder(Version incompatibleImprovements, Class<?> classTemplateLoaderBase) {
-        super(incompatibleImprovements != null ? incompatibleImprovements : Configuration.VERSION_3_0_0);
-        this.classTemplateLoaderBase = classTemplateLoaderBase;
-    }
-
-    @Override
-    protected Locale getDefaultLocale() {
-        return Locale.US;
-    }
-
-    @Override
-    protected Charset getDefaultSourceEncoding() {
-        return StandardCharsets.UTF_8;
-    }
-
-    @Override
-    protected TimeZone getDefaultTimeZone() {
-        return DEFAULT_TIME_ZONE;
-    }
-
-    @Override
-    protected TemplateLoader getDefaultTemplateLoader() {
-        if (defaultTemplateLoader == null) {
-            if (classTemplateLoaderBase == null) {
-                defaultTemplateLoader = new ByteArrayTemplateLoader();
-            } else {
-                defaultTemplateLoader = new MultiTemplateLoader(
-                        new ByteArrayTemplateLoader(),
-                        new ClassTemplateLoader(classTemplateLoaderBase, ""));
-            }
-        }
-        return defaultTemplateLoader;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/hamcerst/Matchers.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/hamcerst/Matchers.java b/freemarker-core/src/test/java/org/apache/freemarker/test/hamcerst/Matchers.java
deleted file mode 100644
index 7552a8d..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/hamcerst/Matchers.java
+++ /dev/null
@@ -1,34 +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.test.hamcerst;
-
-import org.hamcrest.Matcher;
-
-public final class Matchers {
-    
-    private Matchers() {
-        // Not meant to be instantiated
-    }
-
-    public static Matcher<String> containsStringIgnoringCase(String substring) {
-        return StringContainsIgnoringCase.containsStringIgnoringCase(substring);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/hamcerst/StringContainsIgnoringCase.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/hamcerst/StringContainsIgnoringCase.java b/freemarker-core/src/test/java/org/apache/freemarker/test/hamcerst/StringContainsIgnoringCase.java
deleted file mode 100644
index 914bbd1..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/hamcerst/StringContainsIgnoringCase.java
+++ /dev/null
@@ -1,47 +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.test.hamcerst;
-
-import org.hamcrest.Factory;
-import org.hamcrest.Matcher;
-import org.hamcrest.core.SubstringMatcher;
-
-public class StringContainsIgnoringCase extends SubstringMatcher {
-    
-    public StringContainsIgnoringCase(String substring) {
-        super(substring);
-    }
-
-    @Override
-    protected boolean evalSubstringOf(String s) {
-        return s.toLowerCase().contains(substring.toLowerCase());
-    }
-
-    @Override
-    protected String relationship() {
-        return "containing ignoring case";
-    }
-
-    @Factory
-    public static Matcher<String> containsStringIgnoringCase(String substring) {
-        return new StringContainsIgnoringCase(substring);
-    }
-    
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/package.html
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/package.html b/freemarker-core/src/test/java/org/apache/freemarker/test/package.html
deleted file mode 100644
index 3dbb3fb..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/package.html
+++ /dev/null
@@ -1,28 +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.
--->
-<html>
-<head>
-</head>
-<body>
-<p>Testing-related classes that don't fit into the normal packages.
-Normally you put the test classes into the same package where the
-tested classes are, but under <tt>src/test/java/<tt> instead of
-under <tt>src/main/java/<tt>.</p>
-</body>
-</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/TemplateTestCase.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/TemplateTestCase.java b/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/TemplateTestCase.java
deleted file mode 100644
index 07bf0ca..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/test/templatesuite/TemplateTestCase.java
+++ /dev/null
@@ -1,515 +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.test.templatesuite;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.ResourceBundle;
-import java.util.Set;
-import java.util.StringTokenizer;
-import java.util.TimeZone;
-import java.util.TreeSet;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-
-import org.apache.freemarker.core.ASTPrinter;
-import org.apache.freemarker.core.Configuration;
-import org.apache.freemarker.core.ConfigurationException;
-import org.apache.freemarker.core.Template;
-import org.apache.freemarker.core.TemplateException;
-import org.apache.freemarker.core.Version;
-import org.apache.freemarker.core.model.TemplateBooleanModel;
-import org.apache.freemarker.core.model.TemplateDateModel;
-import org.apache.freemarker.core.model.TemplateMethodModel;
-import org.apache.freemarker.core.model.TemplateNodeModel;
-import org.apache.freemarker.core.model.TemplateScalarModel;
-import org.apache.freemarker.core.model.TemplateSequenceModel;
-import org.apache.freemarker.core.model.impl.DefaultNonListCollectionAdapter;
-import org.apache.freemarker.core.model.impl.DefaultObjectWrapper;
-import org.apache.freemarker.core.model.impl.ResourceBundleModel;
-import org.apache.freemarker.core.model.impl.SimpleCollection;
-import org.apache.freemarker.core.model.impl.SimpleDate;
-import org.apache.freemarker.core.model.impl.SimpleNumber;
-import org.apache.freemarker.core.templateresolver.impl.ClassTemplateLoader;
-import org.apache.freemarker.core.util._NullArgumentException;
-import org.apache.freemarker.core.util._NullWriter;
-import org.apache.freemarker.core.util._StringUtil;
-import org.apache.freemarker.dom.NodeModel;
-import org.apache.freemarker.test.CopyrightCommentRemoverTemplateLoader;
-import org.apache.freemarker.test.TestConfigurationBuilder;
-import org.apache.freemarker.test.templatesuite.models.BooleanAndStringTemplateModel;
-import org.apache.freemarker.test.templatesuite.models.BooleanHash1;
-import org.apache.freemarker.test.templatesuite.models.BooleanHash2;
-import org.apache.freemarker.test.templatesuite.models.BooleanList1;
-import org.apache.freemarker.test.templatesuite.models.BooleanList2;
-import org.apache.freemarker.test.templatesuite.models.BooleanVsStringMethods;
-import org.apache.freemarker.test.templatesuite.models.JavaObjectInfo;
-import org.apache.freemarker.test.templatesuite.models.Listables;
-import org.apache.freemarker.test.templatesuite.models.MultiModel1;
-import org.apache.freemarker.test.templatesuite.models.OverloadedMethods2;
-import org.apache.freemarker.test.templatesuite.models.VarArgTestModel;
-import org.apache.freemarker.test.util.AssertDirective;
-import org.apache.freemarker.test.util.AssertEqualsDirective;
-import org.apache.freemarker.test.util.AssertFailsDirective;
-import org.apache.freemarker.test.util.FileTestCase;
-import org.apache.freemarker.test.util.NoOutputDirective;
-import org.apache.freemarker.test.util.XMLLoader;
-import org.junit.Ignore;
-import org.xml.sax.InputSource;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-
-import junit.framework.AssertionFailedError;
-
-/**
- * Instances of this are created and called by {@link TemplateTestSuite}. (It's on "Ignore" so that Eclipse doesn't try
- * to run this alone.) 
- */
-@Ignore
-public class TemplateTestCase extends FileTestCase {
-    
-    // Name of variables exposed to all test FTL-s:
-    private static final String ICI_INT_VALUE_VAR_NAME = "iciIntValue";
-    private static final String TEST_NAME_VAR_NAME = "testName";
-    private static final String JAVA_OBJECT_INFO_VAR_NAME = "javaObjectInfo";
-    private static final String NO_OUTPUT_VAR_NAME = "noOutput";
-    private static final String ASSERT_FAILS_VAR_NAME = "assertFails";
-    private static final String ASSERT_EQUALS_VAR_NAME = "assertEquals";
-    private static final String ASSERT_VAR_NAME = "assert";
-    
-    private final String simpleTestName;
-    private final String templateName;
-    private final String expectedFileName;
-    private final boolean noOutput;
-    
-    private final Configuration.ExtendableBuilder confB;
-    private final HashMap<String, Object> dataModel = new HashMap<>();
-    
-    public TemplateTestCase(String testName, String simpleTestName, String templateName, String expectedFileName, boolean noOutput,
-            Version incompatibleImprovements) {
-        super(testName);
-        _NullArgumentException.check("testName", testName);
-        
-        _NullArgumentException.check("simpleTestName", simpleTestName);
-        this.simpleTestName = simpleTestName;
-        
-        _NullArgumentException.check("templateName", templateName);
-        this.templateName = templateName;
-        
-        _NullArgumentException.check("expectedFileName", expectedFileName);
-        this.expectedFileName = expectedFileName;
-        
-        this.noOutput = noOutput;
-
-        confB = new TestConfigurationBuilder(incompatibleImprovements);
-    }
-    
-    public void setSetting(String param, String value) throws IOException {
-        if ("auto_import".equals(param)) {
-            StringTokenizer st = new StringTokenizer(value);
-            if (!st.hasMoreTokens()) fail("Expecting libname");
-            String libname = st.nextToken();
-            if (!st.hasMoreTokens()) fail("Expecting 'as <alias>' in autoimport");
-            String as = st.nextToken();
-            if (!as.equals("as")) fail("Expecting 'as <alias>' in autoimport");
-            if (!st.hasMoreTokens()) fail("Expecting alias after 'as' in autoimport");
-            String alias = st.nextToken();
-            confB.addAutoImport(alias, libname);
-        } else if ("source_encoding".equals(param)) {
-            confB.setSourceEncoding(Charset.forName(value));
-        // INCOMPATIBLE_IMPROVEMENTS is a list here, and was already set in the constructor.
-        } else if (!Configuration.ExtendableBuilder.INCOMPATIBLE_IMPROVEMENTS_KEY.equals(param)) {
-            try {
-                confB.setSetting(param, value);
-            } catch (ConfigurationException e) {
-                throw new RuntimeException(
-                        "Failed to set setting " +
-                        _StringUtil.jQuote(param) + " to " +
-                        _StringUtil.jQuote(value) + "; see cause exception.",
-                        e);
-            }
-        }
-    }
-    
-    /*
-     * This method just contains all the code to seed the data model 
-     * ported over from the individual classes. This seems ugly and unnecessary.
-     * We really might as well just expose pretty much 
-     * the same tree to all our tests. (JR)
-     */
-    @Override
-    @SuppressWarnings("boxing")
-    public void setUp() throws Exception {
-        confB.setTemplateLoader(
-                new CopyrightCommentRemoverTemplateLoader(
-                        new ClassTemplateLoader(TemplateTestCase.class, "templates")));
-        
-        DefaultObjectWrapper dow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
-        
-        dataModel.put(ASSERT_VAR_NAME, AssertDirective.INSTANCE);
-        dataModel.put(ASSERT_EQUALS_VAR_NAME, AssertEqualsDirective.INSTANCE);
-        dataModel.put(ASSERT_FAILS_VAR_NAME, AssertFailsDirective.INSTANCE);
-        dataModel.put(NO_OUTPUT_VAR_NAME, NoOutputDirective.INSTANCE);
-
-        dataModel.put(JAVA_OBJECT_INFO_VAR_NAME, JavaObjectInfo.INSTANCE);
-        dataModel.put(TEST_NAME_VAR_NAME, simpleTestName);
-        dataModel.put(ICI_INT_VALUE_VAR_NAME, confB.getIncompatibleImprovements().intValue());
-        
-        dataModel.put("message", "Hello, world!");
-
-        if (simpleTestName.startsWith("api-builtin")) {
-            dataModel.put("map", ImmutableMap.of(1, "a", 2, "b", 3, "c"));
-            dataModel.put("list", ImmutableList.of(1, 2, 3));
-            dataModel.put("set", ImmutableSet.of("a", "b", "c"));
-            dataModel.put("s", "test");
-        } else if (simpleTestName.equals("default-object-wrapper")) {
-            dataModel.put("array", new String[] { "array-0", "array-1"});
-            dataModel.put("list", Arrays.asList("list-0", "list-1", "list-2"));
-            Map<Object, Object> tmap = new HashMap<>();
-            tmap.put("key", "value");
-            Object objKey = new Object();
-            tmap.put(objKey, "objValue");
-            dataModel.put("map", tmap);
-            dataModel.put("objKey", objKey);
-            dataModel.put("obj", new org.apache.freemarker.test.templatesuite.models.BeanTestClass());
-            dataModel.put("resourceBundle",
-                    new ResourceBundleModel(ResourceBundle.getBundle(
-                            "org.apache.freemarker.test.templatesuite.models.BeansTestResources"), dow));
-            dataModel.put("date", new GregorianCalendar(1974, 10, 14).getTime());
-            dataModel.put("statics", dow.getStaticModels());
-            dataModel.put("enums", dow.getEnumModels());
-        } else if (simpleTestName.equals("boolean")) {
-            dataModel.put( "boolean1", TemplateBooleanModel.FALSE);
-            dataModel.put( "boolean2", TemplateBooleanModel.TRUE);
-            dataModel.put( "boolean3", TemplateBooleanModel.TRUE);
-            dataModel.put( "boolean4", TemplateBooleanModel.TRUE);
-            dataModel.put( "boolean5", TemplateBooleanModel.FALSE);
-            
-            dataModel.put( "list1", new BooleanList1(dow) );
-            dataModel.put( "list2", new BooleanList2(dow) );
-    
-            dataModel.put( "hash1", new BooleanHash1() );
-            dataModel.put( "hash2", new BooleanHash2() );
-        } else if (simpleTestName.startsWith("dateformat")) {
-            GregorianCalendar cal = new GregorianCalendar(2002, 10, 15, 14, 54, 13);
-            cal.setTimeZone(TimeZone.getTimeZone("GMT"));
-            dataModel.put("date", new SimpleDate(cal.getTime(), TemplateDateModel.DATETIME));
-            dataModel.put("unknownDate", new SimpleDate(cal.getTime(), TemplateDateModel.UNKNOWN));
-            dataModel.put("javaGMT02", TimeZone.getTimeZone("GMT+02"));
-            dataModel.put("javaUTC", TimeZone.getTimeZone("UTC"));
-            dataModel.put("adaptedToStringScalar", new Object() {
-                @Override
-                public String toString() {
-                    return "GMT+02";
-                }
-            });
-            dataModel.put("sqlDate", new java.sql.Date(1273955885023L));
-            dataModel.put("sqlTime", new java.sql.Time(74285023L));
-        } else if (
-                templateName.equals("list.ftl") || templateName.equals("list2.ftl") || templateName.equals("list3.ftl")
-                || simpleTestName.equals("listhash")) {
-            dataModel.put("listables", new Listables());
-        } else if (simpleTestName.startsWith("number-format")) {
-            dataModel.put("int", new SimpleNumber(Integer.valueOf(1)));
-            dataModel.put("double", new SimpleNumber(Double.valueOf(1.0)));
-            dataModel.put("double2", new SimpleNumber(Double.valueOf(1 + 1e-15)));
-            dataModel.put("double3", new SimpleNumber(Double.valueOf(1e-16)));
-            dataModel.put("double4", new SimpleNumber(Double.valueOf(-1e-16)));
-            dataModel.put("bigDecimal", new SimpleNumber(java.math.BigDecimal.valueOf(1)));
-            dataModel.put("bigDecimal2", new SimpleNumber(java.math.BigDecimal.valueOf(1, 16)));
-        } else if (simpleTestName.equals("simplehash-char-key")) {
-            HashMap<String, String> mStringC = new HashMap<>();
-            mStringC.put("c", "string");
-            dataModel.put("mStringC", mStringC);
-            
-            HashMap<String, String> mStringCNull = new HashMap<>();
-            mStringCNull.put("c", null);
-            dataModel.put("mStringCNull", mStringCNull);
-            
-            HashMap<Character, String> mCharC = new HashMap<>();
-            mCharC.put(Character.valueOf('c'), "char");
-            dataModel.put("mCharC", mCharC);
-            
-            HashMap<String, String> mCharCNull = new HashMap<>();
-            mCharCNull.put("c", null);
-            dataModel.put("mCharCNull", mCharCNull);
-            
-            HashMap<Object, String> mMixed = new HashMap<>();
-            mMixed.put(Character.valueOf('c'), "char");
-            mMixed.put("s", "string");
-            mMixed.put("s2", "string2");
-            mMixed.put("s2n", null);
-            dataModel.put("mMixed", mMixed);
-        } else if (simpleTestName.equals("default-xmlns")) {
-            InputSource is = new InputSource(getClass().getResourceAsStream("models/defaultxmlns1.xml"));
-            NodeModel nm = XMLLoader.toModel(is);
-            dataModel.put("doc", nm);
-        } else if (simpleTestName.equals("multimodels")) {
-            dataModel.put("test", "selftest");
-            dataModel.put("self", "self");
-            dataModel.put("zero", Integer.valueOf(0));
-            dataModel.put("data", new MultiModel1());
-        } else if (simpleTestName.equals("stringbimethods")) {
-            dataModel.put("multi", new TestBoolean());
-        } else if (simpleTestName.startsWith("type-builtins")) {
-            dataModel.put("testmethod", new TestMethod());
-            dataModel.put("testnode", new TestNode());
-            dataModel.put("testcollection", new SimpleCollection(new ArrayList<>(), dow));
-            dataModel.put("testcollectionEx", DefaultNonListCollectionAdapter.adapt(new HashSet<>(), dow));
-            dataModel.put("bean", new TestBean());
-        } else if (simpleTestName.equals("date-type-builtins")) {
-            GregorianCalendar cal = new GregorianCalendar(2003, 4 - 1, 5, 6, 7, 8);
-            cal.setTimeZone(TimeZone.getTimeZone("UTC"));
-            Date d = cal.getTime();
-            dataModel.put("unknown", d);
-            dataModel.put("timeOnly", new java.sql.Time(d.getTime()));
-            dataModel.put("dateOnly", new java.sql.Date(d.getTime()));
-            dataModel.put("dateTime", new java.sql.Timestamp(d.getTime()));
-        } else if (simpleTestName.equals("var-layers")) {
-            dataModel.put("x", Integer.valueOf(4));
-            dataModel.put("z", Integer.valueOf(4));
-            confB.setSharedVariable("y", Integer.valueOf(7));
-        } else if (simpleTestName.equals("xml-fragment")) {
-            DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
-            f.setNamespaceAware(true);
-            DocumentBuilder db = f.newDocumentBuilder();
-            org.w3c.dom.Document doc = db.parse(new InputSource(getClass().getResourceAsStream("models/xmlfragment.xml")));
-            NodeModel.simplify(doc);
-            dataModel.put("node", NodeModel.wrap(doc.getDocumentElement().getFirstChild().getFirstChild()));
-        } else if (simpleTestName.equals("xmlns1")) {
-            InputSource is = new InputSource(getClass().getResourceAsStream("models/xmlns.xml"));
-            NodeModel nm = XMLLoader.toModel(is);
-            dataModel.put("doc", nm);
-        } else if (simpleTestName.equals("xmlns2")) {
-            InputSource is = new InputSource(getClass().getResourceAsStream("models/xmlns2.xml"));
-            NodeModel nm = XMLLoader.toModel(is);
-            dataModel.put("doc", nm);
-        } else if (simpleTestName.equals("xmlns3") || simpleTestName.equals("xmlns4")) {
-            InputSource is = new InputSource(getClass().getResourceAsStream("models/xmlns3.xml"));
-            NodeModel nm = XMLLoader.toModel(is);
-            dataModel.put("doc", nm);
-        } else if (simpleTestName.equals("xmlns5")) {
-            InputSource is = new InputSource(getClass().getResourceAsStream("models/defaultxmlns1.xml"));
-            NodeModel nm = XMLLoader.toModel(is);
-            dataModel.put("doc", nm);
-        } else if (simpleTestName.equals("xml-ns_prefix-scope")) {
-            InputSource is = new InputSource(getClass().getResourceAsStream("models/xml-ns_prefix-scope.xml"));
-            NodeModel nm = XMLLoader.toModel(is);
-            dataModel.put("doc", nm);
-        } else if (simpleTestName.startsWith("sequence-builtins")) {
-            Set<String> abcSet = new TreeSet<>();
-            abcSet.add("a");
-            abcSet.add("b");
-            abcSet.add("c");
-            dataModel.put("abcSet", abcSet);
-            dataModel.put("abcSetNonSeq", DefaultNonListCollectionAdapter.adapt(abcSet, dow));
-            
-            List<String> listWithNull = new ArrayList<>();
-            listWithNull.add("a");
-            listWithNull.add(null);
-            listWithNull.add("c");
-            dataModel.put("listWithNull", listWithNull);
-            
-            List<String> listWithNullsOnly = new ArrayList<>();
-            listWithNull.add(null);
-            listWithNull.add(null);
-            listWithNull.add(null);
-            dataModel.put("listWithNullsOnly", listWithNullsOnly);
-            
-            dataModel.put("abcCollection", new SimpleCollection(abcSet, dow));
-            
-            Set<String> set = new HashSet<>();
-            set.add("a");
-            set.add("b");
-            set.add("c");
-            dataModel.put("set", set);
-        } else if (simpleTestName.equals("number-to-date")) {
-          dataModel.put("bigInteger", new BigInteger("1305575275540"));
-          dataModel.put("bigDecimal", new BigDecimal("1305575275539.5"));
-        } else if (simpleTestName.equals("varargs")) {
-          dataModel.put("m", new VarArgTestModel());
-        } else if (simpleTestName.startsWith("boolean-formatting")) {
-          dataModel.put("booleanAndString", new BooleanAndStringTemplateModel());
-          dataModel.put("booleanVsStringMethods", new BooleanVsStringMethods());
-        } else if (simpleTestName.startsWith("number-math-builtins")) {
-            dataModel.put("fNan", Float.valueOf(Float.NaN));
-            dataModel.put("dNan", Double.valueOf(Double.NaN));
-            dataModel.put("fNinf", Float.valueOf(Float.NEGATIVE_INFINITY));
-            dataModel.put("dPinf", Double.valueOf(Double.POSITIVE_INFINITY));
-            
-            dataModel.put("fn", Float.valueOf(-0.05f));
-            dataModel.put("dn", Double.valueOf(-0.05));
-            dataModel.put("ineg", Integer.valueOf(-5));
-            dataModel.put("ln", Long.valueOf(-5));
-            dataModel.put("sn", Short.valueOf((short) -5));
-            dataModel.put("bn", Byte.valueOf((byte) -5));
-            dataModel.put("bin", BigInteger.valueOf(5));
-            dataModel.put("bdn", BigDecimal.valueOf(-0.05));
-            
-            dataModel.put("fp", Float.valueOf(0.05f));
-            dataModel.put("dp", Double.valueOf(0.05));
-            dataModel.put("ip", Integer.valueOf(5));
-            dataModel.put("lp", Long.valueOf(5));
-            dataModel.put("sp", Short.valueOf((short) 5));
-            dataModel.put("bp", Byte.valueOf((byte) 5));
-            dataModel.put("bip", BigInteger.valueOf(5));
-            dataModel.put("bdp", BigDecimal.valueOf(0.05));
-        } else if (simpleTestName.startsWith("overloaded-methods")) {
-            dataModel.put("obj", new OverloadedMethods2());
-        }
-    }
-    
-    @Override
-    public void runTest() throws IOException, ConfigurationException {
-        Template template;
-        try {
-            template = confB.build().getTemplate(templateName);
-        } catch (IOException e) {
-            throw new AssertionFailedError(
-                    "Could not load template " + _StringUtil.jQuote(templateName) + ":\n" + getStackTrace(e));
-        }
-        ASTPrinter.validateAST(template);
-        
-        StringWriter out = noOutput ? null : new StringWriter();
-        try {
-            template.process(dataModel, out != null ? out : _NullWriter.INSTANCE);
-        } catch (TemplateException e) {
-            throw new AssertionFailedError("Template " + _StringUtil.jQuote(templateName) + " has stopped with error:\n"
-                        + getStackTrace(e));
-        }
-        
-        if (out != null) {
-            assertExpectedFileEqualsString(expectedFileName, out.toString());
-        }
-    }
-
-    private String getStackTrace(Throwable e) {
-        StringWriter sw = new StringWriter();
-        e.printStackTrace(new PrintWriter(sw));
-        return sw.toString();
-    }
-
-    @Override
-    protected String getExpectedContentFileDirectoryResourcePath() throws IOException {
-        return joinResourcePaths(super.getExpectedContentFileDirectoryResourcePath(), "expected");
-    }
-
-    @Override
-    protected Charset getTestResourceDefaultCharset() {
-        return confB.getOutputEncoding() != null ? confB.getOutputEncoding() : StandardCharsets.UTF_8;
-    }
-
-    static class TestBoolean implements TemplateBooleanModel, TemplateScalarModel {
-        @Override
-        public boolean getAsBoolean() {
-            return true;
-        }
-        
-        @Override
-        public String getAsString() {
-            return "de";
-        }
-    }
-
-    static class TestMethod implements TemplateMethodModel {
-        @Override
-        public Object exec(List arguments) {
-            return "x";
-        }
-    }
-
-    static class TestNode implements TemplateNodeModel {
-
-        @Override
-        public String getNodeName() {
-            return "name";
-        }
-
-        @Override
-        public TemplateNodeModel getParentNode() {
-            return null;
-        }
-
-        @Override
-        public String getNodeType() {
-            return "element";
-        }
-
-        @Override
-        public TemplateSequenceModel getChildNodes() {
-            return null;
-        }
-
-        @Override
-        public String getNodeNamespace() {
-            return null;
-        }
-    }
-
-   public Object getTestMapBean() {
-        Map<String, Object> testBean = new TestMapBean();
-        testBean.put("name", "Chris");
-        testBean.put("location", "San Francisco");
-        testBean.put("age", Integer.valueOf(27));
-        return testBean;
-    }
-
-    public static class TestMapBean extends HashMap<String, Object> {
-        public String getName() {
-            return "Christopher";
-        }
-        public int getLuckyNumber() {
-            return 7;
-        }
-    }
-
-    public static class TestBean {
-
-        public int m(int n) {
-            return n * 10;
-        }
-
-        public int mOverloaded(int n) {
-            return n * 10;
-        }
-
-        public String mOverloaded(String s) {
-            return s.toUpperCase();
-        }
-        
-    }
-    
-}


[26/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/multimodels.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/multimodels.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/multimodels.ftl
new file mode 100644
index 0000000..f356386
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/multimodels.ftl
@@ -0,0 +1,84 @@
+<#--
+  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.
+-->
+<html>
+<head>
+<title>FreeMarker: Test of Multiple Model implementations</title>
+</head>
+<body>
+
+<p>Let's begin with a simple model:</p>
+<p>${message}</p>
+
+<p>Cool, now get into the first model. This implements a scalar, list, and
+hash as a single class. Let's try some tests...</p>
+
+<p>${data}</p>
+
+<p>Now as a list...</p>
+
+<#list data as item>${item}<br />
+</#list>
+
+<p>Index into a list...</p>
+<p>${data[ 1 ]}</p>
+<p>List size is: ${data.size}</p>
+<p>List size is: ${data["size"]}</p>
+
+<p>Now, again, as a hash. First using dot notation, then using [] notation:</p>
+
+<p>${data.selftest}</p>
+<p>${data["selftest"]}</p>
+
+<p>Now for the tricky stuff... use a model to index into another model...</p>
+<p>${test}</p>
+<p>${data[ test ]}</p>
+<p>${self}</p>
+<p>${data[ self + "test" ]}</p>
+
+<p>Same thing, this time a List index...</p>
+<p>${zero}</p>
+<p>${data[ zero ]}</p>
+<p>${data[ zero + 1 ]}</p>
+
+<p>Now, do the same recursively...</p>
+<p>${data}</p>
+<p>${data.model2}</p>
+<p>${data.model2( "test" )}</p>
+<p>${data.model2( data, data.selftest, message )}</p>
+
+<p>Does this really not work?</p>
+<p>${data[ 10 ]}</p>
+<p>${data[ 10 ].selftest}</p>
+<p>${data[ 10 ].message}</p>
+
+<p>(Again, with Hashes)</p>
+<p>${data.nesting1.nested}</p>
+<p>${data.nesting1.nested.selftest}</p>
+
+<p>${data["nesting1"].nested}</p>
+<p>${data["nesting1"].nested["selftest"]}</p>
+<p>${data["nesting1"]["nested"]["selftest"]}</p>
+
+<p>As I suspected! (Manual on Expressions needs updating.)</p>
+
+<p>Second test on list size</p>
+<p>${data.one.size}</p>
+<p>${data.one["size"]}</p>
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/nested.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/nested.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/nested.ftl
new file mode 100644
index 0000000..46f4492
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/nested.ftl
@@ -0,0 +1,29 @@
+<#--
+  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.
+-->
+<#macro repeat count>
+  <#local y = "test">
+  <#list 1..count as x>
+    ${y} ${count}/${x}: <#nested x, "asdf"> <#-- the second body parameter is not used below -->
+  </#list>
+</#macro>
+<@repeat count=3>${y?default("undefined")} ${x?default("undefined")} ${count?default("undefined")}</...@repeat>
+<#global x = "X">
+<#global y = "Y">
+<#global count = "Count">
+<@repeat count=3 ; param1>${y?default("undefined")} ${x?default("undefined")} ${count?default("undefined")} ${param1}</...@repeat>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/nestedinclude.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/nestedinclude.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/nestedinclude.ftl
new file mode 100644
index 0000000..c6e7b11
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/nestedinclude.ftl
@@ -0,0 +1,21 @@
+<#--
+  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.
+-->
+<#assign nestedMessage = "I'm here, mon!">
+${.main.bar}
+<#-- ${.root.message} -->

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/new-defaultresolver.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/new-defaultresolver.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/new-defaultresolver.ftl
new file mode 100644
index 0000000..9efcd88
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/new-defaultresolver.ftl
@@ -0,0 +1,23 @@
+<#--
+  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.
+-->
+<#attempt>
+${"org.apache.freemarker.test.templatesuite.models.NewTestModel"?new("works")}
+<#recover>
+fails
+</#attempt>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/new-optin.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/new-optin.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/new-optin.ftl
new file mode 100644
index 0000000..7545b58
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/new-optin.ftl
@@ -0,0 +1,30 @@
+<#--
+  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.
+-->
+${"org.apache.freemarker.test.templatesuite.models.NewTestModel"?new("works")}
+<#attempt>
+${"org.apache.freemarker.test.templatesuite.models.NewTestModel2"?new("works")}
+<#recover>
+fails
+</#attempt>
+
+<#include "subdir/new-optin.ftl">
+
+<#include "subdir/new-optin-2.ftl">
+
+<#include "subdir/subsub/new-optin.ftl">
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/newlines1.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/newlines1.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/newlines1.ftl
new file mode 100644
index 0000000..18f4b32
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/newlines1.ftl
@@ -0,0 +1,29 @@
+<#--
+  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.
+-->
+<html>
+<head>
+<title>FreeMarker: Newlines Test</title>
+</head>
+<body>
+<p>A simple test follows:</p>
+
+<p>${message}</p>
+
+</body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/newlines2.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/newlines2.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/newlines2.ftl
new file mode 100644
index 0000000..ac8337c
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/newlines2.ftl
@@ -0,0 +1,33 @@
+<#--
+  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.
+-->
+<#assign message="Hello, world!\n">
+<#assign normalizeNewlines = "org.apache.freemarker.core.util.NormalizeNewlines"?new()>
+<@normalizeNewlines>
+<html>
+<head>
+<title>FreeMarker: Newlines the Second Test</title>
+</head>
+<body>
+<p>A simple test follows:</p>
+
+<p>${message}</p>
+
+</body>
+</html>
+</...@normalizeNewlines>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/noparse.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/noparse.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/noparse.ftl
new file mode 100644
index 0000000..f7f1be3
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/noparse.ftl
@@ -0,0 +1,62 @@
+<#--
+  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.
+-->
+<html>
+<head>
+<title>FreeMarker: NoParse Test</title>
+</head>
+<body>
+<#noparse>
+
+A simple test follows:
+
+${message}
+
+A more rigorous test, showing that we're not faking it:
+
+${message@#$%&}
+
+</#noparse>
+<#if message?exists>
+	<p>Message exists!
+	<#noparse>
+		...and even generates output!
+		<#if message>
+			Nested statements are ok, too.
+		</#if>
+	</#noparse>
+	</p>
+</#if>
+
+Here's another edge case, this time, trying to output a &lt;noparse&gt;
+inside another &lt;noparse&gt;
+
+<#noparse>
+
+This is what the noparse instruction looks like:
+
+<#nop</#noparse><#noparse>arse>This part of the template wont be parsed by the 
+FreeMarker parser. Instead, it will be treated as verbatim text information,
+and output as such.</#nop</#noparse><#noparse>arse>
+
+The rest of the template appears here.
+</#noparse>
+
+Simple.
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/number-format.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/number-format.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/number-format.ftl
new file mode 100644
index 0000000..d060a44
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/number-format.ftl
@@ -0,0 +1,42 @@
+<#--
+  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.
+-->
+<#setting number_format = ",##0.##">
+<#setting locale = "fr_FR">
+${1}
+${1?c}
+${1234567.886}
+${1234567.886?c}
+<#setting number_format = "0.00">
+${1}
+${1?c}
+${1234567.886}
+${1234567.886?c}
+${int?c}
+${double?c}
+${double2?c}
+${double3?c}
+${double4?c}
+${bigDecimal?c}
+${bigDecimal2?c}
+<@assertEquals expected="INF" actual="INF"?number?c />
+<@assertEquals expected="INF" actual="INF"?number?c />
+<@assertEquals expected="-INF" actual="-INF"?number?c />
+<@assertEquals expected="-INF" actual="-INF"?number?float?c />
+<@assertEquals expected="NaN" actual="NaN"?number?float?c />
+<@assertEquals expected="NaN" actual="NaN"?number?float?c />

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/number-literal.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/number-literal.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/number-literal.ftl
new file mode 100644
index 0000000..6342afe
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/number-literal.ftl
@@ -0,0 +1,133 @@
+<#--
+  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.
+-->
+<html>
+<head>
+<title>FreeMarker: Number Literal Test</title>
+</head>
+<body>
+<#assign hash = {"1" : "one", 
+                 "12" : "twelve", 
+                "2one" : "two-one", 
+                "one2" : "one-two"}
+         list = ["zero", 
+                 "one", 
+                 "two", 
+                 "three", 
+                 "four", 
+                 "five", 
+                 "six", 
+                 "seven", 
+                 "eight", 
+                 "nine", 
+                 "ten",
+                 "eleven",
+                 "twelve"],
+          foo = "bar",
+          one = "one",
+          "1" = "one",
+          "12" = "twelve",
+          "2one" = "two-one",
+          "one2" = "one-two",
+          call = "org.apache.freemarker.test.templatesuite.models.SimpleTestMethod"?new()
+>
+
+<p>A simple test follows:</p>
+
+<p>${message}</p>
+
+<p>Now perform a number assignment:</p>
+
+#{1.300000?double}
+
+<#assign mynumber = 1.8, USA="en_US" />
+<#assign myfloat = mynumber?float />
+
+My number is: ${mynumber}
+<#setting locale="en_US">
+My float is: #{myfloat ; m6}
+The int part is: ${myfloat?int}
+
+<#assign mymessage = mynumber?string>
+
+${mymessage + 3}
+
+<p>Now use numbers in assignment</p>
+
+<#assign mymessage = 1 + 5>
+${mymessage}
+
+<#assign mymessage = mymessage + 2>
+#{mymessage}
+
+<p>Try numbers in tests</p>
+
+<#if (mymessage == 152)>
+MyMessage is 152
+<#else>
+MyMessage is not 152, its: ${mymessage}.
+</#if >
+
+<if (mymessage > 5)>
+   MyMessage is greater than five.
+</if
+
+<#switch mymessage>
+	<#case 1>
+		MyMessage is one
+		<#break>
+
+	<#case 15>
+		MyMessage is fifteen
+		<#break>
+	
+	<#case 152>
+		MyMessage is one-five-two
+		<#break>
+	
+	<#default>
+		MyMessage is: ${mymessage}.
+		<#break>
+	
+</#switch>
+
+<p>Now for numbers in dynamic keys:</p>
+
+<#assign one = 1>
+<#assign two = 2>
+
+${list[ 1 ]}
+${list[ 1 + 2 ]}
+
+<p>Numbers in hashes:</p>
+
+${hash[ 1 + "2" ]}
+${hash[ "1" + 2 ]}
+${hash[ "1" + two ]}
+
+
+<p>Numbers in method calls:</p>
+
+${call( 1 )}
+${call( one )}
+${call( one + "2" )}
+${call( one + 2 )}
+${call( 1 + 2 )}
+
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/number-math-builtins.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/number-math-builtins.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/number-math-builtins.ftl
new file mode 100644
index 0000000..6dab082
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/number-math-builtins.ftl
@@ -0,0 +1,78 @@
+<#--
+  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.
+-->
+<@assertEquals actual=0?abs expected=0 />
+<@assertEquals actual=3?abs expected=3 />
+<@assertEquals actual=(-3)?abs expected=3 />
+<@assertEquals actual=3.5?abs expected=3.5 />
+<@assertEquals actual=(-3.5)?abs expected=3.5 />
+
+<@assert test=fNan?abs?is_nan />
+<@assert test=dNan?abs?is_nan />
+<@assert test=fNinf?abs?is_infinite />
+<@assert test=dPinf?abs?is_infinite />
+<@assert test=fNinf lt 0 />
+<@assert test=dPinf gt 0 />
+<@assert test=fNinf?abs gt 0 />
+<@assert test=dPinf?abs gt 0 />
+
+<@assertEquals actual=fn?abs expected=0.05 />
+<@assertEquals actual=dn?abs expected=0.05 />
+<@assertEquals actual=ineg?abs expected=5 />
+<@assertEquals actual=ln?abs expected=5 />
+<@assertEquals actual=sn?abs expected=5 />
+<@assertEquals actual=bn?abs expected=5 />
+<@assertEquals actual=bin?abs expected=5 />
+<@assertEquals actual=bdn?abs expected=0.05 />
+
+<@assertEquals actual=fp?abs expected=0.05 />
+<@assertEquals actual=dp?abs expected=0.05 />
+<@assertEquals actual=ip?abs expected=5 />
+<@assertEquals actual=lp?abs expected=5 />
+<@assertEquals actual=sp?abs expected=5 />
+<@assertEquals actual=bp?abs expected=5 />
+<@assertEquals actual=bip?abs expected=5 />
+<@assertEquals actual=bdp?abs expected=0.05 />
+
+<@assert test=!0?is_infinite />
+<@assert test=!fn?is_infinite />
+<@assert test=!dn?is_infinite />
+<@assert test=!ineg?is_infinite />
+<@assert test=!ln?is_infinite />
+<@assert test=!sn?is_infinite />
+<@assert test=!bn?is_infinite />
+<@assert test=!bin?is_infinite />
+<@assert test=!bdn?is_infinite />
+<@assert test=!fNan?is_infinite />
+<@assert test=!dNan?is_infinite />
+<@assert test=fNinf?is_infinite />
+<@assert test=dPinf?is_infinite />
+
+<@assert test=!0?is_nan />
+<@assert test=!fn?is_nan />
+<@assert test=!dn?is_nan />
+<@assert test=!ineg?is_nan />
+<@assert test=!ln?is_nan />
+<@assert test=!sn?is_nan />
+<@assert test=!bn?is_nan />
+<@assert test=!bin?is_nan />
+<@assert test=!bdn?is_nan />
+<@assert test=fNan?is_nan />
+<@assert test=dNan?is_nan />
+<@assert test=!fNinf?is_nan />
+<@assert test=!dPinf?is_nan />
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/number-to-date.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/number-to-date.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/number-to-date.ftl
new file mode 100644
index 0000000..403e033
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/number-to-date.ftl
@@ -0,0 +1,35 @@
+<#--
+  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.
+-->
+${1305575275540?number_to_datetime?iso_utc_ms} == 2011-05-16T19:47:55.54Z
+${1305575275540?number_to_date?iso_utc} == 2011-05-16
+${1305575275540?number_to_time?iso_utc_ms} == 19:47:55.54Z
+
+${1305575275540?long?number_to_datetime?iso_utc_ms} == 2011-05-16T19:47:55.54Z
+${1305575275540?double?number_to_datetime?iso_utc_ms} == 2011-05-16T19:47:55.54Z
+${bigInteger?number_to_datetime?iso_utc_ms} == 2011-05-16T19:47:55.54Z
+${bigDecimal?number_to_datetime?iso_utc_ms} == 2011-05-16T19:47:55.54Z
+${1000?float?number_to_datetime?iso_utc} == 1970-01-01T00:00:01Z
+${1000?int?number_to_datetime?iso_utc} == 1970-01-01T00:00:01Z
+${0?byte?number_to_datetime?iso_utc} == 1970-01-01T00:00:00Z
+
+<#attempt>
+${9999991305575275540?number_to_datetime?iso_utc} <#-- doesn't fit into long -->
+<#recover>
+failed
+</#attempt>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/numerical-cast.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/numerical-cast.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/numerical-cast.ftl
new file mode 100644
index 0000000..221b61b
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/numerical-cast.ftl
@@ -0,0 +1,82 @@
+<#ftl>
+<#--
+  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.
+-->
+<#setting locale="en_US">
+<#setting number_format="0.#########">
+
+<#assign testlist= [ 0, 1, -1, 0.5, 1.5, -0.5,
+	 -1.5, 0.25, -0.25, 1.75, -1.75,
+	 1.01, -1.01, 0.01, -0.01,
+	 127, 128, -127, -128,
+	 32767, 32768, -32767, -32768,
+	 2147483647, 2147483648, -2147483647, -2147483648,
+	 4294967295, 4294967296, -4294967295, -4294967296,
+	 2147483647.1, 2147483648.1, -2147483647.1, -2147483648.1,
+	 4294967295.1, 4294967296.1, -4294967295.1, -4294967296.1
+	 2147483647.5, 2147483648.5, -2147483647.5, -2147483648.5,
+	 4294967295.5, 4294967296.5, -4294967295.5, -4294967296.5
+  ] />
+
+?int:
+<#list testlist as result>
+    ${result}?int=${result?int}
+</#list>
+
+?double
+<#list testlist as result>
+    ${result}?double=${result?double}
+</#list>
+
+?long
+<#list testlist as result>
+    ${result}?long=${result?long}
+</#list>
+
+?long from date
+    ${"2011-05-08 18:00:15 GMT"?date("yyyy-MM-dd HH:mm:ss z")?long} = 1304877615000
+
+?float
+<#list testlist as result>
+    ${result}?float=${result?float}
+</#list>
+
+?byte
+<#list testlist as result>
+    ${result}?byte=${result?byte}
+</#list>
+
+?short
+<#list testlist as result>
+    ${result}?short=${result?short}
+</#list>
+
+?floor
+<#list testlist as result>
+    ${result}?floor=${result?floor}
+</#list>
+
+?ceiling
+<#list testlist as result>
+    ${result}?ceiling=${result?ceiling}
+</#list>
+
+?round
+<#list testlist as result>
+    ${result}?round=${result?round}
+</#list>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/output-encoding1.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/output-encoding1.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/output-encoding1.ftl
new file mode 100644
index 0000000..da1128f
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/output-encoding1.ftl
@@ -0,0 +1,30 @@
+<#--
+  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.
+-->
+Output charset: ${.output_encoding?default("undefined")}
+URL escaping charset: ${.url_escaping_charset?default("undefined")}
+
+<#assign s="a/%b">
+<#setting url_escaping_charset="UTF-16">
+${s?url}
+${s?url}
+<#setting url_escaping_charset="ISO-8859-1">
+${s?url}
+${s?url}
+${s?url('UTF-16')}
+${s?url}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/output-encoding2.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/output-encoding2.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/output-encoding2.ftl
new file mode 100644
index 0000000..3a4f24d
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/output-encoding2.ftl
@@ -0,0 +1,28 @@
+<#--
+  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.
+-->
+Output charset: ${.output_encoding?default("undefined")}
+URL escaping charset: ${.url_escaping_charset?default("undefined")}
+
+<#assign s="a/%b">
+UTF-16: ${s?url}
+ISO-8859-1: ${s?url('ISO-8859-1')}
+UTF-16: ${s?url}
+<#setting url_escaping_charset="ISO-8859-1">
+ISO-8859-1: ${s?url}
+ISO-8859-1: ${s?url}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/output-encoding3.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/output-encoding3.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/output-encoding3.ftl
new file mode 100644
index 0000000..3a4f24d
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/output-encoding3.ftl
@@ -0,0 +1,28 @@
+<#--
+  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.
+-->
+Output charset: ${.output_encoding?default("undefined")}
+URL escaping charset: ${.url_escaping_charset?default("undefined")}
+
+<#assign s="a/%b">
+UTF-16: ${s?url}
+ISO-8859-1: ${s?url('ISO-8859-1')}
+UTF-16: ${s?url}
+<#setting url_escaping_charset="ISO-8859-1">
+ISO-8859-1: ${s?url}
+ISO-8859-1: ${s?url}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/overloaded-methods.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/overloaded-methods.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/overloaded-methods.ftl
new file mode 100644
index 0000000..329d041
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/overloaded-methods.ftl
@@ -0,0 +1,411 @@
+<#--
+  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.
+-->
+
+<@assertEquals actual=obj.mStringArrayVsListPreference(obj.javaStringList) expected="mStringArrayVsListPreference(List [a, b])" />
+<@assertEquals actual=obj.mStringArrayVsListPreference(obj.javaStringArray) expected="mStringArrayVsListPreference(String[] [a, b])" />
+<@assertEquals actual=obj.mStringArrayVsListPreference(obj.javaObjectArray) expected="mStringArrayVsListPreference(List [a, b])" />
+
+<#-- Check if non-overloaded calls still work; they share some code with overloaded methods: -->
+<@assertEquals actual=obj.mIntArrayNonOverloaded([1, 2, 3]) expected="mIntArrayNonOverloaded(int[] [1, 2, 3])" />
+<@assertEquals actual=obj.mIntegerArrayNonOverloaded([1, 2, 3]) expected="mIntegerArrayNonOverloaded(Integer[] [1, 2, 3])" />
+<@assertEquals actual=obj.mIntegerListNonOverloaded([1, 2, 3]) expected="mIntegerListNonOverloaded(List<Integer> [1, 2, 3])" />
+<@assertEquals actual=obj.mStringListNonOverloaded(['a', 'b', 'c']) expected="mStringListNonOverloaded(List<String> [a, b, c])" />
+<@assertEquals actual=obj.mStringListNonOverloaded(obj.javaStringList) expected="mStringListNonOverloaded(List<String> [a, b])" />
+<@assertEquals actual=obj.mStringListNonOverloaded(obj.javaStringArray) expected="mStringListNonOverloaded(List<String> [a, b])" />
+<@assertEquals actual=obj.mStringArrayNonOverloaded(['a', 'b', 'c']) expected="mStringArrayNonOverloaded(String[] [a, b, c])" />
+<@assertEquals actual=obj.mStringArrayNonOverloaded(obj.javaStringList) expected="mStringArrayNonOverloaded(String[] [a, b])" />
+<@assertEquals actual=obj.mStringArrayNonOverloaded(obj.javaStringArray) expected="mStringArrayNonOverloaded(String[] [a, b])" />
+<@assertEquals actual=obj.mObjectListNonOverloaded(['a', 'b', 3]) expected="mObjectListNonOverloaded(List<Object> [a, b, 3])" />
+<@assertEquals actual=obj.mObjectListNonOverloaded(obj.javaStringList) expected="mObjectListNonOverloaded(List<Object> [a, b])" />
+<@assertEquals actual=obj.mObjectListNonOverloaded(obj.javaStringArray) expected="mObjectListNonOverloaded(List<Object> [a, b])" />
+<@assertEquals actual=obj.mObjectArrayNonOverloaded(['a', 'b', 3]) expected="mObjectArrayNonOverloaded(Object[] [a, b, 3])" />
+<@assertEquals actual=obj.mObjectArrayNonOverloaded(obj.javaStringList) expected="mObjectArrayNonOverloaded(Object[] [a, b])" />
+<@assertEquals actual=obj.mObjectArrayNonOverloaded(obj.javaStringArray) expected="mObjectArrayNonOverloaded(Object[] [a, b])" />
+
+<@assertEquals actual=obj.mStringArrayVsListPreference(obj.javaStringArray) expected="mStringArrayVsListPreference(String[] [a, b])" />
+
+<@assertEquals actual=obj.mStringArrayVarargsNonOverloaded('a', 'b') expected="mStringArrayVarargsNonOverloaded(String[] [a, b])" />
+<@assertEquals actual=obj.mStringArrayVarargsNonOverloaded(['a', 'b']) expected="mStringArrayVarargsNonOverloaded(String[] [a, b])" />
+<@assertEquals actual=obj.mStringArrayVarargsNonOverloaded(obj.javaStringList) expected="mStringArrayVarargsNonOverloaded(String[] [a, b])" />
+<@assertEquals actual=obj.mStringArrayVarargsNonOverloaded(obj.javaStringArray) expected="mStringArrayVarargsNonOverloaded(String[] [a, b])" />
+
+<@assertEquals actual=obj.mStringArrayVarargsOverloaded1('a', 'b') expected="mStringArrayVarargsOverloaded1(String[] [a, b])" />
+<@assertEquals actual=obj.mStringArrayVarargsOverloaded1(['a', 'b']) expected="mStringArrayVarargsOverloaded1(List [a, b])" />
+<@assertEquals actual=obj.mStringArrayVarargsOverloaded1(obj.javaStringList) expected="mStringArrayVarargsOverloaded1(List [a, b])" />
+<@assertEquals actual=obj.mStringArrayVarargsOverloaded1(obj.javaStringArray) expected="mStringArrayVarargsOverloaded1(String[] [a, b])" />
+
+<@assertEquals actual=obj.mStringArrayVarargsOverloaded2('a', 'b') expected="mStringArrayVarargsOverloaded2(String[] [a, b])" />
+<@assertEquals actual=obj.mStringArrayVarargsOverloaded2('a') expected="mStringArrayVarargsOverloaded2(String a)" />
+
+<@assertEquals actual=obj.mStringArrayVarargsOverloaded3(['a']) expected="mStringArrayVarargsOverloaded3(String[] [a])" />
+<@assertEquals actual=obj.mStringArrayVarargsOverloaded3(['a', 'b']) expected="mStringArrayVarargsOverloaded3(String[] [a, b])" />
+<@assertEquals actual=obj.mStringArrayVarargsOverloaded3(['a', 'b', 'c']) expected="mStringArrayVarargsOverloaded3(String[] [a, b, c])" />
+<@assertEquals actual=obj.mStringArrayVarargsOverloaded3('a') expected="mStringArrayVarargsOverloaded3(String[] [a])" />
+<@assertEquals actual=obj.mStringArrayVarargsOverloaded3('a', 'b') expected="mStringArrayVarargsOverloaded3(String a, String b)" />
+<@assertEquals actual=obj.mStringArrayVarargsOverloaded3('a', 'b', 'c') expected="mStringArrayVarargsOverloaded3(String[] [a, b, c])" />
+
+<@assertEquals actual=obj.mListOrString(['a', 'b']) expected="mListOrString(List [a, b])" />
+<@assertEquals actual=obj.mListOrString('a') expected="mListOrString(String a)" />
+<@assertEquals actual=obj.mListListOrString([['a'], 'b', 3]) expected="mListListOrString(List [[a], b, 3])" />
+<@assertEquals actual=obj.mListListOrString('s') expected="mListListOrString(String s)" />
+
+<#-- Because the fixed arg interpretations are ambiguous, it only considers the vararg interpretations:  -->
+<@assertEquals actual=obj.mStringArrayVarargsOverloaded4(['a', 'b', 'c']) expected="mStringArrayVarargsOverloaded4(List[] [[a, b, c]])" />
+<@assertEquals actual=obj.mStringArrayVarargsOverloaded4('a', 'b', 'c') expected="mStringArrayVarargsOverloaded4(String[] [a, b, c])" />
+
+<#-- Fixed arg solutions have priority: -->
+<@assertEquals actual=obj.mStringArrayVarargsOverloaded4(obj.javaStringList) expected="mStringArrayVarargsOverloaded4(List[] [[a, b]])" />
+<@assertEquals actual=obj.mStringArrayVarargsOverloaded4(obj.javaStringArray) expected="mStringArrayVarargsOverloaded4(String[] [a, b])" />
+
+<#-- Choses between the vararg solutions: -->
+<@assertEquals actual=obj.mStringArrayVarargsOverloaded4(obj.javaStringList, obj.javaStringList) expected="mStringArrayVarargsOverloaded4(List[] [[a, b], [a, b]])" />
+
+<#-- Until there's no overloading String->Character conversion work: -->
+<@assertEquals actual=obj.mCharNonOverloaded('c') expected="mCharNonOverloaded(char c)" />
+<@assertEquals actual=obj.mCharNonOverloaded(obj.javaString) expected="mCharNonOverloaded(char s)" />
+<@assertEquals actual=obj.mCharacterNonOverloaded('c') expected="mCharacterNonOverloaded(Character c)" />
+<@assertEquals actual=obj.mCharacterNonOverloaded(obj.javaString) expected="mCharacterNonOverloaded(Character s)" />
+
+<@assertEquals actual=obj.mCharOrStringOverloaded('s', 1) expected="mCharOrStringOverloaded(String s, int 1)" />
+<@assertEquals actual=obj.mCharacterOrStringOverloaded('s', 1) expected="mCharacterOrStringOverloaded(String s, int 1)" />
+<@assertEquals actual=obj.mCharOrStringOverloaded2('ss') expected="mCharOrStringOverloaded2(String ss)" />
+<@assertEquals actual=obj.mCharacterOrStringOverloaded2('ss') expected="mCharacterOrStringOverloaded2(String ss)" />
+
+<@assertEquals actual=obj.mVarargs('a', obj.getNnS('b'), obj.getNnS('c')) expected='mVarargs(String... a1 = abc)' />
+
+<@assertEquals actual=obj.mNull1(null) expected="mNull1(String a1 = null)" />
+<@assertEquals actual=obj.mNull1(123) expected="mNull1(int a1 = 123)" />
+<@assertEquals actual=obj.mNull2(null) expected="mNull2(String a1 = null)" />
+<@assertEquals actual=obj.mVarargs('a', null) expected="mVarargs(String... a1 = anull)" />
+<@assertEquals actual=obj.mVarargs(null, 'a') expected="mVarargs(File a1, String... a2)" />
+<@assertEquals actual=obj.mSpecificity('a', 'b') expected="mSpecificity(String a1, Object a2)" />
+
+<@assertEquals actual=obj.mChar('a') expected='mChar(char a1 = a)' />
+<@assertEquals actual=obj.mBoolean(true) expected="mBoolean(boolean a1 = true)" />
+<@assertEquals actual=obj.mBoolean(null) expected="mBoolean(Boolean a1 = null)" />
+
+<@assertEquals actual=obj.mIntNonOverloaded(123?long) expected=123 />
+<@assertEquals actual=obj.mIntNonOverloaded(123) expected=123 />
+<@assertEquals actual=obj.mIntNonOverloaded(123.5) expected=123 />
+<@assertEquals actual=obj.mIntNonOverloaded(2147483648) expected=-2147483648 /> <#-- overflow -->
+<@assertEquals actual=obj.mNumBoxedVSBoxed(123.5) expected='mNumBoxedVSBoxed(Long a1 = 123)' />
+<@assertEquals actual=obj.mNumBoxedVSBoxed(123?int) expected='mNumBoxedVSBoxed(Long a1 = 123)' />
+<@assertEquals actual=obj.mNumBoxedVSBoxed(123?long) expected="mNumBoxedVSBoxed(Long a1 = 123)" />
+<@assertEquals actual=obj.mNumBoxedVSBoxed(123?short) expected="mNumBoxedVSBoxed(Short a1 = 123)" />
+<@assertEquals 
+    actual=obj.mNumUnambigous(2147483648) expected="mNumUnambigous(Integer a1 = -2147483648)" /> <#-- overflow -->
+
+<@assertEquals actual=obj.mIntPrimVSBoxed(123?int) expected="mIntPrimVSBoxed(int a1 = 123)" />
+<@assertEquals actual=obj.mIntPrimVSBoxed(123?short) expected="mIntPrimVSBoxed(int a1 = 123)" />
+<@assertEquals actual=obj.mIntPrimVSBoxed(123) expected="mIntPrimVSBoxed(int a1 = 123)" />
+<#-- This doesn't fail as 123L can be converted to int without loss: -->
+<@assertEquals actual=obj.mIntPrimVSBoxed(123?long) expected="mIntPrimVSBoxed(int a1 = 123)" />
+
+<@assertEquals actual=obj.mNumPrimVSPrim(123?short) expected="mNumPrimVSPrim(short a1 = 123)" />
+<@assertEquals actual=obj.mNumPrimVSPrim(123?int) expected="mNumPrimVSPrim(long a1 = 123)" />
+<@assertEquals actual=obj.mNumPrimVSPrim(123?long) expected="mNumPrimVSPrim(long a1 = 123)" />
+<@assertEquals actual=obj.mNumPrimVSPrim(123?double) expected="mNumPrimVSPrim(long a1 = 123)" />
+<@assertEquals actual=obj.mNumPrimVSPrim(123456) expected="mNumPrimVSPrim(long a1 = 123456)" />
+
+<@assertEquals actual=obj.mNumPrimAll(123?byte) expected="mNumPrimAll(byte a1 = 123)" />
+<@assertEquals actual=obj.mNumPrimAll(123?short) expected="mNumPrimAll(short a1 = 123)" />
+<@assertEquals actual=obj.mNumPrimAll(123?int) expected="mNumPrimAll(int a1 = 123)" />
+<@assertEquals actual=obj.mNumPrimAll(123?long) expected="mNumPrimAll(long a1 = 123)" />
+<@assertEquals actual=obj.mNumPrimAll(123?float) expected="mNumPrimAll(float a1 = 123.0)" />
+<@assertEquals actual=obj.mNumPrimAll(123?double) expected="mNumPrimAll(double a1 = 123.0)" />
+<@assertEquals actual=obj.mNumPrimAll(123) expected="mNumPrimAll(BigDecimal a1 = 123)" />
+<@assertEquals actual=obj.mNumPrimAll(obj.bigInteger(123)) expected="mNumPrimAll(BigInteger a1 = 123)" />
+
+<@assertEquals actual=obj.mNumBoxedAll(123?byte) expected="mNumBoxedAll(Byte a1 = 123)" />
+<@assertEquals actual=obj.mNumBoxedAll(123?short) expected="mNumBoxedAll(Short a1 = 123)" />
+<@assertEquals actual=obj.mNumBoxedAll(123?int) expected="mNumBoxedAll(Integer a1 = 123)" />
+<@assertEquals actual=obj.mNumBoxedAll(123?long) expected="mNumBoxedAll(Long a1 = 123)" />
+<@assertEquals actual=obj.mNumBoxedAll(123?float) expected="mNumBoxedAll(Float a1 = 123.0)" />
+<@assertEquals actual=obj.mNumBoxedAll(123?double) expected="mNumBoxedAll(Double a1 = 123.0)" />
+<@assertEquals actual=obj.mNumBoxedAll(123) expected="mNumBoxedAll(BigDecimal a1 = 123)" />
+<@assertEquals actual=obj.mNumBoxedAll(obj.bigInteger(123)) expected="mNumBoxedAll(BigInteger a1 = 123)" />
+
+<@assertEquals actual=obj.mNumPrimAll2nd(123?byte) expected="mNumPrimAll2nd(short a1 = 123)" />
+<@assertEquals actual=obj.mNumPrimAll2nd(123?short) expected="mNumPrimAll2nd(short a1 = 123)" />
+<@assertEquals actual=obj.mNumPrimAll2nd(123?int) expected="mNumPrimAll2nd(long a1 = 123)" />
+<@assertEquals actual=obj.mNumPrimAll2nd(123?long) expected="mNumPrimAll2nd(long a1 = 123)" />
+<@assertEquals actual=obj.mNumPrimAll2nd(123?float) expected="mNumPrimAll2nd(double a1 = 123.0)" />
+<@assertEquals actual=obj.mNumPrimAll2nd(123?double) expected="mNumPrimAll2nd(double a1 = 123.0)" />
+
+<@assertEquals actual=obj.mNumBoxedAll2nd(123?byte) expected="mNumBoxedAll2nd(Short a1 = 123)" />
+<@assertEquals actual=obj.mNumBoxedAll2nd(123?short) expected="mNumBoxedAll2nd(Short a1 = 123)" />
+<@assertEquals actual=obj.mNumBoxedAll2nd(123?int) expected="mNumBoxedAll2nd(Long a1 = 123)" />
+<@assertEquals actual=obj.mNumBoxedAll2nd(123?long) expected="mNumBoxedAll2nd(Long a1 = 123)" />
+<@assertEquals actual=obj.mNumBoxedAll2nd(123?float) expected="mNumBoxedAll2nd(Double a1 = 123.0)" />
+<@assertEquals actual=obj.mNumBoxedAll2nd(123?double) expected="mNumBoxedAll2nd(Double a1 = 123.0)" />
+ 
+<@assertEquals actual=obj.mNumPrimFallbackToNumber(123?int) expected="mNumPrimFallbackToNumber(long a1 = 123)" />
+<@assertEquals actual=obj.mNumPrimFallbackToNumber(123?long) expected="mNumPrimFallbackToNumber(long a1 = 123)" />
+<@assertEquals actual=obj.mNumPrimFallbackToNumber(123?double) expected="mNumPrimFallbackToNumber(long a1 = 123)" />
+<@assertEquals actual=obj.mNumPrimFallbackToNumber(123.5?double) expected="mNumPrimFallbackToNumber(Number a1 = 123.5)" />
+<@assertEquals actual=obj.mNumPrimFallbackToNumber(123) expected="mNumPrimFallbackToNumber(long a1 = 123)" />
+<@assertEquals actual=obj.mNumPrimFallbackToNumber(obj.bigInteger(123)) expected="mNumPrimFallbackToNumber(long a1 = 123)" />
+<@assertEquals actual=obj.mNumPrimFallbackToNumber(obj.bigInteger(9223372036854775808))
+    expected="mNumPrimFallbackToNumber(Number a1 = 9223372036854775808)" />
+<@assertEquals actual=obj.mNumPrimFallbackToNumber(obj.rational(246, 2)) expected="mNumPrimFallbackToNumber(Number a1 = 246/2)" />
+<@assertEquals actual=obj.mNumPrimFallbackToNumber('x') expected="mNumPrimFallbackToNumber(Object a1 = x)" />
+
+<@assertEquals actual=obj.mNumBoxedFallbackToNumber(123?int) expected="mNumBoxedFallbackToNumber(Long a1 = 123)" />
+<@assertEquals actual=obj.mNumBoxedFallbackToNumber(123?long) expected="mNumBoxedFallbackToNumber(Long a1 = 123)" />
+<@assertEquals actual=obj.mNumBoxedFallbackToNumber(123?double) expected="mNumBoxedFallbackToNumber(Long a1 = 123)" />
+<@assertEquals actual=obj.mNumBoxedFallbackToNumber(123.5?double) expected="mNumBoxedFallbackToNumber(Number a1 = 123.5)" />
+<@assertEquals actual=obj.mNumBoxedFallbackToNumber(123) expected="mNumBoxedFallbackToNumber(Long a1 = 123)" />
+<@assertEquals actual=obj.mNumBoxedFallbackToNumber(obj.bigInteger(123)) expected="mNumBoxedFallbackToNumber(Long a1 = 123)" />
+<@assertEquals actual=obj.mNumBoxedFallbackToNumber(obj.bigInteger(9223372036854775808))
+    expected="mNumBoxedFallbackToNumber(Number a1 = 9223372036854775808)" />
+<@assertEquals actual=obj.mNumBoxedFallbackToNumber(obj.rational(246, 2)) expected="mNumBoxedFallbackToNumber(Number a1 = 246/2)" />
+<@assertEquals actual=obj.mNumBoxedFallbackToNumber('x') expected="mNumBoxedFallbackToNumber(Object a1 = x)" />
+
+<@assertEquals actual=obj.mDecimalLoss(1.5) expected="mDecimalLoss(double a1 = 1.5)" />
+<@assertEquals actual=obj.mDecimalLoss(1.5?double) expected="mDecimalLoss(double a1 = 1.5)" />
+
+<@assertEquals actual=obj.mNumConversionLoses1(1?double, '', '') expected="Number 1.0 java.lang.Double" />
+<@assertEquals actual=obj.mNumConversionLoses1(1?short, '', '') expected="Number 1 java.lang.Short" />
+<@assertEquals actual=obj.mNumConversionLoses1(1?long, '', '') expected="Number 1 java.lang.Long" />
+<@assertEquals actual=obj.mNumConversionLoses2(1?double, '', '') expected="Number 1.0 java.lang.Double" />
+<@assertEquals actual=obj.mNumConversionLoses2(1?short, '', '') expected="Number 1 java.lang.Short" />
+<@assertEquals actual=obj.mNumConversionLoses2(1?long, '', '') expected="Number 1 java.lang.Long" />
+<@assertEquals actual=obj.mNumConversionLoses3(1?double, '', '') expected="Serializable 1.0 java.lang.Double" />
+<@assertEquals actual=obj.mNumConversionLoses3(1?int, '', '') expected="Serializable 1 java.lang.Integer" />
+<@assertEquals actual=obj.mNumConversionLoses3(1?short, '', '') expected="Serializable 1 java.lang.Short" />
+<@assertEquals actual=obj.mNumConversionLoses3(1?long, '', '') expected="Serializable 1 java.lang.Long" />
+
+<#-- BigDecimal-to-int is preferred over to-long for BC and user expectations: -->
+<@assertEquals actual=obj.nIntAndLong(1) expected="nIntAndLong(int 1)" />
+<@assertEquals actual=obj.nIntAndLong(1?long) expected="nIntAndLong(long 1)" />
+<#-- BigDecimal-to-short is, however unfavored due to the higher chance of overflow: -->
+<@assertEquals actual=obj.nIntAndShort(1) expected="nIntAndShort(int 1)" />
+<@assertEquals actual=obj.nIntAndShort(1?short) expected="nIntAndShort(short 1)" />
+<@assertEquals actual=obj.nLongAndShort(1) expected="nLongAndShort(long 1)" />
+<@assertEquals actual=obj.nLongAndShort(1?short) expected="nLongAndShort(short 1)" />
+
+<@assertEquals actual=obj.varargs1(null, 1, 2, 3.5) expected='varargs1(String s = null, double... xs = [1.0, 2.0, 3.5])' />
+<@assertEquals actual=obj.varargs1(null, 1, 2.5, 3) expected='varargs1(String s = null, double... xs = [1.0, 2.5, 3.0])' />
+<@assertEquals actual=obj.varargs1(null, 1.5, 2, 3) expected='varargs1(String s = null, double... xs = [1.5, 2.0, 3.0])' />
+<@assertEquals actual=obj.varargs1(null, 1, 2, 'c') expected='varargs1(String s = null, Object... xs = [1, 2, c])' />
+<@assertEquals actual=obj.varargs1(null, 1, 'b', 3) expected='varargs1(String s = null, Object... xs = [1, b, 3])' />
+<@assertEquals actual=obj.varargs1(null, 'a', 2, 3) expected='varargs1(String s = null, Object... xs = [a, 2, 3])' />
+<@assertEquals actual=obj.varargs1('s', 1, 2, 3) expected='varargs1(String s = "s", int... xs = [1, 2, 3])' />
+<@assertEquals actual=obj.varargs1('s', 1.1, 2.1, 3.1) expected='varargs1(String s = "s", double... xs = [1.1, 2.1, 3.1])' />
+<@assertEquals actual=obj.varargs1('s', 'a', 'b', 'c') expected='varargs1(String s = "s", Object... xs = [a, b, c])' />
+<@assertEquals actual=obj.varargs1(null, 1, 2, 3) expected='varargs1(String s = null, int... xs = [1, 2, 3])' />
+<@assertEquals actual=obj.varargs1(null, 1.1, 2.1, 3.1) expected='varargs1(String s = null, double... xs = [1.1, 2.1, 3.1])' />
+<@assertEquals actual=obj.varargs1(null, 'a', 'b', 'c') expected='varargs1(String s = null, Object... xs = [a, b, c])' />
+<@assertEquals actual=obj.varargs1(null, 1, 2, 3?double) expected='varargs1(String s = null, int... xs = [1, 2, 3])' />
+<@assertEquals actual=obj.varargs1(null, 1, 2?double, 3?double) expected='varargs1(String s = null, double... xs = [1.0, 2.0, 3.0])' />
+<@assertEquals actual=obj.varargs1(null, 1, 2?float, 3?float) expected='varargs1(String s = null, double... xs = [1.0, 2.0, 3.0])' />
+<@assertEquals actual=obj.varargs1(null, 1?double, 2?byte, 3?byte) expected='varargs1(String s = null, int... xs = [1, 2, 3])' />
+<@assertEquals actual=obj.varargs1(0, 1, 2, 3) expected='varargs1(Object s = 0, Object... xs = [1, 2, 3])' />
+<@assertEquals actual=obj.varargs1('s') expected='varargs1(String s = "s", int... xs = [])' />
+
+<@assertEquals actual=obj.varargs2(1, 2.5, 3) expected='varargs2(double... xs = [1.0, 2.5, 3.0])' />
+<@assertEquals actual=obj.varargs2(1, 2.5?double, 3) expected='varargs2(double... xs = [1.0, 2.5, 3.0])' />
+<@assertEquals actual=obj.varargs2(1?int, 2.5?double, 3) expected='varargs2(double... xs = [1.0, 2.5, 3.0])' />
+<@assertEquals actual=obj.varargs2(1?long, 2.5?double, 3) expected='varargs2(double... xs = [1.0, 2.5, 3.0])' />
+<@assertEquals actual=obj.varargs2(1?long, 2?double, 3) expected='varargs2(int... xs = [1, 2, 3])' />
+
+<@assertEquals actual=obj.varargs3(1, 2, 3) expected='varargs3(Comparable... xs = [1, 2, 3])' />
+<@assertEquals actual=obj.varargs3('a', 'b', 'c') expected='varargs3(String... xs = [a, b, c])' />
+<@assertEquals actual=obj.varargs3(1, 'b', 'c') expected='varargs3(Comparable... xs = [1, b, c])' />
+<@assertEquals actual=obj.varargs3('a', 'b', 3) expected='varargs3(Comparable... xs = [a, b, 3])' />
+<@assertEquals actual=obj.varargs3('a', [], 3) expected='varargs3(Object... xs = [a, [], 3])' />
+<@assertEquals actual=obj.varargs3(null, 'b', null) expected='varargs3(String... xs = [null, b, null])' />
+<@assertEquals actual=obj.varargs3(null, 2, null) expected='varargs3(Comparable... xs = [null, 2, null])' />
+<@assertEquals actual=obj.varargs3(null, [], null) expected='varargs3(Object... xs = [null, [], null])' />
+<@assertEquals actual=obj.varargs3(null, null, null) expected='varargs3(String... xs = [null, null, null])' />
+<@assertEquals actual=obj.varargs3() expected='varargs3(String... xs = [])' />
+
+<@assertEquals actual=obj.varargs4(null) expected='varargs4(Integer... xs = [null])' />
+<@assertEquals actual=obj.varargs4(null, null, null) expected='varargs4(Integer... xs = [null, null, null])' />
+<@assertEquals actual=obj.varargs4(1, null, 2) expected='varargs4(Integer... xs = [1, null, 2])' />
+<@assertEquals actual=obj.varargs4(1) expected='varargs4(int... xs = [1])' />
+<@assertEquals actual=obj.varargs4(1, 2, 3) expected='varargs4(int... xs = [1, 2, 3])' />
+
+<@assertEquals actual=obj.varargs5(1, 2, 3, 4, 5) expected='varargs5(int a1 = 1, int a2 = 2, int a3 = 3, int... xs = [4, 5])' />
+<@assertEquals actual=obj.varargs5(1, 2, 3, 4) expected='varargs5(int a1 = 1, int a2 = 2, int a3 = 3, int... xs = [4])' />
+<@assertEquals actual=obj.varargs5(1, 2, 3) expected='varargs5(int a1 = 1, int a2 = 2, int a3 = 3, int... xs = [])' />
+<@assertEquals actual=obj.varargs5(1, 2) expected='varargs5(int a1 = 1, int a2 = 2, int... xs = [])' />
+<@assertEquals actual=obj.varargs5(1) expected='varargs5(int a1 = 1, int... xs = [])' />
+<@assertEquals actual=obj.varargs5() expected='varargs5(int... xs = [])' />
+
+<@assertEquals actual=obj.varargs6('s', 2) expected='varargs6(String a1 = s, int... xs = [2])' />
+<@assertEquals actual=obj.varargs6('s') expected='varargs6(String a1 = s, int... xs = [])' />
+<@assertEquals actual=obj.varargs6(1, 2) expected='varargs6(Object a1 = 1, int a2 = 2, int... xs = [])' />
+<@assertFails message="no compatible overloaded">${obj.varargs6(1)}</@>
+
+<@assertEquals actual=obj.varargs7(1?int, 2?int) expected='varargs7(int... xs = [1, 2])' />
+<@assertEquals actual=obj.varargs7(1?short, 2?int) expected='varargs7(short a1 = 1, int... xs = [2])' />
+
+<#-- Tests that a pre-2.3.21 bug is fixed now: -->
+<@assertEquals actual=obj.mVarargsIgnoredTail(1, 2, 3) expected='mVarargsIgnoredTail(int... is = [1, 2, 3])' />
+<@assertEquals actual=obj.mVarargsIgnoredTail(1, 2, 3.5) expected='mVarargsIgnoredTail(int i = 1, double... ds = [2.0, 3.5])' />
+
+<@assertEquals actual=obj.mNullAmbiguous('a') expected='mNullAmbiguous(String s = a)' />
+<@assertEquals actual=obj.mNullAmbiguous(123) expected='mNullAmbiguous(int i = 123)' />
+<@assertEquals actual=obj.mNullAmbiguous(1.9) expected='mNullAmbiguous(int i = 1)' />
+<@assertEquals actual=obj.mNullAmbiguous(1?double) expected='mNullAmbiguous(int i = 1)' />
+<@assertFails message="no compatible overloaded">${obj.mNullAmbiguous(1.9?double)}</@>
+<@assertFails message="multiple compatible overloaded">${obj.mNullAmbiguous(null)}</@>
+
+<@assertFails message="multiple compatible overloaded">${obj.mNullAmbiguous2(null)}</@>
+
+<@assertEquals actual=obj.mNullNonAmbiguous(null) expected='mNullNonAmbiguous(String s = null)' />
+
+<#-- The primitive int-s will win twice, but then String wins over Object, which is stronger: -->
+<@assertEquals actual=obj.mLowRankWins(1, 2, 'a') expected='mLowRankWins(Integer x = 1, Integer y = 2, String s = a)' />
+
+<@assertEquals actual=obj.mRareWrappings(obj.file, obj.adaptedNumber, obj.adaptedNumber, obj.adaptedNumber, obj.stringWrappedAsBoolean)
+               expected='mRareWrappings(File f = file, double d1 = 123.0002, Double d2 = 123.0002, double d3 = 123.0002, b = true)' />
+<@assertEquals actual=obj.mRareWrappings(obj.stringWrappedAsBoolean, obj.adaptedNumber, obj.adaptedNumber, obj.adaptedNumber, obj.stringAdaptedToBoolean)
+               expected='mRareWrappings(String s = yes, double d1 = 123.0002, Double d2 = 123.0002, double d3 = 123.0002, b = true)' />
+<@assertEquals actual=obj.mRareWrappings(obj.stringAdaptedToBoolean2, obj.wrapperNumber, obj.wrapperNumber, obj.wrapperNumber, obj.stringAdaptedToBoolean2)
+               expected='mRareWrappings(String s = yes, double d1 = 123.0001, Double d2 = 123.0001, double d3 = 123.0001, b = true)' />
+<@assertEquals actual=obj.mRareWrappings(obj.booleanWrappedAsAnotherBoolean, 0, 0, 0, obj.booleanWrappedAsAnotherBoolean)
+               expected='mRareWrappings(Object o = true, double d1 = 0.0, Double d2 = 0.0, double d3 = 0.0, b = true)' />
+<@assertEquals actual=obj.mRareWrappings(obj.adaptedNumber, 0, 0, 0, !obj.booleanWrappedAsAnotherBoolean)
+               expected='mRareWrappings(Object o = 124, double d1 = 0.0, Double d2 = 0.0, double d3 = 0.0, b = true)' />
+<@assertEquals actual=obj.mRareWrappings(obj.booleanWrappedAsAnotherBoolean, 0, 0, 0, !obj.stringAdaptedToBoolean)
+               expected='mRareWrappings(Object o = true, double d1 = 0.0, Double d2 = 0.0, double d3 = 0.0, b = true)' />
+               
+<@assertEquals actual=obj.mRareWrappings2(obj.adaptedNumber) expected='mRareWrappings2(byte b = 124)' />
+
+<#-- Test for List VS array problems due to too vague hinting: -->
+
+<@assertEquals actual=obj.mSeqToArrayNonOverloaded(['a', 'b'], 'c') expected='mSeqToArrayNonOverloaded(String[] [a, b], String c)' />
+
+<@assertEquals actual=obj.mSeqToArrayGoodHint(['a', 'b'], 'c') expected='mSeqToArrayGoodHint(String[] [a, b], String c)' />
+<@assertEquals actual=obj.mSeqToArrayGoodHint(['a', 'b'], 3) expected='mSeqToArrayGoodHint(String[] [a, b], int 3)' />
+
+<@assertEquals actual=obj.mSeqToArrayGoodHint2(['a', 'b'], 'c') expected='mSeqToArrayGoodHint2(String[] [a, b], String c)' />
+<@assertEquals actual=obj.mSeqToArrayGoodHint2('a') expected='mSeqToArrayGoodHint2(String a)' />
+
+<@assertEquals actual=obj.mSeqToArrayPoorHint(['a', 'b'], 'c') expected='mSeqToArrayPoorHint(String[] [a, b], String c)' />
+<@assertEquals actual=obj.mSeqToArrayPoorHint('a', 2) expected='mSeqToArrayPoorHint(String a, int 2)' />
+
+<@assertEquals actual=obj.mSeqToArrayPoorHint2(['a', 'b']) expected='mSeqToArrayPoorHint2(String[] [a, b])' />
+<@assertEquals actual=obj.mSeqToArrayPoorHint2('a') expected='mSeqToArrayPoorHint2(String a)' />
+
+<@assertFails message="multiple compatible overloaded"><@assertEquals actual=obj.mSeqToArrayPoorHint3(['a', 'b']) expected='mSeqToArrayPoorHint3(String[] [a, b])' /></@>
+<@assertFails message="multiple compatible overloaded"><@assertEquals actual=obj.mSeqToArrayPoorHint3([1, 2]) expected='mSeqToArrayPoorHint3(int[] [a, b])' /></@>
+
+<@assertEquals actual=obj.mStringArrayVsListPreference(['a', 'b']) expected="mStringArrayVsListPreference(List [a, b])" />
+<@assertEquals actual=obj.mStringArrayVsListPreference(obj.javaObjectArray) expected="mStringArrayVsListPreference(List [a, b])" />
+<@assertEquals actual=obj.mStringArrayVsObjectArrayPreference(['a', 'b']) expected="mStringArrayVsObjectArrayPreference(Object[] [a, b])" />
+<@assertEquals actual=obj.mIntArrayVsIntegerArrayPreference([1, 2]) expected="mIntArrayVsIntegerArrayPreference(Integer[] [1, 2])" />
+
+<@assertEquals actual=obj.mStringArrayVsObjectArrayPreference(obj.javaStringArray) expected="mStringArrayVsObjectArrayPreference(String[] [a, b])" />
+<@assertFails message="no compatible overloaded">${obj.mStringArrayVsObjectArrayPreference(obj.javaIntArray)}</@>
+<@assertEquals actual=obj.mStringArrayVsObjectArrayPreference(obj.javaIntegerArray) expected="mStringArrayVsObjectArrayPreference(Object[] [11, 22])" />
+
+<@assertEquals actual=obj.mIntegerArrayOverloaded([1, 2], 3) expected="mIntegerArrayOverloaded(Integer[] [1, 2], int 3)" />
+<@assertEquals actual=obj.mIntegerArrayOverloaded([1?byte, 2?byte], 3) expected="mIntegerArrayOverloaded(Integer[] [1, 2], int 3)" />
+<@assertEquals actual=obj.mIntegerArrayOverloaded(obj.javaIntegerList, 3) expected="mIntegerArrayOverloaded(Integer[] [1, 2], int 3)" />
+<@assertEquals actual=obj.mIntegerArrayOverloaded(obj.javaByteList, 3) expected="mIntegerArrayOverloaded(Integer[] [1, 2], int 3)" />
+
+<@assertEquals actual=obj.mStringArrayOverloaded(['a', 'b'], 3) expected="mStringArrayOverloaded(String[] [a, b], int 3)" />
+<@assertEquals actual=obj.mStringArrayOverloaded(obj.javaStringList, 3) expected="mStringArrayOverloaded(String[] [a, b], int 3)" />
+<@assertEquals actual=obj.mStringArrayOverloaded(obj.javaCharacterList, 3) expected="mStringArrayOverloaded(String[] [c, C], int 3)" />
+<@assertFails message="Failed to convert sequence">${obj.mStringArrayOverloaded([1, 2], 3)}</@>
+<@assertFails message="Failed to convert">${obj.mStringArrayOverloaded(obj.javaIntegerList, 3)}</@>
+
+<@assertEquals actual=obj.mCharArrayOverloaded(['a', 'b'], 3) expected="mCharArrayOverloaded(char[] [a, b], int 3)" />
+<@assertEquals actual=obj.mCharArrayOverloaded(obj.javaCharacterList, 3) expected="mCharArrayOverloaded(char[] [c, C], int 3)" />
+<@assertEquals actual=obj.mCharArrayOverloaded(obj.javaStringList, 3) expected="mCharArrayOverloaded(char[] [a, b], int 3)" />
+<@assertFails message="Failed to convert sequence">${obj.mCharArrayOverloaded(['aa', 'bb'], 3)}</@>
+<@assertFails message="Failed to convert">${obj.mCharArrayOverloaded(obj.javaString2List, 3)}</@>
+<@assertEquals actual=obj.mCharArrayOverloaded(['a', 'b'], 's') expected="mCharArrayOverloaded(Character[] [a, b], String s)" />
+<@assertEquals actual=obj.mCharArrayOverloaded(obj.javaCharacterList, 's') expected="mCharArrayOverloaded(Character[] [c, C], String s)" />
+<@assertEquals actual=obj.mCharArrayOverloaded(obj.javaStringList, 's') expected="mCharArrayOverloaded(Character[] [a, b], String s)" />
+<@assertFails message="Failed to convert sequence">${obj.mCharArrayOverloaded(['aa', 'bb'], 's')}</@>
+<@assertFails message="Failed to convert">${obj.mCharArrayOverloaded(obj.javaString2List, 's')}</@>
+
+<@assertEquals actual=obj.mStringArrayArrayOverloaded([['a', 'b'], ['c']], 3) expected="mStringArrayArrayOverloaded(String[][] [[a, b], [c]], int 3)" />
+<@assertEquals actual=obj.mStringArrayArrayOverloaded(obj.javaStringListList, 3) expected="mStringArrayArrayOverloaded(String[][] [[a, b], [c]], int 3)" />
+<@assertEquals actual=obj.mStringArrayArrayOverloaded(obj.javaStringSequenceList, 3) expected="mStringArrayArrayOverloaded(String[][] [[a, b], [c]], int 3)" />
+<@assertFails message="Failed to convert">${obj.mStringArrayArrayOverloaded(obj.javaStringList, 3)}</@>
+<@assertFails message="Failed to convert">${obj.mStringArrayArrayOverloaded(obj.javaIntegerListList, 3)}</@>
+<@assertEquals actual=obj.mIntArrayArrayOverloaded(obj.javaListOfIntArrays) expected="mIntArrayArrayOverloaded([[1, 2, 3], [], [4]])" />
+<@assertEquals actual=obj.mArrayOfListsOverloaded(obj.javaListOfIntArrays) expected="mArrayOfListsOverloaded([[1, 2, 3], [], [4]])" />
+<@assertEquals actual=obj.mIntArrayArrayNonOverloaded(obj.javaListOfIntArrays) expected="mIntArrayArrayNonOverloaded([[1, 2, 3], [], [4]])" />
+<@assertEquals actual=obj.mArrayOfListsNonOverloaded(obj.javaListOfIntArrays) expected="mArrayOfListsNonOverloaded([[1, 2, 3], [], [4]])" />
+
+<@assertEquals actual=obj.mStringArrayVarargsOverloaded2(['a', 'b']) expected="mStringArrayVarargsOverloaded2(String[] [a, b])" />
+<@assertEquals actual=obj.mStringArrayVarargsOverloaded2(obj.javaStringList) expected="mStringArrayVarargsOverloaded2(String[] [a, b])" />
+<@assertEquals actual=obj.mStringArrayVarargsOverloaded2(obj.javaStringArray) expected="mStringArrayVarargsOverloaded2(String[] [a, b])" />
+<@assertEquals actual=obj.mStringArrayVarargsOverloaded2(['a']) expected="mStringArrayVarargsOverloaded2(String[] [a])" />
+
+<#-- Situations that lead to array-to-List conversion: -->
+<@assertEquals actual=obj.mListOrString(obj.javaStringArray) expected="mListOrString(List [a, b])" />
+<@assertEquals actual=obj.mListOrString(obj.javaEmptyStringArray) expected="mListOrString(List [])" />
+<@assertEquals actual=obj.mListOrString(obj.javaIntArray) expected="mListOrString(List [11, 22])" />
+<@assertEquals actual=obj.mListListOrString(obj.javaStringArrayArray) expected="mListListOrString(List [[a, b], [], [c]])" />
+<@assertEquals actual=obj.mStringArrayVarargsOverloaded4(obj.javaStringArray, obj.javaStringArray) expected="mStringArrayVarargsOverloaded4(List[] [[a, b], [a, b]])" />
+<@assertEquals actual=obj.mStringArrayVarargsOverloaded4(obj.javaStringList, obj.javaStringArray) expected="mStringArrayVarargsOverloaded4(List[] [[a, b], [a, b]])" />
+<@assertEquals actual=obj.mStringArrayVarargsOverloaded4(obj.javaStringArray, obj.javaStringList) expected="mStringArrayVarargsOverloaded4(List[] [[a, b], [a, b]])" />
+
+<@assertEquals actual=obj.mMapOrBoolean(obj.hashAndScalarModel) expected="mMapOrBoolean(Map {})" />
+<@assertEquals actual=obj.mMapOrBoolean(obj.booleanAndScalarModel) expected="mMapOrBoolean(boolean true)" />
+<@assertEquals actual=obj.mMapOrBoolean(obj.allModels) expected="mMapOrBoolean(boolean true)" />
+
+<@assertEquals actual=obj.mMapOrBooleanVarargs(obj.hashAndScalarModel) expected="mMapOrBooleanVarargs(Map... [{}])" />
+<@assertEquals actual=obj.mMapOrBooleanVarargs(obj.hashAndScalarModel, obj.hashAndScalarModel) expected="mMapOrBooleanVarargs(Map... [{}, {}])" />
+<@assertEquals actual=obj.mMapOrBooleanVarargs(obj.allModels) expected="mMapOrBooleanVarargs(boolean... [true])" />
+<@assertEquals actual=obj.mMapOrBooleanVarargs(obj.allModels, obj.allModels) expected="mMapOrBooleanVarargs(boolean... [true, true])" />
+
+<@assertEquals actual=obj.mMapOrBooleanFixedAndVarargs(obj.hashAndScalarModel) expected="mMapOrBooleanFixedAndVarargs(Map {})" />
+<@assertEquals actual=obj.mMapOrBooleanFixedAndVarargs(obj.hashAndScalarModel, obj.hashAndScalarModel) expected="mMapOrBooleanFixedAndVarargs(Map... [{}, {}])" />
+<@assertEquals actual=obj.mMapOrBooleanFixedAndVarargs(obj.hashAndScalarModel, obj.hashAndScalarModel, obj.hashAndScalarModel) expected="mMapOrBooleanFixedAndVarargs(Map... [{}, {}, {}])" />
+<@assertEquals actual=obj.mMapOrBooleanFixedAndVarargs(obj.allModels) expected="mMapOrBooleanFixedAndVarargs(boolean true)" />
+<@assertEquals actual=obj.mMapOrBooleanFixedAndVarargs(obj.allModels, obj.allModels) expected="mMapOrBooleanFixedAndVarargs(boolean... [true, true])" />
+<@assertEquals actual=obj.mMapOrBooleanFixedAndVarargs(obj.allModels, obj.allModels, obj.allModels) expected="mMapOrBooleanFixedAndVarargs(boolean... [true, true, true])" />
+
+<@assertEquals actual=obj.mNumberOrArray(obj.allModels) expected="mNumberOrArray(Number 1)" />
+<@assertEquals actual=obj.mNumberOrArray([obj.allModels]) expected="mNumberOrArray(Object[] [1])" />
+<@assertEquals actual=obj.mIntOrArray(obj.allModels) expected="mIntOrArray(int 1)" />
+<@assertEquals actual=obj.mDateOrArray(obj.allModels) expected="mDateOrArray(Date 0)" />
+<@assertEquals actual=obj.mStringOrArray(obj.allModels) expected="mStringOrArray(String s)" />
+<@assertEquals actual=obj.mBooleanOrArray(obj.allModels) expected="mBooleanOrArray(boolean true)" />
+<@assertEquals actual=obj.mMapOrArray(obj.allModels) expected="mMapOrArray(Map {})" />
+<@assertEquals actual=obj.mListOrArray(obj.allModels) expected="mListOrArray(List [])" />
+<@assertEquals actual=obj.mSetOrArray(obj.allModels) expected="mSetOrArray(Set [])" />
+
+<@assertEquals actual=obj.mCharOrCharacterOverloaded('c') expected="mCharOrCharacterOverloaded(char c)" />
+<@assertEquals actual=obj.mCharOrCharacterOverloaded(obj.javaString) expected="mCharOrCharacterOverloaded(char s)" />
+<@assertEquals actual=obj.mCharOrCharacterOverloaded(null) expected="mCharOrCharacterOverloaded(Character null)" />
+
+<@assertEquals actual=obj.mCharOrBooleanOverloaded('c') expected="mCharOrBooleanOverloaded(char c)" />
+<@assertEquals actual=obj.mCharOrBooleanOverloaded(true) expected="mCharOrBooleanOverloaded(boolean true)" />
+
+<@assertEquals actual=obj.mCharOrStringOverloaded('c', true) expected="mCharOrStringOverloaded(char c, boolean true)" />
+<@assertEquals actual=obj.mCharacterOrStringOverloaded('c', true) expected="mCharacterOrStringOverloaded(Character c, boolean true)" />
+
+<@assertEquals actual=obj.mCharOrStringOverloaded2('c') expected="mCharOrStringOverloaded2(char c)" />
+<@assertEquals actual=obj.mCharacterOrStringOverloaded2('c') expected="mCharacterOrStringOverloaded2(Character c)" />
+<@assertEquals actual=obj.mCharOrStringOverloaded2('ss') expected="mCharOrStringOverloaded2(String ss)" />
+<@assertEquals actual=obj.mCharacterOrStringOverloaded2('ss') expected="mCharacterOrStringOverloaded2(String ss)" />
+
+<#-- The exmple given in bug report 363 -->
+<#assign theMap = {'name':'Billy', 'lastName', 'Pilgrim'} />
+<@assertEquals actual=obj.bugReport363(theMap, []) expected="Executed: testMethod(Map fields, List listField) on input: fields={name=Billy, lastName=Pilgrim} and listField=[]" />
+<@assertEquals actual=obj.bugReport363(theMap, null) expected="Executed: testMethod(Map fields, List listField) on input: fields={name=Billy, lastName=Pilgrim} and listField=null" />

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/precedence.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/precedence.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/precedence.ftl
new file mode 100644
index 0000000..472b076
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/precedence.ftl
@@ -0,0 +1,61 @@
+<#--
+  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.
+-->
+<html>
+<head>
+<title>FreeMarker: Operator Precedence Test</title>
+</head>
+<body>
+<#assign patate1 = "test">
+<#assign patate2 = "test">
+<#assign patate3 = "test">
+
+<#if patate1 == patate2 && patate2 == patate3>
+@@@@@@@@@@@
+</#if>
+
+<br />
+<br />
+
+<#if patate1?exists && patate2 == patate3>
+##########
+</#if>
+
+<br />
+<br />
+
+<#if patate2 == patate2 && (patate2==patate2)>
+&&&&&&&&&&&
+</#if>
+
+<br />
+<br />
+
+<#if (patate2 == patate2) && (patate2==patate2)>
+!!!!!!!!!!!
+</#if>
+
+<br />
+<br />
+
+<#if (patate2 == patate2) && patate2==patate2>
+$$$$$$$$$$$
+</#if>
+
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/range-common.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/range-common.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/range-common.ftl
new file mode 100644
index 0000000..142435b
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/range-common.ftl
@@ -0,0 +1,314 @@
+<#--
+  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.
+-->
+<#-- A version of "?join" that fails at null-s in the sequence: -->
+<#function join seq sep=''>
+  <#local r = "">
+  <#list seq as i>
+    <#local r = r + i>
+    <#if i_has_next>
+      <#local r = r + sep>
+    </#if>
+  </#list>
+  <#return r>
+</#function>
+
+<#----------------------->
+<#-- Range expressions -->
+
+<@assertEquals actual=join(1..2, ' ') expected="1 2" />
+<@assertEquals actual=join(1..1, ' ') expected="1" />
+<@assertEquals actual=join(1..0, ' ') expected="1 0" />
+<@assertEquals actual=join(1..-1, ' ') expected="1 0 -1" />
+<@assertEquals actual=join(-1..-1, ' ') expected="-1" />
+<@assertEquals actual=join(-1..1, ' ') expected="-1 0 1" />
+
+<@assertEquals actual=join(1..<3, ' ') expected="1 2" />
+<@assertEquals actual=join(1..<2, ' ') expected="1" />
+<@assertEquals actual=join(1..<1, ' ') expected="" />
+<@assertEquals actual=join(1..<0, ' ') expected="1" />
+<@assertEquals actual=join(1..<-1, ' ') expected="1 0" />
+<@assertEquals actual=join(1..<-2, ' ') expected="1 0 -1" />
+<@assertEquals actual=join(-1..<0, ' ') expected="-1" />
+<@assertEquals actual=join(-1..<2, ' ') expected="-1 0 1" />
+
+<@assertEquals actual=join(1..!3, ' ') expected="1 2" />
+<@assertEquals actual=join(1..!2, ' ') expected="1" />
+<@assertEquals actual=join(1..!1, ' ') expected="" />
+<@assertEquals actual=join(1..!0, ' ') expected="1" />
+<@assertEquals actual=join(1..!-1, ' ') expected="1 0" />
+<@assertEquals actual=join(1..!-2, ' ') expected="1 0 -1" />
+<@assertEquals actual=join(-1..!0, ' ') expected="-1" />
+<@assertEquals actual=join(-1..!2, ' ') expected="-1 0 1" />
+
+<@assertEquals actual=join(1..*2, ' ') expected="1 2" />
+<@assertEquals actual=join(1..*1, ' ') expected="1" />
+<@assertEquals actual=join(1..*0, ' ') expected="" />
+<@assertEquals actual=join(1..*-1, ' ') expected="1" />
+<@assertEquals actual=join(1..*-2, ' ') expected="1 0" />
+<@assertEquals actual=join(1..*-3, ' ') expected="1 0 -1" />
+<@assertEquals actual=join(-1..*1, ' ') expected="-1" />
+<@assertEquals actual=join(-1..*3, ' ') expected="-1 0 1" />
+
+<@assertEquals actual=1 expected=(0..0)?size />
+<@assertEquals actual=1 expected=(1..1)?size />
+<@assertEquals actual=1 expected=(2..2)?size />
+<@assertEquals actual=2 expected=(0..1)?size />
+<@assertEquals actual=2 expected=(1..2)?size />
+<@assertEquals actual=2 expected=(2..3)?size />
+<@assertEquals actual=3 expected=(2..4)?size />
+<@assertEquals actual=2 expected=(1..0)?size />
+<@assertEquals actual=2 expected=(2..1)?size />
+<@assertEquals actual=2 expected=(3..2)?size />
+<@assertEquals actual=3 expected=(4..2)?size />
+
+<@assertEquals actual=0 expected=(0..<0)?size />
+<@assertEquals actual=0 expected=(1..<1)?size />
+<@assertEquals actual=0 expected=(2..<2)?size />
+<@assertEquals actual=1 expected=(0..<1)?size />
+<@assertEquals actual=1 expected=(1..<2)?size />
+<@assertEquals actual=1 expected=(2..<3)?size />
+<@assertEquals actual=2 expected=(2..<4)?size />
+<@assertEquals actual=1 expected=(1..<0)?size />
+<@assertEquals actual=1 expected=(2..<1)?size />
+<@assertEquals actual=1 expected=(3..<2)?size />
+<@assertEquals actual=2 expected=(4..<2)?size />
+
+<@assertEquals actual=0 expected=(0..*0)?size />
+<@assertEquals actual=0 expected=(1..*0)?size />
+<@assertEquals actual=0 expected=(2..*0)?size />
+<@assertEquals actual=1 expected=(0..*1)?size />
+<@assertEquals actual=1 expected=(1..*1)?size />
+<@assertEquals actual=1 expected=(2..*1)?size />
+<@assertEquals actual=2 expected=(2..*2)?size />
+<@assertEquals actual=1 expected=(0..*-1)?size />
+<@assertEquals actual=1 expected=(1..*-1)?size />
+<@assertEquals actual=1 expected=(2..*-1)?size />
+<@assertEquals actual=2 expected=(0..*-2)?size />
+<@assertEquals actual=2 expected=(1..*-2)?size />
+<@assertEquals actual=2 expected=(2..*-2)?size />
+
+
+<#--------------------->
+<#-- String slicing: -->
+
+<#assign s = 'abcd'>
+
+<@assertEquals actual=s[0..] expected="abcd" />
+<@assertEquals actual=s[1..] expected="bcd" />
+<@assertEquals actual=s[2..] expected="cd" />
+<@assertEquals actual=s[3..] expected="d" />
+<@assertEquals actual=s[4..] expected="" />
+<@assertFails message="5 is out of bounds">
+  <#assign _ = s[5..] />
+</...@assertFails>
+<@assertFails message="6 is out of bounds">
+  <#assign _ = s[6..] />
+</...@assertFails>
+
+<@assertEquals actual=s[1..2] expected="bc" />
+<@assertEquals actual=s[1..1] expected="b" />
+<@assertEquals actual=s[0..1] expected="ab" />
+<@assertEquals actual=s[0..0] expected="a" />
+<@assertFails message="4 is out of bounds">
+  <#assign _ = s[1..4] />
+</...@assertFails>
+<@assertFails message="5 is out of bounds">
+  <#assign _ = s[1..5] />
+</...@assertFails>
+<@assertFails message="negative">
+  <#assign _ = s[-1..1] />
+</...@assertFails>
+<@assertFails message="negative">
+  <#assign _ = s[-2..1] />
+</...@assertFails>
+<@assertFails message="negative">
+  <#assign _ = s[0..-1] />
+</...@assertFails>
+
+<@assertEquals actual=s[1..<3] expected="bc" />
+<@assertEquals actual=s[1..!3] expected="bc" />
+<@assertEquals actual=s[1..<2] expected="b" />
+<@assertEquals actual=s[1..<0] expected="b" />
+<@assertEquals actual=s[1..<1] expected="" />
+<@assertEquals actual=s[0..<0] expected="" />
+<@assertEquals actual=s[5..<5] expected="" />
+<@assertEquals actual=s[6..<6] expected="" />
+<@assertEquals actual=s[-5..<-5] expected="" />
+<@assertFails message="negative">
+  <#assign _ = s[-5..<1] />
+</...@assertFails>
+<@assertFails message="negative">
+  <#assign _ = s[2..<-4] />
+</...@assertFails>
+<@assertFails message="decreasing">
+  <#assign _ = s[2..<0] />
+</...@assertFails>
+
+<@assertEquals actual=s[1..*-1] expected="b" />
+<@assertEquals actual=s[1..*0] expected="" />
+<@assertEquals actual=s[1..*1] expected="b" />
+<@assertEquals actual=s[1..*2] expected="bc" />
+<@assertEquals actual=s[1..*3] expected="bcd" />
+<@assertEquals actual=s[1..*4] expected="bcd" />
+<@assertEquals actual=s[1..*5] expected="bcd" />
+<@assertEquals actual=s[4..*1] expected="" />
+<@assertEquals actual=s[5..*0] expected="" />
+<@assertEquals actual=s[6..*0] expected="" />
+<@assertEquals actual=s[-5..*0] expected="" />
+<@assertEquals actual=s[0..*0] expected="" />
+<@assertEquals actual=s[0..*-1] expected="a" />
+<@assertEquals actual=s[0..*-2] expected="a" />
+<@assertEquals actual=s[0..*-3] expected="a" />
+<@assertFails message="5 is out of bounds">
+  <#assign _ = s[5..*1] />
+</...@assertFails>
+<@assertFails message="negative">
+  <#assign _ = s[-1..*1] />
+</...@assertFails>
+<@assertFails message="negative">
+  <#assign _ = s[-2..*1] />
+</...@assertFails>
+<@assertFails message="decreasing">
+  <#assign _ = s[1..*-2] />
+</...@assertFails>
+<@assertFails message="decreasing">
+  <#assign _ = s[1..*-3] />
+</...@assertFails>
+<@assertFails message="4 is out of bounds">
+  <#assign _ = s[4..*-1] />
+</...@assertFails>
+
+<#-- Legacy string backward-range bug kept for compatibility: -->
+<@assertEquals actual=s[1..0] expected="" />
+<@assertEquals actual=s[2..1] expected="" />
+<@assertFails message="negative">
+  <@assertEquals actual=s[0..-1] expected="" />
+</...@assertFails>
+<@assertFails message="decreasing">
+  <@assertEquals actual=s[3..1] expected="" />
+</...@assertFails>
+<#-- But it isn't emulated for operators introduced after 2.3.20: -->
+<@assertFails message="decreasing">
+  <@assertEquals actual=s[3..<1] expected="" />
+</...@assertFails>
+<@assertFails message="decreasing">
+  <@assertEquals actual=s[3..*-2] expected="" />
+</...@assertFails>
+
+<#assign r = 1..2>
+<@assertEquals actual=s[r] expected="bc" />
+<#assign r = 2..1>
+<@assertEquals actual=s[r] expected="" />
+<#assign r = 1..<2>
+<@assertEquals actual=s[r] expected="b" />
+<#assign r = 2..<4>
+<@assertEquals actual=s[r] expected="cd" />
+<#assign r = 2..>
+<@assertEquals actual=s[r] expected="cd" />
+<#assign r = 1..*2>
+<@assertEquals actual=s[r] expected="bc" />
+
+<#----------------------->
+<#-- Sequence slicing: -->
+
+<#assign s = ['a', 'b', 'c', 'd']>
+
+<@assertEquals actual=join(s[0..]) expected="abcd" />
+<@assertEquals actual=join(s[1..]) expected="bcd" />
+<@assertEquals actual=join(s[2..]) expected="cd" />
+<@assertEquals actual=join(s[3..]) expected="d" />
+<@assertEquals actual=join(s[4..]) expected="" />
+<@assertFails message="5 is out of bounds">
+  <#assign _ = s[5..] />
+</...@assertFails>
+<@assertFails message="negative">
+  <#assign _ = s[-1..] />
+</...@assertFails>
+
+<@assertEquals actual=join(s[1..2]) expected="bc" />
+<@assertEquals actual=join(s[1..1]) expected="b" />
+<@assertEquals actual=join(s[0..1]) expected="ab" />
+<@assertEquals actual=join(s[0..0]) expected="a" />
+<@assertFails message="5 is out of bounds">
+  <#assign _ = s[1..5] />
+</...@assertFails>
+<@assertFails message="negative">
+  <#assign _ = s[-1..0] />
+</...@assertFails>
+<@assertFails message="negative">
+  <#assign _ = s[0..-1] />
+</...@assertFails>
+
+<@assertEquals actual=join(s[1..<3]) expected="bc" />
+<@assertEquals actual=join(s[1..!3]) expected="bc" />
+<@assertEquals actual=join(s[1..<2]) expected="b" />
+<@assertEquals actual=join(s[1..<0]) expected="b" />
+<@assertEquals actual=join(s[1..<1]) expected="" />
+<@assertEquals actual=join(s[0..<0]) expected="" />
+
+<@assertEquals actual=join(s[1..0]) expected="ba" />
+<@assertEquals actual=join(s[2..1]) expected="cb" />
+<@assertEquals actual=join(s[2..0]) expected="cba" />
+<@assertEquals actual=join(s[2..<0]) expected="cb" />
+<@assertEquals actual=join(s[1..<0]) expected="b" />
+<@assertEquals actual=join(s[0..<0]) expected="" />
+<@assertEquals actual=join(s[3..<1]) expected="dc" />
+<@assertEquals actual=join(s[2..<1]) expected="c" />
+<@assertEquals actual=join(s[1..<1]) expected="" />
+<@assertEquals actual=join(s[0..<1]) expected="a" />
+<@assertEquals actual=join(s[0..<0]) expected="" />
+<@assertEquals actual=join(s[5..<5]) expected="" />
+<@assertEquals actual=join(s[-5..<-5]) expected="" />
+
+<@assertEquals actual=join(s[0..*-4]) expected="a" />
+<@assertEquals actual=join(s[1..*-4]) expected="ba" />
+<@assertEquals actual=join(s[1..*-3]) expected="ba" />
+<@assertEquals actual=join(s[1..*-2]) expected="ba" />
+<@assertEquals actual=join(s[1..*-1]) expected="b" />
+<@assertEquals actual=join(s[1..*0]) expected="" />
+<@assertEquals actual=join(s[1..*1]) expected="b" />
+<@assertEquals actual=join(s[1..*2]) expected="bc" />
+<@assertEquals actual=join(s[1..*3]) expected="bcd" />
+<@assertEquals actual=join(s[1..*4]) expected="bcd" />
+<@assertEquals actual=join(s[1..*5]) expected="bcd" />
+<@assertEquals actual=join(s[0..*3]) expected="abc" />
+<@assertEquals actual=join(s[2..*3]) expected="cd" />
+<@assertEquals actual=join(s[3..*3]) expected="d" />
+<@assertEquals actual=join(s[4..*3]) expected="" />
+<@assertFails message="5 is out of bounds">
+  <#assign _ = s[5..*3] />
+</...@assertFails>
+<@assertFails message="negative">
+  <#assign _ = s[-1..*2] />
+</...@assertFails>
+
+<#assign r = 1..2>
+<@assertEquals actual=join(s[r]) expected="bc" />
+<#assign r = 2..0>
+<@assertEquals actual=join(s[r]) expected="cba" />
+<#assign r = 1..<2>
+<@assertEquals actual=join(s[r]) expected="b" />
+<#assign r = 2..<0>
+<@assertEquals actual=join(s[r]) expected="cb" />
+<#assign r = 2..>
+<@assertEquals actual=join(s[r]) expected="cd" />
+<#assign r = 1..*2>
+<@assertEquals actual=join(s[r]) expected="bc" />
+<#assign r = 1..*-9>
+<@assertEquals actual=join(s[r]) expected="ba" />



[36/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PrintfGTemplateNumberFormatFactory.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PrintfGTemplateNumberFormatFactory.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PrintfGTemplateNumberFormatFactory.java
new file mode 100644
index 0000000..e8d5f2b
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PrintfGTemplateNumberFormatFactory.java
@@ -0,0 +1,138 @@
+/*
+ * 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.userpkg;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Locale;
+
+import org.apache.freemarker.core.Environment;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateNumberModel;
+import org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat;
+import org.apache.freemarker.core.util._StringUtil;
+import org.apache.freemarker.core.valueformat.InvalidFormatParametersException;
+import org.apache.freemarker.core.valueformat.TemplateFormatUtil;
+import org.apache.freemarker.core.valueformat.TemplateNumberFormat;
+import org.apache.freemarker.core.valueformat.TemplateNumberFormatFactory;
+import org.apache.freemarker.core.valueformat.UnformattableValueException;
+
+/**
+ * Formats like {@code %G} in {@code printf}, with the specified number of significant digits. Also has special
+ * formatter for HTML output format, where it uses the HTML "sup" element for exponents.
+ */
+public class PrintfGTemplateNumberFormatFactory extends TemplateNumberFormatFactory {
+
+    public static final PrintfGTemplateNumberFormatFactory INSTANCE = new PrintfGTemplateNumberFormatFactory();
+    
+    private PrintfGTemplateNumberFormatFactory() {
+        // Defined to decrease visibility
+    }
+    
+    @Override
+    public TemplateNumberFormat get(String params, Locale locale, Environment env)
+            throws InvalidFormatParametersException {
+        Integer significantDigits;
+        if (!params.isEmpty()) {
+            try {
+                significantDigits = Integer.valueOf(params);
+            } catch (NumberFormatException e) {
+                throw new InvalidFormatParametersException(
+                        "The format parameter must be an integer, but was (shown quoted) "
+                        + _StringUtil.jQuote(params) + ".");
+            }
+        } else {
+            // Use the default of %G
+            significantDigits = null;
+        }
+        return new PrintfGTemplateNumberFormat(significantDigits, locale);
+    }
+
+    private static class PrintfGTemplateNumberFormat extends TemplateNumberFormat {
+        
+        private final Locale locale;
+        private final String printfFormat; 
+
+        private PrintfGTemplateNumberFormat(Integer significantDigits, Locale locale) {
+            printfFormat = "%" + (significantDigits != null ? "." + significantDigits : "") + "G";
+            this.locale = locale;
+        }
+        
+        @Override
+        public String formatToPlainText(TemplateNumberModel numberModel)
+                throws UnformattableValueException, TemplateModelException {
+            final Number n = TemplateFormatUtil.getNonNullNumber(numberModel);
+            
+            // printf %G only accepts Double, BigDecimal and Float 
+            final Number gCompatibleN;
+            if (n instanceof Double  || n instanceof BigDecimal || n instanceof Float) {
+                gCompatibleN = n;
+            } else {
+                if (n instanceof BigInteger) {
+                    gCompatibleN = new BigDecimal((BigInteger) n);                        
+                } else if (n instanceof Long) {
+                    gCompatibleN = BigDecimal.valueOf(n.longValue());
+                } else {
+                    gCompatibleN = Double.valueOf(n.doubleValue());
+                }
+            }
+            
+            return String.format(locale, printfFormat, gCompatibleN);
+        }
+
+        @Override
+        public Object format(TemplateNumberModel numberModel)
+                throws UnformattableValueException, TemplateModelException {
+            String strResult = formatToPlainText(numberModel);
+            
+            int expIdx = strResult.indexOf('E');
+            if (expIdx == -1) {
+                return strResult;
+            }
+                
+            String expStr = strResult.substring(expIdx + 1);
+            int expSignifNumBegin = 0;
+            while (expSignifNumBegin < expStr.length() && isExpSignifNumPrefix(expStr.charAt(expSignifNumBegin))) {
+                expSignifNumBegin++;
+            }
+            
+            return HTMLOutputFormat.INSTANCE.fromMarkup(
+                    strResult.substring(0, expIdx)
+                    + "*10<sup>"
+                    + (expStr.charAt(0) == '-' ? "-" : "") + expStr.substring(expSignifNumBegin)
+                    + "</sup>");
+        }
+
+        private boolean isExpSignifNumPrefix(char c) {
+            return c == '+' || c == '-' || c == '0';
+        }
+
+        @Override
+        public boolean isLocaleBound() {
+            return true;
+        }
+
+        @Override
+        public String getDescription() {
+            return "printf " + printfFormat;
+        }
+        
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PublicAll.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PublicAll.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PublicAll.java
new file mode 100644
index 0000000..5767e93
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PublicAll.java
@@ -0,0 +1,24 @@
+/*
+ * 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.userpkg;
+
+public class PublicAll {
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PublicWithMixedConstructors.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PublicWithMixedConstructors.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PublicWithMixedConstructors.java
new file mode 100644
index 0000000..e521d75
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PublicWithMixedConstructors.java
@@ -0,0 +1,38 @@
+/*
+ * 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.userpkg;
+
+public class PublicWithMixedConstructors {
+    
+    private final String s;
+
+    public PublicWithMixedConstructors(Integer x) {
+        s = "Integer";
+    }
+
+    PublicWithMixedConstructors(int x) {
+        s = "int";
+    }
+
+    public String getS() {
+        return s;
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PublicWithPackageVisibleConstructor.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PublicWithPackageVisibleConstructor.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PublicWithPackageVisibleConstructor.java
new file mode 100644
index 0000000..9fdec49
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/PublicWithPackageVisibleConstructor.java
@@ -0,0 +1,26 @@
+/*
+ * 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.userpkg;
+
+public class PublicWithPackageVisibleConstructor {
+
+    PublicWithPackageVisibleConstructor() { }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/SeldomEscapedOutputFormat.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/SeldomEscapedOutputFormat.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/SeldomEscapedOutputFormat.java
new file mode 100644
index 0000000..b8cab13
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/SeldomEscapedOutputFormat.java
@@ -0,0 +1,71 @@
+/*
+ * 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.userpkg;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.outputformat.CommonMarkupOutputFormat;
+
+public class SeldomEscapedOutputFormat extends CommonMarkupOutputFormat<TemplateSeldomEscapedOutputModel> {
+    
+    public static final SeldomEscapedOutputFormat INSTANCE = new SeldomEscapedOutputFormat();
+    
+    private SeldomEscapedOutputFormat() {
+        // hide
+    }
+
+    @Override
+    public String getName() {
+        return "seldomEscaped";
+    }
+
+    @Override
+    public String getMimeType() {
+        return "text/seldomEscaped";
+    }
+
+    @Override
+    public void output(String textToEsc, Writer out) throws IOException, TemplateModelException {
+        out.write(escapePlainText(textToEsc));
+    }
+
+    @Override
+    public String escapePlainText(String plainTextContent) {
+        return plainTextContent.replaceAll("(\\.|\\\\)", "\\\\$1");
+    }
+
+    @Override
+    public boolean isLegacyBuiltInBypassed(String builtInName) {
+        return false;
+    }
+
+    @Override
+    public boolean isAutoEscapedByDefault() {
+        return false;
+    }
+
+    @Override
+    protected TemplateSeldomEscapedOutputModel newTemplateMarkupOutputModel(
+            String plainTextContent, String markupContent) {
+        return new TemplateSeldomEscapedOutputModel(plainTextContent, markupContent);
+    }
+    
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TemplateDummyOutputModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TemplateDummyOutputModel.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TemplateDummyOutputModel.java
new file mode 100644
index 0000000..c98df53
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TemplateDummyOutputModel.java
@@ -0,0 +1,34 @@
+/*
+ * 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.userpkg;
+
+import org.apache.freemarker.core.outputformat.CommonTemplateMarkupOutputModel;
+
+public class TemplateDummyOutputModel extends CommonTemplateMarkupOutputModel<TemplateDummyOutputModel> {
+
+    TemplateDummyOutputModel(String plainTextContent, String markupContet) {
+        super(plainTextContent, markupContet);
+    }
+
+    @Override
+    public DummyOutputFormat getOutputFormat() {
+        return DummyOutputFormat.INSTANCE;
+    }
+    
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TemplateSeldomEscapedOutputModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TemplateSeldomEscapedOutputModel.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TemplateSeldomEscapedOutputModel.java
new file mode 100644
index 0000000..b0a21f7
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/userpkg/TemplateSeldomEscapedOutputModel.java
@@ -0,0 +1,34 @@
+/*
+ * 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.userpkg;
+
+import org.apache.freemarker.core.outputformat.CommonTemplateMarkupOutputModel;
+
+public class TemplateSeldomEscapedOutputModel extends CommonTemplateMarkupOutputModel<TemplateSeldomEscapedOutputModel> {
+
+    TemplateSeldomEscapedOutputModel(String plainTextContent, String markupContet) {
+        super(plainTextContent, markupContet);
+    }
+
+    @Override
+    public SeldomEscapedOutputFormat getOutputFormat() {
+        return SeldomEscapedOutputFormat.INSTANCE;
+    }
+    
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/util/DateUtilTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/util/DateUtilTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/util/DateUtilTest.java
new file mode 100644
index 0000000..0cd8fc0
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/util/DateUtilTest.java
@@ -0,0 +1,1085 @@
+/*
+ * 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.util;
+
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import javax.xml.datatype.DatatypeConfigurationException;
+import javax.xml.datatype.DatatypeFactory;
+import javax.xml.datatype.XMLGregorianCalendar;
+
+import org.apache.freemarker.core.util._DateUtil.CalendarFieldsToDateConverter;
+import org.apache.freemarker.core.util._DateUtil.DateParseException;
+import org.apache.freemarker.core.util._DateUtil.DateToISO8601CalendarFactory;
+import org.apache.freemarker.core.util._DateUtil.TrivialCalendarFieldsToDateConverter;
+
+import junit.framework.TestCase;
+
+public class DateUtilTest extends TestCase {
+    
+    private final TimeZone originalDefaultTZ = TimeZone.getDefault();
+
+    @Override
+    protected void setUp() throws Exception {
+        TimeZone.setDefault(TimeZone.getTimeZone("Europe/Prague"));
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        TimeZone.setDefault(originalDefaultTZ);
+    }
+
+    private final DateFormat df
+            = new SimpleDateFormat("G yyyy-MM-dd HH:mm:ss:S Z", Locale.US);
+    {
+        df.setTimeZone(_DateUtil.UTC);
+    }
+    
+    private CalendarFieldsToDateConverter cf2dc = new TrivialCalendarFieldsToDateConverter();
+    
+    private DateToISO8601CalendarFactory calendarFactory
+            = new _DateUtil.TrivialDateToISO8601CalendarFactory();
+    
+    public DateUtilTest(String name) {
+        super(name);
+    }
+    
+    public void testDateToUTCString() throws ParseException {
+        assertEquals(
+                "1998-10-30T15:30:00.512Z",
+                dateToISO8601UTCDateTimeMSString(
+                        df.parse("AD 1998-10-30 19:30:00:512 +0400"), true));
+        assertEquals(
+                "1998-10-30T15:30:00.5Z",
+                dateToISO8601UTCDateTimeMSString(
+                        df.parse("AD 1998-10-30 19:30:00:500 +0400"), true));
+        assertEquals(
+                "1998-10-30T15:30:00.51Z",
+                dateToISO8601UTCDateTimeMSString(
+                        df.parse("AD 1998-10-30 19:30:00:510 +0400"), true));
+        assertEquals(
+                "1998-10-30T15:30:00.1Z",
+                dateToISO8601UTCDateTimeMSString(
+                        df.parse("AD 1998-10-30 19:30:00:100 +0400"), true));
+        assertEquals(
+                "1998-10-30T15:30:00.01Z",
+                dateToISO8601UTCDateTimeMSString(
+                        df.parse("AD 1998-10-30 19:30:00:10 +0400"), true));
+        assertEquals(
+                "1998-10-30T15:30:00.001Z",
+                dateToISO8601UTCDateTimeMSString(
+                        df.parse("AD 1998-10-30 19:30:00:1 +0400"), true));
+        assertEquals(
+                "2000-02-08T06:05:04Z",
+                dateToISO8601UTCDateTimeMSString(
+                        df.parse("AD 2000-02-08 09:05:04:0 +0300"), true));
+        assertEquals(
+                "0099-02-28T06:15:24Z",
+                dateToISO8601UTCDateTimeString(
+                        df.parse(
+                        "AD 0099-03-02 09:15:24:0 +0300"), true));
+        assertEquals(
+                "0010-02-28T06:15:24Z",
+                dateToISO8601UTCDateTimeString(
+                        df.parse("AD 0010-03-02 09:15:24:0 +0300"), true));
+        assertEquals(
+                "0001-02-28T06:15:24Z",
+                dateToISO8601UTCDateTimeString(
+                        df.parse("AD 0001-03-02 09:15:24:0 +0300"), true));
+        assertEquals(
+                "0000-02-29T06:15:24Z",
+                dateToISO8601UTCDateTimeString(
+                        df.parse("BC 0001-03-02 09:15:24:0 +0300"), true));
+        assertEquals(
+                "-1-02-28T06:15:24Z",
+                dateToISO8601UTCDateTimeString(
+                        df.parse("BC 2-03-02 09:15:24:0 +0300"), true));
+        assertEquals(
+                "10000-02-28T06:15:24Z",
+                dateToISO8601UTCDateTimeString(
+                        df.parse("AD 10000-02-28 09:15:24:0 +0300"), true));
+
+        Date d = df.parse("AD 1998-10-30 19:30:00:512 +0400");
+        assertEquals(
+                "1998-10-30",
+                dateToISO8601UTCDateString(d));
+        assertEquals(
+                "15:30:00.512Z",
+                dateToISO8601UTCTimeMSString(d, true));
+        assertEquals(
+                "15:30:00.512",
+                dateToISO8601UTCTimeMSString(d, false));
+        assertEquals(
+                "1998-10-30",
+                dateToISO8601UTCDateString(
+                        new java.sql.Date(d.getTime())));
+        assertEquals(
+                "15:30:00.512Z",
+                dateToISO8601UTCTimeMSString(
+                        new java.sql.Time(d.getTime()), true));
+    }
+
+    public void testLocalTime() throws ParseException {
+        Date dsum = df.parse("AD 2010-05-09 20:00:00:0 UTC");
+        Date dwin = df.parse("AD 2010-01-01 20:00:00:0 UTC");
+        
+        TimeZone tzRome = TimeZone.getTimeZone("Europe/Rome");
+        if (tzRome.getOffset(0) == 0) {
+            throw new RuntimeException(
+                    "Can't get time zone for Europe/Rome!");
+        }
+        assertEquals(
+                "2010-05-09T22:00:00+02:00",
+                dateToISO8601DateTimeString(dsum, tzRome));
+        assertEquals(
+                "2010-01-01T21:00:00+01:00",
+                dateToISO8601DateTimeString(dwin, tzRome));
+        assertEquals(
+                "2010-05-09",
+                dateToISO8601DateString(dsum, tzRome));
+        assertEquals(
+                "2010-01-01",
+                dateToISO8601DateString(dwin, tzRome));
+        assertEquals(
+                "22:00:00+02:00",
+                dateToISO8601TimeString(dsum, tzRome));
+        assertEquals(
+                "21:00:00+01:00",
+                dateToISO8601TimeString(dwin, tzRome));
+        
+        TimeZone tzNY = TimeZone.getTimeZone("America/New_York");
+        if (tzNY.getOffset(0) == 0) {
+            throw new RuntimeException(
+                    "Can't get time zone for America/New_York!");
+        }
+        assertEquals(
+                "2010-05-09T16:00:00-04:00",
+                dateToISO8601DateTimeString(dsum, tzNY));
+        assertEquals(
+                "2010-01-01T15:00:00-05:00",
+                dateToISO8601DateTimeString(dwin, tzNY));
+        assertEquals(
+                "2010-05-09",
+                dateToISO8601DateString(dsum, tzNY));
+        assertEquals(
+                "2010-01-01",
+                dateToISO8601DateString(dwin, tzNY));
+        assertEquals(
+                "16:00:00-04:00",
+                dateToISO8601TimeString(dsum, tzNY));
+        assertEquals(
+                "15:00:00-05:00",
+                dateToISO8601TimeString(dwin, tzNY));
+        
+        TimeZone tzFixed = TimeZone.getTimeZone("GMT+02:30");
+        assertEquals(
+                "2010-05-09T22:30:00+02:30",
+                dateToISO8601DateTimeString(dsum, tzFixed));
+        assertEquals(
+                "2010-01-01T22:30:00+02:30",
+                dateToISO8601DateTimeString(dwin, tzFixed));
+    }
+
+    public void testGetTimeZone() throws Exception {
+        assertTrue(_DateUtil.getTimeZone("GMT") != _DateUtil.UTC);
+        assertTrue(_DateUtil.getTimeZone("UT1") != _DateUtil.UTC);
+        assertEquals(_DateUtil.getTimeZone("UTC"), _DateUtil.UTC);
+        
+        assertEquals(_DateUtil.getTimeZone("Europe/Rome"),
+                TimeZone.getTimeZone("Europe/Rome"));
+        
+        assertEquals(_DateUtil.getTimeZone("Iceland"), // GMT and no DST
+                TimeZone.getTimeZone("Iceland"));
+        
+        try {
+            _DateUtil.getTimeZone("Europe/NoSuch");
+            fail();
+        } catch (UnrecognizedTimeZoneException e) {
+            // good
+        }
+    }
+    
+    public void testTimeOnlyDate() throws UnrecognizedTimeZoneException {
+        Date t = new Date(0L);
+        SimpleDateFormat tf = new SimpleDateFormat("HH:mm:ss");
+        
+        tf.setTimeZone(_DateUtil.UTC);
+        assertEquals("00:00:00", tf.format(t));
+        assertEquals("00:00:00",
+                dateToISO8601UTCTimeString(t, false));
+        
+        TimeZone gmt1 = _DateUtil.getTimeZone("GMT+01");
+        tf.setTimeZone(gmt1);
+        assertEquals("01:00:00", tf.format(t)); 
+        assertEquals("01:00:00+01:00",
+                dateToISO8601TimeString(t, gmt1));
+    }
+    
+    public void testAccuracy() throws ParseException {
+        Date d = df.parse("AD 2000-02-08 09:05:04:250 UTC"); 
+        assertEquals("2000-02-08T09:05:04Z",
+                dateToISO8601UTCDateTimeString(d, true));
+        assertEquals("2000-02-08T09:05:04.25Z",
+                dateToISO8601String(d, true, true, true,
+                        _DateUtil.ACCURACY_MILLISECONDS, null));
+        assertEquals("2000-02-08T09:05:04Z",
+                dateToISO8601String(d, true, true, true,
+                        _DateUtil.ACCURACY_SECONDS, null));
+        assertEquals("2000-02-08T09:05Z",
+                dateToISO8601String(d, true, true, true,
+                        _DateUtil.ACCURACY_MINUTES, null));
+        assertEquals("2000-02-08T09Z",
+                dateToISO8601String(d, true, true, true,
+                        _DateUtil.ACCURACY_HOURS, null));
+        
+        d = df.parse("AD 1998-10-30 19:30:00:000 +0400");
+        assertEquals(
+                "15:30:00Z",
+                dateToISO8601UTCTimeMSString(d, true));
+        assertEquals(
+                "15:30:00.000Z",
+                dateToISO8601UTCTimeMSFString(d, true));
+        assertEquals(
+                "1998-10-30T15:30:00Z",
+                dateToISO8601UTCDateTimeMSString(d, true));
+        assertEquals(
+                "1998-10-30T15:30:00.000Z",
+                dateToISO8601UTCDateTimeMSFString(d, true));
+                
+        d = df.parse("AD 1998-10-30 19:30:00:100 +0400");
+        assertEquals(
+                "15:30:00.1Z",
+                dateToISO8601UTCTimeMSString(d, true));
+        assertEquals(
+                "15:30:00.100Z",
+                dateToISO8601UTCTimeMSFString(d, true));
+        assertEquals(
+                "1998-10-30T15:30:00.1Z",
+                dateToISO8601UTCDateTimeMSString(d, true));
+        assertEquals(
+                "1998-10-30T15:30:00.100Z",
+                dateToISO8601UTCDateTimeMSFString(d, true));
+        
+        d = df.parse("AD 1998-10-30 19:30:00:010 +0400");
+        assertEquals(
+                "15:30:00.01Z",
+                dateToISO8601UTCTimeMSString(d, true));
+        assertEquals(
+                "15:30:00.010Z",
+                dateToISO8601UTCTimeMSFString(d, true));
+        assertEquals(
+                "1998-10-30T15:30:00.01Z",
+                dateToISO8601UTCDateTimeMSString(d, true));
+        assertEquals(
+                "1998-10-30T15:30:00.010Z",
+                dateToISO8601UTCDateTimeMSFString(d, true));
+        
+        d = df.parse("AD 1998-10-30 19:30:00:001 +0400");
+        assertEquals(
+                "15:30:00.001Z",
+                dateToISO8601UTCTimeMSString(d, true));
+        assertEquals(
+                "15:30:00.001Z",
+                dateToISO8601UTCTimeMSFString(d, true));
+        assertEquals(
+                "1998-10-30T15:30:00.001Z",
+                dateToISO8601UTCDateTimeMSString(d, true));
+        assertEquals(
+                "1998-10-30T15:30:00.001Z",
+                dateToISO8601UTCDateTimeMSFString(d, true));
+    }
+
+    public void testXSFormatISODeviations() throws ParseException, UnrecognizedTimeZoneException {
+        Date dsum = df.parse("AD 2010-05-09 20:00:00:0 UTC");
+        Date dwin = df.parse("AD 2010-01-01 20:00:00:0 UTC");
+        
+        TimeZone tzRome = _DateUtil.getTimeZone("Europe/Rome");
+        
+        assertEquals(
+                "2010-01-01T21:00:00+01:00",
+                _DateUtil.dateToXSString(dwin, true, true, true, _DateUtil.ACCURACY_SECONDS, tzRome, calendarFactory));
+        assertEquals(
+                "2010-05-09T22:00:00+02:00",
+                _DateUtil.dateToXSString(dsum, true, true, true, _DateUtil.ACCURACY_SECONDS, tzRome, calendarFactory));
+        assertEquals(
+                "2010-01-01+01:00",  // ISO doesn't allow date-only with TZ
+                _DateUtil.dateToXSString(dwin, true, false, true, _DateUtil.ACCURACY_SECONDS, tzRome, calendarFactory));
+        assertEquals(
+                "2010-05-09+02:00",  // ISO doesn't allow date-only with TZ
+                _DateUtil.dateToXSString(dsum, true, false, true, _DateUtil.ACCURACY_SECONDS, tzRome, calendarFactory));
+        assertEquals(
+                "21:00:00+01:00",
+                _DateUtil.dateToXSString(dwin, false, true, true, _DateUtil.ACCURACY_SECONDS, tzRome, calendarFactory));
+        assertEquals(
+                "22:00:00+02:00",
+                _DateUtil.dateToXSString(dsum, false, true, true, _DateUtil.ACCURACY_SECONDS, tzRome, calendarFactory));
+        
+        assertEquals(
+                "-1-02-29T06:15:24Z",  // ISO uses 0 for BC 1
+                _DateUtil.dateToXSString(
+                        df.parse("BC 0001-03-02 09:15:24:0 +0300"),
+                        true, true, true, _DateUtil.ACCURACY_SECONDS, _DateUtil.UTC, calendarFactory));
+        assertEquals(
+                "-2-02-28T06:15:24Z",  // ISO uses -1 for BC 2
+                _DateUtil.dateToXSString(
+                        df.parse("BC 2-03-02 09:15:24:0 +0300"),
+                        true, true, true, _DateUtil.ACCURACY_SECONDS, _DateUtil.UTC, calendarFactory));
+    }
+    
+    private String dateToISO8601DateTimeString(
+            Date date, TimeZone tz) {
+        return dateToISO8601String(date, true, true, true,
+                _DateUtil.ACCURACY_SECONDS, tz);
+    }
+    
+    private String dateToISO8601UTCDateTimeString(
+            Date date, boolean offsetPart) {
+        return dateToISO8601String(date, true, true, offsetPart,
+                _DateUtil.ACCURACY_SECONDS, _DateUtil.UTC);
+    }
+
+    private String dateToISO8601UTCDateTimeMSString(
+            Date date, boolean offsetPart) {
+        return dateToISO8601String(date, true, true, offsetPart,
+                _DateUtil.ACCURACY_MILLISECONDS, _DateUtil.UTC);
+    }
+
+    private String dateToISO8601UTCDateTimeMSFString(
+            Date date, boolean offsetPart) {
+        return dateToISO8601String(date, true, true, offsetPart,
+                _DateUtil.ACCURACY_MILLISECONDS_FORCED, _DateUtil.UTC);
+    }
+        
+    private String dateToISO8601DateString(Date date, TimeZone tz) {
+        return dateToISO8601String(date, true, false, false,
+                _DateUtil.ACCURACY_SECONDS, tz);
+    }
+
+    private String dateToISO8601UTCDateString(Date date) {
+        return dateToISO8601String(date, true, false, false,
+                _DateUtil.ACCURACY_SECONDS, _DateUtil.UTC);
+    }
+    
+    private String dateToISO8601TimeString(
+            Date date, TimeZone tz) {
+        return dateToISO8601String(date, false, true, true,
+                _DateUtil.ACCURACY_SECONDS, tz);
+    }
+    
+    private String dateToISO8601UTCTimeString(
+            Date date, boolean offsetPart) {
+        return dateToISO8601String(date, false, true, offsetPart,
+                _DateUtil.ACCURACY_SECONDS, _DateUtil.UTC);
+    }
+
+    private String dateToISO8601UTCTimeMSString(
+            Date date, boolean offsetPart) {
+        return dateToISO8601String(date, false, true, offsetPart,
+                _DateUtil.ACCURACY_MILLISECONDS, _DateUtil.UTC);
+    }
+
+    private String dateToISO8601UTCTimeMSFString(
+            Date date, boolean offsetPart) {
+        return dateToISO8601String(date, false, true, offsetPart,
+                _DateUtil.ACCURACY_MILLISECONDS_FORCED, _DateUtil.UTC);
+    }
+    
+    private String dateToISO8601String(
+            Date date,
+            boolean datePart, boolean timePart, boolean offsetPart,
+            int accuracy,
+            TimeZone timeZone) {
+        return _DateUtil.dateToISO8601String(
+                date,
+                datePart, timePart, offsetPart,
+                accuracy,
+                timeZone,
+                calendarFactory);        
+    }
+    
+    public void testParseDate() throws DateParseException {
+        assertDateParsing(
+                "AD 1998-10-29 20:00:00:0 +0000",
+                null,
+                "1998-10-30+04:00", _DateUtil.UTC);
+        assertDateParsing(
+                "AD 1998-10-30 02:00:00:0 +0000",
+                null,
+                "1998-10-30-02:00", _DateUtil.UTC);
+        assertDateParsing(
+                "AD 1998-10-30 02:00:00:0 +0000",
+                "1998-10-30", _DateUtil.parseXSTimeZone("-02:00"));
+        assertDateParsing(
+                null,
+                "AD 1998-10-30 02:00:00:0 +0000",
+                "19981030", _DateUtil.parseXSTimeZone("-02:00"));
+        assertDateParsing(
+                "AD 1998-10-30 00:00:00:0 +0000",
+                null,
+                "1998-10-30Z", _DateUtil.UTC);
+        assertDateParsing(
+                "AD 1998-10-30 00:00:00:0 +0000",
+                "1998-10-30", _DateUtil.UTC);
+        assertDateParsing(
+                null,
+                "AD 1998-10-30 00:00:00:0 +0000",
+                "19981030", _DateUtil.UTC);
+
+        assertDateParsing(
+                "AD 1998-10-29 20:00:00:0 +0000",
+                null,
+                "1998-10-30+04:00", _DateUtil.UTC);
+        assertDateParsing(
+                "AD 1998-10-30 04:00:00:0 +0000",
+                null,
+                "1998-10-30-04:00", _DateUtil.UTC);
+        assertDateParsing(
+                "AD 1998-10-30 00:00:00:0 +0000",
+                null,
+                "1998-10-30Z", _DateUtil.UTC);
+        
+        try {
+            // XS doesn't have year 0
+            assertDateParsing(
+                    "BC 0000-02-05 00:00:00:0 +0000",
+                    null,
+                    "0000-02-03Z", _DateUtil.UTC);
+            fail();
+        } catch (DateParseException e) {
+            echo(e);
+        }
+        assertDateParsing(
+                null,
+                "BC 0001-02-05 00:00:00:0 +0000",
+                "0000-02-03", _DateUtil.UTC);
+        assertDateParsing(
+                null,
+                "BC 0001-02-05 00:00:00:0 +0000",
+                "00000203", _DateUtil.UTC);
+        
+        assertDateParsing(
+                "BC 0001-02-05 00:00:00:0 +0000",  // Julian
+                "BC 0002-02-05 00:00:00:0 +0000",  // Julian
+                "-0001-02-03", _DateUtil.UTC);  // Proleptic Gregorian
+        assertDateParsing(
+                null,
+                "BC 0002-02-05 00:00:00:0 +0000",  // Julian
+                "-00010203", _DateUtil.UTC);  // Proleptic Gregorian
+
+        assertDateParsing(
+                "AD 0001-02-05 00:00:00:0 +0000",  // Julian
+                null,
+                "0001-02-03Z", _DateUtil.UTC);  // Proleptic Gregorian
+        assertDateParsing(
+                "AD 0001-02-05 00:00:00:0 +0000",  // Julian
+                "0001-02-03", _DateUtil.UTC);  // Proleptic Gregorian
+        assertDateParsing(
+                null,
+                "AD 0001-02-05 00:00:00:0 +0000",  // Julian
+                "00010203", _DateUtil.UTC);  // Proleptic Gregorian
+        assertDateParsing(
+                "AD 1001-12-07 00:00:00:0 +0000",  // Julian
+                null,
+                "1001-12-13Z", _DateUtil.UTC);  // Proleptic Gregorian
+        assertDateParsing(
+                "AD 1001-12-07 00:00:00:0 +0000",  // Julian
+                "1001-12-13", _DateUtil.UTC);  // Proleptic Gregorian
+        
+        assertDateParsing(
+                "AD 2006-12-31 00:00:00:0 +0000",
+                null,
+                "2006-12-31Z", _DateUtil.UTC);
+        assertDateParsing(
+                "AD 2006-12-31 00:00:00:0 +0000",
+                "2006-12-31", _DateUtil.UTC);
+        assertDateParsing(
+                "AD 2006-01-01 00:00:00:0 +0000",
+                null,
+                "2006-01-01Z", _DateUtil.UTC);
+        assertDateParsing(
+                "AD 2006-01-01 00:00:00:0 +0000",
+                "2006-01-01", _DateUtil.UTC);
+        assertDateParsing(
+                "AD 12006-01-01 00:00:00:0 +0000",
+                "12006-01-01", _DateUtil.UTC);
+        assertDateParsing(
+                null,
+                "AD 12006-01-01 00:00:00:0 +0000",
+                "120060101", _DateUtil.UTC);
+    }
+
+    public void testParseDateMalformed() {
+        assertDateMalformed("1998-10-30x");
+        assertDateMalformed("+1998-10-30");
+        assertDateMalformed("1998-10-");
+        assertDateMalformed("1998-1-30");
+        assertDateMalformed("1998-10-30+01");
+        assertDateMalformed("1998-00-01");
+        assertDateMalformed("1998-13-01");
+        assertDateMalformed("1998-10-00");
+        assertDateMalformed("1998-10-32");
+        assertDateMalformed("1998-02-31");
+        
+        assertISO8601DateMalformed("2100103");
+        assertISO8601DateMalformed("210-01-03");
+        assertISO8601DateMalformed("2012-0301");
+        assertISO8601DateMalformed("201203-01");
+        assertISO8601DateMalformed("2012-01-01+01:00");
+    }
+    
+    public void testParseTime() throws DateParseException {
+        assertTimeParsing(
+                "AD 1970-01-01 17:30:05:0 +0000",
+                "17:30:05", _DateUtil.UTC);
+        assertTimeParsing(
+                null,
+                "AD 1970-01-01 17:30:05:0 +0000",
+                "173005", _DateUtil.UTC);
+        assertTimeParsing(
+                "AD 1970-01-01 07:30:00:100 +0000",
+                "07:30:00.1", _DateUtil.UTC);
+        assertTimeParsing(
+                "AD 1970-01-01 07:30:00:120 +0000",
+                "07:30:00.12", _DateUtil.UTC);
+        assertTimeParsing(
+                "AD 1970-01-01 07:30:00:123 +0000",
+                "07:30:00.123", _DateUtil.UTC);
+        assertTimeParsing(
+                "AD 1970-01-01 07:30:00:123 +0000",
+                "07:30:00.1235", _DateUtil.UTC);
+        assertTimeParsing(
+                "AD 1970-01-01 07:30:00:123 +0000",
+                "07:30:00.12346", _DateUtil.UTC);
+        assertTimeParsing(
+                null,
+                "AD 1970-01-01 07:30:00:123 +0000",
+                "073000.12346", _DateUtil.UTC);
+        assertTimeParsing(
+                null,
+                "AD 1970-01-01 07:30:00:123 +0000",
+                "073000,12346", _DateUtil.UTC);
+        assertTimeParsing(
+                "AD 1970-01-01 07:30:00:120 +0000",
+                "07:30:00.12", _DateUtil.UTC);
+        assertTimeParsing(
+                "AD 1970-01-01 07:30:00:500 +0000",
+                "07:30:00.5", _DateUtil.UTC);
+
+        assertTimeParsing(
+                "AD 1970-01-01 16:30:05:0 +0000",
+                "17:30:05+01:00", _DateUtil.UTC);
+        assertTimeParsing(
+                null,
+                "AD 1970-01-01 16:30:05:0 +0000",
+                "173005+01", _DateUtil.UTC);
+        assertTimeParsing(
+                "AD 1970-01-01 19:00:05:0 +0000",
+                "17:30:05-01:30", _DateUtil.UTC);
+        assertTimeParsing(
+                null,
+                "AD 1970-01-01 19:00:05:0 +0000",
+                "173005-0130", _DateUtil.UTC);
+        assertTimeParsing(
+                "AD 1970-01-01 16:30:05:500 +0000",
+                "17:30:05.5+01:00", _DateUtil.UTC);
+        assertTimeParsing(
+                null,
+                "AD 1970-01-01 16:30:05:500 +0000",
+                "173005.5+0100", _DateUtil.UTC);
+        assertTimeParsing(
+                null,
+                "AD 1970-01-01 16:30:05:500 +0000",
+                "173005.5+01", _DateUtil.UTC);
+        assertTimeParsing(
+                null,
+                "AD 1970-01-01 16:00:00:0 +0000",
+                "170000+01", _DateUtil.UTC);
+        assertTimeParsing(
+                null,
+                "AD 1970-01-01 16:00:00:0 +0000",
+                "1700+01", _DateUtil.UTC);
+        assertTimeParsing(
+                null,
+                "AD 1970-01-01 16:00:00:0 +0000",
+                "17+01", _DateUtil.UTC);
+        
+        assertTimeParsing(
+                "AD 1970-01-01 00:00:00:0 +0000",
+                "00:00:00", _DateUtil.UTC);
+        assertTimeParsing(
+                "AD 1970-01-02 00:00:00:0 +0000",
+                "24:00:00", _DateUtil.UTC);
+        assertTimeParsing(
+                null,
+                "AD 1970-01-02 00:00:00:0 +0000",
+                "240000", _DateUtil.UTC);
+        assertTimeParsing(
+                null,
+                "AD 1970-01-02 00:00:00:0 +0000",
+                "2400", _DateUtil.UTC);
+        assertTimeParsing(
+                null,
+                "AD 1970-01-02 00:00:00:0 +0000",
+                "24:00", _DateUtil.UTC);
+        assertTimeParsing(
+                null,
+                "AD 1970-01-02 00:00:00:0 +0000",
+                "24", _DateUtil.UTC);
+        
+        assertTimeParsing(
+                "AD 1970-01-01 23:59:59:999 +0000",
+                "23:59:59.999", _DateUtil.UTC);
+    }
+
+    public void testParseTimeMalformed() {
+        assertTimeMalformed("00:0000");
+        assertTimeMalformed("00:00:00-01:60");
+        assertTimeMalformed("24:00:01");
+        assertTimeMalformed("00:00:61");
+        assertTimeMalformed("00:60:00");
+        assertTimeMalformed("25:00:00");
+        assertTimeMalformed("2:00:00");
+        assertTimeMalformed("02:0:00");
+        assertTimeMalformed("02:00:0");
+        
+        assertISO8601TimeMalformed("1010101");
+        assertISO8601TimeMalformed("10101");
+        assertISO8601TimeMalformed("101");
+        assertISO8601TimeMalformed("1");
+        assertISO8601TimeMalformed("101010-1");
+        assertISO8601TimeMalformed("101010-100");
+        assertISO8601TimeMalformed("101010-10000");
+        assertISO8601TimeMalformed("101010+1");
+        assertISO8601TimeMalformed("101010+100");
+        assertISO8601TimeMalformed("101010+10000");
+    }
+    
+    public void testParseDateTime() throws DateParseException {
+        assertDateTimeParsing( 
+                "AD 1998-10-30 11:30:00:0 +0000",
+                "1998-10-30T15:30:00+04:00", _DateUtil.UTC);
+        assertDateTimeParsing(
+                null,
+                "AD 1998-10-30 11:30:00:0 +0000",
+                "19981030T153000+0400", _DateUtil.UTC);
+        assertDateTimeParsing(
+                "AD 1998-10-30 11:30:00:500 +0000",
+                "1998-10-30T15:30:00.5+04:00", _DateUtil.UTC);
+        assertDateTimeParsing(
+                "AD 1998-10-30 15:30:00:0 +0000",
+                "1998-10-30T15:30:00Z", _DateUtil.UTC);
+        assertDateTimeParsing(
+                null,
+                "AD 1998-10-30 15:30:00:0 +0000",
+                "19981030T1530Z", _DateUtil.UTC);
+        assertDateTimeParsing(
+                "AD 1998-10-30 15:30:00:500 +0000",
+                "1998-10-30T15:30:00.5Z", _DateUtil.UTC);
+        assertDateTimeParsing(
+                "AD 1998-10-30 11:30:00:0 +0000",
+                "1998-10-30T15:30:00+04:00", _DateUtil.UTC);
+        assertDateTimeParsing(
+                "AD 1998-10-30 15:30:00:0 +0000",
+                "1998-10-30T15:30:00Z", _DateUtil.UTC);
+        assertDateTimeParsing(
+                "AD 1998-10-30 15:30:00:0 +0000",
+                "1998-10-30T15:30:00", _DateUtil.UTC);
+        assertDateTimeParsing(
+                null,
+                "AD 1998-10-30 15:30:00:0 +0000",
+                "1998-10-30T15:30", _DateUtil.UTC);
+        
+        assertDateTimeParsing(
+                "AD 1998-10-29 20:00:00:0 +0000",
+                "1998-10-30T00:00:00+04:00", _DateUtil.UTC);
+        assertDateTimeParsing(
+                "AD 1998-10-30 02:00:00:0 +0000",
+                "1998-10-30T00:00:00-02:00", _DateUtil.UTC);
+        assertDateTimeParsing(
+                "AD 1998-10-30 00:00:00:0 +0000",
+                "1998-10-30T00:00:00Z", _DateUtil.UTC);
+
+        assertDateTimeParsing(
+                "AD 1998-10-29 20:00:00:0 +0000",
+                "1998-10-30T00:00:00+04:00", _DateUtil.UTC);
+        assertDateTimeParsing(
+                "AD 1998-10-30 00:00:00:0 +0000",
+                "1998-10-30T00:00:00Z", _DateUtil.UTC);
+        assertDateTimeParsing(
+                null,
+                "AD 1998-10-30 00:00:00:0 +0000",
+                "1998-10-30T00:00Z", _DateUtil.UTC);
+        assertDateTimeParsing(
+                null,
+                "AD 1998-10-30 00:00:00:0 +0000",
+                "1998-10-30T00:00", _DateUtil.UTC);
+        assertDateTimeParsing(
+                null,
+                "AD 1998-10-30 00:00:00:0 +0000",
+                "19981030T00Z", _DateUtil.UTC);
+        
+        // BC years
+        try {
+            assertDateTimeParsing(
+                        "",
+                        null,
+                        "0000-02-03T00:00:00Z", _DateUtil.UTC);
+            fail();
+        } catch (DateParseException e) {
+            echo(e);
+        }
+        assertDateTimeParsing(
+                null,
+                "BC 0001-02-05 00:00:00:0 +0000",
+                "0000-02-03T00:00:00Z", _DateUtil.UTC);
+        
+        assertDateTimeParsing(
+                "BC 0001-02-05 00:00:00:0 +0000",  // Julian
+                "BC 0002-02-05 00:00:00:0 +0000",  // Julian
+                "-0001-02-03T00:00:00Z", _DateUtil.UTC);  // Proleptic Gregorian
+
+        assertDateTimeParsing(
+                "AD 0001-02-05 00:00:00:0 +0000",  // Julian
+                "0001-02-03T00:00:00Z", _DateUtil.UTC);  // Proleptic Gregorian
+        assertDateTimeParsing(
+                "AD 1001-12-07 00:00:00:0 +0000",  // Julian
+                "1001-12-13T00:00:00Z", _DateUtil.UTC);  // Proleptic Gregorian
+        assertDateTimeParsing(
+                "AD 11001-12-13 00:00:00:0 +0000",
+                "11001-12-13T00:00:00Z", _DateUtil.UTC);
+        assertDateTimeParsing(
+                null,
+                "AD 11001-12-13 00:00:00:0 +0000",
+                "110011213T00Z", _DateUtil.UTC);
+        
+        assertDateTimeParsing(
+                "AD 2006-12-31 00:00:00:0 +0000",
+                "2006-12-31T00:00:00Z", _DateUtil.UTC);
+        assertDateTimeParsing(
+                "AD 2006-01-01 00:00:00:0 +0000",
+                "2006-01-01T00:00:00Z", _DateUtil.UTC);
+        
+        assertDateTimeParsing(
+                "AD 1970-01-01 07:30:00:123 +0000",
+                "1970-01-01T07:30:00.123", _DateUtil.UTC);
+        assertDateTimeParsing(
+                "AD 1970-01-01 07:30:00:123 +0000",
+                "1970-01-01T07:30:00.1235", _DateUtil.UTC);
+        assertDateTimeParsing(
+                "AD 1970-01-01 07:30:00:123 +0000",
+                "1970-01-01T07:30:00.12346", _DateUtil.UTC);
+        assertDateTimeParsing(
+                "AD 1970-01-01 07:30:00:120 +0000",
+                "1970-01-01T07:30:00.12", _DateUtil.UTC);
+        assertDateTimeParsing(
+                "AD 1970-01-01 07:30:00:500 +0000",
+                "1970-01-01T07:30:00.5", _DateUtil.UTC);
+
+        assertDateTimeParsing(
+                "AD 1970-01-01 16:30:05:0 +0000",
+                "1970-01-01T17:30:05+01:00", _DateUtil.UTC);
+        assertDateTimeParsing(
+                "AD 1970-01-01 16:30:05:500 +0000",
+                "1970-01-01T17:30:05.5+01:00", _DateUtil.UTC);
+        
+        assertDateTimeParsing(
+                "AD 1970-01-01 00:00:00:0 +0000",
+                "1970-01-01T00:00:00", _DateUtil.UTC);
+        assertDateTimeParsing(
+                "AD 1970-01-02 00:00:00:0 +0000",
+                "1970-01-01T24:00:00", _DateUtil.UTC);
+        
+        assertDateTimeParsing(
+                "AD 1970-01-01 23:59:59:999 +0000",
+                "1970-01-01T23:59:59.999", _DateUtil.UTC);
+    }
+
+    public void testParseDateTimeMalformed() throws DateParseException {
+        assertDateTimeMalformed("1998-00-01T00:00:00");
+        assertDateTimeMalformed("1998-13-01T00:00:00");
+        assertDateTimeMalformed("1998-10-00T00:00:00");
+        assertDateTimeMalformed("1998-10-32T00:00:00");
+        assertDateTimeMalformed("1998-02-31T00:00:00");
+        assertDateTimeMalformed("1970-01-02T24:00:01");
+        assertDateTimeMalformed("1970-01-01T00:00:61");
+        assertDateTimeMalformed("1970-01-01T00:60:00");
+        assertDateTimeMalformed("1970-01-01T25:00:00");
+        
+        assertISO8601DateTimeMalformed("197-01-01T20:00:00");
+    }
+    
+    public void testParseXSTimeZone() throws DateParseException {
+        assertEquals(0,
+                _DateUtil.parseXSTimeZone("Z").getOffset(0));
+        assertEquals(0,
+                _DateUtil.parseXSTimeZone("-00:00").getOffset(0));
+        assertEquals(0,
+                _DateUtil.parseXSTimeZone("+00:00").getOffset(0));
+        assertEquals(90 * 60 * 1000,
+                _DateUtil.parseXSTimeZone("+01:30").getOffset(0));
+        assertEquals(-4 * 60 * 60 * 1000,
+                _DateUtil.parseXSTimeZone("-04:00").getOffset(0));
+        assertEquals(((-23 * 60) - 59) * 60 * 1000,
+                _DateUtil.parseXSTimeZone("-23:59").getOffset(0));
+        assertEquals(((23 * 60) + 59) * 60 * 1000,
+                _DateUtil.parseXSTimeZone("+23:59").getOffset(0));
+    }
+
+    public void testParseXSTimeZoneWrong() {
+        try {
+            _DateUtil.parseXSTimeZone("04:00").getOffset(0);
+            fail();
+        } catch (DateParseException e) {
+            echo(e);
+        }
+        try {
+            _DateUtil.parseXSTimeZone("-04:00x").getOffset(0);
+            fail();
+        } catch (DateParseException e) {
+            echo(e);
+        }
+        try {
+            _DateUtil.parseXSTimeZone("-04").getOffset(0);
+            fail();
+        } catch (DateParseException e) {
+            echo(e);
+        }
+        try {
+            _DateUtil.parseXSTimeZone("+24:00").getOffset(0);
+            fail();
+        } catch (DateParseException e) {
+            echo(e);
+        }
+        try {
+            _DateUtil.parseXSTimeZone("-24:00").getOffset(0);
+            fail();
+        } catch (DateParseException e) {
+            echo(e);
+        }
+        try {
+            _DateUtil.parseXSTimeZone("-01:60").getOffset(0);
+            fail();
+        } catch (DateParseException e) {
+            echo(e);
+        }
+    }
+    
+    public void testParseXSDateTimeFTLAndJavax() throws DateParseException {
+        // Explicit time zone:
+        assertJavaxAndFTLXSDateTimesSame("2014-01-01T13:35:08Z");
+        assertJavaxAndFTLXSDateTimesSame("2014-01-01T13:35:08+02:00");
+        
+        // Default time zone:
+        assertJavaxAndFTLXSDateTimesSame("2014-01-01T13:35:08"); // winter
+        assertJavaxAndFTLXSDateTimesSame("2014-07-01T13:35:08"); // summer
+        
+        // Proleptic Gregorian
+        assertJavaxAndFTLXSDateTimesSame("1500-01-01T13:35:08Z");
+        assertJavaxAndFTLXSDateTimesSame("0200-01-01T13:35:08Z");
+        assertJavaxAndFTLXSDateTimesSame("0001-01-01T00:00:00+05:00");
+        
+        // BC
+        assertJavaxAndFTLXSDateTimesSame("0001-01-01T13:35:08Z");
+        assertJavaxAndFTLXSDateTimesSame("-0001-01-01T13:35:08Z");
+        
+        // Hour 24
+        assertJavaxAndFTLXSDateTimesSame("2014-01-01T23:59:59");
+        if (isAtLeastJava6()) { // Java 5 has broken parser that doesn't allow 24.
+            assertJavaxAndFTLXSDateTimesSame("2014-01-31T24:00:00");
+            assertJavaxAndFTLXSDateTimesSame("2014-01-01T24:00:00");
+        }
+        assertJavaxAndFTLXSDateTimesSame("2014-01-02T00:00:00");  // same as the previous
+        assertJavaxAndFTLXSDateTimesSame("2014-02-01T00:00:00");  // same as the previous
+        
+        // Under ms
+        assertJavaxAndFTLXSDateTimesSame("2014-01-01T23:59:59.123456789");
+        assertJavaxAndFTLXSDateTimesSame("2014-01-01T23:59:59.1235");
+    }
+    
+    private boolean isAtLeastJava6() {
+        try {
+            Class.forName("java.lang.management.LockInfo");
+        } catch (ClassNotFoundException e) {
+            return false;
+        }
+        return true;
+    }
+
+    private final DatatypeFactory datetypeFactory;
+    {
+        try {
+            datetypeFactory = DatatypeFactory.newInstance();
+        } catch (DatatypeConfigurationException e) {
+            throw new RuntimeException(e);
+        } 
+    }
+    
+    private void assertJavaxAndFTLXSDateTimesSame(String s) throws DateParseException {
+        XMLGregorianCalendar xgc = datetypeFactory.newXMLGregorianCalendar(s);
+        Date javaxDate = xgc.toGregorianCalendar().getTime();
+        Date ftlDate = _DateUtil.parseXSDateTime(s, TimeZone.getDefault(), cf2dc);
+        assertEquals(javaxDate, ftlDate);
+    }
+
+    private void assertDateParsing(String expected, String parsed, TimeZone tz) throws DateParseException {
+        assertDateParsing(expected, expected, parsed, tz);
+    }
+
+    private void assertDateParsing(String expectedXS, String expectedISO8601, String parsed, TimeZone tz)
+            throws DateParseException {
+        if (expectedXS != null) {
+            assertEquals(
+                    expectedXS,
+                    df.format(_DateUtil.parseXSDate(parsed, tz, cf2dc)));
+        }
+        if (expectedISO8601 != null) {
+            assertEquals(
+                    expectedISO8601,
+                    df.format(_DateUtil.parseISO8601Date(parsed, tz, cf2dc)));
+        }
+    }
+
+    private void assertDateTimeParsing(String expected, String parsed, TimeZone tz) throws DateParseException {
+        assertDateTimeParsing(expected, expected, parsed, tz);
+    }
+
+    private void assertDateTimeParsing(String expectedXS, String expectedISO8601, String parsed, TimeZone tz)
+            throws DateParseException {
+        if (expectedXS != null) {
+            assertEquals(
+                    expectedXS,
+                    df.format(_DateUtil.parseXSDateTime(parsed, tz, cf2dc)));
+        }
+        if (expectedISO8601 != null) {
+            assertEquals(
+                    expectedISO8601,
+                    df.format(_DateUtil.parseISO8601DateTime(parsed, tz, cf2dc)));
+        }
+    }
+
+    private void assertTimeParsing(String expected, String parsed, TimeZone tz) throws DateParseException {
+        assertTimeParsing(expected, expected, parsed, tz);
+    }
+
+    private void assertTimeParsing(String expectedXS, String expectedISO8601, String parsed, TimeZone tz)
+            throws DateParseException {
+        if (expectedXS != null) {
+            assertEquals(
+                    expectedXS,
+                    df.format(_DateUtil.parseXSTime(parsed, tz, cf2dc)));
+        }
+        if (expectedISO8601 != null) {
+            assertEquals(
+                    expectedISO8601,
+                    df.format(_DateUtil.parseISO8601Time(parsed, tz, cf2dc)));
+        }
+    }
+    
+    private void assertDateMalformed(String parsed) {
+        try {
+            _DateUtil.parseXSDate(parsed, _DateUtil.UTC, cf2dc);
+            fail();
+        } catch (DateParseException e) {
+            // Expected
+            echo(e);
+        }
+        try {
+            _DateUtil.parseISO8601Date(parsed, _DateUtil.UTC, cf2dc);
+            fail();
+        } catch (DateParseException e) {
+            // Expected
+            echo(e);
+        }
+    }
+
+    private void assertTimeMalformed(String parsed) {
+        try {
+            _DateUtil.parseXSTime(parsed, _DateUtil.UTC, cf2dc);
+            fail();
+        } catch (DateParseException e) {
+            // Expected
+            echo(e);
+        }
+        try {
+            _DateUtil.parseISO8601Time(parsed, _DateUtil.UTC, cf2dc);
+            fail();
+        } catch (DateParseException e) {
+            // Expected
+            echo(e);
+        }
+    }
+
+    private void assertDateTimeMalformed(String parsed) {
+        try {
+            _DateUtil.parseXSDateTime(parsed, _DateUtil.UTC, cf2dc);
+            fail();
+        } catch (DateParseException e) {
+            // Expected
+            echo(e);
+        }
+        try {
+            _DateUtil.parseISO8601DateTime(parsed, _DateUtil.UTC, cf2dc);
+            fail();
+        } catch (DateParseException e) {
+            // Expected
+            echo(e);
+        }
+    }
+
+    private void assertISO8601DateMalformed(String parsed) {
+        try {
+            _DateUtil.parseISO8601Date(parsed, _DateUtil.UTC, cf2dc);
+            fail();
+        } catch (DateParseException e) {
+            // Expected
+            echo(e);
+        }
+    }
+    
+    private void assertISO8601TimeMalformed(String parsed) {
+        try {
+            _DateUtil.parseISO8601Time(parsed, _DateUtil.UTC, cf2dc);
+            fail();
+        } catch (DateParseException e) {
+            // Expected
+            echo(e);
+        }
+    }
+    
+    private void assertISO8601DateTimeMalformed(String parsed) {
+        try {
+            _DateUtil.parseISO8601DateTime(parsed, _DateUtil.UTC, cf2dc);
+            fail();
+        } catch (DateParseException e) {
+            // Expected
+            echo(e);
+        }
+    }
+    
+    private void echo(@SuppressWarnings("unused") DateParseException e) {
+        // System.out.println(e);
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/util/FTLUtilTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/util/FTLUtilTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/util/FTLUtilTest.java
new file mode 100644
index 0000000..f1e44f3
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/util/FTLUtilTest.java
@@ -0,0 +1,117 @@
+/*
+ * 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.util;
+
+import static junit.framework.TestCase.assertFalse;
+import static junit.framework.TestCase.assertNull;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class FTLUtilTest {
+
+    @Test
+    public void testEscapeStringLiteralPart() {
+        assertEquals("", FTLUtil.escapeStringLiteralPart(""));
+        assertEquals("abc", FTLUtil.escapeStringLiteralPart("abc"));
+        assertEquals("{", FTLUtil.escapeStringLiteralPart("{"));
+        assertEquals("a{b}c", FTLUtil.escapeStringLiteralPart("a{b}c"));
+        assertEquals("a#b", FTLUtil.escapeStringLiteralPart("a#b"));
+        assertEquals("a$b", FTLUtil.escapeStringLiteralPart("a$b"));
+        assertEquals("a#\\{b}c", FTLUtil.escapeStringLiteralPart("a#{b}c"));
+        assertEquals("a$\\{b}c", FTLUtil.escapeStringLiteralPart("a${b}c"));
+        assertEquals("a'c\\\"d", FTLUtil.escapeStringLiteralPart("a'c\"d", '"'));
+        assertEquals("a\\'c\"d", FTLUtil.escapeStringLiteralPart("a'c\"d", '\''));
+        assertEquals("a\\'c\"d", FTLUtil.escapeStringLiteralPart("a'c\"d", '\''));
+        assertEquals("\\n\\r\\t\\f\\x0002\\\\", FTLUtil.escapeStringLiteralPart("\n\r\t\f\u0002\\"));
+        assertEquals("\\l\\g\\a", FTLUtil.escapeStringLiteralPart("<>&"));
+    }
+
+    @Test
+    public void testEscapeStringLiteralAll() {
+        assertFTLEsc("", "", "", "", "\"\"");
+        assertFTLEsc("\'", "\\'", "'", "\\'", "\"'\"");
+        assertFTLEsc("\"", "\\\"", "\\\"", "\"", "'\"'");
+        assertFTLEsc("\"", "\\\"", "\\\"", "\"", "'\"'");
+        assertFTLEsc("foo", "foo", "foo", "foo", "\"foo\"");
+        assertFTLEsc("foo's", "foo\\'s", "foo's", "foo\\'s", "\"foo's\"");
+        assertFTLEsc("foo \"", "foo \\\"", "foo \\\"", "foo \"", "'foo \"'");
+        assertFTLEsc("foo's \"", "foo\\'s \\\"", "foo's \\\"", "foo\\'s \"", "\"foo's \\\"\"");
+        assertFTLEsc("foo\nb\u0000c", "foo\\nb\\x0000c", "foo\\nb\\x0000c", "foo\\nb\\x0000c", "\"foo\\nb\\x0000c\"");
+    }
+
+    private void assertFTLEsc(String s, String partAny, String partQuot, String partApos, String quoted) {
+        assertEquals(partAny, FTLUtil.escapeStringLiteralPart(s));
+        assertEquals(partQuot, FTLUtil.escapeStringLiteralPart(s, '\"'));
+        assertEquals(partApos, FTLUtil.escapeStringLiteralPart(s, '\''));
+        assertEquals(quoted, FTLUtil.toStringLiteral(s));
+    }
+
+    @Test
+    public void testUnescapeStringLiteralPart() throws Exception {
+        assertEquals("", FTLUtil.unescapeStringLiteralPart(""));
+        assertEquals("1", FTLUtil.unescapeStringLiteralPart("1"));
+        assertEquals("123", FTLUtil.unescapeStringLiteralPart("123"));
+        assertEquals("1&2&3", FTLUtil.unescapeStringLiteralPart("1\\a2\\a3"));
+        assertEquals("&", FTLUtil.unescapeStringLiteralPart("\\a"));
+        assertEquals("&&&", FTLUtil.unescapeStringLiteralPart("\\a\\a\\a"));
+        assertEquals(
+                "\u0000\u0000&\u0000\u0000\u0000\u0000",
+                FTLUtil.unescapeStringLiteralPart("\\x0000\\x0000\\a\\x0000\\x000\\x00\\x0"));
+        assertEquals(
+                "'\"\n\b\u0000c><&{\\",
+                FTLUtil.unescapeStringLiteralPart("\\'\\\"\\n\\b\\x0000c\\g\\l\\a\\{\\\\"));
+    }
+
+    @Test
+    public void testEscapeIdentifier() {
+        assertNull(FTLUtil.escapeIdentifier(null));
+        assertEquals("", FTLUtil.escapeIdentifier(""));
+        assertEquals("a", FTLUtil.escapeIdentifier("a"));
+        assertEquals("ab", FTLUtil.escapeIdentifier("ab"));
+        assertEquals("\\.", FTLUtil.escapeIdentifier("."));
+        assertEquals("\\.\\:\\-", FTLUtil.escapeIdentifier(".:-"));
+        assertEquals("a\\.b", FTLUtil.escapeIdentifier("a.b"));
+        assertEquals("a\\.b\\:c\\-d", FTLUtil.escapeIdentifier("a.b:c-d"));
+    }
+
+    @Test
+    public void testIsNonEscapedIdentifierStart() {
+        assertTrue(FTLUtil.isNonEscapedIdentifierPart('a'));
+        assertTrue(FTLUtil.isNonEscapedIdentifierPart('á'));
+        assertTrue(FTLUtil.isNonEscapedIdentifierPart('1'));
+        assertFalse(FTLUtil.isNonEscapedIdentifierPart('-'));
+        assertFalse(FTLUtil.isNonEscapedIdentifierPart(' '));
+        assertFalse(FTLUtil.isNonEscapedIdentifierPart('\u0000'));
+        assertFalse(FTLUtil.isNonEscapedIdentifierPart('\\'));
+    }
+
+    @Test
+    public void testisNonEscapedIdentifierStart() {
+        assertTrue(FTLUtil.isNonEscapedIdentifierStart('a'));
+        assertTrue(FTLUtil.isNonEscapedIdentifierStart('á'));
+        assertFalse(FTLUtil.isNonEscapedIdentifierStart('1'));
+        assertFalse(FTLUtil.isNonEscapedIdentifierStart('-'));
+        assertFalse(FTLUtil.isNonEscapedIdentifierStart(' '));
+        assertFalse(FTLUtil.isNonEscapedIdentifierStart('\u0000'));
+        assertFalse(FTLUtil.isNonEscapedIdentifierStart('\\'));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/util/NumberUtilTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/util/NumberUtilTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/util/NumberUtilTest.java
new file mode 100644
index 0000000..d5709da
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/util/NumberUtilTest.java
@@ -0,0 +1,215 @@
+/*
+ * 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.util;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import org.junit.Test;
+
+import junit.framework.TestCase;
+
+public class NumberUtilTest extends TestCase {
+
+    @Test
+    public void testGetSignum() {
+        assertEquals(1, _NumberUtil.getSignum(Double.valueOf(Double.POSITIVE_INFINITY)));
+        assertEquals(1, _NumberUtil.getSignum(Double.valueOf(3)));
+        assertEquals(0, _NumberUtil.getSignum(Double.valueOf(0)));
+        assertEquals(-1, _NumberUtil.getSignum(Double.valueOf(-3)));
+        assertEquals(-1, _NumberUtil.getSignum(Double.valueOf(Double.NEGATIVE_INFINITY)));
+        try {
+            _NumberUtil.getSignum(Double.valueOf(Double.NaN));
+            fail();
+        } catch (ArithmeticException e) {
+            // expected
+        }
+        
+        assertEquals(1, _NumberUtil.getSignum(Float.valueOf(Float.POSITIVE_INFINITY)));
+        assertEquals(1, _NumberUtil.getSignum(Float.valueOf(3)));
+        assertEquals(0, _NumberUtil.getSignum(Float.valueOf(0)));
+        assertEquals(-1, _NumberUtil.getSignum(Float.valueOf(-3)));
+        assertEquals(-1, _NumberUtil.getSignum(Float.valueOf(Float.NEGATIVE_INFINITY)));
+        try {
+            _NumberUtil.getSignum(Float.valueOf(Float.NaN));
+            fail();
+        } catch (ArithmeticException e) {
+            // expected
+        }
+        
+        assertEquals(1, _NumberUtil.getSignum(Long.valueOf(3)));
+        assertEquals(0, _NumberUtil.getSignum(Long.valueOf(0)));
+        assertEquals(-1, _NumberUtil.getSignum(Long.valueOf(-3)));
+        
+        assertEquals(1, _NumberUtil.getSignum(Integer.valueOf(3)));
+        assertEquals(0, _NumberUtil.getSignum(Integer.valueOf(0)));
+        assertEquals(-1, _NumberUtil.getSignum(Integer.valueOf(-3)));
+        
+        assertEquals(1, _NumberUtil.getSignum(Short.valueOf((short) 3)));
+        assertEquals(0, _NumberUtil.getSignum(Short.valueOf((short) 0)));
+        assertEquals(-1, _NumberUtil.getSignum(Short.valueOf((short) -3)));
+        
+        assertEquals(1, _NumberUtil.getSignum(Byte.valueOf((byte) 3)));
+        assertEquals(0, _NumberUtil.getSignum(Byte.valueOf((byte) 0)));
+        assertEquals(-1, _NumberUtil.getSignum(Byte.valueOf((byte) -3)));
+        
+        assertEquals(1, _NumberUtil.getSignum(BigDecimal.valueOf(3)));
+        assertEquals(0, _NumberUtil.getSignum(BigDecimal.valueOf(0)));
+        assertEquals(-1, _NumberUtil.getSignum(BigDecimal.valueOf(-3)));
+        
+        assertEquals(1, _NumberUtil.getSignum(BigInteger.valueOf(3)));
+        assertEquals(0, _NumberUtil.getSignum(BigInteger.valueOf(0)));
+        assertEquals(-1, _NumberUtil.getSignum(BigInteger.valueOf(-3)));
+    }
+    
+    @Test
+    public void testIsBigDecimalInteger() {
+        BigDecimal n1 = new BigDecimal("1.125");
+        if (n1.precision() != 4 || n1.scale() != 3) {
+            throw new RuntimeException("Wrong: " +  n1);
+        }
+        BigDecimal n2 = new BigDecimal("1.125").subtract(new BigDecimal("0.005"));
+        if (n2.precision() != 4 || n2.scale() != 3) {
+            throw new RuntimeException("Wrong: " +  n2);
+        }
+        BigDecimal n3 = new BigDecimal("123");
+        BigDecimal n4 = new BigDecimal("6000");
+        BigDecimal n5 = new BigDecimal("1.12345").subtract(new BigDecimal("0.12345"));
+        if (n5.precision() != 6 || n5.scale() != 5) {
+            throw new RuntimeException("Wrong: " +  n5);
+        }
+        BigDecimal n6 = new BigDecimal("0"); 
+        BigDecimal n7 = new BigDecimal("0.001").subtract(new BigDecimal("0.001")); 
+        BigDecimal n8 = new BigDecimal("60000.5").subtract(new BigDecimal("0.5")); 
+        BigDecimal n9 = new BigDecimal("6").movePointRight(3).setScale(-3);
+        
+        BigDecimal[] ns = new BigDecimal[] {
+                n1, n2, n3, n4, n5, n6, n7, n8, n9,
+                n1.negate(), n2.negate(), n3.negate(), n4.negate(), n5.negate(), n6.negate(), n7.negate(), n8.negate(),
+                n9.negate(),
+        };
+        
+        for (BigDecimal n : ns) {
+            assertEquals(n.doubleValue() == n.longValue(), _NumberUtil.isIntegerBigDecimal(n));
+        }
+        
+    }
+    
+    @Test
+    public void testToIntExcact() {
+        for (int n : new int[] { Integer.MIN_VALUE, Byte.MIN_VALUE, -1, 0, 1, Byte.MAX_VALUE, Integer.MAX_VALUE }) {
+            if (n != Integer.MIN_VALUE && n != Integer.MAX_VALUE) {
+                assertEquals(n, _NumberUtil.toIntExact(Byte.valueOf((byte) n)));
+                assertEquals(n, _NumberUtil.toIntExact(Short.valueOf((short) n)));
+                assertEquals(n, _NumberUtil.toIntExact(Float.valueOf(n)));
+            }
+            assertEquals(n, _NumberUtil.toIntExact(Integer.valueOf(n)));
+            assertEquals(n, _NumberUtil.toIntExact(Long.valueOf(n)));
+            assertEquals(n, _NumberUtil.toIntExact(Double.valueOf(n)));
+            assertEquals(n, _NumberUtil.toIntExact(BigDecimal.valueOf(n)));
+            assertEquals(n, _NumberUtil.toIntExact(BigDecimal.valueOf(n * 10L).divide(BigDecimal.TEN)));
+            assertEquals(n, _NumberUtil.toIntExact(BigInteger.valueOf(n)));
+        }
+
+        try {
+            _NumberUtil.toIntExact(Long.valueOf(Integer.MIN_VALUE - 1L));
+            fail();
+        } catch (ArithmeticException e) {
+            // Expected
+        }
+        try {
+            _NumberUtil.toIntExact(Long.valueOf(Integer.MAX_VALUE + 1L));
+            fail();
+        } catch (ArithmeticException e) {
+            // Expected
+        }
+
+        try {
+            _NumberUtil.toIntExact(Float.valueOf(1.00001f));
+            fail();
+        } catch (ArithmeticException e) {
+            // Expected
+        }
+        try {
+            _NumberUtil.toIntExact(Float.valueOf(Integer.MIN_VALUE - 129L));
+            fail();
+        } catch (ArithmeticException e) {
+            // Expected
+        }
+        try {
+            _NumberUtil.toIntExact(Float.valueOf(Integer.MAX_VALUE));
+            fail();
+        } catch (ArithmeticException e) {
+            // Expected
+        }
+        
+        try {
+            _NumberUtil.toIntExact(Double.valueOf(1.00001));
+            fail();
+        } catch (ArithmeticException e) {
+            // Expected
+        }
+        try {
+            _NumberUtil.toIntExact(Double.valueOf(Integer.MIN_VALUE - 1L));
+            fail();
+        } catch (ArithmeticException e) {
+            // Expected
+        }
+        try {
+            _NumberUtil.toIntExact(Double.valueOf(Integer.MAX_VALUE + 1L));
+            fail();
+        } catch (ArithmeticException e) {
+            // Expected
+        }
+        
+        try {
+            _NumberUtil.toIntExact(new BigDecimal("100.000001"));
+            fail();
+        } catch (ArithmeticException e) {
+            // Expected
+        }
+        try {
+            _NumberUtil.toIntExact(BigDecimal.valueOf(Integer.MIN_VALUE - 1L));
+            fail();
+        } catch (ArithmeticException e) {
+            // Expected
+        }
+        try {
+            _NumberUtil.toIntExact(BigDecimal.valueOf(Integer.MAX_VALUE + 1L));
+            fail();
+        } catch (ArithmeticException e) {
+            // Expected
+        }
+        
+        try {
+            _NumberUtil.toIntExact(BigInteger.valueOf(Integer.MIN_VALUE - 1L));
+            fail();
+        } catch (ArithmeticException e) {
+            // Expected
+        }
+        try {
+            _NumberUtil.toIntExact(BigInteger.valueOf(Integer.MAX_VALUE + 1L));
+            fail();
+        } catch (ArithmeticException e) {
+            // Expected
+        }
+    }
+
+}


[19/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/ObjectBuilderSettingsTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/ObjectBuilderSettingsTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/ObjectBuilderSettingsTest.java
deleted file mode 100644
index 49534fa..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/ObjectBuilderSettingsTest.java
+++ /dev/null
@@ -1,1499 +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;
-
-import static org.apache.freemarker.test.hamcerst.Matchers.*;
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.io.Serializable;
-import java.io.Writer;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.nio.charset.UnsupportedCharsetException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.TimeZone;
-
-import org.apache.freemarker.core.arithmetic.ArithmeticEngine;
-import org.apache.freemarker.core.arithmetic.impl.BigDecimalArithmeticEngine;
-import org.apache.freemarker.core.model.ObjectWrapper;
-import org.apache.freemarker.core.model.impl.DefaultObjectWrapper;
-import org.apache.freemarker.core.templateresolver.CacheStorage;
-import org.apache.freemarker.core.templateresolver.TemplateLoader;
-import org.apache.freemarker.core.templateresolver.TemplateLoaderSession;
-import org.apache.freemarker.core.templateresolver.TemplateLoadingResult;
-import org.apache.freemarker.core.templateresolver.TemplateLoadingSource;
-import org.apache.freemarker.core.templateresolver.impl.MruCacheStorage;
-import org.apache.freemarker.core.userpkg.PublicWithMixedConstructors;
-import org.junit.Test;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-
-@SuppressWarnings("boxing")
-public class ObjectBuilderSettingsTest {
-
-    @Test
-    public void newInstanceTest() throws Exception {
-        {
-            TestBean1 res = (TestBean1) _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            assertEquals(4f, res.f, 0);
-            assertFalse(res.b);
-        }
-        
-        {
-            TestBean1 res = (TestBean1) _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1()",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            assertEquals(4f, res.f, 0);
-            assertFalse(res.b);
-        }
-        
-        {
-            TestBean1 res = (TestBean1) _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1(1.5, -20, 8589934592, true)",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            assertEquals(1.5f, res.f, 0);
-            assertEquals(Integer.valueOf(-20), res.i);
-            assertEquals(8589934592l, res.l);
-            assertTrue(res.b);
-        }
-        
-        {
-            TestBean1 res = (TestBean1) _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1(1, true)",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            assertEquals(2f, res.f, 0);
-            assertEquals(Integer.valueOf(1), res.i);
-            assertEquals(2l, res.l);
-            assertTrue(res.b);
-        }
-        
-        {
-            TestBean1 res = (TestBean1) _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1(11, 22)",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            assertEquals(3f, res.f, 0);
-            assertEquals(Integer.valueOf(11), res.i);
-            assertEquals(22l, res.l);
-            assertFalse(res.b);
-        }
-        
-        {
-            TestBean1 res = (TestBean1) _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1(p1 = 1, p2 = 2, p3 = true, p4 = 's')",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            assertEquals(4f, res.f, 0);
-            assertFalse(res.b);
-            assertEquals(1d, res.getP1(), 0);
-            assertEquals(2, res.getP2());
-            assertTrue(res.isP3());
-            assertEquals("s", res.getP4());
-        }
-
-        {
-            TestBean1 res = (TestBean1) _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1("
-                    + "null, 2, p1 = 1, p2 = 2, p3 = false, p4 = null)",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            assertNull(res.i);
-            assertEquals(2, res.l, 0);
-            assertEquals(3f, res.f, 0);
-            assertFalse(res.b);
-            assertEquals(1d, res.getP1(), 0);
-            assertEquals(2, res.getP2());
-            assertFalse(res.isP3());
-            assertNull(res.getP4());
-        }
-        
-        {
-            // Deliberately odd spacings
-            TestBean1 res = (TestBean1) _ObjectBuilderSettingEvaluator.eval(
-                    "\t\torg.apache.freemarker .core  . \n"
-                    + "\tObjectBuilderSettingsTest$TestBean1(\n\r\tp1=1\n,p2=2,p3=true,p4='s'  )",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            assertEquals(4f, res.f, 0);
-            assertFalse(res.b);
-            assertEquals(1d, res.getP1(), 0);
-            assertEquals(2, res.getP2());
-            assertTrue(res.isP3());
-            assertEquals("s", res.getP4());
-        }
-        
-        {
-            TestBean1 res = (TestBean1) _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1(1, true, p2 = 2)",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            assertEquals(2f, res.f, 0);
-            assertEquals(Integer.valueOf(1), res.i);
-            assertEquals(2l, res.l);
-            assertTrue(res.b);
-            assertEquals(0d, res.getP1(), 0);
-            assertEquals(2, res.getP2());
-            assertFalse(res.isP3());
-        }
-    }
-    
-    @Test
-    public void builderTest() throws Exception {
-        {
-            // `()`-les syntax:
-            TestBean2 res = (TestBean2) _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean2",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            assertTrue(res.built);
-            assertEquals(0, res.x);
-        }
-        
-        {
-            TestBean2 res = (TestBean2) _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean2()",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            assertTrue(res.built);
-            assertEquals(0, res.x);
-        }
-        
-        {
-            TestBean2 res = (TestBean2) _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean2(x = 1)",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            assertTrue(res.built);
-            assertEquals(1, res.x);
-        }
-        
-        {
-            TestBean2 res = (TestBean2) _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean2(1)",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            assertTrue(res.built);
-            assertEquals(1, res.x);
-        }
-    }
-
-    @Test
-    public void staticInstanceTest() throws Exception {
-        // ()-les syntax:
-        {
-            TestBean5 res = (TestBean5) _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean5",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            assertEquals(0, res.i);
-            assertEquals(0, res.x);
-            assertSame(TestBean5.INSTANCE, res); //!
-        }
-        
-        {
-            TestBean5 res = (TestBean5) _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean5()",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            assertEquals(0, res.i);
-            assertEquals(0, res.x);
-            assertSame(TestBean5.INSTANCE, res); //!
-        }
-        
-        {
-            TestBean5 res = (TestBean5) _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean5(x = 1)",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            assertEquals(0, res.i);
-            assertEquals(1, res.x);
-            assertNotSame(TestBean5.INSTANCE, res);
-        }
-
-        {
-            TestBean5 res = (TestBean5) _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean5(1)",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            assertEquals(1, res.i);
-            assertEquals(0, res.x);
-            assertNotSame(TestBean5.INSTANCE, res);
-        }
-    }
-
-    @Test
-    public void stringLiteralsTest() throws Exception {
-        {
-            TestBean4 res = (TestBean4) _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean4(\"\", '', s3 = r\"\", s4 = r'')",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            assertEquals("", res.getS1());
-            assertEquals("", res.getS2());
-            assertEquals("", res.getS3());
-            assertEquals("", res.getS4());
-        }
-        
-        {
-            TestBean4 res = (TestBean4) _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean4(\"a\", 'b', s3 = r\"c\", s4 = r'd')",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            assertEquals("a", res.getS1());
-            assertEquals("b", res.getS2());
-            assertEquals("c", res.getS3());
-            assertEquals("d", res.getS4());
-        }
-        
-        {
-            TestBean4 res = (TestBean4) _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean4(\"a'A\", 'b\"B', s3 = r\"c'C\", s4 = r'd\"D')",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            assertEquals("a'A", res.getS1());
-            assertEquals("b\"B", res.getS2());
-            assertEquals("c'C", res.getS3());
-            assertEquals("d\"D", res.getS4());
-        }
-        
-        {
-            TestBean4 res = (TestBean4) _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean4("
-                    + "\"a\\nA\\\"a\\\\A\", 'a\\nA\\'a\\\\A', s3 = r\"a\\n\\A\", s4 = r'a\\n\\A')",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            assertEquals("a\nA\"a\\A", res.getS1());
-            assertEquals("a\nA'a\\A", res.getS2());
-            assertEquals("a\\n\\A", res.getS3());
-            assertEquals("a\\n\\A", res.getS4());
-        }
-    }
-
-    @Test
-    public void nestedBuilderTest() throws Exception {
-        {
-            TestBean6 res = (TestBean6) _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean6("
-                    + "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1(11, 22, p4 = 'foo'),"
-                    + "1,"
-                    + "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean2(11),"
-                    + "y=2,"
-                    + "b3=org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean2(x = 22)"
-                    + ")",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            assertEquals(Integer.valueOf(11), res.b1.i);
-            assertEquals(22, res.b1.l);
-            assertEquals("foo", res.b1.p4);
-            assertEquals(1, res.x);
-            assertEquals(11, res.b2.x);
-            assertEquals(2, res.y);
-            assertEquals(22, res.b3.x);
-            assertNull(res.b4);
-        }
-        
-        {
-            TestBean6 res = (TestBean6) _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean6("
-                    + "null,"
-                    + "-1,"
-                    + "null,"
-                    + "b4=org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean6("
-                    + "   org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1(11, 22, p4 = 'foo'),"
-                    + "   1,"
-                    + "   org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean2(11),"
-                    + "   y=2,"
-                    + "   b3=org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean2(x = 22)"
-                    + "),"
-                    + "y=2"
-                    + ")",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            assertNull(res.b1);
-            assertEquals(-1, res.x);
-            assertNull(res.b2);
-            assertEquals(2, res.y);
-            assertEquals(Integer.valueOf(11), res.b4.b1.i);
-            assertEquals(22, res.b4.b1.l);
-            assertEquals("foo", res.b4.b1.p4);
-            assertEquals(1, res.b4.x);
-            assertEquals(11, res.b4.b2.x);
-            assertEquals(2, res.b4.y);
-            assertEquals(22, res.b4.b3.x);
-            assertNull(res.b4.b4);
-        }
-    }
-
-    @Test
-    public void defaultObjectWrapperTest() throws Exception {
-        DefaultObjectWrapper ow = (DefaultObjectWrapper) _ObjectBuilderSettingEvaluator.eval(
-                "DefaultObjectWrapper(3.0.0)",
-                ObjectWrapper.class, false, _SettingEvaluationEnvironment.getCurrent());
-        assertEquals(Configuration.VERSION_3_0_0, ow.getIncompatibleImprovements());
-        assertFalse(ow.isExposeFields());
-    }
-
-    @Test
-    public void defaultObjectWrapperTest2() throws Exception {
-        DefaultObjectWrapper ow = (DefaultObjectWrapper) _ObjectBuilderSettingEvaluator.eval(
-                "DefaultObjectWrapper(3.0.0, exposeFields=true)",
-                ObjectWrapper.class, false, _SettingEvaluationEnvironment.getCurrent());
-        assertEquals(Configuration.VERSION_3_0_0, ow.getIncompatibleImprovements());
-        assertTrue(ow.isExposeFields());
-    }
-
-    @Test
-    public void configurationPropertiesTest() throws Exception {
-        final Configuration.Builder cfgB = new Configuration.Builder(Configuration.getVersion());
-        
-        {
-            Properties props = new Properties();
-            props.setProperty(MutableProcessingConfiguration.OBJECT_WRAPPER_KEY,
-                    "org.apache.freemarker.core.model.impl.DefaultObjectWrapper(3.0.0)");
-            props.setProperty(MutableProcessingConfiguration.ARITHMETIC_ENGINE_KEY,
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$DummyArithmeticEngine");
-            props.setProperty(MutableProcessingConfiguration.TEMPLATE_EXCEPTION_HANDLER_KEY,
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$DummyTemplateExceptionHandler");
-            props.setProperty(Configuration.ExtendableBuilder.CACHE_STORAGE_KEY,
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$DummyCacheStorage()");
-            props.setProperty(MutableProcessingConfiguration.NEW_BUILTIN_CLASS_RESOLVER_KEY,
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$DummyNewBuiltinClassResolver()");
-            props.setProperty(Configuration.ExtendableBuilder.SOURCE_ENCODING_KEY, "utf-8");
-            props.setProperty(Configuration.ExtendableBuilder.TEMPLATE_LOADER_KEY,
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$DummyTemplateLoader()");
-            cfgB.setSettings(props);
-            assertEquals(DefaultObjectWrapper.class, cfgB.getObjectWrapper().getClass());
-            assertEquals(
-                    Configuration.VERSION_3_0_0, ((DefaultObjectWrapper) cfgB.getObjectWrapper()).getIncompatibleImprovements());
-            assertEquals(DummyArithmeticEngine.class, cfgB.getArithmeticEngine().getClass());
-            assertEquals(DummyTemplateExceptionHandler.class, cfgB.getTemplateExceptionHandler().getClass());
-            assertEquals(DummyCacheStorage.class, cfgB.getCacheStorage().getClass());
-            assertEquals(DummyNewBuiltinClassResolver.class, cfgB.getNewBuiltinClassResolver().getClass());
-            assertEquals(DummyTemplateLoader.class, cfgB.getTemplateLoader().getClass());
-            assertEquals(StandardCharsets.UTF_8, cfgB.getSourceEncoding());
-        }
-        
-        {
-            Properties props = new Properties();
-            props.setProperty(MutableProcessingConfiguration.OBJECT_WRAPPER_KEY, "defAult");
-            props.setProperty(MutableProcessingConfiguration.ARITHMETIC_ENGINE_KEY,
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$DummyArithmeticEngine(x = 1)");
-            props.setProperty(MutableProcessingConfiguration.TEMPLATE_EXCEPTION_HANDLER_KEY,
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$DummyTemplateExceptionHandler(x = 1)");
-            props.setProperty(Configuration.ExtendableBuilder.CACHE_STORAGE_KEY,
-                    "soft: 500, strong: 100");
-            props.setProperty(MutableProcessingConfiguration.NEW_BUILTIN_CLASS_RESOLVER_KEY,
-                    "allows_nothing");
-            cfgB.setSettings(props);
-            assertEquals(DefaultObjectWrapper.class, cfgB.getObjectWrapper().getClass());
-            assertEquals(1, ((DummyArithmeticEngine) cfgB.getArithmeticEngine()).getX());
-            assertEquals(1, ((DummyTemplateExceptionHandler) cfgB.getTemplateExceptionHandler()).getX());
-            assertEquals(Configuration.VERSION_3_0_0,
-                    ((DefaultObjectWrapper) cfgB.getObjectWrapper()).getIncompatibleImprovements());
-            assertEquals(500, ((MruCacheStorage) cfgB.getCacheStorage()).getSoftSizeLimit());
-            assertEquals(TemplateClassResolver.ALLOWS_NOTHING_RESOLVER, cfgB.getNewBuiltinClassResolver());
-            assertEquals(StandardCharsets.UTF_8, cfgB.getSourceEncoding());
-        }
-
-        {
-            Properties props = new Properties();
-            props.setProperty(MutableProcessingConfiguration.OBJECT_WRAPPER_KEY, "Default");
-            props.setProperty(MutableProcessingConfiguration.ARITHMETIC_ENGINE_KEY, "bigdecimal");
-            props.setProperty(MutableProcessingConfiguration.TEMPLATE_EXCEPTION_HANDLER_KEY, "rethrow");
-            cfgB.setSettings(props);
-            assertEquals(DefaultObjectWrapper.class, cfgB.getObjectWrapper().getClass());
-            assertSame(BigDecimalArithmeticEngine.INSTANCE, cfgB.getArithmeticEngine());
-            assertSame(TemplateExceptionHandler.RETHROW_HANDLER, cfgB.getTemplateExceptionHandler());
-            assertEquals(Configuration.VERSION_3_0_0,
-                    ((DefaultObjectWrapper) cfgB.getObjectWrapper()).getIncompatibleImprovements());
-        }
-        
-        {
-            Properties props = new Properties();
-            props.setProperty(MutableProcessingConfiguration.OBJECT_WRAPPER_KEY, "DefaultObjectWrapper(3.0.0)");
-            cfgB.setSettings(props);
-            assertEquals(DefaultObjectWrapper.class, cfgB.getObjectWrapper().getClass());
-            assertEquals(
-                    Configuration.VERSION_3_0_0,
-                    ((DefaultObjectWrapper) cfgB.getObjectWrapper()).getIncompatibleImprovements());
-        }
-    }
-    
-    @Test
-    public void timeZoneTest() throws _ObjectBuilderSettingEvaluationException, ClassNotFoundException,
-    InstantiationException, IllegalAccessException {
-        for (String timeZoneId : new String[] { "GMT+01", "GMT", "UTC" }) {
-            TestBean8 result = (TestBean8) _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean8(timeZone=TimeZone('"
-                    + timeZoneId + "'))",
-                    TestBean8.class, false, new _SettingEvaluationEnvironment());
-            assertEquals(TimeZone.getTimeZone(timeZoneId), result.getTimeZone());
-        }
-        
-        try {
-            _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean8(timeZone=TimeZone('foobar'))",
-                    TestBean8.class, false, new _SettingEvaluationEnvironment());
-            fail();
-        } catch (_ObjectBuilderSettingEvaluationException e) {
-            assertThat(e.getCause().getMessage(),
-                    allOf(containsStringIgnoringCase("unrecognized"), containsString("foobar")));
-        }
-    }
-
-    @Test
-    public void charsetTest() throws _ObjectBuilderSettingEvaluationException, ClassNotFoundException,
-            InstantiationException, IllegalAccessException {
-        for (String timeZoneId : new String[] { "uTf-8", "GMT", "UTC" }) {
-            TestBean8 result = (TestBean8) _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean8(charset=Charset('iso-8859-1'))",
-                    TestBean8.class, false, new _SettingEvaluationEnvironment());
-            assertEquals(StandardCharsets.ISO_8859_1, result.getCharset());
-        }
-
-        try {
-            _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean8(charset=Charset('noSuchCS'))",
-                    TestBean8.class, false, new _SettingEvaluationEnvironment());
-            fail();
-        } catch (_ObjectBuilderSettingEvaluationException e) {
-            assertThat(e.getCause(), instanceOf(UnsupportedCharsetException.class));
-        }
-    }
-
-    @Test
-    public void configureBeanTest() throws Exception {
-        final TestBean7 bean = new TestBean7();
-        final String src = "a/b(s='foo', x=1, b=true), bar";
-        int nextPos = _ObjectBuilderSettingEvaluator.configureBean(src, src.indexOf('(') + 1, bean,
-                _SettingEvaluationEnvironment.getCurrent());
-        assertEquals("foo", bean.getS());
-        assertEquals(1, bean.getX());
-        assertTrue(bean.isB());
-        assertEquals(", bar", src.substring(nextPos));
-    }
-    
-    @Test
-    public void parsingErrors() throws Exception {
-        try {
-            _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1(1,,2)",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            fail();
-        } catch (_ObjectBuilderSettingEvaluationException e) {
-            assertThat(e.getMessage(), containsString("\",\""));
-        }
-
-        try {
-            _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1(x=1,2)",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            fail();
-        } catch (_ObjectBuilderSettingEvaluationException e) {
-            assertThat(e.getMessage(), containsStringIgnoringCase("must precede named"));
-        }
-
-
-        try {
-            _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1(x=1;2)",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            fail();
-        } catch (_ObjectBuilderSettingEvaluationException e) {
-            assertThat(e.getMessage(), containsString("\";\""));
-        }
-        
-        try {
-            _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1(1,2))",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            fail();
-        } catch (_ObjectBuilderSettingEvaluationException e) {
-            assertThat(e.getMessage(), containsString("\")\""));
-        }
-        
-        try {
-            _ObjectBuilderSettingEvaluator.eval(
-                    "foo.Bar('s${x}s'))",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            fail();
-        } catch (_ObjectBuilderSettingEvaluationException e) {
-            assertThat(e.getMessage(), containsString("${...}"));
-        }
-        
-        try {
-            _ObjectBuilderSettingEvaluator.eval(
-                    "foo.Bar('s#{x}s'))",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            fail();
-        } catch (_ObjectBuilderSettingEvaluationException e) {
-            assertThat(e.getMessage(), containsString("#{...}"));
-        }
-    }
-
-    @Test
-    public void semanticErrors() throws Exception {
-        try {
-            _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$XTestBean1(1,2)",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            fail();
-        } catch (_ObjectBuilderSettingEvaluationException e) {
-            assertThat(e.getMessage(), containsStringIgnoringCase("Failed to get class"));
-        }
-        
-        try {
-            _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1(true, 2)",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            fail();
-        } catch (_ObjectBuilderSettingEvaluationException e) {
-            assertThat(e.getMessage(), containsStringIgnoringCase("constructor"));
-        }
-        
-        try {
-            _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1(x = 1)",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            fail();
-        } catch (_ObjectBuilderSettingEvaluationException e) {
-            assertThat(e.getMessage(), containsStringIgnoringCase("no writeable JavaBeans property called \"x\""));
-        }
-        
-        try {
-            _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1(p1 = 1, p1 = 2)",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            fail();
-        } catch (_ObjectBuilderSettingEvaluationException e) {
-            assertThat(e.getMessage(), containsString("twice"));
-        }
-        
-        try {
-            _ObjectBuilderSettingEvaluator.eval(
-                    "java.util.HashMap()",
-                    ObjectWrapper.class, false, _SettingEvaluationEnvironment.getCurrent());
-            fail();
-        } catch (_ObjectBuilderSettingEvaluationException e) {
-            assertThat(e.getMessage(), containsString("is not a(n) " + ObjectWrapper.class.getName()));
-        }
-        
-        try {
-            _ObjectBuilderSettingEvaluator.eval(
-                    "null",
-                    ObjectWrapper.class, false, _SettingEvaluationEnvironment.getCurrent());
-            fail();
-        } catch (_ObjectBuilderSettingEvaluationException e) {
-            assertThat(e.getMessage(), containsString("can't be null"));
-        }
-    }
-    
-    @Test
-    public void testLiteralAsObjectBuilder() throws Exception {
-        assertNull(_ObjectBuilderSettingEvaluator.eval(
-                "null",
-                ObjectWrapper.class, true, _SettingEvaluationEnvironment.getCurrent()));
-        assertEquals("foo", _ObjectBuilderSettingEvaluator.eval(
-                "'foo'",
-                CharSequence.class, true, _SettingEvaluationEnvironment.getCurrent()));
-        assertEquals(Boolean.TRUE, _ObjectBuilderSettingEvaluator.eval(
-                "  true  ",
-                Object.class, true, _SettingEvaluationEnvironment.getCurrent()));
-        assertEquals(Double.valueOf("1.23"), _ObjectBuilderSettingEvaluator.eval(
-                "1.23 ",
-                Number.class, true, _SettingEvaluationEnvironment.getCurrent()));
-        assertEquals(new Version(1, 2, 3), _ObjectBuilderSettingEvaluator.eval(
-                " 1.2.3",
-                Object.class, true, _SettingEvaluationEnvironment.getCurrent()));
-    }
-
-    @Test
-    public void testNumberLiteralJavaTypes() throws Exception {
-        assertEquals(Double.valueOf("1.0"), _ObjectBuilderSettingEvaluator.eval(
-                "1.0",
-                Number.class, true, _SettingEvaluationEnvironment.getCurrent()));
-
-        assertEquals(new BigInteger("-9223372036854775809"), _ObjectBuilderSettingEvaluator.eval(
-                "-9223372036854775809",
-                Number.class, true, _SettingEvaluationEnvironment.getCurrent()));
-        assertEquals(new BigInteger("9223372036854775808"), _ObjectBuilderSettingEvaluator.eval(
-                "9223372036854775808",
-                Number.class, true, _SettingEvaluationEnvironment.getCurrent()));
-        
-        assertEquals(Long.valueOf(-9223372036854775808L), _ObjectBuilderSettingEvaluator.eval(
-                "-9223372036854775808",
-                Number.class, true, _SettingEvaluationEnvironment.getCurrent()));
-        assertEquals(Long.valueOf(9223372036854775807L), _ObjectBuilderSettingEvaluator.eval(
-                "9223372036854775807",
-                Number.class, true, _SettingEvaluationEnvironment.getCurrent()));
-        
-        assertEquals(Integer.valueOf(-2147483648), _ObjectBuilderSettingEvaluator.eval(
-                "-2147483648",
-                Number.class, true, _SettingEvaluationEnvironment.getCurrent()));
-        assertEquals(Integer.valueOf(2147483647), _ObjectBuilderSettingEvaluator.eval(
-                "2147483647",
-                Number.class, true, _SettingEvaluationEnvironment.getCurrent()));
-        
-        assertEquals(Integer.valueOf(-1), _ObjectBuilderSettingEvaluator.eval(
-                "-1",
-                Number.class, true, _SettingEvaluationEnvironment.getCurrent()));
-        assertEquals(Integer.valueOf(1), _ObjectBuilderSettingEvaluator.eval(
-                "1",
-                Number.class, true, _SettingEvaluationEnvironment.getCurrent()));
-    }
-    
-    @Test
-    public void testListLiterals() throws Exception {
-        {
-            ArrayList<Object> expected = new ArrayList();
-            expected.add("s");
-            expected.add(null);
-            expected.add(true);
-            expected.add(new TestBean9(1));
-            expected.add(ImmutableList.of(11, 22, 33));
-            assertEquals(expected, _ObjectBuilderSettingEvaluator.eval(
-                    "['s', null, true, org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean9(1), [11, 22, 33]]",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent()));
-            assertEquals(expected, _ObjectBuilderSettingEvaluator.eval(
-                    "  [  's'  ,  null ,  true , org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean9(1) ,"
-                    + "  [ 11 , 22 , 33 ]  ]  ",
-                    Collection.class, false, _SettingEvaluationEnvironment.getCurrent()));
-            assertEquals(expected, _ObjectBuilderSettingEvaluator.eval(
-                    "['s',null,true,org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean9(1),[11,22,33]]",
-                    List.class, false, _SettingEvaluationEnvironment.getCurrent()));
-        }
-        
-        assertEquals(Collections.emptyList(), _ObjectBuilderSettingEvaluator.eval(
-                "[]",
-                Object.class, false, _SettingEvaluationEnvironment.getCurrent()));
-        assertEquals(Collections.emptyList(), _ObjectBuilderSettingEvaluator.eval(
-                "[  ]",
-                Object.class, false, _SettingEvaluationEnvironment.getCurrent()));
-
-        assertEquals(Collections.singletonList(123), _ObjectBuilderSettingEvaluator.eval(
-                "[123]",
-                Object.class, false, _SettingEvaluationEnvironment.getCurrent()));
-        assertEquals(Collections.singletonList(123), _ObjectBuilderSettingEvaluator.eval(
-                "[ 123 ]",
-                Object.class, false, _SettingEvaluationEnvironment.getCurrent()));
-        
-        assertEquals(new TestBean9(1, ImmutableList.of("a", "b")), _ObjectBuilderSettingEvaluator.eval(
-                "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean9(1, ['a', 'b'])",
-                Object.class, false, _SettingEvaluationEnvironment.getCurrent()));
-        
-        try {
-            _ObjectBuilderSettingEvaluator.eval(
-                    "[1,]",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            fail();
-        } catch (_ObjectBuilderSettingEvaluationException e) {
-            assertThat(e.getMessage(), containsString("found character \"]\""));
-        }
-        try {
-            _ObjectBuilderSettingEvaluator.eval(
-                    "[,1]",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            fail();
-        } catch (_ObjectBuilderSettingEvaluationException e) {
-            assertThat(e.getMessage(), containsString("found character \",\""));
-        }
-        try {
-            _ObjectBuilderSettingEvaluator.eval(
-                    "1]",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            fail();
-        } catch (_ObjectBuilderSettingEvaluationException e) {
-            assertThat(e.getMessage(), containsString("found character \"]\""));
-        }
-        try {
-            _ObjectBuilderSettingEvaluator.eval(
-                    "[1",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            fail();
-        } catch (_ObjectBuilderSettingEvaluationException e) {
-            assertThat(e.getMessage(), containsString("end of"));
-        }
-    }
-
-    @Test
-    public void testMapLiterals() throws Exception {
-        {
-            HashMap<String, Object> expected = new HashMap();
-            expected.put("k1", "s");
-            expected.put("k2", null);
-            expected.put("k3", true);
-            expected.put("k4", new TestBean9(1));
-            expected.put("k5", ImmutableList.of(11, 22, 33));
-            assertEquals(expected, _ObjectBuilderSettingEvaluator.eval(
-                    "{'k1': 's', 'k2': null, 'k3': true, "
-                    + "'k4': org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean9(1), 'k5': [11, 22, 33]}",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent()));
-            assertEquals(expected, _ObjectBuilderSettingEvaluator.eval(
-                    " {  'k1'  :  's'  ,  'k2' :  null  , 'k3' : true , "
-                    + "'k4' : org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean9 ( 1 ) , 'k5' : [ 11 , 22 , 33 ] } ",
-                    Map.class, false, _SettingEvaluationEnvironment.getCurrent()));
-            assertEquals(expected, _ObjectBuilderSettingEvaluator.eval(
-                    " {'k1':'s','k2':null,'k3':true,"
-                    + "'k4':org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean9(1),'k5':[11,22,33]}",
-                    LinkedHashMap.class, false, _SettingEvaluationEnvironment.getCurrent()));
-        }
-        
-        {
-            HashMap<Object, String> expected = new HashMap();
-            expected.put(true, "T");
-            expected.put(1, "O");
-            expected.put(new TestBean9(1), "B");
-            expected.put(ImmutableList.of(11, 22, 33), "L");
-            assertEquals(expected, _ObjectBuilderSettingEvaluator.eval(
-                    "{ true: 'T', 1: 'O', org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean9(1): 'B', "
-                    + "[11, 22, 33]: 'L' }",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent()));
-        }
-        
-        assertEquals(Collections.emptyMap(), _ObjectBuilderSettingEvaluator.eval(
-                "{}",
-                Object.class, false, _SettingEvaluationEnvironment.getCurrent()));
-        assertEquals(Collections.emptyMap(), _ObjectBuilderSettingEvaluator.eval(
-                "{  }",
-                Object.class, false, _SettingEvaluationEnvironment.getCurrent()));
-
-        assertEquals(Collections.singletonMap("k1", 123), _ObjectBuilderSettingEvaluator.eval(
-                "{'k1':123}",
-                Object.class, false, _SettingEvaluationEnvironment.getCurrent()));
-        assertEquals(Collections.singletonMap("k1", 123), _ObjectBuilderSettingEvaluator.eval(
-                "{ 'k1' : 123 }",
-                Object.class, false, _SettingEvaluationEnvironment.getCurrent()));
-        
-        assertEquals(new TestBean9(1, ImmutableMap.of(11, "a", 22, "b")), _ObjectBuilderSettingEvaluator.eval(
-                "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean9(1, { 11: 'a', 22: 'b' })",
-                Object.class, false, _SettingEvaluationEnvironment.getCurrent()));
-        
-        try {
-            _ObjectBuilderSettingEvaluator.eval(
-                    "{1:2,}",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            fail();
-        } catch (_ObjectBuilderSettingEvaluationException e) {
-            assertThat(e.getMessage(), containsString("found character \"}\""));
-        }
-        try {
-            _ObjectBuilderSettingEvaluator.eval(
-                    "{,1:2}",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            fail();
-        } catch (_ObjectBuilderSettingEvaluationException e) {
-            assertThat(e.getMessage(), containsString("found character \",\""));
-        }
-        try {
-            _ObjectBuilderSettingEvaluator.eval(
-                    "1:2}",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            fail();
-        } catch (_ObjectBuilderSettingEvaluationException e) {
-            assertThat(e.getMessage(), containsString("found character \":\""));
-        }
-        try {
-            _ObjectBuilderSettingEvaluator.eval(
-                    "1}",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            fail();
-        } catch (_ObjectBuilderSettingEvaluationException e) {
-            assertThat(e.getMessage(), containsString("found character \"}\""));
-        }
-        try {
-            _ObjectBuilderSettingEvaluator.eval(
-                    "{1",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            fail();
-        } catch (_ObjectBuilderSettingEvaluationException e) {
-            assertThat(e.getMessage(), containsString("end of"));
-        }
-        try {
-            _ObjectBuilderSettingEvaluator.eval(
-                    "{1:",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            fail();
-        } catch (_ObjectBuilderSettingEvaluationException e) {
-            assertThat(e.getMessage(), containsString("end of"));
-        }
-        try {
-            _ObjectBuilderSettingEvaluator.eval(
-                    "{null:1}",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            fail();
-        } catch (_ObjectBuilderSettingEvaluationException e) {
-            assertThat(e.getMessage(), containsString("null as key"));
-        }
-    }
-
-    @Test
-    public void testMethodParameterNumberTypes() throws Exception {
-        {
-            TestBean8 result = (TestBean8) _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean8(anyObject=1)",
-                    TestBean8.class, false, new _SettingEvaluationEnvironment());
-            assertEquals(result.getAnyObject(), 1);
-        }
-        {
-            TestBean8 result = (TestBean8) _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean8(anyObject=2147483649)",
-                    TestBean8.class, false, new _SettingEvaluationEnvironment());
-            assertEquals(result.getAnyObject(), 2147483649L);
-        }
-        {
-            TestBean8 result = (TestBean8) _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean8(anyObject=1.0)",
-                    TestBean8.class, false, new _SettingEvaluationEnvironment());
-            // Like in FTL, non-integer numbers are BigDecimal-s, that are later coerced to the actual parameter type.
-            // However, here the type is Object, so it remains BigDecimal.
-            assertEquals(new BigDecimal("1.0"), result.getAnyObject());
-        }
-    }
-    
-    @Test
-    public void testNonMethodParameterNumberTypes() throws Exception {
-        assertEqualsEvaled(Integer.valueOf(1), "1");
-        assertEqualsEvaled(Double.valueOf(1), "1.0");
-        assertEqualsEvaled(Long.valueOf(2147483649l), "2147483649");
-
-        assertEqualsEvaled(Double.valueOf(1), "1d");
-        assertEqualsEvaled(Double.valueOf(1), "1D");
-        assertEqualsEvaled(Float.valueOf(1), "1f");
-        assertEqualsEvaled(Float.valueOf(1), "1F");
-        assertEqualsEvaled(Long.valueOf(1), "1l");
-        assertEqualsEvaled(Long.valueOf(1), "1L");
-        assertEqualsEvaled(BigDecimal.valueOf(1), "1bd");
-        assertEqualsEvaled(BigDecimal.valueOf(1), "1Bd");
-        assertEqualsEvaled(BigDecimal.valueOf(1), "1BD");
-        assertEqualsEvaled(BigInteger.valueOf(1), "1bi");
-        assertEqualsEvaled(BigInteger.valueOf(1), "1bI");
-        
-        assertEqualsEvaled(Float.valueOf(1.5f), "1.5f");
-        assertEqualsEvaled(Double.valueOf(1.5), "1.5d");
-        assertEqualsEvaled(BigDecimal.valueOf(1.5), "1.5bd");
-        
-        assertEqualsEvaled(
-                ImmutableList.of(-1, -0.5, new BigDecimal("-0.1")),
-                "[ -1, -0.5, -0.1bd ]");
-        assertEqualsEvaled(
-                ImmutableMap.of(-1, -11, -0.5, -0.55, new BigDecimal("-0.1"), new BigDecimal("-0.11")),
-                "{ -1: -11, -0.5: -0.55, -0.1bd: -0.11bd }");
-    }
-    
-    @Test
-    public void testStaticFields() throws Exception {
-        {
-            TestBean1 res = (TestBean1) _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1("
-                    + "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestStaticFields.CONST, true)",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            assertEquals(TestStaticFields.CONST, (int) res.i);
-        }
-        {
-            TestBean1 res = (TestBean1) _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1("
-                    + "p2 = org.apache.freemarker.core.ObjectBuilderSettingsTest$TestStaticFields.CONST)",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            assertEquals(TestStaticFields.CONST, res.getP2());
-        }
-        assertEqualsEvaled(123, "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestStaticFields.CONST");
-        
-        // With shorthand class name:
-        assertEqualsEvaled(ParsingConfiguration.AUTO_DETECT_TAG_SYNTAX, "Configuration.AUTO_DETECT_TAG_SYNTAX");
-        
-        try {
-            _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1("
-                    + "p2 = org.apache.freemarker.core.ObjectBuilderSettingsTest$TestStaticFields.CONST())",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            fail();
-        } catch (_ObjectBuilderSettingEvaluationException e) {
-            assertThat(e.getMessage(),
-                    containsString("org.apache.freemarker.core.ObjectBuilderSettingsTest$TestStaticFields.CONST"));
-        }
-        try {
-            assertEqualsEvaled(123, "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestStaticFields.CONST()");
-            fail();
-        } catch (_ObjectBuilderSettingEvaluationException e) {
-            assertThat(e.getMessage(),
-                    containsString("org.apache.freemarker.core.ObjectBuilderSettingsTest$TestStaticFields.CONST"));
-        }
-        try {
-            assertEqualsEvaled(123, "java.lang.String(org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean5.INSTANCE)");
-            fail();
-        } catch (_ObjectBuilderSettingEvaluationException e) {
-            assertThat(e.getMessage(),
-                    containsString("org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean5()"));
-        }
-    }
-    
-    private void assertEqualsEvaled(Object expectedValue, String s)
-            throws _ObjectBuilderSettingEvaluationException, ClassNotFoundException, InstantiationException,
-            IllegalAccessException {
-        Object actualValue = _ObjectBuilderSettingEvaluator.eval(
-                s, Object.class, true, _SettingEvaluationEnvironment.getCurrent());
-        assertEquals(expectedValue, actualValue);
-    }
-    
-    @Test
-    public void visibilityTest() throws Exception {
-        try {
-            _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.userpkg.PackageVisibleAll()",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            fail();
-        } catch (_ObjectBuilderSettingEvaluationException e) {
-            assertEquals(IllegalAccessException.class, e.getCause().getClass());
-        }
-
-        try {
-            _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.userpkg.PackageVisibleWithPublicConstructor()",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            fail();
-        } catch (_ObjectBuilderSettingEvaluationException e) {
-            assertEquals(IllegalAccessException.class, e.getCause().getClass());
-        }
-
-        try {
-            _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.userpkg.PublicWithPackageVisibleConstructor()",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            fail();
-        } catch (_ObjectBuilderSettingEvaluationException e) {
-            assertEquals(IllegalAccessException.class, e.getCause().getClass());
-        }
-        
-        {
-            Object o = _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.userpkg.PublicAll()",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            assertEquals(org.apache.freemarker.core.userpkg.PublicAll.class, o.getClass());
-        }
-        
-        {
-            Object o = _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.userpkg.PublicWithMixedConstructors(1)",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            assertEquals("Integer", ((PublicWithMixedConstructors) o).getS());
-        }
-        
-        
-        {
-            Object o = _ObjectBuilderSettingEvaluator.eval(
-                    "org.apache.freemarker.core.userpkg.PackageVisibleAllWithBuilder()",
-                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
-            assertEquals("org.apache.freemarker.core.userpkg.PackageVisibleAllWithBuilder", o.getClass().getName());
-        }
-    }
-
-    public static class TestBean1 {
-        float f;
-        Integer i;
-        long l;
-        boolean b;
-        
-        double p1;
-        int p2;
-        boolean p3;
-        String p4;
-        
-        public TestBean1(float f, Integer i, long l, boolean b) {
-            this.f = f;
-            this.i = i;
-            this.l = l;
-            this.b = b;
-        }
-        
-        public TestBean1(Integer i, boolean b) {
-            f = 2;
-            this.i = i;
-            l = 2;
-            this.b = b;
-        }
-    
-        public TestBean1(Integer i, long l) {
-            f = 3;
-            this.i = i;
-            this.l = l;
-            b = false;
-        }
-        
-        public TestBean1() {
-            f = 4;
-        }
-    
-        public double getP1() {
-            return p1;
-        }
-    
-        public void setP1(double p1) {
-            this.p1 = p1;
-        }
-    
-        public int getP2() {
-            return p2;
-        }
-    
-        public void setP2(int p2) {
-            this.p2 = p2;
-        }
-    
-        public boolean isP3() {
-            return p3;
-        }
-    
-        public void setP3(boolean p3) {
-            this.p3 = p3;
-        }
-
-        public String getP4() {
-            return p4;
-        }
-
-        public void setP4(String p4) {
-            this.p4 = p4;
-        }
-        
-    }
-    
-    public static class TestBean2 {
-        final boolean built;
-        final int x;
-
-        public TestBean2() {
-            built = false;
-            x = 0;
-        }
-        
-        public TestBean2(int x) {
-            built = false;
-            this.x = x;
-        }
-
-        public TestBean2(TestBean2Builder builder) {
-            built = true;
-            x = builder.x;
-        }
-        
-    }
-
-    public static class TestBean2Builder {
-        int x;
-        
-        public TestBean2Builder() { }
-
-        public TestBean2Builder(int x) {
-            this.x = x;
-        }
-        
-        public int getX() {
-            return x;
-        }
-
-        public void setX(int x) {
-            this.x = x;
-        }
-        
-        public TestBean2 build() {
-            return new TestBean2(this);
-        }
-        
-    }
-
-    public static class TestBean3 {
-        
-        private int x;
-
-        public int getX() {
-            return x;
-        }
-
-        public void setX(int x) {
-            this.x = x;
-        }
-        
-    }
-    
-    public static class TestBean4 {
-        private final String s1, s2;
-        private String s3, s4;
-        
-        public TestBean4(String s1, String s2) {
-            this.s1 = s1;
-            this.s2 = s2;
-        }
-        
-        public String getS1() {
-            return s1;
-        }
-
-        public String getS2() {
-            return s2;
-        }
-
-        public String getS3() {
-            return s3;
-        }
-        
-        public void setS3(String s3) {
-            this.s3 = s3;
-        }
-        
-        public String getS4() {
-            return s4;
-        }
-        
-        public void setS4(String s4) {
-            this.s4 = s4;
-        }
-        
-    }
-    
-    public static class TestBean5 {
-        
-        public final static TestBean5 INSTANCE = new TestBean5();
-        
-        private final int i;
-        private int x;
-        
-        public TestBean5() {
-            i = 0;
-        }
-
-        public TestBean5(int i) {
-            this.i = i;
-        }
-
-        public int getI() {
-            return i;
-        }
-
-        public int getX() {
-            return x;
-        }
-
-        public void setX(int x) {
-            this.x = x;
-        }
-        
-    }
-
-    public static class TestBean6 {
-        private final TestBean1 b1;
-        private int x;
-        private final TestBean2 b2;
-        private int y;
-        private TestBean2 b3;
-        private TestBean6 b4;
-        
-        public TestBean6(TestBean1 b1, int x, TestBean2 b2) {
-            this.b1 = b1;
-            this.x = x;
-            this.b2 = b2;
-        }
-
-        public int getX() {
-            return x;
-        }
-
-        public void setX(int x) {
-            this.x = x;
-        }
-
-        public int getY() {
-            return y;
-        }
-
-        public void setY(int y) {
-            this.y = y;
-        }
-
-        public TestBean2 getB3() {
-            return b3;
-        }
-
-        public void setB3(TestBean2 b3) {
-            this.b3 = b3;
-        }
-
-        public TestBean1 getB1() {
-            return b1;
-        }
-
-        public TestBean2 getB2() {
-            return b2;
-        }
-
-        public TestBean6 getB4() {
-            return b4;
-        }
-
-        public void setB4(TestBean6 b4) {
-            this.b4 = b4;
-        }
-        
-    }
-    
-    public class TestBean7 {
-
-        private String s;
-        private int x;
-        private boolean b;
-
-        public String getS() {
-            return s;
-        }
-
-        public void setS(String s) {
-            this.s = s;
-        }
-
-        public int getX() {
-            return x;
-        }
-
-        public void setX(int x) {
-            this.x = x;
-        }
-
-        public boolean isB() {
-            return b;
-        }
-
-        public void setB(boolean b) {
-            this.b = b;
-        }
-
-        @Override
-        public String toString() {
-            return "TestBean [s=" + s + ", x=" + x + ", b=" + b + "]";
-        }
-
-    }
-    
-    public static class TestBean8 {
-        private TimeZone timeZone;
-        private Charset charset;
-        private Object anyObject;
-        private List<?> list;
-        
-        public TimeZone getTimeZone() {
-            return timeZone;
-        }
-        
-        public void setTimeZone(TimeZone timeZone) {
-            this.timeZone = timeZone;
-        }
-
-        public Charset getCharset() {
-            return charset;
-        }
-
-        public void setCharset(Charset charset) {
-            this.charset = charset;
-        }
-
-        public Object getAnyObject() {
-            return anyObject;
-        }
-        
-        public void setAnyObject(Object anyObject) {
-            this.anyObject = anyObject;
-        }
-
-        public List<?> getList() {
-            return list;
-        }
-        
-        public void setList(List<?> list) {
-            this.list = list;
-        }
-        
-    }
-    
-    public static class TestBean9 {
-        
-        private final int n;
-        private final List<?> list;
-        private final Map<?, ?> map;
-
-        public TestBean9(int n) {
-            this(n, null, null);
-        }
-
-        public TestBean9(int n, List<?> list) {
-            this(n, list, null);
-        }
-
-        public TestBean9(int n, Map<?, ?> map) {
-            this(n, null, map);
-        }
-        
-        public TestBean9(int n, List<?> list, Map<?, ?> map) {
-            this.n = n;
-            this.list = list;
-            this.map = map;
-        }
-
-        @Override
-        public int hashCode() {
-            final int prime = 31;
-            int result = 1;
-            result = prime * result + ((list == null) ? 0 : list.hashCode());
-            result = prime * result + ((map == null) ? 0 : map.hashCode());
-            result = prime * result + n;
-            return result;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (this == obj) return true;
-            if (obj == null) return false;
-            if (getClass() != obj.getClass()) return false;
-            TestBean9 other = (TestBean9) obj;
-            if (list == null) {
-                if (other.list != null) return false;
-            } else if (!list.equals(other.list)) return false;
-            if (map == null) {
-                if (other.map != null) return false;
-            } else if (!map.equals(other.map)) return false;
-            return n == other.n;
-        }
-        
-    }
-    
-    public static class TestStaticFields {
-        public static final int CONST = 123;
-    }
-    
-    public static class DummyArithmeticEngine extends ArithmeticEngine {
-        
-        private int x;
-
-        @Override
-        public int compareNumbers(Number first, Number second) throws TemplateException {
-            return 0;
-        }
-
-        @Override
-        public Number add(Number first, Number second) throws TemplateException {
-            return null;
-        }
-
-        @Override
-        public Number subtract(Number first, Number second) throws TemplateException {
-            return null;
-        }
-
-        @Override
-        public Number multiply(Number first, Number second) throws TemplateException {
-            return null;
-        }
-
-        @Override
-        public Number divide(Number first, Number second) throws TemplateException {
-            return null;
-        }
-
-        @Override
-        public Number modulus(Number first, Number second) throws TemplateException {
-            return null;
-        }
-
-        @Override
-        public Number toNumber(String s) {
-            return null;
-        }
-
-        public int getX() {
-            return x;
-        }
-
-        public void setX(int x) {
-            this.x = x;
-        }
-        
-    }
-    
-    public static class DummyTemplateExceptionHandler implements TemplateExceptionHandler {
-        
-        private int x;
-
-        @Override
-        public void handleTemplateException(TemplateException te, Environment env, Writer out) throws TemplateException {
-        }
-
-        public int getX() {
-            return x;
-        }
-
-        public void setX(int x) {
-            this.x = x;
-        }
-        
-    }
-    
-    public static class DummyCacheStorage implements CacheStorage {
-        
-        @Override
-        public Object get(Object key) {
-            return null;
-        }
-
-        @Override
-        public void put(Object key, Object value) {
-        }
-
-        @Override
-        public void remove(Object key) {
-        }
-
-        @Override
-        public void clear() {
-        }
-        
-    }
-    
-    public static class DummyNewBuiltinClassResolver implements TemplateClassResolver {
-
-        @Override
-        public Class resolve(String className, Environment env, Template template) throws TemplateException {
-            return null;
-        }
-        
-    }
-    
-    public static class DummyTemplateLoader implements TemplateLoader {
-
-        @Override
-        public TemplateLoaderSession createSession() {
-            return null;
-        }
-
-        @Override
-        public TemplateLoadingResult load(String name, TemplateLoadingSource ifSourceDiffersFrom,
-                Serializable ifVersionDiffersFrom, TemplateLoaderSession session) throws IOException {
-            return TemplateLoadingResult.NOT_FOUND;
-        }
-
-        @Override
-        public void resetState() {
-            // Do nothing
-        }
-        
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/OptInTemplateClassResolverTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/OptInTemplateClassResolverTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/OptInTemplateClassResolverTest.java
deleted file mode 100644
index 06e863c..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/OptInTemplateClassResolverTest.java
+++ /dev/null
@@ -1,230 +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;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import org.apache.freemarker.core.util.OptInTemplateClassResolver;
-import org.apache.freemarker.test.TestConfigurationBuilder;
-
-import junit.framework.AssertionFailedError;
-import junit.framework.TestCase;
-
-public class OptInTemplateClassResolverTest extends TestCase {
-
-    public OptInTemplateClassResolverTest(String name) {
-        super(name);
-    }
-    
-    private static final Set ALLOWED_CLASSES = new HashSet();
-    static {
-        ALLOWED_CLASSES.add("java.lang.String");
-        ALLOWED_CLASSES.add("java.lang.Integer");
-    }
-    
-    private static final List TRUSTED_TEMPLATES = new ArrayList();
-    static {
-        TRUSTED_TEMPLATES.add("lib/*");
-        TRUSTED_TEMPLATES.add("/include/*");
-        TRUSTED_TEMPLATES.add("trusted.ftl");
-    }
-    
-    private OptInTemplateClassResolver resolver = new OptInTemplateClassResolver(
-            ALLOWED_CLASSES, TRUSTED_TEMPLATES);
-    
-
-    public void testOptIn() throws TemplateException {
-        Template dummyTemp = Template.createPlainTextTemplate("foo.ftl", "",
-                new TestConfigurationBuilder().build());
-
-        assertEquals(String.class, resolver.resolve("java.lang.String", null, dummyTemp));
-        assertEquals(Integer.class, resolver.resolve("java.lang.Integer", null, dummyTemp));
-        try {
-            resolver.resolve("java.lang.Long", null, dummyTemp);
-            fail();
-        } catch (TemplateException e) {
-            // Expected
-        }
-    }
-
-    public void testTrusted() throws TemplateException {
-        Configuration cfg = new TestConfigurationBuilder().build();
-
-        assertEquals(Long.class, resolver.resolve("java.lang.Long", null,
-                Template.createPlainTextTemplate("lib/foo.ftl", "", cfg)));
-        assertEquals(String.class, resolver.resolve("java.lang.String", null,
-                Template.createPlainTextTemplate("lib/foo.ftl", "", cfg)));
-        assertEquals(Long.class, resolver.resolve("java.lang.Long", null,
-                Template.createPlainTextTemplate("/lib/foo.ftl", "", cfg)));
-        assertEquals(Long.class, resolver.resolve("java.lang.Long", null,
-                Template.createPlainTextTemplate("include/foo.ftl", "", cfg)));
-        assertEquals(Long.class, resolver.resolve("java.lang.Long", null,
-                Template.createPlainTextTemplate("trusted.ftl", "", cfg)));
-        assertEquals(Long.class, resolver.resolve("java.lang.Long", null,
-                Template.createPlainTextTemplate("/trusted.ftl", "", cfg)));
-    }
-
-    public void testCraftedTrusted() throws TemplateException {
-        testTrusted_checkFails("lib/../foo.ftl");
-        testTrusted_checkFails("lib\\..\\foo.ftl");
-        testTrusted_checkFails("lib\\../foo.ftl");
-        testTrusted_checkFails("lib/..\\foo.ftl");
-        testTrusted_checkFails("lib/..");
-        testTrusted_checkFails("lib%2f%2E%2e%5cfoo.ftl");
-        testTrusted_checkFails("/lib%5C%.%2e%2Efoo.ftl");
-        
-        try {
-            testTrusted_checkFails("lib/./foo.ftl");
-            fail();
-        } catch (AssertionFailedError e) {
-            // Expected
-        }
-        try {
-            testTrusted_checkFails("lib/foo..ftl");
-            fail();
-        } catch (AssertionFailedError e) {
-            // Expected
-        }
-        try {
-            testTrusted_checkFails("lib/%2e/foo.ftl");
-            fail();
-        } catch (AssertionFailedError e) {
-            // Expected
-        }
-    }
-    
-    public void testTrusted_checkFails(String templateName) {
-        try {
-            resolver.resolve("java.lang.Long", null,
-                    Template.createPlainTextTemplate(templateName, "",
-                            new TestConfigurationBuilder().build()));
-            fail();
-        } catch (TemplateException e) {
-            // Expected
-        }
-    }
-    
-    public void testSettingParser() throws Exception {
-        {
-            Configuration cfg = new TestConfigurationBuilder()
-                    .setting(
-                            "new_builtin_class_resolver",
-                            "trusted_templates: foo.ftl, \"lib/*\"")
-                    .build();
-
-            TemplateClassResolver res = cfg.getNewBuiltinClassResolver();
-            assertEquals(String.class, res.resolve("java.lang.String", null,
-                    Template.createPlainTextTemplate("foo.ftl", "", cfg)));
-            assertEquals(String.class, res.resolve("java.lang.String", null,
-                    Template.createPlainTextTemplate("lib/bar.ftl", "", cfg)));
-            try {
-                res.resolve("java.lang.String", null,
-                        Template.createPlainTextTemplate("bar.ftl", "", cfg));
-                fail();
-            } catch (TemplateException e) {
-                // Expected
-            }
-        }
-
-        {
-            Configuration cfg = new TestConfigurationBuilder()
-                    .setting(
-                            "new_builtin_class_resolver",
-                            "allowed_classes: java.lang.String, java.lang.Integer")
-                    .build();
-
-            TemplateClassResolver res = cfg.getNewBuiltinClassResolver();
-            assertEquals(String.class, res.resolve("java.lang.String", null,
-                    Template.createPlainTextTemplate("foo.ftl", "", cfg)));
-            assertEquals(Integer.class, res.resolve("java.lang.Integer", null,
-                    Template.createPlainTextTemplate("foo.ftl", "", cfg)));
-            try {
-                res.resolve("java.lang.Long", null,
-                        Template.createPlainTextTemplate("foo.ftl", "", cfg));
-                fail();
-            } catch (TemplateException e) {
-                // good
-            }
-        }
-
-        {
-            Configuration cfg = new TestConfigurationBuilder()
-                    .setting(
-                            "new_builtin_class_resolver",
-                            "trusted_templates: foo.ftl, 'lib/*', allowed_classes: 'java.lang.String',"
-                            + " java.lang.Integer")
-                    .build();
-            TemplateClassResolver res = cfg.getNewBuiltinClassResolver();
-            assertEquals(String.class, res.resolve("java.lang.String", null,
-                    Template.createPlainTextTemplate("x.ftl", "", cfg)));
-            assertEquals(Integer.class, res.resolve("java.lang.Integer", null,
-                    Template.createPlainTextTemplate("x.ftl", "", cfg)));
-            try {
-                res.resolve("java.lang.Long", null,
-                        Template.createPlainTextTemplate("x.ftl", "", cfg));
-                fail();
-            } catch (TemplateException e) {
-                // Expected
-            }
-            assertEquals(Long.class, res.resolve("java.lang.Long", null,
-                    Template.createPlainTextTemplate("foo.ftl", "", cfg)));
-            assertEquals(Long.class, res.resolve("java.lang.Long", null,
-                    Template.createPlainTextTemplate("lib/bar.ftl", "", cfg)));
-            try {
-                res.resolve("java.lang.Long", null,
-                        Template.createPlainTextTemplate("x.ftl", "", cfg));
-                fail();
-            } catch (TemplateException e) {
-                // Expected
-            }
-        }
-        
-        try {
-            new TestConfigurationBuilder().setSetting("new_builtin_class_resolver", "wrong: foo");
-            fail();
-        } catch (ConfigurationException e) {
-            // Expected
-        }
-
-        {
-            Configuration cfg = new TestConfigurationBuilder()
-                    .setting(
-                            "new_builtin_class_resolver",
-                            "\"allowed_classes\"  :  java.lang.String  ,  'trusted_templates' :\"lib:*\"")
-                    .build();
-            TemplateClassResolver res = cfg.getNewBuiltinClassResolver();
-            assertEquals(String.class, res.resolve("java.lang.String", null,
-                    Template.createPlainTextTemplate("x.ftl", "", cfg)));
-            try {
-                res.resolve("java.lang.Long", null,
-                        Template.createPlainTextTemplate("x.ftl", "", cfg));
-                fail();
-            } catch (TemplateException e) {
-                // Expected
-            }
-            assertEquals(Long.class, res.resolve("java.lang.Long", null,
-                    Template.createPlainTextTemplate("lib:bar.ftl", "", cfg)));
-        }
-    }
-    
-}


[43/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/SettingDirectiveTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/SettingDirectiveTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/SettingDirectiveTest.java
new file mode 100644
index 0000000..3b59e78
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/SettingDirectiveTest.java
@@ -0,0 +1,40 @@
+/*
+ * 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 org.junit.Test;
+
+public class SettingDirectiveTest {
+
+    @Test
+    public void testGetSettingNamesSorted() throws Exception {
+        String prevName = null;
+        for (String name : ASTDirSetting.SETTING_NAMES) {
+            if (prevName != null) {
+                assertThat(name, greaterThan(prevName));
+            }
+            prevName = name;
+        }
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/SpecialVariableTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/SpecialVariableTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/SpecialVariableTest.java
new file mode 100644
index 0000000..7e17fc7
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/SpecialVariableTest.java
@@ -0,0 +1,114 @@
+/*
+ * 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 org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat;
+import org.apache.freemarker.core.outputformat.impl.PlainTextOutputFormat;
+import org.apache.freemarker.core.outputformat.impl.UndefinedOutputFormat;
+import org.apache.freemarker.test.TemplateTest;
+import org.junit.Test;
+
+public class SpecialVariableTest extends TemplateTest {
+
+    @Test
+    public void testNamesSorted() throws Exception {
+        String prevName = null;
+        for (String name : ASTExpBuiltInVariable.SPEC_VAR_NAMES) {
+            if (prevName != null) {
+                assertThat(name, greaterThan(prevName));
+            }
+            prevName = name;
+        }
+    }
+    
+    @Test
+    public void testVersion() throws Exception {
+        String versionStr = Configuration.getVersion().toString();
+        assertOutput("${.version}", versionStr);
+    }
+
+    @Test
+    public void testIncompationImprovements() throws Exception {
+        setConfiguration(new Configuration.Builder(Configuration.VERSION_3_0_0).build());
+        assertOutput(
+                "${.incompatibleImprovements}",
+                getConfiguration().getIncompatibleImprovements().toString());
+        
+        setConfiguration(new Configuration.Builder(Configuration.getVersion()).build());
+        assertOutput(
+                "${.incompatible_improvements}",
+                getConfiguration().getIncompatibleImprovements().toString());
+    }
+
+    @Test
+    public void testAutoEsc() throws Exception {
+        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
+
+        for (int autoEscaping : new int[] {
+                ParsingConfiguration.ENABLE_IF_DEFAULT_AUTO_ESCAPING_POLICY, ParsingConfiguration.ENABLE_IF_SUPPORTED_AUTO_ESCAPING_POLICY }) {
+            cfgB.setAutoEscapingPolicy(autoEscaping);
+            cfgB.setOutputFormat(HTMLOutputFormat.INSTANCE);
+            setConfiguration(cfgB.build());
+            assertOutput("${.autoEsc?c}", "true");
+            assertOutput("<#ftl autoEsc=false>${.autoEsc?c}", "false");
+
+            cfgB.setOutputFormat(PlainTextOutputFormat.INSTANCE);
+            setConfiguration(cfgB.build());
+            assertOutput("${.autoEsc?c}", "false");
+
+            cfgB.setOutputFormat(UndefinedOutputFormat.INSTANCE);
+            setConfiguration(cfgB.build());
+            assertOutput("${.autoEsc?c}", "false");
+        }
+        
+        cfgB.setAutoEscapingPolicy(ParsingConfiguration.DISABLE_AUTO_ESCAPING_POLICY);
+        cfgB.setOutputFormat(HTMLOutputFormat.INSTANCE);
+        setConfiguration(cfgB.build());
+        assertOutput("${.autoEsc?c}", "false");
+        assertOutput("<#ftl autoEsc=true>${.autoEsc?c}", "true");
+
+        cfgB.setOutputFormat(PlainTextOutputFormat.INSTANCE);
+        setConfiguration(cfgB.build());
+        assertOutput("${.autoEsc?c}", "false");
+
+        cfgB.setOutputFormat(UndefinedOutputFormat.INSTANCE);
+        setConfiguration(cfgB.build());
+        assertOutput("${.autoEsc?c}", "false");
+
+        cfgB.setAutoEscapingPolicy(ParsingConfiguration.ENABLE_IF_DEFAULT_AUTO_ESCAPING_POLICY);
+        setConfiguration(cfgB.build());
+        assertOutput(
+                "${.autoEsc?c} "
+                + "<#outputFormat 'HTML'>${.autoEsc?c}</#outputFormat> "
+                + "<#outputFormat 'undefined'>${.autoEsc?c}</#outputFormat> "
+                + "<#outputFormat 'HTML'>"
+                + "${.autoEsc?c} <#noAutoEsc>${.autoEsc?c} "
+                + "<#autoEsc>${.autoEsc?c}</#autoEsc> ${.autoEsc?c}</#noAutoEsc> ${.autoEsc?c}"
+                + "</#outputFormat>",
+                "false true false "
+                + "true false true false true");
+        
+        assertErrorContains("${.autoEscaping}", "You may meant: \"autoEsc\"");
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/StringLiteralInterpolationTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/StringLiteralInterpolationTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/StringLiteralInterpolationTest.java
new file mode 100644
index 0000000..ae72dac
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/StringLiteralInterpolationTest.java
@@ -0,0 +1,135 @@
+/*
+ * 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.util.Collections;
+
+import org.apache.freemarker.core.outputformat.impl.RTFOutputFormat;
+import org.apache.freemarker.core.userpkg.PrintfGTemplateNumberFormatFactory;
+import org.apache.freemarker.core.valueformat.TemplateNumberFormatFactory;
+import org.apache.freemarker.test.TemplateTest;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+import org.junit.Test;
+
+@SuppressWarnings("boxing")
+public class StringLiteralInterpolationTest extends TemplateTest {
+
+    @Test
+    public void basics() throws IOException, TemplateException {
+        addToDataModel("x", 1);
+        assertOutput("${'${x}'}", "1");
+        assertOutput("${'#{x}'}", "1");
+        assertOutput("${'a${x}b${x*2}c'}", "a1b2c");
+        assertOutput("${'a#{x}b#{x*2}c'}", "a1b2c");
+        assertOutput("${'a#{x; m2}'}", "a1.00");
+        assertOutput("${'${x} ${x}'}", "1 1");
+        assertOutput("${'$\\{x}'}", "${x}");
+        assertOutput("${'$\\{x} $\\{x}'}", "${x} ${x}");
+        assertOutput("${'<#-- not a comment -->${x}'}", "<#-- not a comment -->1");
+        assertOutput("${'<#-- not a comment -->$\\{x}'}", "<#-- not a comment -->${x}");
+        assertOutput("${'<#assign x = 2> ${x} <#assign x = 2>'}", "<#assign x = 2> 1 <#assign x = 2>");
+        assertOutput("${'<#assign x = 2> $\\{x} <#assign x = 2>'}", "<#assign x = 2> ${x} <#assign x = 2>");
+        assertOutput("${'<@x/>${x}<@x/>'}", "<@x/>1<@x/>");
+        assertOutput("${'<@x/>$\\{x}<@x/>'}", "<@x/>${x}<@x/>");
+        assertOutput("${'<@ ${x}<@'}", "<@ 1<@");
+        assertOutput("${'<@ $\\{x}<@'}", "<@ ${x}<@");
+        assertOutput("${'</...@x>${x}'}", "</...@x>1");
+        assertOutput("${'</...@x>$\\{x}'}", "</...@x>${x}");
+        assertOutput("${'</@ ${x}</@'}", "</@ 1</@");
+        assertOutput("${'</@ $\\{x}</@'}", "</@ ${x}</@");
+        assertOutput("${'[@ ${x}'}", "[@ 1");
+        assertOutput("${'[@ $\\{x}'}", "[@ ${x}");
+    }
+
+    /**
+     * Broken behavior for backward compatibility.
+     */
+    @Test
+    public void legacyEscapingBugStillPresent() throws IOException, TemplateException {
+        addToDataModel("x", 1);
+        assertOutput("${'$\\{x} ${x}'}", "1 1");
+        assertOutput("${'${x} $\\{x}'}", "1 1");
+    }
+    
+    @Test
+    public void legacyLengthGlitch() throws IOException, TemplateException {
+        assertOutput("${'${'}", "${");
+        assertOutput("${'${1'}", "${1");
+        assertOutput("${'${}'}", "${}");
+        assertOutput("${'${1}'}", "1");
+        assertErrorContains("${'${  '}", "");
+    }
+    
+    @Test
+    public void testErrors() {
+        addToDataModel("x", 1);
+        assertErrorContains("${'${noSuchVar}'}", InvalidReferenceException.class, "missing", "noSuchVar");
+        assertErrorContains("${'${x/0}'}", ArithmeticException.class, "zero");
+    }
+
+    @Test
+    public void escaping() throws IOException, TemplateException {
+        assertOutput("<#escape x as x?html><#assign x = '&'>${x} ${'${x}'}</#escape> ${x}", "&amp; &amp; &");
+    }
+    
+    // We couldn't test this on 3.0.0, as nothing was fixed there with IcI yet
+    /*-
+    @Test
+    public void iciInheritanceBugFixed() throws Exception {
+        // Broken behavior emulated:
+        getConfiguration().setIncompatibleImprovements(Configuration.VERSION_2_3_23);
+        assertOutput("${'&\\''?html} ${\"${'&\\\\\\''?html}\"}", "&amp;&#39; &amp;'");
+        
+        // Fix enabled:
+        getConfiguration().setIncompatibleImprovements(Configuration.VERSION_2_3_24);
+        assertOutput("${'&\\''?html} ${\"${'&\\\\\\''?html}\"}", "&amp;&#39; &amp;&#39;");
+    }
+    */
+    
+    @Test
+    public void markup() throws IOException, TemplateException {
+        setConfiguration(new TestConfigurationBuilder()
+                .customNumberFormats(Collections.<String, TemplateNumberFormatFactory>singletonMap(
+                        "G", PrintfGTemplateNumberFormatFactory.INSTANCE))
+                .numberFormat("@G 3")
+                .build());
+
+        assertOutput("${\"${1000}\"}", "1.00*10<sup>3</sup>");
+        assertOutput("${\"&_${1000}\"}", "&amp;_1.00*10<sup>3</sup>");
+        assertOutput("${\"${1000}_&\"}", "1.00*10<sup>3</sup>_&amp;");
+        assertOutput("${\"${1000}, ${2000}\"}", "1.00*10<sup>3</sup>, 2.00*10<sup>3</sup>");
+        assertOutput("${\"& ${'x'}, ${2000}\"}", "&amp; x, 2.00*10<sup>3</sup>");
+        assertOutput("${\"& ${'x'}, #{2000}\"}", "& x, 2000");
+        
+        assertOutput("${\"${2000}\"?isMarkupOutput?c}", "true");
+        assertOutput("${\"x ${2000}\"?isMarkupOutput?c}", "true");
+        assertOutput("${\"${2000} x\"?isMarkupOutput?c}", "true");
+        assertOutput("${\"#{2000}\"?isMarkupOutput?c}", "false");
+        assertOutput("${\"${'x'}\"?isMarkupOutput?c}", "false");
+        assertOutput("${\"x ${'x'}\"?isMarkupOutput?c}", "false");
+        assertOutput("${\"${'x'} x\"?isMarkupOutput?c}", "false");
+        
+        addToDataModel("rtf", RTFOutputFormat.INSTANCE.fromMarkup("\\p"));
+        assertOutput("${\"${rtf}\"?isMarkupOutput?c}", "true");
+        assertErrorContains("${\"${1000}${rtf}\"}", TemplateException.class, "HTML", "RTF", "onversion");
+        assertErrorContains("x${\"${1000}${rtf}\"}", TemplateException.class, "HTML", "RTF", "onversion");
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/TabSizeTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/TabSizeTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TabSizeTest.java
new file mode 100644
index 0000000..7945b5e
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TabSizeTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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 org.apache.freemarker.test.TemplateTest;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+import org.junit.Test;
+
+public class TabSizeTest extends TemplateTest {
+
+    @Override
+    protected Configuration createDefaultConfiguration() throws Exception {
+        return super.createDefaultConfiguration();
+    }
+
+    @Test
+    public void testBasics() throws Exception {
+        assertErrorColumnNumber(3, "${*}");
+        assertErrorColumnNumber(8 + 3, "\t${*}");
+        assertErrorColumnNumber(16 + 3, "\t\t${*}");
+        assertErrorColumnNumber(16 + 3, "  \t  \t${*}");
+
+        setConfiguration(new TestConfigurationBuilder().tabSize(1).build());
+        assertErrorColumnNumber(3, "${*}");
+        assertErrorColumnNumber(1 + 3, "\t${*}");
+        assertErrorColumnNumber(2 + 3, "\t\t${*}");
+        assertErrorColumnNumber(6 + 3, "  \t  \t${*}");
+    }
+    
+    @Test
+    public void testEvalBI() throws Exception {
+        assertErrorContains("${r'\t~'?eval}", "column 9");
+        setConfiguration(new TestConfigurationBuilder().tabSize(4).build());
+        assertErrorContains("${r'\t~'?eval}", "column 5");
+    }
+
+    @Test
+    public void testInterpretBI() throws Exception {
+        assertErrorContains("<@'\\t$\\{*}'?interpret />", "column 11");
+        setConfiguration(new TestConfigurationBuilder().tabSize(4).build());
+        assertErrorContains("<@'\\t$\\{*}'?interpret />", "column 7");
+    }
+    
+    @Test
+    public void testStringLiteralInterpolation() throws Exception {
+        assertErrorColumnNumber(6, "${'${*}'}");
+        assertErrorColumnNumber(9, "${'${\t*}'}");
+        setConfiguration(new TestConfigurationBuilder().tabSize(16).build());
+        assertErrorColumnNumber(17, "${'${\t*}'}");
+    }
+
+    protected void assertErrorColumnNumber(int expectedColumn, String templateSource)
+            throws IOException {
+        addTemplate("t", templateSource);
+        try {
+            getConfiguration().getTemplate("t");
+            fail();
+        } catch (ParseException e) {
+            assertEquals(expectedColumn, e.getColumnNumber());
+        }
+        getConfiguration().clearTemplateCache();
+        
+        try {
+            new Template(null, templateSource, getConfiguration());
+            fail();
+        } catch (ParseException e) {
+            assertEquals(expectedColumn, e.getColumnNumber());
+        }
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/TagSyntaxVariationsTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/TagSyntaxVariationsTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TagSyntaxVariationsTest.java
new file mode 100644
index 0000000..fa21c76
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TagSyntaxVariationsTest.java
@@ -0,0 +1,186 @@
+/*
+ * 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.util._StringUtil;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+
+import junit.framework.TestCase;
+
+/**
+ * Test various generated templates (permutations), including some deliberately
+ * wrong ones, with various tag_syntax settings.  
+ */
+public class TagSyntaxVariationsTest extends TestCase {
+    
+    private static final String HDR_ANG = "<#ftl>";
+    private static final String HDR_SQU = squarify(HDR_ANG);
+    private static final String IF_ANG = "<#if true>i</#if>";
+    private static final String IF_SQU = squarify(IF_ANG);
+    private static final String IF_OUT = "i";
+    private static final String ASSIGN_ANG = "<#assign x = 1>a";
+    private static final String ASSIGN_SQU = squarify(ASSIGN_ANG);
+    private static final String ASSIGN_OUT = "a";
+    private static final String WRONG_ANG = "<#wrong>";
+    private static final String WRONG_SQU = squarify(WRONG_ANG);
+    private static final String WRONGC_ANG = "</#wrong>";
+    private static final String WRONGC_SQU = squarify(WRONGC_ANG );
+    private static final String CUST_ANG = "<@compress> z </@>";
+    private static final String CUST_SQU = squarify(CUST_ANG);
+    private static final String CUST_OUT = "z";
+    
+    public TagSyntaxVariationsTest(String name) {
+        super(name);
+    }
+    
+    private static String squarify(String s) {
+        return s.replace('<', '[').replace('>', ']');
+    }
+
+    public final void test()
+            throws TemplateException, IOException {
+        // Permutations
+        for (int ifOrAssign = 0; ifOrAssign < 2; ifOrAssign++) {
+            String dir_ang = ifOrAssign == 0 ? IF_ANG : ASSIGN_ANG;
+            String dir_squ = ifOrAssign == 0 ? IF_SQU : ASSIGN_SQU;
+            String dir_out = ifOrAssign == 0 ? IF_OUT : ASSIGN_OUT;
+
+            // Permutations 
+            for (int angOrSqu = 0; angOrSqu < 2; angOrSqu++) {
+                Configuration cfg = new TestConfigurationBuilder()
+                        .tagSyntax(angOrSqu == 0
+                                ? ParsingConfiguration.ANGLE_BRACKET_TAG_SYNTAX
+                                : ParsingConfiguration.SQUARE_BRACKET_TAG_SYNTAX)
+                        .build();
+
+                String dir_xxx = angOrSqu == 0 ? dir_ang : dir_squ;
+                String cust_xxx = angOrSqu == 0 ? CUST_ANG : CUST_SQU;
+                String hdr_xxx = angOrSqu == 0 ? HDR_ANG : HDR_SQU;
+                String wrong_xxx = angOrSqu == 0 ? WRONG_ANG : WRONG_SQU;
+                String wrongc_xxx = angOrSqu == 0 ? WRONGC_ANG : WRONGC_SQU;
+
+                test(cfg,
+                        dir_xxx + cust_xxx,
+                        dir_out + CUST_OUT);
+
+                // Permutations 
+                for (int wrongOrWrongc = 0; wrongOrWrongc < 2; wrongOrWrongc++) {
+                    String wrongx_xxx = wrongOrWrongc == 0 ? wrong_xxx : wrongc_xxx;
+
+                    test(cfg,
+                            wrongx_xxx + dir_xxx,
+                            null);
+
+                    test(cfg,
+                            dir_xxx + wrongx_xxx,
+                            null);
+
+                    test(cfg,
+                            hdr_xxx + wrongx_xxx,
+                            null);
+
+                    test(cfg,
+                            cust_xxx + wrongx_xxx + dir_xxx,
+                            null);
+                } // for wrongc
+            } // for squ
+
+            {
+                Configuration cfg = new TestConfigurationBuilder()
+                        .tagSyntax(ParsingConfiguration.AUTO_DETECT_TAG_SYNTAX)
+                        .build();
+                for (int perm = 0; perm < 4; perm++) {
+                    // All 4 permutations
+                    String wrong_xxx = (perm & 1) == 0 ? WRONG_ANG : WRONG_SQU;
+                    String dir_xxx = (perm & 2) == 0 ? dir_ang : dir_squ;
+
+                    test(cfg,
+                            wrong_xxx + dir_xxx,
+                            null);
+                } // for perm
+            }
+
+            {
+                Configuration cfg = new TestConfigurationBuilder()
+                        .tagSyntax(ParsingConfiguration.AUTO_DETECT_TAG_SYNTAX)
+                        .build();
+                // Permutations
+                for (int angOrSquStart = 0; angOrSquStart < 2; angOrSquStart++) {
+                    String hdr_xxx = angOrSquStart == 0 ? HDR_ANG : HDR_SQU;
+                    String cust_xxx = angOrSquStart == 0 ? CUST_ANG : CUST_SQU;
+                    String wrong_yyy = angOrSquStart != 0 ? WRONG_ANG : WRONG_SQU;
+                    String dir_xxx = angOrSquStart == 0 ? dir_ang : dir_squ;
+                    String dir_yyy = angOrSquStart != 0 ? dir_ang : dir_squ;
+
+                    test(cfg,
+                            cust_xxx + wrong_yyy + dir_xxx,
+                            CUST_OUT + wrong_yyy + dir_out);
+
+                    test(cfg,
+                            hdr_xxx + wrong_yyy + dir_xxx,
+                            wrong_yyy + dir_out);
+
+                    test(cfg,
+                            cust_xxx + wrong_yyy + dir_yyy,
+                            CUST_OUT + wrong_yyy + dir_yyy);
+
+                    test(cfg,
+                            hdr_xxx + wrong_yyy + dir_yyy,
+                            wrong_yyy + dir_yyy);
+
+                    test(cfg,
+                            dir_xxx + wrong_yyy + dir_yyy,
+                            dir_out + wrong_yyy + dir_yyy);
+                } // for squStart
+            } // for assign
+        }
+    }
+    
+    /**
+     * @param expected the expected output or <tt>null</tt> if we expect
+     * a parsing error.
+     */
+    private static void test(
+            Configuration cfg, String template, String expected)
+            throws TemplateException, IOException {
+        Template t = null;
+        try {
+            t = new Template("string", new StringReader(template), cfg);
+        } catch (ParseException e) {
+            if (expected != null) {
+                fail("Couldn't invoke Template from "
+                        + _StringUtil.jQuote(template) + ": " + e);
+            } else {
+                return;
+            }
+        }
+        if (expected == null) fail("Template parsing should have fail for "
+                + _StringUtil.jQuote(template));
+        
+        StringWriter out = new StringWriter();
+        t.process(new Object(), out);
+        assertEquals(expected, out.toString());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateConfigurationTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateConfigurationTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateConfigurationTest.java
new file mode 100644
index 0000000..5b1cda9
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateConfigurationTest.java
@@ -0,0 +1,909 @@
+/*
+ * 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.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.TimeZone;
+
+import org.apache.commons.collections.ListUtils;
+import org.apache.freemarker.core.arithmetic.ArithmeticEngine;
+import org.apache.freemarker.core.arithmetic.impl.ConservativeArithmeticEngine;
+import org.apache.freemarker.core.model.impl.RestrictedObjectWrapper;
+import org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat;
+import org.apache.freemarker.core.outputformat.impl.UndefinedOutputFormat;
+import org.apache.freemarker.core.outputformat.impl.XMLOutputFormat;
+import org.apache.freemarker.core.templateresolver.ConditionalTemplateConfigurationFactory;
+import org.apache.freemarker.core.templateresolver.FileExtensionMatcher;
+import org.apache.freemarker.core.templateresolver.FileNameGlobMatcher;
+import org.apache.freemarker.core.templateresolver.impl.StringTemplateLoader;
+import org.apache.freemarker.core.userpkg.BaseNTemplateNumberFormatFactory;
+import org.apache.freemarker.core.userpkg.EpochMillisDivTemplateDateFormatFactory;
+import org.apache.freemarker.core.userpkg.EpochMillisTemplateDateFormatFactory;
+import org.apache.freemarker.core.userpkg.HexTemplateNumberFormatFactory;
+import org.apache.freemarker.core.userpkg.LocAndTZSensitiveTemplateDateFormatFactory;
+import org.apache.freemarker.core.userpkg.LocaleSensitiveTemplateNumberFormatFactory;
+import org.apache.freemarker.core.valueformat.TemplateDateFormatFactory;
+import org.apache.freemarker.core.valueformat.TemplateNumberFormatFactory;
+import org.apache.freemarker.test.MonitoredTemplateLoader;
+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 TemplateConfigurationTest {
+
+    private static final Charset ISO_8859_2 = Charset.forName("ISO-8859-2");
+
+    private final class DummyArithmeticEngine extends ArithmeticEngine {
+
+        @Override
+        public int compareNumbers(Number first, Number second) throws TemplateException {
+            return 0;
+        }
+
+        @Override
+        public Number add(Number first, Number second) throws TemplateException {
+            return 22;
+        }
+
+        @Override
+        public Number subtract(Number first, Number second) throws TemplateException {
+            return null;
+        }
+
+        @Override
+        public Number multiply(Number first, Number second) throws TemplateException {
+            return 33;
+        }
+
+        @Override
+        public Number divide(Number first, Number second) throws TemplateException {
+            return null;
+        }
+
+        @Override
+        public Number modulus(Number first, Number second) throws TemplateException {
+            return null;
+        }
+
+        @Override
+        public Number toNumber(String s) {
+            return 11;
+        }
+    }
+
+    private static final Configuration DEFAULT_CFG;
+    static {
+        TestConfigurationBuilder cfgB = new TestConfigurationBuilder();
+        StringTemplateLoader stl = new StringTemplateLoader();
+        stl.putTemplate("t1.ftl", "<#global loaded = (loaded!) + 't1;'>In t1;");
+        stl.putTemplate("t2.ftl", "<#global loaded = (loaded!) + 't2;'>In t2;");
+        stl.putTemplate("t3.ftl", "<#global loaded = (loaded!) + 't3;'>In t3;");
+        try {
+            DEFAULT_CFG = cfgB.templateLoader(stl).build();
+        } catch (ConfigurationException e) {
+            throw new IllegalStateException("Faild to create default configuration", e);
+        }
+    }
+
+    private static final TimeZone NON_DEFAULT_TZ;
+    static {
+        TimeZone defaultTZ = DEFAULT_CFG.getTimeZone();
+        TimeZone tz = TimeZone.getTimeZone("UTC");
+        if (tz.equals(defaultTZ)) {
+            tz = TimeZone.getTimeZone("GMT+01");
+            if (tz.equals(defaultTZ)) {
+                throw new AssertionError("Couldn't chose a non-default time zone");
+            }
+        }
+        NON_DEFAULT_TZ = tz;
+    }
+
+    private static final Locale NON_DEFAULT_LOCALE =
+            DEFAULT_CFG.getLocale().equals(Locale.US) ? Locale.GERMAN : Locale.US;
+
+    private static final Charset NON_DEFAULT_ENCODING =
+            DEFAULT_CFG.getSourceEncoding().equals(StandardCharsets.UTF_8) ? StandardCharsets.UTF_16LE
+                    : StandardCharsets.UTF_8;
+
+    private static final Map<String, Object> SETTING_ASSIGNMENTS;
+
+    static {
+        SETTING_ASSIGNMENTS = new HashMap<>();
+
+        // "MutableProcessingConfiguration" settings:
+        SETTING_ASSIGNMENTS.put("APIBuiltinEnabled", true);
+        SETTING_ASSIGNMENTS.put("SQLDateAndTimeTimeZone", NON_DEFAULT_TZ);
+        SETTING_ASSIGNMENTS.put("URLEscapingCharset", StandardCharsets.UTF_16);
+        SETTING_ASSIGNMENTS.put("autoFlush", false);
+        SETTING_ASSIGNMENTS.put("booleanFormat", "J,N");
+        SETTING_ASSIGNMENTS.put("dateFormat", "yyyy-#DDD");
+        SETTING_ASSIGNMENTS.put("dateTimeFormat", "yyyy-#DDD-@HH:mm");
+        SETTING_ASSIGNMENTS.put("locale", NON_DEFAULT_LOCALE);
+        SETTING_ASSIGNMENTS.put("logTemplateExceptions", true);
+        SETTING_ASSIGNMENTS.put("newBuiltinClassResolver", TemplateClassResolver.ALLOWS_NOTHING_RESOLVER);
+        SETTING_ASSIGNMENTS.put("numberFormat", "0.0000");
+        SETTING_ASSIGNMENTS.put("objectWrapper",
+                new RestrictedObjectWrapper.Builder(Configuration.VERSION_3_0_0).build());
+        SETTING_ASSIGNMENTS.put("outputEncoding", StandardCharsets.UTF_16);
+        SETTING_ASSIGNMENTS.put("showErrorTips", false);
+        SETTING_ASSIGNMENTS.put("templateExceptionHandler", TemplateExceptionHandler.IGNORE_HANDLER);
+        SETTING_ASSIGNMENTS.put("timeFormat", "@HH:mm");
+        SETTING_ASSIGNMENTS.put("timeZone", NON_DEFAULT_TZ);
+        SETTING_ASSIGNMENTS.put("arithmeticEngine", ConservativeArithmeticEngine.INSTANCE);
+        SETTING_ASSIGNMENTS.put("customNumberFormats",
+                ImmutableMap.of("dummy", HexTemplateNumberFormatFactory.INSTANCE));
+        SETTING_ASSIGNMENTS.put("customDateFormats",
+                ImmutableMap.of("dummy", EpochMillisTemplateDateFormatFactory.INSTANCE));
+        SETTING_ASSIGNMENTS.put("customAttributes", ImmutableMap.of("dummy", 123));
+
+        // Parser-only settings:
+        SETTING_ASSIGNMENTS.put("templateLanguage", TemplateLanguage.STATIC_TEXT);
+        SETTING_ASSIGNMENTS.put("tagSyntax", ParsingConfiguration.SQUARE_BRACKET_TAG_SYNTAX);
+        SETTING_ASSIGNMENTS.put("namingConvention", ParsingConfiguration.LEGACY_NAMING_CONVENTION);
+        SETTING_ASSIGNMENTS.put("whitespaceStripping", false);
+        SETTING_ASSIGNMENTS.put("strictSyntaxMode", false);
+        SETTING_ASSIGNMENTS.put("autoEscapingPolicy", ParsingConfiguration.DISABLE_AUTO_ESCAPING_POLICY);
+        SETTING_ASSIGNMENTS.put("outputFormat", HTMLOutputFormat.INSTANCE);
+        SETTING_ASSIGNMENTS.put("recognizeStandardFileExtensions", false);
+        SETTING_ASSIGNMENTS.put("tabSize", 1);
+        SETTING_ASSIGNMENTS.put("lazyImports", Boolean.TRUE);
+        SETTING_ASSIGNMENTS.put("lazyAutoImports", Boolean.FALSE);
+        SETTING_ASSIGNMENTS.put("autoImports", ImmutableMap.of("a", "/lib/a.ftl"));
+        SETTING_ASSIGNMENTS.put("autoIncludes", ImmutableList.of("/lib/b.ftl"));
+        
+        // Special settings:
+        SETTING_ASSIGNMENTS.put("sourceEncoding", NON_DEFAULT_ENCODING);
+    }
+    
+    public static String getIsSetMethodName(String readMethodName) {
+        return (readMethodName.startsWith("get") ? "is" + readMethodName.substring(3)
+                : readMethodName)
+                + "Set";
+    }
+
+    public static List<PropertyDescriptor> getTemplateConfigurationSettingPropDescs(
+            Class<? extends ProcessingConfiguration> confClass, boolean includeCompilerSettings)
+            throws IntrospectionException {
+        List<PropertyDescriptor> settingPropDescs = new ArrayList<>();
+
+        BeanInfo beanInfo = Introspector.getBeanInfo(confClass);
+        for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
+            String name = pd.getName();
+            if (pd.getWriteMethod() != null && !IGNORED_PROP_NAMES.contains(name)
+                    && (includeCompilerSettings
+                            || (CONFIGURABLE_PROP_NAMES.contains(name) || !PARSER_PROP_NAMES.contains(name)))) {
+                if (pd.getReadMethod() == null) {
+                    throw new AssertionError("Property has no read method: " + pd);
+                }
+                settingPropDescs.add(pd);
+            }
+        }
+
+        Collections.sort(settingPropDescs, new Comparator<PropertyDescriptor>() {
+            @Override
+            public int compare(PropertyDescriptor o1, PropertyDescriptor o2) {
+                return o1.getName().compareToIgnoreCase(o2.getName());
+            }
+        });
+
+        return settingPropDescs;
+    }
+
+    private static final Set<String> IGNORED_PROP_NAMES;
+
+    static {
+        IGNORED_PROP_NAMES = new HashSet();
+        IGNORED_PROP_NAMES.add("class");
+        IGNORED_PROP_NAMES.add("strictBeanModels");
+        IGNORED_PROP_NAMES.add("parentConfiguration");
+        IGNORED_PROP_NAMES.add("settings");
+    }
+
+    private static final Set<String> CONFIGURABLE_PROP_NAMES;
+    static {
+        CONFIGURABLE_PROP_NAMES = new HashSet<>();
+        try {
+            for (PropertyDescriptor propDesc : Introspector.getBeanInfo(MutableProcessingConfiguration.class).getPropertyDescriptors()) {
+                String propName = propDesc.getName();
+                if (!IGNORED_PROP_NAMES.contains(propName)) {
+                    CONFIGURABLE_PROP_NAMES.add(propName);
+                }
+            }
+        } catch (IntrospectionException e) {
+            throw new IllegalStateException("Failed to init static field", e);
+        }
+    }
+    
+    private static final Set<String> PARSER_PROP_NAMES;
+    static {
+        PARSER_PROP_NAMES = new HashSet<>();
+        // It's an interface; can't use standard Inrospector
+        for (Method m : ParsingConfiguration.class.getMethods()) {
+            String propertyName;
+            String name = m.getName();
+            if (name.startsWith("get")) {
+                propertyName = name.substring(3);
+            } else if (name.startsWith("is") && !name.endsWith("Set")) {
+                propertyName = name.substring(2);
+            } else {
+                propertyName = null;
+            }
+            if (propertyName != null) {
+                if (!Character.isUpperCase(propertyName.charAt(1))) {
+                    propertyName = Character.toLowerCase(propertyName.charAt(0)) + propertyName.substring(1);
+                }
+                PARSER_PROP_NAMES.add(propertyName);
+            }
+        }
+    }
+
+    private static final Object CA1 = new Object();
+    private static final String CA2 = "ca2";
+    private static final String CA3 = "ca3";
+    private static final String CA4 = "ca4";
+
+    @Test
+    public void testMergeBasicFunctionality() throws Exception {
+        for (PropertyDescriptor propDesc1 : getTemplateConfigurationSettingPropDescs(
+                TemplateConfiguration.Builder.class, true)) {
+            for (PropertyDescriptor propDesc2 : getTemplateConfigurationSettingPropDescs(
+                    TemplateConfiguration.Builder.class, true)) {
+                TemplateConfiguration.Builder tcb1 = new TemplateConfiguration.Builder();
+                TemplateConfiguration.Builder tcb2 = new TemplateConfiguration.Builder();
+
+                Object value1 = SETTING_ASSIGNMENTS.get(propDesc1.getName());
+                propDesc1.getWriteMethod().invoke(tcb1, value1);
+                Object value2 = SETTING_ASSIGNMENTS.get(propDesc2.getName());
+                propDesc2.getWriteMethod().invoke(tcb2, value2);
+
+                tcb1.merge(tcb2);
+                if (propDesc1.getName().equals(propDesc2.getName()) && value1 instanceof List
+                        && !propDesc1.getName().equals("autoIncludes")) {
+                    assertEquals("For " + propDesc1.getName(),
+                            ListUtils.union((List) value1, (List) value1), propDesc1.getReadMethod().invoke(tcb1));
+                } else { // Values of the same setting merged
+                    assertEquals("For " + propDesc1.getName(), value1, propDesc1.getReadMethod().invoke(tcb1));
+                    assertEquals("For " + propDesc2.getName(), value2, propDesc2.getReadMethod().invoke(tcb1));
+                }
+            }
+        }
+    }
+    
+    @Test
+    public void testMergeMapSettings() throws Exception {
+        TemplateConfiguration.Builder tc1 = new TemplateConfiguration.Builder();
+        tc1.setCustomDateFormats(ImmutableMap.of(
+                "epoch", EpochMillisTemplateDateFormatFactory.INSTANCE,
+                "x", LocAndTZSensitiveTemplateDateFormatFactory.INSTANCE));
+        tc1.setCustomNumberFormats(ImmutableMap.of(
+                "hex", HexTemplateNumberFormatFactory.INSTANCE,
+                "x", LocaleSensitiveTemplateNumberFormatFactory.INSTANCE));
+        tc1.setAutoImports(ImmutableMap.of("a", "a1.ftl", "b", "b1.ftl"));
+        
+        TemplateConfiguration.Builder tc2 = new TemplateConfiguration.Builder();
+        tc2.setCustomDateFormats(ImmutableMap.of(
+                "loc", LocAndTZSensitiveTemplateDateFormatFactory.INSTANCE,
+                "x", EpochMillisDivTemplateDateFormatFactory.INSTANCE));
+        tc2.setCustomNumberFormats(ImmutableMap.of(
+                "loc", LocaleSensitiveTemplateNumberFormatFactory.INSTANCE,
+                "x", BaseNTemplateNumberFormatFactory.INSTANCE));
+        tc2.setAutoImports(ImmutableMap.of("b", "b2.ftl", "c", "c2.ftl"));
+        
+        tc1.merge(tc2);
+        
+        Map<String, ? extends TemplateDateFormatFactory> mergedCustomDateFormats = tc1.getCustomDateFormats();
+        assertEquals(EpochMillisTemplateDateFormatFactory.INSTANCE, mergedCustomDateFormats.get("epoch"));
+        assertEquals(LocAndTZSensitiveTemplateDateFormatFactory.INSTANCE, mergedCustomDateFormats.get("loc"));
+        assertEquals(EpochMillisDivTemplateDateFormatFactory.INSTANCE, mergedCustomDateFormats.get("x"));
+        
+        Map<String, ? extends TemplateNumberFormatFactory> mergedCustomNumberFormats = tc1.getCustomNumberFormats();
+        assertEquals(HexTemplateNumberFormatFactory.INSTANCE, mergedCustomNumberFormats.get("hex"));
+        assertEquals(LocaleSensitiveTemplateNumberFormatFactory.INSTANCE, mergedCustomNumberFormats.get("loc"));
+        assertEquals(BaseNTemplateNumberFormatFactory.INSTANCE, mergedCustomNumberFormats.get("x"));
+
+        Map<String, String> mergedAutoImports = tc1.getAutoImports();
+        assertEquals("a1.ftl", mergedAutoImports.get("a"));
+        assertEquals("b2.ftl", mergedAutoImports.get("b"));
+        assertEquals("c2.ftl", mergedAutoImports.get("c"));
+        
+        // Empty map merging optimization:
+        tc1.merge(new TemplateConfiguration.Builder());
+        assertSame(mergedCustomDateFormats, tc1.getCustomDateFormats());
+        assertSame(mergedCustomNumberFormats, tc1.getCustomNumberFormats());
+        
+        // Empty map merging optimization:
+        TemplateConfiguration.Builder tc3 = new TemplateConfiguration.Builder();
+        tc3.merge(tc1);
+        assertSame(mergedCustomDateFormats, tc3.getCustomDateFormats());
+        assertSame(mergedCustomNumberFormats, tc3.getCustomNumberFormats());
+    }
+    
+    @Test
+    public void testMergeListSettings() throws Exception {
+        TemplateConfiguration.Builder tc1 = new TemplateConfiguration.Builder();
+        tc1.setAutoIncludes(ImmutableList.of("a.ftl", "x.ftl", "b.ftl"));
+        
+        TemplateConfiguration.Builder tc2 = new TemplateConfiguration.Builder();
+        tc2.setAutoIncludes(ImmutableList.of("c.ftl", "x.ftl", "d.ftl"));
+        
+        tc1.merge(tc2);
+        
+        assertEquals(ImmutableList.of("a.ftl", "b.ftl", "c.ftl", "x.ftl", "d.ftl"), tc1.getAutoIncludes());
+    }
+    
+    @Test
+    public void testMergePriority() throws Exception {
+        TemplateConfiguration.Builder tc1 = new TemplateConfiguration.Builder();
+        tc1.setDateFormat("1");
+        tc1.setTimeFormat("1");
+        tc1.setDateTimeFormat("1");
+
+        TemplateConfiguration.Builder tc2 = new TemplateConfiguration.Builder();
+        tc2.setDateFormat("2");
+        tc2.setTimeFormat("2");
+
+        TemplateConfiguration.Builder tc3 = new TemplateConfiguration.Builder();
+        tc3.setDateFormat("3");
+
+        tc1.merge(tc2);
+        tc1.merge(tc3);
+
+        assertEquals("3", tc1.getDateFormat());
+        assertEquals("2", tc1.getTimeFormat());
+        assertEquals("1", tc1.getDateTimeFormat());
+    }
+    
+    @Test
+    public void testMergeCustomAttributes() throws Exception {
+        TemplateConfiguration.Builder tc1 = new TemplateConfiguration.Builder();
+        tc1.setCustomAttribute("k1", "v1");
+        tc1.setCustomAttribute("k2", "v1");
+        tc1.setCustomAttribute("k3", "v1");
+        tc1.setCustomAttribute(CA1, "V1");
+        tc1.setCustomAttribute(CA2, "V1");
+        tc1.setCustomAttribute(CA3, "V1");
+
+        TemplateConfiguration.Builder tc2 = new TemplateConfiguration.Builder();
+        tc2.setCustomAttribute("k1", "v2");
+        tc2.setCustomAttribute("k2", "v2");
+        tc2.setCustomAttribute(CA1, "V2");
+        tc2.setCustomAttribute(CA2, "V2");
+
+        TemplateConfiguration.Builder tc3 = new TemplateConfiguration.Builder();
+        tc3.setCustomAttribute("k1", "v3");
+        tc3.setCustomAttribute(CA1, "V3");
+
+        tc1.merge(tc2);
+        tc1.merge(tc3);
+
+        assertEquals("v3", tc1.getCustomAttribute("k1"));
+        assertEquals("v2", tc1.getCustomAttribute("k2"));
+        assertEquals("v1", tc1.getCustomAttribute("k3"));
+        assertEquals("V3", tc1.getCustomAttribute(CA1));
+        assertEquals("V2", tc1.getCustomAttribute(CA2));
+        assertEquals("V1", tc1.getCustomAttribute(CA3));
+    }
+
+    @Test
+    public void testMergeNullCustomAttributes() throws Exception {
+        TemplateConfiguration.Builder tc1 = new TemplateConfiguration.Builder();
+        tc1.setCustomAttribute("k1", "v1");
+        tc1.setCustomAttribute("k2", "v1");
+        tc1.setCustomAttribute(CA1, "V1");
+        tc1.setCustomAttribute(CA2,"V1");
+
+        assertEquals("v1", tc1.getCustomAttribute("k1"));
+        assertEquals("v1", tc1.getCustomAttribute("k2"));
+        assertNull("v1", tc1.getCustomAttribute("k3"));
+        assertEquals("V1", tc1.getCustomAttribute(CA1));
+        assertEquals("V1", tc1.getCustomAttribute(CA2));
+        assertNull(tc1.getCustomAttribute(CA3));
+
+        TemplateConfiguration.Builder tc2 = new TemplateConfiguration.Builder();
+        tc2.setCustomAttribute("k1", "v2");
+        tc2.setCustomAttribute("k2", null);
+        tc2.setCustomAttribute(CA1, "V2");
+        tc2.setCustomAttribute(CA2, null);
+
+        TemplateConfiguration.Builder tc3 = new TemplateConfiguration.Builder();
+        tc3.setCustomAttribute("k1", null);
+        tc2.setCustomAttribute(CA1, null);
+
+        tc1.merge(tc2);
+        tc1.merge(tc3);
+
+        assertNull(tc1.getCustomAttribute("k1"));
+        assertNull(tc1.getCustomAttribute("k2"));
+        assertNull(tc1.getCustomAttribute("k3"));
+        assertNull(tc1.getCustomAttribute(CA1));
+        assertNull(tc1.getCustomAttribute(CA2));
+        assertNull(tc1.getCustomAttribute(CA3));
+
+        TemplateConfiguration.Builder tc4 = new TemplateConfiguration.Builder();
+        tc4.setCustomAttribute("k1", "v4");
+        tc4.setCustomAttribute(CA1, "V4");
+
+        tc1.merge(tc4);
+
+        assertEquals("v4", tc1.getCustomAttribute("k1"));
+        assertNull(tc1.getCustomAttribute("k2"));
+        assertNull(tc1.getCustomAttribute("k3"));
+        assertEquals("V4", tc1.getCustomAttribute(CA1));
+        assertNull(tc1.getCustomAttribute(CA2));
+        assertNull(tc1.getCustomAttribute(CA3));
+    }
+
+    @Test
+    public void testConfigureNonParserConfig() throws Exception {
+        for (PropertyDescriptor pd : getTemplateConfigurationSettingPropDescs(
+                TemplateConfiguration.Builder.class, false)) {
+            TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
+
+            Object newValue = SETTING_ASSIGNMENTS.get(pd.getName());
+            pd.getWriteMethod().invoke(tcb, newValue);
+            
+            TemplateConfiguration tc = tcb.build();
+
+            Method tReaderMethod = Template.class.getMethod(pd.getReadMethod().getName());
+
+            // Without TC
+            assertNotEquals("For \"" + pd.getName() + "\"",
+                    tReaderMethod.invoke(new Template(null, "", DEFAULT_CFG)));
+            // With TC
+            assertEquals("For \"" + pd.getName() + "\"", newValue,
+                    tReaderMethod.invoke(new Template(null, "", DEFAULT_CFG, tc)));
+        }
+    }
+    
+    @Test
+    public void testConfigureCustomAttributes() throws Exception {
+        Configuration cfg = new TestConfigurationBuilder()
+                .customAttribute("k1", "c")
+                .customAttribute("k2", "c")
+                .customAttribute("k3", "c")
+                .build();
+
+        TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
+        tcb.setCustomAttribute("k2", "tc");
+        tcb.setCustomAttribute("k3", null);
+        tcb.setCustomAttribute("k4", "tc");
+        tcb.setCustomAttribute("k5", "tc");
+        tcb.setCustomAttribute("k6", "tc");
+        tcb.setCustomAttribute(CA1, "tc");
+        tcb.setCustomAttribute(CA2,"tc");
+        tcb.setCustomAttribute(CA3,"tc");
+
+        TemplateConfiguration tc = tcb.build();
+        Template t = new Template(null, "", cfg, tc);
+        t.setCustomAttribute("k5", "t");
+        t.setCustomAttribute("k6", null);
+        t.setCustomAttribute("k7", "t");
+        t.setCustomAttribute(CA2, "t");
+        t.setCustomAttribute(CA3, null);
+        t.setCustomAttribute(CA4, "t");
+
+        assertEquals("c", t.getCustomAttribute("k1"));
+        assertEquals("tc", t.getCustomAttribute("k2"));
+        assertNull(t.getCustomAttribute("k3"));
+        assertEquals("tc", t.getCustomAttribute("k4"));
+        assertEquals("t", t.getCustomAttribute("k5"));
+        assertNull(t.getCustomAttribute("k6"));
+        assertEquals("t", t.getCustomAttribute("k7"));
+        assertEquals("tc", t.getCustomAttribute(CA1));
+        assertEquals("t", t.getCustomAttribute(CA2));
+        assertNull(t.getCustomAttribute(CA3));
+        assertEquals("t", t.getCustomAttribute(CA4));
+    }
+    
+    @Test
+    public void testConfigureParser() throws Exception {
+        Set<String> testedProps = new HashSet<>();
+        
+        {
+            TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
+            tcb.setTagSyntax(ParsingConfiguration.SQUARE_BRACKET_TAG_SYNTAX);
+            TemplateConfiguration tc = tcb.build();
+            assertOutputWithoutAndWithTC(tc, "[#if true]y[/#if]", "[#if true]y[/#if]", "y");
+            testedProps.add(Configuration.ExtendableBuilder.TAG_SYNTAX_KEY_CAMEL_CASE);
+        }
+        
+        {
+            TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
+            tcb.setNamingConvention(ParsingConfiguration.CAMEL_CASE_NAMING_CONVENTION);
+            TemplateConfiguration tc = tcb.build();
+            assertOutputWithoutAndWithTC(tc, "<#if true>y<#elseif false>n</#if>", "y", null);
+            testedProps.add(Configuration.ExtendableBuilder.NAMING_CONVENTION_KEY_CAMEL_CASE);
+        }
+        
+        {
+            TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
+            tcb.setWhitespaceStripping(false);
+            TemplateConfiguration tc = tcb.build();
+            assertOutputWithoutAndWithTC(tc, "<#if true>\nx\n</#if>\n", "x\n", "\nx\n\n");
+            testedProps.add(Configuration.ExtendableBuilder.WHITESPACE_STRIPPING_KEY_CAMEL_CASE);
+        }
+
+        {
+            TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
+            tcb.setArithmeticEngine(new DummyArithmeticEngine());
+            TemplateConfiguration tc = tcb.build();
+            assertOutputWithoutAndWithTC(tc, "${1} ${1+1}", "1 2", "11 22");
+            testedProps.add(Configuration.ExtendableBuilder.ARITHMETIC_ENGINE_KEY_CAMEL_CASE);
+        }
+
+        {
+            TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
+            tcb.setOutputFormat(XMLOutputFormat.INSTANCE);
+            TemplateConfiguration tc = tcb.build();
+            assertOutputWithoutAndWithTC(tc, "${.outputFormat} ${\"a'b\"}",
+                    UndefinedOutputFormat.INSTANCE.getName() + " a'b",
+                    XMLOutputFormat.INSTANCE.getName() + " a&apos;b");
+            testedProps.add(Configuration.ExtendableBuilder.OUTPUT_FORMAT_KEY_CAMEL_CASE);
+        }
+
+        {
+            TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
+            tcb.setOutputFormat(XMLOutputFormat.INSTANCE);
+            tcb.setAutoEscapingPolicy(ParsingConfiguration.DISABLE_AUTO_ESCAPING_POLICY);
+            TemplateConfiguration tc = tcb.build();
+            assertOutputWithoutAndWithTC(tc, "${'a&b'}", "a&b", "a&b");
+            testedProps.add(Configuration.ExtendableBuilder.AUTO_ESCAPING_POLICY_KEY_CAMEL_CASE);
+        }
+        
+        {
+            TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
+            /* Can't test this now, as the only valid value is 3.0.0. [FM3.0.1]
+            TemplateConfiguration tc = tcb.build();
+            tc.setParentConfiguration(new Configuration(new Version(2, 3, 0)));
+            assertOutputWithoutAndWithTC(tc, "<#foo>", null, "<#foo>");
+            */
+            testedProps.add(Configuration.ExtendableBuilder.INCOMPATIBLE_IMPROVEMENTS_KEY_CAMEL_CASE);
+        }
+
+        {
+            TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
+            tcb.setRecognizeStandardFileExtensions(false);
+            TemplateConfiguration tc = tcb.build();
+            assertOutputWithoutAndWithTC(tc, "adhoc.ftlh", "${.outputFormat}",
+                    HTMLOutputFormat.INSTANCE.getName(), UndefinedOutputFormat.INSTANCE.getName());
+            testedProps.add(Configuration.ExtendableBuilder.RECOGNIZE_STANDARD_FILE_EXTENSIONS_KEY_CAMEL_CASE);
+        }
+
+        {
+            TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
+            tcb.setLogTemplateExceptions(false);
+            tcb.setTabSize(3);
+            TemplateConfiguration tc = tcb.build();
+            assertOutputWithoutAndWithTC(tc,
+                    "<#attempt><@'\\t$\\{1+}'?interpret/><#recover>"
+                    + "${.error?replace('(?s).*?column ([0-9]+).*', '$1', 'r')}"
+                    + "</#attempt>",
+                    "13", "8");
+            testedProps.add(Configuration.ExtendableBuilder.TAB_SIZE_KEY_CAMEL_CASE);
+        }
+
+        {
+            // As the TemplateLanguage-based parser selection happens in the TemplateResolver, we can't use
+            // assertOutput here, as that hard-coded to create an FTL Template.
+
+            TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
+            tcb.setTemplateLanguage(TemplateLanguage.STATIC_TEXT);
+
+            TestConfigurationBuilder cfgB = new TestConfigurationBuilder();
+            cfgB.setTemplateConfigurations(
+                    new ConditionalTemplateConfigurationFactory(new FileExtensionMatcher("txt"), tcb.build()));
+
+            StringTemplateLoader templateLoader = new StringTemplateLoader();
+            templateLoader.putTemplate("adhoc.ftl", "${1+1}");
+            templateLoader.putTemplate("adhoc.txt", "${1+1}");
+            cfgB.setTemplateLoader(templateLoader);
+
+            Configuration cfg = cfgB.build();
+            
+            {
+                StringWriter out = new StringWriter();
+                cfg.getTemplate("adhoc.ftl").process(null, out);
+                assertEquals("2", out.toString());
+            }
+            {
+                StringWriter out = new StringWriter();
+                cfg.getTemplate("adhoc.txt").process(null, out);
+                assertEquals("${1+1}", out.toString());
+            }
+
+            testedProps.add(Configuration.ExtendableBuilder.TEMPLATE_LANGUAGE_KEY_CAMEL_CASE);
+        }
+
+        {
+            // As the TemplateLanguage-based parser selection happens in the TemplateResolver, we can't use
+            // assertOutput here, as that hard-coded to create an FTL Template.
+
+            TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
+            tcb.setSourceEncoding(StandardCharsets.ISO_8859_1);
+
+            TestConfigurationBuilder cfgB = new TestConfigurationBuilder();
+            cfgB.setSourceEncoding(StandardCharsets.UTF_8);
+            cfgB.setTemplateConfigurations(new ConditionalTemplateConfigurationFactory(
+                    new FileNameGlobMatcher("latin1.ftl"), tcb.build()));
+
+            MonitoredTemplateLoader templateLoader = new MonitoredTemplateLoader();
+            templateLoader.putBinaryTemplate("utf8.ftl", "próba", StandardCharsets.UTF_8, 1);
+            templateLoader.putBinaryTemplate("latin1.ftl", "próba", StandardCharsets.ISO_8859_1, 1);
+            cfgB.setTemplateLoader(templateLoader);
+
+            Configuration cfg = cfgB.build();
+            
+            {
+                StringWriter out = new StringWriter();
+                cfg.getTemplate("utf8.ftl").process(null, out);
+                assertEquals("próba", out.toString());
+            }
+            {
+                StringWriter out = new StringWriter();
+                cfg.getTemplate("latin1.ftl").process(null, out);
+                assertEquals("próba", out.toString());
+            }
+
+            testedProps.add(Configuration.ExtendableBuilder.SOURCE_ENCODING_KEY_CAMEL_CASE);
+        }
+
+        if (!PARSER_PROP_NAMES.equals(testedProps)) {
+            Set<String> diff = new HashSet<>(PARSER_PROP_NAMES);
+            diff.removeAll(testedProps);
+            fail("Some settings weren't checked: " + diff);
+        }
+    }
+    
+    @Test
+    public void testArithmeticEngine() throws TemplateException, IOException {
+        TemplateConfiguration tc = new TemplateConfiguration.Builder()
+                .arithmeticEngine(new DummyArithmeticEngine())
+                .build();
+        assertOutputWithoutAndWithTC(tc,
+                "<#setting locale='en_US'>${1} ${1+1} ${1*3} <#assign x = 1>${x + x} ${x * 3}",
+                "1 2 3 2 3", "11 22 33 22 33");
+        
+        // Does affect template.arithmeticEngine (unlike in FM2)
+        Template t = new Template(null, null, new StringReader(""), DEFAULT_CFG, tc, null);
+        assertEquals(tc.getArithmeticEngine(), t.getArithmeticEngine());
+    }
+
+    @Test
+    public void testAutoImport() throws TemplateException, IOException {
+        TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
+        tcb.setAutoImports(ImmutableMap.of("t1", "t1.ftl", "t2", "t2.ftl"));
+        TemplateConfiguration tc = tcb.build();
+        assertOutputWithoutAndWithTC(tc, "<#import 't3.ftl' as t3>${loaded}", "t3;", "t1;t2;t3;");
+    }
+
+    @Test
+    public void testAutoIncludes() throws TemplateException, IOException {
+        TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
+        tcb.setAutoIncludes(ImmutableList.of("t1.ftl", "t2.ftl"));
+        TemplateConfiguration tc = tcb.build();
+        assertOutputWithoutAndWithTC(tc, "<#include 't3.ftl'>", "In t3;", "In t1;In t2;In t3;");
+    }
+    
+    @Test
+    public void testStringInterpolate() throws TemplateException, IOException {
+        TemplateConfiguration tc = new TemplateConfiguration.Builder()
+                .arithmeticEngine(new DummyArithmeticEngine())
+                .build();
+        assertOutputWithoutAndWithTC(tc,
+                "<#setting locale='en_US'>${'${1} ${1+1} ${1*3}'} <#assign x = 1>${'${x + x} ${x * 3}'}",
+                "1 2 3 2 3", "11 22 33 22 33");
+        
+        // Does affect template.arithmeticEngine (unlike in FM2):
+        Template t = new Template(null, null, new StringReader(""), DEFAULT_CFG, tc, null);
+        assertEquals(tc.getArithmeticEngine(), t.getArithmeticEngine());
+    }
+    
+    @Test
+    public void testInterpret() throws TemplateException, IOException {
+        TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
+        tcb.setArithmeticEngine(new DummyArithmeticEngine());
+        {
+            TemplateConfiguration tc = tcb.build();
+            assertOutputWithoutAndWithTC(tc,
+                    "<#setting locale='en_US'><#assign src = r'${1} <#assign x = 1>${x + x}'><@src?interpret />",
+                    "1 2", "11 22");
+        }
+        tcb.setWhitespaceStripping(false);
+        {
+            TemplateConfiguration tc = tcb.build();
+            assertOutputWithoutAndWithTC(tc,
+                    "<#if true>\nX</#if><#assign src = r'<#if true>\nY</#if>'><@src?interpret />",
+                    "XY", "\nX\nY");
+        }
+    }
+
+    @Test
+    public void testEval() throws TemplateException, IOException {
+        {
+            TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
+            tcb.setArithmeticEngine(new DummyArithmeticEngine());
+            TemplateConfiguration tc = tcb.build();
+            assertOutputWithoutAndWithTC(tc,
+                    "<#assign x = 1>${r'1 + x'?eval?c}",
+                    "2", "22");
+            assertOutputWithoutAndWithTC(tc,
+                    "${r'1?c'?eval}",
+                    "1", "11");
+        }
+        
+        {
+            TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
+            Charset outputEncoding = ISO_8859_2;
+            tcb.setOutputEncoding(outputEncoding);
+
+            String legacyNCFtl = "${r'.output_encoding!\"null\"'?eval}";
+            String camelCaseNCFtl = "${r'.outputEncoding!\"null\"'?eval}";
+
+            {
+                TemplateConfiguration tc = tcb.build();
+
+                // Default is re-auto-detecting in ?eval:
+                assertOutputWithoutAndWithTC(tc, legacyNCFtl, "null", outputEncoding.name());
+                assertOutputWithoutAndWithTC(tc, camelCaseNCFtl, "null", outputEncoding.name());
+            }
+
+            {
+                // Force camelCase:
+                tcb.setNamingConvention(ParsingConfiguration.CAMEL_CASE_NAMING_CONVENTION);
+
+                TemplateConfiguration tc = tcb.build();
+
+                assertOutputWithoutAndWithTC(tc, legacyNCFtl, "null", null);
+                assertOutputWithoutAndWithTC(tc, camelCaseNCFtl, "null", outputEncoding.name());
+            }
+
+            {
+                // Force legacy:
+                tcb.setNamingConvention(ParsingConfiguration.LEGACY_NAMING_CONVENTION);
+
+                TemplateConfiguration tc = tcb.build();
+
+                assertOutputWithoutAndWithTC(tc, legacyNCFtl, "null", outputEncoding.name());
+                assertOutputWithoutAndWithTC(tc, camelCaseNCFtl, "null", null);
+            }
+        }
+    }
+    
+    private void assertOutputWithoutAndWithTC(
+            TemplateConfiguration tc, String ftl, String expectedDefaultOutput,
+            String expectedConfiguredOutput) throws TemplateException, IOException {
+        assertOutputWithoutAndWithTC(tc, null, ftl, expectedDefaultOutput, expectedConfiguredOutput);
+    }
+    
+    private void assertOutputWithoutAndWithTC(
+            TemplateConfiguration tc, String templateName, String ftl, String expectedDefaultOutput,
+            String expectedConfiguredOutput) throws TemplateException, IOException {
+        if (templateName == null) {
+            templateName = "adhoc.ftl";
+        }
+        assertOutput(null, templateName, ftl, expectedDefaultOutput);
+        assertOutput(tc, templateName, ftl, expectedConfiguredOutput);
+    }
+
+    private void assertOutput(TemplateConfiguration tc, String templateName, String ftl, String
+            expectedConfiguredOutput)
+            throws TemplateException, IOException {
+        StringWriter sw = new StringWriter();
+        try {
+            Template t = new Template(templateName, null, new StringReader(ftl), DEFAULT_CFG, tc, null);
+            t.process(null, sw);
+            if (expectedConfiguredOutput == null) {
+                fail("Template should have fail.");
+            }
+        } catch (TemplateException|ParseException e) {
+            if (expectedConfiguredOutput != null) {
+                throw e;
+            }
+        }
+        if (expectedConfiguredOutput != null) {
+            assertEquals(expectedConfiguredOutput, sw.toString());
+        }
+    }
+
+    @Test
+    public void testIsSet() throws Exception {
+        for (PropertyDescriptor pd : getTemplateConfigurationSettingPropDescs(
+                TemplateConfiguration.Builder.class, true)) {
+            TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
+            checkAllIsSetFalseExcept(tcb.build(), null);
+            pd.getWriteMethod().invoke(tcb, SETTING_ASSIGNMENTS.get(pd.getName()));
+            checkAllIsSetFalseExcept(tcb.build(), pd.getName());
+        }
+    }
+
+    private void checkAllIsSetFalseExcept(TemplateConfiguration tc, String setSetting)
+            throws SecurityException, IntrospectionException,
+            IllegalArgumentException, IllegalAccessException, InvocationTargetException {
+        for (PropertyDescriptor pd : getTemplateConfigurationSettingPropDescs(TemplateConfiguration.class, true)) {
+            String isSetMethodName = getIsSetMethodName(pd.getReadMethod().getName());
+            Method isSetMethod;
+            try {
+                isSetMethod = tc.getClass().getMethod(isSetMethodName);
+            } catch (NoSuchMethodException e) {
+                fail("Missing " + isSetMethodName + " method for \"" + pd.getName() + "\".");
+                return;
+            }
+            if (pd.getName().equals(setSetting)) {
+                assertTrue(isSetMethod + " should return true", (Boolean) (isSetMethod.invoke(tc)));
+            } else {
+                assertFalse(isSetMethod + " should return false", (Boolean) (isSetMethod.invoke(tc)));
+            }
+        }
+    }
+
+    /**
+     * Test case self-check.
+     */
+    @Test
+    public void checkTestAssignments() throws Exception {
+        for (PropertyDescriptor pd : getTemplateConfigurationSettingPropDescs(
+                TemplateConfiguration.Builder.class, true)) {
+            String propName = pd.getName();
+            if (!SETTING_ASSIGNMENTS.containsKey(propName)) {
+                fail("Test case doesn't cover all settings in SETTING_ASSIGNMENTS. Missing: " + propName);
+            }
+            Method readMethod = pd.getReadMethod();
+            String cfgMethodName = readMethod.getName();
+            Method cfgMethod = DEFAULT_CFG.getClass().getMethod(cfgMethodName, readMethod.getParameterTypes());
+            Object defaultSettingValue = cfgMethod.invoke(DEFAULT_CFG);
+            Object assignedValue = SETTING_ASSIGNMENTS.get(propName);
+            assertNotEquals("SETTING_ASSIGNMENTS must contain a non-default value for " + propName,
+                    assignedValue, defaultSettingValue);
+
+            TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
+            try {
+                pd.getWriteMethod().invoke(tcb, assignedValue);
+            } catch (Exception e) {
+                throw new IllegalStateException("For setting \"" + propName + "\" and assigned value of type "
+                        + (assignedValue != null ? assignedValue.getClass().getName() : "Null"),
+                        e);
+            }
+        }
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateConfigurationWithDefaultTemplateResolverTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateConfigurationWithDefaultTemplateResolverTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateConfigurationWithDefaultTemplateResolverTest.java
new file mode 100644
index 0000000..4cd50eb
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateConfigurationWithDefaultTemplateResolverTest.java
@@ -0,0 +1,267 @@
+/*
+ * 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.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.Locale;
+
+import org.apache.freemarker.core.templateresolver.ConditionalTemplateConfigurationFactory;
+import org.apache.freemarker.core.templateresolver.FileNameGlobMatcher;
+import org.apache.freemarker.core.templateresolver.FirstMatchTemplateConfigurationFactory;
+import org.apache.freemarker.core.templateresolver.MergingTemplateConfigurationFactory;
+import org.apache.freemarker.core.templateresolver.impl.ByteArrayTemplateLoader;
+import org.apache.freemarker.core.templateresolver.impl.StringTemplateLoader;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+import org.junit.Test;
+
+public class TemplateConfigurationWithDefaultTemplateResolverTest {
+
+    private static final String TEXT_WITH_ACCENTS = "pr\u00F3ba";
+
+    private static final Object CUST_ATT_1 = new Object();
+    private static final Object CUST_ATT_2 = new Object();
+
+    private static final Charset ISO_8859_2 = Charset.forName("ISO-8859-2");
+
+    @Test
+    public void testEncoding() throws Exception {
+        Configuration cfg = createCommonEncodingTesterConfig();
+        
+        {
+            Template t = cfg.getTemplate("utf8.ftl");
+            assertEquals(StandardCharsets.UTF_8, t.getActualSourceEncoding());
+            assertEquals(TEXT_WITH_ACCENTS, getTemplateOutput(t));
+        }
+        {
+            Template t = cfg.getTemplate("utf16.ftl");
+            assertEquals(StandardCharsets.UTF_16LE, t.getActualSourceEncoding());
+            assertEquals(TEXT_WITH_ACCENTS, getTemplateOutput(t));
+        }
+        {
+            Template t = cfg.getTemplate("default.ftl");
+            assertEquals(StandardCharsets.ISO_8859_1, t.getActualSourceEncoding());
+            assertEquals(TEXT_WITH_ACCENTS, getTemplateOutput(t));
+        }
+        {
+            Template t = cfg.getTemplate("utf8-latin2.ftl");
+            assertEquals(ISO_8859_2, t.getActualSourceEncoding());
+            assertEquals(TEXT_WITH_ACCENTS, getTemplateOutput(t));
+        }
+        {
+            Template t = cfg.getTemplate("default-latin2.ftl");
+            assertEquals(ISO_8859_2, t.getActualSourceEncoding());
+            assertEquals(TEXT_WITH_ACCENTS, getTemplateOutput(t));
+        }
+    }
+    
+    @Test
+    public void testIncludeAndEncoding() throws Exception {
+        Configuration cfg = createCommonEncodingTesterConfig();
+        ByteArrayTemplateLoader tl = (ByteArrayTemplateLoader) cfg.getTemplateLoader();
+        tl.putTemplate("main.ftl", (
+                        "<#include 'utf8.ftl'>"
+                        + "<#include 'utf16.ftl'>"
+                        + "<#include 'default.ftl'>"
+                        + "<#include 'utf8-latin2.ftl'>"
+                ).getBytes(StandardCharsets.ISO_8859_1));
+        assertEquals(
+                TEXT_WITH_ACCENTS + TEXT_WITH_ACCENTS + TEXT_WITH_ACCENTS + TEXT_WITH_ACCENTS,
+                getTemplateOutput(cfg.getTemplate("main.ftl")));
+    }
+
+    @Test
+    public void testLocale() throws Exception {
+        StringTemplateLoader loader = new StringTemplateLoader();
+        loader.putTemplate("(de).ftl", "${.locale}");
+        loader.putTemplate("default.ftl", "${.locale}");
+        loader.putTemplate("(de)-fr.ftl",
+                ("<#ftl locale='fr_FR'>${.locale}"));
+        loader.putTemplate("default-fr.ftl",
+                ("<#ftl locale='fr_FR'>${.locale}"));
+
+        Configuration cfg = new TestConfigurationBuilder()
+                .templateLoader(loader)
+                .templateConfigurations(
+                        new ConditionalTemplateConfigurationFactory(
+                                new FileNameGlobMatcher("*(de)*"),
+                                new TemplateConfiguration.Builder()
+                                        .locale(Locale.GERMANY)
+                                        .build()))
+                .build();
+
+        {
+            Template t = cfg.getTemplate("(de).ftl");
+            assertEquals(Locale.GERMANY, t.getLocale());
+            assertEquals("de_DE", getTemplateOutput(t));
+        }
+        {
+            Template t = cfg.getTemplate("(de).ftl", Locale.ITALY);
+            assertEquals(Locale.GERMANY, t.getLocale());
+            assertEquals("de_DE", getTemplateOutput(t));
+        }
+        {
+            Template t = cfg.getTemplate("default.ftl");
+            assertEquals(Locale.US, t.getLocale());
+            assertEquals("en_US", getTemplateOutput(t));
+        }
+        {
+            Template t = cfg.getTemplate("default.ftl", Locale.ITALY);
+            assertEquals(Locale.ITALY, t.getLocale());
+            assertEquals("it_IT", getTemplateOutput(t));
+        }
+    }
+
+    @Test
+    public void testConfigurableSettings() throws Exception {
+        String commonFTL = "${.locale} ${true?string} ${1.2}";
+        StringTemplateLoader loader = new StringTemplateLoader();
+        loader.putTemplate("default", commonFTL);
+        loader.putTemplate("(fr)", commonFTL);
+        loader.putTemplate("(yn)(00)", commonFTL);
+        loader.putTemplate("(00)(fr)", commonFTL);
+
+        Configuration cfg = new TestConfigurationBuilder()
+                .templateConfigurations(
+                        new MergingTemplateConfigurationFactory(
+                                new ConditionalTemplateConfigurationFactory(
+                                        new FileNameGlobMatcher("*(fr)*"),
+                                        new TemplateConfiguration.Builder().locale(Locale.FRANCE).build()),
+                                new ConditionalTemplateConfigurationFactory(
+                                        new FileNameGlobMatcher("*(yn)*"),
+                                        new TemplateConfiguration.Builder().booleanFormat("Y,N").build()),
+                                new ConditionalTemplateConfigurationFactory(
+                                        new FileNameGlobMatcher("*(00)*"),
+                                        new TemplateConfiguration.Builder().numberFormat("0.00").build())))
+                .templateLoader(loader)
+                .build();
+
+        assertEquals("en_US true 1.2", getTemplateOutput(cfg.getTemplate("default")));
+        assertEquals("fr_FR true 1,2", getTemplateOutput(cfg.getTemplate("(fr)")));
+        assertEquals("en_US Y 1.20", getTemplateOutput(cfg.getTemplate("(yn)(00)")));
+        assertEquals("fr_FR true 1,20", getTemplateOutput(cfg.getTemplate("(00)(fr)")));
+    }
+    
+    @Test
+    public void testCustomAttributes() throws Exception {
+        String commonFTL = "<#ftl attributes={ 'a3': 'a3temp' }>";
+        StringTemplateLoader tl = new StringTemplateLoader();
+        tl.putTemplate("(tc1)", commonFTL);
+        tl.putTemplate("(tc1)noHeader", "");
+        tl.putTemplate("(tc2)", commonFTL);
+        tl.putTemplate("(tc1)(tc2)", commonFTL);
+
+        Configuration cfg = new TestConfigurationBuilder()
+                .templateConfigurations(
+                        new MergingTemplateConfigurationFactory(
+                                new ConditionalTemplateConfigurationFactory(
+                                        new FileNameGlobMatcher("*(tc1)*"),
+                                        new TemplateConfiguration.Builder()
+                                                .customAttribute("a1", "a1tc1")
+                                                .customAttribute("a2", "a2tc1")
+                                                .customAttribute("a3", "a3tc1")
+                                                .customAttribute(CUST_ATT_1, "ca1tc1")
+                                                .customAttribute(CUST_ATT_2, "ca2tc1")
+                                                .build()),
+                                new ConditionalTemplateConfigurationFactory(
+                                        new FileNameGlobMatcher("*(tc2)*"),
+                                        new TemplateConfiguration.Builder()
+                                                .customAttribute("a1", "a1tc2")
+                                                .customAttribute(CUST_ATT_1, "ca1tc2")
+                                                .build())))
+                .templateLoader(tl)
+                .build();
+
+        {
+            Template t = cfg.getTemplate("(tc1)");
+            assertEquals("a1tc1", t.getCustomAttribute("a1"));
+            assertEquals("a2tc1", t.getCustomAttribute("a2"));
+            assertEquals("a3temp", t.getCustomAttribute("a3"));
+            assertEquals("ca1tc1", t.getCustomAttribute(CUST_ATT_1));
+            assertEquals("ca2tc1", t.getCustomAttribute(CUST_ATT_2));
+        }
+        {
+            Template t = cfg.getTemplate("(tc1)noHeader");
+            assertEquals("a1tc1", t.getCustomAttribute("a1"));
+            assertEquals("a2tc1", t.getCustomAttribute("a2"));
+            assertEquals("a3tc1", t.getCustomAttribute("a3"));
+            assertEquals("ca1tc1", t.getCustomAttribute(CUST_ATT_1));
+            assertEquals("ca2tc1", t.getCustomAttribute(CUST_ATT_2));
+        }
+        {
+            Template t = cfg.getTemplate("(tc2)");
+            assertEquals("a1tc2", t.getCustomAttribute("a1"));
+            assertNull(t.getCustomAttribute("a2"));
+            assertEquals("a3temp", t.getCustomAttribute("a3"));
+            assertEquals("ca1tc2", t.getCustomAttribute(CUST_ATT_1));
+            assertNull(t.getCustomAttribute(CUST_ATT_2));
+        }
+        {
+            Template t = cfg.getTemplate("(tc1)(tc2)");
+            assertEquals("a1tc2", t.getCustomAttribute("a1"));
+            assertEquals("a2tc1", t.getCustomAttribute("a2"));
+            assertEquals("a3temp", t.getCustomAttribute("a3"));
+            assertEquals("ca1tc2", t.getCustomAttribute(CUST_ATT_1));
+            assertEquals("ca2tc1", t.getCustomAttribute(CUST_ATT_2));
+        }
+    }
+    
+    private String getTemplateOutput(Template t) throws TemplateException, IOException {
+        StringWriter sw = new StringWriter();
+        t.process(null, sw);
+        return sw.toString();
+    }
+
+    private Configuration createCommonEncodingTesterConfig() throws UnsupportedEncodingException {
+        ByteArrayTemplateLoader tl = new ByteArrayTemplateLoader();
+        tl.putTemplate("utf8.ftl", TEXT_WITH_ACCENTS.getBytes(StandardCharsets.UTF_8));
+        tl.putTemplate("utf16.ftl", TEXT_WITH_ACCENTS.getBytes(StandardCharsets.UTF_16LE));
+        tl.putTemplate("default.ftl", TEXT_WITH_ACCENTS.getBytes(ISO_8859_2));
+        tl.putTemplate("utf8-latin2.ftl",
+                ("<#ftl encoding='iso-8859-2'>" + TEXT_WITH_ACCENTS).getBytes(ISO_8859_2));
+        tl.putTemplate("default-latin2.ftl",
+                ("<#ftl encoding='iso-8859-2'>" + TEXT_WITH_ACCENTS).getBytes(ISO_8859_2));
+
+        return new TestConfigurationBuilder()
+                .sourceEncoding(StandardCharsets.ISO_8859_1)
+                .locale(Locale.US)
+                .templateLoader(tl)
+                .templateConfigurations(
+                        new FirstMatchTemplateConfigurationFactory(
+                                new ConditionalTemplateConfigurationFactory(
+                                        new FileNameGlobMatcher("*utf8*"),
+                                        new TemplateConfiguration.Builder()
+                                                .sourceEncoding(StandardCharsets.UTF_8)
+                                                .build()),
+                                new ConditionalTemplateConfigurationFactory(
+                                        new FileNameGlobMatcher("*utf16*"),
+                                        new TemplateConfiguration.Builder()
+                                                .sourceEncoding(StandardCharsets.UTF_16LE)
+                                                .build())
+                        )
+                        .allowNoMatch(true))
+                .build();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateConstructorsTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateConstructorsTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateConstructorsTest.java
new file mode 100644
index 0000000..97c43ad
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateConstructorsTest.java
@@ -0,0 +1,113 @@
+/*
+ * 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.Reader;
+import java.io.StringReader;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.freemarker.test.TestConfigurationBuilder;
+import org.junit.Test;
+public class TemplateConstructorsTest {
+
+    private static final String CONTENT = "From a reader...";
+    private static final String CONTENT_FORCE_UTF8 = "<#ftl encoding='utf-8'>From a reader...";
+    
+    @Test
+    public void test() throws IOException {
+        final Configuration cfg = new TestConfigurationBuilder().sourceEncoding(StandardCharsets.ISO_8859_1).build();
+        
+        final String name = "foo/bar.ftl";
+        final String sourceName = "foo/bar_de.ftl";
+        final Charset sourceEncoding = StandardCharsets.UTF_16LE;
+        {
+            Template t = new Template(name, createReader(), cfg);
+            assertEquals(name, t.getLookupName());
+            assertNull(t.getSourceName());
+            assertEquals(CONTENT, t.toString());
+            assertNull(t.getActualSourceEncoding());
+        }
+        {
+            Template t = new Template(name, CONTENT, cfg);
+            assertEquals(name, t.getLookupName());
+            assertNull(t.getSourceName());
+            assertEquals(CONTENT, t.toString());
+            assertNull(t.getActualSourceEncoding());
+        }
+        {
+            Template t = new Template(name, CONTENT_FORCE_UTF8, cfg);
+            assertEquals(name, t.getLookupName());
+            assertNull(t.getSourceName());
+            // assertEquals(CONTENT_FORCE_UTF8, t.toString()); // FIXME the #ftl header is missing from the dump, why?
+            assertNull(t.getActualSourceEncoding()); // Because it was created from a String
+        }
+        {
+            Template t = new Template(name, createReader(), cfg, sourceEncoding);
+            assertEquals(name, t.getLookupName());
+            assertNull(t.getSourceName());
+            assertEquals(CONTENT, t.toString());
+            assertEquals(StandardCharsets.UTF_16LE, t.getActualSourceEncoding());
+        }
+        {
+            Template t = new Template(name, sourceName, createReader(), cfg);
+            assertEquals(name, t.getLookupName());
+            assertEquals(sourceName, t.getSourceName());
+            assertEquals(CONTENT, t.toString());
+            assertNull(t.getActualSourceEncoding());
+        }
+        {
+            Template t = new Template(name, sourceName, createReader(), cfg, sourceEncoding);
+            assertEquals(name, t.getLookupName());
+            assertEquals(sourceName, t.getSourceName());
+            assertEquals(CONTENT, t.toString());
+            assertEquals(StandardCharsets.UTF_16LE, t.getActualSourceEncoding());
+        }
+        {
+            Template t = Template.createPlainTextTemplate(name, CONTENT, cfg);
+            assertEquals(name, t.getLookupName());
+            assertNull(t.getSourceName());
+            assertEquals(CONTENT, t.toString());
+            assertNull(t.getActualSourceEncoding());
+        }
+        {
+            try {
+                new Template(name, sourceName, createReaderForceUTF8(), cfg, sourceEncoding);
+                fail();
+            } catch (WrongTemplateCharsetException e) {
+                assertThat(e.getMessage(), containsString(StandardCharsets.UTF_8.name()));
+                assertThat(e.getMessage(), containsString(sourceEncoding.name()));
+            }
+        }
+    }
+    
+    private Reader createReader() {
+        return new StringReader(CONTENT);
+    }
+
+    private Reader createReaderForceUTF8() {
+        return new StringReader(CONTENT_FORCE_UTF8);
+    }
+    
+}


[33/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/HashAndScalarModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/HashAndScalarModel.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/HashAndScalarModel.java
new file mode 100644
index 0000000..70ea42a
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/HashAndScalarModel.java
@@ -0,0 +1,84 @@
+/*
+ * 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.test.templatesuite.models;
+
+import org.apache.freemarker.core.model.TemplateCollectionModel;
+import org.apache.freemarker.core.model.TemplateHashModelEx;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateModelIterator;
+import org.apache.freemarker.core.model.TemplateScalarModel;
+import org.apache.freemarker.core.model.impl.SimpleScalar;
+
+public class HashAndScalarModel implements TemplateHashModelEx, TemplateScalarModel {
+    
+    public static final HashAndScalarModel INSTANCE = new HashAndScalarModel();
+    
+    private final TemplateCollectionModel EMPTY_COLLECTION = new TemplateCollectionModel() {
+
+        @Override
+        public TemplateModelIterator iterator() throws TemplateModelException {
+            return new TemplateModelIterator() {
+
+                @Override
+                public TemplateModel next() throws TemplateModelException {
+                    return null;
+                }
+
+                @Override
+                public boolean hasNext() throws TemplateModelException {
+                    return false;
+                }
+                
+            };
+        }
+    };
+
+    @Override
+    public String getAsString() throws TemplateModelException {
+        return "scalarValue";
+    }
+
+    @Override
+    public TemplateModel get(String key) throws TemplateModelException {
+        return new SimpleScalar("mapValue for " + key);
+    }
+
+    @Override
+    public boolean isEmpty() throws TemplateModelException {
+        return true;
+    }
+
+    @Override
+    public int size() throws TemplateModelException {
+        return 0;
+    }
+
+    @Override
+    public TemplateCollectionModel keys() throws TemplateModelException {
+        return EMPTY_COLLECTION;
+    }
+
+    @Override
+    public TemplateCollectionModel values() throws TemplateModelException {
+        return EMPTY_COLLECTION;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/JavaObjectInfo.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/JavaObjectInfo.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/JavaObjectInfo.java
new file mode 100644
index 0000000..4673b09
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/JavaObjectInfo.java
@@ -0,0 +1,35 @@
+/*
+ * 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.test.templatesuite.models;
+
+import org.apache.freemarker.core.util._StringUtil;
+
+public class JavaObjectInfo {
+    
+    public static final Object INSTANCE = new JavaObjectInfo();
+
+    private JavaObjectInfo() { }
+    
+    public String info(Object o) {
+        if (o == null) return "null";
+        return o.getClass().getName() + " " + _StringUtil.jQuote(o.toString());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/Listables.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/Listables.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/Listables.java
new file mode 100644
index 0000000..c2d7c90
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/Listables.java
@@ -0,0 +1,185 @@
+/*
+ * 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.test.templatesuite.models;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.model.ObjectWrapper;
+import org.apache.freemarker.core.model.TemplateCollectionModel;
+import org.apache.freemarker.core.model.TemplateHashModelEx;
+import org.apache.freemarker.core.model.TemplateHashModelEx2;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.WrappingTemplateModel;
+import org.apache.freemarker.core.model.impl.DefaultMapAdapter;
+import org.apache.freemarker.core.model.impl.DefaultObjectWrapper;
+import org.apache.freemarker.core.model.impl.SimpleCollection;
+import org.apache.freemarker.core.model.impl.SimpleHash;
+
+import com.google.common.collect.ImmutableMap;
+
+@SuppressWarnings("boxing")
+public class Listables {
+    
+    private static final List<Integer> LIST;
+    static {
+        List<Integer> list = new ArrayList<>();
+        list.add(11);
+        list.add(22);
+        list.add(33);
+        LIST = list;
+    }
+
+    private static final List<Integer> LINKED_LIST;
+    static {
+        List<Integer> list = new LinkedList<>();
+        list.add(11);
+        list.add(22);
+        list.add(33);
+        LINKED_LIST = list;
+    }
+
+    private static final List<Integer> EMPTY_LINKED_LIST = new LinkedList<>();
+
+    private static final Set<Integer> SET;
+    static {
+        Set<Integer> set = new TreeSet<>();
+        set.add(11);
+        set.add(22);
+        set.add(33);
+        SET = set;
+    }
+    
+    public List<Integer> getList() {
+        return LIST;
+    }
+    
+    public List<Integer> getLinkedList() {
+        return LINKED_LIST;
+    }
+    
+    public Set<Integer> getSet() {
+        return SET;
+    }
+
+    public Iterator<Integer> getIterator() {
+        return SET.iterator();
+    }
+
+    public List<Integer> getEmptyList() {
+        return Collections.emptyList();
+    }
+    
+    public List<Integer> getEmptyLinkedList() {
+        return Collections.emptyList();
+    }
+    
+    public Set<Integer> getEmptySet() {
+        return Collections.emptySet();
+    }
+
+    public Iterator<Integer> getEmptyIterator() {
+        return Collections.<Integer>emptySet().iterator();
+    }
+    
+    public List<TemplateHashModelEx2> getHashEx2s() throws TemplateModelException {
+        Map<Object, Object> map;
+        map = new LinkedHashMap<>();
+        map.put("k1", "v1");
+        map.put(2, "v2");
+        map.put("k3", "v3");
+        map.put(null, "v4");
+        map.put(true, "v5");
+        map.put(false, null);
+        
+        return getMapsWrappedAsEx2(map);
+    }
+
+    public List<? extends TemplateHashModelEx> getEmptyHashes() throws TemplateModelException {
+        List<TemplateHashModelEx> emptyMaps = new ArrayList<>();
+        emptyMaps.addAll(getMapsWrappedAsEx2(Collections.emptyMap()));
+        emptyMaps.add((TemplateHashModelEx) new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build()
+                .wrap(Collections.emptyMap()));
+        return emptyMaps;
+    }
+    
+    /**
+     * Returns the map wrapped on various ways.
+     */
+    private List<TemplateHashModelEx2> getMapsWrappedAsEx2(Map<?, ?> map) throws TemplateModelException {
+        List<TemplateHashModelEx2> maps = new ArrayList<>();
+        
+        DefaultObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
+        maps.add(new SimpleHash(map, ow));
+        maps.add((DefaultMapAdapter) ow.wrap(map));
+
+        return maps;
+    }
+    
+    public TemplateHashModelEx getHashNonEx2() {
+        return new NonEx2MapAdapter(ImmutableMap.of("k1", 11, "k2", 22),
+                new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build());
+    }
+    
+    public static class NonEx2MapAdapter extends WrappingTemplateModel implements TemplateHashModelEx {
+
+        private final Map<?, ?> map;
+        
+        public NonEx2MapAdapter(Map<?, ?> map, ObjectWrapper wrapper) {
+            super(wrapper);
+            this.map = map;
+        }
+        
+        @Override
+        public TemplateModel get(String key) throws TemplateModelException {
+            return wrap(map.get(key));
+        }
+        
+        @Override
+        public boolean isEmpty() {
+            return map.isEmpty();
+        }
+        
+        @Override
+        public int size() {
+            return map.size();
+        }
+        
+        @Override
+        public TemplateCollectionModel keys() {
+            return new SimpleCollection(map.keySet(), getObjectWrapper());
+        }
+        
+        @Override
+        public TemplateCollectionModel values() {
+            return new SimpleCollection(map.values(), getObjectWrapper());
+        }
+        
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel1.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel1.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel1.java
new file mode 100644
index 0000000..66a0ffe
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel1.java
@@ -0,0 +1,116 @@
+/*
+ * 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.test.templatesuite.models;
+
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.model.ObjectWrapper;
+import org.apache.freemarker.core.model.TemplateHashModel;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateScalarModel;
+import org.apache.freemarker.core.model.TemplateSequenceModel;
+import org.apache.freemarker.core.model.impl.DefaultObjectWrapper;
+import org.apache.freemarker.core.model.impl.SimpleHash;
+import org.apache.freemarker.core.model.impl.SimpleScalar;
+import org.apache.freemarker.core.model.impl.SimpleSequence;
+
+/**
+ * Testcase to see how FreeMarker deals with multiple Template models.
+ */
+public class MultiModel1 implements TemplateHashModel,
+        TemplateSequenceModel, TemplateScalarModel {
+
+    private ObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
+
+    private TemplateModel m_cSubModel = new MultiModel2();
+    private TemplateModel m_cListHashModel1 = new MultiModel4(ow);
+    private TemplateModel m_cListHashModel2 = new MultiModel5(ow);
+    private TemplateSequenceModel m_cListModel = new SimpleSequence(ow);
+    private TemplateHashModel m_cHashModel = new SimpleHash(ow);
+
+    /** Creates new MultiModel1 */
+    public MultiModel1() {
+        for ( int i = 0; i < 10; i++ ) {
+            ((SimpleSequence) m_cListModel).add( "Model1 value: " + Integer.toString( i ));
+        }
+        ((SimpleSequence) m_cListModel).add( new MultiModel3() );
+        ((SimpleHash) m_cHashModel).put( "nested", new MultiModel3() );
+    }
+
+    /**
+     * Gets a <tt>TemplateModel</tt> from the hash.
+     *
+     * @param key the name by which the <tt>TemplateModel</tt>
+     * is identified in the template.
+     * @return the <tt>TemplateModel</tt> referred to by the key,
+     * or null if not found.
+     */
+    @Override
+    public TemplateModel get(String key) {
+        if ( key.equals( "model2" )) {
+            return m_cSubModel;
+        } else if ( key.equals( "modellist" )) {
+            return m_cListModel;
+        } else if ( key.equals( "selftest" )) {
+            return new SimpleScalar( "Selftest of a hash from MultiModel1" );
+        } else if ( key.equals( "one" )) {
+            return m_cListHashModel1;
+        } else if ( key.equals( "two" )) {
+            return m_cListHashModel2;
+        } else if ( key.equals( "size" )) {
+            return new SimpleScalar( "Nasty!" );
+        } else if ( key.equals( "nesting1" )) {
+            return m_cHashModel;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * @return true if this object is empty.
+     */
+    @Override
+    public boolean isEmpty() {
+        return false;
+    }
+
+    /**
+     * @return the specified index in the list
+     */
+    @Override
+    public TemplateModel get(int i) throws TemplateModelException {
+        return m_cListModel.get( i );
+    }
+
+    /**
+     * Returns the scalar's value as a String.
+     *
+     * @return the String value of this scalar.
+     */
+    @Override
+    public String getAsString() {
+        return "MultiModel1 as a string!";
+    }
+
+    @Override
+    public int size() throws TemplateModelException {
+        return m_cListModel.size();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel2.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel2.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel2.java
new file mode 100644
index 0000000..a7a75b5
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel2.java
@@ -0,0 +1,63 @@
+/*
+ * 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.test.templatesuite.models;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.freemarker.core.model.TemplateMethodModel;
+import org.apache.freemarker.core.model.TemplateScalarModel;
+import org.apache.freemarker.core.model.impl.SimpleScalar;
+
+/**
+ * Testcase to see how FreeMarker deals with multiple Template models.
+ */
+public class MultiModel2 implements TemplateScalarModel, TemplateMethodModel {
+
+    /**
+     * Returns the scalar's value as a String.
+     *
+     * @return the String value of this scalar.
+     */
+    @Override
+    public String getAsString() {
+        return "Model2 is alive!";
+    }
+
+    /**
+     * Executes a method call.
+     *
+     * @param arguments a <tt>List</tt> of <tt>String</tt> objects containing the values
+     * of the arguments passed to the method.
+     * @return the <tt>TemplateModel</tt> produced by the method, or null.
+     */
+    @Override
+    public Object exec(List arguments) {
+        StringBuilder  aResults = new StringBuilder( "Arguments are:<br />" );
+        Iterator    iList = arguments.iterator();
+
+        while ( iList.hasNext() ) {
+            aResults.append( (String) iList.next() );
+            aResults.append( "<br />" );
+        }
+
+        return new SimpleScalar( aResults.toString() );
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel3.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel3.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel3.java
new file mode 100644
index 0000000..4434afc
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel3.java
@@ -0,0 +1,69 @@
+/*
+ * 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.test.templatesuite.models;
+
+import org.apache.freemarker.core.model.TemplateHashModel;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateScalarModel;
+import org.apache.freemarker.core.model.impl.SimpleScalar;
+
+/**
+ * Testcase to see how FreeMarker deals with multiple Template models.
+ */
+public class MultiModel3 implements TemplateScalarModel, TemplateHashModel {
+
+    /**
+     * Returns the scalar's value as a String.
+     *
+     * @return the String value of this scalar.
+     */
+    @Override
+    public String getAsString() {
+        return "Model3 is alive!";
+    }
+
+    /**
+     * @return true if this object is empty.
+     */
+    @Override
+    public boolean isEmpty() {
+        return false;
+    }
+
+    /**
+     * Gets a <tt>TemplateModel</tt> from the hash.
+     *
+     * @param key the name by which the <tt>TemplateModel</tt>
+     * is identified in the template.
+     * @return the <tt>TemplateModel</tt> referred to by the key,
+     * or null if not found.
+     */
+    @Override
+    public TemplateModel get(String key) {
+        if ( key.equals( "selftest" )) {
+            return new SimpleScalar( "Selftest from MultiModel3!" );
+        } else if ( key.equals( "message" )) {
+            return new SimpleScalar( "Hello world from MultiModel3!" );
+        } else {
+            return null;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel4.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel4.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel4.java
new file mode 100644
index 0000000..bdd11fc
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel4.java
@@ -0,0 +1,77 @@
+/*
+ * 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.test.templatesuite.models;
+
+import org.apache.freemarker.core.model.ObjectWrapper;
+import org.apache.freemarker.core.model.TemplateHashModel;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateSequenceModel;
+import org.apache.freemarker.core.model.impl.SimpleScalar;
+import org.apache.freemarker.core.model.impl.SimpleSequence;
+
+/**
+ * Testcase to see how FreeMarker deals with multiple Template models.
+ */
+public class MultiModel4 implements TemplateSequenceModel, TemplateHashModel {
+
+    private final SimpleSequence m_cList;
+
+    public MultiModel4(ObjectWrapper ow) {
+        this.m_cList = new SimpleSequence(ow);
+    }
+
+    /**
+     * @return the specified index in the list
+     */
+    @Override
+    public TemplateModel get(int i) throws TemplateModelException {
+        return m_cList.get( i );
+    }
+
+    /**
+     * Gets a <tt>TemplateModel</tt> from the hash.
+     *
+     * @param key the name by which the <tt>TemplateModel</tt>
+     * is identified in the template.
+     * @return the <tt>TemplateModel</tt> referred to by the key,
+     * or null if not found.
+     */
+    @Override
+    public TemplateModel get(String key) {
+        if ( key.equals( "size" )) {
+            return new SimpleScalar( "Key size, not the listSize method." );
+        } else {
+            return null;
+        }
+    }
+
+
+    @Override
+    public int size() {
+        return m_cList.size();
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return size() == 0;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel5.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel5.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel5.java
new file mode 100644
index 0000000..01f7a3e
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/MultiModel5.java
@@ -0,0 +1,81 @@
+/*
+ * 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.test.templatesuite.models;
+
+import org.apache.freemarker.core.model.ObjectWrapper;
+import org.apache.freemarker.core.model.TemplateHashModel;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateSequenceModel;
+import org.apache.freemarker.core.model.impl.SimpleScalar;
+import org.apache.freemarker.core.model.impl.SimpleSequence;
+
+/**
+ * Testcase to see how FreeMarker deals with multiple Template models.
+ */
+public class MultiModel5 implements TemplateSequenceModel, TemplateHashModel {
+
+    private final SimpleSequence m_cList;
+
+    /** Creates new MultiModel5 */
+    public MultiModel5(ObjectWrapper ow) {
+        this.m_cList = new SimpleSequence(ow);
+        m_cList.add( new SimpleScalar( "Dummy to make list non-empty" ));
+    }
+
+    /**
+     * @return the specified index in the list
+     */
+    @Override
+    public TemplateModel get(int i) throws TemplateModelException {
+        return m_cList.get( i );
+    }
+
+    /**
+     * @return true if this object is empty.
+     */
+    @Override
+    public boolean isEmpty() {
+        return false;
+    }
+
+    @Override
+    public int size() {
+        return m_cList.size();
+    }
+
+    /**
+     * Gets a <tt>TemplateModel</tt> from the hash.
+     *
+     * @param key the name by which the <tt>TemplateModel</tt>
+     * is identified in the template.
+     * @return the <tt>TemplateModel</tt> referred to by the key,
+     * or null if not found.
+     */
+    @Override
+    public TemplateModel get(String key) {
+        if ( key.equals( "empty" )) {
+            return new SimpleScalar( "Dummy hash value, for test purposes." );
+        } else {
+            return null;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/NewTestModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/NewTestModel.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/NewTestModel.java
new file mode 100644
index 0000000..9f51458
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/NewTestModel.java
@@ -0,0 +1,52 @@
+/*
+ * 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.test.templatesuite.models;
+
+import org.apache.freemarker.core.model.TemplateScalarModel;
+
+/**
+ * Testcase to see how FreeMarker's ?new built-in deals with constructors.
+ */
+public class NewTestModel
+implements
+    TemplateScalarModel {
+    private final String string;
+    
+    public NewTestModel() {
+        string = "default constructor";
+    }
+
+    public NewTestModel(String str) {
+        string = str;
+    }
+
+    public NewTestModel(long i) {
+        string = Long.toString(i);
+    }
+
+    public NewTestModel(Object o1, java.io.Serializable o2) {
+        string = o1 + ":" + o2;
+    }
+
+    @Override
+    public String getAsString() {
+        return string;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/NewTestModel2.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/NewTestModel2.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/NewTestModel2.java
new file mode 100644
index 0000000..420b4fa
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/NewTestModel2.java
@@ -0,0 +1,52 @@
+/*
+ * 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.test.templatesuite.models;
+
+import org.apache.freemarker.core.model.TemplateScalarModel;
+
+/**
+ * Testcase to see how FreeMarker's ?new built-in deals with constructors.
+ */
+public class NewTestModel2
+implements
+    TemplateScalarModel {
+    private final String string;
+    
+    public NewTestModel2() {
+        string = "default constructor";
+    }
+
+    public NewTestModel2(String str) {
+        string = str;
+    }
+
+    public NewTestModel2(long i) {
+        string = Long.toString(i);
+    }
+
+    public NewTestModel2(Object o1, java.io.Serializable o2) {
+        string = o1 + ":" + o2;
+    }
+
+    @Override
+    public String getAsString() {
+        return string;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/NumberAndStringModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/NumberAndStringModel.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/NumberAndStringModel.java
new file mode 100644
index 0000000..5c8e7db
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/NumberAndStringModel.java
@@ -0,0 +1,47 @@
+/*
+ * 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.test.templatesuite.models;
+
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateNumberModel;
+import org.apache.freemarker.core.model.TemplateScalarModel;
+
+public class NumberAndStringModel implements TemplateNumberModel,
+		TemplateScalarModel {
+	
+	private final String s;
+	
+	public NumberAndStringModel(String s) {
+		super();
+		this.s = s;
+	}
+
+	@Override
+    public String getAsString() throws TemplateModelException {
+		return s;
+	}
+
+	@Override
+    @SuppressWarnings("boxing")
+    public Number getAsNumber() throws TemplateModelException {
+		return s.length();
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/OverloadedConstructor.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/OverloadedConstructor.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/OverloadedConstructor.java
new file mode 100644
index 0000000..6e09053
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/OverloadedConstructor.java
@@ -0,0 +1,46 @@
+/*
+ * 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.test.templatesuite.models;
+
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateScalarModel;
+
+public class OverloadedConstructor implements TemplateScalarModel {
+    
+    String value;
+    
+    public OverloadedConstructor(int i) {
+        value = "int " + i;
+    }
+    
+    public OverloadedConstructor(String s) {
+        value = "String " + s;
+    }
+
+    public OverloadedConstructor(CharSequence s) {
+        value = "CharSequence " + s;
+    }
+    
+    @Override
+    public String getAsString() throws TemplateModelException {
+        return value;
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/OverloadedMethods.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/OverloadedMethods.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/OverloadedMethods.java
new file mode 100644
index 0000000..ebd505a
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/OverloadedMethods.java
@@ -0,0 +1,191 @@
+/*
+ * 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.test.templatesuite.models;
+
+import java.math.BigDecimal;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.freemarker.core.util.FTLUtil;
+
+/**
+ * For testing overloaded method selection.
+ */
+public class OverloadedMethods {
+
+	public String oneArg(Object a1) {
+		return methodCallToStr("oneArg<Object>", a1);
+	}
+
+	public String oneArg(String a1) {
+		return methodCallToStr("oneArg<String>", a1);
+	}
+
+	public String oneArg(Boolean a1) {
+		return methodCallToStr("oneArg<Boolean>", a1);
+	}
+
+	public String oneArg(boolean a1) {
+		return methodCallToStr("oneArg<boolean>", Boolean.valueOf(a1));
+	}
+	
+	public String oneArg(List a1) {
+		return methodCallToStr("oneArg<List>", a1);
+	}
+
+	public String oneArg(Map a1) {
+		return methodCallToStr("oneArg<Map>", a1);
+	}
+
+    public String oneArg2(Map a1) {
+        return methodCallToStr("oneArg2<Map>", a1);
+    }
+
+    public String oneArg2(List a1) {
+        return methodCallToStr("oneArg2<List>", a1);
+    }
+    
+    public String oneArg3(List a1, List a2) {
+        return methodCallToStr("oneArg3<List, List>", a1, a2);
+    }
+
+    public String oneArg3(List a1) {
+        return methodCallToStr("oneArg3<List>", a1);
+    }
+    
+    public String oneArg4(Integer a1) {
+        return methodCallToStr("oneArg4<Integer>", a1);
+    }
+
+    public String oneArg4(int a1) {
+        return methodCallToStr("oneArg4<int>", Integer.valueOf(a1));
+    }
+
+    public String notOverloaded(List a1) {
+        return methodCallToStr("notOverloaded<List>", a1);
+    }
+    
+	public String varargsIssue1(Map a1, List a2) {
+	    return methodCallToStr("varargsIssue1<Map, List>", a1, a2);
+	}
+
+    public String varargsIssue1(Object... a1) {
+        return methodCallToStr("varargsIssue1<Object...>", a1);
+    }
+
+    public String varargsIssue2(String a1, List a2) {
+        return methodCallToStr("varargsIssue2<String, List>", a1, a2);
+    }
+
+    public String varargsIssue2(String a1, Map a2) {
+        return methodCallToStr("varargsIssue2<String, Map>", a1, a2);
+    }
+
+    public String varargsIssue2(Object... a1) {
+        return methodCallToStr("varargsIssue2<Object...>", a1);
+    }
+    
+    public String numberIssue1(int a1) {
+        return methodCallToStr("numberIssue1<int>", a1);
+    }
+    
+    public String numberIssue1(float a1) {
+        return methodCallToStr("numberIssue1<float>", a1);
+    }
+    
+    public String numberIssue2(int a1) {
+        return methodCallToStr("numberIssue2<int>", a1);
+    }
+    
+    public String numberIssue2(BigDecimal a1) {
+        return methodCallToStr("numberIssue2<BigDecimal>", a1);
+    }
+
+    public String numberIssue3(int a1) {
+        return methodCallToStr("numberIssue3<int>", a1);
+    }
+    
+    public String numberIssue3(double a1) {
+        return methodCallToStr("numberIssue3<double>", a1);
+    }
+    
+	private String methodCallToStr(String methodName, Object... args) {
+		StringBuilder sb = new StringBuilder();
+		
+		sb.append(methodName);
+		sb.append('(');
+		boolean hadItems = false;
+		for (Object arg : args) {
+			if (hadItems) sb.append(", ");
+			sb.append(valueToStr(arg));
+			hadItems = true;
+		}
+		sb.append(')');
+		
+		return sb.toString();
+	}
+	
+	private String valueToStr(Object value) {
+		if (value == null) {
+		    return "null";
+		} else if (value instanceof Character) {
+			return "'" + FTLUtil.escapeStringLiteralPart(value.toString()) + "'";
+		} else if (value instanceof String) {
+			return "\"" + FTLUtil.escapeStringLiteralPart((String) value) + "\"";
+		} else if (value instanceof Map) {
+			StringBuilder sb = new StringBuilder(); 
+			sb.append("{");
+			boolean hadItems = false;
+			for (Map.Entry<?, ?> ent : ((Map<?, ?>) value).entrySet()) {
+				if (hadItems) sb.append(", ");
+				sb.append(valueToStr(ent.getKey()));
+				sb.append(": ");
+				sb.append(valueToStr(ent.getValue()));
+				hadItems = true;
+			}
+			sb.append("}");
+			return sb.toString();
+		} else if (value instanceof Collection || value.getClass().isArray()) {
+			StringBuilder sb = new StringBuilder();
+			
+	        if (value.getClass().isArray()) {
+	            value = Arrays.asList(value);
+                sb.append("array");
+	        } else if (value instanceof Set) {
+				sb.append("set");
+			}
+			sb.append("[");
+			boolean hadItems = false;
+			for (Object i : (Collection) value) {
+				if (hadItems) sb.append(", ");
+				sb.append(i);
+				hadItems = true;
+			}
+			sb.append("]");
+			return sb.toString();
+		} else {
+			return value.toString(); 
+		}
+	}
+	
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/OverloadedMethods2.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/OverloadedMethods2.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/OverloadedMethods2.java
new file mode 100644
index 0000000..2c5a5df
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/OverloadedMethods2.java
@@ -0,0 +1,1110 @@
+/*
+ * 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.test.templatesuite.models;
+
+import java.io.File;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.freemarker.core.Environment;
+import org.apache.freemarker.core.model.AdapterTemplateModel;
+import org.apache.freemarker.core.model.ObjectWrapper;
+import org.apache.freemarker.core.model.TemplateBooleanModel;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateNumberModel;
+import org.apache.freemarker.core.model.WrapperTemplateModel;
+import org.apache.freemarker.core.model.impl.RationalNumber;
+import org.apache.freemarker.core.util._StringUtil;
+import org.apache.freemarker.test.TestUtil;
+
+public class OverloadedMethods2 {
+
+    public String mVarargs(String... a1) {
+        StringBuilder sb = new StringBuilder();
+        for (String s : a1) {
+            sb.append(s);
+        }
+        return "mVarargs(String... a1 = " + sb + ")";
+    }
+    
+    public BigInteger bigInteger(BigDecimal n) {
+        return n.toBigInteger();
+    }
+
+    public RationalNumber rational(int a, int b) {
+        return new RationalNumber(a, b);
+    }
+    
+    public String mVarargs(File a1, String... a2) {
+        return "mVarargs(File a1, String... a2)";
+    }
+
+    public NumberAndStringModel getNnS(String s) {
+        return new NumberAndStringModel(s);
+    }
+    
+    public String mNull1(String a1) {
+        return "mNull1(String a1 = " + a1 + ")";
+    }
+
+    public String mNull1(int a1) {
+        return "mNull1(int a1 = " + a1 + ")";
+    }
+    
+    public String mNull2(String a1) {
+        return "mNull2(String a1 = " + a1 + ")";
+    }
+    
+    public String mNull2(Object a1) {
+        return "mNull2(Object a1 = " + a1 + ")";
+    }
+    
+    public String mSpecificity(Object a1, String a2) {
+        return "mSpecificity(Object a1, String a2)";
+    }
+    
+    public String mSpecificity(String a1, Object a2) {
+        return "mSpecificity(String a1, Object a2)";
+    }
+    
+    public String mChar(char a1) {
+        return "mChar(char a1 = " + a1 + ")";
+    }
+    
+    public String mChar(Character a1) {
+        return "mChar(Character a1 = " + a1 + ")";
+    }
+    
+    public String mBoolean(boolean a1) {
+        return "mBoolean(boolean a1 = " + a1 + ")";
+    }
+    
+    public String mBoolean(Boolean a1) {
+        return "mBoolean(Boolean a1 = " + a1 + ")";
+    }
+
+    public int mIntNonOverloaded(int a1) {
+        return a1;
+    }
+
+    public String mIntPrimVSBoxed(int a1) {
+        return "mIntPrimVSBoxed(int a1 = " + a1 + ")";
+    }
+    
+    public String mIntPrimVSBoxed(Integer a1) {
+        return "mIntPrimVSBoxed(Integer a1 = " + a1 + ")";
+    }
+
+    public String mNumPrimVSPrim(short a1) {
+        return "mNumPrimVSPrim(short a1 = " + a1 + ")";
+    }
+    
+    public String mNumPrimVSPrim(long a1) {
+        return "mNumPrimVSPrim(long a1 = " + a1 + ")";
+    }
+
+    public String mNumBoxedVSBoxed(Short a1) {
+        return "mNumBoxedVSBoxed(Short a1 = " + a1 + ")";
+    }
+    
+    public String mNumBoxedVSBoxed(Long a1) {
+        return "mNumBoxedVSBoxed(Long a1 = " + a1 + ")";
+    }
+
+    public String mNumUnambigous(Short a1, boolean otherOverload) {
+        return "mmNumUnambigous won't be called";
+    }
+    
+    public String mNumUnambigous(Integer a1) {
+        return "mNumUnambigous(Integer a1 = " + a1 + ")";
+    }
+    
+    public String mNumBoxedAll(Byte a1) {
+        return "mNumBoxedAll(Byte a1 = " + a1 + ")";
+    }
+    
+    public String mNumBoxedAll(Short a1) {
+        return "mNumBoxedAll(Short a1 = " + a1 + ")";
+    }
+
+    public String mNumBoxedAll(Integer a1) {
+        return "mNumBoxedAll(Integer a1 = " + a1 + ")";
+    }
+    
+    public String mNumBoxedAll(Long a1) {
+        return "mNumBoxedAll(Long a1 = " + a1 + ")";
+    }
+    
+    public String mNumBoxedAll(Float a1) {
+        return "mNumBoxedAll(Float a1 = " + a1 + ")";
+    }
+    
+    public String mNumBoxedAll(Double a1) {
+        return "mNumBoxedAll(Double a1 = " + a1 + ")";
+    }
+    
+    public String mNumBoxedAll(BigInteger a1) {
+        return "mNumBoxedAll(BigInteger a1 = " + a1 + ")";
+    }
+    
+    public String mNumBoxedAll(BigDecimal a1) {
+        return "mNumBoxedAll(BigDecimal a1 = " + a1 + ")";
+    }
+    
+    public String mNumPrimAll(byte a1) {
+        return "mNumPrimAll(byte a1 = " + a1 + ")";
+    }
+    
+    public String mNumPrimAll(short a1) {
+        return "mNumPrimAll(short a1 = " + a1 + ")";
+    }
+
+    public String mNumPrimAll(int a1) {
+        return "mNumPrimAll(int a1 = " + a1 + ")";
+    }
+    
+    public String mNumPrimAll(long a1) {
+        return "mNumPrimAll(long a1 = " + a1 + ")";
+    }
+    
+    public String mNumPrimAll(float a1) {
+        return "mNumPrimAll(float a1 = " + a1 + ")";
+    }
+    
+    public String mNumPrimAll(double a1) {
+        return "mNumPrimAll(double a1 = " + a1 + ")";
+    }
+    
+    public String mNumPrimAll(BigInteger a1) {
+        return "mNumPrimAll(BigInteger a1 = " + a1 + ")";
+    }
+    
+    public String mNumPrimAll(BigDecimal a1) {
+        return "mNumPrimAll(BigDecimal a1 = " + a1 + ")";
+    }
+
+    
+    public String mNumBoxedAll2nd(Short a1) {
+        return "mNumBoxedAll2nd(Short a1 = " + a1 + ")";
+    }
+
+    public String mNumBoxedAll2nd(Long a1) {
+        return "mNumBoxedAll2nd(Long a1 = " + a1 + ")";
+    }
+    
+    public String mNumBoxedAll2nd(Double a1) {
+        return "mNumBoxedAll2nd(Double a1 = " + a1 + ")";
+    }
+    
+    public String mNumPrimAll2nd(short a1) {
+        return "mNumPrimAll2nd(short a1 = " + a1 + ")";
+    }
+    
+    public String mNumPrimAll2nd(long a1) {
+        return "mNumPrimAll2nd(long a1 = " + a1 + ")";
+    }
+    
+    public String mNumPrimAll2nd(double a1) {
+        return "mNumPrimAll2nd(double a1 = " + a1 + ")";
+    }
+    
+    public String mNumPrimFallbackToNumber(long a1) {
+        return "mNumPrimFallbackToNumber(long a1 = " + a1 + ")";
+    }
+    
+    public String mNumPrimFallbackToNumber(Number a1) {
+        return "mNumPrimFallbackToNumber(Number a1 = " + a1 + ")";
+    }
+    
+    public String mNumPrimFallbackToNumber(Object a1) {
+        return "mNumPrimFallbackToNumber(Object a1 = " + a1 + ")";
+    }
+    
+    public String mNumBoxedFallbackToNumber(Long a1) {
+        return "mNumBoxedFallbackToNumber(Long a1 = " + a1 + ")";
+    }
+    
+    public String mNumBoxedFallbackToNumber(Number a1) {
+        return "mNumBoxedFallbackToNumber(Number a1 = " + a1 + ")";
+    }
+    
+    public String mNumBoxedFallbackToNumber(Object a1) {
+        return "mNumBoxedFallbackToNumber(Object a1 = " + a1 + ")";
+    }
+
+    public String mDecimalLoss(int a1) {
+        return "mDecimalLoss(int a1 = " + a1 + ")";
+    }
+        
+    public String mDecimalLoss(double a1) {
+        return "mDecimalLoss(double a1 = " + a1 + ")";
+    }
+    
+    public String mNumConversionLoses1(byte i, Object o1, Object o2) {
+        return "byte " + i;
+    }
+    
+    public String mNumConversionLoses1(double i, Object o1, Object o2) {
+        return "double " + i;
+    }
+
+    public String mNumConversionLoses1(Number i, String o1, String o2) {
+        return "Number " + i + " " + i.getClass().getName();
+    }
+
+    public String mNumConversionLoses2(int i, Object o1, Object o2) {
+        return "int " + i;
+    }
+
+    public String mNumConversionLoses2(long i, Object o1, Object o2) {
+        return "long " + i;
+    }
+
+    public String mNumConversionLoses2(Number i, String o1, String o2) {
+        return "Number " + i + " " + i.getClass().getName();
+    }
+
+    public String mNumConversionLoses3(int i, Object o1, Object o2) {
+        return "int " + i;
+    }
+
+    public String mNumConversionLoses3(Serializable i, String o1, String o2) {
+        return "Serializable " + i + " " + i.getClass().getName();
+    }
+    
+    public String nIntAndLong(int i) {
+        return "nIntAndLong(int " + i + ")";
+    }
+    
+    public String nIntAndLong(long i) {
+        return "nIntAndLong(long " + i + ")";
+    }
+
+    public String nIntAndShort(int i) {
+        return "nIntAndShort(int " + i + ")";
+    }
+    
+    public String nIntAndShort(short i) {
+        return "nIntAndShort(short " + i + ")";
+    }
+
+    public String nLongAndShort(long i) {
+        return "nLongAndShort(long " + i + ")";
+    }
+    
+    public String nLongAndShort(short i) {
+        return "nLongAndShort(short " + i + ")";
+    }
+
+    public String varargs1(String s, int... xs) {
+        return "varargs1(String s = " + _StringUtil.jQuote(s) + ", int... xs = " + TestUtil.arrayToString(xs) + ")";
+    }
+
+    public String varargs1(String s, double... xs) {
+        return "varargs1(String s = " + _StringUtil.jQuote(s) + ", double... xs = " + TestUtil.arrayToString(xs) + ")";
+    }
+
+    public String varargs1(String s, Object... xs) {
+        return "varargs1(String s = " + _StringUtil.jQuote(s) + ", Object... xs = " + TestUtil.arrayToString(xs) + ")";
+    }
+
+    public String varargs1(Object s, Object... xs) {
+        return "varargs1(Object s = " + s + ", Object... xs = " + TestUtil.arrayToString(xs) + ")";
+    }
+
+    public String varargs2(int... xs) {
+        return "varargs2(int... xs = " + TestUtil.arrayToString(xs) + ")";
+    }
+
+    public String varargs2(double... xs) {
+        return "varargs2(double... xs = " + TestUtil.arrayToString(xs) + ")";
+    }
+
+    public String varargs3(String... xs) {
+        return "varargs3(String... xs = " + TestUtil.arrayToString(xs) + ")";
+    }
+
+    public String varargs3(Comparable... xs) {
+        return "varargs3(Comparable... xs = " + TestUtil.arrayToString(xs) + ")";
+    }
+    
+    public String varargs3(Object... xs) {
+        return "varargs3(Object... xs = " + TestUtil.arrayToString(xs) + ")";
+    }
+    
+    public String varargs4(Integer... xs) {
+        return "varargs4(Integer... xs = " + TestUtil.arrayToString(xs) + ")";
+    }
+
+    public String varargs4(int... xs) {
+        return "varargs4(int... xs = " + TestUtil.arrayToString(xs) + ")";
+    }
+
+    public String varargs5(int... xs) {
+        return "varargs5(int... xs = " + TestUtil.arrayToString(xs) + ")";
+    }
+    
+    public String varargs5(int a1, int... xs) {
+        return "varargs5(int a1 = " + a1 + ", int... xs = " + TestUtil.arrayToString(xs) + ")";
+    }
+    
+    public String varargs5(int a1, int a2, int... xs) {
+        return "varargs5(int a1 = " + a1 + ", int a2 = " + a2 + ", int... xs = " + TestUtil.arrayToString(xs) + ")";
+    }
+
+    public String varargs5(int a1, int a2, int a3, int... xs) {
+        return "varargs5(int a1 = " + a1 + ", int a2 = " + a2 + ", int a3 = " + a3
+                + ", int... xs = " + TestUtil.arrayToString(xs) + ")";
+    }
+
+    public String varargs6(String a1, int... xs) {
+        return "varargs6(String a1 = " + a1 + ", int... xs = " + TestUtil.arrayToString(xs) + ")";
+    }
+    
+    public String varargs6(Object a1, int a2, int... xs) {
+        return "varargs6(Object a1 = " + a1 + ", int a2 = " + a2 + ", int... xs = " + TestUtil.arrayToString(xs) + ")";
+    }
+    
+    public String varargs7(int... xs) {
+        return "varargs7(int... xs = " + TestUtil.arrayToString(xs) + ")";
+    }
+    
+    public String varargs7(short a1, int... xs) {
+        return "varargs7(short a1 = " + a1 + ", int... xs = " + TestUtil.arrayToString(xs) + ")";
+    }
+    
+    public String mNullAmbiguous(String s) {
+        return "mNullAmbiguous(String s = " + s + ")";
+    }
+
+    public String mNullAmbiguous(int i) {
+        return "mNullAmbiguous(int i = " + i + ")";
+    }
+
+    public String mNullAmbiguous(File f) {
+        return "mNullAmbiguous(File f = " + f + ")";
+    }
+    
+    public String mNullAmbiguous2(String s) {
+        return "mNullNonAmbiguous(String s = " + s + ")";
+    }
+
+    public String mNullAmbiguous2(File f) {
+        return "mNullAmbiguous(File f = " + f + ")";
+    }
+
+    public String mNullAmbiguous2(Object o) {
+        return "mNullAmbiguous(Object o = " + o + ")";
+    }
+
+    public String mNullNonAmbiguous(String s) {
+        return "mNullNonAmbiguous(String s = " + s + ")";
+    }
+
+    public String mNullNonAmbiguous(int i) {
+        return "mNullNonAmbiguous(int i = " + i + ")";
+    }
+    
+    public String mVarargsIgnoredTail(int i, double... ds) {
+        return "mVarargsIgnoredTail(int i = " + i + ", double... ds = " + TestUtil.arrayToString(ds) + ")";
+    }
+    
+    public String mVarargsIgnoredTail(int... is) {
+        return "mVarargsIgnoredTail(int... is = " + TestUtil.arrayToString(is) + ")";
+    }
+    
+    public String mLowRankWins(int x, int y, Object o) {
+        return "mLowRankWins(int x = " + x + ", int y = " + y + ", Object o = " + o + ")";
+    }
+
+    public String mLowRankWins(Integer x, Integer y, String s) {
+        return "mLowRankWins(Integer x = " + x + ", Integer y = " + y + ", String s = " + s + ")";
+    }
+    
+    public String mRareWrappings(File f, double d1, Double d2, double d3, boolean b) {
+        return "mRareWrappings(File f = " + f + ", double d1 = " + d1 + ", Double d2 = " + d2
+                + ", double d3 = " + d3 + ", b = " + b + ")";
+    }
+
+    public String mRareWrappings(Object o, double d1, Double d2, Double d3, boolean b) {
+        return "mRareWrappings(Object o = " + o + ", double d1 = " + d1 + ", Double d2 = " + d2
+                + ", double d3 = " + d3 + ", b = " + b + ")";
+    }
+
+    public String mRareWrappings(String s, double d1, Double d2, Double d3, boolean b) {
+        return "mRareWrappings(String s = " + s + ", double d1 = " + d1 + ", Double d2 = " + d2
+                + ", double d3 = " + d3 + ", b = " + b + ")";
+    }
+
+    public String mRareWrappings2(String s) {
+        return "mRareWrappings2(String s = " + s + ")";
+    }
+    
+    public String mRareWrappings2(byte b) {
+        return "mRareWrappings2(byte b = " + b + ")";
+    }
+    
+    public File getFile() {
+        return new File("file");
+    }
+
+    public String mSeqToArrayNonOverloaded(String[] items, String s) {
+        return "mSeqToArrayNonOverloaded(String[] " + TestUtil.arrayToString(items) + ", String " + s + ")";
+    }
+    
+    public String mSeqToArrayGoodHint(String[] items, String s) {
+        return "mSeqToArrayGoodHint(String[] " + TestUtil.arrayToString(items) + ", String " + s + ")";
+    }
+
+    public String mSeqToArrayGoodHint(String[] items, int i) {
+        return "mSeqToArrayGoodHint(String[] " + TestUtil.arrayToString(items) + ", int " + i + ")";
+    }
+
+    public String mSeqToArrayGoodHint2(String[] items, String s) {
+        return "mSeqToArrayGoodHint2(String[] " + TestUtil.arrayToString(items) + ", String " + s + ")";
+    }
+
+    public String mSeqToArrayGoodHint2(String item) {
+        return "mSeqToArrayGoodHint2(String " + item + ")";
+    }
+    
+    public String mSeqToArrayPoorHint(String[] items, String s) {
+        return "mSeqToArrayPoorHint(String[] " + TestUtil.arrayToString(items) + ", String " + s + ")";
+    }
+
+    public String mSeqToArrayPoorHint(String item, int i) {
+        return "mSeqToArrayPoorHint(String " + item + ", int " + i + ")";
+    }
+
+    public String mSeqToArrayPoorHint2(String[] items) {
+        return "mSeqToArrayPoorHint2(String[] " + TestUtil.arrayToString(items) + ")";
+    }
+
+    public String mSeqToArrayPoorHint2(String item) {
+        return "mSeqToArrayPoorHint2(String " + item + ")";
+    }
+    
+    public String mSeqToArrayPoorHint3(String[] items) {
+        return "mSeqToArrayPoorHint3(String[] " + TestUtil.arrayToString(items) + ")";
+    }
+
+    public String mSeqToArrayPoorHint3(int[] items) {
+        return "mSeqToArrayPoorHint3(int[] " + TestUtil.arrayToString(items) + ")";
+    }
+
+    public String mStringArrayVsListPreference(String[] items) {
+        return "mStringArrayVsListPreference(String[] " + TestUtil.arrayToString(items) + ")";
+    }
+
+    public String mStringArrayVsListPreference(List items) {
+        return "mStringArrayVsListPreference(List " + TestUtil.listToString(items) + ")";
+    }
+
+    public String mStringArrayVsObjectArrayPreference(String[] items) {
+        return "mStringArrayVsObjectArrayPreference(String[] " + TestUtil.arrayToString(items) + ")";
+    }
+
+    public String mStringArrayVsObjectArrayPreference(Object[] items) {
+        return "mStringArrayVsObjectArrayPreference(Object[] " + TestUtil.arrayToString(items) + ")";
+    }
+
+    public String mIntArrayVsIntegerArrayPreference(int[] items) {
+        return "mIntArrayVsIntegerArrayPreference(int[] " + TestUtil.arrayToString(items) + ")";
+    }
+
+    public String mIntArrayVsIntegerArrayPreference(Integer[] items) {
+        return "mIntArrayVsIntegerArrayPreference(Integer[] " + TestUtil.arrayToString(items) + ")";
+    }
+    
+    public String mIntArrayNonOverloaded(int[] items) {
+        return "mIntArrayNonOverloaded(int[] " + TestUtil.arrayToString(items) + ")";
+    }
+
+    public String mIntegerArrayNonOverloaded(Integer[] items) {
+        return "mIntegerArrayNonOverloaded(Integer[] " + TestUtil.arrayToString(items) + ")";
+    }
+
+    public String mIntegerListNonOverloaded(List<Integer> items) {
+        return "mIntegerListNonOverloaded(List<Integer> " + items + ")";
+    }
+
+    public String mStringListNonOverloaded(List<String> items) {
+        return "mStringListNonOverloaded(List<String> " + items + ")";
+    }
+
+    public String mStringArrayNonOverloaded(String[] items) {
+        return "mStringArrayNonOverloaded(String[] " + TestUtil.arrayToString(items) + ")";
+    }
+
+    public String mObjectListNonOverloaded(List<Object> items) {
+        return "mObjectListNonOverloaded(List<Object> " + items + ")";
+    }
+
+    public String mObjectArrayNonOverloaded(Object[] items) {
+        return "mObjectArrayNonOverloaded(Object[] " + TestUtil.arrayToString(items) + ")";
+    }
+
+    public String mIntegerArrayOverloaded(Integer[] items, int i) {
+        return "mIntegerArrayOverloaded(Integer[] " + TestUtil.arrayToString(items) + ", int " + i + ")";
+    }
+
+    public String mIntegerArrayOverloaded(Object obj, boolean b) {
+        return "mIntegerArrayOverloaded(Object " + obj + ", boolean " + b + ")";
+    }
+
+    public String mStringArrayOverloaded(String[] items, int i) {
+        return "mStringArrayOverloaded(String[] " + TestUtil.arrayToString(items) + ", int " + i + ")";
+    }
+
+    public String mStringArrayOverloaded(Object obj, boolean b) {
+        return "mStringArrayOverloaded(Object " + obj + ", boolean " + b + ")";
+    }
+
+    public String mCharArrayOverloaded(char[] items, int i) {
+        return "mCharArrayOverloaded(char[] " + TestUtil.arrayToString(items) + ", int " + i + ")";
+    }
+
+    public String mCharArrayOverloaded(Character[] items, String s) {
+        return "mCharArrayOverloaded(Character[] " + TestUtil.arrayToString(items) + ", String " + s + ")";
+    }
+    
+    public String mCharArrayOverloaded(Object obj, boolean b) {
+        return "mCharArrayOverloaded(Object " + obj + ", boolean " + b + ")";
+    }
+
+    public String mStringArrayArrayOverloaded(String[][] arrayArray, int i) {
+        return "mStringArrayArrayOverloaded(String[][] " + TestUtil.arrayToString(arrayArray) + ", int " + i + ")";
+    }
+    
+    public String mStringArrayArrayOverloaded(Object obj, boolean b) {
+        return "mStringArrayArrayOverloaded(Object " + obj + ", boolean " + b + ")";
+    }
+    
+    public String mIntArrayArrayOverloaded(int[][] xss) {
+        return "mIntArrayArrayOverloaded(" + TestUtil.arrayToString(xss) + ")";
+    }
+
+    public String mIntArrayArrayOverloaded(String s) {
+        return "mIntArrayArrayOverloaded(" + s + ")";
+    }
+    
+    public String mArrayOfListsOverloaded(List[] xss) {
+        return "mArrayOfListsOverloaded(" + TestUtil.arrayToString(xss) + ")";
+    }
+
+    public String mArrayOfListsOverloaded(String x) {
+        return "mArrayOfListsOverloaded(" + x + ")";
+    }
+    
+    public String mIntArrayArrayNonOverloaded(int[][] xss) {
+        return "mIntArrayArrayNonOverloaded(" + TestUtil.arrayToString(xss) + ")";
+    }
+
+    public String mArrayOfListsNonOverloaded(List[] xss) {
+        return "mArrayOfListsNonOverloaded(" + TestUtil.arrayToString(xss) + ")";
+    }
+    
+    public String mStringArrayVarargsNonOverloaded(String... items) {
+        return "mStringArrayVarargsNonOverloaded(String[] " + TestUtil.arrayToString(items) + ")";
+    }
+
+    public String mStringArrayVarargsOverloaded(String... items) {
+        return "mStringArrayVarargsNonOverloaded(String[] " + TestUtil.arrayToString(items) + ")";
+    }
+
+    public String mStringArrayVarargsOverloaded1(String... items) {
+        return "mStringArrayVarargsOverloaded1(String[] " + TestUtil.arrayToString(items) + ")";
+    }
+
+    public String mStringArrayVarargsOverloaded1(List<String> items) {
+        return "mStringArrayVarargsOverloaded1(List " + TestUtil.listToString(items) + ")";
+    }
+
+    public String mStringArrayVarargsOverloaded2(String... items) {
+        return "mStringArrayVarargsOverloaded2(String[] " + TestUtil.arrayToString(items) + ")";
+    }
+
+    public String mStringArrayVarargsOverloaded2(String item) {
+        return "mStringArrayVarargsOverloaded2(String " + item + ")";
+    }
+    
+    public String mStringArrayVarargsOverloaded3(String... items) {
+        return "mStringArrayVarargsOverloaded3(String[] " + TestUtil.arrayToString(items) + ")";
+    }
+
+    public String mStringArrayVarargsOverloaded3(String item1, String item2) {
+        return "mStringArrayVarargsOverloaded3(String " + item1 + ", String " + item2 + ")";
+    }
+    
+    public String mStringArrayVarargsOverloaded4(String... items) {
+        return "mStringArrayVarargsOverloaded4(String[] " + TestUtil.arrayToString(items) + ")";
+    }
+
+    public String mStringArrayVarargsOverloaded4(List... items) {
+        return "mStringArrayVarargsOverloaded4(List[] " + TestUtil.arrayToString(items) + ")";
+    }
+    
+    public String mListOrString(List<String> items) {
+        return "mListOrString(List " + TestUtil.listToString(items) + ")";
+    }
+
+    public String mListOrString(String item) {
+        return "mListOrString(String " + item + ")";
+    }
+
+    public String mListListOrString(List<List<Object>> items) {
+        return "mListListOrString(List " + TestUtil.listToString(items) + ")";
+    }
+
+    public String mListListOrString(String item) {
+        return "mListListOrString(String " + item + ")";
+    }
+    
+    public String mMapOrBoolean(Map v) {
+        return "mMapOrBoolean(Map " + v + ")";
+    }
+
+    public String mMapOrBoolean(boolean v) {
+        return "mMapOrBoolean(boolean " + v + ")";
+    }
+
+    public String mMapOrBooleanVarargs(Map... v) {
+        return "mMapOrBooleanVarargs(Map... " + TestUtil.arrayToString(v) + ")";
+    }
+
+    public String mMapOrBooleanVarargs(boolean... v) {
+        return "mMapOrBooleanVarargs(boolean... " + TestUtil.arrayToString(v) + ")";
+    }
+
+    public String mMapOrBooleanFixedAndVarargs(Map v) {
+        return "mMapOrBooleanFixedAndVarargs(Map " + v + ")";
+    }
+
+    public String mMapOrBooleanFixedAndVarargs(boolean v) {
+        return "mMapOrBooleanFixedAndVarargs(boolean " + v + ")";
+    }
+
+    public String mMapOrBooleanFixedAndVarargs(Map... v) {
+        return "mMapOrBooleanFixedAndVarargs(Map... " + TestUtil.arrayToString(v) + ")";
+    }
+
+    public String mMapOrBooleanFixedAndVarargs(boolean... v) {
+        return "mMapOrBooleanFixedAndVarargs(boolean... " + TestUtil.arrayToString(v) + ")";
+    }
+    
+    public String mNumberOrArray(Number v) {
+        return "mNumberOrArray(Number " + v + ")";
+    }
+
+    public String mNumberOrArray(Object[] v) {
+        return "mNumberOrArray(Object[] " + TestUtil.arrayToString(v) + ")";
+    }
+    
+    public String mIntOrArray(int v) {
+        return "mIntOrArray(int " + v + ")";
+    }
+
+    public String mIntOrArray(Object[] v) {
+        return "mIntOrArray(Object[] " + TestUtil.arrayToString(v) + ")";
+    }
+
+    public String mDateOrArray(Date v) {
+        return "mDateOrArray(Date " + v.getTime() + ")";
+    }
+
+    public String mDateOrArray(Object[] v) {
+        return "mDateOrArray(Object[] " + TestUtil.arrayToString(v) + ")";
+    }
+    
+    public String mStringOrArray(String v) {
+        return "mStringOrArray(String " + v + ")";
+    }
+
+    public String mStringOrArray(Object[] v) {
+        return "mStringOrArray(Object[] " + TestUtil.arrayToString(v) + ")";
+    }
+    
+    public String mBooleanOrArray(boolean v) {
+        return "mBooleanOrArray(boolean " + v + ")";
+    }
+
+    public String mBooleanOrArray(Object[] v) {
+        return "mBooleanOrArray(Object[] " + TestUtil.arrayToString(v) + ")";
+    }
+    
+    public String mMapOrArray(Map v) {
+        return "mMapOrArray(Map " + v + ")";
+    }
+
+    public String mMapOrArray(Object[] v) {
+        return "mMapOrArray(Object[] " + TestUtil.arrayToString(v) + ")";
+    }
+    
+    public String mListOrArray(List v) {
+        return "mListOrArray(List " + v + ")";
+    }
+
+    public String mListOrArray(Object[] v) {
+        return "mListOrArray(Object[] " + TestUtil.arrayToString(v) + ")";
+    }
+    
+    public String mSetOrArray(Set v) {
+        return "mSetOrArray(Set " + v + ")";
+    }
+
+    public String mSetOrArray(Object[] v) {
+        return "mSetOrArray(Object[] " + TestUtil.arrayToString(v) + ")";
+    }
+    
+    public String mCharNonOverloaded(char c) {
+        return "mCharNonOverloaded(char " + c + ")";
+    }
+
+    public String mCharacterNonOverloaded(Character c) {
+        return "mCharacterNonOverloaded(Character " + c + ")";
+    }
+    
+    public String mCharOrCharacterOverloaded(char c) {
+        return "mCharOrCharacterOverloaded(char " + c + ")";
+    }
+
+    public String mCharOrCharacterOverloaded(Character c) {
+        return "mCharOrCharacterOverloaded(Character " + c + ")";
+    }
+
+    public String mCharOrBooleanOverloaded(char c) {
+        return "mCharOrBooleanOverloaded(char " + c + ")";
+    }
+
+    public String mCharOrBooleanOverloaded(boolean b) {
+        return "mCharOrBooleanOverloaded(boolean " + b + ")";
+    }
+
+    public String mCharOrStringOverloaded(char c, boolean b) {
+        return "mCharOrStringOverloaded(char " + c + ", boolean " + b + ")";
+    }
+
+    public String mCharOrStringOverloaded(String s, int i) {
+        return "mCharOrStringOverloaded(String " + s + ", int " + i + ")";
+    }
+
+    public String mCharacterOrStringOverloaded(Character c, boolean b) {
+        return "mCharacterOrStringOverloaded(Character " + c + ", boolean " + b + ")";
+    }
+
+    public String mCharacterOrStringOverloaded(String s, int i) {
+        return "mCharacterOrStringOverloaded(String " + s + ", int " + i + ")";
+    }
+    
+    public String mCharOrStringOverloaded2(String s) {
+        return "mCharOrStringOverloaded2(String " + s + ")";
+    }
+
+    public String mCharOrStringOverloaded2(char c) {
+        return "mCharOrStringOverloaded2(char " + c + ")";
+    }
+    
+    public String mCharacterOrStringOverloaded2(String s) {
+        return "mCharacterOrStringOverloaded2(String " + s + ")";
+    }
+
+    public String mCharacterOrStringOverloaded2(Character c) {
+        return "mCharacterOrStringOverloaded2(Character " + c + ")";
+    }
+    
+
+    public String getJavaString() {
+        return "s";
+    }
+    
+    public List getJavaStringList() {
+        List list = new ArrayList();
+        list.add("a");
+        list.add("b");
+        return list;
+    }
+
+    public List getJavaString2List() {
+        List list = new ArrayList();
+        list.add("aa");
+        list.add("bb");
+        return list;
+    }
+
+    public List getJavaStringListList() {
+        List listList = new ArrayList();
+        {
+            List list = new ArrayList();
+            list.add("a");
+            list.add("b");
+            
+            listList.add(list);
+        }
+        {
+            List list = new ArrayList();
+            list.add("c");
+            
+            listList.add(list);
+        }
+        return listList;
+    }
+
+    public List getJavaStringSequenceList() throws TemplateModelException {
+        ObjectWrapper ow = Environment.getCurrentEnvironment().getObjectWrapper();
+        
+        List listList = new ArrayList();
+        {
+            List list = new ArrayList();
+            list.add("a");
+            list.add("b");
+            
+            listList.add(ow.wrap(list));
+        }
+        {
+            List list = new ArrayList();
+            list.add("c");
+            
+            listList.add(ow.wrap(list));
+        }
+        return listList;
+    }
+    
+    public List<int[]> getJavaListOfIntArrays() {
+        List list = new ArrayList();
+        list.add(new int[] {1, 2, 3});
+        list.add(new int[] {});
+        list.add(new int[] {4});
+        return list;
+    }
+    
+    @SuppressWarnings("boxing")
+    public List getJavaIntegerListList() {
+        List listList = new ArrayList();
+        {
+            List list = new ArrayList();
+            list.add(1);
+            list.add(2);
+            
+            listList.add(list);
+        }
+        {
+            List list = new ArrayList();
+            list.add(3);
+            
+            listList.add(list);
+        }
+        return listList;
+    }
+    
+    @SuppressWarnings("boxing")
+    public List<Integer> getJavaIntegerList() {
+        List<Integer> list = new ArrayList<>();
+        list.add(1);
+        list.add(2);
+        return list;
+    }
+
+    @SuppressWarnings("boxing")
+    public List<Byte> getJavaByteList() {
+        List<Byte> list = new ArrayList<>();
+        list.add((byte) 1);
+        list.add((byte) 2);
+        return list;
+    }
+
+    @SuppressWarnings("boxing")
+    public List<Character> getJavaCharacterList() {
+        List<Character> list = new ArrayList<>();
+        list.add('c');
+        list.add('C');
+        return list;
+    }
+    
+    public String[] getJavaStringArray() {
+        return new String[] { "a", "b" };
+    }
+
+    public int[] getJavaIntArray() {
+        return new int[] { 11, 22 };
+    }
+
+    public Integer[] getJavaIntegerArray() {
+        return new Integer[] { Integer.valueOf(11), Integer.valueOf(22) };
+    }
+    
+    public String[] getJavaEmptyStringArray() {
+        return new String[] { };
+    }
+    
+    public String[][] getJavaStringArrayArray() {
+        return new String[][] { new String[] { "a", "b" }, new String[] { }, new String[] { "c" } };
+    }
+    
+    public Object[] getJavaObjectArray() {
+        return new Object[] { "a", "b" };
+    }
+    
+    public TemplateModel getHashAndScalarModel() {
+        return HashAndScalarModel.INSTANCE;
+    }
+
+    public TemplateModel getBooleanAndScalarModel() {
+        return BooleanAndScalarModel.INSTANCE;
+    }
+    
+    public TemplateModel getAllModels() {
+        return AllTemplateModels.INSTANCE;
+    }
+
+    public TemplateNumberModel getAdaptedNumber() {
+        return new MyAdapterNumberModel();
+    }
+
+    public TemplateNumberModel getWrapperNumber() {
+        return new MyWrapperNumberModel();
+    }
+
+    public TemplateBooleanModel getStringAdaptedToBoolean() {
+        return new MyStringAdaptedToBooleanModel();
+    }
+    
+    public TemplateBooleanModel getStringAdaptedToBoolean2() {
+        return new MyStringAdaptedToBooleanModel2();
+    }
+    
+    public TemplateBooleanModel getStringWrappedAsBoolean() {
+        return new MyStringWrapperAsBooleanModel();
+    }
+    
+    public TemplateBooleanModel getBooleanWrappedAsAnotherBoolean() {
+        return new MyBooleanWrapperAsAnotherBooleanModel(); 
+    }
+    
+    public String bugReport363(Map<String, ?> fields, List<?> listField) {
+        return "Executed: testMethod(Map fields, List listField) on input: fields=" + fields
+                + " and listField=" + listField;
+    }
+
+    public String bugReport363(Object... fields) {
+        return "Executed: testMethod(Object... fields) on input: fields=" + TestUtil.arrayToString(fields);
+    }
+    
+    private static class MyAdapterNumberModel implements TemplateNumberModel, AdapterTemplateModel {
+
+        @Override
+        public Object getAdaptedObject(Class hint) {
+            if (hint == double.class) {
+                return Double.valueOf(123.0001);
+            } else if (hint == Double.class) {
+                return Double.valueOf(123.0002);
+            } else {
+                return Long.valueOf(124L);
+            }
+        }
+
+        @Override
+        public Number getAsNumber() throws TemplateModelException {
+            return Integer.valueOf(122);
+        }
+        
+    }
+    
+    private static class MyWrapperNumberModel implements TemplateNumberModel, WrapperTemplateModel {
+
+        @Override
+        public Number getAsNumber() throws TemplateModelException {
+            return Integer.valueOf(122);
+        }
+
+        @Override
+        public Object getWrappedObject() {
+            return Double.valueOf(123.0001);
+        }
+        
+    }
+    
+    private static class MyStringWrapperAsBooleanModel implements TemplateBooleanModel, WrapperTemplateModel {
+
+        @Override
+        public Object getWrappedObject() {
+            return "yes";
+        }
+
+        @Override
+        public boolean getAsBoolean() throws TemplateModelException {
+            return true;
+        }
+        
+    }
+
+    private static class MyBooleanWrapperAsAnotherBooleanModel implements TemplateBooleanModel, WrapperTemplateModel {
+
+        @Override
+        public Object getWrappedObject() {
+            return Boolean.TRUE;
+        }
+
+        @Override
+        public boolean getAsBoolean() throws TemplateModelException {
+            return false;
+        }
+        
+    }
+    
+    private static class MyStringAdaptedToBooleanModel implements TemplateBooleanModel, AdapterTemplateModel {
+
+        @Override
+        public Object getAdaptedObject(Class hint) {
+            if (hint != Boolean.class && hint != boolean.class) {
+                return "yes";
+            } else {
+                return Boolean.TRUE;
+            }
+        }
+
+        @Override
+        public boolean getAsBoolean() throws TemplateModelException {
+            return false;
+        }
+        
+    }
+
+    private static class MyStringAdaptedToBooleanModel2 implements TemplateBooleanModel, AdapterTemplateModel {
+
+        @Override
+        public Object getAdaptedObject(Class hint) {
+            return "yes";
+        }
+
+        @Override
+        public boolean getAsBoolean() throws TemplateModelException {
+            return true;
+        }
+        
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/SimpleMapAndCollectionObjectWrapper.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/SimpleMapAndCollectionObjectWrapper.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/SimpleMapAndCollectionObjectWrapper.java
new file mode 100644
index 0000000..bd445c6
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/SimpleMapAndCollectionObjectWrapper.java
@@ -0,0 +1,60 @@
+/*
+ * 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.test.templatesuite.models;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.freemarker.core.Version;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.impl.DefaultObjectWrapper;
+import org.apache.freemarker.core.model.impl.SimpleHash;
+import org.apache.freemarker.core.model.impl.SimpleSequence;
+
+/**
+ * Forces using "simple" models for {@link Map}-s, {@link Collection}-s and arrays. This is mostly useful for template
+ * test cases that wish to test with these models, but otherwise need to able to wrap beans and such. 
+ */
+public class SimpleMapAndCollectionObjectWrapper extends DefaultObjectWrapper {
+
+    public SimpleMapAndCollectionObjectWrapper(Version incompatibleImprovements) {
+        super(new DefaultObjectWrapper.Builder(incompatibleImprovements), true);
+    }
+
+    @Override
+    public TemplateModel wrap(Object obj) throws TemplateModelException {
+        if (obj == null) {
+            return super.wrap(null);
+        }        
+        if (obj.getClass().isArray()) {
+            obj = Arrays.asList((Object[]) obj);
+        }
+        if (obj instanceof Collection) {
+            return new SimpleSequence((Collection<?>) obj, this);
+        }
+        if (obj instanceof Map) {
+            return new SimpleHash((Map<?, ?>) obj, this);
+        }
+        
+        return super.wrap(obj);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/SimpleTestMethod.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/SimpleTestMethod.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/SimpleTestMethod.java
new file mode 100644
index 0000000..85e27d7
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/SimpleTestMethod.java
@@ -0,0 +1,49 @@
+/*
+ * 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.test.templatesuite.models;
+
+import java.util.List;
+
+import org.apache.freemarker.core.model.TemplateMethodModel;
+import org.apache.freemarker.core.model.impl.SimpleScalar;
+
+/**
+ * A simple method model used as a test bed.
+ */
+public class SimpleTestMethod implements TemplateMethodModel {
+
+    /**
+     * Executes a method call.
+     *
+     * @param arguments a <tt>List</tt> of <tt>String</tt> objects containing
+     * the values of the arguments passed to the method.
+     * @return the <tt>TemplateModel</tt> produced by the method, or null.
+     */
+    @Override
+    public Object exec(List arguments) {
+        if ( arguments.size() == 0 ) {
+            return new SimpleScalar( "Empty list provided" );
+        } else if ( arguments.size() > 1 ) {
+            return new SimpleScalar( "Argument size is: " + arguments.size() );
+        } else {
+            return new SimpleScalar( "Single argument value is: " + arguments.get(0) );
+        }
+    }
+}


[45/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/ObjectBuilderSettingsTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/ObjectBuilderSettingsTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ObjectBuilderSettingsTest.java
new file mode 100644
index 0000000..49534fa
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ObjectBuilderSettingsTest.java
@@ -0,0 +1,1499 @@
+/*
+ * 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.apache.freemarker.test.hamcerst.Matchers.*;
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.io.Writer;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.nio.charset.UnsupportedCharsetException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.TimeZone;
+
+import org.apache.freemarker.core.arithmetic.ArithmeticEngine;
+import org.apache.freemarker.core.arithmetic.impl.BigDecimalArithmeticEngine;
+import org.apache.freemarker.core.model.ObjectWrapper;
+import org.apache.freemarker.core.model.impl.DefaultObjectWrapper;
+import org.apache.freemarker.core.templateresolver.CacheStorage;
+import org.apache.freemarker.core.templateresolver.TemplateLoader;
+import org.apache.freemarker.core.templateresolver.TemplateLoaderSession;
+import org.apache.freemarker.core.templateresolver.TemplateLoadingResult;
+import org.apache.freemarker.core.templateresolver.TemplateLoadingSource;
+import org.apache.freemarker.core.templateresolver.impl.MruCacheStorage;
+import org.apache.freemarker.core.userpkg.PublicWithMixedConstructors;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+@SuppressWarnings("boxing")
+public class ObjectBuilderSettingsTest {
+
+    @Test
+    public void newInstanceTest() throws Exception {
+        {
+            TestBean1 res = (TestBean1) _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            assertEquals(4f, res.f, 0);
+            assertFalse(res.b);
+        }
+        
+        {
+            TestBean1 res = (TestBean1) _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1()",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            assertEquals(4f, res.f, 0);
+            assertFalse(res.b);
+        }
+        
+        {
+            TestBean1 res = (TestBean1) _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1(1.5, -20, 8589934592, true)",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            assertEquals(1.5f, res.f, 0);
+            assertEquals(Integer.valueOf(-20), res.i);
+            assertEquals(8589934592l, res.l);
+            assertTrue(res.b);
+        }
+        
+        {
+            TestBean1 res = (TestBean1) _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1(1, true)",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            assertEquals(2f, res.f, 0);
+            assertEquals(Integer.valueOf(1), res.i);
+            assertEquals(2l, res.l);
+            assertTrue(res.b);
+        }
+        
+        {
+            TestBean1 res = (TestBean1) _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1(11, 22)",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            assertEquals(3f, res.f, 0);
+            assertEquals(Integer.valueOf(11), res.i);
+            assertEquals(22l, res.l);
+            assertFalse(res.b);
+        }
+        
+        {
+            TestBean1 res = (TestBean1) _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1(p1 = 1, p2 = 2, p3 = true, p4 = 's')",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            assertEquals(4f, res.f, 0);
+            assertFalse(res.b);
+            assertEquals(1d, res.getP1(), 0);
+            assertEquals(2, res.getP2());
+            assertTrue(res.isP3());
+            assertEquals("s", res.getP4());
+        }
+
+        {
+            TestBean1 res = (TestBean1) _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1("
+                    + "null, 2, p1 = 1, p2 = 2, p3 = false, p4 = null)",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            assertNull(res.i);
+            assertEquals(2, res.l, 0);
+            assertEquals(3f, res.f, 0);
+            assertFalse(res.b);
+            assertEquals(1d, res.getP1(), 0);
+            assertEquals(2, res.getP2());
+            assertFalse(res.isP3());
+            assertNull(res.getP4());
+        }
+        
+        {
+            // Deliberately odd spacings
+            TestBean1 res = (TestBean1) _ObjectBuilderSettingEvaluator.eval(
+                    "\t\torg.apache.freemarker .core  . \n"
+                    + "\tObjectBuilderSettingsTest$TestBean1(\n\r\tp1=1\n,p2=2,p3=true,p4='s'  )",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            assertEquals(4f, res.f, 0);
+            assertFalse(res.b);
+            assertEquals(1d, res.getP1(), 0);
+            assertEquals(2, res.getP2());
+            assertTrue(res.isP3());
+            assertEquals("s", res.getP4());
+        }
+        
+        {
+            TestBean1 res = (TestBean1) _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1(1, true, p2 = 2)",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            assertEquals(2f, res.f, 0);
+            assertEquals(Integer.valueOf(1), res.i);
+            assertEquals(2l, res.l);
+            assertTrue(res.b);
+            assertEquals(0d, res.getP1(), 0);
+            assertEquals(2, res.getP2());
+            assertFalse(res.isP3());
+        }
+    }
+    
+    @Test
+    public void builderTest() throws Exception {
+        {
+            // `()`-les syntax:
+            TestBean2 res = (TestBean2) _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean2",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            assertTrue(res.built);
+            assertEquals(0, res.x);
+        }
+        
+        {
+            TestBean2 res = (TestBean2) _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean2()",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            assertTrue(res.built);
+            assertEquals(0, res.x);
+        }
+        
+        {
+            TestBean2 res = (TestBean2) _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean2(x = 1)",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            assertTrue(res.built);
+            assertEquals(1, res.x);
+        }
+        
+        {
+            TestBean2 res = (TestBean2) _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean2(1)",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            assertTrue(res.built);
+            assertEquals(1, res.x);
+        }
+    }
+
+    @Test
+    public void staticInstanceTest() throws Exception {
+        // ()-les syntax:
+        {
+            TestBean5 res = (TestBean5) _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean5",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            assertEquals(0, res.i);
+            assertEquals(0, res.x);
+            assertSame(TestBean5.INSTANCE, res); //!
+        }
+        
+        {
+            TestBean5 res = (TestBean5) _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean5()",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            assertEquals(0, res.i);
+            assertEquals(0, res.x);
+            assertSame(TestBean5.INSTANCE, res); //!
+        }
+        
+        {
+            TestBean5 res = (TestBean5) _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean5(x = 1)",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            assertEquals(0, res.i);
+            assertEquals(1, res.x);
+            assertNotSame(TestBean5.INSTANCE, res);
+        }
+
+        {
+            TestBean5 res = (TestBean5) _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean5(1)",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            assertEquals(1, res.i);
+            assertEquals(0, res.x);
+            assertNotSame(TestBean5.INSTANCE, res);
+        }
+    }
+
+    @Test
+    public void stringLiteralsTest() throws Exception {
+        {
+            TestBean4 res = (TestBean4) _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean4(\"\", '', s3 = r\"\", s4 = r'')",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            assertEquals("", res.getS1());
+            assertEquals("", res.getS2());
+            assertEquals("", res.getS3());
+            assertEquals("", res.getS4());
+        }
+        
+        {
+            TestBean4 res = (TestBean4) _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean4(\"a\", 'b', s3 = r\"c\", s4 = r'd')",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            assertEquals("a", res.getS1());
+            assertEquals("b", res.getS2());
+            assertEquals("c", res.getS3());
+            assertEquals("d", res.getS4());
+        }
+        
+        {
+            TestBean4 res = (TestBean4) _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean4(\"a'A\", 'b\"B', s3 = r\"c'C\", s4 = r'd\"D')",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            assertEquals("a'A", res.getS1());
+            assertEquals("b\"B", res.getS2());
+            assertEquals("c'C", res.getS3());
+            assertEquals("d\"D", res.getS4());
+        }
+        
+        {
+            TestBean4 res = (TestBean4) _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean4("
+                    + "\"a\\nA\\\"a\\\\A\", 'a\\nA\\'a\\\\A', s3 = r\"a\\n\\A\", s4 = r'a\\n\\A')",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            assertEquals("a\nA\"a\\A", res.getS1());
+            assertEquals("a\nA'a\\A", res.getS2());
+            assertEquals("a\\n\\A", res.getS3());
+            assertEquals("a\\n\\A", res.getS4());
+        }
+    }
+
+    @Test
+    public void nestedBuilderTest() throws Exception {
+        {
+            TestBean6 res = (TestBean6) _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean6("
+                    + "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1(11, 22, p4 = 'foo'),"
+                    + "1,"
+                    + "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean2(11),"
+                    + "y=2,"
+                    + "b3=org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean2(x = 22)"
+                    + ")",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            assertEquals(Integer.valueOf(11), res.b1.i);
+            assertEquals(22, res.b1.l);
+            assertEquals("foo", res.b1.p4);
+            assertEquals(1, res.x);
+            assertEquals(11, res.b2.x);
+            assertEquals(2, res.y);
+            assertEquals(22, res.b3.x);
+            assertNull(res.b4);
+        }
+        
+        {
+            TestBean6 res = (TestBean6) _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean6("
+                    + "null,"
+                    + "-1,"
+                    + "null,"
+                    + "b4=org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean6("
+                    + "   org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1(11, 22, p4 = 'foo'),"
+                    + "   1,"
+                    + "   org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean2(11),"
+                    + "   y=2,"
+                    + "   b3=org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean2(x = 22)"
+                    + "),"
+                    + "y=2"
+                    + ")",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            assertNull(res.b1);
+            assertEquals(-1, res.x);
+            assertNull(res.b2);
+            assertEquals(2, res.y);
+            assertEquals(Integer.valueOf(11), res.b4.b1.i);
+            assertEquals(22, res.b4.b1.l);
+            assertEquals("foo", res.b4.b1.p4);
+            assertEquals(1, res.b4.x);
+            assertEquals(11, res.b4.b2.x);
+            assertEquals(2, res.b4.y);
+            assertEquals(22, res.b4.b3.x);
+            assertNull(res.b4.b4);
+        }
+    }
+
+    @Test
+    public void defaultObjectWrapperTest() throws Exception {
+        DefaultObjectWrapper ow = (DefaultObjectWrapper) _ObjectBuilderSettingEvaluator.eval(
+                "DefaultObjectWrapper(3.0.0)",
+                ObjectWrapper.class, false, _SettingEvaluationEnvironment.getCurrent());
+        assertEquals(Configuration.VERSION_3_0_0, ow.getIncompatibleImprovements());
+        assertFalse(ow.isExposeFields());
+    }
+
+    @Test
+    public void defaultObjectWrapperTest2() throws Exception {
+        DefaultObjectWrapper ow = (DefaultObjectWrapper) _ObjectBuilderSettingEvaluator.eval(
+                "DefaultObjectWrapper(3.0.0, exposeFields=true)",
+                ObjectWrapper.class, false, _SettingEvaluationEnvironment.getCurrent());
+        assertEquals(Configuration.VERSION_3_0_0, ow.getIncompatibleImprovements());
+        assertTrue(ow.isExposeFields());
+    }
+
+    @Test
+    public void configurationPropertiesTest() throws Exception {
+        final Configuration.Builder cfgB = new Configuration.Builder(Configuration.getVersion());
+        
+        {
+            Properties props = new Properties();
+            props.setProperty(MutableProcessingConfiguration.OBJECT_WRAPPER_KEY,
+                    "org.apache.freemarker.core.model.impl.DefaultObjectWrapper(3.0.0)");
+            props.setProperty(MutableProcessingConfiguration.ARITHMETIC_ENGINE_KEY,
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$DummyArithmeticEngine");
+            props.setProperty(MutableProcessingConfiguration.TEMPLATE_EXCEPTION_HANDLER_KEY,
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$DummyTemplateExceptionHandler");
+            props.setProperty(Configuration.ExtendableBuilder.CACHE_STORAGE_KEY,
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$DummyCacheStorage()");
+            props.setProperty(MutableProcessingConfiguration.NEW_BUILTIN_CLASS_RESOLVER_KEY,
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$DummyNewBuiltinClassResolver()");
+            props.setProperty(Configuration.ExtendableBuilder.SOURCE_ENCODING_KEY, "utf-8");
+            props.setProperty(Configuration.ExtendableBuilder.TEMPLATE_LOADER_KEY,
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$DummyTemplateLoader()");
+            cfgB.setSettings(props);
+            assertEquals(DefaultObjectWrapper.class, cfgB.getObjectWrapper().getClass());
+            assertEquals(
+                    Configuration.VERSION_3_0_0, ((DefaultObjectWrapper) cfgB.getObjectWrapper()).getIncompatibleImprovements());
+            assertEquals(DummyArithmeticEngine.class, cfgB.getArithmeticEngine().getClass());
+            assertEquals(DummyTemplateExceptionHandler.class, cfgB.getTemplateExceptionHandler().getClass());
+            assertEquals(DummyCacheStorage.class, cfgB.getCacheStorage().getClass());
+            assertEquals(DummyNewBuiltinClassResolver.class, cfgB.getNewBuiltinClassResolver().getClass());
+            assertEquals(DummyTemplateLoader.class, cfgB.getTemplateLoader().getClass());
+            assertEquals(StandardCharsets.UTF_8, cfgB.getSourceEncoding());
+        }
+        
+        {
+            Properties props = new Properties();
+            props.setProperty(MutableProcessingConfiguration.OBJECT_WRAPPER_KEY, "defAult");
+            props.setProperty(MutableProcessingConfiguration.ARITHMETIC_ENGINE_KEY,
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$DummyArithmeticEngine(x = 1)");
+            props.setProperty(MutableProcessingConfiguration.TEMPLATE_EXCEPTION_HANDLER_KEY,
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$DummyTemplateExceptionHandler(x = 1)");
+            props.setProperty(Configuration.ExtendableBuilder.CACHE_STORAGE_KEY,
+                    "soft: 500, strong: 100");
+            props.setProperty(MutableProcessingConfiguration.NEW_BUILTIN_CLASS_RESOLVER_KEY,
+                    "allows_nothing");
+            cfgB.setSettings(props);
+            assertEquals(DefaultObjectWrapper.class, cfgB.getObjectWrapper().getClass());
+            assertEquals(1, ((DummyArithmeticEngine) cfgB.getArithmeticEngine()).getX());
+            assertEquals(1, ((DummyTemplateExceptionHandler) cfgB.getTemplateExceptionHandler()).getX());
+            assertEquals(Configuration.VERSION_3_0_0,
+                    ((DefaultObjectWrapper) cfgB.getObjectWrapper()).getIncompatibleImprovements());
+            assertEquals(500, ((MruCacheStorage) cfgB.getCacheStorage()).getSoftSizeLimit());
+            assertEquals(TemplateClassResolver.ALLOWS_NOTHING_RESOLVER, cfgB.getNewBuiltinClassResolver());
+            assertEquals(StandardCharsets.UTF_8, cfgB.getSourceEncoding());
+        }
+
+        {
+            Properties props = new Properties();
+            props.setProperty(MutableProcessingConfiguration.OBJECT_WRAPPER_KEY, "Default");
+            props.setProperty(MutableProcessingConfiguration.ARITHMETIC_ENGINE_KEY, "bigdecimal");
+            props.setProperty(MutableProcessingConfiguration.TEMPLATE_EXCEPTION_HANDLER_KEY, "rethrow");
+            cfgB.setSettings(props);
+            assertEquals(DefaultObjectWrapper.class, cfgB.getObjectWrapper().getClass());
+            assertSame(BigDecimalArithmeticEngine.INSTANCE, cfgB.getArithmeticEngine());
+            assertSame(TemplateExceptionHandler.RETHROW_HANDLER, cfgB.getTemplateExceptionHandler());
+            assertEquals(Configuration.VERSION_3_0_0,
+                    ((DefaultObjectWrapper) cfgB.getObjectWrapper()).getIncompatibleImprovements());
+        }
+        
+        {
+            Properties props = new Properties();
+            props.setProperty(MutableProcessingConfiguration.OBJECT_WRAPPER_KEY, "DefaultObjectWrapper(3.0.0)");
+            cfgB.setSettings(props);
+            assertEquals(DefaultObjectWrapper.class, cfgB.getObjectWrapper().getClass());
+            assertEquals(
+                    Configuration.VERSION_3_0_0,
+                    ((DefaultObjectWrapper) cfgB.getObjectWrapper()).getIncompatibleImprovements());
+        }
+    }
+    
+    @Test
+    public void timeZoneTest() throws _ObjectBuilderSettingEvaluationException, ClassNotFoundException,
+    InstantiationException, IllegalAccessException {
+        for (String timeZoneId : new String[] { "GMT+01", "GMT", "UTC" }) {
+            TestBean8 result = (TestBean8) _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean8(timeZone=TimeZone('"
+                    + timeZoneId + "'))",
+                    TestBean8.class, false, new _SettingEvaluationEnvironment());
+            assertEquals(TimeZone.getTimeZone(timeZoneId), result.getTimeZone());
+        }
+        
+        try {
+            _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean8(timeZone=TimeZone('foobar'))",
+                    TestBean8.class, false, new _SettingEvaluationEnvironment());
+            fail();
+        } catch (_ObjectBuilderSettingEvaluationException e) {
+            assertThat(e.getCause().getMessage(),
+                    allOf(containsStringIgnoringCase("unrecognized"), containsString("foobar")));
+        }
+    }
+
+    @Test
+    public void charsetTest() throws _ObjectBuilderSettingEvaluationException, ClassNotFoundException,
+            InstantiationException, IllegalAccessException {
+        for (String timeZoneId : new String[] { "uTf-8", "GMT", "UTC" }) {
+            TestBean8 result = (TestBean8) _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean8(charset=Charset('iso-8859-1'))",
+                    TestBean8.class, false, new _SettingEvaluationEnvironment());
+            assertEquals(StandardCharsets.ISO_8859_1, result.getCharset());
+        }
+
+        try {
+            _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean8(charset=Charset('noSuchCS'))",
+                    TestBean8.class, false, new _SettingEvaluationEnvironment());
+            fail();
+        } catch (_ObjectBuilderSettingEvaluationException e) {
+            assertThat(e.getCause(), instanceOf(UnsupportedCharsetException.class));
+        }
+    }
+
+    @Test
+    public void configureBeanTest() throws Exception {
+        final TestBean7 bean = new TestBean7();
+        final String src = "a/b(s='foo', x=1, b=true), bar";
+        int nextPos = _ObjectBuilderSettingEvaluator.configureBean(src, src.indexOf('(') + 1, bean,
+                _SettingEvaluationEnvironment.getCurrent());
+        assertEquals("foo", bean.getS());
+        assertEquals(1, bean.getX());
+        assertTrue(bean.isB());
+        assertEquals(", bar", src.substring(nextPos));
+    }
+    
+    @Test
+    public void parsingErrors() throws Exception {
+        try {
+            _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1(1,,2)",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            fail();
+        } catch (_ObjectBuilderSettingEvaluationException e) {
+            assertThat(e.getMessage(), containsString("\",\""));
+        }
+
+        try {
+            _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1(x=1,2)",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            fail();
+        } catch (_ObjectBuilderSettingEvaluationException e) {
+            assertThat(e.getMessage(), containsStringIgnoringCase("must precede named"));
+        }
+
+
+        try {
+            _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1(x=1;2)",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            fail();
+        } catch (_ObjectBuilderSettingEvaluationException e) {
+            assertThat(e.getMessage(), containsString("\";\""));
+        }
+        
+        try {
+            _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1(1,2))",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            fail();
+        } catch (_ObjectBuilderSettingEvaluationException e) {
+            assertThat(e.getMessage(), containsString("\")\""));
+        }
+        
+        try {
+            _ObjectBuilderSettingEvaluator.eval(
+                    "foo.Bar('s${x}s'))",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            fail();
+        } catch (_ObjectBuilderSettingEvaluationException e) {
+            assertThat(e.getMessage(), containsString("${...}"));
+        }
+        
+        try {
+            _ObjectBuilderSettingEvaluator.eval(
+                    "foo.Bar('s#{x}s'))",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            fail();
+        } catch (_ObjectBuilderSettingEvaluationException e) {
+            assertThat(e.getMessage(), containsString("#{...}"));
+        }
+    }
+
+    @Test
+    public void semanticErrors() throws Exception {
+        try {
+            _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$XTestBean1(1,2)",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            fail();
+        } catch (_ObjectBuilderSettingEvaluationException e) {
+            assertThat(e.getMessage(), containsStringIgnoringCase("Failed to get class"));
+        }
+        
+        try {
+            _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1(true, 2)",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            fail();
+        } catch (_ObjectBuilderSettingEvaluationException e) {
+            assertThat(e.getMessage(), containsStringIgnoringCase("constructor"));
+        }
+        
+        try {
+            _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1(x = 1)",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            fail();
+        } catch (_ObjectBuilderSettingEvaluationException e) {
+            assertThat(e.getMessage(), containsStringIgnoringCase("no writeable JavaBeans property called \"x\""));
+        }
+        
+        try {
+            _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1(p1 = 1, p1 = 2)",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            fail();
+        } catch (_ObjectBuilderSettingEvaluationException e) {
+            assertThat(e.getMessage(), containsString("twice"));
+        }
+        
+        try {
+            _ObjectBuilderSettingEvaluator.eval(
+                    "java.util.HashMap()",
+                    ObjectWrapper.class, false, _SettingEvaluationEnvironment.getCurrent());
+            fail();
+        } catch (_ObjectBuilderSettingEvaluationException e) {
+            assertThat(e.getMessage(), containsString("is not a(n) " + ObjectWrapper.class.getName()));
+        }
+        
+        try {
+            _ObjectBuilderSettingEvaluator.eval(
+                    "null",
+                    ObjectWrapper.class, false, _SettingEvaluationEnvironment.getCurrent());
+            fail();
+        } catch (_ObjectBuilderSettingEvaluationException e) {
+            assertThat(e.getMessage(), containsString("can't be null"));
+        }
+    }
+    
+    @Test
+    public void testLiteralAsObjectBuilder() throws Exception {
+        assertNull(_ObjectBuilderSettingEvaluator.eval(
+                "null",
+                ObjectWrapper.class, true, _SettingEvaluationEnvironment.getCurrent()));
+        assertEquals("foo", _ObjectBuilderSettingEvaluator.eval(
+                "'foo'",
+                CharSequence.class, true, _SettingEvaluationEnvironment.getCurrent()));
+        assertEquals(Boolean.TRUE, _ObjectBuilderSettingEvaluator.eval(
+                "  true  ",
+                Object.class, true, _SettingEvaluationEnvironment.getCurrent()));
+        assertEquals(Double.valueOf("1.23"), _ObjectBuilderSettingEvaluator.eval(
+                "1.23 ",
+                Number.class, true, _SettingEvaluationEnvironment.getCurrent()));
+        assertEquals(new Version(1, 2, 3), _ObjectBuilderSettingEvaluator.eval(
+                " 1.2.3",
+                Object.class, true, _SettingEvaluationEnvironment.getCurrent()));
+    }
+
+    @Test
+    public void testNumberLiteralJavaTypes() throws Exception {
+        assertEquals(Double.valueOf("1.0"), _ObjectBuilderSettingEvaluator.eval(
+                "1.0",
+                Number.class, true, _SettingEvaluationEnvironment.getCurrent()));
+
+        assertEquals(new BigInteger("-9223372036854775809"), _ObjectBuilderSettingEvaluator.eval(
+                "-9223372036854775809",
+                Number.class, true, _SettingEvaluationEnvironment.getCurrent()));
+        assertEquals(new BigInteger("9223372036854775808"), _ObjectBuilderSettingEvaluator.eval(
+                "9223372036854775808",
+                Number.class, true, _SettingEvaluationEnvironment.getCurrent()));
+        
+        assertEquals(Long.valueOf(-9223372036854775808L), _ObjectBuilderSettingEvaluator.eval(
+                "-9223372036854775808",
+                Number.class, true, _SettingEvaluationEnvironment.getCurrent()));
+        assertEquals(Long.valueOf(9223372036854775807L), _ObjectBuilderSettingEvaluator.eval(
+                "9223372036854775807",
+                Number.class, true, _SettingEvaluationEnvironment.getCurrent()));
+        
+        assertEquals(Integer.valueOf(-2147483648), _ObjectBuilderSettingEvaluator.eval(
+                "-2147483648",
+                Number.class, true, _SettingEvaluationEnvironment.getCurrent()));
+        assertEquals(Integer.valueOf(2147483647), _ObjectBuilderSettingEvaluator.eval(
+                "2147483647",
+                Number.class, true, _SettingEvaluationEnvironment.getCurrent()));
+        
+        assertEquals(Integer.valueOf(-1), _ObjectBuilderSettingEvaluator.eval(
+                "-1",
+                Number.class, true, _SettingEvaluationEnvironment.getCurrent()));
+        assertEquals(Integer.valueOf(1), _ObjectBuilderSettingEvaluator.eval(
+                "1",
+                Number.class, true, _SettingEvaluationEnvironment.getCurrent()));
+    }
+    
+    @Test
+    public void testListLiterals() throws Exception {
+        {
+            ArrayList<Object> expected = new ArrayList();
+            expected.add("s");
+            expected.add(null);
+            expected.add(true);
+            expected.add(new TestBean9(1));
+            expected.add(ImmutableList.of(11, 22, 33));
+            assertEquals(expected, _ObjectBuilderSettingEvaluator.eval(
+                    "['s', null, true, org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean9(1), [11, 22, 33]]",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent()));
+            assertEquals(expected, _ObjectBuilderSettingEvaluator.eval(
+                    "  [  's'  ,  null ,  true , org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean9(1) ,"
+                    + "  [ 11 , 22 , 33 ]  ]  ",
+                    Collection.class, false, _SettingEvaluationEnvironment.getCurrent()));
+            assertEquals(expected, _ObjectBuilderSettingEvaluator.eval(
+                    "['s',null,true,org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean9(1),[11,22,33]]",
+                    List.class, false, _SettingEvaluationEnvironment.getCurrent()));
+        }
+        
+        assertEquals(Collections.emptyList(), _ObjectBuilderSettingEvaluator.eval(
+                "[]",
+                Object.class, false, _SettingEvaluationEnvironment.getCurrent()));
+        assertEquals(Collections.emptyList(), _ObjectBuilderSettingEvaluator.eval(
+                "[  ]",
+                Object.class, false, _SettingEvaluationEnvironment.getCurrent()));
+
+        assertEquals(Collections.singletonList(123), _ObjectBuilderSettingEvaluator.eval(
+                "[123]",
+                Object.class, false, _SettingEvaluationEnvironment.getCurrent()));
+        assertEquals(Collections.singletonList(123), _ObjectBuilderSettingEvaluator.eval(
+                "[ 123 ]",
+                Object.class, false, _SettingEvaluationEnvironment.getCurrent()));
+        
+        assertEquals(new TestBean9(1, ImmutableList.of("a", "b")), _ObjectBuilderSettingEvaluator.eval(
+                "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean9(1, ['a', 'b'])",
+                Object.class, false, _SettingEvaluationEnvironment.getCurrent()));
+        
+        try {
+            _ObjectBuilderSettingEvaluator.eval(
+                    "[1,]",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            fail();
+        } catch (_ObjectBuilderSettingEvaluationException e) {
+            assertThat(e.getMessage(), containsString("found character \"]\""));
+        }
+        try {
+            _ObjectBuilderSettingEvaluator.eval(
+                    "[,1]",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            fail();
+        } catch (_ObjectBuilderSettingEvaluationException e) {
+            assertThat(e.getMessage(), containsString("found character \",\""));
+        }
+        try {
+            _ObjectBuilderSettingEvaluator.eval(
+                    "1]",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            fail();
+        } catch (_ObjectBuilderSettingEvaluationException e) {
+            assertThat(e.getMessage(), containsString("found character \"]\""));
+        }
+        try {
+            _ObjectBuilderSettingEvaluator.eval(
+                    "[1",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            fail();
+        } catch (_ObjectBuilderSettingEvaluationException e) {
+            assertThat(e.getMessage(), containsString("end of"));
+        }
+    }
+
+    @Test
+    public void testMapLiterals() throws Exception {
+        {
+            HashMap<String, Object> expected = new HashMap();
+            expected.put("k1", "s");
+            expected.put("k2", null);
+            expected.put("k3", true);
+            expected.put("k4", new TestBean9(1));
+            expected.put("k5", ImmutableList.of(11, 22, 33));
+            assertEquals(expected, _ObjectBuilderSettingEvaluator.eval(
+                    "{'k1': 's', 'k2': null, 'k3': true, "
+                    + "'k4': org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean9(1), 'k5': [11, 22, 33]}",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent()));
+            assertEquals(expected, _ObjectBuilderSettingEvaluator.eval(
+                    " {  'k1'  :  's'  ,  'k2' :  null  , 'k3' : true , "
+                    + "'k4' : org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean9 ( 1 ) , 'k5' : [ 11 , 22 , 33 ] } ",
+                    Map.class, false, _SettingEvaluationEnvironment.getCurrent()));
+            assertEquals(expected, _ObjectBuilderSettingEvaluator.eval(
+                    " {'k1':'s','k2':null,'k3':true,"
+                    + "'k4':org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean9(1),'k5':[11,22,33]}",
+                    LinkedHashMap.class, false, _SettingEvaluationEnvironment.getCurrent()));
+        }
+        
+        {
+            HashMap<Object, String> expected = new HashMap();
+            expected.put(true, "T");
+            expected.put(1, "O");
+            expected.put(new TestBean9(1), "B");
+            expected.put(ImmutableList.of(11, 22, 33), "L");
+            assertEquals(expected, _ObjectBuilderSettingEvaluator.eval(
+                    "{ true: 'T', 1: 'O', org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean9(1): 'B', "
+                    + "[11, 22, 33]: 'L' }",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent()));
+        }
+        
+        assertEquals(Collections.emptyMap(), _ObjectBuilderSettingEvaluator.eval(
+                "{}",
+                Object.class, false, _SettingEvaluationEnvironment.getCurrent()));
+        assertEquals(Collections.emptyMap(), _ObjectBuilderSettingEvaluator.eval(
+                "{  }",
+                Object.class, false, _SettingEvaluationEnvironment.getCurrent()));
+
+        assertEquals(Collections.singletonMap("k1", 123), _ObjectBuilderSettingEvaluator.eval(
+                "{'k1':123}",
+                Object.class, false, _SettingEvaluationEnvironment.getCurrent()));
+        assertEquals(Collections.singletonMap("k1", 123), _ObjectBuilderSettingEvaluator.eval(
+                "{ 'k1' : 123 }",
+                Object.class, false, _SettingEvaluationEnvironment.getCurrent()));
+        
+        assertEquals(new TestBean9(1, ImmutableMap.of(11, "a", 22, "b")), _ObjectBuilderSettingEvaluator.eval(
+                "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean9(1, { 11: 'a', 22: 'b' })",
+                Object.class, false, _SettingEvaluationEnvironment.getCurrent()));
+        
+        try {
+            _ObjectBuilderSettingEvaluator.eval(
+                    "{1:2,}",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            fail();
+        } catch (_ObjectBuilderSettingEvaluationException e) {
+            assertThat(e.getMessage(), containsString("found character \"}\""));
+        }
+        try {
+            _ObjectBuilderSettingEvaluator.eval(
+                    "{,1:2}",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            fail();
+        } catch (_ObjectBuilderSettingEvaluationException e) {
+            assertThat(e.getMessage(), containsString("found character \",\""));
+        }
+        try {
+            _ObjectBuilderSettingEvaluator.eval(
+                    "1:2}",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            fail();
+        } catch (_ObjectBuilderSettingEvaluationException e) {
+            assertThat(e.getMessage(), containsString("found character \":\""));
+        }
+        try {
+            _ObjectBuilderSettingEvaluator.eval(
+                    "1}",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            fail();
+        } catch (_ObjectBuilderSettingEvaluationException e) {
+            assertThat(e.getMessage(), containsString("found character \"}\""));
+        }
+        try {
+            _ObjectBuilderSettingEvaluator.eval(
+                    "{1",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            fail();
+        } catch (_ObjectBuilderSettingEvaluationException e) {
+            assertThat(e.getMessage(), containsString("end of"));
+        }
+        try {
+            _ObjectBuilderSettingEvaluator.eval(
+                    "{1:",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            fail();
+        } catch (_ObjectBuilderSettingEvaluationException e) {
+            assertThat(e.getMessage(), containsString("end of"));
+        }
+        try {
+            _ObjectBuilderSettingEvaluator.eval(
+                    "{null:1}",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            fail();
+        } catch (_ObjectBuilderSettingEvaluationException e) {
+            assertThat(e.getMessage(), containsString("null as key"));
+        }
+    }
+
+    @Test
+    public void testMethodParameterNumberTypes() throws Exception {
+        {
+            TestBean8 result = (TestBean8) _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean8(anyObject=1)",
+                    TestBean8.class, false, new _SettingEvaluationEnvironment());
+            assertEquals(result.getAnyObject(), 1);
+        }
+        {
+            TestBean8 result = (TestBean8) _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean8(anyObject=2147483649)",
+                    TestBean8.class, false, new _SettingEvaluationEnvironment());
+            assertEquals(result.getAnyObject(), 2147483649L);
+        }
+        {
+            TestBean8 result = (TestBean8) _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean8(anyObject=1.0)",
+                    TestBean8.class, false, new _SettingEvaluationEnvironment());
+            // Like in FTL, non-integer numbers are BigDecimal-s, that are later coerced to the actual parameter type.
+            // However, here the type is Object, so it remains BigDecimal.
+            assertEquals(new BigDecimal("1.0"), result.getAnyObject());
+        }
+    }
+    
+    @Test
+    public void testNonMethodParameterNumberTypes() throws Exception {
+        assertEqualsEvaled(Integer.valueOf(1), "1");
+        assertEqualsEvaled(Double.valueOf(1), "1.0");
+        assertEqualsEvaled(Long.valueOf(2147483649l), "2147483649");
+
+        assertEqualsEvaled(Double.valueOf(1), "1d");
+        assertEqualsEvaled(Double.valueOf(1), "1D");
+        assertEqualsEvaled(Float.valueOf(1), "1f");
+        assertEqualsEvaled(Float.valueOf(1), "1F");
+        assertEqualsEvaled(Long.valueOf(1), "1l");
+        assertEqualsEvaled(Long.valueOf(1), "1L");
+        assertEqualsEvaled(BigDecimal.valueOf(1), "1bd");
+        assertEqualsEvaled(BigDecimal.valueOf(1), "1Bd");
+        assertEqualsEvaled(BigDecimal.valueOf(1), "1BD");
+        assertEqualsEvaled(BigInteger.valueOf(1), "1bi");
+        assertEqualsEvaled(BigInteger.valueOf(1), "1bI");
+        
+        assertEqualsEvaled(Float.valueOf(1.5f), "1.5f");
+        assertEqualsEvaled(Double.valueOf(1.5), "1.5d");
+        assertEqualsEvaled(BigDecimal.valueOf(1.5), "1.5bd");
+        
+        assertEqualsEvaled(
+                ImmutableList.of(-1, -0.5, new BigDecimal("-0.1")),
+                "[ -1, -0.5, -0.1bd ]");
+        assertEqualsEvaled(
+                ImmutableMap.of(-1, -11, -0.5, -0.55, new BigDecimal("-0.1"), new BigDecimal("-0.11")),
+                "{ -1: -11, -0.5: -0.55, -0.1bd: -0.11bd }");
+    }
+    
+    @Test
+    public void testStaticFields() throws Exception {
+        {
+            TestBean1 res = (TestBean1) _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1("
+                    + "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestStaticFields.CONST, true)",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            assertEquals(TestStaticFields.CONST, (int) res.i);
+        }
+        {
+            TestBean1 res = (TestBean1) _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1("
+                    + "p2 = org.apache.freemarker.core.ObjectBuilderSettingsTest$TestStaticFields.CONST)",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            assertEquals(TestStaticFields.CONST, res.getP2());
+        }
+        assertEqualsEvaled(123, "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestStaticFields.CONST");
+        
+        // With shorthand class name:
+        assertEqualsEvaled(ParsingConfiguration.AUTO_DETECT_TAG_SYNTAX, "Configuration.AUTO_DETECT_TAG_SYNTAX");
+        
+        try {
+            _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean1("
+                    + "p2 = org.apache.freemarker.core.ObjectBuilderSettingsTest$TestStaticFields.CONST())",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            fail();
+        } catch (_ObjectBuilderSettingEvaluationException e) {
+            assertThat(e.getMessage(),
+                    containsString("org.apache.freemarker.core.ObjectBuilderSettingsTest$TestStaticFields.CONST"));
+        }
+        try {
+            assertEqualsEvaled(123, "org.apache.freemarker.core.ObjectBuilderSettingsTest$TestStaticFields.CONST()");
+            fail();
+        } catch (_ObjectBuilderSettingEvaluationException e) {
+            assertThat(e.getMessage(),
+                    containsString("org.apache.freemarker.core.ObjectBuilderSettingsTest$TestStaticFields.CONST"));
+        }
+        try {
+            assertEqualsEvaled(123, "java.lang.String(org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean5.INSTANCE)");
+            fail();
+        } catch (_ObjectBuilderSettingEvaluationException e) {
+            assertThat(e.getMessage(),
+                    containsString("org.apache.freemarker.core.ObjectBuilderSettingsTest$TestBean5()"));
+        }
+    }
+    
+    private void assertEqualsEvaled(Object expectedValue, String s)
+            throws _ObjectBuilderSettingEvaluationException, ClassNotFoundException, InstantiationException,
+            IllegalAccessException {
+        Object actualValue = _ObjectBuilderSettingEvaluator.eval(
+                s, Object.class, true, _SettingEvaluationEnvironment.getCurrent());
+        assertEquals(expectedValue, actualValue);
+    }
+    
+    @Test
+    public void visibilityTest() throws Exception {
+        try {
+            _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.userpkg.PackageVisibleAll()",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            fail();
+        } catch (_ObjectBuilderSettingEvaluationException e) {
+            assertEquals(IllegalAccessException.class, e.getCause().getClass());
+        }
+
+        try {
+            _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.userpkg.PackageVisibleWithPublicConstructor()",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            fail();
+        } catch (_ObjectBuilderSettingEvaluationException e) {
+            assertEquals(IllegalAccessException.class, e.getCause().getClass());
+        }
+
+        try {
+            _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.userpkg.PublicWithPackageVisibleConstructor()",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            fail();
+        } catch (_ObjectBuilderSettingEvaluationException e) {
+            assertEquals(IllegalAccessException.class, e.getCause().getClass());
+        }
+        
+        {
+            Object o = _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.userpkg.PublicAll()",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            assertEquals(org.apache.freemarker.core.userpkg.PublicAll.class, o.getClass());
+        }
+        
+        {
+            Object o = _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.userpkg.PublicWithMixedConstructors(1)",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            assertEquals("Integer", ((PublicWithMixedConstructors) o).getS());
+        }
+        
+        
+        {
+            Object o = _ObjectBuilderSettingEvaluator.eval(
+                    "org.apache.freemarker.core.userpkg.PackageVisibleAllWithBuilder()",
+                    Object.class, false, _SettingEvaluationEnvironment.getCurrent());
+            assertEquals("org.apache.freemarker.core.userpkg.PackageVisibleAllWithBuilder", o.getClass().getName());
+        }
+    }
+
+    public static class TestBean1 {
+        float f;
+        Integer i;
+        long l;
+        boolean b;
+        
+        double p1;
+        int p2;
+        boolean p3;
+        String p4;
+        
+        public TestBean1(float f, Integer i, long l, boolean b) {
+            this.f = f;
+            this.i = i;
+            this.l = l;
+            this.b = b;
+        }
+        
+        public TestBean1(Integer i, boolean b) {
+            f = 2;
+            this.i = i;
+            l = 2;
+            this.b = b;
+        }
+    
+        public TestBean1(Integer i, long l) {
+            f = 3;
+            this.i = i;
+            this.l = l;
+            b = false;
+        }
+        
+        public TestBean1() {
+            f = 4;
+        }
+    
+        public double getP1() {
+            return p1;
+        }
+    
+        public void setP1(double p1) {
+            this.p1 = p1;
+        }
+    
+        public int getP2() {
+            return p2;
+        }
+    
+        public void setP2(int p2) {
+            this.p2 = p2;
+        }
+    
+        public boolean isP3() {
+            return p3;
+        }
+    
+        public void setP3(boolean p3) {
+            this.p3 = p3;
+        }
+
+        public String getP4() {
+            return p4;
+        }
+
+        public void setP4(String p4) {
+            this.p4 = p4;
+        }
+        
+    }
+    
+    public static class TestBean2 {
+        final boolean built;
+        final int x;
+
+        public TestBean2() {
+            built = false;
+            x = 0;
+        }
+        
+        public TestBean2(int x) {
+            built = false;
+            this.x = x;
+        }
+
+        public TestBean2(TestBean2Builder builder) {
+            built = true;
+            x = builder.x;
+        }
+        
+    }
+
+    public static class TestBean2Builder {
+        int x;
+        
+        public TestBean2Builder() { }
+
+        public TestBean2Builder(int x) {
+            this.x = x;
+        }
+        
+        public int getX() {
+            return x;
+        }
+
+        public void setX(int x) {
+            this.x = x;
+        }
+        
+        public TestBean2 build() {
+            return new TestBean2(this);
+        }
+        
+    }
+
+    public static class TestBean3 {
+        
+        private int x;
+
+        public int getX() {
+            return x;
+        }
+
+        public void setX(int x) {
+            this.x = x;
+        }
+        
+    }
+    
+    public static class TestBean4 {
+        private final String s1, s2;
+        private String s3, s4;
+        
+        public TestBean4(String s1, String s2) {
+            this.s1 = s1;
+            this.s2 = s2;
+        }
+        
+        public String getS1() {
+            return s1;
+        }
+
+        public String getS2() {
+            return s2;
+        }
+
+        public String getS3() {
+            return s3;
+        }
+        
+        public void setS3(String s3) {
+            this.s3 = s3;
+        }
+        
+        public String getS4() {
+            return s4;
+        }
+        
+        public void setS4(String s4) {
+            this.s4 = s4;
+        }
+        
+    }
+    
+    public static class TestBean5 {
+        
+        public final static TestBean5 INSTANCE = new TestBean5();
+        
+        private final int i;
+        private int x;
+        
+        public TestBean5() {
+            i = 0;
+        }
+
+        public TestBean5(int i) {
+            this.i = i;
+        }
+
+        public int getI() {
+            return i;
+        }
+
+        public int getX() {
+            return x;
+        }
+
+        public void setX(int x) {
+            this.x = x;
+        }
+        
+    }
+
+    public static class TestBean6 {
+        private final TestBean1 b1;
+        private int x;
+        private final TestBean2 b2;
+        private int y;
+        private TestBean2 b3;
+        private TestBean6 b4;
+        
+        public TestBean6(TestBean1 b1, int x, TestBean2 b2) {
+            this.b1 = b1;
+            this.x = x;
+            this.b2 = b2;
+        }
+
+        public int getX() {
+            return x;
+        }
+
+        public void setX(int x) {
+            this.x = x;
+        }
+
+        public int getY() {
+            return y;
+        }
+
+        public void setY(int y) {
+            this.y = y;
+        }
+
+        public TestBean2 getB3() {
+            return b3;
+        }
+
+        public void setB3(TestBean2 b3) {
+            this.b3 = b3;
+        }
+
+        public TestBean1 getB1() {
+            return b1;
+        }
+
+        public TestBean2 getB2() {
+            return b2;
+        }
+
+        public TestBean6 getB4() {
+            return b4;
+        }
+
+        public void setB4(TestBean6 b4) {
+            this.b4 = b4;
+        }
+        
+    }
+    
+    public class TestBean7 {
+
+        private String s;
+        private int x;
+        private boolean b;
+
+        public String getS() {
+            return s;
+        }
+
+        public void setS(String s) {
+            this.s = s;
+        }
+
+        public int getX() {
+            return x;
+        }
+
+        public void setX(int x) {
+            this.x = x;
+        }
+
+        public boolean isB() {
+            return b;
+        }
+
+        public void setB(boolean b) {
+            this.b = b;
+        }
+
+        @Override
+        public String toString() {
+            return "TestBean [s=" + s + ", x=" + x + ", b=" + b + "]";
+        }
+
+    }
+    
+    public static class TestBean8 {
+        private TimeZone timeZone;
+        private Charset charset;
+        private Object anyObject;
+        private List<?> list;
+        
+        public TimeZone getTimeZone() {
+            return timeZone;
+        }
+        
+        public void setTimeZone(TimeZone timeZone) {
+            this.timeZone = timeZone;
+        }
+
+        public Charset getCharset() {
+            return charset;
+        }
+
+        public void setCharset(Charset charset) {
+            this.charset = charset;
+        }
+
+        public Object getAnyObject() {
+            return anyObject;
+        }
+        
+        public void setAnyObject(Object anyObject) {
+            this.anyObject = anyObject;
+        }
+
+        public List<?> getList() {
+            return list;
+        }
+        
+        public void setList(List<?> list) {
+            this.list = list;
+        }
+        
+    }
+    
+    public static class TestBean9 {
+        
+        private final int n;
+        private final List<?> list;
+        private final Map<?, ?> map;
+
+        public TestBean9(int n) {
+            this(n, null, null);
+        }
+
+        public TestBean9(int n, List<?> list) {
+            this(n, list, null);
+        }
+
+        public TestBean9(int n, Map<?, ?> map) {
+            this(n, null, map);
+        }
+        
+        public TestBean9(int n, List<?> list, Map<?, ?> map) {
+            this.n = n;
+            this.list = list;
+            this.map = map;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((list == null) ? 0 : list.hashCode());
+            result = prime * result + ((map == null) ? 0 : map.hashCode());
+            result = prime * result + n;
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) return true;
+            if (obj == null) return false;
+            if (getClass() != obj.getClass()) return false;
+            TestBean9 other = (TestBean9) obj;
+            if (list == null) {
+                if (other.list != null) return false;
+            } else if (!list.equals(other.list)) return false;
+            if (map == null) {
+                if (other.map != null) return false;
+            } else if (!map.equals(other.map)) return false;
+            return n == other.n;
+        }
+        
+    }
+    
+    public static class TestStaticFields {
+        public static final int CONST = 123;
+    }
+    
+    public static class DummyArithmeticEngine extends ArithmeticEngine {
+        
+        private int x;
+
+        @Override
+        public int compareNumbers(Number first, Number second) throws TemplateException {
+            return 0;
+        }
+
+        @Override
+        public Number add(Number first, Number second) throws TemplateException {
+            return null;
+        }
+
+        @Override
+        public Number subtract(Number first, Number second) throws TemplateException {
+            return null;
+        }
+
+        @Override
+        public Number multiply(Number first, Number second) throws TemplateException {
+            return null;
+        }
+
+        @Override
+        public Number divide(Number first, Number second) throws TemplateException {
+            return null;
+        }
+
+        @Override
+        public Number modulus(Number first, Number second) throws TemplateException {
+            return null;
+        }
+
+        @Override
+        public Number toNumber(String s) {
+            return null;
+        }
+
+        public int getX() {
+            return x;
+        }
+
+        public void setX(int x) {
+            this.x = x;
+        }
+        
+    }
+    
+    public static class DummyTemplateExceptionHandler implements TemplateExceptionHandler {
+        
+        private int x;
+
+        @Override
+        public void handleTemplateException(TemplateException te, Environment env, Writer out) throws TemplateException {
+        }
+
+        public int getX() {
+            return x;
+        }
+
+        public void setX(int x) {
+            this.x = x;
+        }
+        
+    }
+    
+    public static class DummyCacheStorage implements CacheStorage {
+        
+        @Override
+        public Object get(Object key) {
+            return null;
+        }
+
+        @Override
+        public void put(Object key, Object value) {
+        }
+
+        @Override
+        public void remove(Object key) {
+        }
+
+        @Override
+        public void clear() {
+        }
+        
+    }
+    
+    public static class DummyNewBuiltinClassResolver implements TemplateClassResolver {
+
+        @Override
+        public Class resolve(String className, Environment env, Template template) throws TemplateException {
+            return null;
+        }
+        
+    }
+    
+    public static class DummyTemplateLoader implements TemplateLoader {
+
+        @Override
+        public TemplateLoaderSession createSession() {
+            return null;
+        }
+
+        @Override
+        public TemplateLoadingResult load(String name, TemplateLoadingSource ifSourceDiffersFrom,
+                Serializable ifVersionDiffersFrom, TemplateLoaderSession session) throws IOException {
+            return TemplateLoadingResult.NOT_FOUND;
+        }
+
+        @Override
+        public void resetState() {
+            // Do nothing
+        }
+        
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/OptInTemplateClassResolverTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/OptInTemplateClassResolverTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/OptInTemplateClassResolverTest.java
new file mode 100644
index 0000000..06e863c
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/OptInTemplateClassResolverTest.java
@@ -0,0 +1,230 @@
+/*
+ * 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.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.freemarker.core.util.OptInTemplateClassResolver;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+
+public class OptInTemplateClassResolverTest extends TestCase {
+
+    public OptInTemplateClassResolverTest(String name) {
+        super(name);
+    }
+    
+    private static final Set ALLOWED_CLASSES = new HashSet();
+    static {
+        ALLOWED_CLASSES.add("java.lang.String");
+        ALLOWED_CLASSES.add("java.lang.Integer");
+    }
+    
+    private static final List TRUSTED_TEMPLATES = new ArrayList();
+    static {
+        TRUSTED_TEMPLATES.add("lib/*");
+        TRUSTED_TEMPLATES.add("/include/*");
+        TRUSTED_TEMPLATES.add("trusted.ftl");
+    }
+    
+    private OptInTemplateClassResolver resolver = new OptInTemplateClassResolver(
+            ALLOWED_CLASSES, TRUSTED_TEMPLATES);
+    
+
+    public void testOptIn() throws TemplateException {
+        Template dummyTemp = Template.createPlainTextTemplate("foo.ftl", "",
+                new TestConfigurationBuilder().build());
+
+        assertEquals(String.class, resolver.resolve("java.lang.String", null, dummyTemp));
+        assertEquals(Integer.class, resolver.resolve("java.lang.Integer", null, dummyTemp));
+        try {
+            resolver.resolve("java.lang.Long", null, dummyTemp);
+            fail();
+        } catch (TemplateException e) {
+            // Expected
+        }
+    }
+
+    public void testTrusted() throws TemplateException {
+        Configuration cfg = new TestConfigurationBuilder().build();
+
+        assertEquals(Long.class, resolver.resolve("java.lang.Long", null,
+                Template.createPlainTextTemplate("lib/foo.ftl", "", cfg)));
+        assertEquals(String.class, resolver.resolve("java.lang.String", null,
+                Template.createPlainTextTemplate("lib/foo.ftl", "", cfg)));
+        assertEquals(Long.class, resolver.resolve("java.lang.Long", null,
+                Template.createPlainTextTemplate("/lib/foo.ftl", "", cfg)));
+        assertEquals(Long.class, resolver.resolve("java.lang.Long", null,
+                Template.createPlainTextTemplate("include/foo.ftl", "", cfg)));
+        assertEquals(Long.class, resolver.resolve("java.lang.Long", null,
+                Template.createPlainTextTemplate("trusted.ftl", "", cfg)));
+        assertEquals(Long.class, resolver.resolve("java.lang.Long", null,
+                Template.createPlainTextTemplate("/trusted.ftl", "", cfg)));
+    }
+
+    public void testCraftedTrusted() throws TemplateException {
+        testTrusted_checkFails("lib/../foo.ftl");
+        testTrusted_checkFails("lib\\..\\foo.ftl");
+        testTrusted_checkFails("lib\\../foo.ftl");
+        testTrusted_checkFails("lib/..\\foo.ftl");
+        testTrusted_checkFails("lib/..");
+        testTrusted_checkFails("lib%2f%2E%2e%5cfoo.ftl");
+        testTrusted_checkFails("/lib%5C%.%2e%2Efoo.ftl");
+        
+        try {
+            testTrusted_checkFails("lib/./foo.ftl");
+            fail();
+        } catch (AssertionFailedError e) {
+            // Expected
+        }
+        try {
+            testTrusted_checkFails("lib/foo..ftl");
+            fail();
+        } catch (AssertionFailedError e) {
+            // Expected
+        }
+        try {
+            testTrusted_checkFails("lib/%2e/foo.ftl");
+            fail();
+        } catch (AssertionFailedError e) {
+            // Expected
+        }
+    }
+    
+    public void testTrusted_checkFails(String templateName) {
+        try {
+            resolver.resolve("java.lang.Long", null,
+                    Template.createPlainTextTemplate(templateName, "",
+                            new TestConfigurationBuilder().build()));
+            fail();
+        } catch (TemplateException e) {
+            // Expected
+        }
+    }
+    
+    public void testSettingParser() throws Exception {
+        {
+            Configuration cfg = new TestConfigurationBuilder()
+                    .setting(
+                            "new_builtin_class_resolver",
+                            "trusted_templates: foo.ftl, \"lib/*\"")
+                    .build();
+
+            TemplateClassResolver res = cfg.getNewBuiltinClassResolver();
+            assertEquals(String.class, res.resolve("java.lang.String", null,
+                    Template.createPlainTextTemplate("foo.ftl", "", cfg)));
+            assertEquals(String.class, res.resolve("java.lang.String", null,
+                    Template.createPlainTextTemplate("lib/bar.ftl", "", cfg)));
+            try {
+                res.resolve("java.lang.String", null,
+                        Template.createPlainTextTemplate("bar.ftl", "", cfg));
+                fail();
+            } catch (TemplateException e) {
+                // Expected
+            }
+        }
+
+        {
+            Configuration cfg = new TestConfigurationBuilder()
+                    .setting(
+                            "new_builtin_class_resolver",
+                            "allowed_classes: java.lang.String, java.lang.Integer")
+                    .build();
+
+            TemplateClassResolver res = cfg.getNewBuiltinClassResolver();
+            assertEquals(String.class, res.resolve("java.lang.String", null,
+                    Template.createPlainTextTemplate("foo.ftl", "", cfg)));
+            assertEquals(Integer.class, res.resolve("java.lang.Integer", null,
+                    Template.createPlainTextTemplate("foo.ftl", "", cfg)));
+            try {
+                res.resolve("java.lang.Long", null,
+                        Template.createPlainTextTemplate("foo.ftl", "", cfg));
+                fail();
+            } catch (TemplateException e) {
+                // good
+            }
+        }
+
+        {
+            Configuration cfg = new TestConfigurationBuilder()
+                    .setting(
+                            "new_builtin_class_resolver",
+                            "trusted_templates: foo.ftl, 'lib/*', allowed_classes: 'java.lang.String',"
+                            + " java.lang.Integer")
+                    .build();
+            TemplateClassResolver res = cfg.getNewBuiltinClassResolver();
+            assertEquals(String.class, res.resolve("java.lang.String", null,
+                    Template.createPlainTextTemplate("x.ftl", "", cfg)));
+            assertEquals(Integer.class, res.resolve("java.lang.Integer", null,
+                    Template.createPlainTextTemplate("x.ftl", "", cfg)));
+            try {
+                res.resolve("java.lang.Long", null,
+                        Template.createPlainTextTemplate("x.ftl", "", cfg));
+                fail();
+            } catch (TemplateException e) {
+                // Expected
+            }
+            assertEquals(Long.class, res.resolve("java.lang.Long", null,
+                    Template.createPlainTextTemplate("foo.ftl", "", cfg)));
+            assertEquals(Long.class, res.resolve("java.lang.Long", null,
+                    Template.createPlainTextTemplate("lib/bar.ftl", "", cfg)));
+            try {
+                res.resolve("java.lang.Long", null,
+                        Template.createPlainTextTemplate("x.ftl", "", cfg));
+                fail();
+            } catch (TemplateException e) {
+                // Expected
+            }
+        }
+        
+        try {
+            new TestConfigurationBuilder().setSetting("new_builtin_class_resolver", "wrong: foo");
+            fail();
+        } catch (ConfigurationException e) {
+            // Expected
+        }
+
+        {
+            Configuration cfg = new TestConfigurationBuilder()
+                    .setting(
+                            "new_builtin_class_resolver",
+                            "\"allowed_classes\"  :  java.lang.String  ,  'trusted_templates' :\"lib:*\"")
+                    .build();
+            TemplateClassResolver res = cfg.getNewBuiltinClassResolver();
+            assertEquals(String.class, res.resolve("java.lang.String", null,
+                    Template.createPlainTextTemplate("x.ftl", "", cfg)));
+            try {
+                res.resolve("java.lang.Long", null,
+                        Template.createPlainTextTemplate("x.ftl", "", cfg));
+                fail();
+            } catch (TemplateException e) {
+                // Expected
+            }
+            assertEquals(Long.class, res.resolve("java.lang.Long", null,
+                    Template.createPlainTextTemplate("lib:bar.ftl", "", cfg)));
+        }
+    }
+    
+}


[10/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/PrintfGTemplateNumberFormatFactory.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/PrintfGTemplateNumberFormatFactory.java b/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/PrintfGTemplateNumberFormatFactory.java
deleted file mode 100644
index e8d5f2b..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/PrintfGTemplateNumberFormatFactory.java
+++ /dev/null
@@ -1,138 +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.userpkg;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.Locale;
-
-import org.apache.freemarker.core.Environment;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateNumberModel;
-import org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat;
-import org.apache.freemarker.core.util._StringUtil;
-import org.apache.freemarker.core.valueformat.InvalidFormatParametersException;
-import org.apache.freemarker.core.valueformat.TemplateFormatUtil;
-import org.apache.freemarker.core.valueformat.TemplateNumberFormat;
-import org.apache.freemarker.core.valueformat.TemplateNumberFormatFactory;
-import org.apache.freemarker.core.valueformat.UnformattableValueException;
-
-/**
- * Formats like {@code %G} in {@code printf}, with the specified number of significant digits. Also has special
- * formatter for HTML output format, where it uses the HTML "sup" element for exponents.
- */
-public class PrintfGTemplateNumberFormatFactory extends TemplateNumberFormatFactory {
-
-    public static final PrintfGTemplateNumberFormatFactory INSTANCE = new PrintfGTemplateNumberFormatFactory();
-    
-    private PrintfGTemplateNumberFormatFactory() {
-        // Defined to decrease visibility
-    }
-    
-    @Override
-    public TemplateNumberFormat get(String params, Locale locale, Environment env)
-            throws InvalidFormatParametersException {
-        Integer significantDigits;
-        if (!params.isEmpty()) {
-            try {
-                significantDigits = Integer.valueOf(params);
-            } catch (NumberFormatException e) {
-                throw new InvalidFormatParametersException(
-                        "The format parameter must be an integer, but was (shown quoted) "
-                        + _StringUtil.jQuote(params) + ".");
-            }
-        } else {
-            // Use the default of %G
-            significantDigits = null;
-        }
-        return new PrintfGTemplateNumberFormat(significantDigits, locale);
-    }
-
-    private static class PrintfGTemplateNumberFormat extends TemplateNumberFormat {
-        
-        private final Locale locale;
-        private final String printfFormat; 
-
-        private PrintfGTemplateNumberFormat(Integer significantDigits, Locale locale) {
-            printfFormat = "%" + (significantDigits != null ? "." + significantDigits : "") + "G";
-            this.locale = locale;
-        }
-        
-        @Override
-        public String formatToPlainText(TemplateNumberModel numberModel)
-                throws UnformattableValueException, TemplateModelException {
-            final Number n = TemplateFormatUtil.getNonNullNumber(numberModel);
-            
-            // printf %G only accepts Double, BigDecimal and Float 
-            final Number gCompatibleN;
-            if (n instanceof Double  || n instanceof BigDecimal || n instanceof Float) {
-                gCompatibleN = n;
-            } else {
-                if (n instanceof BigInteger) {
-                    gCompatibleN = new BigDecimal((BigInteger) n);                        
-                } else if (n instanceof Long) {
-                    gCompatibleN = BigDecimal.valueOf(n.longValue());
-                } else {
-                    gCompatibleN = Double.valueOf(n.doubleValue());
-                }
-            }
-            
-            return String.format(locale, printfFormat, gCompatibleN);
-        }
-
-        @Override
-        public Object format(TemplateNumberModel numberModel)
-                throws UnformattableValueException, TemplateModelException {
-            String strResult = formatToPlainText(numberModel);
-            
-            int expIdx = strResult.indexOf('E');
-            if (expIdx == -1) {
-                return strResult;
-            }
-                
-            String expStr = strResult.substring(expIdx + 1);
-            int expSignifNumBegin = 0;
-            while (expSignifNumBegin < expStr.length() && isExpSignifNumPrefix(expStr.charAt(expSignifNumBegin))) {
-                expSignifNumBegin++;
-            }
-            
-            return HTMLOutputFormat.INSTANCE.fromMarkup(
-                    strResult.substring(0, expIdx)
-                    + "*10<sup>"
-                    + (expStr.charAt(0) == '-' ? "-" : "") + expStr.substring(expSignifNumBegin)
-                    + "</sup>");
-        }
-
-        private boolean isExpSignifNumPrefix(char c) {
-            return c == '+' || c == '-' || c == '0';
-        }
-
-        @Override
-        public boolean isLocaleBound() {
-            return true;
-        }
-
-        @Override
-        public String getDescription() {
-            return "printf " + printfFormat;
-        }
-        
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/PublicAll.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/PublicAll.java b/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/PublicAll.java
deleted file mode 100644
index 5767e93..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/PublicAll.java
+++ /dev/null
@@ -1,24 +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.userpkg;
-
-public class PublicAll {
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/PublicWithMixedConstructors.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/PublicWithMixedConstructors.java b/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/PublicWithMixedConstructors.java
deleted file mode 100644
index e521d75..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/PublicWithMixedConstructors.java
+++ /dev/null
@@ -1,38 +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.userpkg;
-
-public class PublicWithMixedConstructors {
-    
-    private final String s;
-
-    public PublicWithMixedConstructors(Integer x) {
-        s = "Integer";
-    }
-
-    PublicWithMixedConstructors(int x) {
-        s = "int";
-    }
-
-    public String getS() {
-        return s;
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/PublicWithPackageVisibleConstructor.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/PublicWithPackageVisibleConstructor.java b/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/PublicWithPackageVisibleConstructor.java
deleted file mode 100644
index 9fdec49..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/PublicWithPackageVisibleConstructor.java
+++ /dev/null
@@ -1,26 +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.userpkg;
-
-public class PublicWithPackageVisibleConstructor {
-
-    PublicWithPackageVisibleConstructor() { }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/SeldomEscapedOutputFormat.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/SeldomEscapedOutputFormat.java b/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/SeldomEscapedOutputFormat.java
deleted file mode 100644
index b8cab13..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/SeldomEscapedOutputFormat.java
+++ /dev/null
@@ -1,71 +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.userpkg;
-
-import java.io.IOException;
-import java.io.Writer;
-
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.outputformat.CommonMarkupOutputFormat;
-
-public class SeldomEscapedOutputFormat extends CommonMarkupOutputFormat<TemplateSeldomEscapedOutputModel> {
-    
-    public static final SeldomEscapedOutputFormat INSTANCE = new SeldomEscapedOutputFormat();
-    
-    private SeldomEscapedOutputFormat() {
-        // hide
-    }
-
-    @Override
-    public String getName() {
-        return "seldomEscaped";
-    }
-
-    @Override
-    public String getMimeType() {
-        return "text/seldomEscaped";
-    }
-
-    @Override
-    public void output(String textToEsc, Writer out) throws IOException, TemplateModelException {
-        out.write(escapePlainText(textToEsc));
-    }
-
-    @Override
-    public String escapePlainText(String plainTextContent) {
-        return plainTextContent.replaceAll("(\\.|\\\\)", "\\\\$1");
-    }
-
-    @Override
-    public boolean isLegacyBuiltInBypassed(String builtInName) {
-        return false;
-    }
-
-    @Override
-    public boolean isAutoEscapedByDefault() {
-        return false;
-    }
-
-    @Override
-    protected TemplateSeldomEscapedOutputModel newTemplateMarkupOutputModel(
-            String plainTextContent, String markupContent) {
-        return new TemplateSeldomEscapedOutputModel(plainTextContent, markupContent);
-    }
-    
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/TemplateDummyOutputModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/TemplateDummyOutputModel.java b/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/TemplateDummyOutputModel.java
deleted file mode 100644
index c98df53..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/TemplateDummyOutputModel.java
+++ /dev/null
@@ -1,34 +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.userpkg;
-
-import org.apache.freemarker.core.outputformat.CommonTemplateMarkupOutputModel;
-
-public class TemplateDummyOutputModel extends CommonTemplateMarkupOutputModel<TemplateDummyOutputModel> {
-
-    TemplateDummyOutputModel(String plainTextContent, String markupContet) {
-        super(plainTextContent, markupContet);
-    }
-
-    @Override
-    public DummyOutputFormat getOutputFormat() {
-        return DummyOutputFormat.INSTANCE;
-    }
-    
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/TemplateSeldomEscapedOutputModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/TemplateSeldomEscapedOutputModel.java b/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/TemplateSeldomEscapedOutputModel.java
deleted file mode 100644
index b0a21f7..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/userpkg/TemplateSeldomEscapedOutputModel.java
+++ /dev/null
@@ -1,34 +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.userpkg;
-
-import org.apache.freemarker.core.outputformat.CommonTemplateMarkupOutputModel;
-
-public class TemplateSeldomEscapedOutputModel extends CommonTemplateMarkupOutputModel<TemplateSeldomEscapedOutputModel> {
-
-    TemplateSeldomEscapedOutputModel(String plainTextContent, String markupContet) {
-        super(plainTextContent, markupContet);
-    }
-
-    @Override
-    public SeldomEscapedOutputFormat getOutputFormat() {
-        return SeldomEscapedOutputFormat.INSTANCE;
-    }
-    
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/util/DateUtilTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/util/DateUtilTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/util/DateUtilTest.java
deleted file mode 100644
index 0cd8fc0..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/util/DateUtilTest.java
+++ /dev/null
@@ -1,1085 +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.util;
-
-import java.text.DateFormat;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Locale;
-import java.util.TimeZone;
-
-import javax.xml.datatype.DatatypeConfigurationException;
-import javax.xml.datatype.DatatypeFactory;
-import javax.xml.datatype.XMLGregorianCalendar;
-
-import org.apache.freemarker.core.util._DateUtil.CalendarFieldsToDateConverter;
-import org.apache.freemarker.core.util._DateUtil.DateParseException;
-import org.apache.freemarker.core.util._DateUtil.DateToISO8601CalendarFactory;
-import org.apache.freemarker.core.util._DateUtil.TrivialCalendarFieldsToDateConverter;
-
-import junit.framework.TestCase;
-
-public class DateUtilTest extends TestCase {
-    
-    private final TimeZone originalDefaultTZ = TimeZone.getDefault();
-
-    @Override
-    protected void setUp() throws Exception {
-        TimeZone.setDefault(TimeZone.getTimeZone("Europe/Prague"));
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        TimeZone.setDefault(originalDefaultTZ);
-    }
-
-    private final DateFormat df
-            = new SimpleDateFormat("G yyyy-MM-dd HH:mm:ss:S Z", Locale.US);
-    {
-        df.setTimeZone(_DateUtil.UTC);
-    }
-    
-    private CalendarFieldsToDateConverter cf2dc = new TrivialCalendarFieldsToDateConverter();
-    
-    private DateToISO8601CalendarFactory calendarFactory
-            = new _DateUtil.TrivialDateToISO8601CalendarFactory();
-    
-    public DateUtilTest(String name) {
-        super(name);
-    }
-    
-    public void testDateToUTCString() throws ParseException {
-        assertEquals(
-                "1998-10-30T15:30:00.512Z",
-                dateToISO8601UTCDateTimeMSString(
-                        df.parse("AD 1998-10-30 19:30:00:512 +0400"), true));
-        assertEquals(
-                "1998-10-30T15:30:00.5Z",
-                dateToISO8601UTCDateTimeMSString(
-                        df.parse("AD 1998-10-30 19:30:00:500 +0400"), true));
-        assertEquals(
-                "1998-10-30T15:30:00.51Z",
-                dateToISO8601UTCDateTimeMSString(
-                        df.parse("AD 1998-10-30 19:30:00:510 +0400"), true));
-        assertEquals(
-                "1998-10-30T15:30:00.1Z",
-                dateToISO8601UTCDateTimeMSString(
-                        df.parse("AD 1998-10-30 19:30:00:100 +0400"), true));
-        assertEquals(
-                "1998-10-30T15:30:00.01Z",
-                dateToISO8601UTCDateTimeMSString(
-                        df.parse("AD 1998-10-30 19:30:00:10 +0400"), true));
-        assertEquals(
-                "1998-10-30T15:30:00.001Z",
-                dateToISO8601UTCDateTimeMSString(
-                        df.parse("AD 1998-10-30 19:30:00:1 +0400"), true));
-        assertEquals(
-                "2000-02-08T06:05:04Z",
-                dateToISO8601UTCDateTimeMSString(
-                        df.parse("AD 2000-02-08 09:05:04:0 +0300"), true));
-        assertEquals(
-                "0099-02-28T06:15:24Z",
-                dateToISO8601UTCDateTimeString(
-                        df.parse(
-                        "AD 0099-03-02 09:15:24:0 +0300"), true));
-        assertEquals(
-                "0010-02-28T06:15:24Z",
-                dateToISO8601UTCDateTimeString(
-                        df.parse("AD 0010-03-02 09:15:24:0 +0300"), true));
-        assertEquals(
-                "0001-02-28T06:15:24Z",
-                dateToISO8601UTCDateTimeString(
-                        df.parse("AD 0001-03-02 09:15:24:0 +0300"), true));
-        assertEquals(
-                "0000-02-29T06:15:24Z",
-                dateToISO8601UTCDateTimeString(
-                        df.parse("BC 0001-03-02 09:15:24:0 +0300"), true));
-        assertEquals(
-                "-1-02-28T06:15:24Z",
-                dateToISO8601UTCDateTimeString(
-                        df.parse("BC 2-03-02 09:15:24:0 +0300"), true));
-        assertEquals(
-                "10000-02-28T06:15:24Z",
-                dateToISO8601UTCDateTimeString(
-                        df.parse("AD 10000-02-28 09:15:24:0 +0300"), true));
-
-        Date d = df.parse("AD 1998-10-30 19:30:00:512 +0400");
-        assertEquals(
-                "1998-10-30",
-                dateToISO8601UTCDateString(d));
-        assertEquals(
-                "15:30:00.512Z",
-                dateToISO8601UTCTimeMSString(d, true));
-        assertEquals(
-                "15:30:00.512",
-                dateToISO8601UTCTimeMSString(d, false));
-        assertEquals(
-                "1998-10-30",
-                dateToISO8601UTCDateString(
-                        new java.sql.Date(d.getTime())));
-        assertEquals(
-                "15:30:00.512Z",
-                dateToISO8601UTCTimeMSString(
-                        new java.sql.Time(d.getTime()), true));
-    }
-
-    public void testLocalTime() throws ParseException {
-        Date dsum = df.parse("AD 2010-05-09 20:00:00:0 UTC");
-        Date dwin = df.parse("AD 2010-01-01 20:00:00:0 UTC");
-        
-        TimeZone tzRome = TimeZone.getTimeZone("Europe/Rome");
-        if (tzRome.getOffset(0) == 0) {
-            throw new RuntimeException(
-                    "Can't get time zone for Europe/Rome!");
-        }
-        assertEquals(
-                "2010-05-09T22:00:00+02:00",
-                dateToISO8601DateTimeString(dsum, tzRome));
-        assertEquals(
-                "2010-01-01T21:00:00+01:00",
-                dateToISO8601DateTimeString(dwin, tzRome));
-        assertEquals(
-                "2010-05-09",
-                dateToISO8601DateString(dsum, tzRome));
-        assertEquals(
-                "2010-01-01",
-                dateToISO8601DateString(dwin, tzRome));
-        assertEquals(
-                "22:00:00+02:00",
-                dateToISO8601TimeString(dsum, tzRome));
-        assertEquals(
-                "21:00:00+01:00",
-                dateToISO8601TimeString(dwin, tzRome));
-        
-        TimeZone tzNY = TimeZone.getTimeZone("America/New_York");
-        if (tzNY.getOffset(0) == 0) {
-            throw new RuntimeException(
-                    "Can't get time zone for America/New_York!");
-        }
-        assertEquals(
-                "2010-05-09T16:00:00-04:00",
-                dateToISO8601DateTimeString(dsum, tzNY));
-        assertEquals(
-                "2010-01-01T15:00:00-05:00",
-                dateToISO8601DateTimeString(dwin, tzNY));
-        assertEquals(
-                "2010-05-09",
-                dateToISO8601DateString(dsum, tzNY));
-        assertEquals(
-                "2010-01-01",
-                dateToISO8601DateString(dwin, tzNY));
-        assertEquals(
-                "16:00:00-04:00",
-                dateToISO8601TimeString(dsum, tzNY));
-        assertEquals(
-                "15:00:00-05:00",
-                dateToISO8601TimeString(dwin, tzNY));
-        
-        TimeZone tzFixed = TimeZone.getTimeZone("GMT+02:30");
-        assertEquals(
-                "2010-05-09T22:30:00+02:30",
-                dateToISO8601DateTimeString(dsum, tzFixed));
-        assertEquals(
-                "2010-01-01T22:30:00+02:30",
-                dateToISO8601DateTimeString(dwin, tzFixed));
-    }
-
-    public void testGetTimeZone() throws Exception {
-        assertTrue(_DateUtil.getTimeZone("GMT") != _DateUtil.UTC);
-        assertTrue(_DateUtil.getTimeZone("UT1") != _DateUtil.UTC);
-        assertEquals(_DateUtil.getTimeZone("UTC"), _DateUtil.UTC);
-        
-        assertEquals(_DateUtil.getTimeZone("Europe/Rome"),
-                TimeZone.getTimeZone("Europe/Rome"));
-        
-        assertEquals(_DateUtil.getTimeZone("Iceland"), // GMT and no DST
-                TimeZone.getTimeZone("Iceland"));
-        
-        try {
-            _DateUtil.getTimeZone("Europe/NoSuch");
-            fail();
-        } catch (UnrecognizedTimeZoneException e) {
-            // good
-        }
-    }
-    
-    public void testTimeOnlyDate() throws UnrecognizedTimeZoneException {
-        Date t = new Date(0L);
-        SimpleDateFormat tf = new SimpleDateFormat("HH:mm:ss");
-        
-        tf.setTimeZone(_DateUtil.UTC);
-        assertEquals("00:00:00", tf.format(t));
-        assertEquals("00:00:00",
-                dateToISO8601UTCTimeString(t, false));
-        
-        TimeZone gmt1 = _DateUtil.getTimeZone("GMT+01");
-        tf.setTimeZone(gmt1);
-        assertEquals("01:00:00", tf.format(t)); 
-        assertEquals("01:00:00+01:00",
-                dateToISO8601TimeString(t, gmt1));
-    }
-    
-    public void testAccuracy() throws ParseException {
-        Date d = df.parse("AD 2000-02-08 09:05:04:250 UTC"); 
-        assertEquals("2000-02-08T09:05:04Z",
-                dateToISO8601UTCDateTimeString(d, true));
-        assertEquals("2000-02-08T09:05:04.25Z",
-                dateToISO8601String(d, true, true, true,
-                        _DateUtil.ACCURACY_MILLISECONDS, null));
-        assertEquals("2000-02-08T09:05:04Z",
-                dateToISO8601String(d, true, true, true,
-                        _DateUtil.ACCURACY_SECONDS, null));
-        assertEquals("2000-02-08T09:05Z",
-                dateToISO8601String(d, true, true, true,
-                        _DateUtil.ACCURACY_MINUTES, null));
-        assertEquals("2000-02-08T09Z",
-                dateToISO8601String(d, true, true, true,
-                        _DateUtil.ACCURACY_HOURS, null));
-        
-        d = df.parse("AD 1998-10-30 19:30:00:000 +0400");
-        assertEquals(
-                "15:30:00Z",
-                dateToISO8601UTCTimeMSString(d, true));
-        assertEquals(
-                "15:30:00.000Z",
-                dateToISO8601UTCTimeMSFString(d, true));
-        assertEquals(
-                "1998-10-30T15:30:00Z",
-                dateToISO8601UTCDateTimeMSString(d, true));
-        assertEquals(
-                "1998-10-30T15:30:00.000Z",
-                dateToISO8601UTCDateTimeMSFString(d, true));
-                
-        d = df.parse("AD 1998-10-30 19:30:00:100 +0400");
-        assertEquals(
-                "15:30:00.1Z",
-                dateToISO8601UTCTimeMSString(d, true));
-        assertEquals(
-                "15:30:00.100Z",
-                dateToISO8601UTCTimeMSFString(d, true));
-        assertEquals(
-                "1998-10-30T15:30:00.1Z",
-                dateToISO8601UTCDateTimeMSString(d, true));
-        assertEquals(
-                "1998-10-30T15:30:00.100Z",
-                dateToISO8601UTCDateTimeMSFString(d, true));
-        
-        d = df.parse("AD 1998-10-30 19:30:00:010 +0400");
-        assertEquals(
-                "15:30:00.01Z",
-                dateToISO8601UTCTimeMSString(d, true));
-        assertEquals(
-                "15:30:00.010Z",
-                dateToISO8601UTCTimeMSFString(d, true));
-        assertEquals(
-                "1998-10-30T15:30:00.01Z",
-                dateToISO8601UTCDateTimeMSString(d, true));
-        assertEquals(
-                "1998-10-30T15:30:00.010Z",
-                dateToISO8601UTCDateTimeMSFString(d, true));
-        
-        d = df.parse("AD 1998-10-30 19:30:00:001 +0400");
-        assertEquals(
-                "15:30:00.001Z",
-                dateToISO8601UTCTimeMSString(d, true));
-        assertEquals(
-                "15:30:00.001Z",
-                dateToISO8601UTCTimeMSFString(d, true));
-        assertEquals(
-                "1998-10-30T15:30:00.001Z",
-                dateToISO8601UTCDateTimeMSString(d, true));
-        assertEquals(
-                "1998-10-30T15:30:00.001Z",
-                dateToISO8601UTCDateTimeMSFString(d, true));
-    }
-
-    public void testXSFormatISODeviations() throws ParseException, UnrecognizedTimeZoneException {
-        Date dsum = df.parse("AD 2010-05-09 20:00:00:0 UTC");
-        Date dwin = df.parse("AD 2010-01-01 20:00:00:0 UTC");
-        
-        TimeZone tzRome = _DateUtil.getTimeZone("Europe/Rome");
-        
-        assertEquals(
-                "2010-01-01T21:00:00+01:00",
-                _DateUtil.dateToXSString(dwin, true, true, true, _DateUtil.ACCURACY_SECONDS, tzRome, calendarFactory));
-        assertEquals(
-                "2010-05-09T22:00:00+02:00",
-                _DateUtil.dateToXSString(dsum, true, true, true, _DateUtil.ACCURACY_SECONDS, tzRome, calendarFactory));
-        assertEquals(
-                "2010-01-01+01:00",  // ISO doesn't allow date-only with TZ
-                _DateUtil.dateToXSString(dwin, true, false, true, _DateUtil.ACCURACY_SECONDS, tzRome, calendarFactory));
-        assertEquals(
-                "2010-05-09+02:00",  // ISO doesn't allow date-only with TZ
-                _DateUtil.dateToXSString(dsum, true, false, true, _DateUtil.ACCURACY_SECONDS, tzRome, calendarFactory));
-        assertEquals(
-                "21:00:00+01:00",
-                _DateUtil.dateToXSString(dwin, false, true, true, _DateUtil.ACCURACY_SECONDS, tzRome, calendarFactory));
-        assertEquals(
-                "22:00:00+02:00",
-                _DateUtil.dateToXSString(dsum, false, true, true, _DateUtil.ACCURACY_SECONDS, tzRome, calendarFactory));
-        
-        assertEquals(
-                "-1-02-29T06:15:24Z",  // ISO uses 0 for BC 1
-                _DateUtil.dateToXSString(
-                        df.parse("BC 0001-03-02 09:15:24:0 +0300"),
-                        true, true, true, _DateUtil.ACCURACY_SECONDS, _DateUtil.UTC, calendarFactory));
-        assertEquals(
-                "-2-02-28T06:15:24Z",  // ISO uses -1 for BC 2
-                _DateUtil.dateToXSString(
-                        df.parse("BC 2-03-02 09:15:24:0 +0300"),
-                        true, true, true, _DateUtil.ACCURACY_SECONDS, _DateUtil.UTC, calendarFactory));
-    }
-    
-    private String dateToISO8601DateTimeString(
-            Date date, TimeZone tz) {
-        return dateToISO8601String(date, true, true, true,
-                _DateUtil.ACCURACY_SECONDS, tz);
-    }
-    
-    private String dateToISO8601UTCDateTimeString(
-            Date date, boolean offsetPart) {
-        return dateToISO8601String(date, true, true, offsetPart,
-                _DateUtil.ACCURACY_SECONDS, _DateUtil.UTC);
-    }
-
-    private String dateToISO8601UTCDateTimeMSString(
-            Date date, boolean offsetPart) {
-        return dateToISO8601String(date, true, true, offsetPart,
-                _DateUtil.ACCURACY_MILLISECONDS, _DateUtil.UTC);
-    }
-
-    private String dateToISO8601UTCDateTimeMSFString(
-            Date date, boolean offsetPart) {
-        return dateToISO8601String(date, true, true, offsetPart,
-                _DateUtil.ACCURACY_MILLISECONDS_FORCED, _DateUtil.UTC);
-    }
-        
-    private String dateToISO8601DateString(Date date, TimeZone tz) {
-        return dateToISO8601String(date, true, false, false,
-                _DateUtil.ACCURACY_SECONDS, tz);
-    }
-
-    private String dateToISO8601UTCDateString(Date date) {
-        return dateToISO8601String(date, true, false, false,
-                _DateUtil.ACCURACY_SECONDS, _DateUtil.UTC);
-    }
-    
-    private String dateToISO8601TimeString(
-            Date date, TimeZone tz) {
-        return dateToISO8601String(date, false, true, true,
-                _DateUtil.ACCURACY_SECONDS, tz);
-    }
-    
-    private String dateToISO8601UTCTimeString(
-            Date date, boolean offsetPart) {
-        return dateToISO8601String(date, false, true, offsetPart,
-                _DateUtil.ACCURACY_SECONDS, _DateUtil.UTC);
-    }
-
-    private String dateToISO8601UTCTimeMSString(
-            Date date, boolean offsetPart) {
-        return dateToISO8601String(date, false, true, offsetPart,
-                _DateUtil.ACCURACY_MILLISECONDS, _DateUtil.UTC);
-    }
-
-    private String dateToISO8601UTCTimeMSFString(
-            Date date, boolean offsetPart) {
-        return dateToISO8601String(date, false, true, offsetPart,
-                _DateUtil.ACCURACY_MILLISECONDS_FORCED, _DateUtil.UTC);
-    }
-    
-    private String dateToISO8601String(
-            Date date,
-            boolean datePart, boolean timePart, boolean offsetPart,
-            int accuracy,
-            TimeZone timeZone) {
-        return _DateUtil.dateToISO8601String(
-                date,
-                datePart, timePart, offsetPart,
-                accuracy,
-                timeZone,
-                calendarFactory);        
-    }
-    
-    public void testParseDate() throws DateParseException {
-        assertDateParsing(
-                "AD 1998-10-29 20:00:00:0 +0000",
-                null,
-                "1998-10-30+04:00", _DateUtil.UTC);
-        assertDateParsing(
-                "AD 1998-10-30 02:00:00:0 +0000",
-                null,
-                "1998-10-30-02:00", _DateUtil.UTC);
-        assertDateParsing(
-                "AD 1998-10-30 02:00:00:0 +0000",
-                "1998-10-30", _DateUtil.parseXSTimeZone("-02:00"));
-        assertDateParsing(
-                null,
-                "AD 1998-10-30 02:00:00:0 +0000",
-                "19981030", _DateUtil.parseXSTimeZone("-02:00"));
-        assertDateParsing(
-                "AD 1998-10-30 00:00:00:0 +0000",
-                null,
-                "1998-10-30Z", _DateUtil.UTC);
-        assertDateParsing(
-                "AD 1998-10-30 00:00:00:0 +0000",
-                "1998-10-30", _DateUtil.UTC);
-        assertDateParsing(
-                null,
-                "AD 1998-10-30 00:00:00:0 +0000",
-                "19981030", _DateUtil.UTC);
-
-        assertDateParsing(
-                "AD 1998-10-29 20:00:00:0 +0000",
-                null,
-                "1998-10-30+04:00", _DateUtil.UTC);
-        assertDateParsing(
-                "AD 1998-10-30 04:00:00:0 +0000",
-                null,
-                "1998-10-30-04:00", _DateUtil.UTC);
-        assertDateParsing(
-                "AD 1998-10-30 00:00:00:0 +0000",
-                null,
-                "1998-10-30Z", _DateUtil.UTC);
-        
-        try {
-            // XS doesn't have year 0
-            assertDateParsing(
-                    "BC 0000-02-05 00:00:00:0 +0000",
-                    null,
-                    "0000-02-03Z", _DateUtil.UTC);
-            fail();
-        } catch (DateParseException e) {
-            echo(e);
-        }
-        assertDateParsing(
-                null,
-                "BC 0001-02-05 00:00:00:0 +0000",
-                "0000-02-03", _DateUtil.UTC);
-        assertDateParsing(
-                null,
-                "BC 0001-02-05 00:00:00:0 +0000",
-                "00000203", _DateUtil.UTC);
-        
-        assertDateParsing(
-                "BC 0001-02-05 00:00:00:0 +0000",  // Julian
-                "BC 0002-02-05 00:00:00:0 +0000",  // Julian
-                "-0001-02-03", _DateUtil.UTC);  // Proleptic Gregorian
-        assertDateParsing(
-                null,
-                "BC 0002-02-05 00:00:00:0 +0000",  // Julian
-                "-00010203", _DateUtil.UTC);  // Proleptic Gregorian
-
-        assertDateParsing(
-                "AD 0001-02-05 00:00:00:0 +0000",  // Julian
-                null,
-                "0001-02-03Z", _DateUtil.UTC);  // Proleptic Gregorian
-        assertDateParsing(
-                "AD 0001-02-05 00:00:00:0 +0000",  // Julian
-                "0001-02-03", _DateUtil.UTC);  // Proleptic Gregorian
-        assertDateParsing(
-                null,
-                "AD 0001-02-05 00:00:00:0 +0000",  // Julian
-                "00010203", _DateUtil.UTC);  // Proleptic Gregorian
-        assertDateParsing(
-                "AD 1001-12-07 00:00:00:0 +0000",  // Julian
-                null,
-                "1001-12-13Z", _DateUtil.UTC);  // Proleptic Gregorian
-        assertDateParsing(
-                "AD 1001-12-07 00:00:00:0 +0000",  // Julian
-                "1001-12-13", _DateUtil.UTC);  // Proleptic Gregorian
-        
-        assertDateParsing(
-                "AD 2006-12-31 00:00:00:0 +0000",
-                null,
-                "2006-12-31Z", _DateUtil.UTC);
-        assertDateParsing(
-                "AD 2006-12-31 00:00:00:0 +0000",
-                "2006-12-31", _DateUtil.UTC);
-        assertDateParsing(
-                "AD 2006-01-01 00:00:00:0 +0000",
-                null,
-                "2006-01-01Z", _DateUtil.UTC);
-        assertDateParsing(
-                "AD 2006-01-01 00:00:00:0 +0000",
-                "2006-01-01", _DateUtil.UTC);
-        assertDateParsing(
-                "AD 12006-01-01 00:00:00:0 +0000",
-                "12006-01-01", _DateUtil.UTC);
-        assertDateParsing(
-                null,
-                "AD 12006-01-01 00:00:00:0 +0000",
-                "120060101", _DateUtil.UTC);
-    }
-
-    public void testParseDateMalformed() {
-        assertDateMalformed("1998-10-30x");
-        assertDateMalformed("+1998-10-30");
-        assertDateMalformed("1998-10-");
-        assertDateMalformed("1998-1-30");
-        assertDateMalformed("1998-10-30+01");
-        assertDateMalformed("1998-00-01");
-        assertDateMalformed("1998-13-01");
-        assertDateMalformed("1998-10-00");
-        assertDateMalformed("1998-10-32");
-        assertDateMalformed("1998-02-31");
-        
-        assertISO8601DateMalformed("2100103");
-        assertISO8601DateMalformed("210-01-03");
-        assertISO8601DateMalformed("2012-0301");
-        assertISO8601DateMalformed("201203-01");
-        assertISO8601DateMalformed("2012-01-01+01:00");
-    }
-    
-    public void testParseTime() throws DateParseException {
-        assertTimeParsing(
-                "AD 1970-01-01 17:30:05:0 +0000",
-                "17:30:05", _DateUtil.UTC);
-        assertTimeParsing(
-                null,
-                "AD 1970-01-01 17:30:05:0 +0000",
-                "173005", _DateUtil.UTC);
-        assertTimeParsing(
-                "AD 1970-01-01 07:30:00:100 +0000",
-                "07:30:00.1", _DateUtil.UTC);
-        assertTimeParsing(
-                "AD 1970-01-01 07:30:00:120 +0000",
-                "07:30:00.12", _DateUtil.UTC);
-        assertTimeParsing(
-                "AD 1970-01-01 07:30:00:123 +0000",
-                "07:30:00.123", _DateUtil.UTC);
-        assertTimeParsing(
-                "AD 1970-01-01 07:30:00:123 +0000",
-                "07:30:00.1235", _DateUtil.UTC);
-        assertTimeParsing(
-                "AD 1970-01-01 07:30:00:123 +0000",
-                "07:30:00.12346", _DateUtil.UTC);
-        assertTimeParsing(
-                null,
-                "AD 1970-01-01 07:30:00:123 +0000",
-                "073000.12346", _DateUtil.UTC);
-        assertTimeParsing(
-                null,
-                "AD 1970-01-01 07:30:00:123 +0000",
-                "073000,12346", _DateUtil.UTC);
-        assertTimeParsing(
-                "AD 1970-01-01 07:30:00:120 +0000",
-                "07:30:00.12", _DateUtil.UTC);
-        assertTimeParsing(
-                "AD 1970-01-01 07:30:00:500 +0000",
-                "07:30:00.5", _DateUtil.UTC);
-
-        assertTimeParsing(
-                "AD 1970-01-01 16:30:05:0 +0000",
-                "17:30:05+01:00", _DateUtil.UTC);
-        assertTimeParsing(
-                null,
-                "AD 1970-01-01 16:30:05:0 +0000",
-                "173005+01", _DateUtil.UTC);
-        assertTimeParsing(
-                "AD 1970-01-01 19:00:05:0 +0000",
-                "17:30:05-01:30", _DateUtil.UTC);
-        assertTimeParsing(
-                null,
-                "AD 1970-01-01 19:00:05:0 +0000",
-                "173005-0130", _DateUtil.UTC);
-        assertTimeParsing(
-                "AD 1970-01-01 16:30:05:500 +0000",
-                "17:30:05.5+01:00", _DateUtil.UTC);
-        assertTimeParsing(
-                null,
-                "AD 1970-01-01 16:30:05:500 +0000",
-                "173005.5+0100", _DateUtil.UTC);
-        assertTimeParsing(
-                null,
-                "AD 1970-01-01 16:30:05:500 +0000",
-                "173005.5+01", _DateUtil.UTC);
-        assertTimeParsing(
-                null,
-                "AD 1970-01-01 16:00:00:0 +0000",
-                "170000+01", _DateUtil.UTC);
-        assertTimeParsing(
-                null,
-                "AD 1970-01-01 16:00:00:0 +0000",
-                "1700+01", _DateUtil.UTC);
-        assertTimeParsing(
-                null,
-                "AD 1970-01-01 16:00:00:0 +0000",
-                "17+01", _DateUtil.UTC);
-        
-        assertTimeParsing(
-                "AD 1970-01-01 00:00:00:0 +0000",
-                "00:00:00", _DateUtil.UTC);
-        assertTimeParsing(
-                "AD 1970-01-02 00:00:00:0 +0000",
-                "24:00:00", _DateUtil.UTC);
-        assertTimeParsing(
-                null,
-                "AD 1970-01-02 00:00:00:0 +0000",
-                "240000", _DateUtil.UTC);
-        assertTimeParsing(
-                null,
-                "AD 1970-01-02 00:00:00:0 +0000",
-                "2400", _DateUtil.UTC);
-        assertTimeParsing(
-                null,
-                "AD 1970-01-02 00:00:00:0 +0000",
-                "24:00", _DateUtil.UTC);
-        assertTimeParsing(
-                null,
-                "AD 1970-01-02 00:00:00:0 +0000",
-                "24", _DateUtil.UTC);
-        
-        assertTimeParsing(
-                "AD 1970-01-01 23:59:59:999 +0000",
-                "23:59:59.999", _DateUtil.UTC);
-    }
-
-    public void testParseTimeMalformed() {
-        assertTimeMalformed("00:0000");
-        assertTimeMalformed("00:00:00-01:60");
-        assertTimeMalformed("24:00:01");
-        assertTimeMalformed("00:00:61");
-        assertTimeMalformed("00:60:00");
-        assertTimeMalformed("25:00:00");
-        assertTimeMalformed("2:00:00");
-        assertTimeMalformed("02:0:00");
-        assertTimeMalformed("02:00:0");
-        
-        assertISO8601TimeMalformed("1010101");
-        assertISO8601TimeMalformed("10101");
-        assertISO8601TimeMalformed("101");
-        assertISO8601TimeMalformed("1");
-        assertISO8601TimeMalformed("101010-1");
-        assertISO8601TimeMalformed("101010-100");
-        assertISO8601TimeMalformed("101010-10000");
-        assertISO8601TimeMalformed("101010+1");
-        assertISO8601TimeMalformed("101010+100");
-        assertISO8601TimeMalformed("101010+10000");
-    }
-    
-    public void testParseDateTime() throws DateParseException {
-        assertDateTimeParsing( 
-                "AD 1998-10-30 11:30:00:0 +0000",
-                "1998-10-30T15:30:00+04:00", _DateUtil.UTC);
-        assertDateTimeParsing(
-                null,
-                "AD 1998-10-30 11:30:00:0 +0000",
-                "19981030T153000+0400", _DateUtil.UTC);
-        assertDateTimeParsing(
-                "AD 1998-10-30 11:30:00:500 +0000",
-                "1998-10-30T15:30:00.5+04:00", _DateUtil.UTC);
-        assertDateTimeParsing(
-                "AD 1998-10-30 15:30:00:0 +0000",
-                "1998-10-30T15:30:00Z", _DateUtil.UTC);
-        assertDateTimeParsing(
-                null,
-                "AD 1998-10-30 15:30:00:0 +0000",
-                "19981030T1530Z", _DateUtil.UTC);
-        assertDateTimeParsing(
-                "AD 1998-10-30 15:30:00:500 +0000",
-                "1998-10-30T15:30:00.5Z", _DateUtil.UTC);
-        assertDateTimeParsing(
-                "AD 1998-10-30 11:30:00:0 +0000",
-                "1998-10-30T15:30:00+04:00", _DateUtil.UTC);
-        assertDateTimeParsing(
-                "AD 1998-10-30 15:30:00:0 +0000",
-                "1998-10-30T15:30:00Z", _DateUtil.UTC);
-        assertDateTimeParsing(
-                "AD 1998-10-30 15:30:00:0 +0000",
-                "1998-10-30T15:30:00", _DateUtil.UTC);
-        assertDateTimeParsing(
-                null,
-                "AD 1998-10-30 15:30:00:0 +0000",
-                "1998-10-30T15:30", _DateUtil.UTC);
-        
-        assertDateTimeParsing(
-                "AD 1998-10-29 20:00:00:0 +0000",
-                "1998-10-30T00:00:00+04:00", _DateUtil.UTC);
-        assertDateTimeParsing(
-                "AD 1998-10-30 02:00:00:0 +0000",
-                "1998-10-30T00:00:00-02:00", _DateUtil.UTC);
-        assertDateTimeParsing(
-                "AD 1998-10-30 00:00:00:0 +0000",
-                "1998-10-30T00:00:00Z", _DateUtil.UTC);
-
-        assertDateTimeParsing(
-                "AD 1998-10-29 20:00:00:0 +0000",
-                "1998-10-30T00:00:00+04:00", _DateUtil.UTC);
-        assertDateTimeParsing(
-                "AD 1998-10-30 00:00:00:0 +0000",
-                "1998-10-30T00:00:00Z", _DateUtil.UTC);
-        assertDateTimeParsing(
-                null,
-                "AD 1998-10-30 00:00:00:0 +0000",
-                "1998-10-30T00:00Z", _DateUtil.UTC);
-        assertDateTimeParsing(
-                null,
-                "AD 1998-10-30 00:00:00:0 +0000",
-                "1998-10-30T00:00", _DateUtil.UTC);
-        assertDateTimeParsing(
-                null,
-                "AD 1998-10-30 00:00:00:0 +0000",
-                "19981030T00Z", _DateUtil.UTC);
-        
-        // BC years
-        try {
-            assertDateTimeParsing(
-                        "",
-                        null,
-                        "0000-02-03T00:00:00Z", _DateUtil.UTC);
-            fail();
-        } catch (DateParseException e) {
-            echo(e);
-        }
-        assertDateTimeParsing(
-                null,
-                "BC 0001-02-05 00:00:00:0 +0000",
-                "0000-02-03T00:00:00Z", _DateUtil.UTC);
-        
-        assertDateTimeParsing(
-                "BC 0001-02-05 00:00:00:0 +0000",  // Julian
-                "BC 0002-02-05 00:00:00:0 +0000",  // Julian
-                "-0001-02-03T00:00:00Z", _DateUtil.UTC);  // Proleptic Gregorian
-
-        assertDateTimeParsing(
-                "AD 0001-02-05 00:00:00:0 +0000",  // Julian
-                "0001-02-03T00:00:00Z", _DateUtil.UTC);  // Proleptic Gregorian
-        assertDateTimeParsing(
-                "AD 1001-12-07 00:00:00:0 +0000",  // Julian
-                "1001-12-13T00:00:00Z", _DateUtil.UTC);  // Proleptic Gregorian
-        assertDateTimeParsing(
-                "AD 11001-12-13 00:00:00:0 +0000",
-                "11001-12-13T00:00:00Z", _DateUtil.UTC);
-        assertDateTimeParsing(
-                null,
-                "AD 11001-12-13 00:00:00:0 +0000",
-                "110011213T00Z", _DateUtil.UTC);
-        
-        assertDateTimeParsing(
-                "AD 2006-12-31 00:00:00:0 +0000",
-                "2006-12-31T00:00:00Z", _DateUtil.UTC);
-        assertDateTimeParsing(
-                "AD 2006-01-01 00:00:00:0 +0000",
-                "2006-01-01T00:00:00Z", _DateUtil.UTC);
-        
-        assertDateTimeParsing(
-                "AD 1970-01-01 07:30:00:123 +0000",
-                "1970-01-01T07:30:00.123", _DateUtil.UTC);
-        assertDateTimeParsing(
-                "AD 1970-01-01 07:30:00:123 +0000",
-                "1970-01-01T07:30:00.1235", _DateUtil.UTC);
-        assertDateTimeParsing(
-                "AD 1970-01-01 07:30:00:123 +0000",
-                "1970-01-01T07:30:00.12346", _DateUtil.UTC);
-        assertDateTimeParsing(
-                "AD 1970-01-01 07:30:00:120 +0000",
-                "1970-01-01T07:30:00.12", _DateUtil.UTC);
-        assertDateTimeParsing(
-                "AD 1970-01-01 07:30:00:500 +0000",
-                "1970-01-01T07:30:00.5", _DateUtil.UTC);
-
-        assertDateTimeParsing(
-                "AD 1970-01-01 16:30:05:0 +0000",
-                "1970-01-01T17:30:05+01:00", _DateUtil.UTC);
-        assertDateTimeParsing(
-                "AD 1970-01-01 16:30:05:500 +0000",
-                "1970-01-01T17:30:05.5+01:00", _DateUtil.UTC);
-        
-        assertDateTimeParsing(
-                "AD 1970-01-01 00:00:00:0 +0000",
-                "1970-01-01T00:00:00", _DateUtil.UTC);
-        assertDateTimeParsing(
-                "AD 1970-01-02 00:00:00:0 +0000",
-                "1970-01-01T24:00:00", _DateUtil.UTC);
-        
-        assertDateTimeParsing(
-                "AD 1970-01-01 23:59:59:999 +0000",
-                "1970-01-01T23:59:59.999", _DateUtil.UTC);
-    }
-
-    public void testParseDateTimeMalformed() throws DateParseException {
-        assertDateTimeMalformed("1998-00-01T00:00:00");
-        assertDateTimeMalformed("1998-13-01T00:00:00");
-        assertDateTimeMalformed("1998-10-00T00:00:00");
-        assertDateTimeMalformed("1998-10-32T00:00:00");
-        assertDateTimeMalformed("1998-02-31T00:00:00");
-        assertDateTimeMalformed("1970-01-02T24:00:01");
-        assertDateTimeMalformed("1970-01-01T00:00:61");
-        assertDateTimeMalformed("1970-01-01T00:60:00");
-        assertDateTimeMalformed("1970-01-01T25:00:00");
-        
-        assertISO8601DateTimeMalformed("197-01-01T20:00:00");
-    }
-    
-    public void testParseXSTimeZone() throws DateParseException {
-        assertEquals(0,
-                _DateUtil.parseXSTimeZone("Z").getOffset(0));
-        assertEquals(0,
-                _DateUtil.parseXSTimeZone("-00:00").getOffset(0));
-        assertEquals(0,
-                _DateUtil.parseXSTimeZone("+00:00").getOffset(0));
-        assertEquals(90 * 60 * 1000,
-                _DateUtil.parseXSTimeZone("+01:30").getOffset(0));
-        assertEquals(-4 * 60 * 60 * 1000,
-                _DateUtil.parseXSTimeZone("-04:00").getOffset(0));
-        assertEquals(((-23 * 60) - 59) * 60 * 1000,
-                _DateUtil.parseXSTimeZone("-23:59").getOffset(0));
-        assertEquals(((23 * 60) + 59) * 60 * 1000,
-                _DateUtil.parseXSTimeZone("+23:59").getOffset(0));
-    }
-
-    public void testParseXSTimeZoneWrong() {
-        try {
-            _DateUtil.parseXSTimeZone("04:00").getOffset(0);
-            fail();
-        } catch (DateParseException e) {
-            echo(e);
-        }
-        try {
-            _DateUtil.parseXSTimeZone("-04:00x").getOffset(0);
-            fail();
-        } catch (DateParseException e) {
-            echo(e);
-        }
-        try {
-            _DateUtil.parseXSTimeZone("-04").getOffset(0);
-            fail();
-        } catch (DateParseException e) {
-            echo(e);
-        }
-        try {
-            _DateUtil.parseXSTimeZone("+24:00").getOffset(0);
-            fail();
-        } catch (DateParseException e) {
-            echo(e);
-        }
-        try {
-            _DateUtil.parseXSTimeZone("-24:00").getOffset(0);
-            fail();
-        } catch (DateParseException e) {
-            echo(e);
-        }
-        try {
-            _DateUtil.parseXSTimeZone("-01:60").getOffset(0);
-            fail();
-        } catch (DateParseException e) {
-            echo(e);
-        }
-    }
-    
-    public void testParseXSDateTimeFTLAndJavax() throws DateParseException {
-        // Explicit time zone:
-        assertJavaxAndFTLXSDateTimesSame("2014-01-01T13:35:08Z");
-        assertJavaxAndFTLXSDateTimesSame("2014-01-01T13:35:08+02:00");
-        
-        // Default time zone:
-        assertJavaxAndFTLXSDateTimesSame("2014-01-01T13:35:08"); // winter
-        assertJavaxAndFTLXSDateTimesSame("2014-07-01T13:35:08"); // summer
-        
-        // Proleptic Gregorian
-        assertJavaxAndFTLXSDateTimesSame("1500-01-01T13:35:08Z");
-        assertJavaxAndFTLXSDateTimesSame("0200-01-01T13:35:08Z");
-        assertJavaxAndFTLXSDateTimesSame("0001-01-01T00:00:00+05:00");
-        
-        // BC
-        assertJavaxAndFTLXSDateTimesSame("0001-01-01T13:35:08Z");
-        assertJavaxAndFTLXSDateTimesSame("-0001-01-01T13:35:08Z");
-        
-        // Hour 24
-        assertJavaxAndFTLXSDateTimesSame("2014-01-01T23:59:59");
-        if (isAtLeastJava6()) { // Java 5 has broken parser that doesn't allow 24.
-            assertJavaxAndFTLXSDateTimesSame("2014-01-31T24:00:00");
-            assertJavaxAndFTLXSDateTimesSame("2014-01-01T24:00:00");
-        }
-        assertJavaxAndFTLXSDateTimesSame("2014-01-02T00:00:00");  // same as the previous
-        assertJavaxAndFTLXSDateTimesSame("2014-02-01T00:00:00");  // same as the previous
-        
-        // Under ms
-        assertJavaxAndFTLXSDateTimesSame("2014-01-01T23:59:59.123456789");
-        assertJavaxAndFTLXSDateTimesSame("2014-01-01T23:59:59.1235");
-    }
-    
-    private boolean isAtLeastJava6() {
-        try {
-            Class.forName("java.lang.management.LockInfo");
-        } catch (ClassNotFoundException e) {
-            return false;
-        }
-        return true;
-    }
-
-    private final DatatypeFactory datetypeFactory;
-    {
-        try {
-            datetypeFactory = DatatypeFactory.newInstance();
-        } catch (DatatypeConfigurationException e) {
-            throw new RuntimeException(e);
-        } 
-    }
-    
-    private void assertJavaxAndFTLXSDateTimesSame(String s) throws DateParseException {
-        XMLGregorianCalendar xgc = datetypeFactory.newXMLGregorianCalendar(s);
-        Date javaxDate = xgc.toGregorianCalendar().getTime();
-        Date ftlDate = _DateUtil.parseXSDateTime(s, TimeZone.getDefault(), cf2dc);
-        assertEquals(javaxDate, ftlDate);
-    }
-
-    private void assertDateParsing(String expected, String parsed, TimeZone tz) throws DateParseException {
-        assertDateParsing(expected, expected, parsed, tz);
-    }
-
-    private void assertDateParsing(String expectedXS, String expectedISO8601, String parsed, TimeZone tz)
-            throws DateParseException {
-        if (expectedXS != null) {
-            assertEquals(
-                    expectedXS,
-                    df.format(_DateUtil.parseXSDate(parsed, tz, cf2dc)));
-        }
-        if (expectedISO8601 != null) {
-            assertEquals(
-                    expectedISO8601,
-                    df.format(_DateUtil.parseISO8601Date(parsed, tz, cf2dc)));
-        }
-    }
-
-    private void assertDateTimeParsing(String expected, String parsed, TimeZone tz) throws DateParseException {
-        assertDateTimeParsing(expected, expected, parsed, tz);
-    }
-
-    private void assertDateTimeParsing(String expectedXS, String expectedISO8601, String parsed, TimeZone tz)
-            throws DateParseException {
-        if (expectedXS != null) {
-            assertEquals(
-                    expectedXS,
-                    df.format(_DateUtil.parseXSDateTime(parsed, tz, cf2dc)));
-        }
-        if (expectedISO8601 != null) {
-            assertEquals(
-                    expectedISO8601,
-                    df.format(_DateUtil.parseISO8601DateTime(parsed, tz, cf2dc)));
-        }
-    }
-
-    private void assertTimeParsing(String expected, String parsed, TimeZone tz) throws DateParseException {
-        assertTimeParsing(expected, expected, parsed, tz);
-    }
-
-    private void assertTimeParsing(String expectedXS, String expectedISO8601, String parsed, TimeZone tz)
-            throws DateParseException {
-        if (expectedXS != null) {
-            assertEquals(
-                    expectedXS,
-                    df.format(_DateUtil.parseXSTime(parsed, tz, cf2dc)));
-        }
-        if (expectedISO8601 != null) {
-            assertEquals(
-                    expectedISO8601,
-                    df.format(_DateUtil.parseISO8601Time(parsed, tz, cf2dc)));
-        }
-    }
-    
-    private void assertDateMalformed(String parsed) {
-        try {
-            _DateUtil.parseXSDate(parsed, _DateUtil.UTC, cf2dc);
-            fail();
-        } catch (DateParseException e) {
-            // Expected
-            echo(e);
-        }
-        try {
-            _DateUtil.parseISO8601Date(parsed, _DateUtil.UTC, cf2dc);
-            fail();
-        } catch (DateParseException e) {
-            // Expected
-            echo(e);
-        }
-    }
-
-    private void assertTimeMalformed(String parsed) {
-        try {
-            _DateUtil.parseXSTime(parsed, _DateUtil.UTC, cf2dc);
-            fail();
-        } catch (DateParseException e) {
-            // Expected
-            echo(e);
-        }
-        try {
-            _DateUtil.parseISO8601Time(parsed, _DateUtil.UTC, cf2dc);
-            fail();
-        } catch (DateParseException e) {
-            // Expected
-            echo(e);
-        }
-    }
-
-    private void assertDateTimeMalformed(String parsed) {
-        try {
-            _DateUtil.parseXSDateTime(parsed, _DateUtil.UTC, cf2dc);
-            fail();
-        } catch (DateParseException e) {
-            // Expected
-            echo(e);
-        }
-        try {
-            _DateUtil.parseISO8601DateTime(parsed, _DateUtil.UTC, cf2dc);
-            fail();
-        } catch (DateParseException e) {
-            // Expected
-            echo(e);
-        }
-    }
-
-    private void assertISO8601DateMalformed(String parsed) {
-        try {
-            _DateUtil.parseISO8601Date(parsed, _DateUtil.UTC, cf2dc);
-            fail();
-        } catch (DateParseException e) {
-            // Expected
-            echo(e);
-        }
-    }
-    
-    private void assertISO8601TimeMalformed(String parsed) {
-        try {
-            _DateUtil.parseISO8601Time(parsed, _DateUtil.UTC, cf2dc);
-            fail();
-        } catch (DateParseException e) {
-            // Expected
-            echo(e);
-        }
-    }
-    
-    private void assertISO8601DateTimeMalformed(String parsed) {
-        try {
-            _DateUtil.parseISO8601DateTime(parsed, _DateUtil.UTC, cf2dc);
-            fail();
-        } catch (DateParseException e) {
-            // Expected
-            echo(e);
-        }
-    }
-    
-    private void echo(@SuppressWarnings("unused") DateParseException e) {
-        // System.out.println(e);
-    }
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/util/FTLUtilTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/util/FTLUtilTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/util/FTLUtilTest.java
deleted file mode 100644
index f1e44f3..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/util/FTLUtilTest.java
+++ /dev/null
@@ -1,117 +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.util;
-
-import static junit.framework.TestCase.assertFalse;
-import static junit.framework.TestCase.assertNull;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import org.junit.Test;
-
-public class FTLUtilTest {
-
-    @Test
-    public void testEscapeStringLiteralPart() {
-        assertEquals("", FTLUtil.escapeStringLiteralPart(""));
-        assertEquals("abc", FTLUtil.escapeStringLiteralPart("abc"));
-        assertEquals("{", FTLUtil.escapeStringLiteralPart("{"));
-        assertEquals("a{b}c", FTLUtil.escapeStringLiteralPart("a{b}c"));
-        assertEquals("a#b", FTLUtil.escapeStringLiteralPart("a#b"));
-        assertEquals("a$b", FTLUtil.escapeStringLiteralPart("a$b"));
-        assertEquals("a#\\{b}c", FTLUtil.escapeStringLiteralPart("a#{b}c"));
-        assertEquals("a$\\{b}c", FTLUtil.escapeStringLiteralPart("a${b}c"));
-        assertEquals("a'c\\\"d", FTLUtil.escapeStringLiteralPart("a'c\"d", '"'));
-        assertEquals("a\\'c\"d", FTLUtil.escapeStringLiteralPart("a'c\"d", '\''));
-        assertEquals("a\\'c\"d", FTLUtil.escapeStringLiteralPart("a'c\"d", '\''));
-        assertEquals("\\n\\r\\t\\f\\x0002\\\\", FTLUtil.escapeStringLiteralPart("\n\r\t\f\u0002\\"));
-        assertEquals("\\l\\g\\a", FTLUtil.escapeStringLiteralPart("<>&"));
-    }
-
-    @Test
-    public void testEscapeStringLiteralAll() {
-        assertFTLEsc("", "", "", "", "\"\"");
-        assertFTLEsc("\'", "\\'", "'", "\\'", "\"'\"");
-        assertFTLEsc("\"", "\\\"", "\\\"", "\"", "'\"'");
-        assertFTLEsc("\"", "\\\"", "\\\"", "\"", "'\"'");
-        assertFTLEsc("foo", "foo", "foo", "foo", "\"foo\"");
-        assertFTLEsc("foo's", "foo\\'s", "foo's", "foo\\'s", "\"foo's\"");
-        assertFTLEsc("foo \"", "foo \\\"", "foo \\\"", "foo \"", "'foo \"'");
-        assertFTLEsc("foo's \"", "foo\\'s \\\"", "foo's \\\"", "foo\\'s \"", "\"foo's \\\"\"");
-        assertFTLEsc("foo\nb\u0000c", "foo\\nb\\x0000c", "foo\\nb\\x0000c", "foo\\nb\\x0000c", "\"foo\\nb\\x0000c\"");
-    }
-
-    private void assertFTLEsc(String s, String partAny, String partQuot, String partApos, String quoted) {
-        assertEquals(partAny, FTLUtil.escapeStringLiteralPart(s));
-        assertEquals(partQuot, FTLUtil.escapeStringLiteralPart(s, '\"'));
-        assertEquals(partApos, FTLUtil.escapeStringLiteralPart(s, '\''));
-        assertEquals(quoted, FTLUtil.toStringLiteral(s));
-    }
-
-    @Test
-    public void testUnescapeStringLiteralPart() throws Exception {
-        assertEquals("", FTLUtil.unescapeStringLiteralPart(""));
-        assertEquals("1", FTLUtil.unescapeStringLiteralPart("1"));
-        assertEquals("123", FTLUtil.unescapeStringLiteralPart("123"));
-        assertEquals("1&2&3", FTLUtil.unescapeStringLiteralPart("1\\a2\\a3"));
-        assertEquals("&", FTLUtil.unescapeStringLiteralPart("\\a"));
-        assertEquals("&&&", FTLUtil.unescapeStringLiteralPart("\\a\\a\\a"));
-        assertEquals(
-                "\u0000\u0000&\u0000\u0000\u0000\u0000",
-                FTLUtil.unescapeStringLiteralPart("\\x0000\\x0000\\a\\x0000\\x000\\x00\\x0"));
-        assertEquals(
-                "'\"\n\b\u0000c><&{\\",
-                FTLUtil.unescapeStringLiteralPart("\\'\\\"\\n\\b\\x0000c\\g\\l\\a\\{\\\\"));
-    }
-
-    @Test
-    public void testEscapeIdentifier() {
-        assertNull(FTLUtil.escapeIdentifier(null));
-        assertEquals("", FTLUtil.escapeIdentifier(""));
-        assertEquals("a", FTLUtil.escapeIdentifier("a"));
-        assertEquals("ab", FTLUtil.escapeIdentifier("ab"));
-        assertEquals("\\.", FTLUtil.escapeIdentifier("."));
-        assertEquals("\\.\\:\\-", FTLUtil.escapeIdentifier(".:-"));
-        assertEquals("a\\.b", FTLUtil.escapeIdentifier("a.b"));
-        assertEquals("a\\.b\\:c\\-d", FTLUtil.escapeIdentifier("a.b:c-d"));
-    }
-
-    @Test
-    public void testIsNonEscapedIdentifierStart() {
-        assertTrue(FTLUtil.isNonEscapedIdentifierPart('a'));
-        assertTrue(FTLUtil.isNonEscapedIdentifierPart('á'));
-        assertTrue(FTLUtil.isNonEscapedIdentifierPart('1'));
-        assertFalse(FTLUtil.isNonEscapedIdentifierPart('-'));
-        assertFalse(FTLUtil.isNonEscapedIdentifierPart(' '));
-        assertFalse(FTLUtil.isNonEscapedIdentifierPart('\u0000'));
-        assertFalse(FTLUtil.isNonEscapedIdentifierPart('\\'));
-    }
-
-    @Test
-    public void testisNonEscapedIdentifierStart() {
-        assertTrue(FTLUtil.isNonEscapedIdentifierStart('a'));
-        assertTrue(FTLUtil.isNonEscapedIdentifierStart('á'));
-        assertFalse(FTLUtil.isNonEscapedIdentifierStart('1'));
-        assertFalse(FTLUtil.isNonEscapedIdentifierStart('-'));
-        assertFalse(FTLUtil.isNonEscapedIdentifierStart(' '));
-        assertFalse(FTLUtil.isNonEscapedIdentifierStart('\u0000'));
-        assertFalse(FTLUtil.isNonEscapedIdentifierStart('\\'));
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/util/NumberUtilTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/util/NumberUtilTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/util/NumberUtilTest.java
deleted file mode 100644
index d5709da..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/util/NumberUtilTest.java
+++ /dev/null
@@ -1,215 +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.util;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-
-import org.junit.Test;
-
-import junit.framework.TestCase;
-
-public class NumberUtilTest extends TestCase {
-
-    @Test
-    public void testGetSignum() {
-        assertEquals(1, _NumberUtil.getSignum(Double.valueOf(Double.POSITIVE_INFINITY)));
-        assertEquals(1, _NumberUtil.getSignum(Double.valueOf(3)));
-        assertEquals(0, _NumberUtil.getSignum(Double.valueOf(0)));
-        assertEquals(-1, _NumberUtil.getSignum(Double.valueOf(-3)));
-        assertEquals(-1, _NumberUtil.getSignum(Double.valueOf(Double.NEGATIVE_INFINITY)));
-        try {
-            _NumberUtil.getSignum(Double.valueOf(Double.NaN));
-            fail();
-        } catch (ArithmeticException e) {
-            // expected
-        }
-        
-        assertEquals(1, _NumberUtil.getSignum(Float.valueOf(Float.POSITIVE_INFINITY)));
-        assertEquals(1, _NumberUtil.getSignum(Float.valueOf(3)));
-        assertEquals(0, _NumberUtil.getSignum(Float.valueOf(0)));
-        assertEquals(-1, _NumberUtil.getSignum(Float.valueOf(-3)));
-        assertEquals(-1, _NumberUtil.getSignum(Float.valueOf(Float.NEGATIVE_INFINITY)));
-        try {
-            _NumberUtil.getSignum(Float.valueOf(Float.NaN));
-            fail();
-        } catch (ArithmeticException e) {
-            // expected
-        }
-        
-        assertEquals(1, _NumberUtil.getSignum(Long.valueOf(3)));
-        assertEquals(0, _NumberUtil.getSignum(Long.valueOf(0)));
-        assertEquals(-1, _NumberUtil.getSignum(Long.valueOf(-3)));
-        
-        assertEquals(1, _NumberUtil.getSignum(Integer.valueOf(3)));
-        assertEquals(0, _NumberUtil.getSignum(Integer.valueOf(0)));
-        assertEquals(-1, _NumberUtil.getSignum(Integer.valueOf(-3)));
-        
-        assertEquals(1, _NumberUtil.getSignum(Short.valueOf((short) 3)));
-        assertEquals(0, _NumberUtil.getSignum(Short.valueOf((short) 0)));
-        assertEquals(-1, _NumberUtil.getSignum(Short.valueOf((short) -3)));
-        
-        assertEquals(1, _NumberUtil.getSignum(Byte.valueOf((byte) 3)));
-        assertEquals(0, _NumberUtil.getSignum(Byte.valueOf((byte) 0)));
-        assertEquals(-1, _NumberUtil.getSignum(Byte.valueOf((byte) -3)));
-        
-        assertEquals(1, _NumberUtil.getSignum(BigDecimal.valueOf(3)));
-        assertEquals(0, _NumberUtil.getSignum(BigDecimal.valueOf(0)));
-        assertEquals(-1, _NumberUtil.getSignum(BigDecimal.valueOf(-3)));
-        
-        assertEquals(1, _NumberUtil.getSignum(BigInteger.valueOf(3)));
-        assertEquals(0, _NumberUtil.getSignum(BigInteger.valueOf(0)));
-        assertEquals(-1, _NumberUtil.getSignum(BigInteger.valueOf(-3)));
-    }
-    
-    @Test
-    public void testIsBigDecimalInteger() {
-        BigDecimal n1 = new BigDecimal("1.125");
-        if (n1.precision() != 4 || n1.scale() != 3) {
-            throw new RuntimeException("Wrong: " +  n1);
-        }
-        BigDecimal n2 = new BigDecimal("1.125").subtract(new BigDecimal("0.005"));
-        if (n2.precision() != 4 || n2.scale() != 3) {
-            throw new RuntimeException("Wrong: " +  n2);
-        }
-        BigDecimal n3 = new BigDecimal("123");
-        BigDecimal n4 = new BigDecimal("6000");
-        BigDecimal n5 = new BigDecimal("1.12345").subtract(new BigDecimal("0.12345"));
-        if (n5.precision() != 6 || n5.scale() != 5) {
-            throw new RuntimeException("Wrong: " +  n5);
-        }
-        BigDecimal n6 = new BigDecimal("0"); 
-        BigDecimal n7 = new BigDecimal("0.001").subtract(new BigDecimal("0.001")); 
-        BigDecimal n8 = new BigDecimal("60000.5").subtract(new BigDecimal("0.5")); 
-        BigDecimal n9 = new BigDecimal("6").movePointRight(3).setScale(-3);
-        
-        BigDecimal[] ns = new BigDecimal[] {
-                n1, n2, n3, n4, n5, n6, n7, n8, n9,
-                n1.negate(), n2.negate(), n3.negate(), n4.negate(), n5.negate(), n6.negate(), n7.negate(), n8.negate(),
-                n9.negate(),
-        };
-        
-        for (BigDecimal n : ns) {
-            assertEquals(n.doubleValue() == n.longValue(), _NumberUtil.isIntegerBigDecimal(n));
-        }
-        
-    }
-    
-    @Test
-    public void testToIntExcact() {
-        for (int n : new int[] { Integer.MIN_VALUE, Byte.MIN_VALUE, -1, 0, 1, Byte.MAX_VALUE, Integer.MAX_VALUE }) {
-            if (n != Integer.MIN_VALUE && n != Integer.MAX_VALUE) {
-                assertEquals(n, _NumberUtil.toIntExact(Byte.valueOf((byte) n)));
-                assertEquals(n, _NumberUtil.toIntExact(Short.valueOf((short) n)));
-                assertEquals(n, _NumberUtil.toIntExact(Float.valueOf(n)));
-            }
-            assertEquals(n, _NumberUtil.toIntExact(Integer.valueOf(n)));
-            assertEquals(n, _NumberUtil.toIntExact(Long.valueOf(n)));
-            assertEquals(n, _NumberUtil.toIntExact(Double.valueOf(n)));
-            assertEquals(n, _NumberUtil.toIntExact(BigDecimal.valueOf(n)));
-            assertEquals(n, _NumberUtil.toIntExact(BigDecimal.valueOf(n * 10L).divide(BigDecimal.TEN)));
-            assertEquals(n, _NumberUtil.toIntExact(BigInteger.valueOf(n)));
-        }
-
-        try {
-            _NumberUtil.toIntExact(Long.valueOf(Integer.MIN_VALUE - 1L));
-            fail();
-        } catch (ArithmeticException e) {
-            // Expected
-        }
-        try {
-            _NumberUtil.toIntExact(Long.valueOf(Integer.MAX_VALUE + 1L));
-            fail();
-        } catch (ArithmeticException e) {
-            // Expected
-        }
-
-        try {
-            _NumberUtil.toIntExact(Float.valueOf(1.00001f));
-            fail();
-        } catch (ArithmeticException e) {
-            // Expected
-        }
-        try {
-            _NumberUtil.toIntExact(Float.valueOf(Integer.MIN_VALUE - 129L));
-            fail();
-        } catch (ArithmeticException e) {
-            // Expected
-        }
-        try {
-            _NumberUtil.toIntExact(Float.valueOf(Integer.MAX_VALUE));
-            fail();
-        } catch (ArithmeticException e) {
-            // Expected
-        }
-        
-        try {
-            _NumberUtil.toIntExact(Double.valueOf(1.00001));
-            fail();
-        } catch (ArithmeticException e) {
-            // Expected
-        }
-        try {
-            _NumberUtil.toIntExact(Double.valueOf(Integer.MIN_VALUE - 1L));
-            fail();
-        } catch (ArithmeticException e) {
-            // Expected
-        }
-        try {
-            _NumberUtil.toIntExact(Double.valueOf(Integer.MAX_VALUE + 1L));
-            fail();
-        } catch (ArithmeticException e) {
-            // Expected
-        }
-        
-        try {
-            _NumberUtil.toIntExact(new BigDecimal("100.000001"));
-            fail();
-        } catch (ArithmeticException e) {
-            // Expected
-        }
-        try {
-            _NumberUtil.toIntExact(BigDecimal.valueOf(Integer.MIN_VALUE - 1L));
-            fail();
-        } catch (ArithmeticException e) {
-            // Expected
-        }
-        try {
-            _NumberUtil.toIntExact(BigDecimal.valueOf(Integer.MAX_VALUE + 1L));
-            fail();
-        } catch (ArithmeticException e) {
-            // Expected
-        }
-        
-        try {
-            _NumberUtil.toIntExact(BigInteger.valueOf(Integer.MIN_VALUE - 1L));
-            fail();
-        } catch (ArithmeticException e) {
-            // Expected
-        }
-        try {
-            _NumberUtil.toIntExact(BigInteger.valueOf(Integer.MAX_VALUE + 1L));
-            fail();
-        } catch (ArithmeticException e) {
-            // Expected
-        }
-    }
-
-}


[15/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/CommonSupertypeForUnwrappingHintTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/CommonSupertypeForUnwrappingHintTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/CommonSupertypeForUnwrappingHintTest.java
deleted file mode 100644
index ef15dae..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/CommonSupertypeForUnwrappingHintTest.java
+++ /dev/null
@@ -1,129 +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.model.impl;
-
-import java.io.Serializable;
-import java.util.List;
-
-import org.apache.freemarker.core.model.TemplateModelException;
-
-import junit.framework.TestCase;
-
-public class CommonSupertypeForUnwrappingHintTest extends TestCase {
-    
-    final OverloadedMethodsSubset oms = new DummyOverloadedMethodsSubset();
-
-    public CommonSupertypeForUnwrappingHintTest(String name) {
-        super(name);
-    }
-
-    public void testInterfaces() {
-        assertEquals(Serializable.class, oms.getCommonSupertypeForUnwrappingHint(String.class, Number.class));
-        assertEquals(C1I1.class, oms.getCommonSupertypeForUnwrappingHint(C2ExtC1I1.class, C3ExtC1I1.class));
-        assertEquals(Object.class, oms.getCommonSupertypeForUnwrappingHint(C3I1I2.class, C4I1I2.class));
-        assertEquals(I1.class, oms.getCommonSupertypeForUnwrappingHint(C3I1I2.class, C5I1.class));
-        assertEquals(I1.class, oms.getCommonSupertypeForUnwrappingHint(C3I1I2.class, I1.class));
-        assertEquals(I2.class, oms.getCommonSupertypeForUnwrappingHint(C3I1I2.class, I2.class));
-        assertEquals(I1.class, oms.getCommonSupertypeForUnwrappingHint(I1I2.class, I1.class));
-        assertEquals(I2.class, oms.getCommonSupertypeForUnwrappingHint(I1I2.class, I2.class));
-        assertEquals(CharSequence.class, oms.getCommonSupertypeForUnwrappingHint(String.class, StringBuilder.class));
-        assertEquals(C6.class, oms.getCommonSupertypeForUnwrappingHint(C7ExtC6I1.class, C8ExtC6I1.class));
-    }
-
-    public void testArrayAndOther() {
-        testArrayAndOther(oms);
-    }
-    
-    /** These will be the same with oms and buggy: */
-    private void testArrayAndOther(OverloadedMethodsSubset oms) {
-        assertEquals(Serializable.class, oms.getCommonSupertypeForUnwrappingHint(int[].class, String.class));
-        assertEquals(Serializable.class, oms.getCommonSupertypeForUnwrappingHint(Object[].class, String.class));
-        
-        assertEquals(Object.class, oms.getCommonSupertypeForUnwrappingHint(int[].class, List.class));
-        assertEquals(Object.class, oms.getCommonSupertypeForUnwrappingHint(Object[].class, List.class));
-        
-        assertEquals(int[].class, oms.getCommonSupertypeForUnwrappingHint(int[].class, int[].class));
-        assertEquals(Object[].class, oms.getCommonSupertypeForUnwrappingHint(Object[].class, Object[].class));
-    }
-    
-    public void testArrayAndDifferentArray() {
-        assertEquals(Serializable.class, oms.getCommonSupertypeForUnwrappingHint(int[].class, Object[].class));
-        assertEquals(Serializable.class, oms.getCommonSupertypeForUnwrappingHint(int[].class, long[].class));
-    }
-    
-    public void testPrimitive() {
-        assertEquals(Integer.class, oms.getCommonSupertypeForUnwrappingHint(int.class, Integer.class));
-        assertEquals(Integer.class, oms.getCommonSupertypeForUnwrappingHint(Integer.class, int.class));
-        assertEquals(Number.class, oms.getCommonSupertypeForUnwrappingHint(int.class, Long.class));
-        assertEquals(Number.class, oms.getCommonSupertypeForUnwrappingHint(Long.class, int.class));
-        assertEquals(Number.class, oms.getCommonSupertypeForUnwrappingHint(Integer.class, long.class));
-        assertEquals(Number.class, oms.getCommonSupertypeForUnwrappingHint(long.class, Integer.class));
-        assertEquals(Boolean.class, oms.getCommonSupertypeForUnwrappingHint(boolean.class, Boolean.class));
-        assertEquals(Boolean.class, oms.getCommonSupertypeForUnwrappingHint(Boolean.class, boolean.class));
-        assertEquals(Character.class, oms.getCommonSupertypeForUnwrappingHint(char.class, Character.class));
-        assertEquals(Character.class, oms.getCommonSupertypeForUnwrappingHint(Character.class, char.class));
-        assertEquals(Number.class, oms.getCommonSupertypeForUnwrappingHint(int.class, short.class));
-        assertEquals(Number.class, oms.getCommonSupertypeForUnwrappingHint(short.class, int.class));
-    }
-
-    public void testMisc() {
-        assertEquals(Number.class, oms.getCommonSupertypeForUnwrappingHint(Long.class, Integer.class));
-        assertEquals(char.class, oms.getCommonSupertypeForUnwrappingHint(char.class, char.class));
-        assertEquals(Integer.class, oms.getCommonSupertypeForUnwrappingHint(Integer.class, Integer.class));
-        assertEquals(String.class, oms.getCommonSupertypeForUnwrappingHint(String.class, String.class));
-    }
-    
-    static interface I1 { };
-    static class C1I1 implements I1 { };
-    static class C2ExtC1I1 extends C1I1 { };
-    static class C3ExtC1I1 extends C1I1 { };
-    static interface I2 { };
-    static class C3I1I2 implements I1, I2 { };
-    static class C4I1I2 implements I1, I2 { };
-    static class C5I1 implements I1 { };
-    static interface I1I2 extends I1, I2 { };
-    static class C6 { };
-    static class C7ExtC6I1 extends C6 implements I1 { };
-    static class C8ExtC6I1 extends C6 implements I1 { };
-    
-    private static class DummyOverloadedMethodsSubset extends OverloadedMethodsSubset {
-
-        DummyOverloadedMethodsSubset() {
-            super();
-        }
-
-        @Override
-        Class[] preprocessParameterTypes(CallableMemberDescriptor memberDesc) {
-            return memberDesc.getParamTypes();
-        }
-
-        @Override
-        void afterWideningUnwrappingHints(Class[] paramTypes, int[] paramNumericalTypes) {
-            // Do nothing
-        }
-
-        @Override
-        MaybeEmptyMemberAndArguments getMemberAndArguments(List tmArgs, DefaultObjectWrapper w) throws TemplateModelException {
-            throw new RuntimeException("Not implemented in this dummy.");
-        }
-        
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperDesc.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperDesc.java b/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperDesc.java
deleted file mode 100644
index 0ed6e7c..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperDesc.java
+++ /dev/null
@@ -1,31 +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.model.impl;
-
-import org.apache.freemarker.core.Configuration;
-
-public class DefaultObjectWrapperDesc extends DefaultObjectWrapper {
-
-    public DefaultObjectWrapperDesc() {
-        super(new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0)
-                .methodSorter(new AlphabeticalMethodSorter(true)), true);
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperInc.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperInc.java b/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperInc.java
deleted file mode 100644
index eb2cda0..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperInc.java
+++ /dev/null
@@ -1,31 +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.model.impl;
-
-import org.apache.freemarker.core.Configuration;
-
-public class DefaultObjectWrapperInc extends DefaultObjectWrapper {
-
-    public DefaultObjectWrapperInc() {
-        super(new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0)
-                .methodSorter(new AlphabeticalMethodSorter(false)), true);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperModelFactoryRegistrationTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperModelFactoryRegistrationTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperModelFactoryRegistrationTest.java
deleted file mode 100644
index 5c2f653..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperModelFactoryRegistrationTest.java
+++ /dev/null
@@ -1,63 +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.model.impl;
-
-import static org.junit.Assert.*;
-
-import java.lang.ref.Reference;
-
-import org.apache.freemarker.core.Configuration;
-import org.junit.Test;
-
-public class DefaultObjectWrapperModelFactoryRegistrationTest {
-
-    @Test
-    public void introspectionSettingChanges() {
-        DefaultObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).usePrivateCaches(true)
-                .build();
-        ClassIntrospector ci1 = ow.getClassIntrospector();
-        checkRegisteredModelFactories(ci1, ow.getStaticModels(), ow.getEnumModels());
-    }
-
-    private void checkRegisteredModelFactories(ClassIntrospector ci, Object... expected) {
-        Object[] actualRefs = ci.getRegisteredModelFactoriesSnapshot();
-
-        scanActuals: for (Object actaulRef : actualRefs) {
-            Object actualItem = ((Reference) actaulRef).get();
-            for (Object expectedItem : expected) {
-                if (actualItem == expectedItem) {
-                    continue scanActuals;
-                }
-            }
-            fail("Actual item " + actualItem + " is not among the expected items");
-        }
-
-        scanExpecteds: for (Object expectedItem : expected) {
-            for (Object ref : actualRefs) {
-                Object actualItem = ((Reference) ref).get();
-                if (actualItem == expectedItem) {
-                    continue scanExpecteds;
-                }
-            }
-            fail("Expected item " + expectedItem + " is not among the actual items");
-        }
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperSingletonsTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperSingletonsTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperSingletonsTest.java
deleted file mode 100644
index 767b640..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperSingletonsTest.java
+++ /dev/null
@@ -1,675 +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.model.impl;
-
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
-import java.lang.ref.Reference;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.freemarker.core.Configuration;
-import org.apache.freemarker.core.Version;
-import org.apache.freemarker.core.model.TemplateDateModel;
-import org.apache.freemarker.core.model.TemplateHashModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateScalarModel;
-import org.apache.freemarker.test.util.CoreTestUtil;
-
-import junit.framework.TestCase;
-
-public class DefaultObjectWrapperSingletonsTest extends TestCase {
-
-    public DefaultObjectWrapperSingletonsTest(String name) {
-        super(name);
-    }
-    
-    @Override
-    protected void setUp() throws Exception {
-        DefaultObjectWrapper.Builder.clearInstanceCache();
-    }
-
-    public void testBuilderEqualsAndHash() throws Exception {
-        assertEquals(Configuration.VERSION_3_0_0, new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).getIncompatibleImprovements());
-        try {
-            new DefaultObjectWrapper.Builder(CoreTestUtil.getClosestFutureVersion());
-            fail("Maybe you need to update this test for the new FreeMarker version");
-        } catch (IllegalArgumentException e) {
-            assertThat(e.getMessage(), containsString("upgrade"));
-        }
-
-        DefaultObjectWrapper.Builder builder1;
-        DefaultObjectWrapper.Builder builder2;
-        
-        builder1 = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
-        builder2 = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
-        assertEquals(builder1, builder2);
-        
-        builder1.setExposeFields(true);
-        assertNotEquals(builder1, builder2);
-        assertNotEquals(builder1.hashCode(), builder2.hashCode());
-        builder2.setExposeFields(true);
-        assertEquals(builder1, builder2);
-        assertEquals(builder1.hashCode(), builder2.hashCode());
-        
-        builder1.setExposureLevel(0);
-        assertNotEquals(builder1, builder2);
-        assertNotEquals(builder1.hashCode(), builder2.hashCode());
-        builder2.setExposureLevel(0);
-        assertEquals(builder1, builder2);
-        assertEquals(builder1.hashCode(), builder2.hashCode());
-        
-        builder1.setExposureLevel(1);
-        assertNotEquals(builder1, builder2);
-        assertNotEquals(builder1.hashCode(), builder2.hashCode());
-        builder2.setExposureLevel(1);
-        assertEquals(builder1, builder2);
-        assertEquals(builder1.hashCode(), builder2.hashCode());
-        
-        builder1.setDefaultDateType(TemplateDateModel.DATE);
-        assertNotEquals(builder1, builder2);
-        builder2.setDefaultDateType(TemplateDateModel.DATE);
-        assertEquals(builder1, builder2);
-        assertEquals(builder1.hashCode(), builder2.hashCode());
-        
-        builder1.setStrict(true);
-        assertNotEquals(builder1, builder2);
-        assertNotEquals(builder1.hashCode(), builder2.hashCode());
-        builder2.setStrict(true);
-        assertEquals(builder1, builder2);
-        assertEquals(builder1.hashCode(), builder2.hashCode());
-
-        builder1.setUseModelCache(true);
-        assertNotEquals(builder1, builder2);
-        assertNotEquals(builder1.hashCode(), builder2.hashCode());
-        builder2.setUseModelCache(true);
-        assertEquals(builder1, builder2);
-        assertEquals(builder1.hashCode(), builder2.hashCode());
-        
-        AlphabeticalMethodSorter ms = new AlphabeticalMethodSorter(true);
-        builder1.setMethodSorter(ms);
-        assertNotEquals(builder1, builder2);
-        builder2.setMethodSorter(ms);
-        assertEquals(builder1, builder2);
-        assertEquals(builder1.hashCode(), builder2.hashCode());
-
-        MethodAppearanceFineTuner maft = new MethodAppearanceFineTuner() {
-            @Override
-            public void process(DecisionInput in, Decision out) { }
-        };
-        builder1.setMethodAppearanceFineTuner(maft);
-        assertNotEquals(builder1, builder2);
-        builder2.setMethodAppearanceFineTuner(maft);
-        assertEquals(builder1, builder2);
-        assertEquals(builder1.hashCode(), builder2.hashCode());
-    }
-    
-    public void testDefaultObjectWrapperBuilderProducts() throws Exception {
-        List<DefaultObjectWrapper> hardReferences = new LinkedList<>();
-        
-        assertEquals(0, getDefaultObjectWrapperInstanceCacheSize());
-        
-        {
-            DefaultObjectWrapper ow = getDefaultObjectWrapperWithSetting(Configuration.VERSION_3_0_0, true);
-            assertEquals(1, getDefaultObjectWrapperInstanceCacheSize());
-            assertSame(ow.getClass(), DefaultObjectWrapper.class);
-            assertEquals(Configuration.VERSION_3_0_0, ow.getIncompatibleImprovements());
-            assertFalse(ow.isStrict());
-            assertTrue(ow.getUseModelCache());
-            assertEquals(TemplateDateModel.UNKNOWN, ow.getDefaultDateType());
-            assertSame(ow, ow.getOuterIdentity());
-            assertTrue(ow.isClassIntrospectionCacheRestricted());
-            assertNull(ow.getMethodAppearanceFineTuner());
-            assertNull(ow.getMethodSorter());
-
-            assertSame(ow, getDefaultObjectWrapperWithSetting(Configuration.VERSION_3_0_0, true));
-            assertEquals(1, getDefaultObjectWrapperInstanceCacheSize());
-            
-            hardReferences.add(ow);
-        }
-        
-        {
-            DefaultObjectWrapper ow = getDefaultObjectWrapperWithSetting(Configuration.VERSION_3_0_0, false);
-            assertEquals(2, getDefaultObjectWrapperInstanceCacheSize());
-            assertSame(ow.getClass(), DefaultObjectWrapper.class);
-            assertEquals(Configuration.VERSION_3_0_0, ow.getIncompatibleImprovements());
-            assertFalse(ow.getUseModelCache());
-
-            assertSame(ow, getDefaultObjectWrapperWithSetting(Configuration.VERSION_3_0_0, false));
-            
-            hardReferences.add(ow);
-        }
-        
-        {
-            DefaultObjectWrapper.Builder factory = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
-            factory.setExposureLevel(DefaultObjectWrapper.EXPOSE_PROPERTIES_ONLY);
-            DefaultObjectWrapper ow1 = factory.build();
-            DefaultObjectWrapper ow2 = factory.build();
-            assertEquals(3, getDefaultObjectWrapperInstanceCacheSize());
-            assertSame(ow1, ow2);
-            
-            assertSame(ow1.getClass(), DefaultObjectWrapper.class);
-            assertEquals(Configuration.VERSION_3_0_0, ow1.getIncompatibleImprovements());
-            assertEquals(DefaultObjectWrapper.EXPOSE_PROPERTIES_ONLY, ow1.getExposureLevel());
-            assertFalse(ow1.isStrict());
-            assertEquals(TemplateDateModel.UNKNOWN, ow1.getDefaultDateType());
-            assertSame(ow1, ow1.getOuterIdentity());
-            
-            hardReferences.add(ow1);
-        }
-        
-        {
-            DefaultObjectWrapper.Builder factory = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
-            factory.setExposeFields(true);
-            DefaultObjectWrapper ow1 = factory.build();
-            DefaultObjectWrapper ow2 = factory.build();
-            assertEquals(4, getDefaultObjectWrapperInstanceCacheSize());
-            assertSame(ow1, ow2);
-            
-            assertSame(ow1.getClass(), DefaultObjectWrapper.class);
-            assertEquals(Configuration.VERSION_3_0_0, ow1.getIncompatibleImprovements());
-            assertTrue(ow1.isExposeFields());
-            
-            hardReferences.add(ow1);
-        }
-        
-        {
-            DefaultObjectWrapper.Builder factory = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
-            factory.setStrict(true);
-            factory.setDefaultDateType(TemplateDateModel.DATETIME);
-            factory.setOuterIdentity(new RestrictedObjectWrapper.Builder(Configuration.VERSION_3_0_0).build());
-            DefaultObjectWrapper ow = factory.build();
-            assertEquals(5, getDefaultObjectWrapperInstanceCacheSize());
-            assertTrue(ow.isStrict());
-            assertEquals(TemplateDateModel.DATETIME, ow.getDefaultDateType());
-            assertSame(RestrictedObjectWrapper.class, ow.getOuterIdentity().getClass());
-            
-            hardReferences.add(ow);
-        }
-        
-        // Effect of reference and cache clearings:
-        {
-            DefaultObjectWrapper bw1 = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
-            assertEquals(5, getDefaultObjectWrapperInstanceCacheSize());
-            assertEquals(5, getDefaultObjectWrapperNonClearedInstanceCacheSize());
-            
-            clearDefaultObjectWrapperInstanceCacheReferences(false);
-            assertEquals(5, getDefaultObjectWrapperInstanceCacheSize());
-            assertEquals(0, getDefaultObjectWrapperNonClearedInstanceCacheSize());
-            
-            DefaultObjectWrapper bw2 = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
-            assertNotSame(bw1, bw2);
-            assertEquals(5, getDefaultObjectWrapperInstanceCacheSize());
-            assertEquals(1, getDefaultObjectWrapperNonClearedInstanceCacheSize());
-            
-            assertSame(bw2, new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build());
-            assertEquals(1, getDefaultObjectWrapperNonClearedInstanceCacheSize());
-            
-            clearDefaultObjectWrapperInstanceCacheReferences(true);
-            DefaultObjectWrapper bw3 = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
-            assertNotSame(bw2, bw3);
-            assertEquals(1, getDefaultObjectWrapperInstanceCacheSize());
-            assertEquals(1, getDefaultObjectWrapperNonClearedInstanceCacheSize());
-        }
-
-        {
-            DefaultObjectWrapper.Builder factory = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
-            factory.setUseModelCache(true);
-            DefaultObjectWrapper ow = factory.build();
-            assertTrue(ow.getUseModelCache());
-            assertEquals(2, getDefaultObjectWrapperInstanceCacheSize());
-            
-            hardReferences.add(ow);
-        }
-        
-        assertTrue(hardReferences.size() != 0);  // just to save it from GC until this line        
-    }
-    
-    private DefaultObjectWrapper getDefaultObjectWrapperWithSetting(Version ici, boolean useModelCache) {
-        DefaultObjectWrapper.Builder f = new DefaultObjectWrapper.Builder(ici);
-        f.setUseModelCache(useModelCache);
-        return f.build();
-    }
-
-    public void testMultipleTCCLs() {
-        List<DefaultObjectWrapper> hardReferences = new LinkedList<>();
-        
-        assertEquals(0, getDefaultObjectWrapperInstanceCacheSize());
-        
-        DefaultObjectWrapper bw1 = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
-        assertEquals(1, getDefaultObjectWrapperInstanceCacheSize());
-        hardReferences.add(bw1);
-        
-        ClassLoader oldTCCL = Thread.currentThread().getContextClassLoader();
-        // Doesn't mater what, just be different from oldTCCL: 
-        ClassLoader newTCCL = oldTCCL == null ? getClass().getClassLoader() : null;
-        
-        DefaultObjectWrapper bw2;
-        Thread.currentThread().setContextClassLoader(newTCCL);
-        try {
-            bw2 = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
-            assertEquals(2, getDefaultObjectWrapperInstanceCacheSize());
-            hardReferences.add(bw2);
-            
-            assertNotSame(bw1, bw2);
-            assertSame(bw2, new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build());
-        } finally {
-            Thread.currentThread().setContextClassLoader(oldTCCL);
-        }
-        
-        assertSame(bw1, new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build());
-        assertEquals(2, getDefaultObjectWrapperInstanceCacheSize());
-
-        DefaultObjectWrapper bw3;
-        Thread.currentThread().setContextClassLoader(newTCCL);
-        try {
-            assertSame(bw2, new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build());
-            
-            DefaultObjectWrapper.Builder bwb = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
-            bwb.setExposeFields(true);
-            bw3 = bwb.build();
-            assertEquals(3, getDefaultObjectWrapperInstanceCacheSize());
-            hardReferences.add(bw3);
-        } finally {
-            Thread.currentThread().setContextClassLoader(oldTCCL);
-        }
-        
-        {
-            DefaultObjectWrapper.Builder bwb = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
-            bwb.setExposeFields(true);
-            DefaultObjectWrapper bw4 = bwb.build();
-            assertEquals(4, getDefaultObjectWrapperInstanceCacheSize());
-            assertNotSame(bw3, bw4);
-            hardReferences.add(bw4);
-        }
-        
-        assertTrue(hardReferences.size() != 0);  // just to save it from GC until this line        
-    }
-    
-    public void testClassInrospectorCache() throws TemplateModelException {
-        assertFalse(new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0)
-                .usePrivateCaches(true).build().isClassIntrospectionCacheRestricted());
-        assertTrue(new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0)
-                .build().isClassIntrospectionCacheRestricted());
-        
-        ClassIntrospector.Builder.clearInstanceCache();
-        DefaultObjectWrapper.Builder.clearInstanceCache();
-        checkClassIntrospectorCacheSize(0);
-        
-        List<DefaultObjectWrapper> hardReferences = new LinkedList<>();
-        DefaultObjectWrapper.Builder builder;
-
-        {
-            builder = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
-            
-            DefaultObjectWrapper bw1 = builder.build();
-            checkClassIntrospectorCacheSize(1);
-            
-            builder.setExposureLevel(DefaultObjectWrapper.EXPOSE_SAFE);  // this was already set to this
-            builder.setUseModelCache(true);  // this shouldn't matter for the introspection cache
-            DefaultObjectWrapper bw2 = builder.build();
-            checkClassIntrospectorCacheSize(1);
-            
-            assertSame(bw2.getClassIntrospector(), bw1.getClassIntrospector());
-            assertNotSame(bw1, bw2);
-            
-            // Wrapping tests:
-            assertFalse(exposesFields(bw1));
-            assertTrue(exposesProperties(bw1));
-            assertTrue(exposesMethods(bw1));
-            assertFalse(exposesUnsafe(bw1));
-            assertTrue(bw1.isClassIntrospectionCacheRestricted());
-            // Prevent introspection cache GC:
-            hardReferences.add(bw1);
-            hardReferences.add(bw2);
-        }
-        
-        {
-            builder = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
-            builder.setExposeFields(true);
-            DefaultObjectWrapper ow = builder.build();
-            checkClassIntrospectorCacheSize(2);
-            // Wrapping tests:
-            assertTrue(exposesFields(ow));
-            assertTrue(exposesProperties(ow));
-            assertTrue(exposesMethods(ow));
-            assertFalse(exposesUnsafe(ow));
-            // Prevent introspection cache GC:
-            hardReferences.add(ow);
-        }
-
-        {
-            builder.setExposureLevel(DefaultObjectWrapper.EXPOSE_ALL);
-            DefaultObjectWrapper ow = builder.build();
-            checkClassIntrospectorCacheSize(3);
-            // Wrapping tests:
-            assertTrue(exposesFields(ow));
-            assertTrue(exposesProperties(ow));
-            assertTrue(exposesMethods(ow));
-            assertTrue(exposesUnsafe(ow));
-            // Prevent introspection cache GC:
-            hardReferences.add(ow);
-        }
-        
-        {
-            builder.setExposeFields(false);
-            DefaultObjectWrapper ow = builder.build();
-            checkClassIntrospectorCacheSize(4);
-            // Wrapping tests:
-            assertFalse(exposesFields(ow));
-            assertTrue(exposesProperties(ow));
-            assertTrue(exposesMethods(ow));
-            assertTrue(exposesUnsafe(ow));
-            // Prevent introspection cache GC:
-            hardReferences.add(ow);
-        }
-        
-        {
-            builder.setExposureLevel(DefaultObjectWrapper.EXPOSE_NOTHING);
-            DefaultObjectWrapper ow = builder.build();
-            checkClassIntrospectorCacheSize(5);
-            // Wrapping tests:
-            assertFalse(exposesFields(ow));
-            assertFalse(exposesProperties(ow));
-            assertFalse(exposesMethods(ow));
-            assertFalse(exposesUnsafe(ow));
-            // Prevent introspection cache GC:
-            hardReferences.add(ow);
-        }
-
-        {
-            builder.setExposeFields(true);
-            DefaultObjectWrapper ow = builder.build();
-            checkClassIntrospectorCacheSize(6);
-            // Wrapping tests:
-            assertTrue(exposesFields(ow));
-            assertFalse(exposesProperties(ow));
-            assertFalse(exposesMethods(ow));
-            assertFalse(exposesUnsafe(ow));
-            // Prevent introspection cache GC:
-            hardReferences.add(ow);
-        }
-
-        {
-            builder.setExposureLevel(DefaultObjectWrapper.EXPOSE_PROPERTIES_ONLY);
-            DefaultObjectWrapper ow = builder.build();
-            checkClassIntrospectorCacheSize(7);
-            // Wrapping tests:
-            assertTrue(exposesFields(ow));
-            assertTrue(exposesProperties(ow));
-            assertFalse(exposesMethods(ow));
-            assertFalse(exposesUnsafe(ow));
-            // Prevent introspection cache GC:
-            hardReferences.add(ow);
-        }
-        
-        {
-            builder = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
-            builder.setUseModelCache(true);
-            builder.setExposeFields(false);
-            builder.setExposureLevel(DefaultObjectWrapper.EXPOSE_PROPERTIES_ONLY);
-            
-            DefaultObjectWrapper bw1 = builder.build();
-            checkClassIntrospectorCacheSize(8);
-            ClassIntrospector ci1 = bw1.getClassIntrospector();
-            
-            builder.setUseModelCache(false);  // Shouldn't mater for the ClassIntrospector
-            DefaultObjectWrapper bw2 = builder.build();
-            ClassIntrospector ci2 = bw2.getClassIntrospector();
-            checkClassIntrospectorCacheSize(8);
-            
-            assertSame(ci1, ci2);
-            assertNotSame(bw1, bw2);
-            
-            // Wrapping tests:
-            assertFalse(exposesFields(bw1));
-            assertTrue(exposesProperties(bw1));
-            assertFalse(exposesMethods(bw1));
-            assertFalse(exposesUnsafe(bw1));
-
-            // Prevent introspection cache GC:
-            hardReferences.add(bw1);
-            hardReferences.add(bw2);
-        }
-
-        // The ClassInrospector cache couldn't become cleared in reality otherwise:
-        DefaultObjectWrapper.Builder.clearInstanceCache();
-
-        clearClassIntrospectorInstanceCacheReferences(false);
-        checkClassIntrospectorCacheSize(8);
-        assertEquals(0, getClassIntrospectorNonClearedInstanceCacheSize());
-
-        {
-            builder.setExposeFields(false);
-            
-            DefaultObjectWrapper bw1 = builder.build();
-            checkClassIntrospectorCacheSize(8);
-            assertEquals(1, getClassIntrospectorNonClearedInstanceCacheSize());
-            ClassIntrospector ci1 = bw1.getClassIntrospector();
-            
-            builder.setUseModelCache(true);  // Shouldn't mater
-            DefaultObjectWrapper bw2 = builder.build();
-            ClassIntrospector ci2 = bw2.getClassIntrospector();
-            
-            assertSame(ci1, ci2);
-            assertNotSame(bw1, bw2);
-            
-            // Wrapping tests:
-            assertFalse(exposesFields(bw1));
-            assertTrue(exposesProperties(bw1));
-            assertFalse(exposesMethods(bw1));
-            assertFalse(exposesUnsafe(bw1));
-
-            // Prevent introspection cache GC:
-            hardReferences.add(bw1);
-            hardReferences.add(bw2);
-        }
-        
-        {
-            builder = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
-            DefaultObjectWrapper ow = builder.build();
-            checkClassIntrospectorCacheSize(8);
-            assertEquals(2, getClassIntrospectorNonClearedInstanceCacheSize());
-            // Wrapping tests:
-            assertFalse(exposesFields(ow));
-            assertTrue(exposesProperties(ow));
-            assertTrue(exposesMethods(ow));
-            assertFalse(exposesUnsafe(ow));
-            // Prevent introspection cache GC:
-            hardReferences.add(ow);
-        }
-
-        clearClassIntrospectorInstanceCacheReferences(true);
-        checkClassIntrospectorCacheSize(8);
-        assertEquals(0, getClassIntrospectorNonClearedInstanceCacheSize());
-        
-        {
-            builder = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
-            builder.setExposeFields(true);
-            DefaultObjectWrapper ow = builder.build();
-            checkClassIntrospectorCacheSize(1);
-            // Wrapping tests:
-            assertTrue(exposesFields(ow));
-            assertTrue(exposesProperties(ow));
-            assertTrue(exposesMethods(ow));
-            assertFalse(exposesUnsafe(ow));
-            // Prevent introspection cache GC:
-            hardReferences.add(ow);
-        }
-        
-        {
-            builder = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
-            builder.setMethodAppearanceFineTuner(new MethodAppearanceFineTuner() {
-                @Override
-                public void process(DecisionInput in, Decision out) {
-                }
-            });  // spoils ClassIntrospector() sharing
-
-            builder.setUseModelCache(false);
-            DefaultObjectWrapper bw1 = builder.build();
-            assertSame(bw1, builder.build());
-
-            builder.setUseModelCache(true);
-            DefaultObjectWrapper bw2 = builder.build();
-            checkClassIntrospectorCacheSize(1);
-            assertNotSame(bw1, bw2);
-            assertNotSame(bw1.getClassIntrospector(), bw2.getClassIntrospector());
-            assertTrue(bw1.isClassIntrospectionCacheRestricted());
-            assertTrue(bw2.isClassIntrospectionCacheRestricted());
-        }
-
-        {
-            builder = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
-            builder.setMethodAppearanceFineTuner(
-                    GetlessMethodsAsPropertyGettersRule.INSTANCE);  // doesn't spoils sharing
-
-            builder.setUseModelCache(false);
-            DefaultObjectWrapper bw1 = builder.build();
-            assertSame(bw1, builder.build());
-            checkClassIntrospectorCacheSize(2);
-            
-            builder.setUseModelCache(true);
-            DefaultObjectWrapper bw2 = builder.build();
-            checkClassIntrospectorCacheSize(2);
-            
-            assertNotSame(bw1, bw2);
-            assertSame(bw1.getClassIntrospector(), bw2.getClassIntrospector());  // !
-            assertTrue(bw2.isClassIntrospectionCacheRestricted());
-        }
-        
-        assertTrue(hardReferences.size() != 0);  // just to save it from GC until this line        
-    }
-    
-    private void checkClassIntrospectorCacheSize(int expectedSize) {
-        assertEquals(expectedSize, getClassIntrospectorInstanceCacheSize());
-    }
-
-    public class C {
-        
-        public String foo = "FOO";
-        
-        public String getBar() {
-            return "BAR";
-        }
-        
-    }
-
-    private boolean exposesFields(DefaultObjectWrapper ow) throws TemplateModelException {
-        TemplateHashModel thm = (TemplateHashModel) ow.wrap(new C());
-        TemplateScalarModel r = (TemplateScalarModel) thm.get("foo");
-        if (r == null) return false;
-        assertEquals("FOO", r.getAsString());
-        return true;
-    }
-
-    private boolean exposesProperties(DefaultObjectWrapper ow) throws TemplateModelException {
-        TemplateHashModel thm = (TemplateHashModel) ow.wrap(new C());
-        TemplateScalarModel r = (TemplateScalarModel) thm.get("bar");
-        if (r == null) return false;
-        assertEquals("BAR", r.getAsString());
-        return true;
-    }
-
-    private boolean exposesMethods(DefaultObjectWrapper ow) throws TemplateModelException {
-        TemplateHashModel thm = (TemplateHashModel) ow.wrap(new C());
-        return thm.get("getBar") != null;
-    }
-
-    private boolean exposesUnsafe(DefaultObjectWrapper ow) throws TemplateModelException {
-        TemplateHashModel thm = (TemplateHashModel) ow.wrap(new C());
-        return thm.get("wait") != null;
-    }
-    
-    static int getClassIntrospectorInstanceCacheSize() {
-        Map instanceCache = ClassIntrospector.Builder.getInstanceCache();
-        synchronized (instanceCache) {
-            return instanceCache.size();
-        }
-    }
-
-    static int getClassIntrospectorNonClearedInstanceCacheSize() {
-        Map instanceCache = ClassIntrospector.Builder.getInstanceCache();
-        synchronized (instanceCache) {
-            int cnt = 0;
-            for (Iterator it = instanceCache.values().iterator(); it.hasNext(); ) {
-                if (((Reference) it.next()).get() != null) cnt++;
-            }
-            return cnt;
-        }
-    }
-    
-    static void clearClassIntrospectorInstanceCacheReferences(boolean enqueue) {
-        Map instanceCache = ClassIntrospector.Builder.getInstanceCache();
-        synchronized (instanceCache) {
-            for (Iterator it = instanceCache.values().iterator(); it.hasNext(); ) {
-                Reference ref = ((Reference) it.next());
-                ref.clear();
-                if (enqueue) {
-                    ref.enqueue();
-                }
-            }
-        }
-    }
-
-    static int getDefaultObjectWrapperInstanceCacheSize() {
-        Map instanceCache = DefaultObjectWrapper.Builder.getInstanceCache();
-        synchronized (instanceCache) {
-            int size = 0; 
-            for (Iterator it1 = instanceCache.values().iterator(); it1.hasNext(); ) {
-                size += ((Map) it1.next()).size();
-            }
-            return size;
-        }
-    }
-
-    static int getDefaultObjectWrapperNonClearedInstanceCacheSize() {
-        Map instanceCache = DefaultObjectWrapper.Builder.getInstanceCache();
-        synchronized (instanceCache) {
-            int cnt = 0;
-            for (Iterator it1 = instanceCache.values().iterator(); it1.hasNext(); ) {
-                Map tcclScope = (Map) it1.next();
-                for (Iterator it2 = tcclScope.values().iterator(); it2.hasNext(); ) {
-                    if (((Reference) it2.next()).get() != null) cnt++;
-                }
-            }
-            return cnt;
-        }
-    }
-    
-    static void clearDefaultObjectWrapperInstanceCacheReferences(boolean enqueue) {
-        Map instanceCache = DefaultObjectWrapper.Builder.getInstanceCache();
-        synchronized (instanceCache) {
-            for (Iterator it1 = instanceCache.values().iterator(); it1.hasNext(); ) {
-                Map tcclScope = (Map) it1.next();
-                for (Iterator it2 = tcclScope.values().iterator(); it2.hasNext(); ) {
-                    Reference ref = ((Reference) it2.next());
-                    ref.clear();
-                    if (enqueue) {
-                        ref.enqueue();
-                    }
-                }
-            }
-        }
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperTest.java
deleted file mode 100644
index 6e9ae25..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/DefaultObjectWrapperTest.java
+++ /dev/null
@@ -1,901 +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.model.impl;
-
-import static org.apache.freemarker.test.hamcerst.Matchers.*;
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.TreeSet;
-import java.util.Vector;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-
-import org.apache.freemarker.core.Configuration;
-import org.apache.freemarker.core.Template;
-import org.apache.freemarker.core.TemplateException;
-import org.apache.freemarker.core.Version;
-import org.apache.freemarker.core._CoreAPI;
-import org.apache.freemarker.core.model.AdapterTemplateModel;
-import org.apache.freemarker.core.model.ObjectWrapper;
-import org.apache.freemarker.core.model.TemplateBooleanModel;
-import org.apache.freemarker.core.model.TemplateCollectionModel;
-import org.apache.freemarker.core.model.TemplateCollectionModelEx;
-import org.apache.freemarker.core.model.TemplateHashModel;
-import org.apache.freemarker.core.model.TemplateHashModelEx;
-import org.apache.freemarker.core.model.TemplateMethodModelEx;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateModelIterator;
-import org.apache.freemarker.core.model.TemplateModelWithAPISupport;
-import org.apache.freemarker.core.model.TemplateNodeModel;
-import org.apache.freemarker.core.model.TemplateNumberModel;
-import org.apache.freemarker.core.model.TemplateScalarModel;
-import org.apache.freemarker.core.model.TemplateSequenceModel;
-import org.apache.freemarker.core.model.WrapperTemplateModel;
-import org.apache.freemarker.core.model.WrappingTemplateModel;
-import org.apache.freemarker.test.TestConfigurationBuilder;
-import org.junit.Test;
-import org.w3c.dom.Document;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-
-public class DefaultObjectWrapperTest {
-
-    private final static DefaultObjectWrapper OW = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0)
-            .build();
-
-    // This will make sense if we will have multipe incompatibleImprovement versions.
-    @Test
-    public void testIncompatibleImprovementsVersionBreakPoints() throws Exception {
-        List<Version> expected = new ArrayList<>();
-        expected.add(Configuration.VERSION_3_0_0);
-
-        List<Version> actual = new ArrayList<>();
-        int i = _CoreAPI.VERSION_INT_3_0_0;
-        while (i <= Configuration.getVersion().intValue()) {
-            int major = i / 1000000;
-            int minor = i % 1000000 / 1000;
-            int micro = i % 1000;
-            final Version version = new Version(major, minor, micro);
-            
-            final Version normalizedVersion = DefaultObjectWrapper.normalizeIncompatibleImprovementsVersion(version);
-            actual.add(normalizedVersion);
-
-            final DefaultObjectWrapper.Builder builder = new DefaultObjectWrapper.Builder(version);
-            assertEquals(normalizedVersion, builder.getIncompatibleImprovements());
-            assertEquals(normalizedVersion, builder.build().getIncompatibleImprovements());
-            
-            i++;
-        }
-
-        assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testIncompatibleImprovementsVersionOutOfBounds() throws Exception {
-        try {
-            DefaultObjectWrapper.normalizeIncompatibleImprovementsVersion(new Version(2, 2, 0));
-            fail();
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-
-        Version curVersion = Configuration.getVersion();
-        final Version futureVersion = new Version(curVersion.getMajor(), curVersion.getMicro(),
-                curVersion.getMicro() + 1);
-        try {
-            DefaultObjectWrapper.normalizeIncompatibleImprovementsVersion(futureVersion);
-            fail();
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-        try {
-            new DefaultObjectWrapper.Builder(futureVersion);
-            fail();
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-    }
-
-    @SuppressWarnings("boxing")
-    @Test
-    public void testBuilder() throws Exception {
-        DefaultObjectWrapper.Builder builder = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
-        DefaultObjectWrapper ow = builder.build();
-        assertSame(ow, builder.build());
-        assertSame(ow.getClass(), DefaultObjectWrapper.class);
-        assertEquals(Configuration.VERSION_3_0_0, ow.getIncompatibleImprovements());
-    }
-
-    @Test
-    public void testWrappedTypes() throws Exception {
-        DefaultObjectWrapper.Builder builder = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
-        DefaultObjectWrapper ow = builder.build();
-
-        assertThat(ow.wrap(new HashMap()), instanceOf(DefaultMapAdapter.class));
-        assertThat(ow.wrap(new ArrayList()), instanceOf(DefaultListAdapter.class));
-        assertThat(ow.wrap(new String[] {}), instanceOf(DefaultArrayAdapter.class));
-        assertThat(ow.wrap(new HashSet()), instanceOf(DefaultNonListCollectionAdapter.class));
-        assertThat(ow.wrap(new PureIterable()), instanceOf(DefaultIterableAdapter.class));
-        assertThat(ow.wrap(new Vector<>().iterator()), instanceOf(DefaultIteratorAdapter.class));
-        assertThat(ow.wrap(new Vector<>().elements()), instanceOf(DefaultEnumerationAdapter.class));
-    }
-    
-    @Test
-    public void testConstructors() throws Exception {
-        {
-            DefaultObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0)
-                    .usePrivateCaches(true).build();
-            assertEquals(Configuration.VERSION_3_0_0, ow.getIncompatibleImprovements());
-        }
-        
-        try {
-            new DefaultObjectWrapper.Builder(new Version(99, 9, 9)).build();
-            fail();
-        } catch (IllegalArgumentException e) {
-            assertThat(e.getMessage(), containsString("version"));
-        }
-    }
-    
-    
-    @Test
-    public void testCustomization() throws TemplateModelException {
-        CustomizedDefaultObjectWrapper ow = new CustomizedDefaultObjectWrapper(Configuration.VERSION_3_0_0);
-        assertEquals(Configuration.VERSION_3_0_0, ow.getIncompatibleImprovements());
-
-        TemplateSequenceModel seq = (TemplateSequenceModel) ow.wrap(new Tupple(11, 22));
-        assertEquals(2, seq.size());
-        assertEquals(11, ow.unwrap(seq.get(0)));
-        assertEquals(22, ow.unwrap(seq.get(1)));
-        
-        assertTrue(ow.wrap("x") instanceof SimpleScalar);
-        assertTrue(ow.wrap(1.5) instanceof SimpleNumber);
-        assertTrue(ow.wrap(new Date()) instanceof SimpleDate);
-        assertEquals(TemplateBooleanModel.TRUE, ow.wrap(true));
-        
-        assertTrue(ow.wrap(Collections.emptyMap()) instanceof DefaultMapAdapter);
-        assertTrue(ow.wrap(Collections.emptyList()) instanceof DefaultListAdapter);
-        assertTrue(ow.wrap(new boolean[] { }) instanceof DefaultArrayAdapter);
-        assertTrue(ow.wrap(new HashSet()) instanceof DefaultNonListCollectionAdapter);
-        assertTrue(ow.wrap('c') instanceof TemplateScalarModel); // BeanAndStringModel right now, but should change later
-        
-        TemplateHashModel bean = (TemplateHashModel) ow.wrap(new TestBean());
-        assertEquals(1, ow.unwrap(bean.get("x")));
-        {
-            // Check method calls, and also if the return value is wrapped with the overidden "wrap".
-            final TemplateModel mr = (TemplateModel) ((TemplateMethodModelEx) bean.get("m")).exec(Collections.emptyList());
-            assertEquals(
-                    Collections.singletonList(1),
-                    ow.unwrap(mr));
-            assertTrue(DefaultListAdapter.class.isInstance(mr));
-        }
-        {
-            // Check custom TM usage and round trip:
-            final TemplateModel mr = (TemplateModel) ((TemplateMethodModelEx) bean.get("incTupple"))
-                    .exec(Collections.singletonList(ow.wrap(new Tupple<>(1, 2))));
-            assertEquals(new Tupple<>(2, 3), ow.unwrap(mr));
-            assertTrue(TuppleAdapter.class.isInstance(mr));
-        }
-    }
-
-    @SuppressWarnings("boxing")
-    @Test
-    public void testCompositeValueWrapping() throws TemplateModelException, ClassNotFoundException {
-        DefaultObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
-
-        final Map hashMap = new HashMap();
-        inintTestMap(hashMap);
-        final Map treeMap = new TreeMap();
-        inintTestMap(treeMap);
-        final Map linkedHashMap = new LinkedHashMap();
-        inintTestMap(linkedHashMap);
-        final Map gMap = ImmutableMap.<String, Object> of("a", 1, "b", 2, "c", 3);
-        final LinkedList linkedList = new LinkedList();
-        linkedList.add("a");
-        linkedList.add("b");
-        linkedList.add("c");
-        final int[] intArray = new int[] { 1, 2, 3 };
-        final String[] stringArray = new String[] { "a", "b", "c" };
-        final PureIterable pureIterable = new PureIterable();
-        final HashSet hashSet = new HashSet();
-
-        assertRoundtrip(ow, linkedHashMap, DefaultMapAdapter.class, LinkedHashMap.class, linkedHashMap.toString());
-        assertRoundtrip(ow, treeMap, DefaultMapAdapter.class, TreeMap.class, treeMap.toString());
-        assertRoundtrip(ow, gMap, DefaultMapAdapter.class, ImmutableMap.class, gMap.toString());
-        assertRoundtrip(ow, linkedList, DefaultListAdapter.class, LinkedList.class, linkedList.toString());
-        assertRoundtrip(ow, intArray, DefaultArrayAdapter.class, int[].class, null);
-        assertRoundtrip(ow, stringArray, DefaultArrayAdapter.class, String[].class, null);
-        assertRoundtrip(ow, pureIterable, DefaultIterableAdapter.class, PureIterable.class, pureIterable.toString());
-        assertRoundtrip(ow, hashSet, DefaultNonListCollectionAdapter.class, HashSet.class, hashSet.toString());
-    }
-
-    @SuppressWarnings("boxing")
-    private void inintTestMap(Map map) {
-        map.put("a", 1);
-        map.put("b", 2);
-        map.put("c", 3);
-    }
-
-    @SuppressWarnings("boxing")
-    @Test
-    public void testMapAdapter() throws TemplateModelException {
-        HashMap<String, Object> testMap = new LinkedHashMap<>();
-        testMap.put("a", 1);
-        testMap.put("b", null);
-        testMap.put("c", "C");
-        testMap.put("d", Collections.singletonList("x"));
-
-        {
-            TemplateHashModelEx hash = (TemplateHashModelEx) OW.wrap(testMap);
-            assertEquals(4, hash.size());
-            assertFalse(hash.isEmpty());
-            assertNull(hash.get("e"));
-            assertEquals(1, ((TemplateNumberModel) hash.get("a")).getAsNumber());
-            assertNull(hash.get("b"));
-            assertEquals("C", ((TemplateScalarModel) hash.get("c")).getAsString());
-            assertTrue(hash.get("d") instanceof DefaultListAdapter);
-
-            assertCollectionTMEquals(hash.keys(), "a", "b", "c", "d");
-            assertCollectionTMEquals(hash.values(), 1, null, "C", Collections.singletonList("x"));
-            
-            assertSizeThroughAPIModel(4, hash);
-        }
-
-        {
-            assertTrue(((TemplateHashModel) OW.wrap(Collections.emptyMap())).isEmpty());
-        }
-    }
-
-    private void assertCollectionTMEquals(TemplateCollectionModel coll, Object... expectedItems)
-            throws TemplateModelException {
-        for (int i = 0; i < 2; i++) { // Run twice to check if we always get a new iterator
-            int idx = 0;
-            TemplateModelIterator it2 = null;
-            for (TemplateModelIterator it = coll.iterator(); it.hasNext(); ) {
-                TemplateModel actualItem = it.next();
-                if (idx >= expectedItems.length) {
-                    fail("Number of items is more than the expected " + expectedItems.length);
-                }
-                assertEquals(expectedItems[idx], OW.unwrap(actualItem));
-                if (i == 1) {
-                    // In the 2nd round we also test with two iterators in parallel.
-                    // This 2nd iterator is also special in that its hasNext() is never called.
-                    if (it2 == null) {
-                        it2 = coll.iterator();
-                    }
-                    assertEquals(expectedItems[idx], OW.unwrap(it2.next()));
-                }
-                idx++;
-            }
-            if (expectedItems.length != idx) {
-                fail("Number of items is " + idx + ", which is less than the expected " + expectedItems.length);
-            }
-        }
-    }
-
-    @SuppressWarnings("boxing")
-    @Test
-    public void testListAdapter() throws TemplateModelException {
-        {
-            List testList = new ArrayList<>();
-            testList.add(1);
-            testList.add(null);
-            testList.add("c");
-            testList.add(new String[] { "x" });
-
-            TemplateSequenceModel seq = (TemplateSequenceModel) OW.wrap(testList);
-            assertTrue(seq instanceof DefaultListAdapter);
-            assertFalse(seq instanceof TemplateCollectionModel); // Maybe changes at 2.4.0
-            assertEquals(4, seq.size());
-            assertNull(seq.get(-1));
-            assertEquals(1, ((TemplateNumberModel) seq.get(0)).getAsNumber());
-            assertNull(seq.get(1));
-            assertEquals("c", ((TemplateScalarModel) seq.get(2)).getAsString());
-            assertTrue(seq.get(3) instanceof DefaultArrayAdapter);
-            assertNull(seq.get(4));
-            
-            assertSizeThroughAPIModel(4, seq);
-        }
-
-        {
-            List testList = new LinkedList<>();
-            testList.add(1);
-            testList.add(null);
-            testList.add("c");
-
-            TemplateSequenceModel seq = (TemplateSequenceModel) OW.wrap(testList);
-            assertTrue(seq instanceof DefaultListAdapter);
-            assertTrue(seq instanceof TemplateCollectionModel); // Maybe changes at 2.4.0
-            assertEquals(3, seq.size());
-            assertNull(seq.get(-1));
-            assertEquals(1, ((TemplateNumberModel) seq.get(0)).getAsNumber());
-            assertNull(seq.get(1));
-            assertEquals("c", ((TemplateScalarModel) seq.get(2)).getAsString());
-            assertNull(seq.get(3));
-
-            assertCollectionTMEquals((TemplateCollectionModel) seq, 1, null, "c");
-
-            TemplateModelIterator it = ((TemplateCollectionModel) seq).iterator();
-            it.next();
-            it.next();
-            it.next();
-            try {
-                it.next();
-                fail();
-            } catch (TemplateModelException e) {
-                assertThat(e.getMessage(), containsString("no more"));
-            }
-        }
-    }
-
-    @Test
-    public void testArrayAdapterTypes() throws TemplateModelException {
-        assertArrayAdapterClass("Object", OW.wrap(new Object[] {}));
-        assertArrayAdapterClass("Object", OW.wrap(new String[] {}));
-        assertArrayAdapterClass("byte", OW.wrap(new byte[] {}));
-        assertArrayAdapterClass("short", OW.wrap(new short[] {}));
-        assertArrayAdapterClass("int", OW.wrap(new int[] {}));
-        assertArrayAdapterClass("long", OW.wrap(new long[] {}));
-        assertArrayAdapterClass("float", OW.wrap(new float[] {}));
-        assertArrayAdapterClass("double", OW.wrap(new double[] {}));
-        assertArrayAdapterClass("boolean", OW.wrap(new boolean[] {}));
-        assertArrayAdapterClass("char", OW.wrap(new char[] {}));
-    }
-
-    private void assertArrayAdapterClass(String adapterCompType, TemplateModel adaptedArray) {
-        assertTrue(adaptedArray instanceof DefaultArrayAdapter);
-        assertThat(adaptedArray.getClass().getName(),
-                containsString("$" + adapterCompType.substring(0, 1).toUpperCase() + adapterCompType.substring(1)));
-    }
-
-    @SuppressWarnings("boxing")
-    @Test
-    public void testArrayAdapters() throws TemplateModelException {
-        {
-            final String[] testArray = new String[] { "a", null, "c" };
-
-            TemplateSequenceModel seq = (TemplateSequenceModel) OW.wrap(testArray);
-            assertEquals(3, seq.size());
-            assertNull(seq.get(-1));
-            assertEquals("a", ((TemplateScalarModel) seq.get(0)).getAsString());
-            assertNull(seq.get(1));
-            assertEquals("c", ((TemplateScalarModel) seq.get(2)).getAsString());
-            assertNull(seq.get(3));
-        }
-
-        {
-            final int[] testArray = new int[] { 11, 22 };
-            TemplateSequenceModel seq = (TemplateSequenceModel) OW.wrap(testArray);
-            assertEquals(2, seq.size());
-            assertNull(seq.get(-1));
-            assertEqualsAndSameClass(Integer.valueOf(11), ((TemplateNumberModel) seq.get(0)).getAsNumber());
-            assertEqualsAndSameClass(Integer.valueOf(22), ((TemplateNumberModel) seq.get(1)).getAsNumber());
-            assertNull(seq.get(2));
-        }
-
-        {
-            final double[] testArray = new double[] { 11, 22 };
-            TemplateSequenceModel seq = (TemplateSequenceModel) OW.wrap(testArray);
-            assertEquals(2, seq.size());
-            assertNull(seq.get(-1));
-            assertEqualsAndSameClass(Double.valueOf(11), ((TemplateNumberModel) seq.get(0)).getAsNumber());
-            assertEqualsAndSameClass(Double.valueOf(22), ((TemplateNumberModel) seq.get(1)).getAsNumber());
-            assertNull(seq.get(2));
-        }
-
-        {
-            final boolean[] testArray = new boolean[] { true, false };
-            TemplateSequenceModel seq = (TemplateSequenceModel) OW.wrap(testArray);
-            assertEquals(2, seq.size());
-            assertNull(seq.get(-1));
-            assertEqualsAndSameClass(Boolean.valueOf(true), ((TemplateBooleanModel) seq.get(0)).getAsBoolean());
-            assertEqualsAndSameClass(Boolean.valueOf(false), ((TemplateBooleanModel) seq.get(1)).getAsBoolean());
-            assertNull(seq.get(2));
-        }
-
-        {
-            final char[] testArray = new char[] { 'a', 'b' };
-            TemplateSequenceModel seq = (TemplateSequenceModel) OW.wrap(testArray);
-            assertEquals(2, seq.size());
-            assertNull(seq.get(-1));
-            assertEquals("a", ((TemplateScalarModel) seq.get(0)).getAsString());
-            assertEquals("b", ((TemplateScalarModel) seq.get(1)).getAsString());
-            assertNull(seq.get(2));
-        }
-    }
-
-    private void assertEqualsAndSameClass(Object expected, Object actual) {
-        assertEquals(expected, actual);
-        if (expected != null) {
-            assertEquals(expected.getClass(), actual.getClass());
-        }
-    }
-
-    private void assertRoundtrip(DefaultObjectWrapper dow, Object obj, Class expectedTMClass,
-            Class expectedPojoClass,
-            String expectedPojoToString)
-            throws TemplateModelException {
-        final TemplateModel objTM = dow.wrap(obj);
-        assertThat(objTM.getClass(), typeCompatibleWith(expectedTMClass));
-
-        final TemplateHashModel testBeanTM = (TemplateHashModel) dow.wrap(new RoundtripTesterBean());
-
-        {
-            TemplateMethodModelEx getClassM = (TemplateMethodModelEx) testBeanTM.get("getClass");
-            Object r = getClassM.exec(Collections.singletonList(objTM));
-            final Class rClass = (Class) ((WrapperTemplateModel) r).getWrappedObject();
-            assertThat(rClass, typeCompatibleWith(expectedPojoClass));
-        }
-
-        if (expectedPojoToString != null) {
-            TemplateMethodModelEx getToStringM = (TemplateMethodModelEx) testBeanTM.get("toString");
-            Object r = getToStringM.exec(Collections.singletonList(objTM));
-            assertEquals(expectedPojoToString, ((TemplateScalarModel) r).getAsString());
-        }
-    }
-
-    @SuppressWarnings("boxing")
-    @Test
-    public void testCollectionAdapterBasics() throws TemplateModelException {
-        {
-            Set set = new TreeSet();
-            set.add("a");
-            set.add("b");
-            set.add("c");
-            TemplateCollectionModelEx coll = (TemplateCollectionModelEx) OW.wrap(set);
-            assertTrue(coll instanceof DefaultNonListCollectionAdapter);
-            assertEquals(3, coll.size());
-            assertFalse(coll.isEmpty());
-            assertCollectionTMEquals(coll, "a", "b", "c");
-
-            assertRoundtrip(OW, set, DefaultNonListCollectionAdapter.class, TreeSet.class, "[a, b, c]");
-            
-            assertSizeThroughAPIModel(3, coll);
-        }
-
-        {
-            Set set = new HashSet();
-            final List<String> list = Collections.singletonList("b");
-            set.add(list);
-            set.add(null);
-            TemplateCollectionModelEx coll = (TemplateCollectionModelEx) OW.wrap(set);
-            TemplateModelIterator it = coll.iterator();
-            final TemplateModel tm1 = it.next();
-            Object obj1 = OW.unwrap(tm1);
-            final TemplateModel tm2 = it.next();
-            Object obj2 = OW.unwrap(tm2);
-            assertTrue(obj1 == null || obj2 == null);
-            assertTrue(obj1 != null && obj1.equals(list) || obj2 != null && obj2.equals(list));
-            assertTrue(tm1 instanceof DefaultListAdapter || tm2 instanceof DefaultListAdapter);
-
-            assertRoundtrip(OW, set, DefaultNonListCollectionAdapter.class, HashSet.class, "[" + obj1 + ", "
-                    + obj2 + "]");
-        }
-    }
-
-    @SuppressWarnings("boxing")
-    @Test
-    public void testCollectionAdapterOutOfBounds() throws TemplateModelException {
-        Set set = Collections.singleton(123);
-
-        TemplateCollectionModelEx coll = (TemplateCollectionModelEx) OW.wrap(set);
-        TemplateModelIterator it = coll.iterator();
-
-        for (int i = 0; i < 3; i++) {
-            assertTrue(it.hasNext());
-        }
-
-        assertEquals(123, OW.unwrap(it.next()));
-
-        for (int i = 0; i < 3; i++) {
-            assertFalse(it.hasNext());
-            try {
-                it.next();
-                fail();
-            } catch (TemplateModelException e) {
-                assertThat(e.getMessage(), containsStringIgnoringCase("no more"));
-            }
-        }
-    }
-
-    @Test
-    public void testCollectionAdapterAndNulls() throws TemplateModelException {
-        Set set = new HashSet();
-        set.add(null);
-
-        TemplateCollectionModelEx coll = (TemplateCollectionModelEx) OW.wrap(set);
-        assertEquals(1, coll.size());
-        assertFalse(coll.isEmpty());
-        assertNull(coll.iterator().next());
-    }
-
-    @Test
-    public void testIteratorWrapping() throws TemplateModelException, ClassNotFoundException {
-        final List<String> list = ImmutableList.of("a", "b", "c");
-        Iterator<String> it = list.iterator();
-        TemplateCollectionModel coll = (TemplateCollectionModel) OW.wrap(it);
-
-        assertRoundtrip(OW, coll, DefaultIteratorAdapter.class, Iterator.class, null);
-
-        TemplateModelIterator itIt = coll.iterator();
-        TemplateModelIterator itIt2 = coll.iterator(); // used later
-        assertTrue(itIt.hasNext());
-        assertEquals("a", OW.unwrap(itIt.next()));
-        assertTrue(itIt.hasNext());
-        assertEquals("b", OW.unwrap(itIt.next()));
-        assertTrue(itIt.hasNext());
-        assertEquals("c", OW.unwrap(itIt.next()));
-        assertFalse(itIt.hasNext());
-        try {
-            itIt.next();
-            fail();
-        } catch (TemplateModelException e) {
-            assertThat(e.getMessage(), containsStringIgnoringCase("no more"));
-        }
-
-        try {
-            itIt2.hasNext();
-            fail();
-        } catch (TemplateModelException e) {
-            assertThat(e.getMessage(), containsString("can be listed only once"));
-        }
-
-        TemplateModelIterator itIt3 = coll.iterator();
-        try {
-            itIt3.hasNext();
-            fail();
-        } catch (TemplateModelException e) {
-            assertThat(e.getMessage(), containsString("can be listed only once"));
-        }
-    }
-
-    @Test
-    public void testIteratorApiSupport() throws TemplateModelException {
-        TemplateModel wrappedIterator = OW.wrap(Collections.emptyIterator());
-        assertThat(wrappedIterator, instanceOf(DefaultIteratorAdapter.class));
-        DefaultIteratorAdapter iteratorAdapter = (DefaultIteratorAdapter) wrappedIterator;
-
-        TemplateHashModel api = (TemplateHashModel) iteratorAdapter.getAPI();
-        assertFalse(((TemplateBooleanModel) ((TemplateMethodModelEx)
-                api.get("hasNext")).exec(Collections.emptyList())).getAsBoolean());
-    }
-
-    @SuppressWarnings("boxing")
-    @Test
-    public void testCharKeyFallback() throws TemplateModelException {
-        Map hashMapS = new HashMap<>();
-        hashMapS.put("a", 1);
-        Map sortedMapS = new TreeMap<>();
-        sortedMapS.put("a", 1);
-        Map hashMapC = new HashMap<>();
-        hashMapC.put('a', 1);
-        Map sortedMapC = new TreeMap<>();
-        sortedMapC.put('a', 1);
-        
-        assertEquals(1, OW.unwrap(((TemplateHashModel) OW.wrap(hashMapS)).get("a")));
-        assertEquals(1, OW.unwrap(((TemplateHashModel) OW.wrap(hashMapC)).get("a")));
-        assertEquals(1, OW.unwrap(((TemplateHashModel) OW.wrap(sortedMapS)).get("a")));
-        try {
-            ((TemplateHashModel) OW.wrap(sortedMapC)).get("a");
-        } catch (TemplateModelException e) {
-            assertThat(e.getMessage(), containsStringIgnoringCase("String key"));
-        }
-        
-        assertNull(((TemplateHashModel) OW.wrap(hashMapS)).get("b"));
-        assertNull(((TemplateHashModel) OW.wrap(hashMapC)).get("b"));
-        assertNull(((TemplateHashModel) OW.wrap(sortedMapS)).get("b"));
-        try {
-            ((TemplateHashModel) OW.wrap(sortedMapC)).get("b");
-        } catch (TemplateModelException e) {
-            assertThat(e.getMessage(), containsStringIgnoringCase("String key"));
-        }
-    }
-    
-    @Test
-    public void testIterableSupport() throws TemplateException, IOException {
-        Iterable<String> iterable = new PureIterable();
-        
-        String listingFTL = "<#list value as x>${x}<#sep>, </#list>";
-        
-        DefaultObjectWrapper ow = OW;
-        TemplateModel tm = ow.wrap(iterable);
-        assertThat(tm, instanceOf(TemplateCollectionModel.class));
-        TemplateCollectionModel iterableTM = (TemplateCollectionModel) tm;
-
-        for (int i = 0; i < 2; i++) {
-            TemplateModelIterator iteratorTM = iterableTM.iterator();
-            assertTrue(iteratorTM.hasNext());
-            assertEquals("a", ow.unwrap(iteratorTM.next()));
-            assertTrue(iteratorTM.hasNext());
-            assertEquals("b", ow.unwrap(iteratorTM.next()));
-            assertTrue(iteratorTM.hasNext());
-            assertEquals("c", ow.unwrap(iteratorTM.next()));
-            assertFalse(iteratorTM.hasNext());
-            try {
-                iteratorTM.next();
-                fail();
-            } catch (TemplateModelException e) {
-                assertThat(e.getMessage(), containsStringIgnoringCase("no more"));
-            }
-        }
-
-        assertTemplateOutput(OW, iterable, listingFTL, "a, b, c");
-    }
-
-    @Test
-    public void testEnumerationAdapter() throws TemplateModelException {
-        Vector<String> vector = new Vector<String>();
-        vector.add("a");
-        vector.add("b");
-
-        TemplateModel wrappedEnumeration = OW.wrap(vector.elements());
-        assertThat(wrappedEnumeration, instanceOf(DefaultEnumerationAdapter.class));
-        DefaultEnumerationAdapter enumAdapter = (DefaultEnumerationAdapter) wrappedEnumeration;
-        TemplateModelIterator iterator = enumAdapter.iterator();
-        assertTrue(iterator.hasNext());
-        assertEquals("a", ((TemplateScalarModel) iterator.next()).getAsString());
-        assertTrue(iterator.hasNext());
-        assertEquals("b", ((TemplateScalarModel) iterator.next()).getAsString());
-        assertFalse(iterator.hasNext());
-
-        iterator = enumAdapter.iterator();
-        try {
-            iterator.hasNext();
-        } catch (TemplateException e) {
-            assertThat(e.getMessage(), containsStringIgnoringCase("only once"));
-        }
-
-        TemplateHashModel api = (TemplateHashModel) enumAdapter.getAPI();
-        assertFalse(((TemplateBooleanModel) ((TemplateMethodModelEx)
-                api.get("hasMoreElements")).exec(Collections.emptyList())).getAsBoolean());
-    }
-
-    @Test
-    public void assertCanWrapDOM() throws SAXException, IOException, ParserConfigurationException,
-            TemplateModelException {
-        DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
-        InputSource is = new InputSource();
-        is.setCharacterStream(new StringReader("<doc><sub a='1' /></doc>"));
-        Document doc = db.parse(is);        
-        assertTrue(OW.wrap(doc) instanceof TemplateNodeModel);
-    }
-
-    @Test
-    public void testExposureLevel() throws Exception {
-        TestBean bean = new TestBean();
-
-        {
-            TemplateHashModel tm = wrapWithExposureLevel(bean, DefaultObjectWrapper.EXPOSE_SAFE);
-            assertNotNull(tm.get("hashCode"));
-            assertNotNull(tm.get("class"));
-        }
-
-        {
-            TemplateHashModel tm = wrapWithExposureLevel(bean, DefaultObjectWrapper.EXPOSE_PROPERTIES_ONLY);
-            assertNull(tm.get("hashCode"));
-            assertNotNull(tm.get("class"));
-        }
-
-        {
-            TemplateHashModel tm = wrapWithExposureLevel(bean, DefaultObjectWrapper.EXPOSE_NOTHING);
-            assertNull(tm.get("hashCode"));
-            assertNull(tm.get("class"));
-        }
-
-        {
-            TemplateHashModel tm = wrapWithExposureLevel(bean, DefaultObjectWrapper.EXPOSE_ALL);
-            assertNotNull(tm.get("hashCode"));
-            assertNotNull(tm.get("class"));
-        }
-    }
-
-    private TemplateHashModel wrapWithExposureLevel(Object bean, int exposureLevel) throws TemplateModelException {
-        return (TemplateHashModel) new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0)
-                .exposureLevel(exposureLevel).build()
-                .wrap(bean);
-    }
-
-    private void assertSizeThroughAPIModel(int expectedSize, TemplateModel normalModel) throws TemplateModelException {
-        if (!(normalModel instanceof TemplateModelWithAPISupport)) {
-            fail(); 
-        }
-        TemplateHashModel apiModel = (TemplateHashModel) ((TemplateModelWithAPISupport) normalModel).getAPI();
-        TemplateMethodModelEx sizeMethod = (TemplateMethodModelEx) apiModel.get("size");
-        TemplateNumberModel r = (TemplateNumberModel) sizeMethod.exec(Collections.emptyList());
-        assertEquals(expectedSize, r.getAsNumber().intValue());
-    }
-
-    private void assertTemplateOutput(ObjectWrapper objectWrapper, Object value, String ftl, String expectedOutput)
-            throws TemplateException, IOException {
-        assertEquals(expectedOutput, processTemplate(objectWrapper, value, ftl));
-    }
-
-    private void assertTemplateFails(ObjectWrapper objectWrapper, Object value, String ftl, String expectedMessagePart)
-            throws TemplateException, IOException {
-        try {
-            processTemplate(objectWrapper, value, ftl);
-            fail();
-        } catch (TemplateException e) {
-            assertThat(e.getMessage(), containsString(expectedMessagePart));
-        }
-    }
-    
-    private String processTemplate(ObjectWrapper objectWrapper, Object value, String ftl)
-            throws TemplateException, IOException {
-        Configuration cfg = new TestConfigurationBuilder()
-                .logTemplateExceptions(false)
-                .objectWrapper(objectWrapper)
-                .build();
-        StringWriter out = new StringWriter();
-        new Template(null, ftl, cfg).process(ImmutableMap.of("value", value), out);
-        return out.toString();
-    }
-
-    private static final class PureIterable implements Iterable<String> {
-        @Override
-        public Iterator<String> iterator() {
-            return ImmutableList.of("a", "b", "c").iterator();
-        }
-    }
-
-    public static class RoundtripTesterBean {
-
-        public Class getClass(Object o) {
-            return o.getClass();
-        }
-
-        public String toString(Object o) {
-            return o.toString();
-        }
-
-    }
-    
-    private static class Tupple<E1, E2> {
-        
-        private final E1 e1;
-        private final E2 e2;
-
-        public Tupple(E1 e1, E2 e2) {
-            if (e1 == null || e2 == null) throw new NullPointerException();
-            this.e1 = e1;
-            this.e2 = e2;
-        }
-
-        public E1 getE1() {
-            return e1;
-        }
-
-        public E2 getE2() {
-            return e2;
-        }
-
-        @Override
-        public int hashCode() {
-            final int prime = 31;
-            int result = 1;
-            result = prime * result + ((e1 == null) ? 0 : e1.hashCode());
-            result = prime * result + ((e2 == null) ? 0 : e2.hashCode());
-            return result;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (this == obj) return true;
-            if (obj == null) return false;
-            if (getClass() != obj.getClass()) return false;
-            Tupple other = (Tupple) obj;
-            if (e1 == null) {
-                if (other.e1 != null) return false;
-            } else if (!e1.equals(other.e1)) return false;
-            if (e2 == null) {
-                if (other.e2 != null) return false;
-            } else if (!e2.equals(other.e2)) return false;
-            return true;
-        }
-        
-    }
-    
-    @SuppressWarnings("boxing")
-    public static class TestBean {
-        
-        public int getX() {
-            return 1;
-        }
-        
-        public List<Integer> m() {
-            return Collections.singletonList(1);
-        }
-
-        public Tupple incTupple(Tupple<Integer, Integer> tupple) {
-            return new Tupple(tupple.e1 + 1, tupple.e2 + 1);
-        }
-        
-    }
-    
-    private static class CustomizedDefaultObjectWrapper extends DefaultObjectWrapper {
-
-        private CustomizedDefaultObjectWrapper(Version incompatibleImprovements) {
-            super(new DefaultObjectWrapper.Builder(incompatibleImprovements), true);
-        }
-        
-        @Override
-        protected TemplateModel handleNonBasicTypes(final Object obj) throws TemplateModelException {
-            if (obj instanceof Tupple) {
-                return new TuppleAdapter((Tupple<?, ?>) obj, this);
-            }
-            
-            return super.handleNonBasicTypes(obj);
-        }
-        
-    }
-    
-    private static class TuppleAdapter extends WrappingTemplateModel implements TemplateSequenceModel,
-            AdapterTemplateModel {
-        
-        private final Tupple<?, ?> tupple;
-        
-        public TuppleAdapter(Tupple<?, ?> tupple, ObjectWrapper ow) {
-            super(ow);
-            this.tupple = tupple;
-        }
-
-        @Override
-        public int size() throws TemplateModelException {
-            return 2;
-        }
-        
-        @Override
-        public TemplateModel get(int index) throws TemplateModelException {
-            switch (index) {
-            case 0: return wrap(tupple.getE1());
-            case 1: return wrap(tupple.getE2());
-            default: return null;
-            }
-        }
-
-        @Override
-        public Object getAdaptedObject(Class hint) {
-            return tupple;
-        }
-        
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/EnumModelsTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/EnumModelsTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/EnumModelsTest.java
deleted file mode 100644
index fc19bb7..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/EnumModelsTest.java
+++ /dev/null
@@ -1,85 +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.model.impl;
-
-import static org.junit.Assert.*;
-
-import java.util.ArrayList;
-
-import org.apache.freemarker.core.Configuration;
-import org.apache.freemarker.core.model.TemplateHashModel;
-import org.apache.freemarker.core.model.TemplateMethodModelEx;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateScalarModel;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class EnumModelsTest {
-    
-    @Test
-    public void modelCaching() throws Exception {
-        DefaultObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).usePrivateCaches(true)
-                .build();
-        TemplateHashModel enums = ow.getEnumModels();
-        TemplateHashModel e = (TemplateHashModel) enums.get(E.class.getName());
-        assertNotNull(e);
-        assertNotNull(e.get("A"));
-        assertNotNull(e.get("B"));
-        assertNull(e.get("C"));
-
-        try {
-            enums.get("no.such.ClassExists");
-            fail();
-        } catch (TemplateModelException ex) {
-            assertTrue(ex.getCause() instanceof ClassNotFoundException);
-        }
-        
-        TemplateModel a = e.get("A");
-        assertTrue(a instanceof TemplateScalarModel);
-        assertTrue(a instanceof TemplateHashModel);
-        assertEquals(((TemplateScalarModel) a).getAsString(), "ts:A");
-        TemplateMethodModelEx nameMethod = (TemplateMethodModelEx) ((TemplateHashModel) a).get("name");
-        assertEquals(((TemplateScalarModel) nameMethod.exec(new ArrayList())).getAsString(), "A");
-        
-        assertSame(e, enums.get(E.class.getName()));
-        
-        ow.clearClassIntrospecitonCache();
-        TemplateHashModel eAfterClean = (TemplateHashModel) enums.get(E.class.getName());
-        assertNotSame(e, eAfterClean);
-        assertSame(eAfterClean, enums.get(E.class.getName()));
-        assertNotNull(eAfterClean.get("A"));
-        assertNotNull(eAfterClean.get("B"));
-        assertNull(eAfterClean.get("C"));
-    }
-    
-    public enum E {
-        A, B;
-
-        @Override
-        public String toString() {
-            return "ts:" + super.toString();
-        }
-        
-    }
-
-}


[47/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/DateFormatTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/DateFormatTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/DateFormatTest.java
new file mode 100644
index 0000000..4ad5937
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/DateFormatTest.java
@@ -0,0 +1,464 @@
+/*
+ * 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.sql.Time;
+import java.sql.Timestamp;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import org.apache.freemarker.core.model.TemplateDateModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.impl.SimpleDate;
+import org.apache.freemarker.core.templateresolver.ConditionalTemplateConfigurationFactory;
+import org.apache.freemarker.core.templateresolver.FileNameGlobMatcher;
+import org.apache.freemarker.core.userpkg.AppMetaTemplateDateFormatFactory;
+import org.apache.freemarker.core.userpkg.EpochMillisDivTemplateDateFormatFactory;
+import org.apache.freemarker.core.userpkg.EpochMillisTemplateDateFormatFactory;
+import org.apache.freemarker.core.userpkg.HTMLISOTemplateDateFormatFactory;
+import org.apache.freemarker.core.userpkg.LocAndTZSensitiveTemplateDateFormatFactory;
+import org.apache.freemarker.core.valueformat.TemplateDateFormat;
+import org.apache.freemarker.core.valueformat.TemplateDateFormatFactory;
+import org.apache.freemarker.core.valueformat.UndefinedCustomFormatException;
+import org.apache.freemarker.core.valueformat.impl.AliasTemplateDateFormatFactory;
+import org.apache.freemarker.test.TemplateTest;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableMap;
+
+public class DateFormatTest extends TemplateTest {
+    
+    /** 2015-09-06T12:00:00Z */
+    private static long T = 1441540800000L;
+    private static TemplateDateModel TM = new SimpleDate(new Date(T), TemplateDateModel.DATETIME);
+    
+    private TestConfigurationBuilder createConfigurationBuilder() {
+        return new TestConfigurationBuilder()
+                .locale(Locale.US)
+                .timeZone(TimeZone.getTimeZone("GMT+01:00"))
+                .sqlDateAndTimeTimeZone(TimeZone.getTimeZone("UTC"))
+                .customDateFormats(ImmutableMap.of(
+                        "epoch", EpochMillisTemplateDateFormatFactory.INSTANCE,
+                        "loc", LocAndTZSensitiveTemplateDateFormatFactory.INSTANCE,
+                        "div", EpochMillisDivTemplateDateFormatFactory.INSTANCE,
+                        "appMeta", AppMetaTemplateDateFormatFactory.INSTANCE,
+                        "htmlIso", HTMLISOTemplateDateFormatFactory.INSTANCE));
+    }
+
+    @Override
+    protected Configuration createDefaultConfiguration() throws Exception {
+        return createConfigurationBuilder().build();
+    }
+
+    @Test
+    public void testCustomFormat() throws Exception {
+        addToDataModel("d", new Date(123456789));
+        assertOutput(
+                "${d?string.@epoch} ${d?string.@epoch} <#setting locale='de_DE'>${d?string.@epoch}",
+                "123456789 123456789 123456789");
+
+        setConfigurationWithDateTimeFormat("@epoch");
+        assertOutput(
+                "<#assign d = d?datetime>"
+                + "${d} ${d?string} <#setting locale='de_DE'>${d}",
+                "123456789 123456789 123456789");
+
+        setConfigurationWithDateTimeFormat("@htmlIso");
+        assertOutput(
+                "<#assign d = d?datetime>"
+                + "${d} ${d?string} <#setting locale='de_DE'>${d}",
+                "1970-01-02<span class='T'>T</span>10:17:36Z "
+                + "1970-01-02T10:17:36Z "
+                + "1970-01-02<span class='T'>T</span>10:17:36Z");
+    }
+
+    @Test
+    public void testLocaleChange() throws Exception {
+        addToDataModel("d", new Date(123456789));
+        assertOutput(
+                "${d?string.@loc} ${d?string.@loc} "
+                + "<#setting locale='de_DE'>"
+                + "${d?string.@loc} ${d?string.@loc} "
+                + "<#setting locale='en_US'>"
+                + "${d?string.@loc} ${d?string.@loc}",
+                "123456789@en_US:GMT+01:00 123456789@en_US:GMT+01:00 "
+                + "123456789@de_DE:GMT+01:00 123456789@de_DE:GMT+01:00 "
+                + "123456789@en_US:GMT+01:00 123456789@en_US:GMT+01:00");
+
+        setConfigurationWithDateTimeFormat("@loc");
+        assertOutput(
+                "<#assign d = d?datetime>"
+                + "${d} ${d?string} "
+                + "<#setting locale='de_DE'>"
+                + "${d} ${d?string} "
+                + "<#setting locale='en_US'>"
+                + "${d} ${d?string}",
+                "123456789@en_US:GMT+01:00 123456789@en_US:GMT+01:00 "
+                + "123456789@de_DE:GMT+01:00 123456789@de_DE:GMT+01:00 "
+                + "123456789@en_US:GMT+01:00 123456789@en_US:GMT+01:00");
+    }
+
+    @Test
+    public void testTimeZoneChange() throws Exception {
+        addToDataModel("d", new Date(123456789));
+        setConfigurationWithDateTimeFormat("iso");
+        assertOutput(
+                "${d?string.@loc} ${d?string.@loc} ${d?datetime?isoLocal} "
+                + "<#setting timeZone='GMT+02:00'>"
+                + "${d?string.@loc} ${d?string.@loc} ${d?datetime?isoLocal} "
+                + "<#setting timeZone='GMT+01:00'>"
+                + "${d?string.@loc} ${d?string.@loc} ${d?datetime?isoLocal}",
+                "123456789@en_US:GMT+01:00 123456789@en_US:GMT+01:00 1970-01-02T11:17:36+01:00 "
+                + "123456789@en_US:GMT+02:00 123456789@en_US:GMT+02:00 1970-01-02T12:17:36+02:00 "
+                + "123456789@en_US:GMT+01:00 123456789@en_US:GMT+01:00 1970-01-02T11:17:36+01:00");
+
+        setConfigurationWithDateTimeFormat("@loc");
+        assertOutput(
+                "<#assign d = d?datetime>"
+                + "${d} ${d?string} "
+                + "<#setting timeZone='GMT+02:00'>"
+                + "${d} ${d?string} "
+                + "<#setting timeZone='GMT+01:00'>"
+                + "${d} ${d?string}",
+                "123456789@en_US:GMT+01:00 123456789@en_US:GMT+01:00 "
+                + "123456789@en_US:GMT+02:00 123456789@en_US:GMT+02:00 "
+                + "123456789@en_US:GMT+01:00 123456789@en_US:GMT+01:00");
+    }
+    
+    @Test
+    public void testWrongFormatStrings() throws Exception {
+        setConfigurationWithDateTimeFormat("x1");
+        assertErrorContains("${.now}", "\"x1\"", "'x'");
+        assertErrorContains("${.now?string}", "\"x1\"", "'x'");
+        setConfigurationWithDateTimeFormat("short");
+        assertErrorContains("${.now?string('x2')}", "\"x2\"", "'x'");
+        assertErrorContains("${.now?string('[wrong]')}", "format string", "[wrong]");
+
+        setConfiguration(createConfigurationBuilder()
+                .dateFormat("[wrong d]")
+                .dateTimeFormat("[wrong dt]")
+                .timeFormat("[wrong t]")
+                .build());
+        assertErrorContains("${.now?date}", "\"date_format\"", "[wrong d]");
+        assertErrorContains("${.now?datetime}", "\"datetime_format\"", "[wrong dt]");
+        assertErrorContains("${.now?time}", "\"time_format\"", "[wrong t]");
+    }
+
+    @Test
+    public void testCustomParameterized() throws Exception {
+        Configuration cfg = getConfiguration();
+        addToDataModel("d", new SimpleDate(new Date(12345678L), TemplateDateModel.DATETIME));
+        setConfigurationWithDateTimeFormat("@div 1000");
+        assertOutput("${d}", "12345");
+        assertOutput("${d?string}", "12345");
+        assertOutput("${d?string.@div_100}", "123456");
+        
+        assertErrorContains("${d?string.@div_xyz}", "\"@div_xyz\"", "\"xyz\"");
+        setConfigurationWithDateTimeFormat("@div");
+        assertErrorContains("${d}", "\"datetime_format\"", "\"@div\"", "format parameter is required");
+    }
+    
+    @Test
+    public void testUnknownCustomFormat() throws Exception {
+        {
+            setConfigurationWithDateTimeFormat("@noSuchFormat");
+            Throwable exc = assertErrorContains(
+                    "${.now}",
+                    "\"@noSuchFormat\"", "\"noSuchFormat\"", "\"datetime_format\"");
+            assertThat(exc.getCause(), instanceOf(UndefinedCustomFormatException.class));
+            
+        }
+        {
+            setConfiguration(createConfigurationBuilder().dateFormat("@noSuchFormatD").build());
+            assertErrorContains(
+                    "${.now?date}",
+                    "\"@noSuchFormatD\"", "\"noSuchFormatD\"", "\"date_format\"");
+        }
+        {
+            setConfiguration(createConfigurationBuilder().timeFormat("@noSuchFormatT").build());
+            assertErrorContains(
+                    "${.now?time}",
+                    "\"@noSuchFormatT\"", "\"noSuchFormatT\"", "\"time_format\"");
+        }
+
+        {
+            setConfigurationWithDateTimeFormat("");
+            Throwable exc = assertErrorContains("${.now?string('@noSuchFormat2')}",
+                    "\"@noSuchFormat2\"", "\"noSuchFormat2\"");
+            assertThat(exc.getCause(), instanceOf(UndefinedCustomFormatException.class));
+        }
+    }
+
+    private void setConfigurationWithDateTimeFormat(String formatString) {
+        setConfiguration(createConfigurationBuilder().dateTimeFormat(formatString).build());
+    }
+
+    @Test
+    public void testNullInModel() throws Exception {
+        addToDataModel("d", new MutableTemplateDateModel());
+        assertErrorContains("${d}", "nothing inside it");
+        assertErrorContains("${d?string}", "nothing inside it");
+    }
+    
+    @Test
+    public void testIcIAndEscaping() throws Exception {
+        addToDataModel("d", new SimpleDate(new Date(12345678L), TemplateDateModel.DATETIME));
+        
+        setConfigurationWithDateTimeFormat("@epoch");
+        assertOutput("${d}", "12345678");
+        setConfigurationWithDateTimeFormat("'@'yyyy");
+        assertOutput("${d}", "@1970");
+        setConfigurationWithDateTimeFormat("@@yyyy");
+        assertOutput("${d}", "@@1970");
+
+        setConfiguration(createConfigurationBuilder()
+                .customDateFormats(Collections.<String, TemplateDateFormatFactory>emptyMap())
+                .dateTimeFormat("@epoch")
+                .build());
+        assertErrorContains("${d}", "custom", "\"epoch\"");
+    }
+
+    @Test
+    public void testEnvironmentGetters() throws Exception {
+        String dateFormatStr = "yyyy.MM.dd. (Z)";
+        String timeFormatStr = "HH:mm";
+        String dateTimeFormatStr = "yyyy.MM.dd. HH:mm";
+
+        setConfiguration(createConfigurationBuilder()
+                .dateFormat(dateFormatStr)
+                .timeFormat(timeFormatStr)
+                .dateTimeFormat(dateTimeFormatStr)
+                .build());
+
+        Configuration cfg = getConfiguration();
+
+        Template t = new Template(null, "", cfg);
+        Environment env = t.createProcessingEnvironment(null, null);
+        
+        // Test that values are coming from the cache if possible
+        for (Class dateClass : new Class[] { Date.class, Timestamp.class, java.sql.Date.class, Time.class } ) {
+            for (int dateType
+                    : new int[] { TemplateDateModel.DATE, TemplateDateModel.TIME, TemplateDateModel.DATETIME }) {
+                String formatString =
+                        dateType == TemplateDateModel.DATE ? cfg.getDateFormat() :
+                        (dateType == TemplateDateModel.TIME ? cfg.getTimeFormat()
+                        : cfg.getDateTimeFormat());
+                TemplateDateFormat expectedF = env.getTemplateDateFormat(formatString, dateType, dateClass);
+                assertSame(expectedF, env.getTemplateDateFormat(dateType, dateClass)); // Note: Only reads the cache
+                assertSame(expectedF, env.getTemplateDateFormat(formatString, dateType, dateClass));
+                assertSame(expectedF, env.getTemplateDateFormat(formatString, dateType, dateClass, cfg.getLocale()));
+                assertSame(expectedF, env.getTemplateDateFormat(formatString, dateType, dateClass, cfg.getLocale(),
+                        cfg.getTimeZone(), cfg.getSQLDateAndTimeTimeZone()));
+            }
+        }
+
+        String dateFormatStr2 = dateFormatStr + "'!'";
+        String timeFormatStr2 = timeFormatStr + "'!'";
+        String dateTimeFormatStr2 = dateTimeFormatStr + "'!'";
+        
+        assertEquals("2015.09.06. 13:00",
+                env.getTemplateDateFormat(TemplateDateModel.DATETIME, Date.class).formatToPlainText(TM));
+        assertEquals("2015.09.06. 13:00!",
+                env.getTemplateDateFormat(dateTimeFormatStr2, TemplateDateModel.DATETIME, Date.class).formatToPlainText(TM));
+        
+        assertEquals("2015.09.06. (+0100)",
+                env.getTemplateDateFormat(TemplateDateModel.DATE, Date.class).formatToPlainText(TM));
+        assertEquals("2015.09.06. (+0100)!",
+                env.getTemplateDateFormat(dateFormatStr2, TemplateDateModel.DATE, Date.class).formatToPlainText(TM));
+        
+        assertEquals("13:00",
+                env.getTemplateDateFormat(TemplateDateModel.TIME, Date.class).formatToPlainText(TM));
+        assertEquals("13:00!",
+                env.getTemplateDateFormat(timeFormatStr2, TemplateDateModel.TIME, Date.class).formatToPlainText(TM));
+        
+        assertEquals("2015.09.06. 13:00",
+                env.getTemplateDateFormat(TemplateDateModel.DATETIME, Timestamp.class).formatToPlainText(TM));
+        assertEquals("2015.09.06. 13:00!",
+                env.getTemplateDateFormat(dateTimeFormatStr2, TemplateDateModel.DATETIME, Timestamp.class).formatToPlainText(TM));
+
+        assertEquals("2015.09.06. (+0000)",
+                env.getTemplateDateFormat(TemplateDateModel.DATE, java.sql.Date.class).formatToPlainText(TM));
+        assertEquals("2015.09.06. (+0000)!",
+                env.getTemplateDateFormat(dateFormatStr2, TemplateDateModel.DATE, java.sql.Date.class).formatToPlainText(TM));
+
+        assertEquals("12:00",
+                env.getTemplateDateFormat(TemplateDateModel.TIME, Time.class).formatToPlainText(TM));
+        assertEquals("12:00!",
+                env.getTemplateDateFormat(timeFormatStr2, TemplateDateModel.TIME, Time.class).formatToPlainText(TM));
+
+        {
+            String dateTimeFormatStrLoc = dateTimeFormatStr + " EEEE";
+            // Gets into cache:
+            TemplateDateFormat format1
+                    = env.getTemplateDateFormat(dateTimeFormatStrLoc, TemplateDateModel.DATETIME, Date.class);
+            assertEquals("2015.09.06. 13:00 Sunday", format1.formatToPlainText(TM));
+            // Different locale (not cached):
+            assertEquals("2015.09.06. 13:00 Sonntag",
+                    env.getTemplateDateFormat(dateTimeFormatStrLoc, TemplateDateModel.DATETIME, Date.class,
+                            Locale.GERMANY).formatToPlainText(TM));
+            // Different locale and zone (not cached):
+            assertEquals("2015.09.06. 14:00 Sonntag",
+                    env.getTemplateDateFormat(dateTimeFormatStrLoc, TemplateDateModel.DATETIME, Date.class,
+                            Locale.GERMANY, TimeZone.getTimeZone("GMT+02"), TimeZone.getTimeZone("GMT+03")).formatToPlainText(TM));
+            // Different locale and zone (not cached):
+            assertEquals("2015.09.06. 15:00 Sonntag",
+                    env.getTemplateDateFormat(dateTimeFormatStrLoc, TemplateDateModel.DATETIME, java.sql.Date.class,
+                            Locale.GERMANY, TimeZone.getTimeZone("GMT+02"), TimeZone.getTimeZone("GMT+03")).formatToPlainText(TM));
+            // Check for corrupted cache:
+            TemplateDateFormat format2
+                    = env.getTemplateDateFormat(dateTimeFormatStrLoc, TemplateDateModel.DATETIME, Date.class);
+            assertEquals("2015.09.06. 13:00 Sunday", format2.formatToPlainText(TM));
+            assertSame(format1, format2);
+        }
+    }
+
+    @Test
+    public void testAliases() throws Exception {
+        setConfiguration(createConfigurationBuilder()
+                .customDateFormats(ImmutableMap.of(
+                        "d", new AliasTemplateDateFormatFactory("yyyy-MMM-dd"),
+                        "m", new AliasTemplateDateFormatFactory("yyyy-MMM"),
+                        "epoch", EpochMillisTemplateDateFormatFactory.INSTANCE))
+                .templateConfigurations(
+                        new ConditionalTemplateConfigurationFactory(
+                                new FileNameGlobMatcher("*2*"),
+                                new TemplateConfiguration.Builder()
+                                        .customDateFormats(ImmutableMap.<String, TemplateDateFormatFactory>of(
+                                                "m", new AliasTemplateDateFormatFactory("yyyy-MMMM"),
+                                                "i", new AliasTemplateDateFormatFactory("@epoch")))
+                                        .build()))
+                .build());
+
+        addToDataModel("d", TM);
+        String commonFtl = "${d?string.@d} ${d?string.@m} "
+                + "<#setting locale='fr_FR'>${d?string.@m} "
+                + "<#attempt>${d?string.@i}<#recover>E</#attempt>";
+        addTemplate("t1.ftl", commonFtl);
+        addTemplate("t2.ftl", commonFtl);
+        
+        // 2015-09-06T12:00:00Z
+        assertOutputForNamed("t1.ftl", "2015-Sep-06 2015-Sep 2015-sept. E");
+        assertOutputForNamed("t2.ftl", "2015-Sep-06 2015-September 2015-septembre " + T);
+    }
+    
+    @Test
+    public void testAliases2() throws Exception {
+        setConfiguration(
+                createConfigurationBuilder()
+                .customDateFormats(ImmutableMap.<String, TemplateDateFormatFactory>of(
+                        "d", new AliasTemplateDateFormatFactory("yyyy-MMM",
+                                ImmutableMap.of(
+                                        new Locale("en"), "yyyy-MMM'_en'",
+                                        Locale.UK, "yyyy-MMM'_en_GB'",
+                                        Locale.FRANCE, "yyyy-MMM'_fr_FR'"))))
+                .dateTimeFormat("@d")
+                .build());
+        addToDataModel("d", TM);
+        assertOutput(
+                "<#setting locale='en_US'>${d} "
+                + "<#setting locale='en_GB'>${d} "
+                + "<#setting locale='en_GB_Win'>${d} "
+                + "<#setting locale='fr_FR'>${d} "
+                + "<#setting locale='hu_HU'>${d}",
+                "2015-Sep_en 2015-Sep_en_GB 2015-Sep_en_GB 2015-sept._fr_FR 2015-szept.");
+    }
+    
+    /**
+     * ?date() and such are new in 2.3.24.
+     */
+    @Test
+    public void testZeroArgDateBI() throws IOException, TemplateException {
+        setConfiguration(
+                createConfigurationBuilder()
+                .dateFormat("@epoch")
+                .dateTimeFormat("@epoch")
+                .timeFormat("@epoch")
+                .build());
+
+        addToDataModel("t", String.valueOf(T));
+        
+        assertOutput(
+                "${t?date?string.xs_u} ${t?date()?string.xs_u}",
+                "2015-09-06Z 2015-09-06Z");
+        assertOutput(
+                "${t?time?string.xs_u} ${t?time()?string.xs_u}",
+                "12:00:00Z 12:00:00Z");
+        assertOutput(
+                "${t?datetime?string.xs_u} ${t?datetime()?string.xs_u}",
+                "2015-09-06T12:00:00Z 2015-09-06T12:00:00Z");
+    }
+
+    @Test
+    public void testAppMetaRoundtrip() throws IOException, TemplateException {
+        setConfiguration(
+                createConfigurationBuilder()
+                .dateFormat("@appMeta")
+                .dateTimeFormat("@appMeta")
+                .timeFormat("@appMeta")
+                .build());
+
+        addToDataModel("t", String.valueOf(T) + "/foo");
+        
+        assertOutput(
+                "${t?date} ${t?date()}",
+                T + " " + T + "/foo");
+        assertOutput(
+                "${t?time} ${t?time()}",
+                T + " " + T + "/foo");
+        assertOutput(
+                "${t?datetime} ${t?datetime()}",
+                T + " " + T + "/foo");
+    }
+    
+    @Test
+    public void testUnknownDateType() throws IOException, TemplateException {
+        addToDataModel("u", new Date(T));
+        assertErrorContains("${u?string}", "isn't known");
+        assertOutput("${u?string('yyyy')}", "2015");
+        assertOutput("<#assign s = u?string>${s('yyyy')}", "2015");
+    }
+    
+    private static class MutableTemplateDateModel implements TemplateDateModel {
+        
+        private Date date;
+
+        public void setDate(Date date) {
+            this.date = date;
+        }
+
+        @Override
+        public Date getAsDate() throws TemplateModelException {
+            return date;
+        }
+
+        @Override
+        public int getDateType() {
+            return DATETIME;
+        }
+        
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/DirectiveCallPlaceTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/DirectiveCallPlaceTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/DirectiveCallPlaceTest.java
new file mode 100644
index 0000000..29220c4
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/DirectiveCallPlaceTest.java
@@ -0,0 +1,249 @@
+/*
+ * 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.StringWriter;
+import java.io.Writer;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.freemarker.core.model.TemplateDirectiveBody;
+import org.apache.freemarker.core.model.TemplateDirectiveModel;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateScalarModel;
+import org.apache.freemarker.core.util.ObjectFactory;
+import org.apache.freemarker.test.TemplateTest;
+import org.junit.Test;
+
+public class DirectiveCallPlaceTest extends TemplateTest {
+
+    @Test
+    public void testCustomDataBasics() throws IOException, TemplateException {
+        addTemplate(
+                "customDataBasics.ftl",
+                "<@u...@uc> <@u...@uc> <@uc>Ab<#-- -->c</...@uc> <@l...@lc> <@l...@lc>");
+        
+        CachingTextConverterDirective.resetCacheRecreationCount();
+        for (int i = 0; i < 3; i++) {
+            assertOutputForNamed(
+                    "customDataBasics.ftl",
+                    "ABC[cached 1] X=123 ABC[cached 2]  abc[cached 3]");
+        }
+    }
+
+    @Test
+    public void testCustomDataProviderMismatch() throws IOException, TemplateException {
+        addTemplate(
+                "customDataProviderMismatch.ftl",
+                "<#list [uc, lc, uc] as d><#list 1..2 as _><@d...@d></#list></#list>");
+        
+        CachingTextConverterDirective.resetCacheRecreationCount();
+        assertOutputForNamed(
+                "customDataProviderMismatch.ftl",
+                "ABC[cached 1]ABC[cached 1]abc[cached 2]abc[cached 2]ABC[cached 3]ABC[cached 3]");
+        assertOutputForNamed(
+                "customDataProviderMismatch.ftl",
+                "ABC[cached 3]ABC[cached 3]abc[cached 4]abc[cached 4]ABC[cached 5]ABC[cached 5]");
+    }
+    
+    @Test
+    public void testPositions() throws IOException, TemplateException {
+        addTemplate(
+                "positions.ftl",
+                "<@pa />\n"
+                + "..<@pa\n"
+                + "/><@pa>xxx</@>\n"
+                + "<@pa>{<@pa/> <@pa/>}</@>\n"
+                + "${curDirLine}<@argP p=curDirLine?string>${curDirLine}</...@argP>${curDirLine}\n"
+                + "<#macro m p>(p=${p}){<#nested>}</#macro>\n"
+                + "${curDirLine}<@m p=curDirLine?string>${curDirLine}</...@m>${curDirLine}");
+        
+        assertOutputForNamed(
+                "positions.ftl",
+                "[positions.ftl:1:1-1:7]"
+                + "..[positions.ftl:2:3-3:2]"
+                + "[positions.ftl:3:3-3:14]xxx\n"
+                + "[positions.ftl:4:1-4:24]{[positions.ftl:4:7-4:12] [positions.ftl:4:14-4:19]}\n"
+                + "-(p=5){-}-\n"
+                + "-(p=7){-}-"
+                );
+    }
+    
+    @SuppressWarnings("boxing")
+    @Override
+    protected Object createDataModel() {
+        Map<String, Object> dm = new HashMap<>();
+        dm.put("uc", new CachingUpperCaseDirective());
+        dm.put("lc", new CachingLowerCaseDirective());
+        dm.put("pa", new PositionAwareDirective());
+        dm.put("argP", new ArgPrinterDirective());
+        dm.put("curDirLine", new CurDirLineScalar());
+        dm.put("x", 123);
+        return dm;
+    }
+
+    private abstract static class CachingTextConverterDirective implements TemplateDirectiveModel {
+
+        /** Only needed for testing. */
+        private static AtomicInteger cacheRecreationCount = new AtomicInteger();
+        
+        /** Only needed for testing. */
+        static void resetCacheRecreationCount() {
+            cacheRecreationCount.set(0);
+        }
+        
+        @Override
+        public void execute(Environment env, Map params, TemplateModel[] loopVars, final TemplateDirectiveBody body)
+                throws TemplateException, IOException {
+            if (body == null) {
+                return;
+            }
+            
+            final String convertedText;
+
+            final DirectiveCallPlace callPlace = env.getCurrentDirectiveCallPlace();
+            if (callPlace.isNestedOutputCacheable()) {
+                try {
+                    convertedText = (String) callPlace.getOrCreateCustomData(
+                            getTextConversionIdentity(), new ObjectFactory<String>() {
+
+                                @Override
+                                public String createObject() throws TemplateException, IOException {
+                                    return convertBodyText(body)
+                                            + "[cached " + cacheRecreationCount.incrementAndGet() + "]";
+                                }
+
+                            });
+                } catch (CallPlaceCustomDataInitializationException e) {
+                    throw new TemplateModelException("Failed to pre-render nested content", e);
+                }
+            } else {
+                convertedText = convertBodyText(body);
+            }
+
+            env.getOut().write(convertedText);
+        }
+
+        protected abstract Class getTextConversionIdentity();
+
+        private String convertBodyText(TemplateDirectiveBody body) throws TemplateException,
+                IOException {
+            StringWriter sw = new StringWriter();
+            body.render(sw);
+            return convertText(sw.toString());
+        }
+        
+        protected abstract String convertText(String s);
+
+    }
+    
+    private static class CachingUpperCaseDirective extends CachingTextConverterDirective {
+
+        @Override
+        protected String convertText(String s) {
+            return s.toUpperCase();
+        }
+        
+        @Override
+        protected Class getTextConversionIdentity() {
+            return CachingUpperCaseDirective.class;
+        }
+        
+    }
+
+    private static class CachingLowerCaseDirective extends CachingTextConverterDirective {
+
+        @Override
+        protected String convertText(String s) {
+            return s.toLowerCase();
+        }
+
+        @Override
+        protected Class getTextConversionIdentity() {
+            return CachingLowerCaseDirective.class;
+        }
+        
+    }
+    
+    private static class PositionAwareDirective implements TemplateDirectiveModel {
+
+        @Override
+        public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
+                throws TemplateException, IOException {
+            Writer out = env.getOut();
+            DirectiveCallPlace callPlace = env.getCurrentDirectiveCallPlace();
+            out.write("[");
+            out.write(getTemplateSourceName(callPlace));
+            out.write(":");
+            out.write(Integer.toString(callPlace.getBeginLine()));
+            out.write(":");
+            out.write(Integer.toString(callPlace.getBeginColumn()));
+            out.write("-");
+            out.write(Integer.toString(callPlace.getEndLine()));
+            out.write(":");
+            out.write(Integer.toString(callPlace.getEndColumn()));
+            out.write("]");
+            if (body != null) {
+                body.render(out);
+            }
+        }
+
+        private String getTemplateSourceName(DirectiveCallPlace callPlace) {
+            return ((ASTDirUserDefined) callPlace).getTemplate().getSourceName();
+        }
+        
+    }
+
+    private static class ArgPrinterDirective implements TemplateDirectiveModel {
+
+        @Override
+        public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
+                throws TemplateException, IOException {
+            final Writer out = env.getOut();
+            if (params.size() > 0) {
+                out.write("(p=");
+                out.write(((TemplateScalarModel) params.get("p")).getAsString());
+                out.write(")");
+            }
+            if (body != null) {
+                out.write("{");
+                body.render(out);
+                out.write("}");
+            }
+        }
+        
+    }
+    
+    private static class CurDirLineScalar implements TemplateScalarModel {
+
+        @Override
+        public String getAsString() throws TemplateModelException {
+            DirectiveCallPlace callPlace = Environment.getCurrentEnvironment().getCurrentDirectiveCallPlace();
+            return callPlace != null
+                    ? String.valueOf(Environment.getCurrentEnvironment().getCurrentDirectiveCallPlace().getBeginLine())
+                    : "-";
+        }
+        
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/EncodingOverrideTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/EncodingOverrideTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/EncodingOverrideTest.java
new file mode 100644
index 0000000..b1acead
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/EncodingOverrideTest.java
@@ -0,0 +1,62 @@
+/*
+ * 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.StringWriter;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+
+import org.apache.freemarker.core.templateresolver.impl.ClassTemplateLoader;
+import org.junit.Test;
+
+public class EncodingOverrideTest {
+
+    @Test
+    public void testMarchingCharset() throws Exception {
+        Template t = createConfig(StandardCharsets.UTF_8).getTemplate("encodingOverride-UTF-8.ftl");
+        assertEquals(StandardCharsets.UTF_8, t.getActualSourceEncoding());
+        checkTemplateOutput(t);
+    }
+
+    @Test
+    public void testDifferentCharset() throws Exception {
+        Template t = createConfig(StandardCharsets.UTF_8).getTemplate("encodingOverride-ISO-8859-1.ftl");
+        assertEquals(StandardCharsets.ISO_8859_1, t.getActualSourceEncoding());
+        checkTemplateOutput(t);
+    }
+
+    private void checkTemplateOutput(Template t) throws TemplateException, IOException {
+        StringWriter out = new StringWriter(); 
+        t.process(Collections.emptyMap(), out);
+        assertEquals("Béka", out.toString());
+    }
+    
+    private Configuration createConfig(Charset charset) {
+       return new Configuration.Builder(Configuration.VERSION_3_0_0)
+               .templateLoader(new ClassTemplateLoader(EncodingOverrideTest.class, ""))
+               .sourceEncoding(charset)
+               .build();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/EnvironmentGetTemplateVariantsTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/EnvironmentGetTemplateVariantsTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/EnvironmentGetTemplateVariantsTest.java
new file mode 100644
index 0000000..b79559c
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/EnvironmentGetTemplateVariantsTest.java
@@ -0,0 +1,214 @@
+/*
+ * 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.Writer;
+import java.util.Collections;
+import java.util.Map;
+
+import org.apache.freemarker.core.model.TemplateDirectiveBody;
+import org.apache.freemarker.core.model.TemplateDirectiveModel;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.impl.SimpleScalar;
+import org.apache.freemarker.core.templateresolver.impl.StringTemplateLoader;
+import org.apache.freemarker.test.TemplateTest;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+import org.junit.Test;
+
+public class EnvironmentGetTemplateVariantsTest extends TemplateTest {
+
+    private static final StringTemplateLoader TEMPLATES = new StringTemplateLoader();
+    static {
+        TEMPLATES.putTemplate("main",
+                "<@tNames />\n"
+                + "---1---\n"
+                + "[imp: <#import 'imp' as i>${i.impIni}]\n"
+                + "---2---\n"
+                + "<@i.impM>"
+                    + "<@tNames />"
+                + "</@>\n"
+                + "---3---\n"
+                + "[inc: <#include 'inc'>]\n"
+                + "---4---\n"
+                + "<@incM>"
+                    + "<@tNames />"
+                + "</@>\n"
+                + "---5---\n"
+                + "[inc2: <#include 'inc2'>]\n"
+                + "---6---\n"
+                + "<#import 'imp2' as i2>"
+                + "<@i.impM2><@tNames /></@>\n"
+                + "---7---\n"
+                + "<#macro mainM>"
+                    + "[mainM: <@tNames /> {<#nested>} <@tNames />]"
+                + "</#macro>"
+                + "[inc3: <#include 'inc3'>]\n"
+                + "<@mainM><@tNames /> <#include 'inc4'> <@tNames /></@>\n"
+                + "<@tNames />\n"
+                + "---8---\n"
+                + "<#function mainF>"
+                    + "<@tNames />"
+                    + "<#return lastTNamesResult>"
+                + "</#function>"
+                + "mainF: ${mainF()}, impF: ${i.impF()}, incF: ${incF()}\n"
+                );
+        TEMPLATES.putTemplate("inc",
+                "<@tNames />\n"
+                + "<#macro incM>"
+                    + "[incM: <@tNames /> {<#nested>}]"
+                + "</#macro>"
+                + "<#function incF>"
+                    + "<@tNames />"
+                    + "<#return lastTNamesResult>"
+                + "</#function>"
+                + "<@incM><@tNames /></@>\n"
+                + "<#if !included!false>[incInc: <#assign included=true><#include 'inc'>]\n</#if>"
+                );
+        TEMPLATES.putTemplate("imp",
+                "<#assign impIni><@tNames /></#assign>\n"
+                + "<#macro impM>"
+                    + "[impM: <@tNames />\n"
+                        + "{<#nested>}\n"
+                        + "[inc: <#include 'inc'>]\n"
+                        + "<@incM><@tNames /></@>\n"
+                    + "]"
+                + "</#macro>"
+                + "<#macro impM2>"
+                    + "[impM2: <@tNames />\n"
+                    + "{<#nested>}\n"
+                    + "<@i2.imp2M><@tNames /></@>\n"
+                    + "]"
+                + "</#macro>"
+                + "<#function impF>"
+                    + "<@tNames />"
+                    + "<#return lastTNamesResult>"
+                + "</#function>"
+                );
+        TEMPLATES.putTemplate("inc2",
+                "<@tNames />\n"
+                + "<@i.impM><@tNames /></@>\n"
+                );
+        TEMPLATES.putTemplate("imp2",
+                "<#macro imp2M>"
+                    + "[imp2M: <@tNames /> {<#nested>}]"
+                + "</#macro>");
+        TEMPLATES.putTemplate("inc3",
+                "<@tNames />\n"
+                + "<@mainM><@tNames /></@>\n"
+                );
+        TEMPLATES.putTemplate("inc4",
+                "<@tNames />"
+                );
+    }
+    
+    @Test
+    public void test() throws IOException, TemplateException {
+        setConfiguration(createConfiguration(Configuration.VERSION_3_0_0));
+        assertOutputForNamed(
+                "main",
+                "<ct=main mt=main>\n"
+                + "---1---\n"
+                + "[imp: <ct=imp mt=main>]\n"
+                + "---2---\n"
+                + "[impM: <ct=imp mt=main>\n"
+                    + "{<ct=main mt=main>}\n"
+                    + "[inc: <ct=inc mt=main>\n"
+                        + "[incM: <ct=inc mt=main> {<ct=inc mt=main>}]\n"
+                        + "[incInc: <ct=inc mt=main>\n"
+                            + "[incM: <ct=inc mt=main> {<ct=inc mt=main>}]\n"
+                        + "]\n"
+                    + "]\n"
+                    + "[incM: <ct=inc mt=main> {<ct=imp mt=main>}]\n"
+                + "]\n"
+                + "---3---\n"
+                + "[inc: <ct=inc mt=main>\n"
+                    + "[incM: <ct=inc mt=main> {<ct=inc mt=main>}]\n"
+                    + "[incInc: <ct=inc mt=main>\n"
+                        + "[incM: <ct=inc mt=main> {<ct=inc mt=main>}]\n"
+                    + "]\n"
+                + "]\n"
+                + "---4---\n"
+                + "[incM: <ct=inc mt=main> {<ct=main mt=main>}]\n"
+                + "---5---\n"
+                + "[inc2: <ct=inc2 mt=main>\n"
+                    + "[impM: <ct=imp mt=main>\n"
+                        + "{<ct=inc2 mt=main>}\n"
+                        + "[inc: <ct=inc mt=main>\n"
+                            + "[incM: <ct=inc mt=main> {<ct=inc mt=main>}]\n"
+                        + "]\n"
+                        + "[incM: <ct=inc mt=main> {<ct=imp mt=main>}]\n"
+                    + "]\n"
+                + "]\n"
+                + "---6---\n"
+                + "[impM2: <ct=imp mt=main>\n"
+                    + "{<ct=main mt=main>}\n"
+                    + "[imp2M: <ct=imp2 mt=main> {<ct=imp mt=main>}]\n"
+                + "]\n"
+                + "---7---\n"
+                + "[inc3: <ct=inc3 mt=main>\n"
+                    + "[mainM: <ct=main mt=main> {<ct=inc3 mt=main>} <ct=main mt=main>]\n"
+                + "]\n"
+                + "[mainM: "
+                    + "<ct=main mt=main> "
+                    + "{<ct=main mt=main> <ct=inc4 mt=main> <ct=main mt=main>} "
+                    + "<ct=main mt=main>"
+                + "]\n"
+                + "<ct=main mt=main>\n"
+                + "---8---\n"
+                + "mainF: <ct=main mt=main>, impF: <ct=imp mt=main>, incF: <ct=inc mt=main>\n"
+                .replaceAll("<t=\\w+", "<t=main"));
+    }
+
+    @Test
+    public void testNotStarted() throws IOException, TemplateException {
+        Template t = new Template("foo", "", createConfiguration(Configuration.VERSION_3_0_0));
+        final Environment env = t.createProcessingEnvironment(null, null);
+        assertSame(t, env.getMainTemplate());
+        assertSame(t, env.getCurrentTemplate());
+    }
+    
+    private Configuration createConfiguration(Version iciVersion) {
+        return new TestConfigurationBuilder(iciVersion)
+                .templateLoader(TEMPLATES)
+                .whitespaceStripping(false)
+                .build();
+    }
+
+    @Override
+    protected Object createDataModel() {
+        return Collections.singletonMap("tNames", new TemplateDirectiveModel() {
+
+            @Override
+            public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
+                    throws TemplateException, IOException {
+                Writer out = env.getOut();
+                final String r = "<ct=" + env.getCurrentTemplate().getLookupName() + " mt="
+                        + env.getMainTemplate().getLookupName() + ">";
+                out.write(r);
+                env.setGlobalVariable("lastTNamesResult", new SimpleScalar(r));
+            }
+            
+        });
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/ExceptionTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/ExceptionTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ExceptionTest.java
new file mode 100644
index 0000000..19c3b6e
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ExceptionTest.java
@@ -0,0 +1,115 @@
+/*
+ * 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.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.Collections;
+import java.util.Locale;
+
+import org.apache.freemarker.core.templateresolver.impl.StringTemplateLoader;
+import org.apache.freemarker.core.util._NullWriter;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+
+import junit.framework.TestCase;
+public class ExceptionTest extends TestCase {
+    
+    public ExceptionTest(String name) {
+        super(name);
+    }
+
+    public void testParseExceptionSerializable() throws IOException, ClassNotFoundException {
+        try {
+            new Template(null, new StringReader("<@>"), new TestConfigurationBuilder().build());
+            fail();
+        } catch (ParseException e) {
+            ByteArrayOutputStream out = new ByteArrayOutputStream();
+            new ObjectOutputStream(out).writeObject(e);
+            new ObjectInputStream(new ByteArrayInputStream(out.toByteArray())).readObject();
+        }
+    }
+
+    public void testTemplateErrorSerializable() throws IOException, ClassNotFoundException {
+        Template tmp = new Template(null, new StringReader("${noSuchVar}"),
+                new TestConfigurationBuilder().build());
+        try {
+            tmp.process(Collections.EMPTY_MAP, new StringWriter());
+            fail();
+        } catch (TemplateException e) {
+            ByteArrayOutputStream out = new ByteArrayOutputStream();
+            new ObjectOutputStream(out).writeObject(e);
+            new ObjectInputStream(new ByteArrayInputStream(out.toByteArray())).readObject();
+        }
+    }
+    
+    @SuppressWarnings("boxing")
+    public void testTemplateExceptionLocationInformation() throws IOException {
+        StringTemplateLoader tl = new StringTemplateLoader();
+        tl.putTemplate("foo_en.ftl", "\n\nxxx${noSuchVariable}");
+
+        Template t = new TestConfigurationBuilder().templateLoader(tl).build()
+                .getTemplate("foo.ftl", Locale.US);
+        try {
+            t.process(null, _NullWriter.INSTANCE);
+            fail();
+        } catch (TemplateException e) {
+            assertEquals("foo.ftl", t.getLookupName());
+            assertEquals("foo.ftl", e.getTemplateLookupName());
+            assertEquals("foo_en.ftl", e.getTemplateSourceName());
+            assertEquals(3, (int) e.getLineNumber());
+            assertEquals(6, (int) e.getColumnNumber());
+            assertEquals(3, (int) e.getEndLineNumber());
+            assertEquals(19, (int) e.getEndColumnNumber());
+            assertThat(e.getMessage(), containsString("foo_en.ftl"));
+            assertThat(e.getMessage(), containsString("noSuchVariable"));
+        }
+    }
+
+    @SuppressWarnings("cast")
+    public void testParseExceptionLocationInformation() throws IOException {
+        StringTemplateLoader tl = new StringTemplateLoader();
+        tl.putTemplate("foo_en.ftl", "\n\nxxx<#noSuchDirective>");
+
+        try {
+            new TestConfigurationBuilder().templateLoader(tl).build()
+                    .getTemplate("foo.ftl", Locale.US);
+            fail();
+        } catch (ParseException e) {
+            System.out.println(e.getMessage());
+            assertEquals("foo_en.ftl", e.getTemplateSourceName());
+            assertEquals("foo.ftl", e.getTemplateLookupName());
+            assertEquals(3, e.getLineNumber());
+            assertEquals(5, e.getColumnNumber());
+            assertEquals(3, e.getEndLineNumber());
+            assertEquals(20, e.getEndColumnNumber());
+            assertThat(e.getMessage(), containsString("foo_en.ftl"));
+            assertThat(e.getMessage(), containsString("noSuchDirective"));
+        }
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/GetSourceTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/GetSourceTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/GetSourceTest.java
new file mode 100644
index 0000000..1462bfc
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/GetSourceTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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 org.apache.freemarker.test.TestConfigurationBuilder;
+import org.junit.Test;
+
+public class GetSourceTest {
+
+    @Test
+    public void testGetSource() throws Exception {
+        {
+            // Note: Default tab size is 8.
+            Template t = new Template(null, "a\n\tb\nc",
+                    new TestConfigurationBuilder().build());
+            // A historical quirk we keep for B.C.: it repaces tabs with spaces.
+            assertEquals("a\n        b\nc", t.getSource(1, 1, 1, 3));
+        }
+        
+        {
+            Template t = new Template(null, "a\n\tb\nc",
+                    new TestConfigurationBuilder().tabSize(4).build());
+            assertEquals("a\n    b\nc", t.getSource(1, 1, 1, 3));
+        }
+        
+        {
+            Template t = new Template(null, "a\n\tb\nc",
+                    new TestConfigurationBuilder().tabSize(1).build());
+            // If tab size is 1, it behaves as it always should have: it keeps the tab.
+            assertEquals("a\n\tb\nc", t.getSource(1, 1, 1, 3));
+        }
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/HeaderParsingTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/HeaderParsingTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/HeaderParsingTest.java
new file mode 100644
index 0000000..6f8851d
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/HeaderParsingTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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;
+
+public class HeaderParsingTest extends TemplateTest {
+
+    private final Configuration cfgStripWS = new TestConfigurationBuilder().build();
+    private final Configuration cfgNoStripWS = new TestConfigurationBuilder().whitespaceStripping(false).build();
+
+    @Test
+    public void test() throws IOException, TemplateException {
+        assertOutput("<#ftl>text", "text", "text");
+        assertOutput(" <#ftl> text", " text", " text");
+        assertOutput("\n<#ftl>\ntext", "text", "text");
+        assertOutput("\n \n\n<#ftl> \ntext", "text", "text");
+        assertOutput("\n \n\n<#ftl>\n\ntext", "\ntext", "\ntext");
+    }
+    
+    private void assertOutput(final String ftl, String expectedOutStripped, String expectedOutNonStripped)
+            throws IOException, TemplateException {
+        for (int i = 0; i < 4; i++) {
+            String ftlPermutation = ftl;
+            if ((i & 1) == 1) {
+                ftlPermutation = ftlPermutation.replace("<#ftl>", "<#ftl encoding='utf-8'>");
+            }
+            if ((i & 2) == 2) {
+                ftlPermutation = ftlPermutation.replace('<', '[').replace('>', ']');
+            }
+            
+            setConfiguration(cfgStripWS);
+            assertOutput(ftlPermutation, expectedOutStripped);
+            setConfiguration(cfgNoStripWS);
+            assertOutput(ftlPermutation, expectedOutNonStripped);
+        }
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/IncludeAndImportConfigurableLayersTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/IncludeAndImportConfigurableLayersTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/IncludeAndImportConfigurableLayersTest.java
new file mode 100644
index 0000000..738b4de
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/IncludeAndImportConfigurableLayersTest.java
@@ -0,0 +1,354 @@
+/*
+ * 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.StringWriter;
+
+import org.apache.freemarker.core.templateresolver.ConditionalTemplateConfigurationFactory;
+import org.apache.freemarker.core.templateresolver.FileNameGlobMatcher;
+import org.apache.freemarker.core.templateresolver.impl.StringTemplateLoader;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+public class IncludeAndImportConfigurableLayersTest {
+
+    @Test
+    public void test3LayerImportNoClashes() throws Exception {
+        TestConfigurationBuilder cfgB = createConfigurationBuilder()
+                .autoImports(ImmutableMap.of("t1", "t1.ftl"))
+                .templateConfigurations(
+                        new ConditionalTemplateConfigurationFactory(
+                                new FileNameGlobMatcher("main.ftl"),
+                                new TemplateConfiguration.Builder()
+                                        .autoImports(ImmutableMap.of("t2", "t2.ftl"))
+                                        .build()));
+        Configuration cfg = cfgB.build();
+
+        {
+            Template t = cfg.getTemplate("main.ftl");
+            StringWriter sw = new StringWriter();
+            Environment env = t.createProcessingEnvironment(null, sw);
+            env.addAutoImport("t3", "t3.ftl");
+    
+            env.process();
+            assertEquals("In main: t1;t2;t3;", sw.toString());
+        }
+
+        {
+            Template t = cfg.getTemplate("main.ftl");
+            StringWriter sw = new StringWriter();
+            Environment env = t.createProcessingEnvironment(null, sw);
+    
+            env.process();
+            assertEquals("In main: t1;t2;", sw.toString());
+        }
+        
+        {
+            Template t = cfg.getTemplate("main2.ftl");
+            StringWriter sw = new StringWriter();
+            Environment env = t.createProcessingEnvironment(null, sw);
+            env.addAutoImport("t3", "t3.ftl");
+    
+            env.process();
+            assertEquals("In main2: t1;t3;", sw.toString());
+        }
+        
+        cfgB.removeAutoImport("t1");
+        cfg = cfgB.build();
+
+        {
+            Template t = cfg.getTemplate("main.ftl");
+            StringWriter sw = new StringWriter();
+            Environment env = t.createProcessingEnvironment(null, sw);
+            env.addAutoImport("t3", "t3.ftl");
+    
+            env.process();
+            assertEquals("In main: t2;t3;", sw.toString());
+        }
+    }
+    
+    @Test
+    public void test3LayerImportClashes() throws Exception {
+        Configuration cfg = createConfigurationBuilder()
+                .autoImports(ImmutableMap.of(
+                        "t1", "t1.ftl",
+                        "t2", "t2.ftl",
+                        "t3", "t3.ftl"))
+                .templateConfigurations(
+                        new ConditionalTemplateConfigurationFactory(
+                                new FileNameGlobMatcher("main.ftl"),
+                                new TemplateConfiguration.Builder()
+                                        .autoImports(ImmutableMap.of("t2", "t2b.ftl"))
+                                        .build()))
+                .build();
+
+        {
+            Template t = cfg.getTemplate("main.ftl");
+            StringWriter sw = new StringWriter();
+            Environment env = t.createProcessingEnvironment(null, sw);
+            env.addAutoImport("t3", "t3b.ftl");
+    
+            env.process();
+            assertEquals("In main: t1;t2b;t3b;", sw.toString());
+        }
+        
+        {
+            Template t = cfg.getTemplate("main2.ftl");
+            StringWriter sw = new StringWriter();
+            Environment env = t.createProcessingEnvironment(null, sw);
+            env.addAutoImport("t3", "t3b.ftl");
+    
+            env.process();
+            assertEquals("In main2: t1;t2;t3b;", sw.toString());
+        }
+        
+        {
+            Template t = cfg.getTemplate("main.ftl");
+            StringWriter sw = new StringWriter();
+            Environment env = t.createProcessingEnvironment(null, sw);
+    
+            env.process();
+            assertEquals("In main: t1;t3;t2b;", sw.toString());
+        }
+    }
+
+    @Test
+    public void test3LayerIncludesNoClashes() throws Exception {
+        TestConfigurationBuilder cfgB = createConfigurationBuilder()
+                .autoIncludes(ImmutableList.of("t1.ftl"))
+                .templateConfigurations(
+                        new ConditionalTemplateConfigurationFactory(
+                                new FileNameGlobMatcher("main.ftl"),
+                                new TemplateConfiguration.Builder()
+                                        .autoIncludes(ImmutableList.of("t2.ftl"))
+                                        .build()));
+
+        Configuration cfg = cfgB.build();
+
+        {
+            Template t = cfg.getTemplate("main.ftl");
+            StringWriter sw = new StringWriter();
+            Environment env = t.createProcessingEnvironment(null, sw);
+            env.addAutoInclude("t3.ftl");
+    
+            env.process();
+            assertEquals("T1;T2;T3;In main: t1;t2;t3;", sw.toString());
+        }
+
+        {
+            Template t = cfg.getTemplate("main.ftl");
+            StringWriter sw = new StringWriter();
+            Environment env = t.createProcessingEnvironment(null, sw);
+    
+            env.process();
+            assertEquals("T1;T2;In main: t1;t2;", sw.toString());
+        }
+        
+        {
+            Template t = cfg.getTemplate("main2.ftl");
+            StringWriter sw = new StringWriter();
+            Environment env = t.createProcessingEnvironment(null, sw);
+            env.addAutoInclude("t3.ftl");
+    
+            env.process();
+            assertEquals("T1;T3;In main2: t1;t3;", sw.toString());
+        }
+        
+        cfgB.removeAutoInclude("t1.ftl");
+        cfg = cfgB.build();
+
+        {
+            Template t = cfg.getTemplate("main.ftl");
+            StringWriter sw = new StringWriter();
+            Environment env = t.createProcessingEnvironment(null, sw);
+            env.addAutoInclude("t3.ftl");
+    
+            env.process();
+            assertEquals("T2;T3;In main: t2;t3;", sw.toString());
+        }
+    }
+
+    @Test
+    public void test3LayerIncludeClashes() throws Exception {
+        Configuration cfg = createConfigurationBuilder()
+                .autoIncludes(ImmutableList.of(
+                        "t1.ftl",
+                        "t2.ftl",
+                        "t3.ftl"))
+                .templateConfigurations(new ConditionalTemplateConfigurationFactory(
+                        new FileNameGlobMatcher("main.ftl"),
+                        new TemplateConfiguration.Builder()
+                                .autoIncludes(ImmutableList.of("t2.ftl"))
+                                .build()))
+                .build();
+
+        {
+            Template t = cfg.getTemplate("main.ftl");
+            StringWriter sw = new StringWriter();
+            Environment env = t.createProcessingEnvironment(null, sw);
+            env.addAutoInclude("t3.ftl");
+    
+            env.process();
+            assertEquals("T1;T2;T3;In main: t1;t2;t3;", sw.toString());
+        }
+        
+        {
+            Template t = cfg.getTemplate("main2.ftl");
+            StringWriter sw = new StringWriter();
+            Environment env = t.createProcessingEnvironment(null, sw);
+            env.addAutoInclude("t3.ftl");
+    
+            env.process();
+            assertEquals("T1;T2;T3;In main2: t1;t2;t3;", sw.toString());
+        }
+        
+        {
+            Template t = cfg.getTemplate("main.ftl");
+            StringWriter sw = new StringWriter();
+            Environment env = t.createProcessingEnvironment(null, sw);
+    
+            env.process();
+            assertEquals("T1;T3;T2;In main: t1;t3;t2;", sw.toString());
+        }
+        
+        {
+            Template t = cfg.getTemplate("main.ftl");
+            StringWriter sw = new StringWriter();
+            Environment env = t.createProcessingEnvironment(null, sw);
+            env.addAutoInclude("t1.ftl");
+    
+            env.process();
+            assertEquals("T3;T2;T1;In main: t3;t2;t1;", sw.toString());
+        }
+    }
+    
+    @Test
+    public void test3LayerIncludesClashes2() throws Exception {
+        Configuration cfg = createConfigurationBuilder()
+                .autoIncludes(ImmutableList.of("t1.ftl", "t1.ftl"))
+                .templateConfigurations(
+                        new ConditionalTemplateConfigurationFactory(
+                                new FileNameGlobMatcher("main.ftl"),
+                                new TemplateConfiguration.Builder()
+                                        .autoIncludes(ImmutableList.of("t2.ftl", "t2.ftl"))
+                                        .build()))
+                .build();
+
+        {
+            Template t = cfg.getTemplate("main.ftl");
+            StringWriter sw = new StringWriter();
+            Environment env = t.createProcessingEnvironment(null, sw);
+            env.addAutoInclude("t3.ftl");
+            env.addAutoInclude("t3.ftl");
+            env.addAutoInclude("t1.ftl");
+            env.addAutoInclude("t1.ftl");
+    
+            env.process();
+            assertEquals("T2;T3;T1;In main: t2;t3;t1;", sw.toString());
+        }
+    }
+    
+    @Test
+    public void test3LayerLaziness() throws Exception {
+        for (Class<?> layer : new Class<?>[] { Configuration.class, Template.class, Environment.class }) {
+            test3LayerLaziness(layer, null, null, false, "t1;t2;");
+            test3LayerLaziness(layer, null, null, true, "t1;t2;");
+            test3LayerLaziness(layer, null, false, true, "t1;t2;");
+            test3LayerLaziness(layer, null, true, true, "t2;");
+            
+            test3LayerLaziness(layer, false, null, false, "t1;t2;");
+            test3LayerLaziness(layer, false, null, true, "t1;t2;");
+            test3LayerLaziness(layer, false, false, true, "t1;t2;");
+            test3LayerLaziness(layer, false, true, true, "t2;");
+
+            test3LayerLaziness(layer, true, null, false, "");
+            test3LayerLaziness(layer, true, null, true, "");
+            test3LayerLaziness(layer, true, false, true, "t1;");
+            test3LayerLaziness(layer, true, true, true, "");
+        }
+    }
+    
+    private void test3LayerLaziness(
+            Class<?> layer,
+            Boolean lazyImports,
+            Boolean lazyAutoImports, boolean setLazyAutoImports,
+            String expectedOutput)
+            throws Exception {
+        Configuration cfg;
+        {
+            TestConfigurationBuilder cfgB = createConfigurationBuilder()
+                    .autoImports(ImmutableMap.of("t1", "t1.ftl"));
+            if (layer == Configuration.class) {
+                setLazinessOfConfigurable(cfgB, lazyImports, lazyAutoImports, setLazyAutoImports);
+            }
+            cfg = cfgB.build();
+        }
+
+        TemplateConfiguration tc;
+        if (layer == Template.class) {
+            TemplateConfiguration.Builder tcb = new TemplateConfiguration.Builder();
+            setLazinessOfConfigurable(tcb, lazyImports, lazyAutoImports, setLazyAutoImports);
+            tc = tcb.build();
+        } else {
+            tc = null;
+        }
+
+        Template t = new Template(null, "<#import 't2.ftl' as t2>${loaded!}", cfg, tc);
+        StringWriter sw = new StringWriter();
+
+        Environment env = t.createProcessingEnvironment(null, sw);
+        if (layer == Environment.class) {
+            setLazinessOfConfigurable(env, lazyImports, lazyAutoImports, setLazyAutoImports);
+        }
+
+        env.process();
+        assertEquals(expectedOutput, sw.toString());
+    }
+
+    private void setLazinessOfConfigurable(
+            MutableProcessingConfiguration<?> cfg,
+            Boolean lazyImports, Boolean lazyAutoImports, boolean setLazyAutoImports) {
+        if (lazyImports != null) {
+            cfg.setLazyImports(lazyImports);
+        }
+        if (setLazyAutoImports) {
+            cfg.setLazyAutoImports(lazyAutoImports);
+        }
+    }
+    
+    private TestConfigurationBuilder createConfigurationBuilder() {
+        StringTemplateLoader loader = new StringTemplateLoader();
+        loader.putTemplate("main.ftl", "In main: ${loaded}");
+        loader.putTemplate("main2.ftl", "In main2: ${loaded}");
+        loader.putTemplate("t1.ftl", "<#global loaded = (loaded!) + 't1;'>T1;");
+        loader.putTemplate("t2.ftl", "<#global loaded = (loaded!) + 't2;'>T2;");
+        loader.putTemplate("t3.ftl", "<#global loaded = (loaded!) + 't3;'>T3;");
+        loader.putTemplate("t1b.ftl", "<#global loaded = (loaded!) + 't1b;'>T1b;");
+        loader.putTemplate("t2b.ftl", "<#global loaded = (loaded!) + 't2b;'>T2b;");
+        loader.putTemplate("t3b.ftl", "<#global loaded = (loaded!) + 't3b;'>T3b;");
+
+        return new TestConfigurationBuilder().templateLoader(loader);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/IncludeAndImportTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/IncludeAndImportTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/IncludeAndImportTest.java
new file mode 100644
index 0000000..fa767ff
--- /dev/null
+++ b/freemarker-core-test/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/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/IncudeFromNamelessTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/IncudeFromNamelessTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/IncudeFromNamelessTest.java
new file mode 100644
index 0000000..f4908b8
--- /dev/null
+++ b/freemarker-core-test/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());
+    }
+
+}


[50/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultMethodsBeanBase.java
----------------------------------------------------------------------
diff --git a/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultMethodsBeanBase.java b/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultMethodsBeanBase.java
deleted file mode 100644
index c01422e..0000000
--- a/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultMethodsBeanBase.java
+++ /dev/null
@@ -1,97 +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.model.impl;
-
-public interface Java8DefaultMethodsBeanBase {
-    
-    static final String DEFAULT_METHOD_PROP = "defaultMethodProp";
-    static final String DEFAULT_METHOD_PROP_VALUE = "defaultMethodPropValue";
-    static final String DEFAULT_METHOD_PROP_2 = "defaultMethodProp2";
-    static final String DEFAULT_METHOD_INDEXED_PROP = "defaultMethodIndexedProp";
-    static final String DEFAULT_METHOD_INDEXED_PROP_GETTER = "getDefaultMethodIndexedProp";
-    static final String DEFAULT_METHOD_INDEXED_PROP_VALUE = "defaultMethodIndexedPropValue";
-    static final String DEFAULT_METHOD_INDEXED_PROP_2 = "defaultMethodIndexedProp2";
-    static final String DEFAULT_METHOD_INDEXED_PROP_2_VALUE_0 = "defaultMethodIndexedProp2(0).value";
-    static final String DEFAULT_METHOD_INDEXED_PROP_3 = "defaultMethodIndexedProp3";
-    static final String DEFAULT_METHOD_INDEXED_PROP_3_VALUE_0 = "indexedProp3Value[0]";
-    static final String DEFAULT_METHOD_NOT_AN_INDEXED_PROP = "defaultMethodNotAnIndexedProp";
-    static final String DEFAULT_METHOD_NOT_AN_INDEXED_PROP_VALUE = "defaultMethodNotAnIndexedPropValue";
-    static final String DEFAULT_METHOD_NOT_AN_INDEXED_PROP_2 = "defaultMethodNotAnIndexedProp2";
-    static final String DEFAULT_METHOD_NOT_AN_INDEXED_PROP_2_VALUE = "defaultMethodNotAnIndexedProp2Value";
-    static final String DEFAULT_METHOD_NOT_AN_INDEXED_PROP_3 = "defaultMethodNotAnIndexedProp3";
-    static final String DEFAULT_METHOD_NOT_AN_INDEXED_PROP_3_VALUE_0 = "defaultMethodNotAnIndexedProp3Value[0]";
-    static final String DEFAULT_METHOD_ACTION = "defaultMethodAction";
-    static final String DEFAULT_METHOD_ACTION_RETURN_VALUE = "defaultMethodActionReturnValue";
-    static final String OVERRIDDEN_DEFAULT_METHOD_ACTION = "overriddenDefaultMethodAction";
-
-    default String getDefaultMethodProp() {
-        return DEFAULT_METHOD_PROP_VALUE;
-    }
-
-    default String getDefaultMethodProp2() {
-        return "";
-    }
-
-    /**
-     * Will be kept as there's no non-indexed read methods for this.
-     */
-    default String getDefaultMethodIndexedProp(int i) {
-        return DEFAULT_METHOD_INDEXED_PROP_VALUE;
-    }
-
-    /**
-     * Will be kept as there will be a matching non-indexed read method in the subclass.
-     * However, as of FM3, the non-indexed read method is used if it's available.
-     */
-    default String getDefaultMethodIndexedProp2(int i) {
-        return DEFAULT_METHOD_INDEXED_PROP_2_VALUE_0;
-    }
-
-    /**
-     * This is not an indexed reader method, but a matching indexed reader method will be added in the subclass. 
-     * However, as of FM3, the non-indexed read method is used if it's available.
-     */
-    default String[] getDefaultMethodIndexedProp3() {
-        return new String[] {DEFAULT_METHOD_INDEXED_PROP_3_VALUE_0};
-    }
-    
-    /** Will be discarded because of a non-matching non-indexed read method in a subclass */
-    default String getDefaultMethodNotAnIndexedProp(int i) {
-        return "";
-    }
-    
-    /** The subclass will try to override this with a non-matching indexed reader, but this will be stronger. */
-    default String getDefaultMethodNotAnIndexedProp2() {
-        return DEFAULT_METHOD_NOT_AN_INDEXED_PROP_2_VALUE;
-    }
-
-    /** The subclass will try to override this with a non-matching indexed reader, but this will be stronger. */
-    default String[] getDefaultMethodNotAnIndexedProp3() {
-        return new String[] { DEFAULT_METHOD_NOT_AN_INDEXED_PROP_3_VALUE_0 };
-    }
-    
-    default String defaultMethodAction() {
-        return DEFAULT_METHOD_ACTION_RETURN_VALUE;
-    }
-
-    default Object overriddenDefaultMethodAction() {
-        return null;
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperBridgeMethodsTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperBridgeMethodsTest.java b/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperBridgeMethodsTest.java
deleted file mode 100644
index 495f3f9..0000000
--- a/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperBridgeMethodsTest.java
+++ /dev/null
@@ -1,65 +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.model.impl;
-
-import static org.junit.Assert.*;
-
-import java.util.Collections;
-
-import org.junit.Test;
-
-import org.apache.freemarker.core.Configuration;
-import org.apache.freemarker.core.model.TemplateHashModel;
-import org.apache.freemarker.core.model.TemplateMethodModelEx;
-import org.apache.freemarker.core.model.TemplateModelException;
-
-public class Java8DefaultObjectWrapperBridgeMethodsTest {
-    
-    @Test
-    public void testWithoutDefaultMethod() throws TemplateModelException {
-        test(BridgeMethodsBean.class);
-    }
-
-    @Test
-    public void testWithDefaultMethod() throws TemplateModelException {
-        test(Java8BridgeMethodsWithDefaultMethodBean.class);
-    }
-
-    @Test
-    public void testWithDefaultMethod2() throws TemplateModelException {
-        test(Java8BridgeMethodsWithDefaultMethodBean2.class);
-    }
-
-    private void test(Class<?> pClass) throws TemplateModelException {
-        DefaultObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
-        TemplateHashModel wrapped;
-        try {
-            wrapped = (TemplateHashModel) ow.wrap(pClass.newInstance());
-        } catch (Exception e) {
-            throw new IllegalStateException(e);
-        }
-        
-        TemplateMethodModelEx m1 = (TemplateMethodModelEx) wrapped.get("m1");
-        assertEquals(BridgeMethodsBean.M1_RETURN_VALUE, "" + m1.exec(Collections.emptyList()));
-        
-        TemplateMethodModelEx m2 = (TemplateMethodModelEx) wrapped.get("m2");
-        assertNull(m2.exec(Collections.emptyList()));
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperTest.java b/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperTest.java
deleted file mode 100644
index 905d536..0000000
--- a/freemarker-core-java8-test/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperTest.java
+++ /dev/null
@@ -1,160 +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.model.impl;
-
-import static org.junit.Assert.*;
-
-import java.util.Collections;
-
-import org.junit.Test;
-
-import org.apache.freemarker.core.Configuration;
-import org.apache.freemarker.core.model.TemplateHashModel;
-import org.apache.freemarker.core.model.TemplateMethodModelEx;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateNumberModel;
-import org.apache.freemarker.core.model.TemplateScalarModel;
-import org.apache.freemarker.core.model.TemplateSequenceModel;
-
-public class Java8DefaultObjectWrapperTest {
-
-    @Test
-    public void testDefaultMethodRecognized() throws TemplateModelException {
-        DefaultObjectWrapper.Builder owb = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
-        DefaultObjectWrapper ow = owb.build();
-        TemplateHashModel wrappedBean = (TemplateHashModel) ow.wrap(new Java8DefaultMethodsBean());
-        
-        {
-            TemplateScalarModel prop = (TemplateScalarModel) wrappedBean.get(Java8DefaultMethodsBean.NORMAL_PROP);
-            assertNotNull(prop);
-            assertEquals(Java8DefaultMethodsBean.NORMAL_PROP_VALUE, prop.getAsString());
-        }
-        {
-            // This is overridden in the subclass, so it's visible even without default method support: 
-            TemplateScalarModel prop = (TemplateScalarModel) wrappedBean.get(
-                    Java8DefaultMethodsBean.DEFAULT_METHOD_PROP_2);
-            assertNotNull(prop);
-            assertEquals(Java8DefaultMethodsBean.PROP_2_OVERRIDE_VALUE, prop.getAsString());
-        }
-        {
-            TemplateScalarModel prop = (TemplateScalarModel) wrappedBean.get(
-                    Java8DefaultMethodsBeanBase.DEFAULT_METHOD_PROP);
-            assertNotNull(prop);
-            assertEquals(Java8DefaultMethodsBeanBase.DEFAULT_METHOD_PROP_VALUE, prop.getAsString());
-        }
-        {
-            // Has only indexed read method, so it's not exposed as a property
-            assertNull(wrappedBean.get(Java8DefaultMethodsBeanBase.DEFAULT_METHOD_INDEXED_PROP));
-
-            TemplateMethodModelEx indexedReadMethod = (TemplateMethodModelEx) wrappedBean.get(
-                    Java8DefaultMethodsBeanBase.DEFAULT_METHOD_INDEXED_PROP_GETTER);
-            assertNotNull(indexedReadMethod);
-            assertEquals(Java8DefaultMethodsBeanBase.DEFAULT_METHOD_INDEXED_PROP_VALUE,
-                    ((TemplateScalarModel) indexedReadMethod.exec(Collections.singletonList(new SimpleNumber(0))))
-                            .getAsString
-                            ());
-        }
-        {
-            // We see default method indexed read method, but it's invalidated by normal getter in the subclass
-            TemplateNumberModel prop = (TemplateNumberModel) wrappedBean.get(
-                    Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP);
-            assertNotNull(prop);
-            assertEquals(Java8DefaultMethodsBean.NOT_AN_INDEXED_PROP_VALUE, prop.getAsNumber());
-        }
-        {
-            // The default method read method invalidates the indexed read method in the subclass
-            TemplateScalarModel prop = (TemplateScalarModel) wrappedBean.get(
-                    Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP_2);
-            assertNotNull(prop);
-            assertEquals(Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP_2_VALUE, prop.getAsString());
-        }
-        {
-            // The default method read method invalidates the indexed read method in the subclass
-            TemplateSequenceModel prop = (TemplateSequenceModel) wrappedBean.get(
-                    Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP_3);
-            assertNotNull(prop);
-            assertEquals(Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP_3_VALUE_0,
-                    ((TemplateScalarModel) prop.get(0)).getAsString());
-        }
-        {
-            // We see the default method indexed reader, which overrides the plain array reader in the subclass.
-            TemplateSequenceModel prop = (TemplateSequenceModel) wrappedBean.get(
-                    Java8DefaultMethodsBean.DEFAULT_METHOD_INDEXED_PROP_2);
-            assertNotNull(prop);
-            assertEquals(Java8DefaultMethodsBean.ARRAY_PROP_2_VALUE_0,
-                    ((TemplateScalarModel) prop.get(0)).getAsString());
-        }
-        {
-            // We do see the default method non-indexed reader, but the subclass has a matching indexed reader, so that
-            // takes over.
-            TemplateSequenceModel prop = (TemplateSequenceModel) wrappedBean.get(
-                    Java8DefaultMethodsBean.DEFAULT_METHOD_INDEXED_PROP_3);
-            assertNotNull(prop);
-            assertEquals(Java8DefaultMethodsBeanBase.DEFAULT_METHOD_INDEXED_PROP_3_VALUE_0,
-                    ((TemplateScalarModel) prop.get(0)).getAsString());
-        }        
-        {
-            // Only present in the subclass.
-
-            // Has only indexed read method, so it's not exposed as a property
-            assertNull(wrappedBean.get(Java8DefaultMethodsBean.INDEXED_PROP_4));
-
-            TemplateMethodModelEx indexedReadMethod = (TemplateMethodModelEx) wrappedBean.get(
-                    Java8DefaultMethodsBean.INDEXED_PROP_GETTER_4);
-            assertNotNull(indexedReadMethod);
-            assertEquals(Java8DefaultMethodsBean.INDEXED_PROP_4_VALUE,
-                    ((TemplateScalarModel) indexedReadMethod.exec(Collections.singletonList(new SimpleNumber(0))))
-                            .getAsString());
-        }        
-        {
-            TemplateMethodModelEx action = (TemplateMethodModelEx) wrappedBean.get(
-                    Java8DefaultMethodsBean.NORMAL_ACTION);
-            assertNotNull(action);
-            assertEquals(
-                    Java8DefaultMethodsBean.NORMAL_ACTION_RETURN_VALUE,
-                    ((TemplateScalarModel) action.exec(Collections.emptyList())).getAsString());
-        }
-        
-        {
-            TemplateMethodModelEx action = (TemplateMethodModelEx) wrappedBean.get(
-                    Java8DefaultMethodsBean.NORMAL_ACTION);
-            assertNotNull(action);
-            assertEquals(
-                    Java8DefaultMethodsBean.NORMAL_ACTION_RETURN_VALUE,
-                    ((TemplateScalarModel) action.exec(Collections.emptyList())).getAsString());
-        }
-        {
-            TemplateMethodModelEx action = (TemplateMethodModelEx) wrappedBean.get(
-                    Java8DefaultMethodsBean.DEFAULT_METHOD_ACTION);
-            assertNotNull(action);
-            assertEquals(
-                    Java8DefaultMethodsBean.DEFAULT_METHOD_ACTION_RETURN_VALUE,
-                    ((TemplateScalarModel) action.exec(Collections.emptyList())).getAsString());
-        }
-        {
-            TemplateMethodModelEx action = (TemplateMethodModelEx) wrappedBean.get(
-                    Java8DefaultMethodsBean.OVERRIDDEN_DEFAULT_METHOD_ACTION);
-            assertNotNull(action);
-            assertEquals(
-                    Java8DefaultMethodsBean.OVERRIDDEN_DEFAULT_METHOD_ACTION_RETURN_VALUE,
-                    ((TemplateScalarModel) action.exec(Collections.emptyList())).getAsString());
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test-java8/build.gradle
----------------------------------------------------------------------
diff --git a/freemarker-core-test-java8/build.gradle b/freemarker-core-test-java8/build.gradle
new file mode 100644
index 0000000..44b95ae
--- /dev/null
+++ b/freemarker-core-test-java8/build.gradle
@@ -0,0 +1,25 @@
+description = """\
+The unit tests of freemarker-core that need Java 8 features. These were moved to a separate project to avoid \
+a project that contains java files that require varous Java versions.
+"""
+
+// Override inherited default Java version:
+sourceCompatibility = "1.8"
+targetCompatibility = "1.8"
+[compileJava, compileTestJava]*.options*.bootClasspath = bootClasspathJava8
+
+dependencies {
+    compile project(":freemarker-core")
+    compile project(":freemarker-test-utils")
+}
+
+// We have nothing to put into the jar, as we have test classes only
+jar.enabled = false
+
+javadoc.enabled = false
+
+// Must not be deployed to a public Maven repository
+uploadArchives.enabled = false
+
+// Doesn't make sense to Maven "install" this, as the artifact won't contain test classes
+install.enabled = false

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test-java8/src/main/resources/META-INF/DISCLAIMER
----------------------------------------------------------------------
diff --git a/freemarker-core-test-java8/src/main/resources/META-INF/DISCLAIMER b/freemarker-core-test-java8/src/main/resources/META-INF/DISCLAIMER
new file mode 100644
index 0000000..569ba05
--- /dev/null
+++ b/freemarker-core-test-java8/src/main/resources/META-INF/DISCLAIMER
@@ -0,0 +1,8 @@
+Apache FreeMarker is an effort undergoing incubation at The Apache Software
+Foundation (ASF), sponsored by the Apache Incubator. Incubation is required of
+all newly accepted projects until a further review indicates that the
+infrastructure, communications, and decision making process have stabilized in
+a manner consistent with other successful ASF projects. While incubation
+status is not necessarily a reflection of the completeness or stability of the
+code, it does indicate that the project has yet to be fully endorsed by the
+ASF.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test-java8/src/main/resources/META-INF/LICENSE
----------------------------------------------------------------------
diff --git a/freemarker-core-test-java8/src/main/resources/META-INF/LICENSE b/freemarker-core-test-java8/src/main/resources/META-INF/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/freemarker-core-test-java8/src/main/resources/META-INF/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/BridgeMethodsBean.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/BridgeMethodsBean.java b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/BridgeMethodsBean.java
new file mode 100644
index 0000000..2c9d4e9
--- /dev/null
+++ b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/BridgeMethodsBean.java
@@ -0,0 +1,30 @@
+/*
+ * 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.model.impl;
+
+public class BridgeMethodsBean extends BridgeMethodsBeanBase<String> {
+
+    static final String M1_RETURN_VALUE = "m1ReturnValue"; 
+    
+    @Override
+    public String m1() {
+        return M1_RETURN_VALUE;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/BridgeMethodsBeanBase.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/BridgeMethodsBeanBase.java b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/BridgeMethodsBeanBase.java
new file mode 100644
index 0000000..4ecec7c
--- /dev/null
+++ b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/BridgeMethodsBeanBase.java
@@ -0,0 +1,29 @@
+/*
+ * 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.model.impl;
+
+public abstract class BridgeMethodsBeanBase<T> {
+
+    public abstract T m1();
+    
+    public T m2() {
+        return null;
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBean.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBean.java b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBean.java
new file mode 100644
index 0000000..c7d27a6
--- /dev/null
+++ b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBean.java
@@ -0,0 +1,29 @@
+/*
+ * 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.model.impl;
+
+public class Java8BridgeMethodsWithDefaultMethodBean implements Java8BridgeMethodsWithDefaultMethodBeanBase<String> {
+
+    static final String M1_RETURN_VALUE = "m1ReturnValue"; 
+    
+    public String m1() {
+        return M1_RETURN_VALUE;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBean2.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBean2.java b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBean2.java
new file mode 100644
index 0000000..7dfb39a
--- /dev/null
+++ b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBean2.java
@@ -0,0 +1,23 @@
+/*
+ * 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.model.impl;
+
+public class Java8BridgeMethodsWithDefaultMethodBean2 implements Java8BridgeMethodsWithDefaultMethodBeanBase2 {
+    // All inherited
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBeanBase.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBeanBase.java b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBeanBase.java
new file mode 100644
index 0000000..fdd8821
--- /dev/null
+++ b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBeanBase.java
@@ -0,0 +1,31 @@
+/*
+ * 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.model.impl;
+
+public interface Java8BridgeMethodsWithDefaultMethodBeanBase<T> {
+
+    default T m1() {
+        return null;
+    }
+    
+    default T m2() {
+        return null;
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBeanBase2.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBeanBase2.java b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBeanBase2.java
new file mode 100644
index 0000000..6f68dc7
--- /dev/null
+++ b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8BridgeMethodsWithDefaultMethodBeanBase2.java
@@ -0,0 +1,28 @@
+/*
+ * 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.model.impl;
+
+public interface Java8BridgeMethodsWithDefaultMethodBeanBase2 extends Java8BridgeMethodsWithDefaultMethodBeanBase<String> {
+
+    @Override
+    default String m1() {
+        return Java8BridgeMethodsWithDefaultMethodBean.M1_RETURN_VALUE;
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultMethodsBean.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultMethodsBean.java b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultMethodsBean.java
new file mode 100644
index 0000000..eabc3d0
--- /dev/null
+++ b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultMethodsBean.java
@@ -0,0 +1,84 @@
+/*
+ * 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.model.impl;
+
+public class Java8DefaultMethodsBean implements Java8DefaultMethodsBeanBase {
+    
+    static final String NORMAL_PROP = "normalProp";
+    static final String NORMAL_PROP_VALUE = "normalPropValue";
+    static final String PROP_2_OVERRIDE_VALUE = "prop2OverrideValue";
+    static final int NOT_AN_INDEXED_PROP_VALUE = 1;
+    static final String ARRAY_PROP_2_VALUE_0 = "arrayProp2[0].value";
+    private static final int NOT_AN_INDEXED_PROP_3_VALUE = 3;
+    private static final String NOT_AN_INDEXED_PROP_2_VALUE = "notAnIndecedProp2Value";
+    static final String INDEXED_PROP_4 = "indexedProp4";
+    static final String INDEXED_PROP_GETTER_4 = "getIndexedProp4";
+    static final String INDEXED_PROP_4_VALUE = "indexedProp4Value[0]";
+    static final String NORMAL_ACTION = "normalAction";
+    static final String NORMAL_ACTION_RETURN_VALUE = "normalActionReturnValue";
+    static final String OVERRIDDEN_DEFAULT_METHOD_ACTION_RETURN_VALUE = "overriddenValue";
+    
+    public String getNormalProp() {
+        return NORMAL_PROP_VALUE;
+    }
+    
+    @Override
+    public String getDefaultMethodProp2() {
+        return PROP_2_OVERRIDE_VALUE;
+    }
+    
+    public String[] getDefaultMethodIndexedProp2() {
+        return new String[] { ARRAY_PROP_2_VALUE_0 };
+    }
+
+    /**
+     * There's a matching non-indexed reader method in the base class, but as this is indexed, it takes over. 
+     */
+    public String getDefaultMethodIndexedProp3(int index) {
+        return "";
+    }
+    
+    public int getDefaultMethodNotAnIndexedProp() {
+        return NOT_AN_INDEXED_PROP_VALUE;
+    }
+
+    /** Actually, this will be indexed if the default method support is off. */
+    public String getDefaultMethodNotAnIndexedProp2(int index) {
+        return NOT_AN_INDEXED_PROP_2_VALUE;
+    }
+    
+    /** Actually, this will be indexed if the default method support is off. */
+    public int getDefaultMethodNotAnIndexedProp3(int index) {
+        return NOT_AN_INDEXED_PROP_3_VALUE;
+    }
+    
+    public String getIndexedProp4(int index) {
+        return INDEXED_PROP_4_VALUE;
+    }
+    
+    public String normalAction() {
+        return NORMAL_ACTION_RETURN_VALUE;
+    }
+    
+    @Override
+    public String overriddenDefaultMethodAction() {
+        return OVERRIDDEN_DEFAULT_METHOD_ACTION_RETURN_VALUE;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultMethodsBeanBase.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultMethodsBeanBase.java b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultMethodsBeanBase.java
new file mode 100644
index 0000000..c01422e
--- /dev/null
+++ b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultMethodsBeanBase.java
@@ -0,0 +1,97 @@
+/*
+ * 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.model.impl;
+
+public interface Java8DefaultMethodsBeanBase {
+    
+    static final String DEFAULT_METHOD_PROP = "defaultMethodProp";
+    static final String DEFAULT_METHOD_PROP_VALUE = "defaultMethodPropValue";
+    static final String DEFAULT_METHOD_PROP_2 = "defaultMethodProp2";
+    static final String DEFAULT_METHOD_INDEXED_PROP = "defaultMethodIndexedProp";
+    static final String DEFAULT_METHOD_INDEXED_PROP_GETTER = "getDefaultMethodIndexedProp";
+    static final String DEFAULT_METHOD_INDEXED_PROP_VALUE = "defaultMethodIndexedPropValue";
+    static final String DEFAULT_METHOD_INDEXED_PROP_2 = "defaultMethodIndexedProp2";
+    static final String DEFAULT_METHOD_INDEXED_PROP_2_VALUE_0 = "defaultMethodIndexedProp2(0).value";
+    static final String DEFAULT_METHOD_INDEXED_PROP_3 = "defaultMethodIndexedProp3";
+    static final String DEFAULT_METHOD_INDEXED_PROP_3_VALUE_0 = "indexedProp3Value[0]";
+    static final String DEFAULT_METHOD_NOT_AN_INDEXED_PROP = "defaultMethodNotAnIndexedProp";
+    static final String DEFAULT_METHOD_NOT_AN_INDEXED_PROP_VALUE = "defaultMethodNotAnIndexedPropValue";
+    static final String DEFAULT_METHOD_NOT_AN_INDEXED_PROP_2 = "defaultMethodNotAnIndexedProp2";
+    static final String DEFAULT_METHOD_NOT_AN_INDEXED_PROP_2_VALUE = "defaultMethodNotAnIndexedProp2Value";
+    static final String DEFAULT_METHOD_NOT_AN_INDEXED_PROP_3 = "defaultMethodNotAnIndexedProp3";
+    static final String DEFAULT_METHOD_NOT_AN_INDEXED_PROP_3_VALUE_0 = "defaultMethodNotAnIndexedProp3Value[0]";
+    static final String DEFAULT_METHOD_ACTION = "defaultMethodAction";
+    static final String DEFAULT_METHOD_ACTION_RETURN_VALUE = "defaultMethodActionReturnValue";
+    static final String OVERRIDDEN_DEFAULT_METHOD_ACTION = "overriddenDefaultMethodAction";
+
+    default String getDefaultMethodProp() {
+        return DEFAULT_METHOD_PROP_VALUE;
+    }
+
+    default String getDefaultMethodProp2() {
+        return "";
+    }
+
+    /**
+     * Will be kept as there's no non-indexed read methods for this.
+     */
+    default String getDefaultMethodIndexedProp(int i) {
+        return DEFAULT_METHOD_INDEXED_PROP_VALUE;
+    }
+
+    /**
+     * Will be kept as there will be a matching non-indexed read method in the subclass.
+     * However, as of FM3, the non-indexed read method is used if it's available.
+     */
+    default String getDefaultMethodIndexedProp2(int i) {
+        return DEFAULT_METHOD_INDEXED_PROP_2_VALUE_0;
+    }
+
+    /**
+     * This is not an indexed reader method, but a matching indexed reader method will be added in the subclass. 
+     * However, as of FM3, the non-indexed read method is used if it's available.
+     */
+    default String[] getDefaultMethodIndexedProp3() {
+        return new String[] {DEFAULT_METHOD_INDEXED_PROP_3_VALUE_0};
+    }
+    
+    /** Will be discarded because of a non-matching non-indexed read method in a subclass */
+    default String getDefaultMethodNotAnIndexedProp(int i) {
+        return "";
+    }
+    
+    /** The subclass will try to override this with a non-matching indexed reader, but this will be stronger. */
+    default String getDefaultMethodNotAnIndexedProp2() {
+        return DEFAULT_METHOD_NOT_AN_INDEXED_PROP_2_VALUE;
+    }
+
+    /** The subclass will try to override this with a non-matching indexed reader, but this will be stronger. */
+    default String[] getDefaultMethodNotAnIndexedProp3() {
+        return new String[] { DEFAULT_METHOD_NOT_AN_INDEXED_PROP_3_VALUE_0 };
+    }
+    
+    default String defaultMethodAction() {
+        return DEFAULT_METHOD_ACTION_RETURN_VALUE;
+    }
+
+    default Object overriddenDefaultMethodAction() {
+        return null;
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperBridgeMethodsTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperBridgeMethodsTest.java b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperBridgeMethodsTest.java
new file mode 100644
index 0000000..495f3f9
--- /dev/null
+++ b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperBridgeMethodsTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.model.impl;
+
+import static org.junit.Assert.*;
+
+import java.util.Collections;
+
+import org.junit.Test;
+
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.model.TemplateHashModel;
+import org.apache.freemarker.core.model.TemplateMethodModelEx;
+import org.apache.freemarker.core.model.TemplateModelException;
+
+public class Java8DefaultObjectWrapperBridgeMethodsTest {
+    
+    @Test
+    public void testWithoutDefaultMethod() throws TemplateModelException {
+        test(BridgeMethodsBean.class);
+    }
+
+    @Test
+    public void testWithDefaultMethod() throws TemplateModelException {
+        test(Java8BridgeMethodsWithDefaultMethodBean.class);
+    }
+
+    @Test
+    public void testWithDefaultMethod2() throws TemplateModelException {
+        test(Java8BridgeMethodsWithDefaultMethodBean2.class);
+    }
+
+    private void test(Class<?> pClass) throws TemplateModelException {
+        DefaultObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
+        TemplateHashModel wrapped;
+        try {
+            wrapped = (TemplateHashModel) ow.wrap(pClass.newInstance());
+        } catch (Exception e) {
+            throw new IllegalStateException(e);
+        }
+        
+        TemplateMethodModelEx m1 = (TemplateMethodModelEx) wrapped.get("m1");
+        assertEquals(BridgeMethodsBean.M1_RETURN_VALUE, "" + m1.exec(Collections.emptyList()));
+        
+        TemplateMethodModelEx m2 = (TemplateMethodModelEx) wrapped.get("m2");
+        assertNull(m2.exec(Collections.emptyList()));
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperTest.java b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperTest.java
new file mode 100644
index 0000000..905d536
--- /dev/null
+++ b/freemarker-core-test-java8/src/test/java/org/apache/freemarker/core/model/impl/Java8DefaultObjectWrapperTest.java
@@ -0,0 +1,160 @@
+/*
+ * 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.model.impl;
+
+import static org.junit.Assert.*;
+
+import java.util.Collections;
+
+import org.junit.Test;
+
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.model.TemplateHashModel;
+import org.apache.freemarker.core.model.TemplateMethodModelEx;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateNumberModel;
+import org.apache.freemarker.core.model.TemplateScalarModel;
+import org.apache.freemarker.core.model.TemplateSequenceModel;
+
+public class Java8DefaultObjectWrapperTest {
+
+    @Test
+    public void testDefaultMethodRecognized() throws TemplateModelException {
+        DefaultObjectWrapper.Builder owb = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0);
+        DefaultObjectWrapper ow = owb.build();
+        TemplateHashModel wrappedBean = (TemplateHashModel) ow.wrap(new Java8DefaultMethodsBean());
+        
+        {
+            TemplateScalarModel prop = (TemplateScalarModel) wrappedBean.get(Java8DefaultMethodsBean.NORMAL_PROP);
+            assertNotNull(prop);
+            assertEquals(Java8DefaultMethodsBean.NORMAL_PROP_VALUE, prop.getAsString());
+        }
+        {
+            // This is overridden in the subclass, so it's visible even without default method support: 
+            TemplateScalarModel prop = (TemplateScalarModel) wrappedBean.get(
+                    Java8DefaultMethodsBean.DEFAULT_METHOD_PROP_2);
+            assertNotNull(prop);
+            assertEquals(Java8DefaultMethodsBean.PROP_2_OVERRIDE_VALUE, prop.getAsString());
+        }
+        {
+            TemplateScalarModel prop = (TemplateScalarModel) wrappedBean.get(
+                    Java8DefaultMethodsBeanBase.DEFAULT_METHOD_PROP);
+            assertNotNull(prop);
+            assertEquals(Java8DefaultMethodsBeanBase.DEFAULT_METHOD_PROP_VALUE, prop.getAsString());
+        }
+        {
+            // Has only indexed read method, so it's not exposed as a property
+            assertNull(wrappedBean.get(Java8DefaultMethodsBeanBase.DEFAULT_METHOD_INDEXED_PROP));
+
+            TemplateMethodModelEx indexedReadMethod = (TemplateMethodModelEx) wrappedBean.get(
+                    Java8DefaultMethodsBeanBase.DEFAULT_METHOD_INDEXED_PROP_GETTER);
+            assertNotNull(indexedReadMethod);
+            assertEquals(Java8DefaultMethodsBeanBase.DEFAULT_METHOD_INDEXED_PROP_VALUE,
+                    ((TemplateScalarModel) indexedReadMethod.exec(Collections.singletonList(new SimpleNumber(0))))
+                            .getAsString
+                            ());
+        }
+        {
+            // We see default method indexed read method, but it's invalidated by normal getter in the subclass
+            TemplateNumberModel prop = (TemplateNumberModel) wrappedBean.get(
+                    Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP);
+            assertNotNull(prop);
+            assertEquals(Java8DefaultMethodsBean.NOT_AN_INDEXED_PROP_VALUE, prop.getAsNumber());
+        }
+        {
+            // The default method read method invalidates the indexed read method in the subclass
+            TemplateScalarModel prop = (TemplateScalarModel) wrappedBean.get(
+                    Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP_2);
+            assertNotNull(prop);
+            assertEquals(Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP_2_VALUE, prop.getAsString());
+        }
+        {
+            // The default method read method invalidates the indexed read method in the subclass
+            TemplateSequenceModel prop = (TemplateSequenceModel) wrappedBean.get(
+                    Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP_3);
+            assertNotNull(prop);
+            assertEquals(Java8DefaultMethodsBean.DEFAULT_METHOD_NOT_AN_INDEXED_PROP_3_VALUE_0,
+                    ((TemplateScalarModel) prop.get(0)).getAsString());
+        }
+        {
+            // We see the default method indexed reader, which overrides the plain array reader in the subclass.
+            TemplateSequenceModel prop = (TemplateSequenceModel) wrappedBean.get(
+                    Java8DefaultMethodsBean.DEFAULT_METHOD_INDEXED_PROP_2);
+            assertNotNull(prop);
+            assertEquals(Java8DefaultMethodsBean.ARRAY_PROP_2_VALUE_0,
+                    ((TemplateScalarModel) prop.get(0)).getAsString());
+        }
+        {
+            // We do see the default method non-indexed reader, but the subclass has a matching indexed reader, so that
+            // takes over.
+            TemplateSequenceModel prop = (TemplateSequenceModel) wrappedBean.get(
+                    Java8DefaultMethodsBean.DEFAULT_METHOD_INDEXED_PROP_3);
+            assertNotNull(prop);
+            assertEquals(Java8DefaultMethodsBeanBase.DEFAULT_METHOD_INDEXED_PROP_3_VALUE_0,
+                    ((TemplateScalarModel) prop.get(0)).getAsString());
+        }        
+        {
+            // Only present in the subclass.
+
+            // Has only indexed read method, so it's not exposed as a property
+            assertNull(wrappedBean.get(Java8DefaultMethodsBean.INDEXED_PROP_4));
+
+            TemplateMethodModelEx indexedReadMethod = (TemplateMethodModelEx) wrappedBean.get(
+                    Java8DefaultMethodsBean.INDEXED_PROP_GETTER_4);
+            assertNotNull(indexedReadMethod);
+            assertEquals(Java8DefaultMethodsBean.INDEXED_PROP_4_VALUE,
+                    ((TemplateScalarModel) indexedReadMethod.exec(Collections.singletonList(new SimpleNumber(0))))
+                            .getAsString());
+        }        
+        {
+            TemplateMethodModelEx action = (TemplateMethodModelEx) wrappedBean.get(
+                    Java8DefaultMethodsBean.NORMAL_ACTION);
+            assertNotNull(action);
+            assertEquals(
+                    Java8DefaultMethodsBean.NORMAL_ACTION_RETURN_VALUE,
+                    ((TemplateScalarModel) action.exec(Collections.emptyList())).getAsString());
+        }
+        
+        {
+            TemplateMethodModelEx action = (TemplateMethodModelEx) wrappedBean.get(
+                    Java8DefaultMethodsBean.NORMAL_ACTION);
+            assertNotNull(action);
+            assertEquals(
+                    Java8DefaultMethodsBean.NORMAL_ACTION_RETURN_VALUE,
+                    ((TemplateScalarModel) action.exec(Collections.emptyList())).getAsString());
+        }
+        {
+            TemplateMethodModelEx action = (TemplateMethodModelEx) wrappedBean.get(
+                    Java8DefaultMethodsBean.DEFAULT_METHOD_ACTION);
+            assertNotNull(action);
+            assertEquals(
+                    Java8DefaultMethodsBean.DEFAULT_METHOD_ACTION_RETURN_VALUE,
+                    ((TemplateScalarModel) action.exec(Collections.emptyList())).getAsString());
+        }
+        {
+            TemplateMethodModelEx action = (TemplateMethodModelEx) wrappedBean.get(
+                    Java8DefaultMethodsBean.OVERRIDDEN_DEFAULT_METHOD_ACTION);
+            assertNotNull(action);
+            assertEquals(
+                    Java8DefaultMethodsBean.OVERRIDDEN_DEFAULT_METHOD_ACTION_RETURN_VALUE,
+                    ((TemplateScalarModel) action.exec(Collections.emptyList())).getAsString());
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/build.gradle
----------------------------------------------------------------------
diff --git a/freemarker-core-test/build.gradle b/freemarker-core-test/build.gradle
new file mode 100644
index 0000000..411f6ea
--- /dev/null
+++ b/freemarker-core-test/build.gradle
@@ -0,0 +1,19 @@
+description = """\
+The unit tests of freemarker-core. These tests used to be in freemarker-core, but to avoid depenency loop \
+through freemarker-test-utils, they had to be moved into a separate project."""
+
+dependencies {
+    compile project(":freemarker-core")
+    compile project(":freemarker-test-utils")
+}
+
+// We have nothing to put into the jar, as we have test classes only
+jar.enabled = false
+
+javadoc.enabled = false
+
+// Must not be deployed to a public Maven repository
+uploadArchives.enabled = false
+
+// Doesn't make sense to Maven "install" this, as the artifact won't contain test classes
+install.enabled = false

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/ASTBasedErrorMessagesTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/ASTBasedErrorMessagesTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ASTBasedErrorMessagesTest.java
new file mode 100644
index 0000000..10d63b3
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ASTBasedErrorMessagesTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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.Map;
+
+import org.apache.freemarker.test.TemplateTest;
+import org.junit.Test;
+
+public class ASTBasedErrorMessagesTest extends TemplateTest {
+    
+    @Test
+    public void testInvalidRefBasic() {
+        assertErrorContains("${foo}", "foo", "specify a default");
+        assertErrorContains("${map[foo]}", "foo", "\\!map[", "specify a default");
+    }
+    
+    @Test
+    public void testInvalidRefDollar() {
+        assertErrorContains("${$x}", "$x", "must not start with \"$\"", "specify a default");
+        assertErrorContains("${map.$x}", "map.$x", "must not start with \"$\"", "specify a default");
+    }
+
+    @Test
+    public void testInvalidRefAfterDot() {
+        assertErrorContains("${map.foo.bar}", "map.foo", "\\!foo.bar", "after the last dot", "specify a default");
+    }
+
+    @Test
+    public void testInvalidRefInSquareBrackets() {
+        assertErrorContains("${map['foo']}", "map", "final [] step", "specify a default");
+    }
+
+    @Test
+    public void testInvalidRefSize() {
+        assertErrorContains("${map.size()}", "map.size", "?size", "specify a default");
+        assertErrorContains("${map.length()}", "map.length", "?length", "specify a default");
+    }
+
+    @Override
+    protected Object createDataModel() {
+        Map<String, Object> dataModel = createCommonTestValuesDataModel();
+        dataModel.put("overloads", new Overloads());
+        return dataModel;
+    }
+    
+    public static class Overloads {
+        
+        @SuppressWarnings("unused")
+        public void m(String s) {}
+        
+        @SuppressWarnings("unused")
+        public void m(int i) {}
+        
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/ASTPrinter.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/ASTPrinter.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ASTPrinter.java
new file mode 100644
index 0000000..3518b29
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ASTPrinter.java
@@ -0,0 +1,438 @@
+/*
+ * 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.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.nio.ByteBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.CodingErrorAction;
+import java.nio.charset.StandardCharsets;
+import java.util.Enumeration;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.util.FTLUtil;
+import org.apache.freemarker.core.util._ClassUtil;
+import org.apache.freemarker.core.util._StringUtil;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+
+/**
+ * Static methods and command-line tool for printing the AST of a template. 
+ */
+public class ASTPrinter {
+
+    private final Configuration cfg;
+    private int successfulCounter;
+    private int failedCounter;
+    
+    static public void main(String[] args) throws IOException {
+        if (args.length == 0) {
+            usage();
+            System.exit(-1);
+        }
+        
+        ASTPrinter astp = new ASTPrinter(); 
+        if (args[0].equalsIgnoreCase("-r")) {
+            astp.mainRecursive(args);
+        } else {
+            astp.mainSingleTemplate(args);
+        }
+    }
+    
+    private ASTPrinter() {
+        cfg = new TestConfigurationBuilder(Configuration.VERSION_3_0_0).build();
+    }
+    
+    private void mainSingleTemplate(String[] args) throws IOException, FileNotFoundException {
+        final String templateFileName;
+        final String templateContent;
+        if (args[0].startsWith("ftl:")) {
+            templateFileName = null;
+            templateContent = args[0];
+        } else {
+            templateFileName = args[0];
+            templateContent = null;
+        }
+        
+        Template t = new Template(
+                templateFileName,
+                templateFileName == null ? new StringReader(templateContent) : new FileReader(templateFileName),
+                cfg);
+        
+        p(getASTAsString(t));
+    }
+
+    private void mainRecursive(String[] args) throws IOException {
+        if (args.length != 4) {
+            p("Number of arguments must be 4, but was: " + args.length);
+            usage();
+            System.exit(-1);
+        }
+        
+        final String srcDirPath = args[1].trim();
+        File srcDir = new File(srcDirPath);
+        if (!srcDir.isDirectory()) {
+            p("This should be an existing directory: " + srcDirPath);
+            System.exit(-1);
+        }
+        
+        Pattern fnPattern;
+        try {
+            fnPattern = Pattern.compile(args[2]);
+        } catch (PatternSyntaxException e) {
+            p(_StringUtil.jQuote(args[2]) + " is not a valid regular expression");
+            System.exit(-1);
+            return;
+        }
+        
+        final String dstDirPath = args[3].trim();
+        File dstDir = new File(dstDirPath);
+        if (!dstDir.isDirectory()) {
+            p("This should be an existing directory: " + dstDirPath);
+            System.exit(-1);
+        }
+        
+        long startTime = System.currentTimeMillis();
+        recurse(srcDir, fnPattern, dstDir);
+        long endTime = System.currentTimeMillis();
+        
+        p("Templates successfully processed " + successfulCounter + ", failed " + failedCounter
+                + ". Time taken: " + (endTime - startTime) / 1000.0 + " s");
+    }
+    
+    private void recurse(File srcDir, Pattern fnPattern, File dstDir) throws IOException {
+        File[] files = srcDir.listFiles();
+        if (files == null) {
+            throw new IOException("Failed to kust directory: " + srcDir);
+        }
+        for (File file : files) {
+            if (file.isDirectory()) {
+                recurse(file, fnPattern, new File(dstDir, file.getName()));
+            } else {
+                if (fnPattern.matcher(file.getName()).matches()) {
+                    File dstFile = new File(dstDir, file.getName());
+                    String res;
+                    try {
+                        Template t = new Template(file.getPath().replace('\\', '/'), loadIntoString(file), cfg);
+                        res = getASTAsString(t);
+                        successfulCounter++;
+                    } catch (ParseException e) {
+                        res = "<<<FAILED>>>\n" + e.getMessage();
+                        failedCounter++;
+                        p("");
+                        p("-------------------------failed-------------------------");
+                        p("Error message was saved into: " + dstFile.getAbsolutePath());
+                        p("");
+                        p(e.getMessage());
+                    }
+                    save(res, dstFile);
+                }
+            }
+        }
+    }
+
+    private String loadIntoString(File file) throws IOException {
+        long ln = file.length();
+        if (ln < 0) {
+            throw new IOException("Failed to get the length of " + file);
+        }
+        byte[] buffer = new byte[(int) ln];
+        InputStream in = new FileInputStream(file);
+        try {
+            int offset = 0;
+            int bytesRead;
+            while (offset < buffer.length) {
+                bytesRead = in.read(buffer, offset, buffer.length - offset);
+                if (bytesRead == -1) {
+                    throw new IOException("Unexpected end of file: " + file);
+                }
+                offset += bytesRead;
+            }
+        } finally {
+            in.close();
+        }
+        
+        try {
+            return decode(buffer, StandardCharsets.UTF_8);
+        } catch (CharacterCodingException e) {
+            return decode(buffer, StandardCharsets.ISO_8859_1);
+        }
+    }
+
+    private String decode(byte[] buffer, Charset charset) throws CharacterCodingException {
+        return charset.newDecoder()
+                .onMalformedInput(CodingErrorAction.REPORT).onUnmappableCharacter(CodingErrorAction.REPORT)
+                .decode(ByteBuffer.wrap(buffer)).toString();
+    }
+
+    private void save(String astStr, File file) throws IOException {
+        File parentDir = file.getParentFile();
+        if (!parentDir.isDirectory() && !parentDir.mkdirs()) {
+            throw new IOException("Failed to invoke parent directory: " + parentDir);
+        }
+        
+        Writer w = new BufferedWriter(new FileWriter(file));
+        try {
+            w.write(astStr);
+        } finally {
+            w.close();
+        }
+    }
+
+    private static void usage() {
+        p("Prints template Abstract Syntax Tree (AST) as plain text.");
+        p("Usage:");
+        p("    java org.apache.freemarker.core.PrintAST <templateFile>");
+        p("    java org.apache.freemarker.core.PrintAST ftl:<templateSource>");
+        p("    java org.apache.freemarker.core.PrintAST -r <src-directory> <regexp> <dst-directory>");
+    }
+
+    private static final String INDENTATION = "    ";
+
+    public static String getASTAsString(String ftl) throws IOException {
+        return getASTAsString(ftl, (Options) null);
+    }
+    
+    public static String getASTAsString(String ftl, Options opts) throws IOException {
+        return getASTAsString(null, ftl, opts);
+    }
+
+    public static String getASTAsString(String templateName, String ftl) throws IOException {
+        return getASTAsString(templateName, ftl, null);
+    }
+    
+    public static String getASTAsString(String templateName, String ftl, Options opts) throws IOException {
+        Template t = new Template(templateName, ftl, new TestConfigurationBuilder().build());
+        return getASTAsString(t, opts);
+    }
+
+    public static String getASTAsString(Template t) throws IOException {
+        return getASTAsString(t, null);
+    }
+
+    public static String getASTAsString(Template t, Options opts) throws IOException {
+        validateAST(t);
+        
+        StringWriter out = new StringWriter();
+        printNode(t.getRootASTNode(), "", null, opts != null ? opts : Options.DEFAULT_INSTANCE, out);
+        return out.toString();
+    }
+    
+    public static void validateAST(Template t) throws InvalidASTException {
+        final ASTElement node = t.getRootASTNode();
+        if (node.getParent() != null) {
+            throw new InvalidASTException("Root node parent must be null."
+                    + "\nRoot node: " + node.dump(false)
+                    + "\nParent"
+                    + ": " + node.getParent().getClass() + ", " + node.getParent().dump(false));
+        }
+        validateAST(node);
+    }
+
+    private static void validateAST(ASTElement te) {
+        int childCount = te.getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            ASTElement child = te.getChild(i);
+            ASTElement parentElement = child.getParent();
+            // As ASTImplicitParent.accept does nothing but returns its children, it's optimized out in the final
+            // AST tree. While it will be present as a child, the parent element also will have children
+            // that contains the children of the ASTImplicitParent directly. 
+            if (parentElement instanceof ASTImplicitParent && parentElement.getParent() != null) {
+                parentElement = parentElement.getParent();
+            }
+            if (parentElement != te) {
+                throw new InvalidASTException("Wrong parent node."
+                        + "\nNode: " + child.dump(false)
+                        + "\nExpected parent: " + te.dump(false)
+                        + "\nActual parent: " + parentElement.dump(false));
+            }
+            if (child.getIndex() != i) {
+                throw new InvalidASTException("Wrong node index."
+                        + "\nNode: " + child.dump(false)
+                        + "\nExpected index: " + i
+                        + "\nActual index: " + child.getIndex());
+            }
+        }
+        if (te instanceof ASTImplicitParent && te.getChildCount() < 2) {
+            throw new InvalidASTException("Mixed content with child count less than 2 should removed by optimizatoin, "
+                    + "but found one with " + te.getChildCount() + " child(ren).");
+        }
+        ASTElement[] children = te.getChildBuffer();
+        if (children != null) {
+            if (childCount == 0) {
+                throw new InvalidASTException(
+                        "Children must be null when childCount is 0."
+                        + "\nNode: " + te.dump(false));
+            }
+            for (int i = 0; i < te.getChildCount(); i++) {
+                if (children[i] == null) {
+                    throw new InvalidASTException(
+                            "Child can't be null at index " + i
+                            + "\nNode: " + te.dump(false));
+                }
+            }
+            for (int i = te.getChildCount(); i < children.length; i++) {
+                if (children[i] != null) {
+                    throw new InvalidASTException(
+                            "Children can't be non-null at index " + i
+                            + "\nNode: " + te.dump(false));
+                }
+            }
+        } else {
+            if (childCount != 0) {
+                throw new InvalidASTException(
+                        "Children mustn't be null when child count isn't 0."
+                        + "\nNode: " + te.dump(false));
+            }
+        }
+    }
+
+    private static void printNode(Object node, String ind, ParameterRole paramRole, Options opts, Writer out) throws IOException {
+        if (node instanceof ASTNode) {
+            ASTNode tObj = (ASTNode) node;
+
+            printNodeLineStart(paramRole, ind, out);
+            out.write(tObj.getNodeTypeSymbol());
+            printNodeLineEnd(node, out, opts);
+            
+            if (opts.getShowConstantValue() && node instanceof ASTExpression) {
+                TemplateModel tm = ((ASTExpression) node).constantValue;
+                if (tm != null) {
+                    out.write(INDENTATION);
+                    out.write(ind);
+                    out.write("= const ");
+                    out.write(FTLUtil.getTypeDescription(tm));
+                    out.write(' ');
+                    out.write(tm.toString());
+                    out.write('\n');
+                }
+            }
+            
+            int paramCnt = tObj.getParameterCount();
+            for (int i = 0; i < paramCnt; i++) {
+                ParameterRole role = tObj.getParameterRole(i);
+                if (role == null) throw new NullPointerException("parameter role");
+                Object value = tObj.getParameterValue(i);
+                printNode(value, ind + INDENTATION, role, opts, out);
+            }
+            if (tObj instanceof ASTElement) {
+                Enumeration enu = ((ASTElement) tObj).children();
+                while (enu.hasMoreElements()) {
+                    printNode(enu.nextElement(), INDENTATION + ind, null, opts, out);
+                }
+            }
+        } else {
+            printNodeLineStart(paramRole, ind, out);
+            out.write(_StringUtil.jQuote(node));
+            printNodeLineEnd(node, out, opts);
+        }
+    }
+
+    protected static void printNodeLineEnd(Object node, Writer out, Options opts) throws IOException {
+        boolean commentStared = false;
+        if (opts.getShowJavaClass()) {
+            out.write("  // ");
+            commentStared = true;
+            out.write(_ClassUtil.getShortClassNameOfObject(node, true));
+        }
+        if (opts.getShowLocation() && node instanceof ASTNode) {
+            if (!commentStared) {
+                out.write("  // ");
+                commentStared = true;
+            } else {
+                out.write("; ");
+            }
+            ASTNode tObj = (ASTNode) node;
+            out.write("Location " + tObj.beginLine + ":" + tObj.beginColumn + "-" + tObj.endLine + ":" + tObj.endColumn);
+        }
+        out.write('\n');
+    }
+
+    private static void printNodeLineStart(ParameterRole paramRole, String ind, Writer out) throws IOException {
+        out.write(ind);
+        if (paramRole != null) {
+            out.write("- ");
+            out.write(paramRole.toString());
+            out.write(": ");
+        }
+    }
+    
+    public static class Options {
+        
+        private final static Options DEFAULT_INSTANCE = new Options(); 
+        
+        private boolean showJavaClass = true;
+        private boolean showConstantValue = false;
+        private boolean showLocation = false;
+        
+        public boolean getShowJavaClass() {
+            return showJavaClass;
+        }
+        
+        public void setShowJavaClass(boolean showJavaClass) {
+            this.showJavaClass = showJavaClass;
+        }
+        
+        public boolean getShowConstantValue() {
+            return showConstantValue;
+        }
+        
+        public void setShowConstantValue(boolean showConstantValue) {
+            this.showConstantValue = showConstantValue;
+        }
+
+        public boolean getShowLocation() {
+            return showLocation;
+        }
+
+        public void setShowLocation(boolean showLocation) {
+            this.showLocation = showLocation;
+        }
+        
+    }
+    
+    private static void p(Object obj) {
+        System.out.println(obj);
+    }
+
+    public static class InvalidASTException extends RuntimeException {
+
+        public InvalidASTException(String message, Throwable cause) {
+            super(message, cause);
+        }
+
+        public InvalidASTException(String message) {
+            super(message);
+        }
+        
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/ASTTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/ASTTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ASTTest.java
new file mode 100644
index 0000000..7379e28
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ASTTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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.FileNotFoundException;
+import java.io.IOException;
+
+import org.apache.freemarker.core.ASTPrinter.Options;
+import org.apache.freemarker.core.util._StringUtil;
+import org.apache.freemarker.test.TestUtil;
+import org.apache.freemarker.test.FileTestCase;
+
+public class ASTTest extends FileTestCase {
+
+    public ASTTest(String name) {
+        super(name);
+    }
+    
+    public void test1() throws Exception {
+        testAST("ast-1");
+    }
+
+    public void testRange() throws Exception {
+        testAST("ast-range");
+    }
+    
+    public void testAssignments() throws Exception {
+        testAST("ast-assignments");
+    }
+    
+    public void testBuiltins() throws Exception {
+        testAST("ast-builtins");
+    }
+    
+    public void testStringLiteralInterpolation() throws Exception {
+        testAST("ast-strlitinterpolation");
+    }
+    
+    public void testWhitespaceStripping() throws Exception {
+        testAST("ast-whitespacestripping");
+    }
+
+    public void testMixedContentSimplifications() throws Exception {
+        testAST("ast-mixedcontentsimplifications");
+    }
+
+    public void testMultipleIgnoredChildren() throws Exception {
+        testAST("ast-multipleignoredchildren");
+    }
+    
+    public void testNestedIgnoredChildren() throws Exception {
+        testAST("ast-nestedignoredchildren");
+    }
+
+    public void testLocations() throws Exception {
+        testASTWithLocations("ast-locations");
+    }
+    
+    private void testAST(String testName) throws FileNotFoundException, IOException {
+        testAST(testName, null);
+    }
+
+    private void testASTWithLocations(String testName) throws FileNotFoundException, IOException {
+        Options options = new Options();
+        options.setShowLocation(true);
+        testAST(testName, options);
+    }
+
+    private void testAST(String testName, Options ops) throws FileNotFoundException, IOException {
+        final String templateName = testName + ".ftl";
+        assertExpectedFileEqualsString(
+                testName + ".ast",
+                ASTPrinter.getASTAsString(templateName,
+                        TestUtil.removeFTLCopyrightComment(
+                                normalizeLineBreaks(
+                                        loadTestTextResource(
+                                                getTestFileURL(
+                                                        getExpectedContentFileDirectoryResourcePath(), templateName)))
+                        ), ops));
+    }
+    
+    private String normalizeLineBreaks(final String s) throws FileNotFoundException, IOException {
+        return _StringUtil.replace(s, "\r\n", "\n").replace('\r', '\n');
+    }
+    
+}



[40/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/ErrorMessagesTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/ErrorMessagesTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/ErrorMessagesTest.java
new file mode 100644
index 0000000..4306a50
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/ErrorMessagesTest.java
@@ -0,0 +1,170 @@
+/*
+ * 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.model.impl;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.util.Collections;
+import java.util.Date;
+
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.model.TemplateHashModel;
+import org.apache.freemarker.core.model.TemplateMethodModelEx;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateScalarModel;
+import org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat;
+import org.apache.freemarker.core.outputformat.impl.TemplateHTMLOutputModel;
+import org.junit.Test;
+
+public class ErrorMessagesTest {
+
+    @Test
+    public void getterMessage() throws TemplateModelException {
+        DefaultObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
+        TemplateHashModel thm= (TemplateHashModel) ow.wrap(new TestBean());
+        
+        try {
+            thm.get("foo");
+        } catch (TemplateModelException e) {
+            e.printStackTrace();
+            final String msg = e.getMessage();
+            assertThat(msg, containsString("\"foo\""));
+            assertThat(msg, containsString("existing sub-variable"));
+        }
+        assertNull(thm.get("bar"));
+    }
+    
+    @Test
+    public void markupOutputParameter() throws Exception {
+        TemplateHTMLOutputModel html = HTMLOutputFormat.INSTANCE.fromMarkup("<p>a");
+
+        DefaultObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
+        TemplateHashModel thm = (TemplateHashModel) ow.wrap(new TestBean());
+        
+        {
+            TemplateMethodModelEx m = (TemplateMethodModelEx) thm.get("m1");
+            try {
+                m.exec(Collections.singletonList(html));
+                fail();
+            } catch (TemplateModelException e) {
+                assertThat(e.getMessage(), allOf(
+                        containsString("String"), containsString("convert"), containsString("markup_output"),
+                        containsString("Tip:"), containsString("?markup_string")));
+            }
+        }
+        
+        {
+            TemplateMethodModelEx m = (TemplateMethodModelEx) thm.get("m2");
+            try {
+                m.exec(Collections.singletonList(html));
+                fail();
+            } catch (TemplateModelException e) {
+                assertThat(e.getMessage(), allOf(
+                        containsString("Date"), containsString("convert"), containsString("markup_output"),
+                        not(containsString("?markup_string"))));
+            }
+        }
+        
+        for (String methodName : new String[] { "mOverloaded", "mOverloaded3" }) {
+            TemplateMethodModelEx m = (TemplateMethodModelEx) thm.get(methodName);
+            try {
+                m.exec(Collections.singletonList(html));
+                fail();
+            } catch (TemplateModelException e) {
+                assertThat(e.getMessage(), allOf(
+                        containsString("No compatible overloaded"),
+                        containsString("String"), containsString("markup_output"),
+                        containsString("Tip:"), containsString("?markup_string")));
+            }
+        }
+        
+        {
+            TemplateMethodModelEx m = (TemplateMethodModelEx) thm.get("mOverloaded2");
+            try {
+                m.exec(Collections.singletonList(html));
+                fail();
+            } catch (TemplateModelException e) {
+                assertThat(e.getMessage(), allOf(
+                        containsString("No compatible overloaded"),
+                        containsString("Integer"), containsString("markup_output"),
+                        not(containsString("?markup_string"))));
+            }
+        }
+        
+        {
+            TemplateMethodModelEx m = (TemplateMethodModelEx) thm.get("mOverloaded4");
+            Object r = m.exec(Collections.singletonList(html));
+            if (r instanceof TemplateScalarModel) {
+                r = ((TemplateScalarModel) r).getAsString();
+            }
+            assertEquals("<p>a", r);
+        }
+    }
+    
+    public static class TestBean {
+        
+        public String getFoo() {
+            throw new RuntimeException("Dummy");
+        }
+        
+        public void m1(String s) {
+            // nop
+        }
+
+        public void m2(Date s) {
+            // nop
+        }
+
+        public void mOverloaded(String s) {
+            // nop
+        }
+
+        public void mOverloaded(Date d) {
+            // nop
+        }
+
+        public void mOverloaded2(Integer n) {
+            // nop
+        }
+
+        public void mOverloaded2(Date d) {
+            // nop
+        }
+
+        public void mOverloaded3(String... s) {
+            // nop
+        }
+
+        public void mOverloaded3(Date d) {
+            // nop
+        }
+        
+        public String mOverloaded4(String s) {
+            return s;
+        }
+
+        public String mOverloaded4(TemplateHTMLOutputModel s) throws TemplateModelException {
+            return s.getOutputFormat().getMarkupString(s);
+        }
+        
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/FineTuneMethodAppearanceTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/FineTuneMethodAppearanceTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/FineTuneMethodAppearanceTest.java
new file mode 100644
index 0000000..92f59fb
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/FineTuneMethodAppearanceTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.model.impl;
+
+import static org.junit.Assert.*;
+
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.model.TemplateHashModel;
+import org.apache.freemarker.core.model.TemplateMethodModelEx;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateScalarModel;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class FineTuneMethodAppearanceTest {
+
+    @Test
+    public void newWayOfConfiguring() throws TemplateModelException {
+        DefaultObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0)
+                .methodAppearanceFineTuner(GetlessMethodsAsPropertyGettersRule.INSTANCE)
+                .exposeFields(true)
+                .build();
+        checkIfProperlyWrapped(ow.wrap(new C()));
+    }
+    
+    private void checkIfProperlyWrapped(TemplateModel tm) throws TemplateModelException {
+        TemplateHashModel thm = (TemplateHashModel) tm;
+        assertEquals("v1", ((TemplateScalarModel) thm.get("v1")).getAsString());
+        assertEquals("v2()", ((TemplateScalarModel) thm.get("v2")).getAsString());
+        assertEquals("getV3()", ((TemplateScalarModel) thm.get("v3")).getAsString());
+        assertTrue(thm.get("getV3") instanceof TemplateMethodModelEx);
+    }
+    
+    static public class C {
+        
+        public String v1 = "v1";
+
+        public String v2 = "v2";
+        public String v2() { return "v2()"; }
+        
+        public String v3() { return "v3()"; }
+        public String getV3() { return "getV3()"; }
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/GetlessMethodsAsPropertyGettersRule.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/GetlessMethodsAsPropertyGettersRule.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/GetlessMethodsAsPropertyGettersRule.java
new file mode 100644
index 0000000..716f863
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/GetlessMethodsAsPropertyGettersRule.java
@@ -0,0 +1,67 @@
+/*
+ * 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.model.impl;
+
+import java.beans.IntrospectionException;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Method;
+
+class GetlessMethodsAsPropertyGettersRule implements MethodAppearanceFineTuner, SingletonCustomizer {
+    
+    static final GetlessMethodsAsPropertyGettersRule INSTANCE = new GetlessMethodsAsPropertyGettersRule();
+    
+    // Can't be constructed from outside
+    private GetlessMethodsAsPropertyGettersRule() { }
+
+    @Override
+    public void process(
+            DecisionInput in, Decision out) {
+        legacyProcess(in.getContainingClass(), in.getMethod(), out);
+    }
+
+    /** This only exists as the tests need to call this through the deprecated method too. */
+    public void legacyProcess(
+            Class clazz, Method m, Decision decision) {
+        if (m.getDeclaringClass() != Object.class
+                && m.getReturnType() != void.class
+                && m.getParameterTypes().length == 0) {
+            String mName = m.getName();
+            if (!looksLikePropertyReadMethod(mName)) {
+                decision.setExposeMethodAs(null);
+                try {
+                    decision.setExposeAsProperty(new PropertyDescriptor(
+                            mName, clazz, mName, null));
+                } catch (IntrospectionException e) {  // Won't happen...
+                    throw new RuntimeException(e); 
+                }
+            }
+        }
+    }
+    
+    private static boolean looksLikePropertyReadMethod(String name) {
+        final int verbEnd;
+        if (name.startsWith("get")) verbEnd = 3;
+        else if (name.startsWith("is")) verbEnd = 2;
+        else return false;
+        
+        return name.length() == verbEnd || Character.isUpperCase(name.charAt(verbEnd));
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/IsApplicableTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/IsApplicableTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/IsApplicableTest.java
new file mode 100644
index 0000000..599e6f2
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/IsApplicableTest.java
@@ -0,0 +1,171 @@
+/*
+ * 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.model.impl;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+@SuppressWarnings("boxing")
+public class IsApplicableTest extends TestCase {
+
+    public IsApplicableTest(String name) {
+        super(name);
+    }
+    
+    public void testSingle() {
+        ArgumentTypes ats = new ArgumentTypes(new Object[] { new Object() });
+        assertApplicable(ats, Object.class);
+        assertNotApplicable(ats, String.class);
+        assertNotApplicable(ats, CharSequence.class);
+        assertNotApplicable(ats, Integer.class);
+        assertNotApplicable(ats, Integer.TYPE);
+        
+        ats = new ArgumentTypes(new Object[] { "" });
+        assertApplicable(ats, Object.class);
+        assertApplicable(ats, CharSequence.class);
+        assertApplicable(ats, String.class);
+        assertNotApplicable(ats, Integer.class);
+        assertNotApplicable(ats, Integer.TYPE);
+
+        ats = new ArgumentTypes(new Object[] { 1 });
+        assertApplicable(ats, Object.class);
+        assertNotApplicable(ats, CharSequence.class);
+        assertNotApplicable(ats, String.class);
+        assertNotApplicable(ats, Short.class);
+        assertNotApplicable(ats, Short.TYPE);
+        assertApplicable(ats, Integer.class);
+        assertApplicable(ats, Integer.TYPE);
+        assertApplicable(ats, Float.class);
+        assertApplicable(ats, Float.TYPE);
+        assertApplicable(ats, Double.class);
+        assertApplicable(ats, Double.TYPE);
+        assertApplicable(ats, BigDecimal.class);
+        assertApplicable(ats, BigInteger.class);
+
+        ats = new ArgumentTypes(new Object[] { new OverloadedNumberUtil.IntegerOrByte(1, (byte) 1) });
+        assertApplicable(ats, Object.class);
+        assertNotApplicable(ats, CharSequence.class);
+        assertNotApplicable(ats, String.class);
+        assertApplicable(ats, Short.class);
+        assertApplicable(ats, Short.TYPE);
+        assertApplicable(ats, Integer.class);
+        assertApplicable(ats, Integer.TYPE);
+        assertApplicable(ats, Float.class);
+        assertApplicable(ats, Float.TYPE);
+        assertApplicable(ats, Double.class);
+        assertApplicable(ats, Double.TYPE);
+        assertApplicable(ats, BigDecimal.class);
+        assertApplicable(ats, BigInteger.class);
+        
+        ats = new ArgumentTypes(new Object[] { 1.0f });
+        assertApplicable(ats, Object.class);
+        assertNotApplicable(ats, CharSequence.class);
+        assertNotApplicable(ats, String.class);
+        assertNotApplicable(ats, Integer.class);
+        assertNotApplicable(ats, Integer.TYPE);
+        assertApplicable(ats, Float.class);
+        assertApplicable(ats, Float.TYPE);
+        assertApplicable(ats, Double.class);
+        assertApplicable(ats, Double.TYPE);
+        assertApplicable(ats, BigDecimal.class);
+        assertNotApplicable(ats, BigInteger.class);
+        
+        ats = new ArgumentTypes(new Object[] { null });
+        assertApplicable(ats, Object.class);
+        assertApplicable(ats, String.class);
+        assertApplicable(ats, Integer.class);
+        assertNotApplicable(ats, Integer.TYPE);
+        assertNotApplicable(ats, Boolean.TYPE);
+        assertNotApplicable(ats, Object.class, Object.class);
+        assertNotApplicable(ats);
+    }
+    
+    public void testMulti() {
+        ArgumentTypes ats = new ArgumentTypes(new Object[] { new Object(), "", 1, true });
+        assertApplicable(ats, Object.class, Object.class, Object.class, Object.class);
+        assertApplicable(ats, Object.class, String.class, Number.class, Boolean.class);
+        assertApplicable(ats, Object.class, CharSequence.class, Integer.class, Serializable.class);
+        assertApplicable(ats, Object.class, Comparable.class, Integer.TYPE, Serializable.class);
+        assertNotApplicable(ats, Object.class, String.class, Number.class, Number.class);
+        assertNotApplicable(ats, Object.class, StringBuilder.class, Number.class, Boolean.class);
+        assertNotApplicable(ats, int.class, Object.class, Object.class, Object.class);
+        assertNotApplicable(ats, Object.class, Object.class, Object.class);
+        assertNotApplicable(ats, Object.class, Object.class, Object.class, Object.class, Object.class);
+    }    
+
+    public void testNoParam() {
+        ArgumentTypes ats = new ArgumentTypes(new Object[] { });
+        assertApplicable(ats);
+        assertNotApplicable(ats, Object.class);
+    }
+
+    public void testVarags() {
+        Object[][] argLists = new Object[][] {
+            new Object[] { "", 1, 2, 3 },
+            new Object[] { "", 1, (byte) 2, 3 },
+            new Object[] { "", 1},
+            new Object[] { "" },
+        };
+        for (Object[] args : argLists) {
+            ArgumentTypes ats = new ArgumentTypes(args);
+            assertApplicable(ats, true, String.class, int[].class);
+            assertApplicable(ats, true, String.class, Integer[].class);
+            assertApplicable(ats, true, Object.class, Comparable[].class);
+            assertApplicable(ats, true, Object.class, Object[].class);
+            assertNotApplicable(ats, true, StringBuilder.class, int[].class);
+            if (args.length > 1) {
+                assertNotApplicable(ats, true, String.class, String[].class);
+            } else {
+                assertApplicable(ats, true, String.class, String[].class);
+            }
+        }
+    }
+    
+    private void assertNotApplicable(ArgumentTypes ats, Class... paramTypes) {
+        assertNotApplicable(ats, false, paramTypes);
+    }
+    
+    private void assertNotApplicable(ArgumentTypes ats, boolean varargs, Class... paramTypes) {
+        List tested = new ArrayList();
+        tested.add(new ReflectionCallableMemberDescriptor((Method) null, paramTypes));
+        if (ats.getApplicables(tested, varargs).size() != 0) {
+            fail("Parameter types were applicable");
+        }
+    }
+
+    private void assertApplicable(ArgumentTypes ats, Class<?>... paramTypes) {
+        assertApplicable(ats, false, paramTypes);
+    }
+    
+    private void assertApplicable(ArgumentTypes ats, boolean varargs, Class<?>... paramTypes) {
+        List tested = new ArrayList();
+        tested.add(new ReflectionCallableMemberDescriptor((Method) null, paramTypes));
+        if (ats.getApplicables(tested, varargs).size() != 1) {
+            fail("Parameter types weren't applicable");
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/IsMoreSpecificParameterTypeTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/IsMoreSpecificParameterTypeTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/IsMoreSpecificParameterTypeTest.java
new file mode 100644
index 0000000..3de3f13
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/IsMoreSpecificParameterTypeTest.java
@@ -0,0 +1,98 @@
+/*
+ * 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.model.impl;
+
+import java.math.BigDecimal;
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+public class IsMoreSpecificParameterTypeTest extends TestCase {
+
+    public IsMoreSpecificParameterTypeTest(String name) {
+        super(name);
+    }
+    
+    public void testFixed() {
+        assertEquals(1, _MethodUtil.isMoreOrSameSpecificParameterType(String.class, String.class, true, 0));
+        assertEquals(1, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, int.class, true, 0));
+        
+        assertEquals(2, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, Integer.class, true, 0));
+        assertEquals(2, _MethodUtil.isMoreOrSameSpecificParameterType(boolean.class, Boolean.class, true, 0));
+        
+        assertEquals(3, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, long.class, true, 0));
+        assertEquals(3, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, double.class, true, 0));
+        assertEquals(3, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, Long.class, true, 0));
+        assertEquals(3, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, Double.class, true, 0));
+        assertEquals(3, _MethodUtil.isMoreOrSameSpecificParameterType(Integer.class, Long.class, true, 0));
+        assertEquals(3, _MethodUtil.isMoreOrSameSpecificParameterType(Integer.class, Double.class, true, 0));
+
+        assertEquals(4, _MethodUtil.isMoreOrSameSpecificParameterType(HashMap.class, Map.class, true, 0));
+        assertEquals(4, _MethodUtil.isMoreOrSameSpecificParameterType(String.class, CharSequence.class, true, 0));
+        assertEquals(4, _MethodUtil.isMoreOrSameSpecificParameterType(Integer.class, Number.class, true, 0));
+        assertEquals(4, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, Number.class, true, 0));
+        
+        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(Map.class, String.class, true, 0));
+        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(Integer.class, int.class, true, 0));
+        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(Boolean.class, boolean.class, true, 0));
+        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, boolean.class, true, 0));
+        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, Boolean.class, true, 0));
+        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, String.class, true, 0));
+        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, BigDecimal.class, true, 0));
+        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(Long.class, Integer.class, true, 0));
+        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(long.class, Integer.class, true, 0));
+        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(Long.class, int.class, true, 0));
+        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(Integer.class, BigDecimal.class, true, 0));
+    }
+    
+    public void testBuggy() {
+        assertEquals(1, _MethodUtil.isMoreOrSameSpecificParameterType(String.class, String.class, false, 0));
+        assertEquals(1, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, int.class, false, 0));
+        
+        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, Integer.class, false, 0));
+        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(boolean.class, Boolean.class, false, 0));
+        
+        assertEquals(3, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, long.class, false, 0));
+        assertEquals(3, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, double.class, false, 0));
+        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, Long.class, false, 0));
+        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, Double.class, false, 0));
+        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(Integer.class, Long.class, false, 0));
+        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(Integer.class, Double.class, false, 0));
+
+        assertEquals(4, _MethodUtil.isMoreOrSameSpecificParameterType(HashMap.class, Map.class, false, 0));
+        assertEquals(4, _MethodUtil.isMoreOrSameSpecificParameterType(String.class, CharSequence.class, false, 0));
+        assertEquals(4, _MethodUtil.isMoreOrSameSpecificParameterType(Integer.class, Number.class, false, 0));
+        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, Number.class, false, 0));
+        
+        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(Map.class, String.class, true, 0));
+        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(Integer.class, int.class, true, 0));
+        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(Boolean.class, boolean.class, true, 0));
+        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, boolean.class, true, 0));
+        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, Boolean.class, true, 0));
+        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, String.class, true, 0));
+        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, BigDecimal.class, true, 0));
+        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(Long.class, Integer.class, true, 0));
+        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(long.class, Integer.class, true, 0));
+        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(Long.class, int.class, true, 0));
+        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(Integer.class, BigDecimal.class, true, 0));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/Java7MembersOnlyDefaultObjectWrapper.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/Java7MembersOnlyDefaultObjectWrapper.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/Java7MembersOnlyDefaultObjectWrapper.java
new file mode 100644
index 0000000..96c1adf
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/Java7MembersOnlyDefaultObjectWrapper.java
@@ -0,0 +1,101 @@
+/*
+ * 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.model.impl;
+
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.Version;
+
+/**
+ * A hack to keep some unit tests producing exactly the same results on Java 8 as on Java 5-7, by hiding members
+ * added after Java 7.
+ */
+public class Java7MembersOnlyDefaultObjectWrapper extends DefaultObjectWrapper {
+    
+    private static final Set<String> POST_JAVA_7_MAP_METHODS = newHashSet(
+            "compute", "computeIfAbsent", "computeIfPresent",
+            "forEach", "getOrDefault", "merge", "putIfAbsent", "replace", "replaceAll");
+
+    private static final Set<String> POST_JAVA_7_ITERABLE_METHODS = newHashSet("forEach");
+    private static final Set<String> POST_JAVA_7_COLLECTION_METHODS = newHashSet("parallelStream", "removeIf", "stream");
+    private static final Set<String> POST_JAVA_7_LIST_METHODS = newHashSet("sort", "spliterator");
+    
+    static final MethodAppearanceFineTuner POST_JAVA_7_FILTER = new MethodAppearanceFineTuner() {
+
+        @Override
+        public void process(DecisionInput in, Decision out) {
+            Method m = in.getMethod();
+            Class declCl = m.getDeclaringClass();
+            if (Map.class.isAssignableFrom(declCl)) {
+                if (POST_JAVA_7_MAP_METHODS.contains(m.getName())) {
+                    hideMember(out);
+                    return;
+                }
+            }
+            if (Iterable.class.isAssignableFrom(declCl)) {
+                if (POST_JAVA_7_ITERABLE_METHODS.contains(m.getName())) {
+                    hideMember(out);
+                    return;
+                }
+            }
+            if (Collection.class.isAssignableFrom(declCl)) {
+                if (POST_JAVA_7_COLLECTION_METHODS.contains(m.getName())) {
+                    hideMember(out);
+                    return;
+                }
+            }
+            if (List.class.isAssignableFrom(declCl)) {
+                if (POST_JAVA_7_LIST_METHODS.contains(m.getName())) {
+                    hideMember(out);
+                    return;
+                }
+            }
+        }
+
+        private void hideMember(Decision out) {
+            out.setExposeMethodAs(null);
+            out.setExposeAsProperty(null);
+        }
+        
+    };
+    
+    public Java7MembersOnlyDefaultObjectWrapper(Version version) {
+        super(new DefaultObjectWrapper.Builder(version).methodAppearanceFineTuner(POST_JAVA_7_FILTER), true);
+    }
+
+    private static <T> Set<T> newHashSet(T... items) {
+        HashSet<T> r = new HashSet<>();
+        for (T item : items) {
+            r.add(item);
+        }
+        return r;
+    }
+
+    public Java7MembersOnlyDefaultObjectWrapper() {
+        this(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/ManyObjectsOfDifferentClasses.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/ManyObjectsOfDifferentClasses.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/ManyObjectsOfDifferentClasses.java
new file mode 100644
index 0000000..fa7ce29
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/ManyObjectsOfDifferentClasses.java
@@ -0,0 +1,249 @@
+/*
+ * 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.model.impl;
+
+// FMPP template source:
+// ----
+// package org.apache.freemarker.core.model.impl;
+// 
+// // FMPP template source:
+// // ----
+// <#assign src><#include "ManyObjectsOfDifferentClasses.java.ftl" parse=false></#assign>
+// ${src?trim?replace('(.*\r?\n)|.+', r'// $0', 'r')}
+// // ----
+// 
+// <#assign MAX_CLA = 8 - 1>
+// <#assign MAX_MET = 10 - 1>
+// <#assign MAX_PRO = 10 - 1>
+// 
+// public class ManyObjectsOfDifferentClasses {
+// 
+//     public static final Object[] OBJECTS = new Object[] {
+//         <#list 0..MAX_CLA as claI>
+//         new C${claI}(),
+//         </#list>
+//     };
+// 
+//     <#list 0..MAX_CLA as claI>
+//     static public class C${claI} {
+//         <#list 0..MAX_PRO as proI>
+//         public int getP${proI}() { return ${claI} * 1000 + ${proI}; }
+//         </#list>
+//         <#list 0..MAX_MET as metI>
+//         public int m${metI}() { return ${claI} * 1000 + ${metI}; };
+//         </#list>
+//     }
+//     </#list>
+//     
+// }
+// ----
+
+
+public class ManyObjectsOfDifferentClasses {
+
+    public static final Object[] OBJECTS = new Object[] {
+        new C0(),
+        new C1(),
+        new C2(),
+        new C3(),
+        new C4(),
+        new C5(),
+        new C6(),
+        new C7(),
+    };
+
+    static public class C0 {
+        public int getP0() { return 0 * 1000 + 0; }
+        public int getP1() { return 0 * 1000 + 1; }
+        public int getP2() { return 0 * 1000 + 2; }
+        public int getP3() { return 0 * 1000 + 3; }
+        public int getP4() { return 0 * 1000 + 4; }
+        public int getP5() { return 0 * 1000 + 5; }
+        public int getP6() { return 0 * 1000 + 6; }
+        public int getP7() { return 0 * 1000 + 7; }
+        public int getP8() { return 0 * 1000 + 8; }
+        public int getP9() { return 0 * 1000 + 9; }
+        public int m0() { return 0 * 1000 + 0; };
+        public int m1() { return 0 * 1000 + 1; };
+        public int m2() { return 0 * 1000 + 2; };
+        public int m3() { return 0 * 1000 + 3; };
+        public int m4() { return 0 * 1000 + 4; };
+        public int m5() { return 0 * 1000 + 5; };
+        public int m6() { return 0 * 1000 + 6; };
+        public int m7() { return 0 * 1000 + 7; };
+        public int m8() { return 0 * 1000 + 8; };
+        public int m9() { return 0 * 1000 + 9; };
+    }
+    static public class C1 {
+        public int getP0() { return 1 * 1000 + 0; }
+        public int getP1() { return 1 * 1000 + 1; }
+        public int getP2() { return 1 * 1000 + 2; }
+        public int getP3() { return 1 * 1000 + 3; }
+        public int getP4() { return 1 * 1000 + 4; }
+        public int getP5() { return 1 * 1000 + 5; }
+        public int getP6() { return 1 * 1000 + 6; }
+        public int getP7() { return 1 * 1000 + 7; }
+        public int getP8() { return 1 * 1000 + 8; }
+        public int getP9() { return 1 * 1000 + 9; }
+        public int m0() { return 1 * 1000 + 0; };
+        public int m1() { return 1 * 1000 + 1; };
+        public int m2() { return 1 * 1000 + 2; };
+        public int m3() { return 1 * 1000 + 3; };
+        public int m4() { return 1 * 1000 + 4; };
+        public int m5() { return 1 * 1000 + 5; };
+        public int m6() { return 1 * 1000 + 6; };
+        public int m7() { return 1 * 1000 + 7; };
+        public int m8() { return 1 * 1000 + 8; };
+        public int m9() { return 1 * 1000 + 9; };
+    }
+    static public class C2 {
+        public int getP0() { return 2 * 1000 + 0; }
+        public int getP1() { return 2 * 1000 + 1; }
+        public int getP2() { return 2 * 1000 + 2; }
+        public int getP3() { return 2 * 1000 + 3; }
+        public int getP4() { return 2 * 1000 + 4; }
+        public int getP5() { return 2 * 1000 + 5; }
+        public int getP6() { return 2 * 1000 + 6; }
+        public int getP7() { return 2 * 1000 + 7; }
+        public int getP8() { return 2 * 1000 + 8; }
+        public int getP9() { return 2 * 1000 + 9; }
+        public int m0() { return 2 * 1000 + 0; };
+        public int m1() { return 2 * 1000 + 1; };
+        public int m2() { return 2 * 1000 + 2; };
+        public int m3() { return 2 * 1000 + 3; };
+        public int m4() { return 2 * 1000 + 4; };
+        public int m5() { return 2 * 1000 + 5; };
+        public int m6() { return 2 * 1000 + 6; };
+        public int m7() { return 2 * 1000 + 7; };
+        public int m8() { return 2 * 1000 + 8; };
+        public int m9() { return 2 * 1000 + 9; };
+    }
+    static public class C3 {
+        public int getP0() { return 3 * 1000 + 0; }
+        public int getP1() { return 3 * 1000 + 1; }
+        public int getP2() { return 3 * 1000 + 2; }
+        public int getP3() { return 3 * 1000 + 3; }
+        public int getP4() { return 3 * 1000 + 4; }
+        public int getP5() { return 3 * 1000 + 5; }
+        public int getP6() { return 3 * 1000 + 6; }
+        public int getP7() { return 3 * 1000 + 7; }
+        public int getP8() { return 3 * 1000 + 8; }
+        public int getP9() { return 3 * 1000 + 9; }
+        public int m0() { return 3 * 1000 + 0; };
+        public int m1() { return 3 * 1000 + 1; };
+        public int m2() { return 3 * 1000 + 2; };
+        public int m3() { return 3 * 1000 + 3; };
+        public int m4() { return 3 * 1000 + 4; };
+        public int m5() { return 3 * 1000 + 5; };
+        public int m6() { return 3 * 1000 + 6; };
+        public int m7() { return 3 * 1000 + 7; };
+        public int m8() { return 3 * 1000 + 8; };
+        public int m9() { return 3 * 1000 + 9; };
+    }
+    static public class C4 {
+        public int getP0() { return 4 * 1000 + 0; }
+        public int getP1() { return 4 * 1000 + 1; }
+        public int getP2() { return 4 * 1000 + 2; }
+        public int getP3() { return 4 * 1000 + 3; }
+        public int getP4() { return 4 * 1000 + 4; }
+        public int getP5() { return 4 * 1000 + 5; }
+        public int getP6() { return 4 * 1000 + 6; }
+        public int getP7() { return 4 * 1000 + 7; }
+        public int getP8() { return 4 * 1000 + 8; }
+        public int getP9() { return 4 * 1000 + 9; }
+        public int m0() { return 4 * 1000 + 0; };
+        public int m1() { return 4 * 1000 + 1; };
+        public int m2() { return 4 * 1000 + 2; };
+        public int m3() { return 4 * 1000 + 3; };
+        public int m4() { return 4 * 1000 + 4; };
+        public int m5() { return 4 * 1000 + 5; };
+        public int m6() { return 4 * 1000 + 6; };
+        public int m7() { return 4 * 1000 + 7; };
+        public int m8() { return 4 * 1000 + 8; };
+        public int m9() { return 4 * 1000 + 9; };
+    }
+    static public class C5 {
+        public int getP0() { return 5 * 1000 + 0; }
+        public int getP1() { return 5 * 1000 + 1; }
+        public int getP2() { return 5 * 1000 + 2; }
+        public int getP3() { return 5 * 1000 + 3; }
+        public int getP4() { return 5 * 1000 + 4; }
+        public int getP5() { return 5 * 1000 + 5; }
+        public int getP6() { return 5 * 1000 + 6; }
+        public int getP7() { return 5 * 1000 + 7; }
+        public int getP8() { return 5 * 1000 + 8; }
+        public int getP9() { return 5 * 1000 + 9; }
+        public int m0() { return 5 * 1000 + 0; };
+        public int m1() { return 5 * 1000 + 1; };
+        public int m2() { return 5 * 1000 + 2; };
+        public int m3() { return 5 * 1000 + 3; };
+        public int m4() { return 5 * 1000 + 4; };
+        public int m5() { return 5 * 1000 + 5; };
+        public int m6() { return 5 * 1000 + 6; };
+        public int m7() { return 5 * 1000 + 7; };
+        public int m8() { return 5 * 1000 + 8; };
+        public int m9() { return 5 * 1000 + 9; };
+    }
+    static public class C6 {
+        public int getP0() { return 6 * 1000 + 0; }
+        public int getP1() { return 6 * 1000 + 1; }
+        public int getP2() { return 6 * 1000 + 2; }
+        public int getP3() { return 6 * 1000 + 3; }
+        public int getP4() { return 6 * 1000 + 4; }
+        public int getP5() { return 6 * 1000 + 5; }
+        public int getP6() { return 6 * 1000 + 6; }
+        public int getP7() { return 6 * 1000 + 7; }
+        public int getP8() { return 6 * 1000 + 8; }
+        public int getP9() { return 6 * 1000 + 9; }
+        public int m0() { return 6 * 1000 + 0; };
+        public int m1() { return 6 * 1000 + 1; };
+        public int m2() { return 6 * 1000 + 2; };
+        public int m3() { return 6 * 1000 + 3; };
+        public int m4() { return 6 * 1000 + 4; };
+        public int m5() { return 6 * 1000 + 5; };
+        public int m6() { return 6 * 1000 + 6; };
+        public int m7() { return 6 * 1000 + 7; };
+        public int m8() { return 6 * 1000 + 8; };
+        public int m9() { return 6 * 1000 + 9; };
+    }
+    static public class C7 {
+        public int getP0() { return 7 * 1000 + 0; }
+        public int getP1() { return 7 * 1000 + 1; }
+        public int getP2() { return 7 * 1000 + 2; }
+        public int getP3() { return 7 * 1000 + 3; }
+        public int getP4() { return 7 * 1000 + 4; }
+        public int getP5() { return 7 * 1000 + 5; }
+        public int getP6() { return 7 * 1000 + 6; }
+        public int getP7() { return 7 * 1000 + 7; }
+        public int getP8() { return 7 * 1000 + 8; }
+        public int getP9() { return 7 * 1000 + 9; }
+        public int m0() { return 7 * 1000 + 0; };
+        public int m1() { return 7 * 1000 + 1; };
+        public int m2() { return 7 * 1000 + 2; };
+        public int m3() { return 7 * 1000 + 3; };
+        public int m4() { return 7 * 1000 + 4; };
+        public int m5() { return 7 * 1000 + 5; };
+        public int m6() { return 7 * 1000 + 6; };
+        public int m7() { return 7 * 1000 + 7; };
+        public int m8() { return 7 * 1000 + 8; };
+        public int m9() { return 7 * 1000 + 9; };
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/ManyStaticsOfDifferentClasses.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/ManyStaticsOfDifferentClasses.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/ManyStaticsOfDifferentClasses.java
new file mode 100644
index 0000000..dd73bee
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/ManyStaticsOfDifferentClasses.java
@@ -0,0 +1,236 @@
+/*
+ * 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.model.impl;
+
+// FMPP template source:
+// ----
+// package org.apache.freemarker.core.model.impl;
+// 
+// // FMPP template source:
+// // ----
+// <#assign src><#include "ManyStaticsOfDifferentClasses.java.ftl" parse=false></#assign>
+// ${src?trim?replace('(.*\r?\n)|.+', r'// $0', 'r')}
+// // ----
+// 
+// <#assign MAX_CLA = 8 - 1>
+// <#assign MAX_MET = 10 - 1>
+// <#assign MAX_PRO = 10 - 1>
+// 
+// public class ManyStaticsOfDifferentClasses {
+// 
+//     private ManyStaticsOfDifferentClasses() { }
+// 
+//     <#list 0..MAX_CLA as claI>
+//     static public class C${claI} {
+//         <#list 0..MAX_PRO as proI>
+//         public static int p${proI} = ${claI} * 1000 + ${proI};
+//         </#list>
+//         <#list 0..MAX_MET as metI>
+//         public static int m${metI}() { return ${claI} * 1000 + ${metI}; };
+//         </#list>
+//     }
+//     </#list>
+//     
+// }
+// ----
+
+
+public class ManyStaticsOfDifferentClasses {
+
+    private ManyStaticsOfDifferentClasses() { }
+
+    static public class C0 {
+        public static int p0 = 0 * 1000 + 0;
+        public static int p1 = 0 * 1000 + 1;
+        public static int p2 = 0 * 1000 + 2;
+        public static int p3 = 0 * 1000 + 3;
+        public static int p4 = 0 * 1000 + 4;
+        public static int p5 = 0 * 1000 + 5;
+        public static int p6 = 0 * 1000 + 6;
+        public static int p7 = 0 * 1000 + 7;
+        public static int p8 = 0 * 1000 + 8;
+        public static int p9 = 0 * 1000 + 9;
+        public static int m0() { return 0 * 1000 + 0; };
+        public static int m1() { return 0 * 1000 + 1; };
+        public static int m2() { return 0 * 1000 + 2; };
+        public static int m3() { return 0 * 1000 + 3; };
+        public static int m4() { return 0 * 1000 + 4; };
+        public static int m5() { return 0 * 1000 + 5; };
+        public static int m6() { return 0 * 1000 + 6; };
+        public static int m7() { return 0 * 1000 + 7; };
+        public static int m8() { return 0 * 1000 + 8; };
+        public static int m9() { return 0 * 1000 + 9; };
+    }
+    static public class C1 {
+        public static int p0 = 1 * 1000 + 0;
+        public static int p1 = 1 * 1000 + 1;
+        public static int p2 = 1 * 1000 + 2;
+        public static int p3 = 1 * 1000 + 3;
+        public static int p4 = 1 * 1000 + 4;
+        public static int p5 = 1 * 1000 + 5;
+        public static int p6 = 1 * 1000 + 6;
+        public static int p7 = 1 * 1000 + 7;
+        public static int p8 = 1 * 1000 + 8;
+        public static int p9 = 1 * 1000 + 9;
+        public static int m0() { return 1 * 1000 + 0; };
+        public static int m1() { return 1 * 1000 + 1; };
+        public static int m2() { return 1 * 1000 + 2; };
+        public static int m3() { return 1 * 1000 + 3; };
+        public static int m4() { return 1 * 1000 + 4; };
+        public static int m5() { return 1 * 1000 + 5; };
+        public static int m6() { return 1 * 1000 + 6; };
+        public static int m7() { return 1 * 1000 + 7; };
+        public static int m8() { return 1 * 1000 + 8; };
+        public static int m9() { return 1 * 1000 + 9; };
+    }
+    static public class C2 {
+        public static int p0 = 2 * 1000 + 0;
+        public static int p1 = 2 * 1000 + 1;
+        public static int p2 = 2 * 1000 + 2;
+        public static int p3 = 2 * 1000 + 3;
+        public static int p4 = 2 * 1000 + 4;
+        public static int p5 = 2 * 1000 + 5;
+        public static int p6 = 2 * 1000 + 6;
+        public static int p7 = 2 * 1000 + 7;
+        public static int p8 = 2 * 1000 + 8;
+        public static int p9 = 2 * 1000 + 9;
+        public static int m0() { return 2 * 1000 + 0; };
+        public static int m1() { return 2 * 1000 + 1; };
+        public static int m2() { return 2 * 1000 + 2; };
+        public static int m3() { return 2 * 1000 + 3; };
+        public static int m4() { return 2 * 1000 + 4; };
+        public static int m5() { return 2 * 1000 + 5; };
+        public static int m6() { return 2 * 1000 + 6; };
+        public static int m7() { return 2 * 1000 + 7; };
+        public static int m8() { return 2 * 1000 + 8; };
+        public static int m9() { return 2 * 1000 + 9; };
+    }
+    static public class C3 {
+        public static int p0 = 3 * 1000 + 0;
+        public static int p1 = 3 * 1000 + 1;
+        public static int p2 = 3 * 1000 + 2;
+        public static int p3 = 3 * 1000 + 3;
+        public static int p4 = 3 * 1000 + 4;
+        public static int p5 = 3 * 1000 + 5;
+        public static int p6 = 3 * 1000 + 6;
+        public static int p7 = 3 * 1000 + 7;
+        public static int p8 = 3 * 1000 + 8;
+        public static int p9 = 3 * 1000 + 9;
+        public static int m0() { return 3 * 1000 + 0; };
+        public static int m1() { return 3 * 1000 + 1; };
+        public static int m2() { return 3 * 1000 + 2; };
+        public static int m3() { return 3 * 1000 + 3; };
+        public static int m4() { return 3 * 1000 + 4; };
+        public static int m5() { return 3 * 1000 + 5; };
+        public static int m6() { return 3 * 1000 + 6; };
+        public static int m7() { return 3 * 1000 + 7; };
+        public static int m8() { return 3 * 1000 + 8; };
+        public static int m9() { return 3 * 1000 + 9; };
+    }
+    static public class C4 {
+        public static int p0 = 4 * 1000 + 0;
+        public static int p1 = 4 * 1000 + 1;
+        public static int p2 = 4 * 1000 + 2;
+        public static int p3 = 4 * 1000 + 3;
+        public static int p4 = 4 * 1000 + 4;
+        public static int p5 = 4 * 1000 + 5;
+        public static int p6 = 4 * 1000 + 6;
+        public static int p7 = 4 * 1000 + 7;
+        public static int p8 = 4 * 1000 + 8;
+        public static int p9 = 4 * 1000 + 9;
+        public static int m0() { return 4 * 1000 + 0; };
+        public static int m1() { return 4 * 1000 + 1; };
+        public static int m2() { return 4 * 1000 + 2; };
+        public static int m3() { return 4 * 1000 + 3; };
+        public static int m4() { return 4 * 1000 + 4; };
+        public static int m5() { return 4 * 1000 + 5; };
+        public static int m6() { return 4 * 1000 + 6; };
+        public static int m7() { return 4 * 1000 + 7; };
+        public static int m8() { return 4 * 1000 + 8; };
+        public static int m9() { return 4 * 1000 + 9; };
+    }
+    static public class C5 {
+        public static int p0 = 5 * 1000 + 0;
+        public static int p1 = 5 * 1000 + 1;
+        public static int p2 = 5 * 1000 + 2;
+        public static int p3 = 5 * 1000 + 3;
+        public static int p4 = 5 * 1000 + 4;
+        public static int p5 = 5 * 1000 + 5;
+        public static int p6 = 5 * 1000 + 6;
+        public static int p7 = 5 * 1000 + 7;
+        public static int p8 = 5 * 1000 + 8;
+        public static int p9 = 5 * 1000 + 9;
+        public static int m0() { return 5 * 1000 + 0; };
+        public static int m1() { return 5 * 1000 + 1; };
+        public static int m2() { return 5 * 1000 + 2; };
+        public static int m3() { return 5 * 1000 + 3; };
+        public static int m4() { return 5 * 1000 + 4; };
+        public static int m5() { return 5 * 1000 + 5; };
+        public static int m6() { return 5 * 1000 + 6; };
+        public static int m7() { return 5 * 1000 + 7; };
+        public static int m8() { return 5 * 1000 + 8; };
+        public static int m9() { return 5 * 1000 + 9; };
+    }
+    static public class C6 {
+        public static int p0 = 6 * 1000 + 0;
+        public static int p1 = 6 * 1000 + 1;
+        public static int p2 = 6 * 1000 + 2;
+        public static int p3 = 6 * 1000 + 3;
+        public static int p4 = 6 * 1000 + 4;
+        public static int p5 = 6 * 1000 + 5;
+        public static int p6 = 6 * 1000 + 6;
+        public static int p7 = 6 * 1000 + 7;
+        public static int p8 = 6 * 1000 + 8;
+        public static int p9 = 6 * 1000 + 9;
+        public static int m0() { return 6 * 1000 + 0; };
+        public static int m1() { return 6 * 1000 + 1; };
+        public static int m2() { return 6 * 1000 + 2; };
+        public static int m3() { return 6 * 1000 + 3; };
+        public static int m4() { return 6 * 1000 + 4; };
+        public static int m5() { return 6 * 1000 + 5; };
+        public static int m6() { return 6 * 1000 + 6; };
+        public static int m7() { return 6 * 1000 + 7; };
+        public static int m8() { return 6 * 1000 + 8; };
+        public static int m9() { return 6 * 1000 + 9; };
+    }
+    static public class C7 {
+        public static int p0 = 7 * 1000 + 0;
+        public static int p1 = 7 * 1000 + 1;
+        public static int p2 = 7 * 1000 + 2;
+        public static int p3 = 7 * 1000 + 3;
+        public static int p4 = 7 * 1000 + 4;
+        public static int p5 = 7 * 1000 + 5;
+        public static int p6 = 7 * 1000 + 6;
+        public static int p7 = 7 * 1000 + 7;
+        public static int p8 = 7 * 1000 + 8;
+        public static int p9 = 7 * 1000 + 9;
+        public static int m0() { return 7 * 1000 + 0; };
+        public static int m1() { return 7 * 1000 + 1; };
+        public static int m2() { return 7 * 1000 + 2; };
+        public static int m3() { return 7 * 1000 + 3; };
+        public static int m4() { return 7 * 1000 + 4; };
+        public static int m5() { return 7 * 1000 + 5; };
+        public static int m6() { return 7 * 1000 + 6; };
+        public static int m7() { return 7 * 1000 + 7; };
+        public static int m8() { return 7 * 1000 + 8; };
+        public static int m9() { return 7 * 1000 + 9; };
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/MiscNumericalOperationsTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/MiscNumericalOperationsTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/MiscNumericalOperationsTest.java
new file mode 100644
index 0000000..9e175e5
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/MiscNumericalOperationsTest.java
@@ -0,0 +1,111 @@
+/*
+ * 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.model.impl;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import org.junit.Assert;
+
+import junit.framework.TestCase;
+
+public class MiscNumericalOperationsTest extends TestCase {
+
+    public MiscNumericalOperationsTest(String name) {
+        super(name);
+    }
+    
+    public void testForceUnwrappedNumberToType() {
+        // Usual type to to all other types:
+        Double n = Double.valueOf(123.75);
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, Short.class), Short.valueOf(n.shortValue()));
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, Short.TYPE), Short.valueOf(n.shortValue()));
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, Byte.class), Byte.valueOf(n.byteValue()));
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, Byte.TYPE), Byte.valueOf(n.byteValue()));
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, Integer.class), Integer.valueOf(n.intValue()));
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, Integer.TYPE), Integer.valueOf(n.intValue()));
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, Long.class), Long.valueOf(n.longValue()));
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, Long.TYPE), Long.valueOf(n.longValue()));
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, Float.class), Float.valueOf(n.floatValue()));
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, Float.TYPE), Float.valueOf(n.floatValue()));
+        assertTrue(DefaultObjectWrapper.forceUnwrappedNumberToType(n, Double.class) == n);
+        assertTrue(DefaultObjectWrapper.forceUnwrappedNumberToType(n, Double.TYPE) == n);
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, BigInteger.class), new BigInteger("123"));
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, BigDecimal.class), new BigDecimal("123.75"));
+        
+        // Cases of conversion to BigDecimal:
+        BigDecimal bd = new BigDecimal("123");
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(new BigInteger("123"), BigDecimal.class), bd);
+        assertTrue(DefaultObjectWrapper.forceUnwrappedNumberToType(bd, BigDecimal.class) == bd);
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(Long.valueOf(123), BigDecimal.class), bd);
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(Double.valueOf(123), BigDecimal.class), bd);
+        
+        // Cases of conversion to BigInteger:
+        BigInteger bi = new BigInteger("123");
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(new BigDecimal("123.6"), BigInteger.class), bi);
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(
+                new OverloadedNumberUtil.IntegerBigDecimal(new BigDecimal("123")), BigInteger.class), bi);
+        assertTrue(DefaultObjectWrapper.forceUnwrappedNumberToType(bi, BigInteger.class) == bi);
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(Long.valueOf(123), BigInteger.class), bi);
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(Double.valueOf(123.6), BigInteger.class), bi);
+
+        assertTrue(DefaultObjectWrapper.forceUnwrappedNumberToType(n, Number.class) == n);
+        assertNull(DefaultObjectWrapper.forceUnwrappedNumberToType(n, RationalNumber.class));
+        RationalNumber r = new RationalNumber(1, 2);
+        assertTrue(DefaultObjectWrapper.forceUnwrappedNumberToType(r, RationalNumber.class) == r);
+        assertTrue(DefaultObjectWrapper.forceUnwrappedNumberToType(r, Number.class) == r);
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(r, Double.class), Double.valueOf(0.5));
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(r, BigDecimal.class), new BigDecimal("0.5"));
+        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(r, BigInteger.class), BigInteger.ZERO);
+    }
+    
+    @SuppressWarnings("boxing")
+    public void testForceNumberArgumentsToParameterTypes() {
+        OverloadedMethodsSubset oms = new OverloadedFixArgsMethods();
+        Class[] paramTypes = new Class[] { Short.TYPE, Short.class, Double.TYPE, BigDecimal.class, BigInteger.class };
+        Object[] args;
+        
+        args = newArgs();
+        oms.forceNumberArgumentsToParameterTypes(args, paramTypes, new int[] { 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF });
+        Assert.assertArrayEquals(
+                args,
+                new Object[] { (short) 123, (short) 123, 123.75, new BigDecimal("123.75"), BigInteger.valueOf(123) });
+        
+        args = newArgs();
+        oms.forceNumberArgumentsToParameterTypes(args, paramTypes, new int[] { 0, 0, 0, 0, 0 });
+        Assert.assertArrayEquals(args, newArgs());
+        
+        args = newArgs();
+        oms.forceNumberArgumentsToParameterTypes(args, paramTypes, new int[] { 8, 8, 8, 8, 8 });
+        Assert.assertArrayEquals(args, newArgs());
+        
+        args = newArgs();
+        oms.forceNumberArgumentsToParameterTypes(args, paramTypes, new int[] { 0xFFFF, 0, 0xFFFF, 0, 0xFFFF });
+        Assert.assertArrayEquals(
+                args,
+                new Object[] { (short) 123, 123.75, 123.75, 123.75, BigInteger.valueOf(123) });
+    }
+
+    @SuppressWarnings("boxing")
+    private Object[] newArgs() {
+        return new Object[] { 123.75, 123.75, 123.75, 123.75, 123.75 };
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/ModelAPINewInstanceTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/ModelAPINewInstanceTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/ModelAPINewInstanceTest.java
new file mode 100644
index 0000000..0b0a614
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/ModelAPINewInstanceTest.java
@@ -0,0 +1,134 @@
+/*
+ * 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.model.impl;
+
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.test.TestUtil;
+
+import junit.framework.TestCase;
+
+public class ModelAPINewInstanceTest extends TestCase {
+
+    private DefaultObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
+
+    public ModelAPINewInstanceTest(String name) {
+        super(name);
+    }
+    
+    @SuppressWarnings("boxing")
+    public void test() throws Exception {
+        testClassConstructors("");
+        testClassConstructors("int... [1]", 1);
+        testClassConstructors("int 1, int 2", 1, 2);
+        testClassConstructors("int... [1, 2, 3]", 1, 2, 3);
+        testClassConstructors("int... [1, 2, 3]", 1, (byte) 2, (short) 3);
+        try {
+            testClassConstructors("int... [1, 2, 3]", 1, 2, (long) 3);
+            fail();
+        } catch (NoSuchMethodException e) {
+            // Expected
+        }
+        
+        testClassConstructors("int 1, int 2", (byte) 1, (short) 2);
+        testClassConstructors("double 1.0, double 2.0", (long) 1, (short) 2);
+        testClassConstructors("double 1.0, double 2.0", 1, 2f);
+        testClassConstructors("Integer null, Integer null", null, null);
+        testClassConstructors("Integer null, Integer 1", null, 1);
+        testClassConstructors("int 1, String s", 1, "s");
+        testClassConstructors("int 1, String null", 1, null);
+        testClassConstructors("Object null, Object s", null, "s");
+        testClassConstructors("Object 1.0, Object s", 1f, "s");
+        
+        testClassConstructors("Object s, int... [1, 2]", "s", 1, 2);
+        testClassConstructors("Object s, int... []", "s");
+        
+        testClassConstructors2("int 1, int 2", (byte) 1, (short) 2);
+        try {
+            testClassConstructors2("int 1, int 2", 1, 2L);
+            fail();
+        } catch (NoSuchMethodException e) {
+            // Expected
+        }
+        try {
+            testClassConstructors2("", "", "");
+            fail();
+        } catch (NoSuchMethodException e) {
+            // Expected
+        }
+        try {
+            testClassConstructors2("int 1", 1);
+            fail();
+        } catch (NoSuchMethodException e) {
+            // Expected
+        }
+        try {
+            testClassConstructors2("");
+            fail();
+        } catch (NoSuchMethodException e) {
+            // Expected
+        }
+    }
+    
+    private void testClassConstructors(String expected, Object... args) throws Exception {
+        testCall(expected, Constructors.class, args); 
+    }
+
+    private void testClassConstructors2(String expected, Object... args) throws Exception {
+        testCall(expected, Constructors2.class, args); 
+    }
+    
+    private void testCall(String expected, Class cl, Object... args) throws Exception {
+        Object obj = _ModelAPI.newInstance(cl, args, ow);
+        assertEquals(expected, obj.toString());        
+    }
+    
+    public static class Constructors {
+        private final String s;
+
+        public Constructors() { s = ""; }
+        
+        public Constructors(int x, int y) { s = "int " + x + ", int " + y; }
+        public Constructors(int x, String y) { s = "int " + x + ", String " + y; }
+        public Constructors(int x, long y) { s = "int " + x + ", long " + y; }
+        public Constructors(double x, double y) { s = "double " + x + ", double " + y; }
+        public Constructors(Integer x, Integer y) { s = "Integer " + x + ", Integer " + y; }
+        public Constructors(Object x, Object y) { s = "Object " + x + ", Object " + y; }
+
+        public Constructors(int... xs) { s = "int... " + TestUtil.arrayToString(xs); }
+        public Constructors(Object x, int... ys) { s = "Object " + x + ", int... " + TestUtil.arrayToString(ys); }
+        
+        @Override
+        public String toString() {
+            return s;
+        }
+    }
+
+    public static class Constructors2 {
+        private final String s;
+
+        public Constructors2(int x, int y) { s = "int " + x + ", int " + y; }
+        
+        @Override
+        public String toString() {
+            return s;
+        }
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/ModelCacheTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/ModelCacheTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/ModelCacheTest.java
new file mode 100644
index 0000000..2498859
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/ModelCacheTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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.model.impl;
+
+import static org.junit.Assert.*;
+
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class ModelCacheTest {
+    
+    @Test
+    public void modelCacheOff() throws Exception {
+        DefaultObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
+        assertFalse(ow.getUseModelCache());  // default is off
+        
+        String s = "foo";
+        assertNotSame(ow.wrap(s), ow.wrap(s));
+        
+        C c = new C();
+        assertNotSame(ow.wrap(c), ow.wrap(c));
+    }
+    
+    @Test
+    @Ignore // ModelCache is current removed in FM3
+    public void modelCacheOn() throws Exception {
+        DefaultObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0)
+                .useModelCache(true).build();
+        assertTrue(ow.getUseModelCache());
+
+        TestBean obj = new TestBean();
+        assertSame(ow.wrap(obj), ow.wrap(obj));
+        
+        C c = new C();
+        TemplateModel wrappedC = ow.wrap(c);
+        assertSame(wrappedC, ow.wrap(c));
+        
+        ow.clearClassIntrospecitonCache();
+        assertNotSame(wrappedC, ow.wrap(c));
+        assertSame(ow.wrap(c), ow.wrap(c));
+    }
+
+    static public class C { }
+
+    public static class TestBean {
+        //
+    }
+    
+}


[49/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/ActualNamingConvetionTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/ActualNamingConvetionTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ActualNamingConvetionTest.java
new file mode 100644
index 0000000..57e40fa
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ActualNamingConvetionTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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 org.apache.freemarker.test.TestConfigurationBuilder;
+import org.junit.Test;
+
+public class ActualNamingConvetionTest {
+    
+    @Test
+    public void testUndetectable() throws IOException {
+        final String ftl = "<#if true>${x?size}</#if>";
+        assertEquals(getActualNamingConvention(ftl,
+                ParsingConfiguration.AUTO_DETECT_NAMING_CONVENTION), ParsingConfiguration.AUTO_DETECT_NAMING_CONVENTION);
+        assertEquals(getActualNamingConvention(ftl,
+                ParsingConfiguration.LEGACY_NAMING_CONVENTION), ParsingConfiguration.LEGACY_NAMING_CONVENTION);
+        assertEquals(getActualNamingConvention(ftl,
+                ParsingConfiguration.CAMEL_CASE_NAMING_CONVENTION), ParsingConfiguration.CAMEL_CASE_NAMING_CONVENTION);
+    }
+
+    @Test
+    public void testLegacyDetected() throws IOException {
+        final String ftl = "${x?upper_case}";
+        assertEquals(getActualNamingConvention(ftl,
+                ParsingConfiguration.AUTO_DETECT_NAMING_CONVENTION), ParsingConfiguration.LEGACY_NAMING_CONVENTION);
+        assertEquals(getActualNamingConvention(ftl,
+                ParsingConfiguration.LEGACY_NAMING_CONVENTION), ParsingConfiguration.LEGACY_NAMING_CONVENTION);
+    }
+
+    @Test
+    public void testCamelCaseDetected() throws IOException {
+        final String ftl = "${x?upperCase}";
+        assertEquals(getActualNamingConvention(ftl,
+                ParsingConfiguration.AUTO_DETECT_NAMING_CONVENTION), ParsingConfiguration.CAMEL_CASE_NAMING_CONVENTION);
+        assertEquals(getActualNamingConvention(ftl,
+                ParsingConfiguration.CAMEL_CASE_NAMING_CONVENTION), ParsingConfiguration.CAMEL_CASE_NAMING_CONVENTION);
+    }
+
+    private int getActualNamingConvention(String ftl, int namingConvention) throws IOException {
+        return new Template(null, ftl,
+                new TestConfigurationBuilder().namingConvention(namingConvention).build())
+                .getActualNamingConvention();
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/ActualTagSyntaxTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/ActualTagSyntaxTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ActualTagSyntaxTest.java
new file mode 100644
index 0000000..88f0646
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ActualTagSyntaxTest.java
@@ -0,0 +1,68 @@
+/*
+ * 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.apache.freemarker.core.ParsingConfiguration.*;
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+
+import org.apache.freemarker.test.TestConfigurationBuilder;
+import org.junit.Test;
+
+public class ActualTagSyntaxTest {
+
+    @Test
+    public void testWithFtlHeader() throws IOException {
+        testWithFtlHeader(AUTO_DETECT_TAG_SYNTAX);
+        testWithFtlHeader(ANGLE_BRACKET_TAG_SYNTAX);
+        testWithFtlHeader(SQUARE_BRACKET_TAG_SYNTAX);
+    }
+    
+    private void testWithFtlHeader(int cfgTagSyntax) throws IOException {
+        assertEquals(getActualTagSyntax("[#ftl]foo", cfgTagSyntax), SQUARE_BRACKET_TAG_SYNTAX);
+        assertEquals(getActualTagSyntax("<#ftl>foo", cfgTagSyntax), ANGLE_BRACKET_TAG_SYNTAX);
+    }
+    
+    @Test
+    public void testUndecidable() throws IOException {
+        assertEquals(getActualTagSyntax("foo", AUTO_DETECT_TAG_SYNTAX), ANGLE_BRACKET_TAG_SYNTAX);
+        assertEquals(getActualTagSyntax("foo", ANGLE_BRACKET_TAG_SYNTAX), ANGLE_BRACKET_TAG_SYNTAX);
+        assertEquals(getActualTagSyntax("foo", SQUARE_BRACKET_TAG_SYNTAX), SQUARE_BRACKET_TAG_SYNTAX);
+    }
+
+    @Test
+    public void testDecidableWithoutFtlHeader() throws IOException {
+        assertEquals(getActualTagSyntax("foo<#if true></#if>", AUTO_DETECT_TAG_SYNTAX), ANGLE_BRACKET_TAG_SYNTAX);
+        assertEquals(getActualTagSyntax("foo<#if true></#if>", ANGLE_BRACKET_TAG_SYNTAX), ANGLE_BRACKET_TAG_SYNTAX);
+        assertEquals(getActualTagSyntax("foo<#if true></#if>", SQUARE_BRACKET_TAG_SYNTAX), SQUARE_BRACKET_TAG_SYNTAX);
+        
+        assertEquals(getActualTagSyntax("foo[#if true][/#if]", AUTO_DETECT_TAG_SYNTAX), SQUARE_BRACKET_TAG_SYNTAX);
+        assertEquals(getActualTagSyntax("foo[#if true][/#if]", ANGLE_BRACKET_TAG_SYNTAX), ANGLE_BRACKET_TAG_SYNTAX);
+        assertEquals(getActualTagSyntax("foo[#if true][/#if]", SQUARE_BRACKET_TAG_SYNTAX), SQUARE_BRACKET_TAG_SYNTAX);
+    }
+    
+    private int getActualTagSyntax(String ftl, int cfgTagSyntax) throws IOException {
+        return new Template(
+                null, ftl,
+                new TestConfigurationBuilder().tagSyntax(cfgTagSyntax).build()).getActualTagSyntax();
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/BreakPlacementTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/BreakPlacementTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/BreakPlacementTest.java
new file mode 100644
index 0000000..61ba02b
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/BreakPlacementTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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.junit.Test;
+
+public class BreakPlacementTest extends TemplateTest {
+    
+    private static final String BREAK_NESTING_ERROR_MESSAGE_PART = "<#break> must be nested";
+
+    @Test
+    public void testValidPlacements() throws IOException, TemplateException {
+        assertOutput("<#assign x = 1><#switch x><#case 1>one<#break><#case 2>two</#switch>", "one");
+        assertOutput("<#list 1..2 as x>${x}<#break></#list>", "1");
+        assertOutput("<#list 1..2>[<#items as x>${x}<#break></#items>]</#list>", "[1]");
+        assertOutput("<#list 1..2 as x>${x}<#list 1..3>B<#break>E<#items as y></#items></#list>E</#list>.", "1B.");
+        assertOutput("<#list 1..2 as x>${x}<#list 3..4 as x>${x}<#break></#list>;</#list>", "13;23;");
+        assertOutput("<#list [1..2, 3..4, [], 5..6] as xs>[<#list xs as x>${x}<#else><#break></#list>]</#list>.",
+                "[12][34][.");
+        assertOutput("<#list [1..2, 3..4, [], 5..6] as xs>"
+                + "<#list xs>[<#items as x>${x}</#items>]<#else><#break></#list>"
+                + "</#list>.",
+                "[12][34].");
+    }
+
+    @Test
+    public void testInvalidPlacements() throws IOException, TemplateException {
+        assertErrorContains("<#break>", BREAK_NESTING_ERROR_MESSAGE_PART);
+        assertErrorContains("<#list 1..2 as x>${x}</#list><#break>", BREAK_NESTING_ERROR_MESSAGE_PART);
+        assertErrorContains("<#if false><#break></#if>", BREAK_NESTING_ERROR_MESSAGE_PART);
+        assertErrorContains("<#list xs><#break></#list>", BREAK_NESTING_ERROR_MESSAGE_PART);
+        assertErrorContains("<#list 1..2 as x>${x}<#else><#break></#list>", BREAK_NESTING_ERROR_MESSAGE_PART);
+        assertErrorContains("<#list 1..2 as x>${x}<#macro m><#break></#macro></#list>", BREAK_NESTING_ERROR_MESSAGE_PART);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/CamelCaseTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/CamelCaseTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/CamelCaseTest.java
new file mode 100644
index 0000000..95572ad
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/CamelCaseTest.java
@@ -0,0 +1,486 @@
+/*
+ * 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.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Set;
+
+import org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat;
+import org.apache.freemarker.core.outputformat.impl.UndefinedOutputFormat;
+import org.apache.freemarker.core.util._StringUtil;
+import org.apache.freemarker.test.TemplateTest;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+import org.junit.Test;
+
+public class CamelCaseTest extends TemplateTest {
+
+    @Test
+    public void camelCaseSpecialVars() throws IOException, TemplateException {
+        setConfiguration(new TestConfigurationBuilder()
+                .outputEncoding(StandardCharsets.UTF_8)
+                .urlEscapingCharset(StandardCharsets.ISO_8859_1)
+                .locale(Locale.GERMANY)
+                .build());
+        assertOutput("${.dataModel?isHash?c}", "true");
+        assertOutput("${.data_model?is_hash?c}", "true");
+        assertOutput("${.localeObject.toString()}", "de_DE");
+        assertOutput("${.locale_object.toString()}", "de_DE");
+        assertOutput("${.templateName!'null'}", "null");
+        assertOutput("${.template_name!'null'}", "null");
+        assertOutput("${.currentTemplateName!'null'}", "null");
+        assertOutput("${.current_template_name!'null'}", "null");
+        assertOutput("${.mainTemplateName!'null'}", "null");
+        assertOutput("${.main_template_name!'null'}", "null");
+        assertOutput("${.outputEncoding}", StandardCharsets.UTF_8.name());
+        assertOutput("${.output_encoding}", StandardCharsets.UTF_8.name());
+        assertOutput("${.outputFormat}", UndefinedOutputFormat.INSTANCE.getName());
+        assertOutput("${.output_format}", UndefinedOutputFormat.INSTANCE.getName());
+        assertOutput("${.urlEscapingCharset}", StandardCharsets.ISO_8859_1.name());
+        assertOutput("${.url_escaping_charset}", StandardCharsets.ISO_8859_1.name());
+        assertOutput("${.currentNode!'-'}", "-");
+        assertOutput("${.current_node!'-'}", "-");
+    }
+
+    @Test
+    public void camelCaseSpecialVarsInErrorMessage() throws IOException, TemplateException {
+        assertErrorContains("${.fooBar}", "dataModel", "\\!data_model");
+        assertErrorContains("${.foo_bar}", "data_model", "\\!dataModel");
+        // [2.4] If camel case will be the recommended style, then this need to be inverted:
+        assertErrorContains("${.foo}", "data_model", "\\!dataModel");
+        
+        assertErrorContains("<#if x><#elseIf y></#if>${.foo}", "dataModel", "\\!data_model");
+        assertErrorContains("<#if x><#elseif y></#if>${.foo}", "data_model", "\\!dataModel");
+
+        setConfigurationToCamelCaseNamingConvention();
+        assertErrorContains("${.foo}", "dataModel", "\\!data_model");
+
+        setConfigurationToLegacyCaseNamingConvention();
+        assertErrorContains("${.foo}", "data_model", "\\!dataModel");
+    }
+    
+    @Test
+    public void camelCaseSettingNames() throws IOException, TemplateException {
+        assertOutput("<#setting booleanFormat='Y,N'>${true} <#setting booleanFormat='+,-'>${true}", "Y +");
+        assertOutput("<#setting boolean_format='Y,N'>${true} <#setting boolean_format='+,-'>${true}", "Y +");
+        
+        // Still works inside ?interpret
+        assertOutput("<@r\"<#setting booleanFormat='Y,N'>${true}\"?interpret />", "Y");
+    }
+    
+    @Test
+    public void camelCaseFtlHeaderParameters() throws IOException, TemplateException {
+        assertOutput(
+                "<#ftl "
+                + "stripWhitespace=false "
+                + "stripText=true "
+                + "outputFormat='" + HTMLOutputFormat.INSTANCE.getName() + "' "
+                + "autoEsc=true "
+                + "nsPrefixes={} "
+                + ">\nx\n<#if true>\n${.outputFormat}\n</#if>\n",
+                "\nHTML\n");
+
+        assertOutput(
+                "<#ftl "
+                + "strip_whitespace=false "
+                + "strip_text=true "
+                + "output_format='" + HTMLOutputFormat.INSTANCE.getName() + "' "
+                + "auto_esc=true "
+                + "ns_prefixes={} "
+                + ">\nx\n<#if true>\n${.output_format}\n</#if>\n",
+                "\nHTML\n");
+
+        assertErrorContains("<#ftl strip_text=true xmlns={}>", "ns_prefixes", "\\!nsPrefixes");
+        assertErrorContains("<#ftl stripText=true xmlns={}>", "nsPrefixes");
+        
+        assertErrorContains("<#ftl stripWhitespace=true strip_text=true>", "naming convention");
+        assertErrorContains("<#ftl strip_whitespace=true stripText=true>", "naming convention");
+        assertErrorContains("<#ftl stripWhitespace=true>${.foo_bar}", "naming convention");
+        assertErrorContains("<#ftl strip_whitespace=true>${.fooBar}", "naming convention");
+
+        setConfiguration(new TestConfigurationBuilder()
+                .namingConvention(ParsingConfiguration.CAMEL_CASE_NAMING_CONVENTION)
+                .outputEncoding(StandardCharsets.UTF_8)
+                .build());
+        assertErrorContains("<#ftl strip_whitespace=true>", "naming convention");
+        assertOutput("<#ftl stripWhitespace=true>${.outputEncoding}", StandardCharsets.UTF_8.name());
+        
+        setConfiguration(new TestConfigurationBuilder()
+                .namingConvention(ParsingConfiguration.LEGACY_NAMING_CONVENTION)
+                .outputEncoding(StandardCharsets.UTF_8)
+                .build());
+        assertErrorContains("<#ftl stripWhitespace=true>", "naming convention");
+        assertOutput("<#ftl strip_whitespace=true>${.output_encoding}", StandardCharsets.UTF_8.name());
+        
+        setConfiguration(new TestConfigurationBuilder()
+                .namingConvention(ParsingConfiguration.AUTO_DETECT_NAMING_CONVENTION)
+                .outputEncoding(StandardCharsets.UTF_8)
+                .build());
+        assertOutput("<#ftl stripWhitespace=true>${.outputEncoding}", StandardCharsets.UTF_8.name());
+        assertOutput("<#ftl encoding='iso-8859-1' stripWhitespace=true>${.outputEncoding}", StandardCharsets.UTF_8.name());
+        assertOutput("<#ftl stripWhitespace=true encoding='iso-8859-1'>${.outputEncoding}", StandardCharsets.UTF_8.name());
+        assertOutput("<#ftl encoding='iso-8859-1' strip_whitespace=true>${.output_encoding}", StandardCharsets.UTF_8.name());
+        assertOutput("<#ftl strip_whitespace=true encoding='iso-8859-1'>${.output_encoding}", StandardCharsets.UTF_8.name());
+    }
+    
+    @Test
+    public void camelCaseSettingNamesInErrorMessages() throws IOException, TemplateException {
+        assertErrorContains("<#setting fooBar=1>", "booleanFormat", "\\!boolean_format");
+        assertErrorContains("<#setting foo_bar=1>", "boolean_format", "\\!booleanFormat");
+        // [2.4] If camel case will be the recommended style, then this need to be inverted:
+        assertErrorContains("<#setting foo=1>", "boolean_format", "\\!booleanFormat");
+
+        assertErrorContains("<#if x><#elseIf y></#if><#setting foo=1>", "booleanFormat", "\\!boolean_format");
+        assertErrorContains("<#if x><#elseif y></#if><#setting foo=1>", "boolean_format", "\\!booleanFormat");
+
+        setConfigurationToCamelCaseNamingConvention();
+        assertErrorContains("<#setting foo=1>", "booleanFormat", "\\!boolean_format");
+
+        setConfigurationToLegacyCaseNamingConvention();
+        assertErrorContains("<#setting foo=1>", "boolean_format", "\\!booleanFormat");
+    }
+    
+    @Test
+    public void camelCaseIncludeParameters() throws IOException, TemplateException {
+        assertOutput("<#ftl stripWhitespace=true>[<#include 'noSuchTemplate' ignoreMissing=true>]", "[]");
+        assertOutput("<#ftl strip_whitespace=true>[<#include 'noSuchTemplate' ignore_missing=true>]", "[]");
+        assertErrorContains("<#ftl stripWhitespace=true>[<#include 'noSuchTemplate' ignore_missing=true>]",
+                "naming convention", "ignore_missing");
+        assertErrorContains("<#ftl strip_whitespace=true>[<#include 'noSuchTemplate' ignoreMissing=true>]",
+                "naming convention", "ignoreMissing");
+    }
+    
+    @Test
+    public void specialVarsHasBothNamingStyle() throws IOException, TemplateException {
+        assertContainsBothNamingStyles(
+                new HashSet(Arrays.asList(ASTExpBuiltInVariable.SPEC_VAR_NAMES)),
+                new NamePairAssertion() { @Override
+                public void assertPair(String name1, String name2) { } });
+    }
+    
+    @Test
+    public void camelCaseBuiltIns() throws IOException, TemplateException {
+        assertOutput("${'x'?upperCase}", "X");
+        assertOutput("${'x'?upper_case}", "X");
+    }
+
+    @Test
+    public void stringLiteralInterpolation() throws IOException, TemplateException {
+        assertEquals(ParsingConfiguration.AUTO_DETECT_NAMING_CONVENTION, getConfiguration().getNamingConvention());
+        addToDataModel("x", "x");
+        
+        assertOutput("${'-${x?upperCase}-'} ${x?upperCase}", "-X- X");
+        assertOutput("${x?upperCase} ${'-${x?upperCase}-'}", "X -X-");
+        assertOutput("${'-${x?upper_case}-'} ${x?upper_case}", "-X- X");
+        assertOutput("${x?upper_case} ${'-${x?upper_case}-'}", "X -X-");
+
+        assertErrorContains("${'-${x?upper_case}-'} ${x?upperCase}",
+                "naming convention", "legacy", "upperCase", "detection", "9");
+        assertErrorContains("${x?upper_case} ${'-${x?upperCase}-'}",
+                "naming convention", "legacy", "upperCase", "detection", "5");
+        assertErrorContains("${'-${x?upperCase}-'} ${x?upper_case}",
+                "naming convention", "camel", "upper_case");
+        assertErrorContains("${x?upperCase} ${'-${x?upper_case}-'}",
+                "naming convention", "camel", "upper_case");
+
+        setConfigurationToCamelCaseNamingConvention();
+        assertOutput("${'-${x?upperCase}-'} ${x?upperCase}", "-X- X");
+        assertErrorContains("${'-${x?upper_case}-'}",
+                "naming convention", "camel", "upper_case", "\\!detection");
+
+        setConfigurationToLegacyCaseNamingConvention();
+        assertOutput("${'-${x?upper_case}-'} ${x?upper_case}", "-X- X");
+        assertErrorContains("${'-${x?upperCase}-'}",
+                "naming convention", "legacy", "upperCase", "\\!detection");
+    }
+    
+    @Test
+    public void evalAndInterpret() throws IOException, TemplateException {
+        assertEquals(ParsingConfiguration.AUTO_DETECT_NAMING_CONVENTION, getConfiguration().getNamingConvention());
+        // The naming convention detected doesn't affect the enclosing template's naming convention.
+        // - ?eval:
+        assertOutput("${\"'x'?upperCase\"?eval}${'x'?upper_case}", "XX");
+        assertOutput("${\"'x'?upper_case\"?eval}${'x'?upperCase}", "XX");
+        assertOutput("${'x'?upperCase}${\"'x'?upper_case\"?eval}", "XX");
+        assertErrorContains("${\"'x'\n?upperCase\n?is_string\"?eval}",
+                "naming convention", "camel", "upperCase", "is_string", "line 2", "line 3");
+        // - ?interpret:
+        assertOutput("<@r\"${'x'?upperCase}\"?interpret />${'x'?upper_case}", "XX");
+        assertOutput("<@r\"${'x'?upper_case}\"?interpret />${'x'?upperCase}", "XX");
+        assertOutput("${'x'?upper_case}<@r\"${'x'?upperCase}\"?interpret />", "XX");
+        assertErrorContains("<@r\"${'x'\n?upperCase\n?is_string}\"?interpret />",
+                "naming convention", "camel", "upperCase", "is_string", "line 2", "line 3");
+        
+        // Will be inherited by ?eval-ed/?interpreted fragments:
+        setConfigurationToCamelCaseNamingConvention();
+        // - ?eval:
+        assertErrorContains("${\"'x'?upper_case\"?eval}", "naming convention", "camel", "upper_case");
+        assertOutput("${\"'x'?upperCase\"?eval}", "X");
+        // - ?interpret:
+        assertErrorContains("<@r\"${'x'?upper_case}\"?interpret />", "naming convention", "camel", "upper_case");
+        assertOutput("<@r\"${'x'?upperCase}\"?interpret />", "X");
+        
+        // Again, will be inherited by ?eval-ed/?interpreted fragments:
+        setConfigurationToLegacyCaseNamingConvention();
+        // - ?eval:
+        assertErrorContains("${\"'x'?upperCase\"?eval}", "naming convention", "legacy", "upperCase");
+        assertOutput("${\"'x'?upper_case\"?eval}", "X");
+        // - ?interpret:
+        assertErrorContains("<@r\"${'x'?upperCase}\"?interpret />", "naming convention", "legacy", "upperCase");
+        assertOutput("<@r\"${'x'?upper_case}\"?interpret />", "X");
+    }
+
+    private void setConfigurationToLegacyCaseNamingConvention() {
+        setConfiguration(new TestConfigurationBuilder()
+                .namingConvention(ParsingConfiguration.LEGACY_NAMING_CONVENTION)
+                .build());
+    }
+
+    @Test
+    public void camelCaseBuiltInErrorMessage() throws IOException, TemplateException {
+        assertErrorContains("${'x'?upperCasw}", "upperCase", "\\!upper_case");
+        assertErrorContains("${'x'?upper_casw}", "upper_case", "\\!upperCase");
+        // [2.4] If camel case will be the recommended style, then this need to be inverted:
+        assertErrorContains("${'x'?foo}", "upper_case", "\\!upperCase");
+        
+        assertErrorContains("<#if x><#elseIf y></#if> ${'x'?foo}", "upperCase", "\\!upper_case");
+        assertErrorContains("<#if x><#elseif y></#if>${'x'?foo}", "upper_case", "\\!upperCase");
+
+        setConfigurationToCamelCaseNamingConvention();
+        assertErrorContains("${'x'?foo}", "upperCase", "\\!upper_case");
+        setConfigurationToLegacyCaseNamingConvention();
+        assertErrorContains("${'x'?foo}", "upper_case", "\\!upperCase");
+    }
+
+    private void setConfigurationToCamelCaseNamingConvention() {
+        setConfiguration(new TestConfigurationBuilder()
+                .namingConvention(ParsingConfiguration.CAMEL_CASE_NAMING_CONVENTION)
+                .build());
+    }
+
+    @Test
+    public void builtInsHasBothNamingStyle() throws IOException, TemplateException {
+        assertContainsBothNamingStyles(getConfiguration().getSupportedBuiltInNames(), new NamePairAssertion() {
+
+            @Override
+            public void assertPair(String name1, String name2) {
+                ASTExpBuiltIn bi1  = ASTExpBuiltIn.BUILT_INS_BY_NAME.get(name1);
+                ASTExpBuiltIn bi2 = ASTExpBuiltIn.BUILT_INS_BY_NAME.get(name2);
+                assertTrue("\"" + name1 + "\" and \"" + name2 + "\" doesn't belong to the same BI object.",
+                        bi1 == bi2);
+            }
+            
+        });
+    }
+
+    private void assertContainsBothNamingStyles(Set<String> names, NamePairAssertion namePairAssertion) {
+        Set<String> underscoredNamesWithCamelCasePair = new HashSet<>();
+        for (String name : names) {
+            if (_StringUtil.getIdentifierNamingConvention(name) == ParsingConfiguration.CAMEL_CASE_NAMING_CONVENTION) {
+                String underscoredName = correctIsoBIExceptions(_StringUtil.camelCaseToUnderscored(name)); 
+                assertTrue(
+                        "Missing underscored variation \"" + underscoredName + "\" for \"" + name + "\".",
+                        names.contains(underscoredName));
+                assertTrue(underscoredNamesWithCamelCasePair.add(underscoredName));
+                
+                namePairAssertion.assertPair(name, underscoredName);
+            }
+        }
+        for (String name : names) {
+            if (_StringUtil.getIdentifierNamingConvention(name) == ParsingConfiguration.LEGACY_NAMING_CONVENTION) {
+                assertTrue("Missing camel case variation for \"" + name + "\".",
+                        underscoredNamesWithCamelCasePair.contains(name));
+            }
+        }
+    }
+    
+    private String correctIsoBIExceptions(String underscoredName) {
+        return underscoredName.replace("_n_z", "_nz").replace("_f_z", "_fz");
+    }
+    
+    @Test
+    public void camelCaseDirectives() throws IOException, TemplateException {
+        camelCaseDirectives(false);
+        setConfiguration(new TestConfigurationBuilder()
+                .tagSyntax(ParsingConfiguration.AUTO_DETECT_TAG_SYNTAX)
+                .build());
+        camelCaseDirectives(true);
+    }
+
+    private void camelCaseDirectives(boolean squared) throws IOException, TemplateException {
+        assertOutput(
+                squared("<#list 1..4 as x><#if x == 1>one <#elseIf x == 2>two <#elseIf x == 3>three "
+                        + "<#else>more</#if></#list>", squared),
+                "one two three more");
+        assertOutput(
+                squared("<#list 1..4 as x><#if x == 1>one <#elseif x == 2>two <#elseif x == 3>three "
+                        + "<#else>more</#if></#list>", squared),
+                "one two three more");
+        
+        assertOutput(
+                squared("<#escape x as x?upperCase>${'a'}<#noEscape>${'b'}</#noEscape></#escape>", squared),
+                "Ab");
+        assertOutput(
+                squared("<#escape x as x?upper_case>${'a'}<#noescape>${'b'}</#noescape></#escape>", squared),
+                "Ab");
+        
+        assertOutput(
+                squared("<#noParse></#noparse></#noParse>", squared),
+                squared("</#noparse>", squared));
+        assertOutput(
+                squared("<#noparse></#noParse></#noparse>", squared),
+                squared("</#noParse>", squared));
+    }
+    
+    private String squared(String ftl, boolean squared) {
+        return squared ? ftl.replace('<', '[').replace('>', ']') : ftl;
+    }
+
+    @Test
+    public void explicitNamingConvention() throws IOException, TemplateException {
+        explicitNamingConvention(false);
+        explicitNamingConvention(true);
+    }
+    
+    private void explicitNamingConvention(boolean squared) throws IOException, TemplateException {
+        int tagSyntax = squared ? ParsingConfiguration.AUTO_DETECT_TAG_SYNTAX
+                : ParsingConfiguration.ANGLE_BRACKET_TAG_SYNTAX;
+        setConfiguration(new TestConfigurationBuilder()
+                .tagSyntax(tagSyntax)
+                .namingConvention(ParsingConfiguration.CAMEL_CASE_NAMING_CONVENTION)
+                .build());
+
+        assertErrorContains(
+                squared("<#if true>t<#elseif false>f</#if>", squared),
+                "naming convention", "camel", "#elseif");
+        assertOutput(
+                squared("<#if true>t<#elseIf false>f</#if>", squared),
+                "t");
+        
+        assertErrorContains(
+                squared("<#noparse>${x}</#noparse>", squared),
+                "naming convention", "camel", "#noparse");
+        assertOutput(
+                squared("<#noParse>${x}</#noParse>", squared),
+                "${x}");
+        
+        assertErrorContains(
+                squared("<#escape x as -x><#noescape>${1}</#noescape></#escape>", squared),
+                "naming convention", "camel", "#noescape");
+        assertOutput(
+                squared("<#escape x as -x><#noEscape>${1}</#noEscape></#escape>", squared),
+                "1");
+
+        // ---
+
+        setConfiguration(new TestConfigurationBuilder()
+                .tagSyntax(tagSyntax)
+                .namingConvention(ParsingConfiguration.LEGACY_NAMING_CONVENTION)
+                .build());
+
+        assertErrorContains(
+                squared("<#if true>t<#elseIf false>f</#if>", squared),
+                "naming convention", "legacy", "#elseIf");
+        assertOutput(
+                squared("<#if true>t<#elseif false>f</#if>", squared),
+                "t");
+        
+        assertErrorContains(
+                squared("<#noParse>${x}</#noParse>", squared),
+                "naming convention", "legacy", "#noParse");
+        assertOutput(
+                squared("<#noparse>${x}</#noparse>", squared),
+                "${x}");
+        
+        assertErrorContains(
+                squared("<#escape x as -x><#noEscape>${1}</#noEscape></#escape>", squared),
+                "naming convention", "legacy", "#noEscape");
+        assertOutput(
+                squared("<#escape x as -x><#noescape>${1}</#noescape></#escape>", squared),
+                "1");
+    }
+    
+    @Test
+    public void inconsistentAutoDetectedNamingConvention() {
+        assertErrorContains(
+                "<#if x><#elseIf y><#elseif z></#if>",
+                "naming convention", "camel");
+        assertErrorContains(
+                "<#if x><#elseif y><#elseIf z></#if>",
+                "naming convention", "legacy");
+        assertErrorContains(
+                "<#if x><#elseIf y></#if><#noparse></#noparse>",
+                "naming convention", "camel");
+        assertErrorContains(
+                "<#if x><#elseif y></#if><#noParse></#noParse>",
+                "naming convention", "legacy");
+        assertErrorContains(
+                "<#if x><#elseif y><#elseIf z></#if>",
+                "naming convention", "legacy");
+        assertErrorContains(
+                "<#escape x as x + 1><#noEscape></#noescape></#escape>",
+                "naming convention", "camel");
+        assertErrorContains(
+                "<#escape x as x + 1><#noEscape></#noEscape><#noescape></#noescape></#escape>",
+                "naming convention", "camel");
+        assertErrorContains(
+                "<#escape x as x + 1><#noescape></#noEscape></#escape>",
+                "naming convention", "legacy");
+        assertErrorContains(
+                "<#escape x as x + 1><#noescape></#noescape><#noEscape></#noEscape></#escape>",
+                "naming convention", "legacy");
+
+        assertErrorContains("${x?upperCase?is_string}",
+                "naming convention", "camel", "upperCase", "is_string");
+        assertErrorContains("${x?upper_case?isString}",
+                "naming convention", "legacy", "upper_case", "isString");
+
+        assertErrorContains("<#setting outputEncoding='utf-8'>${x?is_string}",
+                "naming convention", "camel", "outputEncoding", "is_string");
+        assertErrorContains("<#setting output_encoding='utf-8'>${x?isString}",
+                "naming convention", "legacy", "output_encoding", "isString");
+        
+        assertErrorContains("${x?isString}<#setting output_encoding='utf-8'>",
+                "naming convention", "camel", "isString", "output_encoding");
+        assertErrorContains("${x?is_string}<#setting outputEncoding='utf-8'>",
+                "naming convention", "legacy", "is_string", "outputEncoding");
+        
+        assertErrorContains("${.outputEncoding}${x?is_string}",
+                "naming convention", "camel", "outputEncoding", "is_string");
+        assertErrorContains("${.output_encoding}${x?isString}",
+                "naming convention", "legacy", "output_encoding", "isString");
+        
+        assertErrorContains("${x?upperCase}<#noparse></#noparse>",
+                "naming convention", "camel", "upperCase", "noparse");
+        assertErrorContains("${x?upper_case}<#noParse></#noParse>",
+                "naming convention", "legacy", "upper_case", "noParse");
+    }
+    
+    private interface NamePairAssertion {
+        
+        void assertPair(String name1, String name2);
+        
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/CanonicalFormTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/CanonicalFormTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/CanonicalFormTest.java
new file mode 100644
index 0000000..fd1a5a5
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/CanonicalFormTest.java
@@ -0,0 +1,68 @@
+/*
+ * 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.StringWriter;
+
+import org.apache.freemarker.core.templateresolver.impl.ClassTemplateLoader;
+import org.apache.freemarker.test.CopyrightCommentRemoverTemplateLoader;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+import org.apache.freemarker.test.FileTestCase;
+
+public class CanonicalFormTest extends FileTestCase {
+
+    public CanonicalFormTest(String name) {
+        super(name);
+    }
+
+    public void testMacrosCanonicalForm() throws Exception {
+        assertCanonicalFormOf("cano-macros.ftl");
+    }
+    
+    public void testIdentifierEscapingCanonicalForm() throws Exception {
+        assertCanonicalFormOf("cano-identifier-escaping.ftl");
+    }
+
+    public void testAssignmentCanonicalForm() throws Exception {
+        assertCanonicalFormOf("cano-assignments.ftl");
+    }
+
+    public void testBuiltInCanonicalForm() throws Exception {
+        assertCanonicalFormOf("cano-builtins.ftl");
+    }
+
+    public void testStringLiteralInterpolationCanonicalForm() throws Exception {
+        assertCanonicalFormOf("cano-strlitinterpolation.ftl");
+    }
+    
+    private void assertCanonicalFormOf(String ftlFileName)
+            throws IOException {
+        Configuration cfg = new TestConfigurationBuilder()
+                .templateLoader(
+                        new CopyrightCommentRemoverTemplateLoader(
+                                new ClassTemplateLoader(CanonicalFormTest.class, "")))
+                .build();
+        StringWriter sw = new StringWriter();
+        cfg.getTemplate(ftlFileName).dump(sw);
+        assertExpectedFileEqualsString(ftlFileName + ".out", sw.toString());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/CoercionToTextualTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/CoercionToTextualTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/CoercionToTextualTest.java
new file mode 100644
index 0000000..91d3749
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/CoercionToTextualTest.java
@@ -0,0 +1,149 @@
+/*
+ * 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.util.Collections;
+import java.util.Date;
+
+import org.apache.freemarker.core.model.TemplateDateModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.impl.SimpleDate;
+import org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat;
+import org.apache.freemarker.core.userpkg.HTMLISOTemplateDateFormatFactory;
+import org.apache.freemarker.core.userpkg.PrintfGTemplateNumberFormatFactory;
+import org.apache.freemarker.core.valueformat.TemplateDateFormatFactory;
+import org.apache.freemarker.core.valueformat.TemplateNumberFormatFactory;
+import org.apache.freemarker.test.TemplateTest;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+import org.junit.Before;
+import org.junit.Test;
+
+@SuppressWarnings("boxing")
+public class CoercionToTextualTest extends TemplateTest {
+    
+    /** 2015-09-06T12:00:00Z */
+    private static long T = 1441540800000L;
+    private static TemplateDateModel TM = new SimpleDate(new Date(T), TemplateDateModel.DATETIME);
+    
+    @Test
+    public void testBasicStringBuiltins() throws IOException, TemplateException {
+        assertOutput("${s?upperCase}", "ABC");
+        assertOutput("${n?string?lowerCase}", "1.50e+03");
+        assertErrorContains("${n?lowerCase}", "convert", "string", "markup", "text/html");
+        assertOutput("${dt?string?lowerCase}", "2015-09-06t12:00:00z");
+        assertErrorContains("${dt?lowerCase}", "convert", "string", "markup", "text/html");
+        assertOutput("${b?upperCase}", "Y");
+        assertErrorContains("${m?upperCase}", "convertible to string", "HTMLOutputModel");
+    }
+
+    @Test
+    public void testEscBuiltin() throws IOException, TemplateException {
+        setConfiguration(createDefaultConfigurationBuilder()
+                .outputFormat(HTMLOutputFormat.INSTANCE)
+                .autoEscapingPolicy(ParsingConfiguration.DISABLE_AUTO_ESCAPING_POLICY)
+                .booleanFormat("<y>,<n>")
+                .build());
+        assertOutput("${'a<b'?esc}", "a&lt;b");
+        assertOutput("${n?string?esc}", "1.50E+03");
+        assertOutput("${n?esc}", "1.50*10<sup>3</sup>");
+        assertOutput("${dt?string?esc}", "2015-09-06T12:00:00Z");
+        assertOutput("${dt?esc}", "2015-09-06<span class='T'>T</span>12:00:00Z");
+        assertOutput("${b?esc}", "&lt;y&gt;");
+        assertOutput("${m?esc}", "<p>M</p>");
+    }
+    
+    @Test
+    public void testStringOverloadedBuiltIns() throws IOException, TemplateException {
+        assertOutput("${s?contains('b')}", "y");
+        assertOutput("${n?string?contains('E')}", "y");
+        assertErrorContains("${n?contains('E')}", "convert", "string", "markup", "text/html");
+        assertErrorContains("${n?indexOf('E')}", "convert", "string", "markup", "text/html");
+        assertOutput("${dt?string?contains('0')}", "y");
+        assertErrorContains("${dt?contains('0')}", "convert", "string", "markup", "text/html");
+        assertErrorContains("${m?contains('0')}", "convertible to string", "HTMLOutputModel");
+        assertErrorContains("${m?indexOf('0')}", "convertible to string", "HTMLOutputModel");
+    }
+    
+    @Test
+    public void testMarkupStringBuiltIns() throws IOException, TemplateException {
+        assertErrorContains("${n?string?markupString}", "Expected", "markup", "string");
+        assertErrorContains("${n?markupString}", "Expected", "markup", "number");
+        assertErrorContains("${dt?markupString}", "Expected", "markup", "date");
+    }
+    
+    @Test
+    public void testSimpleInterpolation() throws IOException, TemplateException {
+        assertOutput("${s}", "abc");
+        assertOutput("${n?string}", "1.50E+03");
+        assertOutput("${n}", "1.50*10<sup>3</sup>");
+        assertOutput("${dt?string}", "2015-09-06T12:00:00Z");
+        assertOutput("${dt}", "2015-09-06<span class='T'>T</span>12:00:00Z");
+        assertOutput("${b}", "y");
+        assertOutput("${m}", "<p>M</p>");
+    }
+    
+    @Test
+    public void testConcatenation() throws IOException, TemplateException {
+        assertOutput("${s + '&'}", "abc&");
+        assertOutput("${n?string + '&'}", "1.50E+03&");
+        assertOutput("${n + '&'}", "1.50*10<sup>3</sup>&amp;");
+        assertOutput("${dt?string + '&'}", "2015-09-06T12:00:00Z&");
+        assertOutput("${dt + '&'}", "2015-09-06<span class='T'>T</span>12:00:00Z&amp;");
+        assertOutput("${b + '&'}", "y&");
+        assertOutput("${m + '&'}", "<p>M</p>&amp;");
+    }
+
+    @Test
+    public void testConcatenation2() throws IOException, TemplateException {
+        assertOutput("${'&' + s}", "&abc");
+        assertOutput("${'&' + n?string}", "&1.50E+03");
+        assertOutput("${'&' + n}", "&amp;1.50*10<sup>3</sup>");
+        assertOutput("${'&' + dt?string}", "&2015-09-06T12:00:00Z");
+        assertOutput("${'&' + dt}", "&amp;2015-09-06<span class='T'>T</span>12:00:00Z");
+        assertOutput("${'&' + b}", "&y");
+        assertOutput("${'&' + m}", "&amp;<p>M</p>");
+    }
+
+    @Override
+    protected Configuration createDefaultConfiguration() throws Exception {
+        return createDefaultConfigurationBuilder().build();
+    }
+
+    private TestConfigurationBuilder createDefaultConfigurationBuilder() {
+        return new TestConfigurationBuilder()
+                .customNumberFormats(Collections.<String, TemplateNumberFormatFactory>singletonMap(
+                        "G", PrintfGTemplateNumberFormatFactory.INSTANCE))
+                .customDateFormats(Collections.<String, TemplateDateFormatFactory>singletonMap(
+                        "HI", HTMLISOTemplateDateFormatFactory.INSTANCE))
+                .numberFormat("@G 3")
+                .dateTimeFormat("@HI")
+                .booleanFormat("y,n");
+    }
+
+    @Before
+    public void setup() throws TemplateModelException {
+        addToDataModel("s", "abc");
+        addToDataModel("n", 1500);
+        addToDataModel("dt", TM);
+        addToDataModel("b", Boolean.TRUE);
+        addToDataModel("m", HTMLOutputFormat.INSTANCE.fromMarkup("<p>M</p>"));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/ConfigurableTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/ConfigurableTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ConfigurableTest.java
new file mode 100644
index 0000000..ebcc465
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ConfigurableTest.java
@@ -0,0 +1,176 @@
+/*
+ * 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.Field;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.freemarker.core.util._StringUtil;
+import org.junit.Test;
+
+public class ConfigurableTest {
+
+    @Test
+    public void testGetSettingNamesAreSorted() throws Exception {
+        MutableProcessingConfiguration cfgable = createConfigurable();
+        for (boolean camelCase : new boolean[] { false, true }) {
+            Collection<String> names = cfgable.getSettingNames(camelCase);
+            String prevName = null;
+            for (String name : names) {
+                if (prevName != null) {
+                    assertThat(name, greaterThan(prevName));
+                }
+                prevName = name;
+            }
+        }
+    }
+
+    @Test
+    public void testStaticFieldKeysCoverAllGetSettingNames() throws Exception {
+        MutableProcessingConfiguration cfgable = createConfigurable();
+        Collection<String> names = cfgable.getSettingNames(false);
+        for (String name : names) {
+                assertTrue("No field was found for " + name, keyFieldExists(name));
+        }
+    }
+    
+    @Test
+    public void testGetSettingNamesCoversAllStaticKeyFields() throws Exception {
+        MutableProcessingConfiguration cfgable = createConfigurable();
+        Collection<String> names = cfgable.getSettingNames(false);
+        
+        for (Field f : MutableProcessingConfiguration.class.getFields()) {
+            if (f.getName().endsWith("_KEY")) {
+                final Object name = f.get(null);
+                assertTrue("Missing setting name: " + name, names.contains(name));
+            }
+        }
+    }
+
+    @Test
+    public void testKeyStaticFieldsHasAllVariationsAndCorrectFormat() throws IllegalArgumentException, IllegalAccessException {
+        ConfigurableTest.testKeyStaticFieldsHasAllVariationsAndCorrectFormat(MutableProcessingConfiguration.class);
+    }
+    
+    @Test
+    public void testGetSettingNamesNameConventionsContainTheSame() throws Exception {
+        MutableProcessingConfiguration cfgable = createConfigurable();
+        ConfigurableTest.testGetSettingNamesNameConventionsContainTheSame(
+                new ArrayList<>(cfgable.getSettingNames(false)),
+                new ArrayList<>(cfgable.getSettingNames(true)));
+    }
+
+    public static void testKeyStaticFieldsHasAllVariationsAndCorrectFormat(
+            Class<? extends MutableProcessingConfiguration> confClass) throws IllegalArgumentException, IllegalAccessException {
+        // For all _KEY fields there must be a _KEY_CAMEL_CASE and a _KEY_SNAKE_CASE field.
+        // Their content must not contradict the expected naming convention.
+        // They _KEY filed value must be deducable from the field name
+        // The _KEY value must be the same as _KEY_SNAKE_CASE field.
+        // The _KEY_CAMEL_CASE converted to snake case must give the value of the _KEY_SNAKE_CASE.
+        for (Field field : confClass.getFields()) {
+            String fieldName = field.getName();
+            if (fieldName.endsWith("_KEY")) {
+                String keyFieldValue = (String) field.get(null);
+                assertNotEquals(ParsingConfiguration.CAMEL_CASE_NAMING_CONVENTION,
+                        _StringUtil.getIdentifierNamingConvention(keyFieldValue));
+                assertEquals(fieldName.substring(0, fieldName.length() - 4).toLowerCase(), keyFieldValue);
+                
+                try {
+                    String keySCFieldValue = (String) confClass.getField(fieldName + "_SNAKE_CASE").get(null);
+                    assertEquals(keyFieldValue, keySCFieldValue);
+                } catch (NoSuchFieldException e) {
+                    fail("Missing ..._SNAKE_CASE field for " + fieldName);
+                }
+                
+                try {
+                    String keyCCFieldValue = (String) confClass.getField(fieldName + "_CAMEL_CASE").get(null);
+                    assertNotEquals(ParsingConfiguration.LEGACY_NAMING_CONVENTION,
+                            _StringUtil.getIdentifierNamingConvention(keyCCFieldValue));
+                    assertEquals(keyFieldValue, _StringUtil.camelCaseToUnderscored(keyCCFieldValue));
+                } catch (NoSuchFieldException e) {
+                    fail("Missing ..._CAMEL_CASE field for " + fieldName);
+                }
+            }
+        }
+        
+        // For each _KEY_SNAKE_CASE field there must be a _KEY field.
+        for (Field field : confClass.getFields()) {
+            String fieldName = field.getName();
+            if (fieldName.endsWith("_KEY_SNAKE_CASE")) {
+                try {
+                    confClass.getField(fieldName.substring(0, fieldName.length() - 11)).get(null);
+                } catch (NoSuchFieldException e) {
+                    fail("Missing ..._KEY field for " + fieldName);
+                }
+            }
+        }
+        
+        // For each _KEY_CAMEL_CASE field there must be a _KEY field.
+        for (Field field : confClass.getFields()) {
+            String fieldName = field.getName();
+            if (fieldName.endsWith("_KEY_CAMEL_CASE")) {
+                try {
+                    confClass.getField(fieldName.substring(0, fieldName.length() - 11)).get(null);
+                } catch (NoSuchFieldException e) {
+                    fail("Missing ..._KEY field for " + fieldName);
+                }
+            }
+        }
+    }
+    
+    public static void testGetSettingNamesNameConventionsContainTheSame(List<String> namesSCList, List<String> namesCCList) {
+        Set<String> namesSC = new HashSet<>(namesSCList);
+        assertEquals(namesSCList.size(), namesSC.size());
+        
+        Set<String> namesCC = new HashSet<>(namesCCList);
+        assertEquals(namesCCList.size(), namesCC.size());
+
+        assertEquals(namesSC.size(), namesCC.size());
+        
+        for (String nameCC : namesCC) {
+            final String nameSC = _StringUtil.camelCaseToUnderscored(nameCC);
+            if (!namesSC.contains(nameSC)) {
+                fail("\"" + nameCC + "\" misses corresponding snake case name, \"" + nameSC + "\".");
+            }
+        }
+    }
+    
+    private MutableProcessingConfiguration createConfigurable() throws IOException {
+        return new TemplateConfiguration.Builder();
+    }
+
+    private boolean keyFieldExists(String name) throws Exception {
+        try {
+            MutableProcessingConfiguration.class.getField(name.toUpperCase() + "_KEY");
+        } catch (NoSuchFieldException e) {
+            return false;
+        }
+        return true;
+    }
+
+}


[23/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/CamelCaseTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/CamelCaseTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/CamelCaseTest.java
deleted file mode 100644
index 95572ad..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/CamelCaseTest.java
+++ /dev/null
@@ -1,486 +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;
-
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Locale;
-import java.util.Set;
-
-import org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat;
-import org.apache.freemarker.core.outputformat.impl.UndefinedOutputFormat;
-import org.apache.freemarker.core.util._StringUtil;
-import org.apache.freemarker.test.TemplateTest;
-import org.apache.freemarker.test.TestConfigurationBuilder;
-import org.junit.Test;
-
-public class CamelCaseTest extends TemplateTest {
-
-    @Test
-    public void camelCaseSpecialVars() throws IOException, TemplateException {
-        setConfiguration(new TestConfigurationBuilder()
-                .outputEncoding(StandardCharsets.UTF_8)
-                .urlEscapingCharset(StandardCharsets.ISO_8859_1)
-                .locale(Locale.GERMANY)
-                .build());
-        assertOutput("${.dataModel?isHash?c}", "true");
-        assertOutput("${.data_model?is_hash?c}", "true");
-        assertOutput("${.localeObject.toString()}", "de_DE");
-        assertOutput("${.locale_object.toString()}", "de_DE");
-        assertOutput("${.templateName!'null'}", "null");
-        assertOutput("${.template_name!'null'}", "null");
-        assertOutput("${.currentTemplateName!'null'}", "null");
-        assertOutput("${.current_template_name!'null'}", "null");
-        assertOutput("${.mainTemplateName!'null'}", "null");
-        assertOutput("${.main_template_name!'null'}", "null");
-        assertOutput("${.outputEncoding}", StandardCharsets.UTF_8.name());
-        assertOutput("${.output_encoding}", StandardCharsets.UTF_8.name());
-        assertOutput("${.outputFormat}", UndefinedOutputFormat.INSTANCE.getName());
-        assertOutput("${.output_format}", UndefinedOutputFormat.INSTANCE.getName());
-        assertOutput("${.urlEscapingCharset}", StandardCharsets.ISO_8859_1.name());
-        assertOutput("${.url_escaping_charset}", StandardCharsets.ISO_8859_1.name());
-        assertOutput("${.currentNode!'-'}", "-");
-        assertOutput("${.current_node!'-'}", "-");
-    }
-
-    @Test
-    public void camelCaseSpecialVarsInErrorMessage() throws IOException, TemplateException {
-        assertErrorContains("${.fooBar}", "dataModel", "\\!data_model");
-        assertErrorContains("${.foo_bar}", "data_model", "\\!dataModel");
-        // [2.4] If camel case will be the recommended style, then this need to be inverted:
-        assertErrorContains("${.foo}", "data_model", "\\!dataModel");
-        
-        assertErrorContains("<#if x><#elseIf y></#if>${.foo}", "dataModel", "\\!data_model");
-        assertErrorContains("<#if x><#elseif y></#if>${.foo}", "data_model", "\\!dataModel");
-
-        setConfigurationToCamelCaseNamingConvention();
-        assertErrorContains("${.foo}", "dataModel", "\\!data_model");
-
-        setConfigurationToLegacyCaseNamingConvention();
-        assertErrorContains("${.foo}", "data_model", "\\!dataModel");
-    }
-    
-    @Test
-    public void camelCaseSettingNames() throws IOException, TemplateException {
-        assertOutput("<#setting booleanFormat='Y,N'>${true} <#setting booleanFormat='+,-'>${true}", "Y +");
-        assertOutput("<#setting boolean_format='Y,N'>${true} <#setting boolean_format='+,-'>${true}", "Y +");
-        
-        // Still works inside ?interpret
-        assertOutput("<@r\"<#setting booleanFormat='Y,N'>${true}\"?interpret />", "Y");
-    }
-    
-    @Test
-    public void camelCaseFtlHeaderParameters() throws IOException, TemplateException {
-        assertOutput(
-                "<#ftl "
-                + "stripWhitespace=false "
-                + "stripText=true "
-                + "outputFormat='" + HTMLOutputFormat.INSTANCE.getName() + "' "
-                + "autoEsc=true "
-                + "nsPrefixes={} "
-                + ">\nx\n<#if true>\n${.outputFormat}\n</#if>\n",
-                "\nHTML\n");
-
-        assertOutput(
-                "<#ftl "
-                + "strip_whitespace=false "
-                + "strip_text=true "
-                + "output_format='" + HTMLOutputFormat.INSTANCE.getName() + "' "
-                + "auto_esc=true "
-                + "ns_prefixes={} "
-                + ">\nx\n<#if true>\n${.output_format}\n</#if>\n",
-                "\nHTML\n");
-
-        assertErrorContains("<#ftl strip_text=true xmlns={}>", "ns_prefixes", "\\!nsPrefixes");
-        assertErrorContains("<#ftl stripText=true xmlns={}>", "nsPrefixes");
-        
-        assertErrorContains("<#ftl stripWhitespace=true strip_text=true>", "naming convention");
-        assertErrorContains("<#ftl strip_whitespace=true stripText=true>", "naming convention");
-        assertErrorContains("<#ftl stripWhitespace=true>${.foo_bar}", "naming convention");
-        assertErrorContains("<#ftl strip_whitespace=true>${.fooBar}", "naming convention");
-
-        setConfiguration(new TestConfigurationBuilder()
-                .namingConvention(ParsingConfiguration.CAMEL_CASE_NAMING_CONVENTION)
-                .outputEncoding(StandardCharsets.UTF_8)
-                .build());
-        assertErrorContains("<#ftl strip_whitespace=true>", "naming convention");
-        assertOutput("<#ftl stripWhitespace=true>${.outputEncoding}", StandardCharsets.UTF_8.name());
-        
-        setConfiguration(new TestConfigurationBuilder()
-                .namingConvention(ParsingConfiguration.LEGACY_NAMING_CONVENTION)
-                .outputEncoding(StandardCharsets.UTF_8)
-                .build());
-        assertErrorContains("<#ftl stripWhitespace=true>", "naming convention");
-        assertOutput("<#ftl strip_whitespace=true>${.output_encoding}", StandardCharsets.UTF_8.name());
-        
-        setConfiguration(new TestConfigurationBuilder()
-                .namingConvention(ParsingConfiguration.AUTO_DETECT_NAMING_CONVENTION)
-                .outputEncoding(StandardCharsets.UTF_8)
-                .build());
-        assertOutput("<#ftl stripWhitespace=true>${.outputEncoding}", StandardCharsets.UTF_8.name());
-        assertOutput("<#ftl encoding='iso-8859-1' stripWhitespace=true>${.outputEncoding}", StandardCharsets.UTF_8.name());
-        assertOutput("<#ftl stripWhitespace=true encoding='iso-8859-1'>${.outputEncoding}", StandardCharsets.UTF_8.name());
-        assertOutput("<#ftl encoding='iso-8859-1' strip_whitespace=true>${.output_encoding}", StandardCharsets.UTF_8.name());
-        assertOutput("<#ftl strip_whitespace=true encoding='iso-8859-1'>${.output_encoding}", StandardCharsets.UTF_8.name());
-    }
-    
-    @Test
-    public void camelCaseSettingNamesInErrorMessages() throws IOException, TemplateException {
-        assertErrorContains("<#setting fooBar=1>", "booleanFormat", "\\!boolean_format");
-        assertErrorContains("<#setting foo_bar=1>", "boolean_format", "\\!booleanFormat");
-        // [2.4] If camel case will be the recommended style, then this need to be inverted:
-        assertErrorContains("<#setting foo=1>", "boolean_format", "\\!booleanFormat");
-
-        assertErrorContains("<#if x><#elseIf y></#if><#setting foo=1>", "booleanFormat", "\\!boolean_format");
-        assertErrorContains("<#if x><#elseif y></#if><#setting foo=1>", "boolean_format", "\\!booleanFormat");
-
-        setConfigurationToCamelCaseNamingConvention();
-        assertErrorContains("<#setting foo=1>", "booleanFormat", "\\!boolean_format");
-
-        setConfigurationToLegacyCaseNamingConvention();
-        assertErrorContains("<#setting foo=1>", "boolean_format", "\\!booleanFormat");
-    }
-    
-    @Test
-    public void camelCaseIncludeParameters() throws IOException, TemplateException {
-        assertOutput("<#ftl stripWhitespace=true>[<#include 'noSuchTemplate' ignoreMissing=true>]", "[]");
-        assertOutput("<#ftl strip_whitespace=true>[<#include 'noSuchTemplate' ignore_missing=true>]", "[]");
-        assertErrorContains("<#ftl stripWhitespace=true>[<#include 'noSuchTemplate' ignore_missing=true>]",
-                "naming convention", "ignore_missing");
-        assertErrorContains("<#ftl strip_whitespace=true>[<#include 'noSuchTemplate' ignoreMissing=true>]",
-                "naming convention", "ignoreMissing");
-    }
-    
-    @Test
-    public void specialVarsHasBothNamingStyle() throws IOException, TemplateException {
-        assertContainsBothNamingStyles(
-                new HashSet(Arrays.asList(ASTExpBuiltInVariable.SPEC_VAR_NAMES)),
-                new NamePairAssertion() { @Override
-                public void assertPair(String name1, String name2) { } });
-    }
-    
-    @Test
-    public void camelCaseBuiltIns() throws IOException, TemplateException {
-        assertOutput("${'x'?upperCase}", "X");
-        assertOutput("${'x'?upper_case}", "X");
-    }
-
-    @Test
-    public void stringLiteralInterpolation() throws IOException, TemplateException {
-        assertEquals(ParsingConfiguration.AUTO_DETECT_NAMING_CONVENTION, getConfiguration().getNamingConvention());
-        addToDataModel("x", "x");
-        
-        assertOutput("${'-${x?upperCase}-'} ${x?upperCase}", "-X- X");
-        assertOutput("${x?upperCase} ${'-${x?upperCase}-'}", "X -X-");
-        assertOutput("${'-${x?upper_case}-'} ${x?upper_case}", "-X- X");
-        assertOutput("${x?upper_case} ${'-${x?upper_case}-'}", "X -X-");
-
-        assertErrorContains("${'-${x?upper_case}-'} ${x?upperCase}",
-                "naming convention", "legacy", "upperCase", "detection", "9");
-        assertErrorContains("${x?upper_case} ${'-${x?upperCase}-'}",
-                "naming convention", "legacy", "upperCase", "detection", "5");
-        assertErrorContains("${'-${x?upperCase}-'} ${x?upper_case}",
-                "naming convention", "camel", "upper_case");
-        assertErrorContains("${x?upperCase} ${'-${x?upper_case}-'}",
-                "naming convention", "camel", "upper_case");
-
-        setConfigurationToCamelCaseNamingConvention();
-        assertOutput("${'-${x?upperCase}-'} ${x?upperCase}", "-X- X");
-        assertErrorContains("${'-${x?upper_case}-'}",
-                "naming convention", "camel", "upper_case", "\\!detection");
-
-        setConfigurationToLegacyCaseNamingConvention();
-        assertOutput("${'-${x?upper_case}-'} ${x?upper_case}", "-X- X");
-        assertErrorContains("${'-${x?upperCase}-'}",
-                "naming convention", "legacy", "upperCase", "\\!detection");
-    }
-    
-    @Test
-    public void evalAndInterpret() throws IOException, TemplateException {
-        assertEquals(ParsingConfiguration.AUTO_DETECT_NAMING_CONVENTION, getConfiguration().getNamingConvention());
-        // The naming convention detected doesn't affect the enclosing template's naming convention.
-        // - ?eval:
-        assertOutput("${\"'x'?upperCase\"?eval}${'x'?upper_case}", "XX");
-        assertOutput("${\"'x'?upper_case\"?eval}${'x'?upperCase}", "XX");
-        assertOutput("${'x'?upperCase}${\"'x'?upper_case\"?eval}", "XX");
-        assertErrorContains("${\"'x'\n?upperCase\n?is_string\"?eval}",
-                "naming convention", "camel", "upperCase", "is_string", "line 2", "line 3");
-        // - ?interpret:
-        assertOutput("<@r\"${'x'?upperCase}\"?interpret />${'x'?upper_case}", "XX");
-        assertOutput("<@r\"${'x'?upper_case}\"?interpret />${'x'?upperCase}", "XX");
-        assertOutput("${'x'?upper_case}<@r\"${'x'?upperCase}\"?interpret />", "XX");
-        assertErrorContains("<@r\"${'x'\n?upperCase\n?is_string}\"?interpret />",
-                "naming convention", "camel", "upperCase", "is_string", "line 2", "line 3");
-        
-        // Will be inherited by ?eval-ed/?interpreted fragments:
-        setConfigurationToCamelCaseNamingConvention();
-        // - ?eval:
-        assertErrorContains("${\"'x'?upper_case\"?eval}", "naming convention", "camel", "upper_case");
-        assertOutput("${\"'x'?upperCase\"?eval}", "X");
-        // - ?interpret:
-        assertErrorContains("<@r\"${'x'?upper_case}\"?interpret />", "naming convention", "camel", "upper_case");
-        assertOutput("<@r\"${'x'?upperCase}\"?interpret />", "X");
-        
-        // Again, will be inherited by ?eval-ed/?interpreted fragments:
-        setConfigurationToLegacyCaseNamingConvention();
-        // - ?eval:
-        assertErrorContains("${\"'x'?upperCase\"?eval}", "naming convention", "legacy", "upperCase");
-        assertOutput("${\"'x'?upper_case\"?eval}", "X");
-        // - ?interpret:
-        assertErrorContains("<@r\"${'x'?upperCase}\"?interpret />", "naming convention", "legacy", "upperCase");
-        assertOutput("<@r\"${'x'?upper_case}\"?interpret />", "X");
-    }
-
-    private void setConfigurationToLegacyCaseNamingConvention() {
-        setConfiguration(new TestConfigurationBuilder()
-                .namingConvention(ParsingConfiguration.LEGACY_NAMING_CONVENTION)
-                .build());
-    }
-
-    @Test
-    public void camelCaseBuiltInErrorMessage() throws IOException, TemplateException {
-        assertErrorContains("${'x'?upperCasw}", "upperCase", "\\!upper_case");
-        assertErrorContains("${'x'?upper_casw}", "upper_case", "\\!upperCase");
-        // [2.4] If camel case will be the recommended style, then this need to be inverted:
-        assertErrorContains("${'x'?foo}", "upper_case", "\\!upperCase");
-        
-        assertErrorContains("<#if x><#elseIf y></#if> ${'x'?foo}", "upperCase", "\\!upper_case");
-        assertErrorContains("<#if x><#elseif y></#if>${'x'?foo}", "upper_case", "\\!upperCase");
-
-        setConfigurationToCamelCaseNamingConvention();
-        assertErrorContains("${'x'?foo}", "upperCase", "\\!upper_case");
-        setConfigurationToLegacyCaseNamingConvention();
-        assertErrorContains("${'x'?foo}", "upper_case", "\\!upperCase");
-    }
-
-    private void setConfigurationToCamelCaseNamingConvention() {
-        setConfiguration(new TestConfigurationBuilder()
-                .namingConvention(ParsingConfiguration.CAMEL_CASE_NAMING_CONVENTION)
-                .build());
-    }
-
-    @Test
-    public void builtInsHasBothNamingStyle() throws IOException, TemplateException {
-        assertContainsBothNamingStyles(getConfiguration().getSupportedBuiltInNames(), new NamePairAssertion() {
-
-            @Override
-            public void assertPair(String name1, String name2) {
-                ASTExpBuiltIn bi1  = ASTExpBuiltIn.BUILT_INS_BY_NAME.get(name1);
-                ASTExpBuiltIn bi2 = ASTExpBuiltIn.BUILT_INS_BY_NAME.get(name2);
-                assertTrue("\"" + name1 + "\" and \"" + name2 + "\" doesn't belong to the same BI object.",
-                        bi1 == bi2);
-            }
-            
-        });
-    }
-
-    private void assertContainsBothNamingStyles(Set<String> names, NamePairAssertion namePairAssertion) {
-        Set<String> underscoredNamesWithCamelCasePair = new HashSet<>();
-        for (String name : names) {
-            if (_StringUtil.getIdentifierNamingConvention(name) == ParsingConfiguration.CAMEL_CASE_NAMING_CONVENTION) {
-                String underscoredName = correctIsoBIExceptions(_StringUtil.camelCaseToUnderscored(name)); 
-                assertTrue(
-                        "Missing underscored variation \"" + underscoredName + "\" for \"" + name + "\".",
-                        names.contains(underscoredName));
-                assertTrue(underscoredNamesWithCamelCasePair.add(underscoredName));
-                
-                namePairAssertion.assertPair(name, underscoredName);
-            }
-        }
-        for (String name : names) {
-            if (_StringUtil.getIdentifierNamingConvention(name) == ParsingConfiguration.LEGACY_NAMING_CONVENTION) {
-                assertTrue("Missing camel case variation for \"" + name + "\".",
-                        underscoredNamesWithCamelCasePair.contains(name));
-            }
-        }
-    }
-    
-    private String correctIsoBIExceptions(String underscoredName) {
-        return underscoredName.replace("_n_z", "_nz").replace("_f_z", "_fz");
-    }
-    
-    @Test
-    public void camelCaseDirectives() throws IOException, TemplateException {
-        camelCaseDirectives(false);
-        setConfiguration(new TestConfigurationBuilder()
-                .tagSyntax(ParsingConfiguration.AUTO_DETECT_TAG_SYNTAX)
-                .build());
-        camelCaseDirectives(true);
-    }
-
-    private void camelCaseDirectives(boolean squared) throws IOException, TemplateException {
-        assertOutput(
-                squared("<#list 1..4 as x><#if x == 1>one <#elseIf x == 2>two <#elseIf x == 3>three "
-                        + "<#else>more</#if></#list>", squared),
-                "one two three more");
-        assertOutput(
-                squared("<#list 1..4 as x><#if x == 1>one <#elseif x == 2>two <#elseif x == 3>three "
-                        + "<#else>more</#if></#list>", squared),
-                "one two three more");
-        
-        assertOutput(
-                squared("<#escape x as x?upperCase>${'a'}<#noEscape>${'b'}</#noEscape></#escape>", squared),
-                "Ab");
-        assertOutput(
-                squared("<#escape x as x?upper_case>${'a'}<#noescape>${'b'}</#noescape></#escape>", squared),
-                "Ab");
-        
-        assertOutput(
-                squared("<#noParse></#noparse></#noParse>", squared),
-                squared("</#noparse>", squared));
-        assertOutput(
-                squared("<#noparse></#noParse></#noparse>", squared),
-                squared("</#noParse>", squared));
-    }
-    
-    private String squared(String ftl, boolean squared) {
-        return squared ? ftl.replace('<', '[').replace('>', ']') : ftl;
-    }
-
-    @Test
-    public void explicitNamingConvention() throws IOException, TemplateException {
-        explicitNamingConvention(false);
-        explicitNamingConvention(true);
-    }
-    
-    private void explicitNamingConvention(boolean squared) throws IOException, TemplateException {
-        int tagSyntax = squared ? ParsingConfiguration.AUTO_DETECT_TAG_SYNTAX
-                : ParsingConfiguration.ANGLE_BRACKET_TAG_SYNTAX;
-        setConfiguration(new TestConfigurationBuilder()
-                .tagSyntax(tagSyntax)
-                .namingConvention(ParsingConfiguration.CAMEL_CASE_NAMING_CONVENTION)
-                .build());
-
-        assertErrorContains(
-                squared("<#if true>t<#elseif false>f</#if>", squared),
-                "naming convention", "camel", "#elseif");
-        assertOutput(
-                squared("<#if true>t<#elseIf false>f</#if>", squared),
-                "t");
-        
-        assertErrorContains(
-                squared("<#noparse>${x}</#noparse>", squared),
-                "naming convention", "camel", "#noparse");
-        assertOutput(
-                squared("<#noParse>${x}</#noParse>", squared),
-                "${x}");
-        
-        assertErrorContains(
-                squared("<#escape x as -x><#noescape>${1}</#noescape></#escape>", squared),
-                "naming convention", "camel", "#noescape");
-        assertOutput(
-                squared("<#escape x as -x><#noEscape>${1}</#noEscape></#escape>", squared),
-                "1");
-
-        // ---
-
-        setConfiguration(new TestConfigurationBuilder()
-                .tagSyntax(tagSyntax)
-                .namingConvention(ParsingConfiguration.LEGACY_NAMING_CONVENTION)
-                .build());
-
-        assertErrorContains(
-                squared("<#if true>t<#elseIf false>f</#if>", squared),
-                "naming convention", "legacy", "#elseIf");
-        assertOutput(
-                squared("<#if true>t<#elseif false>f</#if>", squared),
-                "t");
-        
-        assertErrorContains(
-                squared("<#noParse>${x}</#noParse>", squared),
-                "naming convention", "legacy", "#noParse");
-        assertOutput(
-                squared("<#noparse>${x}</#noparse>", squared),
-                "${x}");
-        
-        assertErrorContains(
-                squared("<#escape x as -x><#noEscape>${1}</#noEscape></#escape>", squared),
-                "naming convention", "legacy", "#noEscape");
-        assertOutput(
-                squared("<#escape x as -x><#noescape>${1}</#noescape></#escape>", squared),
-                "1");
-    }
-    
-    @Test
-    public void inconsistentAutoDetectedNamingConvention() {
-        assertErrorContains(
-                "<#if x><#elseIf y><#elseif z></#if>",
-                "naming convention", "camel");
-        assertErrorContains(
-                "<#if x><#elseif y><#elseIf z></#if>",
-                "naming convention", "legacy");
-        assertErrorContains(
-                "<#if x><#elseIf y></#if><#noparse></#noparse>",
-                "naming convention", "camel");
-        assertErrorContains(
-                "<#if x><#elseif y></#if><#noParse></#noParse>",
-                "naming convention", "legacy");
-        assertErrorContains(
-                "<#if x><#elseif y><#elseIf z></#if>",
-                "naming convention", "legacy");
-        assertErrorContains(
-                "<#escape x as x + 1><#noEscape></#noescape></#escape>",
-                "naming convention", "camel");
-        assertErrorContains(
-                "<#escape x as x + 1><#noEscape></#noEscape><#noescape></#noescape></#escape>",
-                "naming convention", "camel");
-        assertErrorContains(
-                "<#escape x as x + 1><#noescape></#noEscape></#escape>",
-                "naming convention", "legacy");
-        assertErrorContains(
-                "<#escape x as x + 1><#noescape></#noescape><#noEscape></#noEscape></#escape>",
-                "naming convention", "legacy");
-
-        assertErrorContains("${x?upperCase?is_string}",
-                "naming convention", "camel", "upperCase", "is_string");
-        assertErrorContains("${x?upper_case?isString}",
-                "naming convention", "legacy", "upper_case", "isString");
-
-        assertErrorContains("<#setting outputEncoding='utf-8'>${x?is_string}",
-                "naming convention", "camel", "outputEncoding", "is_string");
-        assertErrorContains("<#setting output_encoding='utf-8'>${x?isString}",
-                "naming convention", "legacy", "output_encoding", "isString");
-        
-        assertErrorContains("${x?isString}<#setting output_encoding='utf-8'>",
-                "naming convention", "camel", "isString", "output_encoding");
-        assertErrorContains("${x?is_string}<#setting outputEncoding='utf-8'>",
-                "naming convention", "legacy", "is_string", "outputEncoding");
-        
-        assertErrorContains("${.outputEncoding}${x?is_string}",
-                "naming convention", "camel", "outputEncoding", "is_string");
-        assertErrorContains("${.output_encoding}${x?isString}",
-                "naming convention", "legacy", "output_encoding", "isString");
-        
-        assertErrorContains("${x?upperCase}<#noparse></#noparse>",
-                "naming convention", "camel", "upperCase", "noparse");
-        assertErrorContains("${x?upper_case}<#noParse></#noParse>",
-                "naming convention", "legacy", "upper_case", "noParse");
-    }
-    
-    private interface NamePairAssertion {
-        
-        void assertPair(String name1, String name2);
-        
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/CanonicalFormTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/CanonicalFormTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/CanonicalFormTest.java
deleted file mode 100644
index c78c90e..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/CanonicalFormTest.java
+++ /dev/null
@@ -1,68 +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;
-
-import java.io.IOException;
-import java.io.StringWriter;
-
-import org.apache.freemarker.core.templateresolver.impl.ClassTemplateLoader;
-import org.apache.freemarker.test.CopyrightCommentRemoverTemplateLoader;
-import org.apache.freemarker.test.TestConfigurationBuilder;
-import org.apache.freemarker.test.util.FileTestCase;
-
-public class CanonicalFormTest extends FileTestCase {
-
-    public CanonicalFormTest(String name) {
-        super(name);
-    }
-
-    public void testMacrosCanonicalForm() throws Exception {
-        assertCanonicalFormOf("cano-macros.ftl");
-    }
-    
-    public void testIdentifierEscapingCanonicalForm() throws Exception {
-        assertCanonicalFormOf("cano-identifier-escaping.ftl");
-    }
-
-    public void testAssignmentCanonicalForm() throws Exception {
-        assertCanonicalFormOf("cano-assignments.ftl");
-    }
-
-    public void testBuiltInCanonicalForm() throws Exception {
-        assertCanonicalFormOf("cano-builtins.ftl");
-    }
-
-    public void testStringLiteralInterpolationCanonicalForm() throws Exception {
-        assertCanonicalFormOf("cano-strlitinterpolation.ftl");
-    }
-    
-    private void assertCanonicalFormOf(String ftlFileName)
-            throws IOException {
-        Configuration cfg = new TestConfigurationBuilder()
-                .templateLoader(
-                        new CopyrightCommentRemoverTemplateLoader(
-                                new ClassTemplateLoader(CanonicalFormTest.class, "")))
-                .build();
-        StringWriter sw = new StringWriter();
-        cfg.getTemplate(ftlFileName).dump(sw);
-        assertExpectedFileEqualsString(ftlFileName + ".out", sw.toString());
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/CoercionToTextualTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/CoercionToTextualTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/CoercionToTextualTest.java
deleted file mode 100644
index 91d3749..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/CoercionToTextualTest.java
+++ /dev/null
@@ -1,149 +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;
-
-import java.io.IOException;
-import java.util.Collections;
-import java.util.Date;
-
-import org.apache.freemarker.core.model.TemplateDateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.impl.SimpleDate;
-import org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat;
-import org.apache.freemarker.core.userpkg.HTMLISOTemplateDateFormatFactory;
-import org.apache.freemarker.core.userpkg.PrintfGTemplateNumberFormatFactory;
-import org.apache.freemarker.core.valueformat.TemplateDateFormatFactory;
-import org.apache.freemarker.core.valueformat.TemplateNumberFormatFactory;
-import org.apache.freemarker.test.TemplateTest;
-import org.apache.freemarker.test.TestConfigurationBuilder;
-import org.junit.Before;
-import org.junit.Test;
-
-@SuppressWarnings("boxing")
-public class CoercionToTextualTest extends TemplateTest {
-    
-    /** 2015-09-06T12:00:00Z */
-    private static long T = 1441540800000L;
-    private static TemplateDateModel TM = new SimpleDate(new Date(T), TemplateDateModel.DATETIME);
-    
-    @Test
-    public void testBasicStringBuiltins() throws IOException, TemplateException {
-        assertOutput("${s?upperCase}", "ABC");
-        assertOutput("${n?string?lowerCase}", "1.50e+03");
-        assertErrorContains("${n?lowerCase}", "convert", "string", "markup", "text/html");
-        assertOutput("${dt?string?lowerCase}", "2015-09-06t12:00:00z");
-        assertErrorContains("${dt?lowerCase}", "convert", "string", "markup", "text/html");
-        assertOutput("${b?upperCase}", "Y");
-        assertErrorContains("${m?upperCase}", "convertible to string", "HTMLOutputModel");
-    }
-
-    @Test
-    public void testEscBuiltin() throws IOException, TemplateException {
-        setConfiguration(createDefaultConfigurationBuilder()
-                .outputFormat(HTMLOutputFormat.INSTANCE)
-                .autoEscapingPolicy(ParsingConfiguration.DISABLE_AUTO_ESCAPING_POLICY)
-                .booleanFormat("<y>,<n>")
-                .build());
-        assertOutput("${'a<b'?esc}", "a&lt;b");
-        assertOutput("${n?string?esc}", "1.50E+03");
-        assertOutput("${n?esc}", "1.50*10<sup>3</sup>");
-        assertOutput("${dt?string?esc}", "2015-09-06T12:00:00Z");
-        assertOutput("${dt?esc}", "2015-09-06<span class='T'>T</span>12:00:00Z");
-        assertOutput("${b?esc}", "&lt;y&gt;");
-        assertOutput("${m?esc}", "<p>M</p>");
-    }
-    
-    @Test
-    public void testStringOverloadedBuiltIns() throws IOException, TemplateException {
-        assertOutput("${s?contains('b')}", "y");
-        assertOutput("${n?string?contains('E')}", "y");
-        assertErrorContains("${n?contains('E')}", "convert", "string", "markup", "text/html");
-        assertErrorContains("${n?indexOf('E')}", "convert", "string", "markup", "text/html");
-        assertOutput("${dt?string?contains('0')}", "y");
-        assertErrorContains("${dt?contains('0')}", "convert", "string", "markup", "text/html");
-        assertErrorContains("${m?contains('0')}", "convertible to string", "HTMLOutputModel");
-        assertErrorContains("${m?indexOf('0')}", "convertible to string", "HTMLOutputModel");
-    }
-    
-    @Test
-    public void testMarkupStringBuiltIns() throws IOException, TemplateException {
-        assertErrorContains("${n?string?markupString}", "Expected", "markup", "string");
-        assertErrorContains("${n?markupString}", "Expected", "markup", "number");
-        assertErrorContains("${dt?markupString}", "Expected", "markup", "date");
-    }
-    
-    @Test
-    public void testSimpleInterpolation() throws IOException, TemplateException {
-        assertOutput("${s}", "abc");
-        assertOutput("${n?string}", "1.50E+03");
-        assertOutput("${n}", "1.50*10<sup>3</sup>");
-        assertOutput("${dt?string}", "2015-09-06T12:00:00Z");
-        assertOutput("${dt}", "2015-09-06<span class='T'>T</span>12:00:00Z");
-        assertOutput("${b}", "y");
-        assertOutput("${m}", "<p>M</p>");
-    }
-    
-    @Test
-    public void testConcatenation() throws IOException, TemplateException {
-        assertOutput("${s + '&'}", "abc&");
-        assertOutput("${n?string + '&'}", "1.50E+03&");
-        assertOutput("${n + '&'}", "1.50*10<sup>3</sup>&amp;");
-        assertOutput("${dt?string + '&'}", "2015-09-06T12:00:00Z&");
-        assertOutput("${dt + '&'}", "2015-09-06<span class='T'>T</span>12:00:00Z&amp;");
-        assertOutput("${b + '&'}", "y&");
-        assertOutput("${m + '&'}", "<p>M</p>&amp;");
-    }
-
-    @Test
-    public void testConcatenation2() throws IOException, TemplateException {
-        assertOutput("${'&' + s}", "&abc");
-        assertOutput("${'&' + n?string}", "&1.50E+03");
-        assertOutput("${'&' + n}", "&amp;1.50*10<sup>3</sup>");
-        assertOutput("${'&' + dt?string}", "&2015-09-06T12:00:00Z");
-        assertOutput("${'&' + dt}", "&amp;2015-09-06<span class='T'>T</span>12:00:00Z");
-        assertOutput("${'&' + b}", "&y");
-        assertOutput("${'&' + m}", "&amp;<p>M</p>");
-    }
-
-    @Override
-    protected Configuration createDefaultConfiguration() throws Exception {
-        return createDefaultConfigurationBuilder().build();
-    }
-
-    private TestConfigurationBuilder createDefaultConfigurationBuilder() {
-        return new TestConfigurationBuilder()
-                .customNumberFormats(Collections.<String, TemplateNumberFormatFactory>singletonMap(
-                        "G", PrintfGTemplateNumberFormatFactory.INSTANCE))
-                .customDateFormats(Collections.<String, TemplateDateFormatFactory>singletonMap(
-                        "HI", HTMLISOTemplateDateFormatFactory.INSTANCE))
-                .numberFormat("@G 3")
-                .dateTimeFormat("@HI")
-                .booleanFormat("y,n");
-    }
-
-    @Before
-    public void setup() throws TemplateModelException {
-        addToDataModel("s", "abc");
-        addToDataModel("n", 1500);
-        addToDataModel("dt", TM);
-        addToDataModel("b", Boolean.TRUE);
-        addToDataModel("m", HTMLOutputFormat.INSTANCE.fromMarkup("<p>M</p>"));
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/ConfigurableTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/ConfigurableTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/ConfigurableTest.java
deleted file mode 100644
index ebcc465..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/ConfigurableTest.java
+++ /dev/null
@@ -1,176 +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;
-
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import org.apache.freemarker.core.util._StringUtil;
-import org.junit.Test;
-
-public class ConfigurableTest {
-
-    @Test
-    public void testGetSettingNamesAreSorted() throws Exception {
-        MutableProcessingConfiguration cfgable = createConfigurable();
-        for (boolean camelCase : new boolean[] { false, true }) {
-            Collection<String> names = cfgable.getSettingNames(camelCase);
-            String prevName = null;
-            for (String name : names) {
-                if (prevName != null) {
-                    assertThat(name, greaterThan(prevName));
-                }
-                prevName = name;
-            }
-        }
-    }
-
-    @Test
-    public void testStaticFieldKeysCoverAllGetSettingNames() throws Exception {
-        MutableProcessingConfiguration cfgable = createConfigurable();
-        Collection<String> names = cfgable.getSettingNames(false);
-        for (String name : names) {
-                assertTrue("No field was found for " + name, keyFieldExists(name));
-        }
-    }
-    
-    @Test
-    public void testGetSettingNamesCoversAllStaticKeyFields() throws Exception {
-        MutableProcessingConfiguration cfgable = createConfigurable();
-        Collection<String> names = cfgable.getSettingNames(false);
-        
-        for (Field f : MutableProcessingConfiguration.class.getFields()) {
-            if (f.getName().endsWith("_KEY")) {
-                final Object name = f.get(null);
-                assertTrue("Missing setting name: " + name, names.contains(name));
-            }
-        }
-    }
-
-    @Test
-    public void testKeyStaticFieldsHasAllVariationsAndCorrectFormat() throws IllegalArgumentException, IllegalAccessException {
-        ConfigurableTest.testKeyStaticFieldsHasAllVariationsAndCorrectFormat(MutableProcessingConfiguration.class);
-    }
-    
-    @Test
-    public void testGetSettingNamesNameConventionsContainTheSame() throws Exception {
-        MutableProcessingConfiguration cfgable = createConfigurable();
-        ConfigurableTest.testGetSettingNamesNameConventionsContainTheSame(
-                new ArrayList<>(cfgable.getSettingNames(false)),
-                new ArrayList<>(cfgable.getSettingNames(true)));
-    }
-
-    public static void testKeyStaticFieldsHasAllVariationsAndCorrectFormat(
-            Class<? extends MutableProcessingConfiguration> confClass) throws IllegalArgumentException, IllegalAccessException {
-        // For all _KEY fields there must be a _KEY_CAMEL_CASE and a _KEY_SNAKE_CASE field.
-        // Their content must not contradict the expected naming convention.
-        // They _KEY filed value must be deducable from the field name
-        // The _KEY value must be the same as _KEY_SNAKE_CASE field.
-        // The _KEY_CAMEL_CASE converted to snake case must give the value of the _KEY_SNAKE_CASE.
-        for (Field field : confClass.getFields()) {
-            String fieldName = field.getName();
-            if (fieldName.endsWith("_KEY")) {
-                String keyFieldValue = (String) field.get(null);
-                assertNotEquals(ParsingConfiguration.CAMEL_CASE_NAMING_CONVENTION,
-                        _StringUtil.getIdentifierNamingConvention(keyFieldValue));
-                assertEquals(fieldName.substring(0, fieldName.length() - 4).toLowerCase(), keyFieldValue);
-                
-                try {
-                    String keySCFieldValue = (String) confClass.getField(fieldName + "_SNAKE_CASE").get(null);
-                    assertEquals(keyFieldValue, keySCFieldValue);
-                } catch (NoSuchFieldException e) {
-                    fail("Missing ..._SNAKE_CASE field for " + fieldName);
-                }
-                
-                try {
-                    String keyCCFieldValue = (String) confClass.getField(fieldName + "_CAMEL_CASE").get(null);
-                    assertNotEquals(ParsingConfiguration.LEGACY_NAMING_CONVENTION,
-                            _StringUtil.getIdentifierNamingConvention(keyCCFieldValue));
-                    assertEquals(keyFieldValue, _StringUtil.camelCaseToUnderscored(keyCCFieldValue));
-                } catch (NoSuchFieldException e) {
-                    fail("Missing ..._CAMEL_CASE field for " + fieldName);
-                }
-            }
-        }
-        
-        // For each _KEY_SNAKE_CASE field there must be a _KEY field.
-        for (Field field : confClass.getFields()) {
-            String fieldName = field.getName();
-            if (fieldName.endsWith("_KEY_SNAKE_CASE")) {
-                try {
-                    confClass.getField(fieldName.substring(0, fieldName.length() - 11)).get(null);
-                } catch (NoSuchFieldException e) {
-                    fail("Missing ..._KEY field for " + fieldName);
-                }
-            }
-        }
-        
-        // For each _KEY_CAMEL_CASE field there must be a _KEY field.
-        for (Field field : confClass.getFields()) {
-            String fieldName = field.getName();
-            if (fieldName.endsWith("_KEY_CAMEL_CASE")) {
-                try {
-                    confClass.getField(fieldName.substring(0, fieldName.length() - 11)).get(null);
-                } catch (NoSuchFieldException e) {
-                    fail("Missing ..._KEY field for " + fieldName);
-                }
-            }
-        }
-    }
-    
-    public static void testGetSettingNamesNameConventionsContainTheSame(List<String> namesSCList, List<String> namesCCList) {
-        Set<String> namesSC = new HashSet<>(namesSCList);
-        assertEquals(namesSCList.size(), namesSC.size());
-        
-        Set<String> namesCC = new HashSet<>(namesCCList);
-        assertEquals(namesCCList.size(), namesCC.size());
-
-        assertEquals(namesSC.size(), namesCC.size());
-        
-        for (String nameCC : namesCC) {
-            final String nameSC = _StringUtil.camelCaseToUnderscored(nameCC);
-            if (!namesSC.contains(nameSC)) {
-                fail("\"" + nameCC + "\" misses corresponding snake case name, \"" + nameSC + "\".");
-            }
-        }
-    }
-    
-    private MutableProcessingConfiguration createConfigurable() throws IOException {
-        return new TemplateConfiguration.Builder();
-    }
-
-    private boolean keyFieldExists(String name) throws Exception {
-        try {
-            MutableProcessingConfiguration.class.getField(name.toUpperCase() + "_KEY");
-        } catch (NoSuchFieldException e) {
-            return false;
-        }
-        return true;
-    }
-
-}



[12/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/TypeFlagsTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/TypeFlagsTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/TypeFlagsTest.java
deleted file mode 100644
index fe11d1c..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/TypeFlagsTest.java
+++ /dev/null
@@ -1,671 +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.model.impl;
-
-import java.io.File;
-import java.lang.reflect.Method;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.freemarker.core.Configuration;
-
-import junit.framework.TestCase;
-
-public class TypeFlagsTest extends TestCase {
-
-    public TypeFlagsTest(String name) {
-        super(name);
-    }
-    
-    private final DefaultObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
-
-    public void testSingleNumType() {
-        checkTypeFlags(SingleNumTypeC.class, "mInt",
-                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER,
-                TypeFlags.INTEGER | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER
-                | TypeFlags.ACCEPTS_STRING);
-        checkTypeFlags(SingleNumTypeC.class, "mLong",
-                TypeFlags.LONG | TypeFlags.ACCEPTS_NUMBER);
-        checkTypeFlags(SingleNumTypeC.class, "mShort",
-                TypeFlags.SHORT | TypeFlags.ACCEPTS_NUMBER);
-        checkTypeFlags(SingleNumTypeC.class, "mByte",
-                TypeFlags.BYTE | TypeFlags.ACCEPTS_NUMBER,
-                TypeFlags.ACCEPTS_ANY_OBJECT);
-        checkTypeFlags(SingleNumTypeC.class, "mDouble",
-                TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER);
-        checkTypeFlags(SingleNumTypeC.class, "mFloat",
-                TypeFlags.FLOAT | TypeFlags.ACCEPTS_NUMBER);
-        checkTypeFlags(SingleNumTypeC.class, "mUnknown",
-                TypeFlags.UNKNOWN_NUMERICAL_TYPE | TypeFlags.ACCEPTS_NUMBER);
-        
-        checkTypeFlags(SingleNumTypeC.class, "mVarParamCnt",
-                TypeFlags.BIG_DECIMAL | TypeFlags.ACCEPTS_NUMBER);
-        checkTypeFlags(SingleNumTypeC.class, "mVarParamCnt",
-                TypeFlags.BIG_INTEGER | TypeFlags.ACCEPTS_NUMBER,
-                TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER);
-        checkTypeFlags(SingleNumTypeC.class, "mVarParamCnt",
-                TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER,
-                TypeFlags.FLOAT | TypeFlags.ACCEPTS_NUMBER,
-                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER);
-    }
-    
-    static public class SingleNumTypeC {
-        public void mInt(int a1, String a2) { }
-        public void mInt(int a1, int a2) { }
-        public void mLong(long a1) { }
-        public void mLong(Long a1) { }
-        public void mShort(short a1) { }
-        public void mByte(byte a1, boolean a2) { }
-        public void mByte(byte a1, String a2) { }
-        public void mByte(byte a1, Object a2) { }
-        public void mDouble(double a1) { }
-        public void mFloat(float a1) { }
-        public void mUnknown(RationalNumber a1) { };
-        
-        public void mVarParamCnt(BigDecimal a1) { }
-        public void mVarParamCnt(BigInteger a1, Double a2) { }
-        public void mVarParamCnt(Double a1,     Float a2, Integer a3) { }
-        public void mVarParamCnt(Object a1,     char a2,  boolean a3, File a4, Map a5,    Boolean a6) { }
-        public void mVarParamCnt(Long a1,       int a2,   short a3,   byte a4, double a5, float a6) { }
-    }
-
-    public void testMultipleNumTypes() {
-        checkTypeFlags(MultiNumTypeC.class, "m1",
-                TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT 
-                | TypeFlags.BYTE | TypeFlags.DOUBLE | TypeFlags.INTEGER
-                | TypeFlags.ACCEPTS_NUMBER
-                );
-        
-        checkTypeFlags(MultiNumTypeC.class, "m2",
-                TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT 
-                | TypeFlags.SHORT | TypeFlags.LONG | TypeFlags.FLOAT
-                | TypeFlags.ACCEPTS_NUMBER | TypeFlags.CHARACTER
-                );
-
-        checkTypeFlags(MultiNumTypeC.class, "m3",
-                TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT 
-                | TypeFlags.BIG_DECIMAL | TypeFlags.BIG_INTEGER
-                | TypeFlags.ACCEPTS_NUMBER,
-                TypeFlags.BIG_INTEGER | TypeFlags.ACCEPTS_NUMBER,
-                TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT
-                | TypeFlags.BIG_DECIMAL | TypeFlags.UNKNOWN_NUMERICAL_TYPE
-                | TypeFlags.ACCEPTS_NUMBER
-                );
-        
-        checkTypeFlags(MultiNumTypeC.class, "m4",
-                TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.FLOAT | TypeFlags.ACCEPTS_NUMBER
-                | TypeFlags.CHARACTER
-                );
-        
-        checkTypeFlags(MultiNumTypeC.class, "m5",
-                TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT
-                | TypeFlags.FLOAT | TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER
-                );
-        
-        checkTypeFlags(MultiNumTypeC.class, "m6",
-                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER
-                );
-        assertSame(getTypeFlags(MultiNumTypeC.class, "m6", false, 2), OverloadedMethodsSubset.ALL_ZEROS_ARRAY);
-        assertSame(getTypeFlags(MultiNumTypeC.class, "m6", true, 2), OverloadedMethodsSubset.ALL_ZEROS_ARRAY);
-        assertSame(getTypeFlags(MultiNumTypeC.class, "m6", false, 3), OverloadedMethodsSubset.ALL_ZEROS_ARRAY);
-        assertSame(getTypeFlags(MultiNumTypeC.class, "m6", true, 3), OverloadedMethodsSubset.ALL_ZEROS_ARRAY);
-        checkTypeFlags(MultiNumTypeC.class, "m6",
-                TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER,
-                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER,
-                TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER,
-                0
-                );
-    }
-    
-    static public class MultiNumTypeC {
-        public void m1(byte a1) { };
-        public void m1(int a1) { };
-        public void m1(double a2) { };
-        
-        public void m2(short a1) { };
-        public void m2(long a1) { };
-        public void m2(float a1) { };
-        public void m2(char a1) { };
-        
-        public void m3(BigInteger a1, BigInteger a2, BigDecimal a3) { };
-        public void m3(BigDecimal a1, BigInteger a2, RationalNumber a3) { };
-        
-        public void m4(float a1) { };
-        public void m4(char a1) { };
-        
-        public void m5(Float a1) { };
-        public void m5(Double a1) { };
-        public void m5(Enum a1) { };
-        
-        public void m6(int a1) { };
-        public void m6(File a1, Throwable a2) { };
-        public void m6(File a1, Throwable a2, StringBuilder a3) { };
-        public void m6(File a1, Throwable a2, Throwable a3) { };
-        public void m6(double a1, int a2, File a3, File a4) { };
-        public void m6(File a1, int a2, double a3, File a4) { };
-    }
-
-    public void testVarargsNums() {
-        checkTypeFlags(VarArgsC.class, "m1",
-                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER
-                );
-        checkTypeFlags(VarArgsC.class, "m2",
-                TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER,
-                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER
-                );
-        
-        checkTypeFlags(VarArgsC.class, "m3",
-                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER
-                );
-        checkTypeFlags(VarArgsC.class, "m3",
-                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER,
-                TypeFlags.DOUBLE | TypeFlags.INTEGER
-                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER
-                );
-        checkTypeFlags(VarArgsC.class, "m3",
-                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER,
-                TypeFlags.DOUBLE | TypeFlags.INTEGER
-                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER,
-                TypeFlags.DOUBLE | TypeFlags.INTEGER
-                | TypeFlags.BIG_DECIMAL | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER
-                );
-        
-        checkTypeFlags(VarArgsC.class, "m4",
-                TypeFlags.INTEGER | TypeFlags.LONG
-                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER
-                );
-        
-        checkTypeFlags(VarArgsC.class, "m5",
-                TypeFlags.LONG | TypeFlags.ACCEPTS_NUMBER
-                );
-        
-        checkTypeFlags(VarArgsC.class, "m6",
-                TypeFlags.LONG | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER
-                | TypeFlags.ACCEPTS_STRING
-                );
-        
-        checkTypeFlags(VarArgsC.class, "m7",
-                TypeFlags.INTEGER | TypeFlags.BYTE
-                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER,
-                TypeFlags.DOUBLE | TypeFlags.FLOAT
-                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER
-                );
-
-        checkTypeFlags(VarArgsC.class, "m8",
-                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER,
-                TypeFlags.DOUBLE | TypeFlags.FLOAT
-                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER
-                );
-        
-        checkTypeFlags(VarArgsC.class, "m9",
-                TypeFlags.INTEGER | TypeFlags.BYTE
-                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER,
-                TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER
-                );
-        
-        checkTypeFlags(VarArgsC.class, "m10",
-                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER,
-                TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER
-                );
-        checkTypeFlags(VarArgsC.class, "m10",
-                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER,
-                TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER,
-                TypeFlags.LONG | TypeFlags.DOUBLE
-                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER
-                );
-        
-        checkTypeFlags(VarArgsC.class, "m11",
-                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER,
-                TypeFlags.DOUBLE | TypeFlags.SHORT | TypeFlags.ACCEPTS_NUMBER
-                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER
-                );
-        checkTypeFlags(VarArgsC.class, "m11",
-                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER,
-                TypeFlags.DOUBLE | TypeFlags.SHORT
-                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER,
-                TypeFlags.LONG | TypeFlags.DOUBLE
-                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER
-                );
-        
-        checkTypeFlags(VarArgsC.class, "m12",
-                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER,
-                TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER
-                );
-        checkTypeFlags(VarArgsC.class, "m12",
-                TypeFlags.INTEGER | TypeFlags.ACCEPTS_NUMBER,
-                TypeFlags.DOUBLE | TypeFlags.SHORT
-                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER,
-                TypeFlags.DOUBLE | TypeFlags.BYTE
-                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER,
-                TypeFlags.LONG | TypeFlags.DOUBLE
-                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER
-                );
-        
-        checkTypeFlags(VarArgsC.class, "m13",
-                TypeFlags.CHARACTER,
-                TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER);
-        checkTypeFlags(VarArgsC.class, "m13",
-                TypeFlags.CHARACTER,
-                TypeFlags.DOUBLE | TypeFlags.ACCEPTS_NUMBER,
-                TypeFlags.DOUBLE | TypeFlags.UNKNOWN_NUMERICAL_TYPE
-                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER,
-                TypeFlags.DOUBLE | TypeFlags.LONG
-                | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT | TypeFlags.ACCEPTS_NUMBER
-                );
-    }
-    
-    static public class VarArgsC {
-        public void m1(int... va) { }
-        
-        public void m2(double a1, int... va) { }
-        
-        public void m3(int... va) { }
-        public void m3(int a1, double... va) { }
-        public void m3(int a1, double a2, BigDecimal... va) { }
-        
-        public void m4(int... va) { }
-        public void m4(long... va) { }
-
-        public void m5(Long... va) { }
-        public void m5(long... va) { }
-        
-        public void m6(long... va) { }
-        public void m6(String... va) { }
-        
-        public void m7(int a1, double... va) { }
-        public void m7(byte a1, float... va) { }
-
-        public void m8(int a1, double... va) { }
-        public void m8(int a1, float... va) { }
-        
-        public void m9(int a1, double... va) { }
-        public void m9(byte a1, double... va) { }
-        
-        public void m10(int a1, double a2, long... va) { }
-        public void m10(int a1, double... va) { }
-        
-        public void m11(int a1, short a2, long... va) { }
-        public void m11(int a1, double... va) { }
-        
-        public void m12(int a1, short a2, byte a3, long... va) { }
-        public void m12(int a1, double... va) { }
-        
-        public void m13(char a1, double a2, RationalNumber a3, Long... va) { }
-        public void m13(char a1, Double... va) { }
-    }
-    
-    public void testAllZeros() {
-        for (boolean reverse : new boolean[] { true, false }) {
-            assertSame(OverloadedMethodsSubset.ALL_ZEROS_ARRAY, getTypeFlags(AllZeroC.class, "m1", reverse, 0));
-            assertSame(OverloadedMethodsSubset.ALL_ZEROS_ARRAY, getTypeFlags(AllZeroC.class, "m2", reverse, 2));
-            assertSame(OverloadedMethodsSubset.ALL_ZEROS_ARRAY, getTypeFlags(AllZeroC.class, "m3", reverse, 1));
-        }
-    }
-    
-    static public class AllZeroC {
-        public void m1() {}
-        
-        public void m2(File a1, File a2) {}
-        
-        public void m3(File a1) {}
-        public void m3(StringBuilder a1) {}
-    }
-
-    public void testAcceptanceNonOverloaded() {
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber1",  TypeFlags.ACCEPTS_NUMBER | TypeFlags.UNKNOWN_NUMERICAL_TYPE);
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber2",  TypeFlags.ACCEPTS_NUMBER | TypeFlags.BYTE);
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber3",  TypeFlags.ACCEPTS_NUMBER | TypeFlags.BYTE);
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber4",  TypeFlags.ACCEPTS_NUMBER | TypeFlags.SHORT);
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber5",  TypeFlags.ACCEPTS_NUMBER | TypeFlags.SHORT);
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber6",  TypeFlags.ACCEPTS_NUMBER | TypeFlags.INTEGER);
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber7",  TypeFlags.ACCEPTS_NUMBER | TypeFlags.INTEGER);
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber8",  TypeFlags.ACCEPTS_NUMBER | TypeFlags.LONG);
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber9",  TypeFlags.ACCEPTS_NUMBER | TypeFlags.LONG);
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber10", TypeFlags.ACCEPTS_NUMBER | TypeFlags.FLOAT);
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber11", TypeFlags.ACCEPTS_NUMBER | TypeFlags.FLOAT);
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber12", TypeFlags.ACCEPTS_NUMBER | TypeFlags.DOUBLE);
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber13", TypeFlags.ACCEPTS_NUMBER | TypeFlags.DOUBLE);
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber14", TypeFlags.ACCEPTS_NUMBER | TypeFlags.BIG_INTEGER);
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber15", TypeFlags.ACCEPTS_NUMBER | TypeFlags.BIG_DECIMAL);
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mNumber16", TypeFlags.ACCEPTS_NUMBER | TypeFlags.UNKNOWN_NUMERICAL_TYPE);
-        
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mDate", TypeFlags.ACCEPTS_DATE);
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mSQLDate1", 0);
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mSQLDate2", 0);
-        
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mString", TypeFlags.ACCEPTS_STRING);
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mCharSequence", TypeFlags.ACCEPTS_STRING);
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mStringBuilder", 0);
-        
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mBool", TypeFlags.ACCEPTS_BOOLEAN);
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mBoolean", TypeFlags.ACCEPTS_BOOLEAN);
-        
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mMap1", TypeFlags.ACCEPTS_MAP);
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mMap2", 0);
-        
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mList1", TypeFlags.ACCEPTS_LIST);
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mList2", 0);
-        
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mSet1", TypeFlags.ACCEPTS_SET);
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mSet2", 0);
-        
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mCollection", TypeFlags.ACCEPTS_SET | TypeFlags.ACCEPTS_LIST);
-        
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mChar1", TypeFlags.CHARACTER);
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mChar2", TypeFlags.CHARACTER);
-        
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mArray1", TypeFlags.ACCEPTS_ARRAY);
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mArray2", TypeFlags.ACCEPTS_ARRAY);
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mArray3", TypeFlags.ACCEPTS_ARRAY);
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mArray4", TypeFlags.ACCEPTS_ARRAY);
-        
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mObject", TypeFlags.ACCEPTS_ANY_OBJECT);
-        assertTrue((TypeFlags.ACCEPTS_ANY_OBJECT & TypeFlags.ACCEPTS_NUMBER) != 0);
-        assertTrue((TypeFlags.ACCEPTS_ANY_OBJECT & TypeFlags.ACCEPTS_STRING) != 0);
-        assertTrue((TypeFlags.ACCEPTS_ANY_OBJECT & TypeFlags.ACCEPTS_BOOLEAN) != 0);
-        assertTrue((TypeFlags.ACCEPTS_ANY_OBJECT & TypeFlags.ACCEPTS_MAP) != 0);
-        assertTrue((TypeFlags.ACCEPTS_ANY_OBJECT & TypeFlags.ACCEPTS_LIST) != 0);
-        assertTrue((TypeFlags.ACCEPTS_ANY_OBJECT & TypeFlags.ACCEPTS_SET) != 0);
-        assertTrue((TypeFlags.ACCEPTS_ANY_OBJECT & TypeFlags.ACCEPTS_ARRAY) != 0);
-        assertTrue((TypeFlags.ACCEPTS_ANY_OBJECT & TypeFlags.CHARACTER) == 0);  // deliberatly 0 
-        
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mMapDate", 0);
-        
-        checkTypeFlags(AcceptanceNonoverloadedC.class, "mDateBooleanList",
-                TypeFlags.ACCEPTS_DATE, TypeFlags.ACCEPTS_BOOLEAN, TypeFlags.ACCEPTS_LIST);
-    }
-    
-    static public class AcceptanceNonoverloadedC {
-        public void mNumber1(Number a1) {}
-        public void mNumber2(Byte a1) {}
-        public void mNumber3(byte a1) {}
-        public void mNumber4(Short a1) {}
-        public void mNumber5(short a1) {}
-        public void mNumber6(Integer a1) {}
-        public void mNumber7(int a1) {}
-        public void mNumber8(Long a1) {}
-        public void mNumber9(long a1) {}
-        public void mNumber10(Float a1) {}
-        public void mNumber11(float a1) {}
-        public void mNumber12(Double a1) {}
-        public void mNumber13(double a1) {}
-        public void mNumber14(BigInteger a1) {}
-        public void mNumber15(BigDecimal a1) {}
-        public void mNumber16(RationalNumber a1) {}
-        
-        public void mDate(Date a1) {}
-        public void mSQLDate1(java.sql.Date a1) {}
-        public void mSQLDate2(java.sql.Timestamp a1) {}
-        
-        public void mString(String a1) {}
-        public void mCharSequence(CharSequence a1) {}
-        public void mStringBuilder(StringBuilder a1) {}
-        
-        public void mBool(boolean a1) {}
-        public void mBoolean(Boolean a1) {}
-
-        public void mMap1(Map a1) {}
-        public void mMap2(LinkedHashMap a1) {}
-        
-        public void mList1(List a1) {}
-        public void mList2(ArrayList a1) {}
-        
-        public void mSet1(Set a1) {}
-        public void mSet2(HashSet a1) {}
-        
-        public void mCollection(Collection a1) {}
-        
-        public void mMapDate(MapDate a1) {}
-
-        public void mChar1(Character a1) {}
-        public void mChar2(char a1) {}
-
-        public void mArray1(Object[] a1) {}
-        public void mArray2(int[] a1) {}
-        public void mArray3(Integer[] a1) {}
-        public void mArray4(Void[] a1) {}
-        
-        public void mObject(Object a1) {}
-        
-        public void mDateBooleanList(Date a1, boolean a2, List a3) {}
-    }
-
-    public void testAcceptanceOverloaded() {
-        checkTypeFlags(AcceptanceOverloadedC.class, "mLongDateList",
-                TypeFlags.ACCEPTS_NUMBER | TypeFlags.LONG | TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT
-                | TypeFlags.ACCEPTS_DATE | TypeFlags.ACCEPTS_LIST);
-        checkTypeFlags(AcceptanceOverloadedC.class, "mBoolean", TypeFlags.ACCEPTS_BOOLEAN);
-        checkTypeFlags(AcceptanceOverloadedC.class, "mStringChar",
-                TypeFlags.ACCEPTS_STRING | TypeFlags.CHARACTER);
-        checkTypeFlags(AcceptanceOverloadedC.class, "mStringFile", TypeFlags.ACCEPTS_STRING);
-        checkTypeFlags(AcceptanceOverloadedC.class, "mMapObject", TypeFlags.ACCEPTS_ANY_OBJECT);
-        checkTypeFlags(AcceptanceOverloadedC.class, "mSetMap", TypeFlags.ACCEPTS_MAP | TypeFlags.ACCEPTS_SET);
-        checkTypeFlags(AcceptanceOverloadedC.class, "mCollectionMap",
-                TypeFlags.ACCEPTS_MAP | TypeFlags.ACCEPTS_SET | TypeFlags.ACCEPTS_LIST);
-        checkTypeFlags(AcceptanceOverloadedC.class, "mArray", TypeFlags.ACCEPTS_ARRAY);
-        checkTypeFlags(AcceptanceOverloadedC.class, "mArrayList", TypeFlags.ACCEPTS_ARRAY | TypeFlags.ACCEPTS_LIST);
-        
-        checkTypeFlags(AcceptanceOverloadedC.class, "mStringCollectionThenBooleanThenMapList",
-                TypeFlags.ACCEPTS_STRING | TypeFlags.ACCEPTS_LIST | TypeFlags.ACCEPTS_SET,
-                TypeFlags.ACCEPTS_BOOLEAN,
-                TypeFlags.ACCEPTS_MAP | TypeFlags.ACCEPTS_LIST);
-    }
-    
-    static public class AcceptanceOverloadedC {
-        public void mLongDateList(long a1) {}
-        public void mLongDateList(Date a1) {}
-        public void mLongDateList(List a1) {}
-
-        public void mBoolean(boolean a1) {}
-        public void mBoolean(Boolean a1) {}
-        
-        public void mDate(Date a1) {}
-        public void mDate(java.sql.Date a1) {}
-        public void mDate(java.sql.Timestamp a1) {}
-        
-        public void mStringChar(String a1) {}
-        public void mStringChar(char a1) {}
-        public void mStringChar(Character a1) {}
-
-        public void mStringFile(String a1) {}
-        public void mStringFile(File a1) {}
-        
-        public void mMapObject(Map a1) {}
-        public void mMapObject(Object a1) {}
-        
-        public void mSetMap(Set a1) {}
-        public void mSetMap(Map a1) {}
-        
-        public void mCollectionMap(Collection a1) {}
-        public void mCollectionMap(Map a1) {}
-        
-        public void mArray(Object[] a1) {}
-        public void mArray(int[] a1) {}
-        public void mArray(Integer[] a1) {}
-        public void mArray(Void[] a1) {}
-        
-        public void mArrayList(String[] a1) {}
-        public void mArrayList(List a1) {}
-        
-        public void mStringCollectionThenBooleanThenMapList(String a1, boolean a2, Map a3) {}
-        public void mStringCollectionThenBooleanThenMapList(Collection a1, boolean a2, Map a3) {}
-        public void mStringCollectionThenBooleanThenMapList(String a1, boolean a2, List a3) {}
-    }
-
-    public void testAcceptanceVarargsC() {
-        checkTypeFlags(AcceptanceVarArgsC.class, "m1",
-                TypeFlags.ACCEPTS_LIST | TypeFlags.ACCEPTS_STRING);
-        
-        checkTypeFlags(AcceptanceVarArgsC.class, "m2",
-                TypeFlags.ACCEPTS_MAP,
-                TypeFlags.ACCEPTS_MAP | TypeFlags.ACCEPTS_STRING | TypeFlags.ACCEPTS_BOOLEAN,
-                TypeFlags.ACCEPTS_MAP | TypeFlags.ACCEPTS_STRING);
-        checkTypeFlags(AcceptanceVarArgsC.class, "m2",
-                TypeFlags.ACCEPTS_MAP,
-                TypeFlags.ACCEPTS_MAP | TypeFlags.ACCEPTS_STRING | TypeFlags.ACCEPTS_BOOLEAN);
-        checkTypeFlags(AcceptanceVarArgsC.class, "m2",
-                TypeFlags.ACCEPTS_MAP);
-        
-        checkTypeFlags(AcceptanceVarArgsC.class, "m3",
-                TypeFlags.ACCEPTS_BOOLEAN);
-        checkTypeFlags(AcceptanceVarArgsC.class, "m3",
-                TypeFlags.ACCEPTS_BOOLEAN | TypeFlags.ACCEPTS_STRING,
-                TypeFlags.ACCEPTS_BOOLEAN | TypeFlags.ACCEPTS_MAP,
-                TypeFlags.ACCEPTS_BOOLEAN | TypeFlags.CHARACTER,
-                TypeFlags.ACCEPTS_BOOLEAN);
-    }
-    
-    static public class AcceptanceVarArgsC {
-        public void m1(List... a1) {}
-        public void m1(String... a1) {}
-
-        public void m2(Map a1, String... a2) {}
-        public void m2(Map a1, boolean a2, String... a3) {}
-        public void m2(Map... a1) {}
-        
-        public void m3(String a1, Map a2, char a3, Boolean... a4) {}
-        public void m3(boolean... a1) {}
-    }
-
-    static public class MapDate extends Date implements Map {
-    
-        @Override
-        public int size() {
-            return 0;
-        }
-    
-        @Override
-        public boolean isEmpty() {
-            return false;
-        }
-    
-        @Override
-        public boolean containsKey(Object key) {
-            return false;
-        }
-    
-        @Override
-        public boolean containsValue(Object value) {
-            return false;
-        }
-    
-        @Override
-        public Object get(Object key) {
-            return null;
-        }
-    
-        @Override
-        public Object put(Object key, Object value) {
-            return null;
-        }
-    
-        @Override
-        public Object remove(Object key) {
-            return null;
-        }
-    
-        @Override
-        public void putAll(Map m) {
-        }
-    
-        @Override
-        public void clear() {
-        }
-    
-        @Override
-        public Set keySet() {
-            return null;
-        }
-    
-        @Override
-        public Collection values() {
-            return null;
-        }
-    
-        @Override
-        public Set entrySet() {
-            return null;
-        }
-        
-    }
-
-    private OverloadedMethodsSubset newOverloadedMethodsSubset(Class cl, String methodName, final boolean desc) {
-        final Method[] ms = cl.getMethods();
-        
-        final List<Method> filteredMethods = new ArrayList();
-        for (Method m : ms) {
-            if (m.getName().equals(methodName)) {
-                filteredMethods.add(m);
-            }
-        }
-        // As the order in which getMethods() returns the methods is undefined, we sort them for test predictability: 
-        Collections.sort(filteredMethods, new Comparator<Method>() {
-            @Override
-            public int compare(Method o1, Method o2) {
-                int res = o1.toString().compareTo(o2.toString());
-                return desc ? -res : res;
-            }
-        });
-        
-        final OverloadedMethodsSubset oms = cl.getName().indexOf("VarArgs") == -1
-                ? new OverloadedFixArgsMethods() : new OverloadedVarArgsMethods();
-        for (Method m : filteredMethods) {
-            oms.addCallableMemberDescriptor(new ReflectionCallableMemberDescriptor(m, m.getParameterTypes()));
-        }
-        return oms;
-    }
-    
-    private void checkTypeFlags(Class cl, String methodName, int... expectedTypeFlags) {
-        checkTypeFlags(cl, methodName, false, expectedTypeFlags);
-        checkTypeFlags(cl, methodName, true, expectedTypeFlags);
-    }
-    
-    private void checkTypeFlags(Class cl, String methodName, boolean revMetOrder, int... expectedTypeFlags) {
-        int[] actualParamTypes = getTypeFlags(cl, methodName, revMetOrder, expectedTypeFlags.length);
-        assertNotNull("Method " + methodName + "(#" + expectedTypeFlags.length + ") doesn't exist", actualParamTypes);
-        if (actualParamTypes != OverloadedMethodsSubset.ALL_ZEROS_ARRAY) {
-            assertEquals(expectedTypeFlags.length, actualParamTypes.length);
-            for (int i = 0; i < expectedTypeFlags.length; i++) {
-                assertEquals(expectedTypeFlags[i], actualParamTypes[i]);
-            }
-        } else {
-            for (int expectedTypeFlag : expectedTypeFlags) {
-                assertEquals(expectedTypeFlag, 0);
-            }
-        }
-    }
-
-    private int[] getTypeFlags(Class cl, String methodName, boolean revMetOrder, int paramCnt) {
-        OverloadedMethodsSubset oms = newOverloadedMethodsSubset(cl, methodName, revMetOrder);
-        int[] actualParamTypes = oms.getTypeFlags(paramCnt);
-        return actualParamTypes;
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/outputformat/_OutputFormatTestAPI.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/outputformat/_OutputFormatTestAPI.java b/freemarker-core/src/test/java/org/apache/freemarker/core/outputformat/_OutputFormatTestAPI.java
deleted file mode 100644
index 0a479aa..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/outputformat/_OutputFormatTestAPI.java
+++ /dev/null
@@ -1,35 +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.outputformat;
-
-public final class _OutputFormatTestAPI {
-
-    private _OutputFormatTestAPI() {
-        //
-    }
-    
-    public static String getMarkupContent(CommonTemplateMarkupOutputModel<?> tm) {
-        return tm.getMarkupContent();
-    }
-    
-    public static String getPlainTextContent(CommonTemplateMarkupOutputModel<?> tm) {
-        return tm.getPlainTextContent();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/outputformat/impl/CombinedMarkupOutputFormatTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/outputformat/impl/CombinedMarkupOutputFormatTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/outputformat/impl/CombinedMarkupOutputFormatTest.java
deleted file mode 100644
index 19e45de..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/outputformat/impl/CombinedMarkupOutputFormatTest.java
+++ /dev/null
@@ -1,194 +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.outputformat.impl;
-
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.io.StringWriter;
-
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.outputformat.MarkupOutputFormat;
-import org.apache.freemarker.core.outputformat._OutputFormatTestAPI;
-import org.junit.Test; 
-
-public class CombinedMarkupOutputFormatTest {
-    
-    private static final CombinedMarkupOutputFormat HTML_RTF = new CombinedMarkupOutputFormat(
-            HTMLOutputFormat.INSTANCE, RTFOutputFormat.INSTANCE);
-    private static final CombinedMarkupOutputFormat XML_XML = new CombinedMarkupOutputFormat(
-            XMLOutputFormat.INSTANCE, XMLOutputFormat.INSTANCE);
-
-    @Test
-    public void testName() {
-        assertEquals("HTML{RTF}", HTML_RTF.getName());
-        assertEquals("XML{XML}", XML_XML.getName());
-    }
-    
-    @Test
-    public void testOutputMO() throws TemplateModelException, IOException {
-       StringWriter out = new StringWriter();
-       
-       HTML_RTF.output(HTML_RTF.fromMarkup("<pre>\\par Test "), out);
-       HTML_RTF.output(HTML_RTF.fromPlainTextByEscaping("foo { bar } \\ "), out);
-       HTML_RTF.output(HTML_RTF.fromPlainTextByEscaping("& baaz "), out);
-       HTML_RTF.output(HTML_RTF.fromPlainTextByEscaping("\\par & qwe"), out);
-       HTML_RTF.output(HTML_RTF.fromMarkup("\\par{0} End</pre>"), out);
-       
-       assertEquals(
-               "<pre>\\par Test "
-               + "foo \\{ bar \\} \\\\ "
-               + "&amp; baaz "
-               + "\\\\par &amp; qwe"
-               + "\\par{0} End</pre>",
-               out.toString());
-    }
-
-    @Test
-    public void testOutputMO2() throws TemplateModelException, IOException {
-       StringWriter out = new StringWriter();
-       
-       XML_XML.output(XML_XML.fromMarkup("<pre>&lt;p&gt; Test "), out);
-       XML_XML.output(XML_XML.fromPlainTextByEscaping("a & b < c"), out);
-       XML_XML.output(XML_XML.fromMarkup(" End</pre>"), out);
-       
-       assertEquals(
-               "<pre>&lt;p&gt; Test "
-               + "a &amp;amp; b &amp;lt; c"
-               + " End</pre>",
-               out.toString());
-    }
-
-    @Test
-    public void testOutputMO3() throws TemplateModelException, IOException {
-        MarkupOutputFormat outputFormat = new CombinedMarkupOutputFormat(
-                RTFOutputFormat.INSTANCE,
-                new CombinedMarkupOutputFormat(RTFOutputFormat.INSTANCE, RTFOutputFormat.INSTANCE));
-        StringWriter out = new StringWriter();
-        
-        outputFormat.output(outputFormat.fromPlainTextByEscaping("b{}"), out);
-        outputFormat.output(outputFormat.fromMarkup("a{}"), out);
-        
-        assertEquals(
-                "b\\\\\\\\\\\\\\{\\\\\\\\\\\\\\}"
-                + "a{}",
-                out.toString());
-    }
-    
-    @Test
-    public void testOutputString() throws TemplateModelException, IOException {
-        StringWriter out = new StringWriter();
-        
-        HTML_RTF.output("a", out);
-        HTML_RTF.output("{", out);
-        HTML_RTF.output("<b>}c", out);
-        
-        assertEquals("a\\{&lt;b&gt;\\}c", out.toString());
-    }
-    
-    @Test
-    public void testOutputString2() throws TemplateModelException, IOException {
-        StringWriter out = new StringWriter();
-        
-        XML_XML.output("a", out);
-        XML_XML.output("&", out);
-        XML_XML.output("<b>", out);
-        
-        assertEquals("a&amp;amp;&amp;lt;b&amp;gt;", out.toString());
-    }
-    
-    @Test
-    public void testFromPlainTextByEscaping() throws TemplateModelException {
-        String plainText = "a\\b&c";
-        TemplateCombinedMarkupOutputModel mo = HTML_RTF.fromPlainTextByEscaping(plainText);
-        assertSame(plainText, _OutputFormatTestAPI.getPlainTextContent(mo));
-        assertNull(_OutputFormatTestAPI.getMarkupContent(mo)); // Not the MO's duty to calculate it!
-    }
-
-    @Test
-    public void testFromMarkup() throws TemplateModelException {
-        String markup = "a \\par <b>";
-        TemplateCombinedMarkupOutputModel mo = HTML_RTF.fromMarkup(markup);
-        assertSame(markup, _OutputFormatTestAPI.getMarkupContent(mo));
-        assertNull(_OutputFormatTestAPI.getPlainTextContent(mo)); // Not the MO's duty to calculate it!
-    }
-    
-    @Test
-    public void testGetMarkup() throws TemplateModelException {
-        {
-            String markup = "a \\par <b>";
-            TemplateCombinedMarkupOutputModel mo = HTML_RTF.fromMarkup(markup);
-            assertSame(markup, HTML_RTF.getMarkupString(mo));
-        }
-        
-        {
-            String safe = "abc";
-            TemplateCombinedMarkupOutputModel mo = HTML_RTF.fromPlainTextByEscaping(safe);
-            assertSame(safe, HTML_RTF.getMarkupString(mo));
-        }
-    }
-    
-    @Test
-    public void testConcat() throws Exception {
-        assertMO(
-                "ab", null,
-                HTML_RTF.concat(
-                        new TemplateCombinedMarkupOutputModel("a", null, HTML_RTF),
-                        new TemplateCombinedMarkupOutputModel("b", null, HTML_RTF)));
-        assertMO(
-                null, "ab",
-                HTML_RTF.concat(
-                        new TemplateCombinedMarkupOutputModel(null, "a", HTML_RTF),
-                        new TemplateCombinedMarkupOutputModel(null, "b", HTML_RTF)));
-        assertMO(
-                null, "{<a>}\\{&lt;b&gt;\\}",
-                HTML_RTF.concat(
-                        new TemplateCombinedMarkupOutputModel(null, "{<a>}", HTML_RTF),
-                        new TemplateCombinedMarkupOutputModel("{<b>}", null, HTML_RTF)));
-        assertMO(
-                null, "\\{&lt;a&gt;\\}{<b>}",
-                HTML_RTF.concat(
-                        new TemplateCombinedMarkupOutputModel("{<a>}", null, HTML_RTF),
-                        new TemplateCombinedMarkupOutputModel(null, "{<b>}", HTML_RTF)));
-    }
-    
-    @Test
-    public void testEscaplePlainText() throws TemplateModelException {
-        assertEquals("", HTML_RTF.escapePlainText(""));
-        assertEquals("a", HTML_RTF.escapePlainText("a"));
-        assertEquals("\\{a\\\\b&amp;\\}", HTML_RTF.escapePlainText("{a\\b&}"));
-        assertEquals("a\\\\b&amp;", HTML_RTF.escapePlainText("a\\b&"));
-        assertEquals("\\{\\}&amp;", HTML_RTF.escapePlainText("{}&"));
-        
-        assertEquals("a", XML_XML.escapePlainText("a"));
-        assertEquals("a&amp;apos;b", XML_XML.escapePlainText("a'b"));
-    }
-    
-    private void assertMO(String pc, String mc, TemplateCombinedMarkupOutputModel mo) {
-        assertEquals(pc, _OutputFormatTestAPI.getPlainTextContent(mo));
-        assertEquals(mc, _OutputFormatTestAPI.getMarkupContent(mo));
-    }
-    
-    @Test
-    public void testGetMimeType() {
-        assertEquals("text/html", HTML_RTF.getMimeType());
-        assertEquals("application/xml", XML_XML.getMimeType());
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/outputformat/impl/HTMLOutputFormatTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/outputformat/impl/HTMLOutputFormatTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/outputformat/impl/HTMLOutputFormatTest.java
deleted file mode 100644
index 2199179..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/outputformat/impl/HTMLOutputFormatTest.java
+++ /dev/null
@@ -1,187 +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.outputformat.impl;
-
-import static org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat.*;
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.io.StringWriter;
-
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.outputformat.CommonMarkupOutputFormat;
-import org.apache.freemarker.core.outputformat._OutputFormatTestAPI;
-import org.junit.Test; 
-
-/**
- * This actually more a {@link CommonMarkupOutputFormat} test.
- */
-public class HTMLOutputFormatTest {
-    
-    @Test
-    public void testOutputMO() throws TemplateModelException, IOException {
-       StringWriter out = new StringWriter();
-       
-       INSTANCE.output(INSTANCE.fromMarkup("<p>Test "), out);
-       INSTANCE.output(INSTANCE.fromPlainTextByEscaping("foo & bar "), out);
-       INSTANCE.output(INSTANCE.fromPlainTextByEscaping("baaz "), out);
-       INSTANCE.output(INSTANCE.fromPlainTextByEscaping("<b>A</b> <b>B</b> <b>C</b>"), out);
-       INSTANCE.output(INSTANCE.fromPlainTextByEscaping(""), out);
-       INSTANCE.output(INSTANCE.fromPlainTextByEscaping("\"' x's \"y\" \""), out);
-       INSTANCE.output(INSTANCE.fromMarkup("</p>"), out);
-       
-       assertEquals(
-               "<p>Test "
-               + "foo &amp; bar "
-               + "baaz "
-               + "&lt;b&gt;A&lt;/b&gt; &lt;b&gt;B&lt;/b&gt; &lt;b&gt;C&lt;/b&gt;"
-               + "&quot;&#39; x&#39;s &quot;y&quot; &quot;"
-               + "</p>",
-               out.toString());
-    }
-    
-    @Test
-    public void testOutputString() throws TemplateModelException, IOException {
-        StringWriter out = new StringWriter();
-        
-        INSTANCE.output("a", out);
-        INSTANCE.output("<", out);
-        INSTANCE.output("b'c", out);
-        
-        assertEquals("a&lt;b&#39;c", out.toString());
-    }
-    
-    @Test
-    public void testFromPlainTextByEscaping() throws TemplateModelException {
-        String plainText = "a&b";
-        TemplateHTMLOutputModel mo = INSTANCE.fromPlainTextByEscaping(plainText);
-        assertSame(plainText, _OutputFormatTestAPI.getPlainTextContent(mo));
-        assertNull(_OutputFormatTestAPI.getMarkupContent(mo)); // Not the MO's duty to calculate it!
-    }
-
-    @Test
-    public void testFromMarkup() throws TemplateModelException {
-        String markup = "a&amp;b";
-        TemplateHTMLOutputModel mo = INSTANCE.fromMarkup(markup);
-        assertSame(markup, _OutputFormatTestAPI.getMarkupContent(mo));
-        assertNull(_OutputFormatTestAPI.getPlainTextContent(mo)); // Not the MO's duty to calculate it!
-    }
-    
-    @Test
-    public void testGetMarkup() throws TemplateModelException {
-        {
-            String markup = "a&amp;b";
-            TemplateHTMLOutputModel mo = INSTANCE.fromMarkup(markup);
-            assertSame(markup, INSTANCE.getMarkupString(mo));
-        }
-        
-        {
-            String safe = "abc";
-            TemplateHTMLOutputModel mo = INSTANCE.fromPlainTextByEscaping(safe);
-            assertSame(safe, INSTANCE.getMarkupString(mo));
-        }
-        {
-            String safe = "";
-            TemplateHTMLOutputModel mo = INSTANCE.fromPlainTextByEscaping(safe);
-            assertSame(safe, INSTANCE.getMarkupString(mo));
-        }
-        {
-            TemplateHTMLOutputModel mo = INSTANCE.fromPlainTextByEscaping("<abc");
-            assertEquals("&lt;abc", INSTANCE.getMarkupString(mo));
-        }
-        {
-            TemplateHTMLOutputModel mo = INSTANCE.fromPlainTextByEscaping("abc>");
-            assertEquals("abc&gt;", INSTANCE.getMarkupString(mo));
-        }
-        {
-            TemplateHTMLOutputModel mo = INSTANCE.fromPlainTextByEscaping("<abc>");
-            assertEquals("&lt;abc&gt;", INSTANCE.getMarkupString(mo));
-        }
-        {
-            TemplateHTMLOutputModel mo = INSTANCE.fromPlainTextByEscaping("a&bc");
-            assertEquals("a&amp;bc", INSTANCE.getMarkupString(mo));
-        }
-        {
-            TemplateHTMLOutputModel mo = INSTANCE.fromPlainTextByEscaping("a&b&c");
-            assertEquals("a&amp;b&amp;c", INSTANCE.getMarkupString(mo));
-        }
-        {
-            TemplateHTMLOutputModel mo = INSTANCE.fromPlainTextByEscaping("a<&>b&c");
-            assertEquals("a&lt;&amp;&gt;b&amp;c", INSTANCE.getMarkupString(mo));
-        }
-        {
-            TemplateHTMLOutputModel mo = INSTANCE.fromPlainTextByEscaping("\"<a<&>b&c>\"");
-            assertEquals("&quot;&lt;a&lt;&amp;&gt;b&amp;c&gt;&quot;", INSTANCE.getMarkupString(mo));
-        }
-        {
-            TemplateHTMLOutputModel mo = INSTANCE.fromPlainTextByEscaping("<");
-            assertEquals("&lt;", INSTANCE.getMarkupString(mo));
-        }
-        {
-            TemplateHTMLOutputModel mo = INSTANCE.fromPlainTextByEscaping("'");
-            String mc = INSTANCE.getMarkupString(mo);
-            assertEquals("&#39;", mc);
-            assertSame(mc, INSTANCE.getMarkupString(mo)); // cached
-        }
-    }
-    
-    @Test
-    public void testConcat() throws Exception {
-        assertMO(
-                "ab", null,
-                INSTANCE.concat(new TemplateHTMLOutputModel("a", null), new TemplateHTMLOutputModel("b", null)));
-        assertMO(
-                null, "ab",
-                INSTANCE.concat(new TemplateHTMLOutputModel(null, "a"), new TemplateHTMLOutputModel(null, "b")));
-        assertMO(
-                null, "<a>&lt;b&gt;",
-                INSTANCE.concat(new TemplateHTMLOutputModel(null, "<a>"), new TemplateHTMLOutputModel("<b>", null)));
-        assertMO(
-                null, "&lt;a&gt;<b>",
-                INSTANCE.concat(new TemplateHTMLOutputModel("<a>", null), new TemplateHTMLOutputModel(null, "<b>")));
-    }
-    
-    @Test
-    public void testEscaplePlainText() {
-        assertEquals("", INSTANCE.escapePlainText(""));
-        assertEquals("a", INSTANCE.escapePlainText("a"));
-        assertEquals("&lt;a&amp;b&#39;c&quot;d&gt;", INSTANCE.escapePlainText("<a&b'c\"d>"));
-        assertEquals("a&amp;b", INSTANCE.escapePlainText("a&b"));
-        assertEquals("&lt;&gt;", INSTANCE.escapePlainText("<>"));
-    }
-    
-    @Test
-    public void testIsEmpty() throws Exception {
-        assertTrue(INSTANCE.isEmpty(INSTANCE.fromMarkup("")));
-        assertTrue(INSTANCE.isEmpty(INSTANCE.fromPlainTextByEscaping("")));
-        assertFalse(INSTANCE.isEmpty(INSTANCE.fromMarkup(" ")));
-        assertFalse(INSTANCE.isEmpty(INSTANCE.fromPlainTextByEscaping(" ")));
-    }
-    
-    private void assertMO(String pc, String mc, TemplateHTMLOutputModel mo) {
-        assertEquals(pc, _OutputFormatTestAPI.getPlainTextContent(mo));
-        assertEquals(mc, _OutputFormatTestAPI.getMarkupContent(mo));
-    }
-    
-    @Test
-    public void testGetMimeType() {
-        assertEquals("text/html", INSTANCE.getMimeType());
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/outputformat/impl/RTFOutputFormatTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/outputformat/impl/RTFOutputFormatTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/outputformat/impl/RTFOutputFormatTest.java
deleted file mode 100644
index 13563f5..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/outputformat/impl/RTFOutputFormatTest.java
+++ /dev/null
@@ -1,129 +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.outputformat.impl;
-
-import static org.apache.freemarker.core.outputformat.impl.RTFOutputFormat.*;
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.io.StringWriter;
-
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.outputformat._OutputFormatTestAPI;
-import org.junit.Test; 
-
-public class RTFOutputFormatTest {
-    
-    @Test
-    public void testOutputMO() throws TemplateModelException, IOException {
-       StringWriter out = new StringWriter();
-       
-       INSTANCE.output(INSTANCE.fromMarkup("\\par Test "), out);
-       INSTANCE.output(INSTANCE.fromPlainTextByEscaping("foo { bar } \\ "), out);
-       INSTANCE.output(INSTANCE.fromPlainTextByEscaping("baaz "), out);
-       INSTANCE.output(INSTANCE.fromPlainTextByEscaping("\\par qweqwe"), out);
-       INSTANCE.output(INSTANCE.fromMarkup("\\par{0} End"), out);
-       
-       assertEquals(
-               "\\par Test "
-               + "foo \\{ bar \\} \\\\ "
-               + "baaz "
-               + "\\\\par qweqwe"
-               + "\\par{0} End",
-               out.toString());
-    }
-    
-    @Test
-    public void testOutputString() throws TemplateModelException, IOException {
-        StringWriter out = new StringWriter();
-        
-        INSTANCE.output("a", out);
-        INSTANCE.output("{", out);
-        INSTANCE.output("b}c", out);
-        
-        assertEquals("a\\{b\\}c", out.toString());
-    }
-    
-    @Test
-    public void testFromPlainTextByEscaping() throws TemplateModelException {
-        String plainText = "a\\b";
-        TemplateRTFOutputModel mo = INSTANCE.fromPlainTextByEscaping(plainText);
-        assertSame(plainText, _OutputFormatTestAPI.getPlainTextContent(mo));
-        assertNull(_OutputFormatTestAPI.getMarkupContent(mo)); // Not the MO's duty to calculate it!
-    }
-
-    @Test
-    public void testFromMarkup() throws TemplateModelException {
-        String markup = "a \\par b";
-        TemplateRTFOutputModel mo = INSTANCE.fromMarkup(markup);
-        assertSame(markup, _OutputFormatTestAPI.getMarkupContent(mo));
-        assertNull(_OutputFormatTestAPI.getPlainTextContent(mo)); // Not the MO's duty to calculate it!
-    }
-    
-    @Test
-    public void testGetMarkup() throws TemplateModelException {
-        {
-            String markup = "a \\par b";
-            TemplateRTFOutputModel mo = INSTANCE.fromMarkup(markup);
-            assertSame(markup, INSTANCE.getMarkupString(mo));
-        }
-        
-        {
-            String safe = "abc";
-            TemplateRTFOutputModel mo = INSTANCE.fromPlainTextByEscaping(safe);
-            assertSame(safe, INSTANCE.getMarkupString(mo));
-        }
-    }
-    
-    @Test
-    public void testConcat() throws Exception {
-        assertMO(
-                "ab", null,
-                INSTANCE.concat(new TemplateRTFOutputModel("a", null), new TemplateRTFOutputModel("b", null)));
-        assertMO(
-                null, "ab",
-                INSTANCE.concat(new TemplateRTFOutputModel(null, "a"), new TemplateRTFOutputModel(null, "b")));
-        assertMO(
-                null, "{a}\\{b\\}",
-                INSTANCE.concat(new TemplateRTFOutputModel(null, "{a}"), new TemplateRTFOutputModel("{b}", null)));
-        assertMO(
-                null, "\\{a\\}{b}",
-                INSTANCE.concat(new TemplateRTFOutputModel("{a}", null), new TemplateRTFOutputModel(null, "{b}")));
-    }
-    
-    @Test
-    public void testEscaplePlainText() {
-        assertEquals("", INSTANCE.escapePlainText(""));
-        assertEquals("a", INSTANCE.escapePlainText("a"));
-        assertEquals("\\{a\\\\b\\}", INSTANCE.escapePlainText("{a\\b}"));
-        assertEquals("a\\\\b", INSTANCE.escapePlainText("a\\b"));
-        assertEquals("\\{\\}", INSTANCE.escapePlainText("{}"));
-    }
-    
-    private void assertMO(String pc, String mc, TemplateRTFOutputModel mo) {
-        assertEquals(pc, _OutputFormatTestAPI.getPlainTextContent(mo));
-        assertEquals(mc, _OutputFormatTestAPI.getMarkupContent(mo));
-    }
-    
-    @Test
-    public void testGetMimeType() {
-        assertEquals("application/rtf", INSTANCE.getMimeType());
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/templateresolver/DefaultTemplateResolverTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/templateresolver/DefaultTemplateResolverTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/templateresolver/DefaultTemplateResolverTest.java
deleted file mode 100644
index a7063fd..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/templateresolver/DefaultTemplateResolverTest.java
+++ /dev/null
@@ -1,365 +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.templateresolver;
-
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.io.Serializable;
-import java.nio.charset.StandardCharsets;
-import java.util.Locale;
-
-import org.apache.freemarker.core.Configuration;
-import org.apache.freemarker.core.Template;
-import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateLookupStrategy;
-import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormat;
-import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateResolver;
-import org.apache.freemarker.core.templateresolver.impl.StringTemplateLoader;
-import org.apache.freemarker.core.templateresolver.impl.StrongCacheStorage;
-import org.apache.freemarker.test.MonitoredTemplateLoader;
-import org.apache.freemarker.test.MonitoredTemplateLoader.CloseSessionEvent;
-import org.apache.freemarker.test.MonitoredTemplateLoader.CreateSessionEvent;
-import org.apache.freemarker.test.MonitoredTemplateLoader.LoadEvent;
-import org.apache.freemarker.test.TestConfigurationBuilder;
-import org.hamcrest.Matchers;
-import org.junit.Test;
-
-import com.google.common.collect.ImmutableList;
-
-public class DefaultTemplateResolverTest {
-
-    @Test
-    public void testCachedException() throws Exception {
-        MockTemplateLoader loader = new MockTemplateLoader();
-        DefaultTemplateResolver tr = new DefaultTemplateResolver(
-                loader,
-                new StrongCacheStorage(), 1000L,
-                DefaultTemplateLookupStrategy.INSTANCE, true,
-                DefaultTemplateNameFormat.INSTANCE,
-                null,
-                new TestConfigurationBuilder().build());
-        loader.setThrowException(true);
-        try {
-            tr.getTemplate("t", Locale.getDefault(), null).getTemplate();
-            fail();
-        } catch (IOException e) {
-            assertEquals("mock IO exception", e.getMessage());
-            assertEquals(1, loader.getLoadAttemptCount());
-            try {
-                tr.getTemplate("t", Locale.getDefault(), null).getTemplate();
-                fail();
-            } catch (IOException e2) {
-                // Still 1 - returned cached exception
-                assertThat(e2.getMessage(),
-                        Matchers.allOf(Matchers.containsString("There was an error loading the template on an " +
-                        "earlier attempt")));
-                assertSame(e, e2.getCause());
-                assertEquals(1, loader.getLoadAttemptCount());
-                try {
-                    Thread.sleep(1100L);
-                    tr.getTemplate("t", Locale.getDefault(), null).getTemplate();
-                    fail();
-                } catch (IOException e3) {
-                    // Cache had to retest
-                    assertEquals("mock IO exception", e.getMessage());
-                    assertEquals(2, loader.getLoadAttemptCount());
-                }
-            }
-        }
-    }
-    
-    @Test
-    public void testCachedNotFound() throws Exception {
-        MockTemplateLoader loader = new MockTemplateLoader();
-        DefaultTemplateResolver cache = new DefaultTemplateResolver(
-                loader,
-                new StrongCacheStorage(), 1000L,
-                DefaultTemplateLookupStrategy.INSTANCE, false,
-                DefaultTemplateNameFormat.INSTANCE,
-                null, new TestConfigurationBuilder().build());
-        assertNull(cache.getTemplate("t", Locale.getDefault(), null).getTemplate());
-        assertEquals(1, loader.getLoadAttemptCount());
-        assertNull(cache.getTemplate("t", Locale.getDefault(), null).getTemplate());
-        // Still 1 - returned cached exception
-        assertEquals(1, loader.getLoadAttemptCount());
-        Thread.sleep(1100L);
-        assertNull(cache.getTemplate("t", Locale.getDefault(), null).getTemplate());
-        // Cache had to retest
-        assertEquals(2, loader.getLoadAttemptCount());
-    }
-
-    private static class MockTemplateLoader implements TemplateLoader {
-        private boolean throwException;
-        private int loadAttemptCount; 
-        
-        public void setThrowException(boolean throwException) {
-           this.throwException = throwException;
-        }
-        
-        public int getLoadAttemptCount() {
-            return loadAttemptCount;
-        }
-        
-        @Override
-        public TemplateLoaderSession createSession() {
-            return null;
-        }
-
-        @Override
-        public TemplateLoadingResult load(String name, TemplateLoadingSource ifSourceDiffersFrom,
-                Serializable ifVersionDiffersFrom, TemplateLoaderSession session) throws IOException {
-            ++loadAttemptCount;
-            if (throwException) {
-                throw new IOException("mock IO exception");
-            }
-            return TemplateLoadingResult.NOT_FOUND;
-        }
-
-        @Override
-        public void resetState() {
-            //
-        }
-        
-    }
-    
-    @Test
-    public void testManualRemovalPlain() throws Exception {
-        StringTemplateLoader loader = new StringTemplateLoader();
-        Configuration cfg = new TestConfigurationBuilder()
-                .cacheStorage(new StrongCacheStorage())
-                .templateLoader(loader)
-                .templateUpdateDelayMilliseconds(Long.MAX_VALUE)
-                .build();
-
-        loader.putTemplate("1.ftl", "1 v1");
-        loader.putTemplate("2.ftl", "2 v1");
-        assertEquals("1 v1", cfg.getTemplate("1.ftl").toString()); 
-        assertEquals("2 v1", cfg.getTemplate("2.ftl").toString());
-        
-        loader.putTemplate("1.ftl", "1 v2");
-        loader.putTemplate("2.ftl", "2 v2");
-        assertEquals("1 v1", cfg.getTemplate("1.ftl").toString()); // no change 
-        assertEquals("2 v1", cfg.getTemplate("2.ftl").toString()); // no change
-        
-        cfg.removeTemplateFromCache("1.ftl", cfg.getLocale(), null);
-        assertEquals("1 v2", cfg.getTemplate("1.ftl").toString()); // changed 
-        assertEquals("2 v1", cfg.getTemplate("2.ftl").toString());
-        
-        cfg.removeTemplateFromCache("2.ftl", cfg.getLocale(), null);
-        assertEquals("1 v2", cfg.getTemplate("1.ftl").toString()); 
-        assertEquals("2 v2", cfg.getTemplate("2.ftl").toString()); // changed
-    }
-
-    @Test
-    public void testManualRemovalI18ed() throws Exception {
-        StringTemplateLoader loader = new StringTemplateLoader();
-        Configuration cfg = new TestConfigurationBuilder()
-                .cacheStorage(new StrongCacheStorage())
-                .templateLoader(loader)
-                .templateUpdateDelayMilliseconds(Long.MAX_VALUE)
-                .build();
-
-        loader.putTemplate("1_en_US.ftl", "1_en_US v1");
-        loader.putTemplate("1_en.ftl", "1_en v1");
-        loader.putTemplate("1.ftl", "1 v1");
-        
-        assertEquals("1_en_US v1", cfg.getTemplate("1.ftl").toString());        
-        assertEquals("1_en v1", cfg.getTemplate("1.ftl", Locale.UK).toString());        
-        assertEquals("1 v1", cfg.getTemplate("1.ftl", Locale.GERMANY).toString());
-        
-        loader.putTemplate("1_en_US.ftl", "1_en_US v2");
-        loader.putTemplate("1_en.ftl", "1_en v2");
-        loader.putTemplate("1.ftl", "1 v2");
-        assertEquals("1_en_US v1", cfg.getTemplate("1.ftl").toString());        
-        assertEquals("1_en v1", cfg.getTemplate("1.ftl", Locale.UK).toString());        
-        assertEquals("1 v1", cfg.getTemplate("1.ftl", Locale.GERMANY).toString());
-        
-        cfg.removeTemplateFromCache("1.ftl", cfg.getLocale(), null);
-        assertEquals("1_en_US v2", cfg.getTemplate("1.ftl").toString());        
-        assertEquals("1_en v1", cfg.getTemplate("1.ftl", Locale.UK).toString());        
-        assertEquals("1 v1", cfg.getTemplate("1.ftl", Locale.GERMANY).toString());
-        assertEquals("1 v2", cfg.getTemplate("1.ftl", Locale.ITALY).toString());
-        
-        cfg.removeTemplateFromCache("1.ftl", Locale.GERMANY, null);
-        assertEquals("1_en v1", cfg.getTemplate("1.ftl", Locale.UK).toString());        
-        assertEquals("1 v2", cfg.getTemplate("1.ftl", Locale.GERMANY).toString());
-
-        cfg.removeTemplateFromCache("1.ftl", Locale.CANADA, null);
-        assertEquals("1_en v1", cfg.getTemplate("1.ftl", Locale.UK).toString());
-        
-        cfg.removeTemplateFromCache("1.ftl", Locale.UK, null);
-        assertEquals("1_en v2", cfg.getTemplate("1.ftl", Locale.UK).toString());        
-    }
-
-    @Test
-    public void testZeroUpdateDelay() throws Exception {
-        MonitoredTemplateLoader loader = new MonitoredTemplateLoader();
-        TestConfigurationBuilder cfgB = new TestConfigurationBuilder()
-                .cacheStorage(new StrongCacheStorage())
-                .templateLoader(loader)
-                .templateUpdateDelayMilliseconds(0);
-
-        Configuration cfg = cfgB.build();
-
-        for (int i = 1; i <= 3; i++) {
-            loader.putTextTemplate("t.ftl", "v" + i);
-            assertEquals("v" + i, cfg.getTemplate("t.ftl").toString());
-        }
-
-        loader.clearEvents();
-        loader.putTextTemplate("t.ftl", "v8");
-        assertEquals("v8", cfg.getTemplate("t.ftl").toString());
-        assertEquals("v8", cfg.getTemplate("t.ftl").toString());
-        loader.putTextTemplate("t.ftl", "v9");
-        assertEquals("v9", cfg.getTemplate("t.ftl").toString());
-        assertEquals("v9", cfg.getTemplate("t.ftl").toString());
-        assertEquals(
-                ImmutableList.of(
-                        new LoadEvent("t_en_US.ftl", TemplateLoadingResultStatus.NOT_FOUND), // v8
-                        new LoadEvent("t_en.ftl", TemplateLoadingResultStatus.NOT_FOUND),
-                        new LoadEvent("t.ftl", TemplateLoadingResultStatus.OPENED),
-
-                        new LoadEvent("t_en_US.ftl", TemplateLoadingResultStatus.NOT_FOUND), // v8
-                        new LoadEvent("t_en.ftl", TemplateLoadingResultStatus.NOT_FOUND),
-                        new LoadEvent("t.ftl", TemplateLoadingResultStatus.NOT_MODIFIED),
-                        
-                        new LoadEvent("t_en_US.ftl", TemplateLoadingResultStatus.NOT_FOUND), // v9
-                        new LoadEvent("t_en.ftl", TemplateLoadingResultStatus.NOT_FOUND),
-                        new LoadEvent("t.ftl", TemplateLoadingResultStatus.OPENED),
-
-                        new LoadEvent("t_en_US.ftl", TemplateLoadingResultStatus.NOT_FOUND), // v9
-                        new LoadEvent("t_en.ftl", TemplateLoadingResultStatus.NOT_FOUND),
-                        new LoadEvent("t.ftl", TemplateLoadingResultStatus.NOT_MODIFIED)
-                ),
-                loader.getEvents(LoadEvent.class));
-        
-        cfg = cfgB.localizedLookup(false).build();
-        loader.clearEvents();
-        loader.putTextTemplate("t.ftl", "v10");
-        assertEquals("v10", cfg.getTemplate("t.ftl").toString());
-        loader.putTextTemplate("t.ftl", "v11"); // same time stamp, different content
-        assertEquals("v11", cfg.getTemplate("t.ftl").toString());
-        assertEquals("v11", cfg.getTemplate("t.ftl").toString());
-        assertEquals("v11", cfg.getTemplate("t.ftl").toString());
-        Thread.sleep(17L);
-        assertEquals("v11", cfg.getTemplate("t.ftl").toString());
-        loader.putTextTemplate("t.ftl", "v12");
-        assertEquals("v12", cfg.getTemplate("t.ftl").toString());
-        assertEquals("v12", cfg.getTemplate("t.ftl").toString());
-        assertEquals(
-                ImmutableList.of(
-                        new LoadEvent("t.ftl", TemplateLoadingResultStatus.OPENED), // v10
-                        new LoadEvent("t.ftl", TemplateLoadingResultStatus.OPENED), // v11
-                        new LoadEvent("t.ftl", TemplateLoadingResultStatus.NOT_MODIFIED),
-                        new LoadEvent("t.ftl", TemplateLoadingResultStatus.NOT_MODIFIED),
-                        new LoadEvent("t.ftl", TemplateLoadingResultStatus.NOT_MODIFIED),
-                        new LoadEvent("t.ftl", TemplateLoadingResultStatus.OPENED), // v12
-                        new LoadEvent("t.ftl", TemplateLoadingResultStatus.NOT_MODIFIED)
-                ),
-                loader.getEvents(LoadEvent.class));
-    }
-    
-    @Test
-    public void testWrongEncodingReload() throws Exception {
-        MonitoredTemplateLoader loader = new MonitoredTemplateLoader();
-        loader.putBinaryTemplate("utf-8_en.ftl", "<#ftl encoding='utf-8'>Béka");
-        loader.putBinaryTemplate("utf-8.ftl", "Bar");
-        loader.putBinaryTemplate("iso-8859-1_en_US.ftl", "<#ftl encoding='ISO-8859-1'>Béka",
-                StandardCharsets.ISO_8859_1, "v1");
-        Configuration cfg = new TestConfigurationBuilder().templateLoader(loader).build();
-
-        {
-            Template t = cfg.getTemplate("utf-8.ftl");
-            assertEquals("utf-8.ftl", t.getLookupName());
-            assertEquals("utf-8_en.ftl", t.getSourceName());
-            assertEquals(StandardCharsets.UTF_8, t.getActualSourceEncoding());
-            assertEquals("Béka", t.toString());
-            
-            assertEquals(
-                    ImmutableList.of(
-                            CreateSessionEvent.INSTANCE,
-                            new LoadEvent("utf-8_en_US.ftl", TemplateLoadingResultStatus.NOT_FOUND),
-                            new LoadEvent("utf-8_en.ftl", TemplateLoadingResultStatus.OPENED),
-                            CloseSessionEvent.INSTANCE),
-                    loader.getEvents());
-        }
-
-        {
-            loader.clearEvents();
-            
-            Template t = cfg.getTemplate("iso-8859-1.ftl");
-            assertEquals("iso-8859-1.ftl", t.getLookupName());
-            assertEquals("iso-8859-1_en_US.ftl", t.getSourceName());
-            assertEquals(StandardCharsets.ISO_8859_1, t.getActualSourceEncoding());
-            assertEquals("Béka", t.toString());
-            
-            assertEquals(
-                    ImmutableList.of(
-                            CreateSessionEvent.INSTANCE,
-                            new LoadEvent("iso-8859-1_en_US.ftl", TemplateLoadingResultStatus.OPENED),
-                            CloseSessionEvent.INSTANCE),
-                    loader.getEvents());
-        }
-    }
-
-    @Test
-    public void testNoWrongEncodingForTemplateLoader2WithReader() throws Exception {
-        MonitoredTemplateLoader loader = new MonitoredTemplateLoader();
-        loader.putTextTemplate("foo_en.ftl", "<#ftl encoding='utf-8'>ő");
-        loader.putTextTemplate("foo.ftl", "B");
-        Configuration cfg = new TestConfigurationBuilder().templateLoader(loader).build();
-        
-        {
-            Template t = cfg.getTemplate("foo.ftl");
-            assertEquals("foo.ftl", t.getLookupName());
-            assertEquals("foo_en.ftl", t.getSourceName());
-            assertNull(t.getActualSourceEncoding());
-            assertEquals("ő", t.toString());
-            
-            assertEquals(
-                    ImmutableList.of(
-                            CreateSessionEvent.INSTANCE,
-                            new LoadEvent("foo_en_US.ftl", TemplateLoadingResultStatus.NOT_FOUND),
-                            new LoadEvent("foo_en.ftl", TemplateLoadingResultStatus.OPENED),
-                            CloseSessionEvent.INSTANCE),                
-                    loader.getEvents());
-        }
-    }
-
-    @Test
-    public void testTemplateNameFormatException() throws Exception {
-        Configuration cfg = new TestConfigurationBuilder()
-                .templateNameFormat(DefaultTemplateNameFormat.INSTANCE)
-                .build();
-        try {
-            cfg.getTemplate("../x");
-            fail();
-        } catch (MalformedTemplateNameException e) {
-            // expected
-        }
-        try {
-            cfg.getTemplate("\\x");
-            fail();
-        } catch (MalformedTemplateNameException e) {
-            // expected
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/templateresolver/FileTemplateLoaderTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/templateresolver/FileTemplateLoaderTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/templateresolver/FileTemplateLoaderTest.java
deleted file mode 100644
index 393dbae..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/templateresolver/FileTemplateLoaderTest.java
+++ /dev/null
@@ -1,122 +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.templateresolver;
-
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
-import java.io.File;
-import java.io.IOException;
-
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.lang3.SystemUtils;
-import org.apache.freemarker.core.Configuration;
-import org.apache.freemarker.core.TemplateNotFoundException;
-import org.apache.freemarker.core.templateresolver.impl.FileTemplateLoader;
-import org.apache.freemarker.test.TestConfigurationBuilder;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.google.common.io.Files;
-
-public class FileTemplateLoaderTest {
-    
-    private File templateRootDir;
-    
-    private Configuration cfg;
-    
-    @Before
-    public void setup() throws IOException {
-        templateRootDir = Files.createTempDir();
-        File sub1Dir = new File(templateRootDir, "sub1");
-        File sub2Dir = new File(sub1Dir, "sub2");
-        if (!sub2Dir.mkdirs()) {
-            throw new IOException("Failed to invoke subdirectories");
-        }
-        File tFile = new File(sub2Dir, "t.ftl");
-        FileUtils.write(tFile, "foo");
-
-        cfg = new TestConfigurationBuilder().templateLoader(new FileTemplateLoader(templateRootDir)).build();
-    }
-    
-    @Test
-    public void testSuccessful() throws Exception {
-        for (int i = 0; i < 2; i++) {
-            assertEquals("foo", cfg.getTemplate("sub1/sub2/t.ftl").toString());
-        }
-    }
-
-    @Test
-    public void testSuccessful2() throws Exception {
-        ((FileTemplateLoader) cfg.getTemplateLoader()).setEmulateCaseSensitiveFileSystem(true);
-        for (int i = 0; i < 2; i++) {
-            cfg.clearTemplateCache();
-            assertEquals("foo", cfg.getTemplate("sub1/sub2/t.ftl").toString());
-        }
-    }
-    
-    
-    @Test
-    public void testNotFound() throws Exception {
-        for (int i = 0; i < 2; i++) {
-            try {
-                cfg.getTemplate("sub1X/sub2/t.ftl");
-                fail();
-            } catch (TemplateNotFoundException e) {
-                assertThat(e.getMessage(), containsString("sub1X"));
-                assertNull(e.getCause());
-            }
-        }
-    }
-
-    @Test
-    public void testCaseSensitivity() throws Exception {
-        for (boolean emuCaseSensFS : new boolean[] { false, true }) {
-            for (String nameWithBadCase : new String[] { "SUB1/sub2/t.ftl", "sub1/SUB2/t.ftl", "sub1/sub2/T.FTL" }) {
-                ((FileTemplateLoader) cfg.getTemplateLoader()).setEmulateCaseSensitiveFileSystem(emuCaseSensFS);
-                cfg.clearTemplateCache();
-                
-                if ((SystemUtils.IS_OS_WINDOWS || SystemUtils.IS_OS_MAC_OSX) && !emuCaseSensFS) {
-                    assertEquals("foo", cfg.getTemplate(nameWithBadCase).toString());
-                } else {
-                    assertEquals("foo", cfg.getTemplate(nameWithBadCase.toLowerCase()).toString());
-                    try {
-                        cfg.getTemplate(nameWithBadCase);
-                        fail();
-                    } catch (TemplateNotFoundException e) {
-                        assertThat(e.getMessage(), containsString(nameWithBadCase));
-                        assertNull(e.getCause());
-                    }
-                }
-            }
-        }
-    }
-    
-    @Test
-    public void testDefault() throws IOException {
-        assertFalse(new FileTemplateLoader(templateRootDir).getEmulateCaseSensitiveFileSystem());
-    }
-    
-    @After
-    public void tearDown() throws IOException {
-        FileUtils.deleteDirectory(templateRootDir);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/templateresolver/MultiTemplateLoaderTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/templateresolver/MultiTemplateLoaderTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/templateresolver/MultiTemplateLoaderTest.java
deleted file mode 100644
index c8531c5..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/templateresolver/MultiTemplateLoaderTest.java
+++ /dev/null
@@ -1,99 +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.templateresolver;
-
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.nio.charset.StandardCharsets;
-
-import org.apache.commons.io.IOUtils;
-import org.apache.freemarker.core.templateresolver.impl.ByteArrayTemplateLoader;
-import org.apache.freemarker.core.templateresolver.impl.MultiTemplateLoader;
-import org.apache.freemarker.core.templateresolver.impl.StringTemplateLoader;
-import org.junit.Test;
-
-public class MultiTemplateLoaderTest {
-
-    @Test
-    public void testBasics() throws IOException {
-        StringTemplateLoader stl1 = new StringTemplateLoader();
-        stl1.putTemplate("1.ftl", "1");
-        stl1.putTemplate("both.ftl", "both 1");
-
-        StringTemplateLoader stl2 = new StringTemplateLoader();
-        stl2.putTemplate("2.ftl", "2");
-        stl2.putTemplate("both.ftl", "both 2");
-        
-        MultiTemplateLoader mtl = new MultiTemplateLoader(stl1, stl2);
-        assertEquals("1", getTemplateContent(mtl, "1.ftl"));
-        assertEquals("2", getTemplateContent(mtl, "2.ftl"));
-        assertEquals("both 1", getTemplateContent(mtl, "both.ftl"));
-        assertNull(getTemplateContent(mtl, "neither.ftl"));
-    }
-
-    @Test
-    public void testSticky() throws IOException {
-        testStickiness(true);
-    }
-
-    @Test
-    public void testNonSticky() throws IOException {
-        testStickiness(false);
-    }
-    
-    private void testStickiness(boolean sticky) throws IOException {
-        StringTemplateLoader stl1 = new StringTemplateLoader();
-        stl1.putTemplate("both.ftl", "both 1");
-        
-        ByteArrayTemplateLoader stl2 = new ByteArrayTemplateLoader();
-        stl2.putTemplate("both.ftl", "both 2".getBytes(StandardCharsets.UTF_8));
-
-        MultiTemplateLoader mtl = new MultiTemplateLoader(stl1, stl2);
-        mtl.setSticky(sticky);
-        
-        assertEquals("both 1", getTemplateContent(mtl, "both.ftl"));
-        assertTrue(stl1.removeTemplate("both.ftl"));
-        assertEquals("both 2", getTemplateContent(mtl, "both.ftl"));
-        stl1.putTemplate("both.ftl", "both 1");
-        assertEquals(sticky ? "both 2" : "both 1", getTemplateContent(mtl, "both.ftl"));
-        assertTrue(stl2.removeTemplate("both.ftl"));
-        assertEquals("both 1", getTemplateContent(mtl, "both.ftl"));
-    }
-    
-    private String getTemplateContent(TemplateLoader tl, String name) throws IOException {
-        TemplateLoaderSession ses = tl.createSession();
-        try {
-            TemplateLoadingResult res = tl.load(name, null, null, ses);
-            if (res.getStatus() == TemplateLoadingResultStatus.NOT_FOUND) {
-                return null;
-            }
-            return IOUtils.toString(
-                    res.getReader() != null
-                            ? res.getReader()
-                            : new InputStreamReader(res.getInputStream(), StandardCharsets.UTF_8));
-        } finally {
-            if (ses != null) {
-                ses.close();
-            }
-        }
-    }
-    
-}


[39/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/OverloadedNumberUtilTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/OverloadedNumberUtilTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/OverloadedNumberUtilTest.java
new file mode 100644
index 0000000..37e4726
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/OverloadedNumberUtilTest.java
@@ -0,0 +1,585 @@
+/*
+ * 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.model.impl;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import junit.framework.TestCase;
+
+@SuppressWarnings("boxing")
+public class OverloadedNumberUtilTest extends TestCase {
+
+    public OverloadedNumberUtilTest(String name) {
+        super(name);
+    }
+    
+    public void testIntegerCoercions() {
+        cipEqu(Byte.valueOf(Byte.MAX_VALUE));
+        cipEqu(Byte.valueOf((byte) 0));
+        cipEqu(Byte.valueOf(Byte.MIN_VALUE));
+        
+        cipEqu(Short.valueOf(Byte.MAX_VALUE),
+                new OverloadedNumberUtil.ShortOrByte((short) Byte.MAX_VALUE, Byte.MAX_VALUE));
+        cipEqu(Short.valueOf((short) 0),
+                new OverloadedNumberUtil.ShortOrByte((short) 0, (byte) 0));
+        cipEqu(Short.valueOf(Byte.MIN_VALUE),
+                new OverloadedNumberUtil.ShortOrByte((short) Byte.MIN_VALUE, Byte.MIN_VALUE));
+        
+        cipEqu(Short.valueOf((short) (Byte.MAX_VALUE + 1)));
+        cipEqu(Short.valueOf((short) (Byte.MIN_VALUE - 1)));
+        cipEqu(Short.valueOf(Short.MAX_VALUE));
+        cipEqu(Short.valueOf(Short.MIN_VALUE));
+        
+        cipEqu(Integer.valueOf(Byte.MAX_VALUE),
+                new OverloadedNumberUtil.IntegerOrByte((int) Byte.MAX_VALUE, Byte.MAX_VALUE));
+        cipEqu(Integer.valueOf(0),
+                new OverloadedNumberUtil.IntegerOrByte(0, (byte) 0));
+        cipEqu(Integer.valueOf(Byte.MIN_VALUE),
+                new OverloadedNumberUtil.IntegerOrByte((int) Byte.MIN_VALUE, Byte.MIN_VALUE));
+        
+        cipEqu(Integer.valueOf(Byte.MAX_VALUE + 1),
+                new OverloadedNumberUtil.IntegerOrShort(Byte.MAX_VALUE + 1, (short) (Byte.MAX_VALUE + 1)));
+        cipEqu(Integer.valueOf(Byte.MIN_VALUE - 1),
+                new OverloadedNumberUtil.IntegerOrShort(Byte.MIN_VALUE - 1, (short) (Byte.MIN_VALUE - 1)));
+        cipEqu(Integer.valueOf(Short.MAX_VALUE),
+                new OverloadedNumberUtil.IntegerOrShort((int) Short.MAX_VALUE, Short.MAX_VALUE));
+        cipEqu(Integer.valueOf(Short.MIN_VALUE),
+                new OverloadedNumberUtil.IntegerOrShort((int) Short.MIN_VALUE, Short.MIN_VALUE));
+        
+        cipEqu(Integer.valueOf(Short.MAX_VALUE + 1));
+        cipEqu(Integer.valueOf(Short.MIN_VALUE - 1));
+        cipEqu(Integer.valueOf(Integer.MAX_VALUE));
+        cipEqu(Integer.valueOf(Integer.MIN_VALUE));
+        
+        cipEqu(Long.valueOf(Byte.MAX_VALUE),
+                new OverloadedNumberUtil.LongOrByte((long) Byte.MAX_VALUE, Byte.MAX_VALUE));
+        cipEqu(Long.valueOf(0),
+                new OverloadedNumberUtil.LongOrByte((long) 0, (byte) 0));
+        cipEqu(Long.valueOf(Byte.MIN_VALUE),
+                new OverloadedNumberUtil.LongOrByte((long) Byte.MIN_VALUE, Byte.MIN_VALUE));
+        
+        cipEqu(Long.valueOf(Byte.MAX_VALUE + 1),
+                new OverloadedNumberUtil.LongOrShort((long) (Byte.MAX_VALUE + 1), (short) (Byte.MAX_VALUE + 1)));
+        cipEqu(Long.valueOf(Byte.MIN_VALUE - 1),
+                new OverloadedNumberUtil.LongOrShort((long) (Byte.MIN_VALUE - 1), (short) (Byte.MIN_VALUE - 1)));
+        cipEqu(Long.valueOf(Short.MAX_VALUE),
+                new OverloadedNumberUtil.LongOrShort((long) Short.MAX_VALUE, Short.MAX_VALUE));
+        cipEqu(Long.valueOf(Short.MIN_VALUE),
+                new OverloadedNumberUtil.LongOrShort((long) Short.MIN_VALUE, Short.MIN_VALUE));
+
+        cipEqu(Long.valueOf(Short.MAX_VALUE + 1),
+                new OverloadedNumberUtil.LongOrInteger((long) Short.MAX_VALUE + 1, Short.MAX_VALUE + 1));
+        cipEqu(Long.valueOf(Short.MIN_VALUE - 1),
+                new OverloadedNumberUtil.LongOrInteger((long) Short.MIN_VALUE - 1, Short.MIN_VALUE - 1));
+        cipEqu(Long.valueOf(Integer.MAX_VALUE),
+                new OverloadedNumberUtil.LongOrInteger((long) Integer.MAX_VALUE, Integer.MAX_VALUE));
+        cipEqu(Long.valueOf(Integer.MIN_VALUE),
+                new OverloadedNumberUtil.LongOrInteger((long) Integer.MIN_VALUE, Integer.MIN_VALUE));
+        
+        cipEqu(Long.valueOf(Integer.MAX_VALUE + 1L));
+        cipEqu(Long.valueOf(Integer.MIN_VALUE - 1L));
+        cipEqu(Long.valueOf(Long.MAX_VALUE));
+        cipEqu(Long.valueOf(Long.MIN_VALUE));
+    }
+    
+    public void testIntegerNoCoercions() {
+        cipEqu(Integer.valueOf(Byte.MAX_VALUE), Integer.valueOf(Byte.MAX_VALUE), 0);
+        cipEqu(Integer.valueOf(0), Integer.valueOf(0), 0);
+        cipEqu(Integer.valueOf(Byte.MIN_VALUE), Integer.valueOf(Byte.MIN_VALUE), 0);
+    }
+    
+    public void testIntegerLimitedCoercions() {
+        cipEqu(Integer.valueOf(Byte.MAX_VALUE), Integer.valueOf(Byte.MAX_VALUE), TypeFlags.INTEGER);
+        cipEqu(Integer.valueOf(0), Integer.valueOf(0), TypeFlags.INTEGER);
+        cipEqu(Integer.valueOf(Byte.MIN_VALUE), Integer.valueOf(Byte.MIN_VALUE), TypeFlags.INTEGER);
+        
+        cipEqu(Long.valueOf(Integer.MAX_VALUE + 1L), Long.valueOf(Integer.MAX_VALUE + 1L), TypeFlags.INTEGER);
+        
+        for (int n = -1; n < 2; n++) {
+            final Long longN = Long.valueOf(n);
+            cipEqu(longN, new OverloadedNumberUtil.LongOrInteger(longN, n), TypeFlags.INTEGER);
+            cipEqu(longN, new OverloadedNumberUtil.LongOrShort(longN, (short) n), TypeFlags.SHORT);
+            cipEqu(longN, new OverloadedNumberUtil.LongOrByte(longN, (byte) n), TypeFlags.BYTE);
+            cipEqu(longN, new OverloadedNumberUtil.LongOrShort(longN, (short) n),
+                    TypeFlags.SHORT | TypeFlags.INTEGER);
+        }
+    }
+
+    public void testBigDecimalCoercions() {
+        cipEqu(new BigDecimal(123), new OverloadedNumberUtil.IntegerBigDecimal(new BigDecimal(123)));
+        cipEqu(new BigDecimal(123), new OverloadedNumberUtil.IntegerBigDecimal(new BigDecimal(123)),
+                TypeFlags.DOUBLE | TypeFlags.INTEGER);
+        cipEqu(new BigDecimal(123), TypeFlags.INTEGER);
+        cipEqu(new BigDecimal(123), TypeFlags.INTEGER | TypeFlags.LONG);
+        cipEqu(new BigDecimal(123), TypeFlags.DOUBLE);
+        cipEqu(new BigDecimal(123), TypeFlags.DOUBLE | TypeFlags.FLOAT);
+        
+        cipEqu(new BigDecimal(123.5));
+        // Not wasting time with check if it's a whole number if we only have integer-only or non-integer-only targets:  
+        cipEqu(new BigDecimal(123.5), TypeFlags.INTEGER | TypeFlags.LONG);
+        cipEqu(new BigDecimal(123.5), TypeFlags.DOUBLE | TypeFlags.FLOAT);
+        
+        cipEqu(new BigDecimal("0.01"));
+        cipEqu(new BigDecimal("-0.01"));
+        cipEqu(BigDecimal.ZERO, new OverloadedNumberUtil.IntegerBigDecimal(BigDecimal.ZERO));
+    }
+
+    public void testUnknownNumberCoercion() {
+        cipEqu(new RationalNumber(2, 3));
+    }
+
+    @SuppressWarnings("boxing")
+    public void testDoubleCoercion() {
+        cipEqu(Double.valueOf(1.5), new OverloadedNumberUtil.DoubleOrFloat(1.5));
+        cipEqu(Double.valueOf(-0.125), new OverloadedNumberUtil.DoubleOrFloat(-0.125));
+        cipEqu(Double.valueOf(Float.MAX_VALUE), new OverloadedNumberUtil.DoubleOrFloat((double) Float.MAX_VALUE));
+        cipEqu(Double.valueOf(-Float.MAX_VALUE), new OverloadedNumberUtil.DoubleOrFloat((double) -Float.MAX_VALUE));
+        cipEqu(Double.valueOf(Float.MAX_VALUE * 10.0));
+        cipEqu(Double.valueOf(-Float.MAX_VALUE * 10.0));
+        
+        cipEqu(Double.valueOf(0), new OverloadedNumberUtil.DoubleOrByte(0.0, (byte) 0));
+        cipEqu(Double.valueOf(Byte.MAX_VALUE), new OverloadedNumberUtil.DoubleOrByte((double) Byte.MAX_VALUE, Byte.MAX_VALUE));
+        cipEqu(Double.valueOf(Byte.MIN_VALUE), new OverloadedNumberUtil.DoubleOrByte((double) Byte.MIN_VALUE, Byte.MIN_VALUE));
+        
+        cipEqu(Double.valueOf(Byte.MAX_VALUE + 1), new OverloadedNumberUtil.DoubleOrShort((double)
+                (Byte.MAX_VALUE + 1), (short) (Byte.MAX_VALUE + 1)));
+        cipEqu(Double.valueOf(Byte.MIN_VALUE - 1), new OverloadedNumberUtil.DoubleOrShort((double)
+                (Byte.MIN_VALUE - 1), (short) (Byte.MIN_VALUE - 1)));
+        
+        cipEqu(Double.valueOf(Short.MAX_VALUE + 1),
+                new OverloadedNumberUtil.DoubleOrIntegerOrFloat((double) Short.MAX_VALUE + 1, Short.MAX_VALUE + 1));
+        cipEqu(Double.valueOf(Short.MIN_VALUE - 1),
+                new OverloadedNumberUtil.DoubleOrIntegerOrFloat((double) Short.MIN_VALUE - 1, Short.MIN_VALUE -  1));
+        cipEqu(Double.valueOf(16777216), new OverloadedNumberUtil.DoubleOrIntegerOrFloat(16777216.0, 16777216));
+        cipEqu(Double.valueOf(-16777216), new OverloadedNumberUtil.DoubleOrIntegerOrFloat(-16777216.0, -16777216));
+        
+        cipEqu(Double.valueOf(Integer.MAX_VALUE),
+                new OverloadedNumberUtil.DoubleOrInteger((double) Integer.MAX_VALUE, Integer.MAX_VALUE));
+        cipEqu(Double.valueOf(Integer.MIN_VALUE),
+                new OverloadedNumberUtil.DoubleOrInteger((double) Integer.MIN_VALUE, Integer.MIN_VALUE));
+        
+        cipEqu(Double.valueOf(Integer.MAX_VALUE + 1L),
+                new OverloadedNumberUtil.DoubleOrLong(Double.valueOf(Integer.MAX_VALUE + 1L), Integer.MAX_VALUE + 1L));
+        cipEqu(Double.valueOf(Integer.MIN_VALUE - 1L),
+                new OverloadedNumberUtil.DoubleOrLong(Double.valueOf(Integer.MIN_VALUE - 1L), Integer.MIN_VALUE - 1L));
+        cipEqu(Double.valueOf(Long.MAX_VALUE),
+                new OverloadedNumberUtil.DoubleOrFloat((double) Long.MAX_VALUE));
+        cipEqu(Double.valueOf(Long.MIN_VALUE),
+                new OverloadedNumberUtil.DoubleOrFloat((double) Long.MIN_VALUE));
+
+        // When only certain target types are present:
+        cipEqu(Double.valueOf(5), new OverloadedNumberUtil.DoubleOrByte(5.0, (byte) 5), TypeFlags.BYTE);
+        cipEqu(Double.valueOf(5), new OverloadedNumberUtil.DoubleOrByte(5.0, (byte) 5), TypeFlags.BYTE | TypeFlags.SHORT);
+        cipEqu(Double.valueOf(-129), TypeFlags.BYTE);
+        cipEqu(Double.valueOf(5), new OverloadedNumberUtil.DoubleOrShort(5.0, (short) 5), TypeFlags.SHORT);
+        cipEqu(Double.valueOf(5), new OverloadedNumberUtil.DoubleOrInteger(5.0, 5), TypeFlags.INTEGER);
+        cipEqu(Double.valueOf(5), new OverloadedNumberUtil.DoubleOrLong(5.0, 5), TypeFlags.LONG);
+        cipEqu(Double.valueOf(5), new OverloadedNumberUtil.DoubleOrFloat(5.0), TypeFlags.FLOAT);
+        cipEqu(Double.valueOf(5), Double.valueOf(5), TypeFlags.DOUBLE);
+        cipEqu(Double.valueOf(5), new OverloadedNumberUtil.DoubleOrFloat(5.0),
+                TypeFlags.DOUBLE | TypeFlags.FLOAT);
+        cipEqu(Double.valueOf(5.9), new OverloadedNumberUtil.DoubleOrFloat(5.9),
+                TypeFlags.DOUBLE | TypeFlags.FLOAT);
+        cipEqu(Double.valueOf(5.9),
+                TypeFlags.DOUBLE | TypeFlags.INTEGER);
+        cipEqu(Double.valueOf(5.9), new OverloadedNumberUtil.DoubleOrFloat(5.9),
+                TypeFlags.FLOAT | TypeFlags.INTEGER);
+        cipEqu(Double.valueOf(5.9), TypeFlags.INTEGER);
+        cipEqu(Double.valueOf(Long.MAX_VALUE),
+                new OverloadedNumberUtil.DoubleOrFloat((double) Long.MAX_VALUE),
+                TypeFlags.DOUBLE | TypeFlags.FLOAT);
+        cipEqu(Double.valueOf(Long.MAX_VALUE),
+                TypeFlags.DOUBLE | TypeFlags.LONG);
+        cipEqu(Double.valueOf(Long.MIN_VALUE),
+                new OverloadedNumberUtil.DoubleOrFloat((double) Long.MIN_VALUE),
+                TypeFlags.DOUBLE | TypeFlags.FLOAT);
+        cipEqu(Double.valueOf(Float.MAX_VALUE * 10),
+                TypeFlags.DOUBLE | TypeFlags.FLOAT);
+        cipEqu(Double.valueOf(-Float.MAX_VALUE * 10),
+                TypeFlags.DOUBLE | TypeFlags.FLOAT);
+        
+        // Rounded values:
+        cipEqu(Double.valueOf(0.0000009),
+                new OverloadedNumberUtil.DoubleOrByte(0.0000009, (byte) 0));
+        cipEqu(Double.valueOf(-0.0000009),
+                new OverloadedNumberUtil.DoubleOrByte(-0.0000009, (byte) 0));
+        cipEqu(Double.valueOf(0.9999991),
+                new OverloadedNumberUtil.DoubleOrByte(0.9999991, (byte) 1));
+        cipEqu(Double.valueOf(-0.9999991),
+                new OverloadedNumberUtil.DoubleOrByte(-0.9999991, (byte) -1));
+        cipEqu(Double.valueOf(0.0000009),
+                new OverloadedNumberUtil.DoubleOrShort(0.0000009, (short) 0),
+                TypeFlags.SHORT | TypeFlags.DOUBLE);
+        cipEqu(Double.valueOf(0.0000009), new OverloadedNumberUtil.DoubleOrInteger(0.0000009, 0),
+                TypeFlags.INTEGER | TypeFlags.DOUBLE);
+        cipEqu(Double.valueOf(0.0000009), new OverloadedNumberUtil.DoubleOrLong(0.0000009, 0),
+                TypeFlags.LONG | TypeFlags.DOUBLE);
+        cipEqu(Double.valueOf(0.0000009),
+                new OverloadedNumberUtil.DoubleOrByte(0.0000009, (byte) 0), TypeFlags.BYTE);
+        cipEqu(Double.valueOf(0.0000009),
+                new OverloadedNumberUtil.DoubleOrShort(0.0000009, (short) 0), TypeFlags.SHORT);
+        cipEqu(Double.valueOf(0.0000009),
+                new OverloadedNumberUtil.DoubleOrInteger(0.0000009, 0), TypeFlags.INTEGER);
+        cipEqu(Double.valueOf(0.0000009),
+                new OverloadedNumberUtil.DoubleOrLong(0.0000009, 0L), TypeFlags.LONG);
+        cipEqu(Double.valueOf(0.9999999),
+                new OverloadedNumberUtil.DoubleOrInteger(0.9999999, 1), TypeFlags.INTEGER);
+        cipEqu(Double.valueOf(Byte.MAX_VALUE + 0.9e-6),
+                new OverloadedNumberUtil.DoubleOrByte(Byte.MAX_VALUE + 0.9e-6, Byte.MAX_VALUE));
+        cipEqu(Double.valueOf(Byte.MIN_VALUE - 0.9e-6),
+                new OverloadedNumberUtil.DoubleOrByte(Byte.MIN_VALUE - 0.9e-6, Byte.MIN_VALUE));
+        cipEqu(Double.valueOf(Byte.MAX_VALUE + 1.1e-6),
+                new OverloadedNumberUtil.DoubleOrFloat(Byte.MAX_VALUE + 1.1e-6));
+        cipEqu(Double.valueOf(Byte.MIN_VALUE - 1.1e-6),
+                new OverloadedNumberUtil.DoubleOrFloat(Byte.MIN_VALUE - 1.1e-6));
+        cipEqu(Double.valueOf(Byte.MAX_VALUE + 0.9999991),
+                new OverloadedNumberUtil.DoubleOrShort(
+                        Byte.MAX_VALUE + 0.9999991, (short) (Byte.MAX_VALUE + 1)));
+        cipEqu(Double.valueOf(Byte.MIN_VALUE - 0.9999991),
+                new OverloadedNumberUtil.DoubleOrShort(
+                        Byte.MIN_VALUE - 0.9999991, (short) (Byte.MIN_VALUE - 1)));
+        
+        cipEqu(Double.valueOf(Byte.MAX_VALUE + 1), new OverloadedNumberUtil.DoubleOrShort((double)
+                (Byte.MAX_VALUE + 1), (short) (Byte.MAX_VALUE + 1)));
+        cipEqu(Double.valueOf(Byte.MIN_VALUE - 1), new OverloadedNumberUtil.DoubleOrShort((double)
+                (Byte.MIN_VALUE - 1), (short) (Byte.MIN_VALUE - 1)));
+        
+        cipEqu(Short.MAX_VALUE + 0.9999991,
+                new OverloadedNumberUtil.DoubleOrIntegerOrFloat(Short.MAX_VALUE + 0.9999991, Short.MAX_VALUE + 1));
+        cipEqu(Short.MIN_VALUE - 0.9999991,
+                new OverloadedNumberUtil.DoubleOrIntegerOrFloat(Short.MIN_VALUE - 0.9999991, Short.MIN_VALUE - 1));
+        cipEqu(16777216 + 0.9e-6,
+                new OverloadedNumberUtil.DoubleOrIntegerOrFloat(16777216 + 0.9e-6, 16777216));
+        cipEqu(-16777216 - 0.9e-6,
+                new OverloadedNumberUtil.DoubleOrIntegerOrFloat(-16777216 - 0.9e-6, -16777216));
+        
+        cipEqu(Integer.MAX_VALUE + 0.9e-6,
+                new OverloadedNumberUtil.DoubleOrInteger(Integer.MAX_VALUE + 0.9e-6, Integer.MAX_VALUE));
+        cipEqu(Integer.MIN_VALUE - 0.9e-6,
+                new OverloadedNumberUtil.DoubleOrInteger(Integer.MIN_VALUE - 0.9e-6, Integer.MIN_VALUE));
+        
+        cipEqu(Integer.MAX_VALUE + 1L + 0.9e-6,
+                new OverloadedNumberUtil.DoubleOrFloat(Integer.MAX_VALUE + 1L + 0.9e-6));
+        cipEqu(Integer.MIN_VALUE - 1L - 0.9e-6,
+                new OverloadedNumberUtil.DoubleOrFloat(Integer.MIN_VALUE - 1L - 0.9e-6));
+        cipEqu(Long.MAX_VALUE + 0.9e-6,
+                new OverloadedNumberUtil.DoubleOrFloat(Long.MAX_VALUE + 0.9e-6));
+        cipEqu(Long.MIN_VALUE - 0.9e-6,
+                new OverloadedNumberUtil.DoubleOrFloat(Long.MIN_VALUE - 0.9e-6));
+    }
+
+    @SuppressWarnings("boxing")
+    public void testFloatCoercion() {
+        cipEqu(1.00002f);
+        cipEqu(-1.00002f);
+        cipEqu(1.999989f);
+        cipEqu(-1.999989f);
+        cipEqu(16777218f);
+        cipEqu(-16777218f);
+        
+        cipEqu(1f, new OverloadedNumberUtil.FloatOrByte(1f, (byte) 1));
+        cipEqu(-1f, new OverloadedNumberUtil.FloatOrByte(-1f, (byte) -1));
+        cipEqu(1.000009f, new OverloadedNumberUtil.FloatOrByte(1.000009f, (byte) 1));
+        cipEqu(-1.000009f, new OverloadedNumberUtil.FloatOrByte(-1.000009f, (byte) -1));
+        cipEqu(1.999991f, new OverloadedNumberUtil.FloatOrByte(1.999991f, (byte) 2));
+        cipEqu(-1.999991f, new OverloadedNumberUtil.FloatOrByte(-1.999991f, (byte) -2));
+        
+        cipEqu(1000f, new OverloadedNumberUtil.FloatOrShort(1000f, (short) 1000));
+        cipEqu(-1000f, new OverloadedNumberUtil.FloatOrShort(-1000f, (short) -1000));
+        cipEqu(1000.00006f);
+
+        cipEqu(60000f, new OverloadedNumberUtil.FloatOrInteger(60000f, 60000));
+        cipEqu(-60000f, new OverloadedNumberUtil.FloatOrInteger(-60000f, -60000));
+        cipEqu(60000.004f);
+
+        cipEqu(100f, new OverloadedNumberUtil.FloatOrByte(100f, (byte) 100), TypeFlags.MASK_KNOWN_INTEGERS);
+        cipEqu(1000f, new OverloadedNumberUtil.FloatOrShort(1000f, (short) 1000), TypeFlags.MASK_KNOWN_INTEGERS);
+        cipEqu(60000f, new OverloadedNumberUtil.FloatOrInteger(60000f, 60000), TypeFlags.MASK_KNOWN_INTEGERS);
+        cipEqu(60000f, new OverloadedNumberUtil.FloatOrInteger(60000f, 60000), TypeFlags.LONG);
+        cipEqu((float) Integer.MAX_VALUE, (float) Integer.MAX_VALUE, TypeFlags.LONG);
+        cipEqu((float) -Integer.MAX_VALUE, (float) -Integer.MAX_VALUE);
+        
+        cipEqu(0.5f, 0.5f, TypeFlags.DOUBLE | TypeFlags.FLOAT);
+        cipEqu(0.5f, 0.5f, TypeFlags.DOUBLE);
+    }
+    
+    public void testBigIntegerCoercion() {
+        BigInteger bi;
+        
+        cipEqu(BigInteger.ZERO, new OverloadedNumberUtil.BigIntegerOrByte(BigInteger.ZERO));
+        bi = new BigInteger(String.valueOf(Byte.MAX_VALUE));
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrByte(bi));
+        bi = new BigInteger(String.valueOf(Byte.MIN_VALUE));
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrByte(bi));
+        
+        bi = new BigInteger(String.valueOf(Byte.MAX_VALUE + 1));
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrShort(bi));
+        bi = new BigInteger(String.valueOf(Byte.MIN_VALUE - 1));
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrShort(bi));
+        bi = new BigInteger(String.valueOf(Short.MAX_VALUE));
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrShort(bi));
+        bi = new BigInteger(String.valueOf(Short.MIN_VALUE));
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrShort(bi));
+        
+        bi = new BigInteger(String.valueOf(Short.MAX_VALUE + 1));
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrInteger(bi));
+        bi = new BigInteger(String.valueOf(Short.MIN_VALUE - 1));
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrInteger(bi));
+        bi = new BigInteger(String.valueOf(Integer.MAX_VALUE));
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrInteger(bi));
+        bi = new BigInteger(String.valueOf(Integer.MIN_VALUE));
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrInteger(bi));
+        
+        bi = new BigInteger(String.valueOf(Integer.MAX_VALUE + 1L));
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrLong(bi));
+        bi = new BigInteger(String.valueOf(Integer.MIN_VALUE - 1L));
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrLong(bi));
+        bi = new BigInteger(String.valueOf(Long.MAX_VALUE));
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrLong(bi));
+        bi = new BigInteger(String.valueOf(Long.MIN_VALUE));
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrLong(bi));
+        
+        cipEqu(new BigInteger(String.valueOf(Long.MAX_VALUE)).add(BigInteger.ONE));
+        cipEqu(new BigInteger(String.valueOf(Long.MIN_VALUE)).subtract(BigInteger.ONE));
+        
+        bi = new BigInteger("0");
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrFloat(bi),
+                TypeFlags.DOUBLE | TypeFlags.FLOAT);
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrFloat(bi),
+                TypeFlags.MASK_KNOWN_NONINTEGERS);
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrFloat(bi),
+                TypeFlags.FLOAT);
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrDouble(bi),
+                TypeFlags.DOUBLE);
+
+        bi = new BigInteger("16777215");
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrFloat(bi), TypeFlags.MASK_KNOWN_NONINTEGERS);
+        bi = new BigInteger("-16777215");
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrFloat(bi), TypeFlags.MASK_KNOWN_NONINTEGERS);
+        
+        bi = new BigInteger("16777216");
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrFloat(bi), TypeFlags.MASK_KNOWN_NONINTEGERS);
+        bi = new BigInteger("-16777216");
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrFloat(bi), TypeFlags.MASK_KNOWN_NONINTEGERS);
+        
+        bi = new BigInteger("16777217");
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrDouble(bi), TypeFlags.MASK_KNOWN_NONINTEGERS);
+        cipEqu(bi, TypeFlags.FLOAT);
+        bi = new BigInteger("-16777217");
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrDouble(bi), TypeFlags.MASK_KNOWN_NONINTEGERS);
+        cipEqu(bi, TypeFlags.FLOAT);
+        
+        bi = new BigInteger("9007199254740991");
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrDouble(bi), TypeFlags.MASK_KNOWN_NONINTEGERS);
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrDouble(bi), TypeFlags.DOUBLE);
+        bi = new BigInteger("-9007199254740991");
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrDouble(bi), TypeFlags.MASK_KNOWN_NONINTEGERS);
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrDouble(bi), TypeFlags.DOUBLE);
+        
+        bi = new BigInteger("9007199254740992");
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrDouble(bi), TypeFlags.MASK_KNOWN_NONINTEGERS);
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrDouble(bi), TypeFlags.DOUBLE);
+        bi = new BigInteger("-9007199254740992");
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrDouble(bi), TypeFlags.MASK_KNOWN_NONINTEGERS);
+        cipEqu(bi, new OverloadedNumberUtil.BigIntegerOrDouble(bi), TypeFlags.DOUBLE);
+        
+        bi = new BigInteger("9007199254740993");
+        cipEqu(bi, TypeFlags.MASK_KNOWN_NONINTEGERS);
+        cipEqu(bi, TypeFlags.DOUBLE | TypeFlags.FLOAT);
+        cipEqu(bi, TypeFlags.FLOAT);
+        cipEqu(bi, TypeFlags.DOUBLE);
+        bi = new BigInteger("-9007199254740993");
+        cipEqu(bi, TypeFlags.MASK_KNOWN_NONINTEGERS);
+        cipEqu(bi, TypeFlags.DOUBLE | TypeFlags.FLOAT);
+        cipEqu(bi, TypeFlags.FLOAT);
+        cipEqu(bi, TypeFlags.DOUBLE);
+        
+        bi = new BigInteger("9007199254740994");
+        cipEqu(bi, TypeFlags.MASK_KNOWN_NONINTEGERS);
+        bi = new BigInteger("-9007199254740994");
+        cipEqu(bi, TypeFlags.MASK_KNOWN_NONINTEGERS);
+    }
+    
+    private void cipEqu(Number actualAndExpected) {
+        cipEqu(actualAndExpected, actualAndExpected, -1);
+    }
+    
+    private void cipEqu(Number actual, Number expected) {
+        cipEqu(actual, expected, -1);
+    }
+
+    private void cipEqu(Number actualAndExpected, int flags) {
+        cipEqu(actualAndExpected, actualAndExpected, flags);
+    }
+    
+    @SuppressWarnings("boxing")
+    private void cipEqu(Number actual, Number expected, int flags) {
+        Number res = OverloadedNumberUtil.addFallbackType(actual, flags);
+        assertEquals(expected.getClass(), res.getClass());
+        assertEquals(expected, res);
+        
+        // Some number types wrap the number with multiple types and equals() only compares one of them. So we try to
+        // catch any inconsistency:
+        assertEquals(expected.byteValue(), res.byteValue());
+        assertEquals(expected.shortValue(), res.shortValue());
+        assertEquals(expected.intValue(), res.intValue());
+        assertEquals(expected.longValue(), res.longValue());
+        assertEquals(expected.floatValue(), res.floatValue());
+        assertEquals(expected.doubleValue(), res.doubleValue());
+    }
+    
+    public void testGetArgumentConversionPrice() {
+        // Unknown number types:
+        assertEquals(Integer.MAX_VALUE, OverloadedNumberUtil.getArgumentConversionPrice(
+                RationalNumber.class, Integer.class));
+        assertEquals(Integer.MAX_VALUE, OverloadedNumberUtil.getArgumentConversionPrice(
+                Integer.class, RationalNumber.class));
+        assertEquals(Integer.MAX_VALUE, OverloadedNumberUtil.getArgumentConversionPrice(
+                RationalNumber.class, Float.class));
+        assertEquals(Integer.MAX_VALUE, OverloadedNumberUtil.getArgumentConversionPrice(
+                Float.class, RationalNumber.class));
+        assertEquals(0, OverloadedNumberUtil.getArgumentConversionPrice(
+                RationalNumber.class, RationalNumber.class));
+        
+        // Fully check some rows (not all of them; the code is generated anyways):
+
+        assertEquals(Integer.MAX_VALUE, OverloadedNumberUtil.getArgumentConversionPrice(
+                Integer.class, Byte.class));
+        assertEquals(Integer.MAX_VALUE, OverloadedNumberUtil.getArgumentConversionPrice(
+                Integer.class, Short.class));
+        assertEquals(0, OverloadedNumberUtil.getArgumentConversionPrice(
+                Integer.class, Integer.class));
+        assertEquals(10004, OverloadedNumberUtil.getArgumentConversionPrice(
+                Integer.class, Long.class));
+        assertEquals(10005, OverloadedNumberUtil.getArgumentConversionPrice(
+                Integer.class, BigInteger.class));
+        assertEquals(30006, OverloadedNumberUtil.getArgumentConversionPrice(
+                Integer.class, Float.class));
+        assertEquals(20007, OverloadedNumberUtil.getArgumentConversionPrice(
+                Integer.class, Double.class));
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                Integer.class, BigDecimal.class));
+        
+        assertEquals(45001, OverloadedNumberUtil.getArgumentConversionPrice(
+                BigDecimal.class, Byte.class));
+        assertEquals(44002, OverloadedNumberUtil.getArgumentConversionPrice(
+                BigDecimal.class, Short.class));
+        assertEquals(41003, OverloadedNumberUtil.getArgumentConversionPrice(
+                BigDecimal.class, Integer.class));
+        assertEquals(41004, OverloadedNumberUtil.getArgumentConversionPrice(
+                BigDecimal.class, Long.class));
+        assertEquals(40005, OverloadedNumberUtil.getArgumentConversionPrice(
+                BigDecimal.class, BigInteger.class));
+        assertEquals(33006, OverloadedNumberUtil.getArgumentConversionPrice(
+                BigDecimal.class, Float.class));
+        assertEquals(32007, OverloadedNumberUtil.getArgumentConversionPrice(
+                BigDecimal.class, Double.class));
+        assertEquals(0, OverloadedNumberUtil.getArgumentConversionPrice(
+                BigDecimal.class, BigDecimal.class));
+        
+        assertEquals(Integer.MAX_VALUE, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.DoubleOrLong.class, Byte.class));
+        assertEquals(Integer.MAX_VALUE, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.DoubleOrLong.class, Short.class));
+        assertEquals(Integer.MAX_VALUE, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.DoubleOrLong.class, Integer.class));
+        assertEquals(21004, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.DoubleOrLong.class, Long.class));
+        assertEquals(21005, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.DoubleOrLong.class, BigInteger.class));
+        assertEquals(40006, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.DoubleOrLong.class, Float.class));
+        assertEquals(0, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.DoubleOrLong.class, Double.class));
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.DoubleOrLong.class, BigDecimal.class));
+        
+        assertEquals(Integer.MAX_VALUE, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.BigIntegerOrDouble.class, Byte.class));
+        assertEquals(Integer.MAX_VALUE, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.BigIntegerOrDouble.class, Short.class));
+        assertEquals(Integer.MAX_VALUE, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.BigIntegerOrDouble.class, Integer.class));
+        assertEquals(Integer.MAX_VALUE, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.BigIntegerOrDouble.class, Long.class));
+        assertEquals(0, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.BigIntegerOrDouble.class, BigInteger.class));
+        assertEquals(40006, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.BigIntegerOrDouble.class, Float.class));
+        assertEquals(20007, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.BigIntegerOrDouble.class, Double.class));
+        assertEquals(10008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.BigIntegerOrDouble.class, BigDecimal.class));
+        
+        // Check if all fromC is present:
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                Byte.class, BigDecimal.class));
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                Short.class, BigDecimal.class));
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                Integer.class, BigDecimal.class));
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                Long.class, BigDecimal.class));
+        assertEquals(10008, OverloadedNumberUtil.getArgumentConversionPrice(
+                BigInteger.class, BigDecimal.class));
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                Float.class, BigDecimal.class));
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                Double.class, BigDecimal.class));
+        assertEquals(0, OverloadedNumberUtil.getArgumentConversionPrice(
+                BigDecimal.class, BigDecimal.class));
+        assertEquals(0, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.IntegerBigDecimal.class, BigDecimal.class));
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.DoubleOrFloat.class, BigDecimal.class));
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.FloatOrByte.class, BigDecimal.class));
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.DoubleOrShort.class, BigDecimal.class));
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.FloatOrByte.class, BigDecimal.class));
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.FloatOrShort.class, BigDecimal.class));
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.FloatOrInteger.class, BigDecimal.class));
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.DoubleOrByte.class, BigDecimal.class));
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.DoubleOrIntegerOrFloat.class, BigDecimal.class));
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.DoubleOrInteger.class, BigDecimal.class));
+        assertEquals(20008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.DoubleOrLong.class, BigDecimal.class));
+        assertEquals(10008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.BigIntegerOrByte.class, BigDecimal.class));
+        assertEquals(10008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.BigIntegerOrShort.class, BigDecimal.class));
+        assertEquals(10008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.BigIntegerOrInteger.class, BigDecimal.class));
+        assertEquals(10008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.BigIntegerOrLong.class, BigDecimal.class));
+        assertEquals(10008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.BigIntegerOrFloat.class, BigDecimal.class));
+        assertEquals(10008, OverloadedNumberUtil.getArgumentConversionPrice(
+                OverloadedNumberUtil.BigIntegerOrDouble.class, BigDecimal.class));
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/ParameterListPreferabilityTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/ParameterListPreferabilityTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/ParameterListPreferabilityTest.java
new file mode 100644
index 0000000..3e6c2ed
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/ParameterListPreferabilityTest.java
@@ -0,0 +1,445 @@
+/*
+ * 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.model.impl;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.apache.freemarker.core.util._NumberUtil;
+
+import junit.framework.TestCase;
+
+@SuppressWarnings("boxing")
+public class ParameterListPreferabilityTest extends TestCase {
+
+    public ParameterListPreferabilityTest(String name) {
+        super(name);
+    }
+    
+    public void testNumberical() {
+        // Note: the signature lists consists of the same elements, only their order changes depending on the type
+        // of the argument value.
+        
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { byte.class },
+                    new Class[] { Byte.class },
+                    new Class[] { short.class },
+                    new Class[] { Short.class },
+                    new Class[] { int.class },
+                    new Class[] { Integer.class },
+                    new Class[] { long.class },
+                    new Class[] { Long.class },
+                    new Class[] { BigInteger.class },
+                    new Class[] { float.class },
+                    new Class[] { Float.class },
+                    new Class[] { double.class },
+                    new Class[] { Double.class },
+                    new Class[] { BigDecimal.class },
+                    new Class[] { Number.class },
+                    new Class[] { Serializable.class },
+                    new Class[] { Object.class }
+                },
+                new Object[] { (byte) 1 });
+        
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { BigDecimal.class },
+                    new Class[] { BigInteger.class },
+                    new Class[] { int.class },
+                    new Class[] { Integer.class },
+                    new Class[] { long.class },
+                    new Class[] { Long.class },
+                    new Class[] { double.class },
+                    new Class[] { Double.class },
+                    new Class[] { float.class },
+                    new Class[] { Float.class },
+                    new Class[] { short.class },
+                    new Class[] { Short.class },
+                    new Class[] { byte.class },
+                    new Class[] { Byte.class },
+                    new Class[] { Number.class },
+                    new Class[] { Serializable.class },
+                    new Class[] { Object.class },
+                },
+                new Object[] { new OverloadedNumberUtil.IntegerBigDecimal(new BigDecimal("1")) });
+
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { BigDecimal.class },
+                    new Class[] { double.class },
+                    new Class[] { Double.class },
+                    new Class[] { float.class },
+                    new Class[] { Float.class },
+                    new Class[] { BigInteger.class },
+                    new Class[] { int.class },
+                    new Class[] { Integer.class },
+                    new Class[] { long.class },
+                    new Class[] { Long.class },
+                    new Class[] { short.class },
+                    new Class[] { Short.class },
+                    new Class[] { byte.class },
+                    new Class[] { Byte.class },
+                    new Class[] { Number.class },
+                    new Class[] { Serializable.class },
+                    new Class[] { Object.class },
+                },
+                new Object[] { new BigDecimal("1") /* possibly non-integer */ });
+        
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { float.class },
+                    new Class[] { Float.class },
+                    new Class[] { double.class },
+                    new Class[] { Double.class },
+                    new Class[] { BigDecimal.class },
+                    new Class[] { int.class },
+                    new Class[] { Integer.class },
+                    new Class[] { long.class },
+                    new Class[] { Long.class },
+                    new Class[] { short.class },
+                    new Class[] { Short.class },
+                    new Class[] { byte.class },
+                    new Class[] { Byte.class },
+                    new Class[] { BigInteger.class },
+                    new Class[] { Number.class },
+                    new Class[] { Serializable.class },
+                    new Class[] { Object.class },
+                },
+                new Object[] { new OverloadedNumberUtil.FloatOrByte(1f, (byte) 1) });
+        
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { int.class },
+                    new Class[] { Integer.class },
+                    new Class[] { long.class },
+                    new Class[] { Long.class },
+                    new Class[] { BigInteger.class },
+                    new Class[] { double.class },
+                    new Class[] { Double.class },
+                    new Class[] { BigDecimal.class },
+                    new Class[] { short.class },
+                    new Class[] { Short.class },
+                    new Class[] { float.class },
+                    new Class[] { Float.class },
+                    
+                    // Two incompatibles removed, would be removed in reality:
+                    new Class[] { byte.class },
+                    new Class[] { Byte.class },
+                    
+                    new Class[] { Number.class },
+                    new Class[] { Serializable.class },
+                    new Class[] { Object.class }
+                },
+                new Object[] { new OverloadedNumberUtil.IntegerOrShort(1, (short) 1) });
+        
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { long.class },
+                    new Class[] { Long.class },
+                    new Class[] { BigInteger.class },
+                    new Class[] { BigDecimal.class },
+                    new Class[] { double.class },
+                    new Class[] { Double.class },
+                    new Class[] { float.class },
+                    new Class[] { Float.class },
+                    // skip byte and short  as the would be equal with int (all invalid target types)
+                    new Class[] { int.class },  // In reality, this and Integer are removed as not-applicable overloads
+                    new Class[] { Integer.class },
+                    new Class[] { Number.class },
+                    new Class[] { Serializable.class },
+                    new Class[] { Object.class }
+                },
+                new Object[] { 1L });
+        
+        // Undecidable comparisons:
+        
+        testAllCmpPermutationsEqu(
+                new Class[][] {
+                        new Class[] { Byte.class },
+                        new Class[] { Short.class },
+                        new Class[] { Integer.class },
+                        new Class[] { Long.class },
+                        new Class[] { BigInteger.class },
+                        new Class[] { Float.class },
+                    },
+                    new Object[] { 1.0 });
+        
+        testAllCmpPermutationsEqu(
+                new Class[][] {
+                        new Class[] { byte.class },
+                        new Class[] { short.class },
+                        new Class[] { int.class },
+                        new Class[] { long.class },
+                        new Class[] { float.class },
+                    },
+                    new Object[] { 1.0 });
+    }
+    
+    public void testPrimitiveIsMoreSpecific() {
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { boolean.class },
+                    new Class[] { Boolean.class }
+                },
+                new Object[] { true });
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { char.class },
+                    new Class[] { Character.class }
+                },
+                new Object[] { 'x' });
+    }
+    
+    public void testCharIsMoreSpecificThanString() {
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { char.class },
+                    new Class[] { Character.class },
+                    new Class[] { String.class },
+                    new Class[] { CharSequence.class }
+                },
+                new Object[] { "s" });
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { char.class },
+                    new Class[] { Character.class },
+                    new Class[] { String.class }
+                },
+                new Object[] { 'c' });
+    }
+    
+    public void testClassHierarchy() {
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { LinkedHashMap.class },
+                    new Class[] { HashMap.class },
+                    new Class[] { Map.class },
+                    new Class[] { Object.class }
+                },
+                new Object[] { new LinkedHashMap() });
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { LinkedHashMap.class },
+                    new Class[] { Cloneable.class },
+                    new Class[] { Object.class }
+                },
+                new Object[] { new LinkedHashMap() });
+    }
+
+    public void testNumericalWithNonNumerical() {
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { int.class },
+                    new Class[] { Integer.class },
+                    new Class[] { Comparable.class },
+                    new Class[] { Object.class },
+                },
+                new Object[] { 1 });
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { int.class },
+                    new Class[] { Integer.class },
+                    new Class[] { char.class },
+                    new Class[] { Character.class },
+                },
+                new Object[] { 1 });
+    }
+    
+    public void testUnrelated() {
+        testAllCmpPermutationsEqu(
+                new Class[][] {
+                    new Class[] { Serializable.class },
+                    new Class[] { CharSequence.class },
+                    new Class[] { Comparable.class }
+                },
+                new Object[] { "s" });
+        
+        testAllCmpPermutationsEqu(
+                new Class[][] {
+                    new Class[] { HashMap.class },
+                    new Class[] { TreeMap.class }
+                },
+                new Object[] { null });
+    }
+
+    public void testMultiParameter() {
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { String.class, String.class, String.class },
+                        
+                    new Class[] { String.class, String.class, Object.class },
+                    new Class[] { String.class, Object.class, String.class },
+                    new Class[] { Object.class, String.class, String.class },
+                    
+                    new Class[] { String.class, Object.class, Object.class },
+                    new Class[] { Object.class, String.class, Object.class },
+                    new Class[] { Object.class, Object.class, String.class },
+                    
+                    new Class[] { Object.class, Object.class, Object.class },
+                },
+                new Object[] { "a", "b", "c" });
+        
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { String.class, String.class },
+                    new Class[] { String.class, Object.class },
+                    new Class[] { CharSequence.class, CharSequence.class },
+                    new Class[] { CharSequence.class, Object.class },
+                    new Class[] { Object.class, String.class },
+                    new Class[] { Object.class, CharSequence.class },
+                    new Class[] { Object.class, Object.class },
+                },
+                new Object[] { "a", "b" });
+        
+        // Subclassing is more important than primitive-VS-boxed:
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { boolean.class, boolean.class, boolean.class, String.class },
+                    new Class[] { Boolean.class, boolean.class, boolean.class, String.class },
+                    new Class[] { boolean.class, Boolean.class, Boolean.class, String.class },
+                    new Class[] { Boolean.class, boolean.class, Boolean.class, String.class },
+                    new Class[] { Boolean.class, Boolean.class, boolean.class, String.class },
+                    new Class[] { Boolean.class, Boolean.class, Boolean.class, String.class },
+                    new Class[] { Boolean.class, Boolean.class, Boolean.class, CharSequence.class },
+                    new Class[] { boolean.class, boolean.class, boolean.class, Object.class },
+                    new Class[] { Boolean.class, boolean.class, boolean.class, Object.class },
+                    new Class[] { boolean.class, Boolean.class, Boolean.class, Object.class },
+                    new Class[] { Boolean.class, boolean.class, Boolean.class, Object.class },
+                    new Class[] { Boolean.class, Boolean.class, boolean.class, Object.class },
+                    new Class[] { Boolean.class, Boolean.class, Boolean.class, Object.class },
+                },
+                new Object[] { true, false, true, "a" });
+        
+        // Subclassing is more important than primitive-VS-boxed:
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { int.class, int.class, int.class, String.class },
+                    new Class[] { Integer.class, int.class, int.class, String.class },
+                    new Class[] { int.class, Integer.class, Integer.class, String.class },
+                    new Class[] { Integer.class, int.class, Integer.class, String.class },
+                    new Class[] { Integer.class, Integer.class, int.class, String.class },
+                    new Class[] { Integer.class, Integer.class, Integer.class, String.class },
+                    new Class[] { Integer.class, Integer.class, Integer.class, CharSequence.class },
+                    new Class[] { int.class, int.class, int.class, Object.class },
+                    new Class[] { Integer.class, int.class, int.class, Object.class },
+                    new Class[] { int.class, Integer.class, Integer.class, Object.class },
+                    new Class[] { Integer.class, int.class, Integer.class, Object.class },
+                    new Class[] { Integer.class, Integer.class, int.class, Object.class },
+                    new Class[] { Integer.class, Integer.class, Integer.class, Object.class },
+                },
+                new Object[] { 1, 2, 3, "a" });
+    }
+
+    public void testVarargs() {
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { String.class, String[].class },
+                    new Class[] { String.class, CharSequence[].class },
+                    new Class[] { String.class, Object[].class },
+                },
+                new Object[] { "a", "b", "c" },
+                true);
+        
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { String.class, int[].class },
+                    new Class[] { String.class, Integer[].class },
+                    new Class[] { String.class, long[].class },
+                    new Class[] { String.class, Long[].class },
+                    new Class[] { String.class, double[].class },
+                    new Class[] { String.class, Double[].class },
+                    new Class[] { String.class, Serializable[].class },
+                    new Class[] { String.class, Object[].class },
+                },
+                new Object[] { "a", 1, 2, 3 },
+                true);
+        
+        // 0-long varargs list; in case of ambiguity, the varargs component type decides:
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { String.class, Object[].class },
+                    new Class[] { CharSequence.class, int[].class },
+                    new Class[] { CharSequence.class, Integer[].class },
+                    new Class[] { CharSequence.class, long[].class },
+                    new Class[] { CharSequence.class, Long[].class },
+                    new Class[] { CharSequence.class, double[].class },
+                    new Class[] { CharSequence.class, Double[].class },
+                    new Class[] { CharSequence.class, Serializable[].class },
+                    new Class[] { CharSequence.class, Object[].class },
+                    new Class[] { Object.class, int[].class },
+                },
+                new Object[] { "a" },
+                true);
+        
+        
+        // Different oms prefix length; in the case of ambiguity, the one with higher oms param count wins.
+        testAllCmpPermutationsInc(
+                new Class[][] {
+                    new Class[] { String.class, int.class, int.class, int[].class },
+                    new Class[] { String.class, int.class, int[].class },
+                    new Class[] { String.class, int[].class },
+                },
+                new Object[] { "a", 1, 2, 3 },
+                true);
+    }
+    
+    private void testAllCmpPermutationsInc(Class[][] sortedSignatures, Object[] args) {
+        testAllCmpPermutationsInc(sortedSignatures, args, false);
+    }
+
+    /**
+     * Compares all items with all other items in the provided descending sorted array of signatures, checking that
+     * for all valid indexes i and j, where j > i, it stands that sortedSignatures[i] > sortedSignatures[j].
+     * The comparisons are done with both operand orders, also each items is compared to itself too.
+     * 
+     * @param sortedSignatures method signatures sorted by decreasing specificity
+     */
+    private void testAllCmpPermutationsInc(Class[][] sortedSignatures, Object[] args, boolean varargs) {
+        final ArgumentTypes argTs = new ArgumentTypes(args);
+        for (int i = 0; i < sortedSignatures.length; i++) {
+            for (int j = 0; j < sortedSignatures.length; j++) {
+                assertEquals("sortedSignatures[" + i + "] <==> sortedSignatures [" + j + "]",
+                        _NumberUtil.getSignum(
+                                Integer.valueOf(j).compareTo(i)),
+                        _NumberUtil.getSignum(
+                                argTs.compareParameterListPreferability(
+                                        sortedSignatures[i], sortedSignatures[j], varargs)));
+            }
+        }
+    }
+
+    private void testAllCmpPermutationsEqu(Class[][] signatures, Object[] args) {
+        final ArgumentTypes argTs = new ArgumentTypes(args);
+        for (int i = 0; i < signatures.length; i++) {
+            for (int j = 0; j < signatures.length; j++) {
+                assertEquals("sortedSignatures[" + i + "] <==> sortedSignatures [" + j + "]",
+                        0,
+                        argTs.compareParameterListPreferability(signatures[i], signatures[j], false));
+            }
+        }
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/PrallelObjectIntrospectionTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/PrallelObjectIntrospectionTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/PrallelObjectIntrospectionTest.java
new file mode 100644
index 0000000..4f4c0a1
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/PrallelObjectIntrospectionTest.java
@@ -0,0 +1,43 @@
+/*
+ * 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.model.impl;
+
+import org.apache.freemarker.core.model.TemplateHashModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+
+public class PrallelObjectIntrospectionTest extends AbstractParallelIntrospectionTest {
+
+    public PrallelObjectIntrospectionTest(String name) {
+        super(name);
+    }
+
+    public static void main(String[] args) {
+        new PrallelObjectIntrospectionTest("almostForever")
+                .testReliability(Integer.MAX_VALUE);
+    }
+    
+    @Override
+    protected TemplateHashModel getWrappedEntity(int objIdx)
+    throws TemplateModelException {
+        return (TemplateHashModel) getObjectWrapper().wrap(
+                ManyObjectsOfDifferentClasses.OBJECTS[objIdx]);
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/PrallelStaticIntrospectionTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/PrallelStaticIntrospectionTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/PrallelStaticIntrospectionTest.java
new file mode 100644
index 0000000..836d559
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/PrallelStaticIntrospectionTest.java
@@ -0,0 +1,47 @@
+/*
+ * 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.model.impl;
+
+import org.apache.freemarker.core.model.TemplateHashModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+
+public class PrallelStaticIntrospectionTest extends AbstractParallelIntrospectionTest {
+
+    private static final String STATICS_CLASS_CONTAINER_CLASS_NAME
+            = ManyStaticsOfDifferentClasses.class.getName();
+
+    public PrallelStaticIntrospectionTest(String name) {
+        super(name);
+    }
+
+    public static void main(String[] args) {
+        new PrallelStaticIntrospectionTest("almostForever")
+                .testReliability(Integer.MAX_VALUE);
+    }
+    
+    @Override
+    protected TemplateHashModel getWrappedEntity(int clIdx)
+    throws TemplateModelException {
+        return (TemplateHashModel) getObjectWrapper().getStaticModels().get(
+                STATICS_CLASS_CONTAINER_CLASS_NAME + "$C"
+                + clIdx);
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/RationalNumber.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/RationalNumber.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/RationalNumber.java
new file mode 100644
index 0000000..806a186
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/RationalNumber.java
@@ -0,0 +1,90 @@
+/*
+ * 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.model.impl;
+
+public final class RationalNumber extends Number {
+    
+    final int divident;
+    final int divisor;
+    
+    public RationalNumber(int divident, int divisor) {
+        this.divident = divident;
+        this.divisor = divisor;
+    }
+
+    @Override
+    public int intValue() {
+        return divident / divisor;
+    }
+
+    @Override
+    public long longValue() {
+        return divident / (long) divisor;
+    }
+
+    @Override
+    public float floatValue() {
+        return (float) (divident / (double) divisor);
+    }
+
+    @Override
+    public double doubleValue() {
+        return divident / (double) divisor;
+    }
+
+    public int getDivident() {
+        return divident;
+    }
+
+    public int getDivisor() {
+        return divisor;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + divident;
+        result = prime * result + divisor;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        RationalNumber other = (RationalNumber) obj;
+        if (divident != other.divident)
+            return false;
+        if (divisor != other.divisor)
+            return false;
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return divident + "/" + divisor;
+    }
+    
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/StaticModelsTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/StaticModelsTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/StaticModelsTest.java
new file mode 100644
index 0000000..609d632
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/model/impl/StaticModelsTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.model.impl;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.util.ArrayList;
+
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.model.TemplateHashModel;
+import org.apache.freemarker.core.model.TemplateMethodModelEx;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateScalarModel;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class StaticModelsTest {
+
+    @Test
+    public void modelCaching() throws Exception {
+        DefaultObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).usePrivateCaches(true)
+                .build();
+        TemplateHashModel statics = ow.getStaticModels();
+        TemplateHashModel s = (TemplateHashModel) statics.get(S.class.getName());
+        assertNotNull(s);
+        assertNotNull(s.get("F"));
+        assertNotNull(s.get("m"));
+        try {
+            s.get("x");
+            fail();
+        } catch (TemplateModelException e) {
+            assertThat(e.getMessage(), containsString("No such key"));
+        }
+        
+        try {
+            statics.get("no.such.ClassExists");
+            fail();
+        } catch (TemplateModelException e) {
+            assertTrue(e.getCause() instanceof ClassNotFoundException);
+        }
+        
+        TemplateModel f = s.get("F");
+        assertTrue(f instanceof TemplateScalarModel);
+        assertEquals(((TemplateScalarModel) f).getAsString(), "F OK");
+        
+        TemplateModel m = s.get("m");
+        assertTrue(m instanceof TemplateMethodModelEx);
+        assertEquals(((TemplateScalarModel) ((TemplateMethodModelEx) m).exec(new ArrayList())).getAsString(), "m OK");
+        
+        assertSame(s, statics.get(S.class.getName()));
+        
+        ow.clearClassIntrospecitonCache();
+        TemplateHashModel sAfterClean = (TemplateHashModel) statics.get(S.class.getName());
+        assertNotSame(s, sAfterClean);
+        assertSame(sAfterClean, statics.get(S.class.getName()));
+        assertNotNull(sAfterClean.get("F"));
+        assertNotNull(sAfterClean.get("m"));
+    }
+    
+    public static class S {
+        
+        public static final String F = "F OK"; 
+        
+        public static String m() {
+            return "m OK";
+        }
+        
+    }
+    
+}


[32/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/TransformHashWrapper.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/TransformHashWrapper.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/TransformHashWrapper.java
new file mode 100644
index 0000000..4602b67
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/TransformHashWrapper.java
@@ -0,0 +1,79 @@
+/*
+ * 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.test.templatesuite.models;
+
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.model.ObjectWrapper;
+import org.apache.freemarker.core.model.TemplateHashModel;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateScalarModel;
+import org.apache.freemarker.core.model.impl.DefaultObjectWrapper;
+import org.apache.freemarker.core.model.impl.SimpleHash;
+import org.apache.freemarker.core.util.HtmlEscape;
+import org.apache.freemarker.core.util.StandardCompress;
+
+/**
+ * Part of the TestTransform testcase suite.
+ */
+public class TransformHashWrapper implements TemplateHashModel,
+        TemplateScalarModel {
+
+    private ObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
+    private SimpleHash m_cHashModel = new SimpleHash(ow);
+
+    /** Creates new TransformHashWrapper */
+    public TransformHashWrapper() {
+        m_cHashModel.put( "htmlEscape", new HtmlEscape() );
+        m_cHashModel.put( "compress", new StandardCompress() );
+        m_cHashModel.put( "escape", new TransformMethodWrapper1() );
+        m_cHashModel.put( "special", new TransformMethodWrapper2() );
+    }
+
+    /**
+     * Gets a <tt>TemplateModel</tt> from the hash.
+     *
+     * @param key the name by which the <tt>TemplateModel</tt>
+     * is identified in the template.
+     * @return the <tt>TemplateModel</tt> referred to by the key,
+     * or null if not found.
+     */
+    @Override
+    public TemplateModel get(String key) throws TemplateModelException {
+        return m_cHashModel.get( key );
+    }
+
+    /**
+     * @return true if this object is empty.
+     */
+    @Override
+    public boolean isEmpty() {
+        return false;
+    }
+
+    /**
+     * Returns the scalar's value as a String.
+     * @return the String value of this scalar.
+     */
+    @Override
+    public String getAsString() {
+        return "Utility transformations";
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/TransformMethodWrapper1.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/TransformMethodWrapper1.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/TransformMethodWrapper1.java
new file mode 100644
index 0000000..8311134
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/TransformMethodWrapper1.java
@@ -0,0 +1,49 @@
+/*
+ * 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.test.templatesuite.models;
+
+import java.util.List;
+
+import org.apache.freemarker.core.model.TemplateMethodModel;
+import org.apache.freemarker.core.util.HtmlEscape;
+import org.apache.freemarker.core.util.XmlEscape;
+
+/**
+ * Simple test of the interaction between MethodModels and TransformModels.
+ */
+public class TransformMethodWrapper1 implements TemplateMethodModel {
+
+    /**
+     * Executes a method call.
+     *
+     * @param arguments a <tt>List</tt> of <tt>String</tt> objects containing
+     * the values of the arguments passed to the method.
+     * @return the <tt>TemplateModel</tt> produced by the method, or null.
+     */
+    @Override
+    public Object exec(List arguments) {
+
+        if (( arguments.size() > 0 ) && ( arguments.get( 0 ).toString().equals( "xml" ))) {
+            return new XmlEscape();
+        } else {
+            return new HtmlEscape();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/TransformMethodWrapper2.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/TransformMethodWrapper2.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/TransformMethodWrapper2.java
new file mode 100644
index 0000000..96eb1a5
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/TransformMethodWrapper2.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.test.templatesuite.models;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.freemarker.core.model.TemplateMethodModel;
+
+/**
+ * Another test of the interaction between MethodModels and TransformModels.
+ */
+public class TransformMethodWrapper2 implements TemplateMethodModel {
+
+    /**
+     * Executes a method call.
+     *
+     * @param arguments a <tt>List</tt> of <tt>String</tt> objects containing
+     * the values of the arguments passed to the method.
+     * @return the <tt>TemplateModel</tt> produced by the method, or null.
+     */
+    @Override
+    public Object exec(List arguments) {
+        TransformModel1 cTransformer = new TransformModel1();
+        Iterator    iArgument = arguments.iterator();
+
+        // Sets up properties of the Transform model based on the arguments
+        // passed into this method
+
+        while ( iArgument.hasNext() ) {
+            String  aArgument = (String) iArgument.next();
+
+            if ( aArgument.equals( "quote" )) {
+                cTransformer.setQuotes( true );
+            } else if ( aArgument.equals( "tag" )) {
+                cTransformer.setTags( true );
+            } else if ( aArgument.equals( "ampersand" )) {
+                cTransformer.setAmpersands( true );
+            } else {
+                cTransformer.setComment( aArgument );
+            }
+        }
+
+        // Now return the transform class.
+        return cTransformer;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/TransformModel1.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/TransformModel1.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/TransformModel1.java
new file mode 100644
index 0000000..0875679
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/TransformModel1.java
@@ -0,0 +1,175 @@
+/*
+ * 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.test.templatesuite.models;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.Map;
+
+import org.apache.freemarker.core.model.TemplateTransformModel;
+
+/**
+ * A TemplateTransformModel that includes properties. These properties can be
+ * set at model construction time, or, for the purposes of this demonstration,
+ * can be passed in from a wrapper TemplateMethodModel.
+ */
+public class TransformModel1 implements TemplateTransformModel {
+
+    private boolean m_bAmpersands = false;
+    private boolean m_bQuotes = false;
+    private boolean m_bTags = false;
+    private String  m_aComment = "";
+
+    private static final int READER_BUFFER_SIZE = 4096;
+
+    @Override
+    public Writer getWriter(final Writer out,
+                            final Map args) {
+        final StringBuilder buf = new StringBuilder();
+        return new Writer(out) {
+            @Override
+            public void write(char cbuf[], int off, int len) {
+                buf.append(cbuf, off, len);
+            }
+
+            @Override
+            public void flush() {
+            }
+
+            @Override
+            public void close() throws IOException {
+                StringReader sr = new StringReader(buf.toString());
+                StringWriter sw = new StringWriter();
+                transform(sr, sw);
+                out.write(sw.toString());
+            }
+        };
+    }
+
+
+    /**
+     * Indicates whether we escape ampersands. This property can be set either
+     * while the model is being constructed, or via a property passed in through
+     * a <code>TemplateMethodModel</code>.
+     */
+    public void setAmpersands( boolean bAmpersands ) {
+        m_bAmpersands = bAmpersands;
+    }
+
+    /**
+     * Indicates whether we escape quotes. This property can be set either
+     * while the model is being constructed, or via a property passed in through
+     * a <code>TemplateMethodModel</code>.
+     */
+    public void setQuotes( boolean bQuotes ) {
+        m_bQuotes = bQuotes;
+    }
+
+    /**
+     * Indicates whether we escape tags. This property can be set either
+     * while the model is being constructed, or via a property passed in through
+     * a <code>TemplateMethodModel</code>.
+     */
+    public void setTags( boolean bTags ) {
+        m_bTags = bTags;
+    }
+
+    /**
+     * Sets a comment for this transformation. This property can be set either
+     * while the model is being constructed, or via a property passed in through
+     * a <code>TemplateMethodModel</code>.
+     */
+    public void setComment( String aComment ) {
+        m_aComment = aComment;
+    }
+
+    /**
+     * Performs a transformation/filter on FreeMarker output.
+     *
+     * @param source the input to be transformed
+     * @param output the destination of the transformation
+     */
+    public void transform(Reader source, Writer output)
+    throws IOException {
+        // Output the source, converting unsafe certain characters to their
+        // equivalent entities.
+        int n = 0;
+        boolean bCommentSent = false;
+        char[]  aBuffer = new char[ READER_BUFFER_SIZE ];
+        int i = source.read( aBuffer );
+        while (i >= 0) {
+            for ( int j = 0; j < i; j++ ) {
+                char c = aBuffer[j];
+                switch (c) {
+                    case '&':
+                        if ( m_bAmpersands ) {
+                            output.write("&amp;");
+                        } else {
+                            output.write( c );
+                        }
+                        break;
+                    case '<':
+                        if ( m_bTags ) {
+                            output.write("&lt;");
+                        } else {
+                            output.write( c );
+                        }
+                        break;
+                    case '>':
+                        if ( m_bTags ) {
+                            output.write("&gt;");
+                        } else {
+                            output.write( c );
+                        }
+                        break;
+                    case '"':
+                        if ( m_bQuotes ) {
+                            output.write("&quot;");
+                        } else {
+                            output.write( c );
+                        }
+                        break;
+                    case '\'':
+                        if ( m_bQuotes ) {
+                            output.write("&apos;");
+                        } else {
+                            output.write( c );
+                        }
+                        break;
+                    case '*':
+                        if ( ! bCommentSent ) {
+                            output.write( m_aComment );
+                            bCommentSent = true;
+                        } else {
+                            output.write( c );
+                        }
+                        break;
+                    default:
+                        output.write(c);
+                }
+                n++;
+            }
+            i = source.read( aBuffer );
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/VarArgTestModel.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/VarArgTestModel.java b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/VarArgTestModel.java
new file mode 100644
index 0000000..940cb17
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/models/VarArgTestModel.java
@@ -0,0 +1,63 @@
+/*
+ * 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.test.templatesuite.models;
+
+import java.util.Date;
+
+public class VarArgTestModel {
+
+    public int bar(Integer... xs) {
+        int sum = 0;
+        for (Integer x : xs) {
+            if (x != null) {
+                sum *= 100;
+                sum += x;
+            }
+        }
+        return sum;
+    }
+
+    public int bar2(int first, int... xs) {
+        int sum = 0;
+        for (int x : xs) {
+            sum *= 100;
+            sum += x;
+        }
+        return -(sum * 100 + first);
+    }
+    
+    public int overloaded(int x, int y) {
+        return x * 100 + y;
+    }
+
+    public int overloaded(int... xs) {
+        int sum = 0;
+        for (int x : xs) {
+            sum *= 100;
+            sum += x;
+        }
+        return -sum;
+    }
+    
+    public String noVarArgs(String s, boolean b, int i, Date d) {
+        return s + ", " + b + ", " + i + ", " + d.getTime();
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/package.html
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/package.html b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/package.html
new file mode 100644
index 0000000..cabffb0
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/test/templatesuite/package.html
@@ -0,0 +1,42 @@
+<!--
+  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.
+-->
+<html>
+<head>
+</head>
+<body>
+
+<p>JUnit test-suite that processes FreeMarker templates and compare their
+output to reference files.</p>
+
+<p>To add a test-case, go to
+<tt>src/test/resources/freemarker/test/templatesuite/</tt> and inside that
+directory:</p>
+<ol>
+  <li>Add a template to under <tt>templates/</tt> with whatever meaningful
+      file name</li>
+  <li>Add the expected output to <tt>references/</tt> with exactly the same
+      file name</li>
+  <li>Add a new <tt>testcase</tt> elemen to <tt>testcases.xml</tt></li>
+  <li>If you want to add items to the data-model or do something else special,
+      modify the <tt>setUp()</tt> method in
+      <tt>src/test/java/freemarker/test/templatesuite/TemplateTestCase.java</tt>
+      </li>
+</ol>
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-1.ast
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-1.ast b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-1.ast
new file mode 100644
index 0000000..1cdd496
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-1.ast
@@ -0,0 +1,187 @@
+/*
+ * 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.
+ */
+#mixed_content  // o.a.f.c.ASTImplicitParent
+    #text  // o.a.f.c.ASTStaticText
+        - content: "1 "  // String
+    @  // o.a.f.c.ASTDirUserDefined
+        - callee: foo  // o.a.f.c.ASTExpVariable
+        - argument name: "x"  // String
+        - argument value: 1  // o.a.f.c.ASTExpNumberLiteral
+        - argument name: "y"  // String
+        - argument value: 2  // o.a.f.c.ASTExpNumberLiteral
+        - target loop variable: "b1"  // String
+        - target loop variable: "b2"  // String
+        #text  // o.a.f.c.ASTStaticText
+            - content: "x"  // String
+    #text  // o.a.f.c.ASTStaticText
+        - content: "\n2 "  // String
+    @  // o.a.f.c.ASTDirUserDefined
+        - callee: .  // o.a.f.c.ASTExpDot
+            - left-hand operand: ns  // o.a.f.c.ASTExpVariable
+            - right-hand operand: "bar"  // String
+        - argument value: 1  // o.a.f.c.ASTExpNumberLiteral
+        - argument value: 2  // o.a.f.c.ASTExpNumberLiteral
+        - target loop variable: "b1"  // String
+        - target loop variable: "b2"  // String
+        #text  // o.a.f.c.ASTStaticText
+            - content: "y"  // String
+    #text  // o.a.f.c.ASTStaticText
+        - content: "\n3 "  // String
+    #assign  // o.a.f.c.ASTDirAssignment
+        - assignment target: "x"  // String
+        - assignment operator: "="  // String
+        - assignment source: 123  // o.a.f.c.ASTExpNumberLiteral
+        - variable scope: "1"  // Integer
+        - namespace: null  // Null
+    #assign  // o.a.f.c.ASTDirAssignment
+        - assignment target: "x"  // String
+        - assignment operator: "="  // String
+        - assignment source: 123  // o.a.f.c.ASTExpNumberLiteral
+        - variable scope: "1"  // Integer
+        - namespace: ns  // o.a.f.c.ASTExpVariable
+    #global  // o.a.f.c.ASTDirAssignment
+        - assignment target: "x"  // String
+        - assignment operator: "="  // String
+        - assignment source: 123  // o.a.f.c.ASTExpNumberLiteral
+        - variable scope: "3"  // Integer
+        - namespace: null  // Null
+    #text  // o.a.f.c.ASTStaticText
+        - content: "\n4 "  // String
+    #if-#elseif-#else-container  // o.a.f.c.ASTDirIfElseIfElseContainer
+        #if  // o.a.f.c.ASTDirIfOrElseOrElseIf
+            - condition: ==  // o.a.f.c.ASTExpComparison
+                - left-hand operand: +  // o.a.f.c.ASTExpAddOrConcat
+                    - left-hand operand: x  // o.a.f.c.ASTExpVariable
+                    - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
+                - right-hand operand: 0  // o.a.f.c.ASTExpNumberLiteral
+            - AST-node subtype: "0"  // Integer
+            #text  // o.a.f.c.ASTStaticText
+                - content: "foo"  // String
+            ${...}  // o.a.f.c.ASTDollarInterpolation
+                - content: y  // o.a.f.c.ASTExpVariable
+            #text  // o.a.f.c.ASTStaticText
+                - content: "bar"  // String
+        #else  // o.a.f.c.ASTDirIfOrElseOrElseIf
+            - condition: null  // Null
+            - AST-node subtype: "1"  // Integer
+            ${...}  // o.a.f.c.ASTDollarInterpolation
+                - content: "static"  // o.a.f.c.ASTExpStringLiteral
+            ${...}  // o.a.f.c.ASTDollarInterpolation
+                - content: dynamic "..."  // o.a.f.c.ASTExpStringLiteral
+                    - value part: "x"  // String
+                    - value part: ${...}  // o.a.f.c.ASTDollarInterpolation
+                        - content: *  // o.a.f.c.ArithmeticExpression
+                            - left-hand operand: baaz  // o.a.f.c.ASTExpVariable
+                            - right-hand operand: 10  // o.a.f.c.ASTExpNumberLiteral
+                            - AST-node subtype: "1"  // Integer
+                    - value part: "y"  // String
+    #text  // o.a.f.c.ASTStaticText
+        - content: "\n5 "  // String
+    #switch  // o.a.f.c.ASTDirSwitch
+        - value: x  // o.a.f.c.ASTExpVariable
+        #case  // o.a.f.c.ASTDirCase
+            - condition: 1  // o.a.f.c.ASTExpNumberLiteral
+            - AST-node subtype: "0"  // Integer
+            #text  // o.a.f.c.ASTStaticText
+                - content: "one"  // String
+        #case  // o.a.f.c.ASTDirCase
+            - condition: 2  // o.a.f.c.ASTExpNumberLiteral
+            - AST-node subtype: "0"  // Integer
+            #text  // o.a.f.c.ASTStaticText
+                - content: "two"  // String
+        #default  // o.a.f.c.ASTDirCase
+            - condition: null  // Null
+            - AST-node subtype: "1"  // Integer
+            #text  // o.a.f.c.ASTStaticText
+                - content: "more"  // String
+    #text  // o.a.f.c.ASTStaticText
+        - content: "\n6 "  // String
+    #macro  // o.a.f.c.ASTDirMacro
+        - assignment target: "foo"  // String
+        - parameter name: "x"  // String
+        - parameter default: null  // Null
+        - parameter name: "y"  // String
+        - parameter default: 2  // o.a.f.c.ASTExpNumberLiteral
+        - parameter name: "z"  // String
+        - parameter default: +  // o.a.f.c.ASTExpAddOrConcat
+            - left-hand operand: y  // o.a.f.c.ASTExpVariable
+            - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
+        - catch-all parameter name: "q"  // String
+        - AST-node subtype: "0"  // Integer
+        #nested  // o.a.f.c.ASTDirNested
+            - passed value: x  // o.a.f.c.ASTExpVariable
+            - passed value: y  // o.a.f.c.ASTExpVariable
+    #text  // o.a.f.c.ASTStaticText
+        - content: "\n7 "  // String
+    #function  // o.a.f.c.ASTDirMacro
+        - assignment target: "foo"  // String
+        - parameter name: "x"  // String
+        - parameter default: null  // Null
+        - parameter name: "y"  // String
+        - parameter default: null  // Null
+        - catch-all parameter name: null  // Null
+        - AST-node subtype: "1"  // Integer
+        #local  // o.a.f.c.ASTDirAssignment
+            - assignment target: "x"  // String
+            - assignment operator: "="  // String
+            - assignment source: 123  // o.a.f.c.ASTExpNumberLiteral
+            - variable scope: "2"  // Integer
+            - namespace: null  // Null
+        #return  // o.a.f.c.ASTDirReturn
+            - value: 1  // o.a.f.c.ASTExpNumberLiteral
+    #text  // o.a.f.c.ASTStaticText
+        - content: "\n8 "  // String
+    #list  // o.a.f.c.ASTDirList
+        - list source: xs  // o.a.f.c.ASTExpVariable
+        - target loop variable: "x"  // String
+    #text  // o.a.f.c.ASTStaticText
+        - content: "\n9 "  // String
+    #list-#else-container  // o.a.f.c.ASTDirListElseContainer
+        #list  // o.a.f.c.ASTDirList
+            - list source: xs  // o.a.f.c.ASTExpVariable
+            #text  // o.a.f.c.ASTStaticText
+                - content: "["  // String
+            #items  // o.a.f.c.ASTDirItems
+                - target loop variable: "x"  // String
+                ${...}  // o.a.f.c.ASTDollarInterpolation
+                    - content: x  // o.a.f.c.ASTExpVariable
+                #sep  // o.a.f.c.ASTDirSep
+                    #text  // o.a.f.c.ASTStaticText
+                        - content: ", "  // String
+            #text  // o.a.f.c.ASTStaticText
+                - content: "]"  // String
+        #else  // o.a.f.c.ASTDirElseOfList
+            #text  // o.a.f.c.ASTStaticText
+                - content: "None"  // String
+    #text  // o.a.f.c.ASTStaticText
+        - content: "\n10 "  // String
+    #--...--  // o.a.f.c.ASTComment
+        - content: " A comment "  // String
+    #text  // o.a.f.c.ASTStaticText
+        - content: "\n11 "  // String
+    #outputformat  // o.a.f.c.ASTDirOutputFormat
+        - value: "XML"  // o.a.f.c.ASTExpStringLiteral
+        #noautoesc  // o.a.f.c.ASTDirNoAutoEsc
+            ${...}  // o.a.f.c.ASTDollarInterpolation
+                - content: a  // o.a.f.c.ASTExpVariable
+            #autoesc  // o.a.f.c.ASTDirAutoEsc
+                ${...}  // o.a.f.c.ASTDollarInterpolation
+                    - content: b  // o.a.f.c.ASTExpVariable
+            ${...}  // o.a.f.c.ASTDollarInterpolation
+                - content: c  // o.a.f.c.ASTExpVariable

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-1.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-1.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-1.ftl
new file mode 100644
index 0000000..8c8953a
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-1.ftl
@@ -0,0 +1,29 @@
+<#--
+  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.
+-->
+1 <@foo x=1 y=2; b1, b2>x</...@foo>
+2 <@ns.bar 1 2; b1, b2>y</@>
+3 <#assign x = 123><#assign x = 123 in ns><#global x = 123>
+4 <#if x + 1 == 0>foo${y}bar<#else>${"static"}${'x${baaz * 10}y'}</#if>
+5 <#switch x><#case 1>one<#case 2>two<#default>more</#switch>
+6 <#macro foo x y=2 z=y+1 q...><#nested x y></#macro>
+7 <#function foo x y><#local x = 123><#return 1></#function>
+8 <#list xs as x></#list>
+9 <#list xs>[<#items as x>${x}<#sep>, </#items>]<#else>None</#list>
+10 <#-- A comment -->
+11 <#outputFormat "XML"><#noAutoEsc>${a}<#autoEsc>${b}</#autoEsc>${c}</#noAutoEsc></#outputFormat>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-assignments.ast
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-assignments.ast b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-assignments.ast
new file mode 100644
index 0000000..4839892
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-assignments.ast
@@ -0,0 +1,172 @@
+/*
+ * 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.
+ */
+#mixed_content  // o.a.f.c.ASTImplicitParent
+    #text  // o.a.f.c.ASTStaticText
+        - content: "1 "  // String
+    #assign  // o.a.f.c.ASTDirAssignment
+        - assignment target: "x"  // String
+        - assignment operator: "="  // String
+        - assignment source: 1  // o.a.f.c.ASTExpNumberLiteral
+        - variable scope: "1"  // Integer
+        - namespace: null  // Null
+    #text  // o.a.f.c.ASTStaticText
+        - content: "\n2 "  // String
+    #assign  // o.a.f.c.ASTDirAssignmentsContainer
+        - variable scope: "1"  // Integer
+        - namespace: null  // Null
+        #assign  // o.a.f.c.ASTDirAssignment
+            - assignment target: "x"  // String
+            - assignment operator: "="  // String
+            - assignment source: 1  // o.a.f.c.ASTExpNumberLiteral
+            - variable scope: "1"  // Integer
+            - namespace: null  // Null
+        #assign  // o.a.f.c.ASTDirAssignment
+            - assignment target: "y"  // String
+            - assignment operator: "="  // String
+            - assignment source: 2  // o.a.f.c.ASTExpNumberLiteral
+            - variable scope: "1"  // Integer
+            - namespace: null  // Null
+    #text  // o.a.f.c.ASTStaticText
+        - content: "\n3 "  // String
+    #assign  // o.a.f.c.ASTDirAssignment
+        - assignment target: "x"  // String
+        - assignment operator: "="  // String
+        - assignment source: 1  // o.a.f.c.ASTExpNumberLiteral
+        - variable scope: "1"  // Integer
+        - namespace: ns  // o.a.f.c.ASTExpVariable
+    #text  // o.a.f.c.ASTStaticText
+        - content: "\n4 "  // String
+    #assign  // o.a.f.c.ASTDirAssignmentsContainer
+        - variable scope: "1"  // Integer
+        - namespace: ns  // o.a.f.c.ASTExpVariable
+        #assign  // o.a.f.c.ASTDirAssignment
+            - assignment target: "x"  // String
+            - assignment operator: "="  // String
+            - assignment source: 1  // o.a.f.c.ASTExpNumberLiteral
+            - variable scope: "1"  // Integer
+            - namespace: ns  // o.a.f.c.ASTExpVariable
+        #assign  // o.a.f.c.ASTDirAssignment
+            - assignment target: "y"  // String
+            - assignment operator: "="  // String
+            - assignment source: 2  // o.a.f.c.ASTExpNumberLiteral
+            - variable scope: "1"  // Integer
+            - namespace: ns  // o.a.f.c.ASTExpVariable
+    #text  // o.a.f.c.ASTStaticText
+        - content: "\n5 "  // String
+    #global  // o.a.f.c.ASTDirAssignment
+        - assignment target: "x"  // String
+        - assignment operator: "="  // String
+        - assignment source: 1  // o.a.f.c.ASTExpNumberLiteral
+        - variable scope: "3"  // Integer
+        - namespace: null  // Null
+    #text  // o.a.f.c.ASTStaticText
+        - content: "\n6 "  // String
+    #global  // o.a.f.c.ASTDirAssignmentsContainer
+        - variable scope: "3"  // Integer
+        - namespace: null  // Null
+        #global  // o.a.f.c.ASTDirAssignment
+            - assignment target: "x"  // String
+            - assignment operator: "="  // String
+            - assignment source: 1  // o.a.f.c.ASTExpNumberLiteral
+            - variable scope: "3"  // Integer
+            - namespace: null  // Null
+        #global  // o.a.f.c.ASTDirAssignment
+            - assignment target: "y"  // String
+            - assignment operator: "="  // String
+            - assignment source: 2  // o.a.f.c.ASTExpNumberLiteral
+            - variable scope: "3"  // Integer
+            - namespace: null  // Null
+    #macro  // o.a.f.c.ASTDirMacro
+        - assignment target: "m"  // String
+        - catch-all parameter name: null  // Null
+        - AST-node subtype: "0"  // Integer
+        #text  // o.a.f.c.ASTStaticText
+            - content: "  7 "  // String
+        #local  // o.a.f.c.ASTDirAssignment
+            - assignment target: "x"  // String
+            - assignment operator: "="  // String
+            - assignment source: 1  // o.a.f.c.ASTExpNumberLiteral
+            - variable scope: "2"  // Integer
+            - namespace: null  // Null
+        #text  // o.a.f.c.ASTStaticText
+            - content: "\n  8 "  // String
+        #local  // o.a.f.c.ASTDirAssignmentsContainer
+            - variable scope: "2"  // Integer
+            - namespace: null  // Null
+            #local  // o.a.f.c.ASTDirAssignment
+                - assignment target: "x"  // String
+                - assignment operator: "="  // String
+                - assignment source: 1  // o.a.f.c.ASTExpNumberLiteral
+                - variable scope: "2"  // Integer
+                - namespace: null  // Null
+            #local  // o.a.f.c.ASTDirAssignment
+                - assignment target: "y"  // String
+                - assignment operator: "="  // String
+                - assignment source: 2  // o.a.f.c.ASTExpNumberLiteral
+                - variable scope: "2"  // Integer
+                - namespace: null  // Null
+        #text  // o.a.f.c.ASTStaticText
+            - content: "\n"  // String
+    #text  // o.a.f.c.ASTStaticText
+        - content: "9 "  // String
+    #assign  // o.a.f.c.ASTDirAssignmentsContainer
+        - variable scope: "1"  // Integer
+        - namespace: null  // Null
+        #assign  // o.a.f.c.ASTDirAssignment
+            - assignment target: "a"  // String
+            - assignment operator: "+="  // String
+            - assignment source: 1  // o.a.f.c.ASTExpNumberLiteral
+            - variable scope: "1"  // Integer
+            - namespace: null  // Null
+        #assign  // o.a.f.c.ASTDirAssignment
+            - assignment target: "b"  // String
+            - assignment operator: "-="  // String
+            - assignment source: 2  // o.a.f.c.ASTExpNumberLiteral
+            - variable scope: "1"  // Integer
+            - namespace: null  // Null
+        #assign  // o.a.f.c.ASTDirAssignment
+            - assignment target: "c"  // String
+            - assignment operator: "*="  // String
+            - assignment source: 3  // o.a.f.c.ASTExpNumberLiteral
+            - variable scope: "1"  // Integer
+            - namespace: null  // Null
+        #assign  // o.a.f.c.ASTDirAssignment
+            - assignment target: "d"  // String
+            - assignment operator: "/="  // String
+            - assignment source: 4  // o.a.f.c.ASTExpNumberLiteral
+            - variable scope: "1"  // Integer
+            - namespace: null  // Null
+        #assign  // o.a.f.c.ASTDirAssignment
+            - assignment target: "e"  // String
+            - assignment operator: "%="  // String
+            - assignment source: 5  // o.a.f.c.ASTExpNumberLiteral
+            - variable scope: "1"  // Integer
+            - namespace: null  // Null
+        #assign  // o.a.f.c.ASTDirAssignment
+            - assignment target: "f"  // String
+            - assignment operator: "++"  // String
+            - assignment source: null  // Null
+            - variable scope: "1"  // Integer
+            - namespace: null  // Null
+        #assign  // o.a.f.c.ASTDirAssignment
+            - assignment target: "g"  // String
+            - assignment operator: "--"  // String
+            - assignment source: null  // Null
+            - variable scope: "1"  // Integer
+            - namespace: null  // Null

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-assignments.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-assignments.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-assignments.ftl
new file mode 100644
index 0000000..c070635
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-assignments.ftl
@@ -0,0 +1,29 @@
+<#--
+  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.
+-->
+1 <#assign x = 1>
+2 <#assign x = 1, y = 2>
+3 <#assign x = 1 in ns>
+4 <#assign x = 1, y = 2 in ns>
+5 <#global x = 1>
+6 <#global x = 1, y = 2>
+<#macro m>
+  7 <#local x = 1>
+  8 <#local x = 1, y = 2>
+</#macro>
+9 <#assign a += 1, b -= 2, c *= 3, d /= 4, e %= 5, f++, g-->

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-builtins.ast
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-builtins.ast b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-builtins.ast
new file mode 100644
index 0000000..b8b696f
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-builtins.ast
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+#mixed_content  // o.a.f.c.ASTImplicitParent
+    ${...}  // o.a.f.c.ASTDollarInterpolation
+        - content: ?trim  // o.a.f.c.BuiltInsForStringsBasic$trimBI
+            - left-hand operand: x  // o.a.f.c.ASTExpVariable
+            - right-hand operand: "trim"  // String
+    #text  // o.a.f.c.ASTStaticText
+        - content: "\n"  // String
+    ${...}  // o.a.f.c.ASTDollarInterpolation
+        - content: ...(...)  // o.a.f.c.ASTExpMethodCall
+            - callee: ?left_pad  // o.a.f.c.BuiltInsForStringsBasic$padBI
+                - left-hand operand: x  // o.a.f.c.ASTExpVariable
+                - right-hand operand: "left_pad"  // String
+            - argument value: 5  // o.a.f.c.ASTExpNumberLiteral
+    #text  // o.a.f.c.ASTStaticText
+        - content: "\n"  // String
+    ${...}  // o.a.f.c.ASTDollarInterpolation
+        - content: ...(...)  // o.a.f.c.ASTExpMethodCall
+            - callee: ?left_pad  // o.a.f.c.BuiltInsForStringsBasic$padBI
+                - left-hand operand: x  // o.a.f.c.ASTExpVariable
+                - right-hand operand: "left_pad"  // String
+            - argument value: 5  // o.a.f.c.ASTExpNumberLiteral
+            - argument value: "-"  // o.a.f.c.ASTExpStringLiteral
+    #text  // o.a.f.c.ASTStaticText
+        - content: "\n"  // String
+    ${...}  // o.a.f.c.ASTDollarInterpolation
+        - content: ?then(...)  // o.a.f.c.BuiltInsWithParseTimeParameters$then_BI
+            - left-hand operand: x  // o.a.f.c.ASTExpVariable
+            - right-hand operand: "then"  // String
+            - argument value: "y"  // o.a.f.c.ASTExpStringLiteral
+            - argument value: "n"  // o.a.f.c.ASTExpStringLiteral
+    #text  // o.a.f.c.ASTStaticText
+        - content: "\n"  // String
+    ${...}  // o.a.f.c.ASTDollarInterpolation
+        - content: ?switch(...)  // o.a.f.c.BuiltInsWithParseTimeParameters$switch_BI
+            - left-hand operand: x  // o.a.f.c.ASTExpVariable
+            - right-hand operand: "switch"  // String
+            - argument value: 1  // o.a.f.c.ASTExpNumberLiteral
+            - argument value: 11  // o.a.f.c.ASTExpNumberLiteral
+            - argument value: 2  // o.a.f.c.ASTExpNumberLiteral
+            - argument value: 22  // o.a.f.c.ASTExpNumberLiteral
+            - argument value: 33  // o.a.f.c.ASTExpNumberLiteral

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-builtins.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-builtins.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-builtins.ftl
new file mode 100644
index 0000000..74aee52
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-builtins.ftl
@@ -0,0 +1,23 @@
+<#--
+  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.
+-->
+${x?trim}
+${x?left_pad(5)}
+${x?left_pad(5, '-')}
+${x?then('y', 'n')}
+${x?switch(1, 11, 2, 22, 33)}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-locations.ast
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-locations.ast b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-locations.ast
new file mode 100644
index 0000000..7770d72
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-locations.ast
@@ -0,0 +1,155 @@
+/*
+ * 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.
+ */
+#mixed_content  // o.a.f.c.ASTImplicitParent; Location 1:1-18:8
+    #if  // o.a.f.c.ASTDirIfOrElseOrElseIf; Location 1:1-1:15
+        - condition: exp  // o.a.f.c.ASTExpVariable; Location 1:6-1:8
+        - AST-node subtype: "0"  // Integer
+    #if  // o.a.f.c.ASTDirIfOrElseOrElseIf; Location 2:1-2:16
+        - condition: exp  // o.a.f.c.ASTExpVariable; Location 2:6-2:8
+        - AST-node subtype: "0"  // Integer
+        #text  // o.a.f.c.ASTStaticText; Location 2:10-2:10
+            - content: "1"  // String
+    #text  // o.a.f.c.ASTStaticText; Location 2:17-2:17
+        - content: "\n"  // String
+    #if  // o.a.f.c.ASTDirIfOrElseOrElseIf; Location 3:1-3:20
+        - condition: exp  // o.a.f.c.ASTExpVariable; Location 3:6-3:8
+        - AST-node subtype: "0"  // Integer
+        ${...}  // o.a.f.c.ASTDollarInterpolation; Location 3:10-3:13
+            - content: 1  // o.a.f.c.ASTExpNumberLiteral; Location 3:12-3:12
+        #text  // o.a.f.c.ASTStaticText; Location 3:14-3:14
+            - content: "2"  // String
+    #text  // o.a.f.c.ASTStaticText; Location 3:21-3:21
+        - content: "\n"  // String
+    #if-#elseif-#else-container  // o.a.f.c.ASTDirIfElseIfElseContainer; Location 4:1-4:22
+        #if  // o.a.f.c.ASTDirIfOrElseOrElseIf; Location 4:1-4:9
+            - condition: exp  // o.a.f.c.ASTExpVariable; Location 4:6-4:8
+            - AST-node subtype: "0"  // Integer
+        #else  // o.a.f.c.ASTDirIfOrElseOrElseIf; Location 4:10-4:16
+            - condition: null  // Null
+            - AST-node subtype: "1"  // Integer
+    #if-#elseif-#else-container  // o.a.f.c.ASTDirIfElseIfElseContainer; Location 5:1-5:24
+        #if  // o.a.f.c.ASTDirIfOrElseOrElseIf; Location 5:1-5:10
+            - condition: exp  // o.a.f.c.ASTExpVariable; Location 5:6-5:8
+            - AST-node subtype: "0"  // Integer
+            #text  // o.a.f.c.ASTStaticText; Location 5:10-5:10
+                - content: "1"  // String
+        #else  // o.a.f.c.ASTDirIfOrElseOrElseIf; Location 5:11-5:18
+            - condition: null  // Null
+            - AST-node subtype: "1"  // Integer
+            #text  // o.a.f.c.ASTStaticText; Location 5:18-5:18
+                - content: "1"  // String
+    #text  // o.a.f.c.ASTStaticText; Location 5:25-5:25
+        - content: "\n"  // String
+    #if-#elseif-#else-container  // o.a.f.c.ASTDirIfElseIfElseContainer; Location 6:1-6:32
+        #if  // o.a.f.c.ASTDirIfOrElseOrElseIf; Location 6:1-6:14
+            - condition: exp  // o.a.f.c.ASTExpVariable; Location 6:6-6:8
+            - AST-node subtype: "0"  // Integer
+            ${...}  // o.a.f.c.ASTDollarInterpolation; Location 6:10-6:13
+                - content: 1  // o.a.f.c.ASTExpNumberLiteral; Location 6:12-6:12
+            #text  // o.a.f.c.ASTStaticText; Location 6:14-6:14
+                - content: "2"  // String
+        #else  // o.a.f.c.ASTDirIfOrElseOrElseIf; Location 6:15-6:26
+            - condition: null  // Null
+            - AST-node subtype: "1"  // Integer
+            ${...}  // o.a.f.c.ASTDollarInterpolation; Location 6:22-6:25
+                - content: 1  // o.a.f.c.ASTExpNumberLiteral; Location 6:24-6:24
+            #text  // o.a.f.c.ASTStaticText; Location 6:26-6:26
+                - content: "2"  // String
+    #text  // o.a.f.c.ASTStaticText; Location 6:33-6:33
+        - content: "\n"  // String
+    #if-#elseif-#else-container  // o.a.f.c.ASTDirIfElseIfElseContainer; Location 7:1-7:28
+        #if  // o.a.f.c.ASTDirIfOrElseOrElseIf; Location 7:1-7:9
+            - condition: exp  // o.a.f.c.ASTExpVariable; Location 7:6-7:8
+            - AST-node subtype: "0"  // Integer
+        #elseif  // o.a.f.c.ASTDirIfOrElseOrElseIf; Location 7:10-7:22
+            - condition: exp  // o.a.f.c.ASTExpVariable; Location 7:19-7:21
+            - AST-node subtype: "2"  // Integer
+    #if-#elseif-#else-container  // o.a.f.c.ASTDirIfElseIfElseContainer; Location 8:1-8:29
+        #if  // o.a.f.c.ASTDirIfOrElseOrElseIf; Location 8:1-8:9
+            - condition: exp  // o.a.f.c.ASTExpVariable; Location 8:6-8:8
+            - AST-node subtype: "0"  // Integer
+        #elseif  // o.a.f.c.ASTDirIfOrElseOrElseIf; Location 8:10-8:23
+            - condition: exp  // o.a.f.c.ASTExpVariable; Location 8:19-8:21
+            - AST-node subtype: "2"  // Integer
+            #text  // o.a.f.c.ASTStaticText; Location 8:23-8:23
+                - content: "1"  // String
+    #text  // o.a.f.c.ASTStaticText; Location 8:30-8:30
+        - content: "\n"  // String
+    #attempt  // o.a.f.c.ASTDirAttemptRecoverContainer; Location 9:1-9:31
+        - error handler: #recover  // o.a.f.c.ASTDirRecover; Location 9:11-9:20
+        #recover  // o.a.f.c.ASTDirRecover; Location 9:11-9:20
+    #attempt  // o.a.f.c.ASTDirAttemptRecoverContainer; Location 10:1-10:33
+        - error handler: #recover  // o.a.f.c.ASTDirRecover; Location 10:12-10:22
+            #text  // o.a.f.c.ASTStaticText; Location 10:22-10:22
+                - content: "1"  // String
+        #text  // o.a.f.c.ASTStaticText; Location 10:11-10:11
+            - content: "1"  // String
+        #recover  // o.a.f.c.ASTDirRecover; Location 10:12-10:22
+            #text  // o.a.f.c.ASTStaticText; Location 10:22-10:22
+                - content: "1"  // String
+    #text  // o.a.f.c.ASTStaticText; Location 10:34-10:34
+        - content: "\n"  // String
+    #list  // o.a.f.c.ASTDirList; Location 11:1-11:22
+        - list source: s  // o.a.f.c.ASTExpVariable; Location 11:8-11:8
+        - target loop variable: "i"  // String
+    #list  // o.a.f.c.ASTDirList; Location 12:1-12:23
+        - list source: s  // o.a.f.c.ASTExpVariable; Location 12:8-12:8
+        - target loop variable: "i"  // String
+        #text  // o.a.f.c.ASTStaticText; Location 12:15-12:15
+            - content: "1"  // String
+    #text  // o.a.f.c.ASTStaticText; Location 12:24-12:24
+        - content: "\n"  // String
+    #list  // o.a.f.c.ASTDirList; Location 13:1-13:28
+        - list source: s  // o.a.f.c.ASTExpVariable; Location 13:8-13:8
+        - target loop variable: "i"  // String
+        #sep  // o.a.f.c.ASTDirSep; Location 13:15-13:20
+    #list  // o.a.f.c.ASTDirList; Location 14:1-14:30
+        - list source: s  // o.a.f.c.ASTExpVariable; Location 14:8-14:8
+        - target loop variable: "i"  // String
+        #text  // o.a.f.c.ASTStaticText; Location 14:15-14:15
+            - content: "1"  // String
+        #sep  // o.a.f.c.ASTDirSep; Location 14:16-14:22
+            #text  // o.a.f.c.ASTStaticText; Location 14:22-14:22
+                - content: "1"  // String
+    #text  // o.a.f.c.ASTStaticText; Location 14:31-14:31
+        - content: "\n"  // String
+    #list  // o.a.f.c.ASTDirList; Location 15:1-15:45
+        - list source: s  // o.a.f.c.ASTExpVariable; Location 15:8-15:8
+        #items  // o.a.f.c.ASTDirItems; Location 15:10-15:37
+            - target loop variable: "i"  // String
+            #sep  // o.a.f.c.ASTDirSep; Location 15:23-15:28
+    #list  // o.a.f.c.ASTDirList; Location 16:1-16:49
+        - list source: s  // o.a.f.c.ASTExpVariable; Location 16:8-16:8
+        #text  // o.a.f.c.ASTStaticText; Location 16:10-16:10
+            - content: "1"  // String
+        #items  // o.a.f.c.ASTDirItems; Location 16:11-16:40
+            - target loop variable: "i"  // String
+            #text  // o.a.f.c.ASTStaticText; Location 16:24-16:24
+                - content: "1"  // String
+            #sep  // o.a.f.c.ASTDirSep; Location 16:25-16:31
+                #text  // o.a.f.c.ASTStaticText; Location 16:31-16:31
+                    - content: "1"  // String
+        #text  // o.a.f.c.ASTStaticText; Location 16:41-16:41
+            - content: "1"  // String
+    #text  // o.a.f.c.ASTStaticText; Location 16:50-17:2
+        - content: "\n1\n"  // String
+    ${...}  // o.a.f.c.ASTDollarInterpolation; Location 18:1-18:8
+        - content: +  // o.a.f.c.ASTExpAddOrConcat; Location 18:3-18:7
+            - left-hand operand: x  // o.a.f.c.ASTExpVariable; Location 18:3-18:3
+            - right-hand operand: y  // o.a.f.c.ASTExpVariable; Location 18:7-18:7

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-locations.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-locations.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-locations.ftl
new file mode 100644
index 0000000..99fa244
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-locations.ftl
@@ -0,0 +1,36 @@
+<#--
+  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.
+-->
+<#if exp></#if>
+<#if exp>1</#if>
+<#if exp>${1}2</#if>
+<#if exp><#else></#if>
+<#if exp>1<#else>1</#if>
+<#if exp>${1}2<#else>${1}2</#if>
+<#if exp><#elseif exp></#if>
+<#if exp><#elseif exp>1</#if>
+<#attempt><#recover></#attempt>
+<#attempt>1<#recover>1</#attempt>
+<#list s as i></#list>
+<#list s as i>1</#list>
+<#list s as i><#sep></#list>
+<#list s as i>1<#sep>1</#list>
+<#list s><#items as i><#sep></#items></#list>
+<#list s>1<#items as i>1<#sep>1</#items>1</#list>
+1
+${x + y}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-mixedcontentsimplifications.ast
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-mixedcontentsimplifications.ast b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-mixedcontentsimplifications.ast
new file mode 100644
index 0000000..41fc90b
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-mixedcontentsimplifications.ast
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+#if  // o.a.f.c.ASTDirIfOrElseOrElseIf
+    - condition: true  // o.a.f.c.ASTExpBooleanLiteral
+    - AST-node subtype: "0"  // Integer
+    #if  // o.a.f.c.ASTDirIfOrElseOrElseIf
+        - condition: true  // o.a.f.c.ASTExpBooleanLiteral
+        - AST-node subtype: "0"  // Integer
+    #if  // o.a.f.c.ASTDirIfOrElseOrElseIf
+        - condition: true  // o.a.f.c.ASTExpBooleanLiteral
+        - AST-node subtype: "0"  // Integer
+        #text  // o.a.f.c.ASTStaticText
+            - content: "        text\n"  // String
+    #text  // o.a.f.c.ASTStaticText
+        - content: "    "  // String
+    #if  // o.a.f.c.ASTDirIfOrElseOrElseIf
+        - condition: true  // o.a.f.c.ASTExpBooleanLiteral
+        - AST-node subtype: "0"  // Integer
+        ${...}  // o.a.f.c.ASTDollarInterpolation
+            - content: x  // o.a.f.c.ASTExpVariable
+    #text  // o.a.f.c.ASTStaticText
+        - content: "\n"  // String

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-mixedcontentsimplifications.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-mixedcontentsimplifications.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-mixedcontentsimplifications.ftl
new file mode 100644
index 0000000..53716e4
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-mixedcontentsimplifications.ftl
@@ -0,0 +1,26 @@
+<#--
+  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.
+-->
+<#if true>
+    <#if true>
+    </#if>
+    <#if true>
+        text
+    </#if>
+    <#if true>${x}</#if>
+</#if>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-multipleignoredchildren.ast
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-multipleignoredchildren.ast b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-multipleignoredchildren.ast
new file mode 100644
index 0000000..7675522
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-multipleignoredchildren.ast
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+#mixed_content  // o.a.f.c.ASTImplicitParent
+    #text  // o.a.f.c.ASTStaticText
+        - content: "a\n"  // String
+    #text  // o.a.f.c.ASTStaticText
+        - content: "b\n"  // String
+    #text  // o.a.f.c.ASTStaticText
+        - content: "c\n"  // String
+    #text  // o.a.f.c.ASTStaticText
+        - content: "d\n"  // String
+    #if  // o.a.f.c.ASTDirIfOrElseOrElseIf
+        - condition: true  // o.a.f.c.ASTExpBooleanLiteral
+        - AST-node subtype: "0"  // Integer

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-multipleignoredchildren.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-multipleignoredchildren.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-multipleignoredchildren.ftl
new file mode 100644
index 0000000..501802a
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-multipleignoredchildren.ftl
@@ -0,0 +1,33 @@
+<#--
+  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.
+-->
+a
+<#compress></#compress>
+b
+<#compress></#compress>
+<#compress></#compress>
+c
+<#compress></#compress>
+<#compress></#compress>
+<#compress></#compress>
+d
+<#if true>
+  <#compress></#compress>
+  <#compress></#compress>
+  <#compress></#compress>
+</#if>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-nestedignoredchildren.ast
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-nestedignoredchildren.ast b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-nestedignoredchildren.ast
new file mode 100644
index 0000000..eefa5b1
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-nestedignoredchildren.ast
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+#outputformat  // o.a.f.c.ASTDirOutputFormat
+    - value: "HTML"  // o.a.f.c.ASTExpStringLiteral

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-nestedignoredchildren.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-nestedignoredchildren.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-nestedignoredchildren.ftl
new file mode 100644
index 0000000..fbdb342
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-nestedignoredchildren.ftl
@@ -0,0 +1,19 @@
+<#--
+  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.
+-->
+<#outputFormat 'HTML'><#outputFormat 'HTML'><#outputFormat 'HTML'></#outputFormat></#outputFormat></#outputFormat>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-range.ast
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-range.ast b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-range.ast
new file mode 100644
index 0000000..831c7dc
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-range.ast
@@ -0,0 +1,281 @@
+/*
+ * 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.
+ */
+#mixed_content  // o.a.f.c.ASTImplicitParent
+    #assign  // o.a.f.c.ASTDirAssignment
+        - assignment target: "x"  // String
+        - assignment operator: "="  // String
+        - assignment source: ..  // o.a.f.c.ASTExpRange
+            - left-hand operand: 0  // o.a.f.c.ASTExpNumberLiteral
+            - right-hand operand: null  // Null
+        - variable scope: "1"  // Integer
+        - namespace: null  // Null
+    #assign  // o.a.f.c.ASTDirAssignment
+        - assignment target: "x"  // String
+        - assignment operator: "="  // String
+        - assignment source: ..  // o.a.f.c.ASTExpRange
+            - left-hand operand: 0  // o.a.f.c.ASTExpNumberLiteral
+            - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
+        - variable scope: "1"  // Integer
+        - namespace: null  // Null
+    #assign  // o.a.f.c.ASTDirAssignment
+        - assignment target: "x"  // String
+        - assignment operator: "="  // String
+        - assignment source: ..<  // o.a.f.c.ASTExpRange
+            - left-hand operand: 0  // o.a.f.c.ASTExpNumberLiteral
+            - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
+        - variable scope: "1"  // Integer
+        - namespace: null  // Null
+    #assign  // o.a.f.c.ASTDirAssignment
+        - assignment target: "x"  // String
+        - assignment operator: "="  // String
+        - assignment source: ..<  // o.a.f.c.ASTExpRange
+            - left-hand operand: 0  // o.a.f.c.ASTExpNumberLiteral
+            - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
+        - variable scope: "1"  // Integer
+        - namespace: null  // Null
+    #assign  // o.a.f.c.ASTDirAssignment
+        - assignment target: "x"  // String
+        - assignment operator: "="  // String
+        - assignment source: ..  // o.a.f.c.ASTExpRange
+            - left-hand operand: +  // o.a.f.c.ASTExpAddOrConcat
+                - left-hand operand: n  // o.a.f.c.ASTExpVariable
+                - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
+            - right-hand operand: +  // o.a.f.c.ASTExpAddOrConcat
+                - left-hand operand: m  // o.a.f.c.ASTExpVariable
+                - right-hand operand: 2  // o.a.f.c.ASTExpNumberLiteral
+        - variable scope: "1"  // Integer
+        - namespace: null  // Null
+    #assign  // o.a.f.c.ASTDirAssignment
+        - assignment target: "x"  // String
+        - assignment operator: "="  // String
+        - assignment source: ..<  // o.a.f.c.ASTExpRange
+            - left-hand operand: +  // o.a.f.c.ASTExpAddOrConcat
+                - left-hand operand: n  // o.a.f.c.ASTExpVariable
+                - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
+            - right-hand operand: +  // o.a.f.c.ASTExpAddOrConcat
+                - left-hand operand: m  // o.a.f.c.ASTExpVariable
+                - right-hand operand: 2  // o.a.f.c.ASTExpNumberLiteral
+        - variable scope: "1"  // Integer
+        - namespace: null  // Null
+    #assign  // o.a.f.c.ASTDirAssignment
+        - assignment target: "x"  // String
+        - assignment operator: "="  // String
+        - assignment source: ..<  // o.a.f.c.ASTExpRange
+            - left-hand operand: +  // o.a.f.c.ASTExpAddOrConcat
+                - left-hand operand: n  // o.a.f.c.ASTExpVariable
+                - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
+            - right-hand operand: +  // o.a.f.c.ASTExpAddOrConcat
+                - left-hand operand: m  // o.a.f.c.ASTExpVariable
+                - right-hand operand: 2  // o.a.f.c.ASTExpNumberLiteral
+        - variable scope: "1"  // Integer
+        - namespace: null  // Null
+    #assign  // o.a.f.c.ASTDirAssignment
+        - assignment target: "x"  // String
+        - assignment operator: "="  // String
+        - assignment source: ..  // o.a.f.c.ASTExpRange
+            - left-hand operand: *  // o.a.f.c.ArithmeticExpression
+                - left-hand operand: n  // o.a.f.c.ASTExpVariable
+                - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
+                - AST-node subtype: "1"  // Integer
+            - right-hand operand: *  // o.a.f.c.ArithmeticExpression
+                - left-hand operand: m  // o.a.f.c.ASTExpVariable
+                - right-hand operand: 2  // o.a.f.c.ASTExpNumberLiteral
+                - AST-node subtype: "1"  // Integer
+        - variable scope: "1"  // Integer
+        - namespace: null  // Null
+    #assign  // o.a.f.c.ASTDirAssignment
+        - assignment target: "x"  // String
+        - assignment operator: "="  // String
+        - assignment source: ..  // o.a.f.c.ASTExpRange
+            - left-hand operand: ?abs  // o.a.f.c.BuiltInsForNumbers$absBI
+                - left-hand operand: n  // o.a.f.c.ASTExpVariable
+                - right-hand operand: "abs"  // String
+            - right-hand operand: ?abs  // o.a.f.c.BuiltInsForNumbers$absBI
+                - left-hand operand: m  // o.a.f.c.ASTExpVariable
+                - right-hand operand: "abs"  // String
+        - variable scope: "1"  // Integer
+        - namespace: null  // Null
+    #assign  // o.a.f.c.ASTDirAssignment
+        - assignment target: "x"  // String
+        - assignment operator: "="  // String
+        - assignment source: ..  // o.a.f.c.ASTExpRange
+            - left-hand operand: ...(...)  // o.a.f.c.ASTExpMethodCall
+                - callee: ?index_of  // o.a.f.c.BuiltInsForStringsBasic$index_ofBI
+                    - left-hand operand: n  // o.a.f.c.ASTExpVariable
+                    - right-hand operand: "index_of"  // String
+                - argument value: "x"  // o.a.f.c.ASTExpStringLiteral
+            - right-hand operand: ...(...)  // o.a.f.c.ASTExpMethodCall
+                - callee: ?index_of  // o.a.f.c.BuiltInsForStringsBasic$index_ofBI
+                    - left-hand operand: m  // o.a.f.c.ASTExpVariable
+                    - right-hand operand: "index_of"  // String
+                - argument value: "y"  // o.a.f.c.ASTExpStringLiteral
+        - variable scope: "1"  // Integer
+        - namespace: null  // Null
+    #assign  // o.a.f.c.ASTDirAssignment
+        - assignment target: "x"  // String
+        - assignment operator: "="  // String
+        - assignment source: ==  // o.a.f.c.ASTExpComparison
+            - left-hand operand: ..  // o.a.f.c.ASTExpRange
+                - left-hand operand: n  // o.a.f.c.ASTExpVariable
+                - right-hand operand: m  // o.a.f.c.ASTExpVariable
+            - right-hand operand: ..  // o.a.f.c.ASTExpRange
+                - left-hand operand: o  // o.a.f.c.ASTExpVariable
+                - right-hand operand: p  // o.a.f.c.ASTExpVariable
+        - variable scope: "1"  // Integer
+        - namespace: null  // Null
+    #assign  // o.a.f.c.ASTDirAssignment
+        - assignment target: "x"  // String
+        - assignment operator: "="  // String
+        - assignment source: ==  // o.a.f.c.ASTExpComparison
+            - left-hand operand: ..  // o.a.f.c.ASTExpRange
+                - left-hand operand: +  // o.a.f.c.ASTExpAddOrConcat
+                    - left-hand operand: +  // o.a.f.c.ASTExpAddOrConcat
+                        - left-hand operand: n  // o.a.f.c.ASTExpVariable
+                        - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
+                    - right-hand operand: 2  // o.a.f.c.ASTExpNumberLiteral
+                - right-hand operand: -  // o.a.f.c.ArithmeticExpression
+                    - left-hand operand: -  // o.a.f.c.ArithmeticExpression
+                        - left-hand operand: m  // o.a.f.c.ASTExpVariable
+                        - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
+                        - AST-node subtype: "0"  // Integer
+                    - right-hand operand: 2  // o.a.f.c.ASTExpNumberLiteral
+                    - AST-node subtype: "0"  // Integer
+            - right-hand operand: ..  // o.a.f.c.ASTExpRange
+                - left-hand operand: +  // o.a.f.c.ASTExpAddOrConcat
+                    - left-hand operand: +  // o.a.f.c.ASTExpAddOrConcat
+                        - left-hand operand: o  // o.a.f.c.ASTExpVariable
+                        - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
+                    - right-hand operand: 2  // o.a.f.c.ASTExpNumberLiteral
+                - right-hand operand: -  // o.a.f.c.ArithmeticExpression
+                    - left-hand operand: -  // o.a.f.c.ArithmeticExpression
+                        - left-hand operand: p  // o.a.f.c.ASTExpVariable
+                        - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
+                        - AST-node subtype: "0"  // Integer
+                    - right-hand operand: 2  // o.a.f.c.ASTExpNumberLiteral
+                    - AST-node subtype: "0"  // Integer
+        - variable scope: "1"  // Integer
+        - namespace: null  // Null
+    #assign  // o.a.f.c.ASTDirAssignment
+        - assignment target: "x"  // String
+        - assignment operator: "="  // String
+        - assignment source: ..  // o.a.f.c.ASTExpRange
+            - left-hand operand: +  // o.a.f.c.ASTExpAddOrConcat
+                - left-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
+                - right-hand operand: a  // o.a.f.c.ASTExpVariable
+            - right-hand operand: +...  // o.a.f.c.ASTExpNegateOrPlus
+                - right-hand operand: 2  // o.a.f.c.ASTExpNumberLiteral
+                - AST-node subtype: "1"  // Integer
+        - variable scope: "1"  // Integer
+        - namespace: null  // Null
+    #assign  // o.a.f.c.ASTDirAssignment
+        - assignment target: "x"  // String
+        - assignment operator: "="  // String
+        - assignment source: ..  // o.a.f.c.ASTExpRange
+            - left-hand operand: -  // o.a.f.c.ArithmeticExpression
+                - left-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
+                - right-hand operand: a  // o.a.f.c.ASTExpVariable
+                - AST-node subtype: "0"  // Integer
+            - right-hand operand: -...  // o.a.f.c.ASTExpNegateOrPlus
+                - right-hand operand: 2  // o.a.f.c.ASTExpNumberLiteral
+                - AST-node subtype: "0"  // Integer
+        - variable scope: "1"  // Integer
+        - namespace: null  // Null
+    #assign  // o.a.f.c.ASTDirAssignment
+        - assignment target: "x"  // String
+        - assignment operator: "="  // String
+        - assignment source: ..*  // o.a.f.c.ASTExpRange
+            - left-hand operand: *  // o.a.f.c.ArithmeticExpression
+                - left-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
+                - right-hand operand: a  // o.a.f.c.ASTExpVariable
+                - AST-node subtype: "1"  // Integer
+            - right-hand operand: 2  // o.a.f.c.ASTExpNumberLiteral
+        - variable scope: "1"  // Integer
+        - namespace: null  // Null
+    #assign  // o.a.f.c.ASTDirAssignment
+        - assignment target: "x"  // String
+        - assignment operator: "="  // String
+        - assignment source: ||  // o.a.f.c.ASTExpOr
+            - left-hand operand: &&  // o.a.f.c.ASTExpAnd
+                - left-hand operand: a  // o.a.f.c.ASTExpVariable
+                - right-hand operand: ..  // o.a.f.c.ASTExpRange
+                    - left-hand operand: b  // o.a.f.c.ASTExpVariable
+                    - right-hand operand: c  // o.a.f.c.ASTExpVariable
+            - right-hand operand: d  // o.a.f.c.ASTExpVariable
+        - variable scope: "1"  // Integer
+        - namespace: null  // Null
+    #assign  // o.a.f.c.ASTDirAssignment
+        - assignment target: "x"  // String
+        - assignment operator: "="  // String
+        - assignment source: ||  // o.a.f.c.ASTExpOr
+            - left-hand operand: &&  // o.a.f.c.ASTExpAnd
+                - left-hand operand: ..  // o.a.f.c.ASTExpRange
+                    - left-hand operand: a  // o.a.f.c.ASTExpVariable
+                    - right-hand operand: null  // Null
+                - right-hand operand: ..  // o.a.f.c.ASTExpRange
+                    - left-hand operand: b  // o.a.f.c.ASTExpVariable
+                    - right-hand operand: null  // Null
+            - right-hand operand: d  // o.a.f.c.ASTExpVariable
+        - variable scope: "1"  // Integer
+        - namespace: null  // Null
+    #text  // o.a.f.c.ASTStaticText
+        - content: "\n"  // String
+    ${...}  // o.a.f.c.ASTDollarInterpolation
+        - content: ...(...)  // o.a.f.c.ASTExpMethodCall
+            - callee: f  // o.a.f.c.ASTExpVariable
+            - argument value: ..  // o.a.f.c.ASTExpRange
+                - left-hand operand: m  // o.a.f.c.ASTExpVariable
+                - right-hand operand: null  // Null
+            - argument value: ..  // o.a.f.c.ASTExpRange
+                - left-hand operand: -  // o.a.f.c.ArithmeticExpression
+                    - left-hand operand: m  // o.a.f.c.ASTExpVariable
+                    - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
+                    - AST-node subtype: "0"  // Integer
+                - right-hand operand: null  // Null
+            - argument value: ..  // o.a.f.c.ASTExpRange
+                - left-hand operand: +  // o.a.f.c.ASTExpAddOrConcat
+                    - left-hand operand: m  // o.a.f.c.ASTExpVariable
+                    - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
+                - right-hand operand: -  // o.a.f.c.ArithmeticExpression
+                    - left-hand operand: n  // o.a.f.c.ASTExpVariable
+                    - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
+                    - AST-node subtype: "0"  // Integer
+    #text  // o.a.f.c.ASTStaticText
+        - content: "\n\n"  // String
+    @  // o.a.f.c.ASTDirUserDefined
+        - callee: m  // o.a.f.c.ASTExpVariable
+        - argument value: ..  // o.a.f.c.ASTExpRange
+            - left-hand operand: *  // o.a.f.c.ArithmeticExpression
+                - left-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
+                - right-hand operand: m  // o.a.f.c.ASTExpVariable
+                - AST-node subtype: "1"  // Integer
+            - right-hand operand: -  // o.a.f.c.ArithmeticExpression
+                - left-hand operand: m  // o.a.f.c.ASTExpVariable
+                - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
+                - AST-node subtype: "0"  // Integer
+        - argument value: ..  // o.a.f.c.ASTExpRange
+            - left-hand operand: +  // o.a.f.c.ASTExpAddOrConcat
+                - left-hand operand: m  // o.a.f.c.ASTExpVariable
+                - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
+            - right-hand operand: -  // o.a.f.c.ArithmeticExpression
+                - left-hand operand: n  // o.a.f.c.ASTExpVariable
+                - right-hand operand: 1  // o.a.f.c.ASTExpNumberLiteral
+                - AST-node subtype: "0"  // Integer
+        - argument value: ..  // o.a.f.c.ASTExpRange
+            - left-hand operand: m  // o.a.f.c.ASTExpVariable
+            - right-hand operand: null  // Null

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-range.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-range.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-range.ftl
new file mode 100644
index 0000000..cb55c8a
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/core/ast-range.ftl
@@ -0,0 +1,47 @@
+<#--
+  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.
+-->
+<#assign x = 0..>
+
+<#assign x = 0..1>
+<#assign x = 0..<1>
+<#assign x = 0..!1>
+
+<#assign x = n + 1 .. m + 2>
+<#assign x = n + 1 ..< m + 2>
+<#assign x = n + 1 ..! m + 2>
+
+<#assign x = n * 1 .. m * 2>
+
+<#assign x = n?abs .. m?abs>
+
+<#assign x = n?index_of('x') .. m?index_of('y')>
+
+<#assign x = n..m == o..p>
+
+<#assign x = n+1+2..m-1-2 == o+1+2..p-1-2>
+
+<#assign x = 1+a..+2>
+<#assign x = 1-a..-2>
+<#assign x = 1*a..*2> 
+<#assign x = a && b..c || d> 
+<#assign x = a.. && b.. || d> 
+
+${f(m.., m-1.., m+1..n-1)}
+
+<@m 1 * m .. m - 1 m + 1 .. n - 1 m .. />



[28/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/xml-ns_prefix-scope.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/xml-ns_prefix-scope.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/xml-ns_prefix-scope.txt
new file mode 100644
index 0000000..bf8e6bd
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/xml-ns_prefix-scope.txt
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+//e: e in NS namespace-test, e in NS namespace-test
+//n:e: e in NS foo, e in NS foo
+//bar:e: e in NS bar, e in NS bar
+
+Included:
+//n:e: e in NS foo, e in NS foo
+//n:e: e in NS foo, e in NS foo
+
+Imported:
+//n:e: e in NS bar, e in NS bar
+//n:e: e in NS bar, e in NS bar

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/xml.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/xml.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/xml.txt
new file mode 100644
index 0000000..718bba1
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/xml.txt
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+  <?firstPi customKey="something"?>
+  firstPi
+  customKey="something"
+  <?secondPi secondPiData?>
+  secondPi
+  secondPiData
+2
+p
+ customKey="something"
+
+<ns1:e11 xmlns:ns1="http://www.foo.com/ns1/">text1</ns1:e11><ns1:e11 xmlns:ns1="http://www.foo.com/ns1/">text2</ns1:e11>
+<ns1:e12 xmlns:ns1="http://www.foo.com/ns1/"><![CDATA[cdata-section1]]></ns1:e12><ns1:e12 xmlns:ns1="http://www.foo.com/ns1/"><![CDATA[cdata-section2<&]]></ns1:e12>
+<ns1:e1 xmlns:ns1="http://www.foo.com/ns1/" a1="v1" a2="v2">
+    <ns1:e11>text1</ns1:e11>
+    <ns1:e12><![CDATA[cdata-section1]]></ns1:e12>
+  </ns1:e1>
+<ns1:e11 xmlns:ns1="http://www.foo.com/ns1/">text1</ns1:e11><ns1:e11 xmlns:ns1="http://www.foo.com/ns1/">text2</ns1:e11>
+a1
+v2
+rootroot
+root
+  root
+  e1
+  e11
+  e12
+  e2
+  e11
+  e12
+  root
+  root
+  e1
+  root
+  e1
+  e11
+  root
+  e1
+  e12
+  root
+  e2
+  root
+  e2
+  e11
+  root
+  e2
+  e12
+cdata-section2&lt;&amp;
+cdata-section2<&

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/xmlns1.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/xmlns1.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/xmlns1.txt
new file mode 100644
index 0000000..69af553
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/xmlns1.txt
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+<book xmlns="http://example.com/eBook">
+  <title>Test Book</title>
+  <chapter>
+    <title>Ch1</title>
+    <para>p1.1</para>
+    <para>p1.2</para>
+    <para>p1.3</para>
+  </chapter>
+  <chapter>
+    <title>Ch2</title>
+    <para>p2.1</para>
+    <para>p2.2</para>
+  </chapter>
+</book>
+
+  <html>
+    <head>
+      <title>Test Book</title>
+    </head>
+    <body>
+      <h1>Test Book</h1>
+
+  
+    <h2>Ch1</h2>
+
+    
+      <p>p1.1
+
+      <p>p1.2
+
+      <p>p1.3
+
+  
+    <h2>Ch2</h2>
+
+    
+      <p>p2.1
+
+      <p>p2.2
+
+  
+    </body>
+  </html>
+

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/xmlns3.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/xmlns3.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/xmlns3.txt
new file mode 100644
index 0000000..f028f0a
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/xmlns3.txt
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+  <html>
+    <head>
+      <title>Test Book</title>
+    </head>
+    <body>
+      <h1>Test Book</h1>
+
+  
+    <h2>Ch1</h2>
+
+    
+      <p>p1.1
+
+      <p>p1.2
+
+      <p>p1.3
+
+  
+    <h2>Ch2</h2>
+
+    
+      <p>p2.1
+
+      <p>p2.2
+
+  
+    </body>
+  </html>
+

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/xmlns4.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/xmlns4.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/xmlns4.txt
new file mode 100644
index 0000000..f028f0a
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/xmlns4.txt
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+  <html>
+    <head>
+      <title>Test Book</title>
+    </head>
+    <body>
+      <h1>Test Book</h1>
+
+  
+    <h2>Ch1</h2>
+
+    
+      <p>p1.1
+
+      <p>p1.2
+
+      <p>p1.3
+
+  
+    <h2>Ch2</h2>
+
+    
+      <p>p2.1
+
+      <p>p2.2
+
+  
+    </body>
+  </html>
+

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/xmlns5.txt
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/xmlns5.txt b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/xmlns5.txt
new file mode 100644
index 0000000..6e42b09
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/expected/xmlns5.txt
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+No NS = No NS
+x NS = x NS
+y NS = y NS
+x NS = x NS
+No NS = No NS
+- = -
+- = -
+- = -

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/models/BeansTestResources.properties
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/models/BeansTestResources.properties b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/models/BeansTestResources.properties
new file mode 100644
index 0000000..609e20b
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/models/BeansTestResources.properties
@@ -0,0 +1,19 @@
+# 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.
+
+message=Message
+format={0,date,yyyy-MM-dd}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/models/defaultxmlns1.xml
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/models/defaultxmlns1.xml b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/models/defaultxmlns1.xml
new file mode 100644
index 0000000..ed289bb
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/models/defaultxmlns1.xml
@@ -0,0 +1,24 @@
+<!--
+  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.
+-->
+<root xmlns:x="http://x.com" xmlns:y="http://y.com">
+  <t1>No NS</t1>
+  <x:t2>x NS</x:t2>
+  <y:t3>y NS</y:t3>
+  <t4 xmlns="http://x.com">x NS</t4>
+</root>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/models/xml-ns_prefix-scope.xml
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/models/xml-ns_prefix-scope.xml b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/models/xml-ns_prefix-scope.xml
new file mode 100644
index 0000000..934acac
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/models/xml-ns_prefix-scope.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<root xmlns="http://freemarker.org/test/namespace-test"
+    xmlns:foo="http://freemarker.org/test/foo"
+    xmlns:bar="http://freemarker.org/test/bar">
+  <e>e in NS namespace-test</e>
+  <foo:e>e in NS foo</foo:e>
+  <bar:e>e in NS bar</bar:e>
+</root>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/models/xml.xml
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/models/xml.xml b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/models/xml.xml
new file mode 100644
index 0000000..abf7e96
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/models/xml.xml
@@ -0,0 +1,31 @@
+<?xml version="1.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.
+-->
+<?firstPi customKey="something"?>
+<?secondPi secondPiData?>
+<ns1:root xmlns:ns1="http://www.foo.com/ns1/">
+  <ns1:e1 a1="v1" a2="v2">
+    <ns1:e11>text1</ns1:e11>
+    <ns1:e12><![CDATA[cdata-section1]]></ns1:e12>
+  </ns1:e1>
+  <ns1:e2>
+    <ns1:e11>text2</ns1:e11>
+    <ns1:e12><![CDATA[cdata-section2<&]]></ns1:e12>
+  </ns1:e2>
+</ns1:root>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/models/xmlfragment.xml
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/models/xmlfragment.xml b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/models/xmlfragment.xml
new file mode 100644
index 0000000..b5578b6
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/models/xmlfragment.xml
@@ -0,0 +1,19 @@
+<!--
+  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.
+-->
+<root><a><b><c xmlns="http://x">C&lt;&gt;&amp;"']]&gt;</c></b></a></root>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/models/xmlns.xml
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/models/xmlns.xml b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/models/xmlns.xml
new file mode 100644
index 0000000..6f6453e
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/models/xmlns.xml
@@ -0,0 +1,32 @@
+<!--
+  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.
+-->
+<book xmlns="http://example.com/eBook">
+  <title>Test Book</title>
+  <chapter>
+    <title>Ch1</title>
+    <para>p1.1</para>
+    <para>p1.2</para>
+    <para>p1.3</para>
+  </chapter>
+  <chapter>
+    <title>Ch2</title>
+    <para>p2.1</para>
+    <para>p2.2</para>
+  </chapter>
+</book>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/models/xmlns2.xml
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/models/xmlns2.xml b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/models/xmlns2.xml
new file mode 100644
index 0000000..c8bfc9f
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/models/xmlns2.xml
@@ -0,0 +1,32 @@
+<!--
+  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.
+-->
+<eb:book xmlns:eb="http://example.com/eBook">
+  <eb:title>Test Book</eb:title>
+  <eb:chapter>
+    <eb:title>Ch1</eb:title>
+    <eb:para>p1.1</eb:para>
+    <eb:para>p1.2</eb:para>
+    <eb:para>p1.3</eb:para>
+  </eb:chapter>
+  <eb:chapter>
+    <eb:title>Ch2</eb:title>
+    <eb:para>p2.1</eb:para>
+    <eb:para>p2.2</eb:para>
+  </eb:chapter>
+</eb:book>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/models/xmlns3.xml
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/models/xmlns3.xml b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/models/xmlns3.xml
new file mode 100644
index 0000000..8502ead
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/models/xmlns3.xml
@@ -0,0 +1,32 @@
+<!--
+  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.
+-->
+<book xmlns:x="http://x" xmlns:y="http://y">
+  <x:title>Test Book</x:title>
+  <chapter>
+    <y:title>Ch1</y:title>
+    <para>p1.1</para>
+    <para>p1.2</para>
+    <para>p1.3</para>
+  </chapter>
+  <x:chapter>
+    <y:title>Ch2</y:title>
+    <x:para>p2.1</x:para>
+    <y:para>p2.2</y:para>
+  </x:chapter>
+</book>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/api-builtins.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/api-builtins.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/api-builtins.ftl
new file mode 100644
index 0000000..5a9e2d7
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/api-builtins.ftl
@@ -0,0 +1,40 @@
+<#--
+  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.
+-->
+<@assertEquals expected="b" actual=map?api.get(2?int) />
+<@assertEquals expected=2 actual=list?api.indexOf(3?int) />
+<@assert test=set?api.contains("b") />
+<@assert test=!set?api.contains("d") />
+
+<#assign dump = "">
+<#list map?api.entrySet() as entry>
+    <#assign dump = dump + entry.key + ": " + entry.value>
+    <#if entry_has_next>
+        <#assign dump = dump + ", ">
+    </#if>
+</#list>
+<@assertEquals expected="1: a, 2: b, 3: c" actual=dump />
+
+<@assert test=map?has_api />
+<@assert test=list?has_api />
+<@assert test=set?has_api />
+<@assert test=!s?has_api />
+<@assert test=!1?has_api />
+<@assert test=!""?has_api />
+<@assert test=!{}?has_api />
+<@assert test=!true?has_api />

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/arithmetic.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/arithmetic.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/arithmetic.ftl
new file mode 100644
index 0000000..afd4c28
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/arithmetic.ftl
@@ -0,0 +1,50 @@
+[#ftl]
+[#--
+  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.
+--]
+<html>
+<head>
+<title>FreeMarker: Arithmetic Test</title>
+</head>
+<body>
+[#assign foo = 1234, bar = 23.77] 
+
+<p>A simple test follows:</p>
+
+<p>Perform a number assignment:</p>
+
+[#setting locale="en_US"][#assign x = 1.2345, y=2]
+
+#{ x+y ; m2M3}
+#{ y ; m2M3}
+#{ x/y ; m40M40}
+#{y/x}
+#{ y/x ; M4}
+
+<P>Display a number with at least 3 digits after the decimal point</P>
+
+#{foo ; m3}
+
+<p>Now use numbers in assignment</p>
+
+[#assign mynumber = foo + bar   [#-- a comment --] ]
+
+#{mynumber}
+
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/assignments.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/assignments.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/assignments.ftl
new file mode 100644
index 0000000..f9f546d
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/assignments.ftl
@@ -0,0 +1,108 @@
+<#--
+  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.
+-->
+<#assign x = 1>
+<@assertEquals expected=1 actual=x />
+<#assign x = x + 1>
+<@assertEquals expected=2 actual=x />
+<#assign x += 1>
+<@assertEquals expected=3 actual=x />
+<#assign x /= 2>
+<@assertEquals expected=1.5 actual=x />
+<#assign x *= 2>
+<@assertEquals expected=3 actual=x />
+<#assign x %= 2>
+<@assertEquals expected=1 actual=x />
+<#assign x += x  x += x  x += x>
+<@assertEquals expected=8 actual=x />
+<#assign x += x, x += x, x += x>
+<@assertEquals expected=64 actual=x />
+<#assign x++>
+<@assertEquals expected=65 actual=x />
+<#assign x-->
+<@assertEquals expected=64 actual=x />
+<#assign x--, x--, x--, x++, x -= 60>
+<@assertEquals expected=2 actual=x />
+
+<#assign x = 'a'>
+<#assign x += 1>
+<@assertEquals expected='a1' actual=x />
+
+<#assign x = 1>
+<#assign x += 'a'>
+<@assertEquals expected='1a' actual=x />
+
+<#assign x = [11]>
+<#assign x += [22]>
+<@assertEquals expected=11 actual=x[0] />
+<@assertEquals expected=22 actual=x[1] />
+<@assertEquals expected=2 actual=x?size />
+
+<#assign x = { 'a': 11 }>
+<#assign x += { 'b': 22 }>
+<@assertEquals expected=11 actual=x.a />
+<@assertEquals expected=22 actual=x.b />
+<@assertEquals expected=2 actual=x?size />
+
+<#assign x = 1>
+<#global g = 11>
+<#global g -= x>
+<@assertEquals expected=10 actual=g />
+<#global g *= 2>
+<@assertEquals expected=20 actual=g />
+<#global g /= 2.5>
+<@assertEquals expected=8 actual=g />
+<#global g += 2>
+<@assertEquals expected=10 actual=g />
+<#global g++>
+<@assertEquals expected=11 actual=g />
+<#global g-->
+<@assertEquals expected=10 actual=g />
+
+<#macro m>
+    <#local v = x + g>
+    <@assertEquals expected=11 actual=v />
+    <#local v -= x>
+    <@assertEquals expected=10 actual=v />
+    <#local v *= 2>
+    <@assertEquals expected=20 actual=v />
+    <#local v /= 2.5>
+    <@assertEquals expected=8 actual=v />
+    <#local v += 2>
+    <@assertEquals expected=10 actual=v />
+    <#local v++>
+    <@assertEquals expected=11 actual=v />
+    <#local v-->
+    <@assertEquals expected=10 actual=v />
+</#macro>
+<@m />
+
+<#assign foo = 'a'>
+<@assertFails messageRegexp=r".*expected.*number.*assignment.*foo.*string.*"><#assign foo -= 1></@>
+<@assertFails messageRegexp=r".*expected.*number.*assignment.*foo.*string.*"><#assign foo++></@>
+<@assertFails messageRegexp=r".*expected.*number.*assignment.*foo.*string.*"><#assign foo--></@>
+<#assign x = 1>
+<@assertFails messageRegexp=r"(?s).*expected.*number.*string.*'a'.*"><#assign x -= 'a'></@>
+<@assertFails messageRegexp=r"(?s).*assignment.*noSuchVar.*missing.*-=.*"><#assign noSuchVar -= 1></@>
+<@assertFails messageRegexp=r"(?s).*assignment.*noSuchVar.*missing.*\+=.*"><#assign noSuchVar += 1></@>
+<@assertFails messageRegexp=r"(?s).*assignment.*noSuchVar.*missing.*\*=.*"><#assign noSuchVar *= 1></@>
+<@assertFails messageRegexp=r"(?s).*assignment.*noSuchVar.*missing.*/=.*"><#assign noSuchVar /= 1></@>
+<@assertFails messageRegexp=r"(?s).*assignment.*noSuchVar.*missing.*%=.*"><#assign noSuchVar %= 1></@>
+<@assertFails messageRegexp=r"(?s).*assignment.*noSuchVar.*missing.*\+\+.*"><#assign noSuchVar++></@>
+<@assertFails messageRegexp=r"(?s).*assignment.*noSuchVar.*missing.*--.*"><#assign noSuchVar--></@>
+<@assertFails messageRegexp=r'(?s).*assignment.*noSuchVar.*missing.*\+=.*"\$".*'><#assign $noSuchVar += 1></@>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/boolean-formatting.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/boolean-formatting.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/boolean-formatting.ftl
new file mode 100644
index 0000000..a521fe8
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/boolean-formatting.ftl
@@ -0,0 +1,82 @@
+<#--
+  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.
+-->
+<#assign suppress>
+<@assertFails message="true,false">${true}</@>
+<@assertFails message="true,false">${false}</@>
+<@assertFails message="true,false">${"" + true}</@>
+<@assertFails message="true,false">${"" + false}</@>
+<@assertFails message="true,false">${true?upper_case}</@>
+<@assertFails message="true,false">${false?upper_case}</@>
+<@assertEquals expected="true" actual=true?string />
+<@assertEquals expected="false" actual=false?string />
+<@assertEquals expected="true" actual=true?c />
+<@assertEquals expected="false" actual=false?c />
+<@assertEquals expected="t" actual=true?string('t', 'f') />
+<@assertEquals expected="f" actual=false?string('t', 'f') />
+<#setting boolean_format = 'true,false'>
+<@assertFails message="true,false">${true}</@>
+
+<#setting boolean_format = 'ja,nein'>
+<@assertEquals expected="ja" actual="" + true />
+<@assertEquals expected="nein" actual="" + false />
+<@assertEquals expected="JA" actual=true?upper_case />
+<@assertEquals expected="NEIN" actual=false?upper_case />
+<@assertEquals expected="ja" actual=true?string />
+<@assertEquals expected="nein" actual=false?string />
+<@assertEquals expected="true" actual=true?c />
+<@assertEquals expected="false" actual=false?c />
+<@assertEquals expected="t" actual=true?string('t', 'f') />
+<@assertEquals expected="f" actual=false?string('t', 'f') />
+
+<#setting boolean_format = 'y,n'>
+<#assign x = false>
+<#assign n = 123><#assign m = { x: 'foo', n: 'bar' }><@assertEquals actual=m['n'] + m['123'] expected='foobar' />
+<@assertFails exception="UnexpectedTypeException">${m[false]}</@>
+<@assertFails message="can't compare">${x == 'false'}</@>
+<@assertFails message="can't compare">${x != 'false'}</@>
+<@assertFails message="can't convert">${booleanVsStringMethods.expectsString(x)}</@>
+<@assertEquals actual=booleanVsStringMethods.expectsString(booleanAndString) expected="theStringValue" />
+<@assertEquals actual=booleanVsStringMethods.expectsBoolean(x) expected=false />
+<@assertEquals actual=booleanVsStringMethods.expectsBoolean(booleanAndString) expected=true />
+<@assertEquals actual=booleanVsStringMethods.overloaded(x) expected="boolean false" />
+<@assertEquals actual=123?upper_case expected="123" />
+<@assertEquals actual=true?upper_case expected="Y" />
+
+</#assign>
+<#escape x as x?upper_case>
+<#assign x = true>${x} ${true} ${true?string}
+<#assign x = false>${x} ${false} ${false?string}
+<#noescape><#assign x = true>${x} ${true} ${true?string}</#noescape>
+</#escape>
+<#assign x = false>${x} ${false} ${false?string}
+<#assign x = true>${x} ${true} ${true?string}
+<#assign x = false>${x} ${false} ${false?string}
+${'str:' + x} ${'str:' + false}
+${x?string('ja', 'nein')} ${true?string('ja', 'nein')}
+${booleanAndString} ${booleanAndString?string}
+
+<#setting boolean_format = 'y,n'>
+<@assertEquals actual='true'?boolean expected=true />
+<@assertEquals actual='false'?boolean expected=false />
+<@assertEquals actual='y'?boolean expected=true />
+<@assertEquals actual='n'?boolean expected=false />
+<@assertFails message="can't convert">${'N'?boolean}</@>
+<@assertFails message="can't convert">${'True'?boolean}</@>
+<@assertFails message="can't convert">${0?boolean}</@>
+<@assertFails message="sequence">${[]?boolean}</@>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/boolean.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/boolean.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/boolean.ftl
new file mode 100644
index 0000000..ab11c64
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/boolean.ftl
@@ -0,0 +1,142 @@
+<#--
+  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.
+-->
+<html>
+<head>
+<title>FreeMarker: Boolean Values Test</title>
+</head>
+<body>
+
+<p>A simple test follows:</p>
+
+<p>${message}</p>
+
+<#assign b=true>
+
+<p>Now perform scalar boolean tests:</p>
+
+<p><#if b>
+    b is true.<br />
+<#else>
+    b is false.<br />
+</#if></p>
+
+<p><#if false>
+    This can't be!<br />
+<#else>
+    This makes sense.<br />
+</#if></p>
+
+<p><#if boolean3>
+    boolean3 succeeded.<br />
+<#else>
+    boolean3 failed.<br />
+</#if></p>
+
+<p><#if boolean4>
+    boolean4 succeeded.<br />
+<#else>
+    boolean4 failed.<br />
+</#if></p>
+
+<p><#if boolean4 || boolean5>
+    boolean4 || boolean5 succeeded.<br />
+<#else>
+    boolean4 || boolean5 failed.<br />
+</#if></p>
+
+<p><#if boolean5 || boolean4 || boolean5>
+    boolean5 || boolean4 || boolean5 succeeded.<br />
+<#else>
+    boolean5 || boolean4 || boolean5 failed.<br />
+</#if></p>
+
+<p><#if boolean4 && boolean5>
+    boolean4 && boolean5 succeeded.<br />
+<#else>
+    boolean4 && boolean5 failed.<br />
+</#if></p>
+ 
+<p>Now test list models:</p>
+
+<p><#if list1?exists>
+    list1 succeeded.<br />
+<#else>
+    list1 failed.<br />
+</#if></p>
+
+<p><#if list2?exists>
+    list2 succeeded.<br />
+<#else>
+    list2 failed.<br />
+</#if></p>
+
+<p>Test hash models:</p>
+
+<p><#if hash1?exists>
+    hash1 succeeded: ${hash1.temp}<br />
+<#else>
+    hash1 failed: ${hash1.temp}<br />
+</#if></p>
+
+<p><#if hash2?exists>
+    hash2 succeeded.<br />
+<#else>
+    hash2 failed.<br />
+</#if></p>
+
+<p>Test not operator:</p>
+
+<p><#if ! boolean1>
+   Not boolean1 succeeded
+<#else>
+   Not boolean1 failed
+</#if></p>
+
+<p><#if !boolean1>
+   Not boolean1 succeeded
+<#else>
+   Not boolean1 failed
+</#if></p>
+
+<p><#if ! boolean2>
+   Not boolean2 succeeded
+<#else>
+   Not boolean2 failed
+</#if></p>
+
+<p><#if !boolean2>
+   Not boolean2 succeeded
+<#else>
+   Not boolean2 failed
+</#if></p>
+
+<p><#if message == "Hello, world!">
+   Message is "Hello, world!"
+<#else>
+   Message is something else (${message})
+</#if></p>
+
+<p><#if message != "Hello, world!">
+   Message is not "Hello, world!" -- it's ${message}
+<#else>
+   Message is "Hello, world!"
+</#if></p>
+
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/charset-in-header.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/charset-in-header.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/charset-in-header.ftl
new file mode 100644
index 0000000..638f4b9
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/charset-in-header.ftl
@@ -0,0 +1,27 @@
+<#ftl encoding="ISO-8859-2">
+<#--
+  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.
+-->
+<head>
+  <meta http-equiv="Content-type" content="text/html; charset=UTF-8">
+</head>
+<body>
+����
+<#include "charset-in-header_inc1.ftl">
+<#include "charset-in-header_inc2.ftl">
+</body>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/charset-in-header_inc1.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/charset-in-header_inc1.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/charset-in-header_inc1.ftl
new file mode 100644
index 0000000..b8dc608
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/charset-in-header_inc1.ftl
@@ -0,0 +1,20 @@
+<#ftl encoding="ISO-8859-1">
+<#--
+  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.
+-->
+����

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/charset-in-header_inc2.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/charset-in-header_inc2.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/charset-in-header_inc2.ftl
new file mode 100644
index 0000000..66100ec
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/charset-in-header_inc2.ftl
@@ -0,0 +1,19 @@
+<#--
+  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.
+-->
+őŐűŰ

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/comment.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/comment.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/comment.ftl
new file mode 100644
index 0000000..9c47168
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/comment.ftl
@@ -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.
+-->
+<html>
+<head>
+<title>FreeMarker: Comment Test</title>
+</head>
+<body>
+<#--
+
+A simple test follows:
+
+${message}
+
+A more rigorous test, showing that we're not faking it:
+
+${message@#$%&}
+
+--><#-- > --><#-- -> --><#-- -- --><#-- -- > -->
+<#if message?exists>
+	<p>Message exists!
+	<#--
+		...and even generates output!
+	-->
+	</p>
+</#if>
+
+a <#-- < --> b
+a <#-- </#noparse> - -- --> b
+
+${1 + 2 + [#-- c --] <#-- c --> <!-- c --> 3}
+${<!-- > -> -- #> #] --> 7}
+${<#-- glitch... --] 8}
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/comparisons.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/comparisons.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/comparisons.ftl
new file mode 100644
index 0000000..a711d4d
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/comparisons.ftl
@@ -0,0 +1,218 @@
+<#--
+  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.
+-->
+<html>
+<head>
+<title>FreeMarker: Numeric Operations Test</title>
+</head>
+<body>
+
+<p>A simple test follows:</p>
+
+<p>${message}</p>
+
+<p>Start with the increment operator:</p>
+<#assign a1 = 0>
+<p>a1 = ${a1}</p>
+<#assign a1 = a1 + 1>
+<p>a1 = ${a1}</p>
+<#assign a1 = a1 + 1>
+<p>a1 = ${a1}</p>
+
+<p>Now the decrement operator:</p>
+<#assign a2 = 5>
+<p>a2 = ${a2}</p>
+<#assign a2 = a2 - 1>
+<p>a2 = ${a2}</p>
+<#assign a2 = a2 - 1>
+<p>a2 = ${a2}</p>
+<#assign a2 = a2 - 1>
+<p>a2 = ${a2}</p>
+<#assign a2 = a2 - 1>
+<p>a2 = ${a2}</p>
+<#assign a2 = a2 - 1>
+<p>a2 = ${a2}</p>
+<#assign a2 = a2 - 1>
+<p>a2 = ${a2}</p>
+<#assign a2 = a2 - 1>
+
+<p>Now the add operator:</p>
+<#assign op1 = 5>
+<#assign op2 = 3>
+<#assign op3 = op1 + op2>
+<p>op1 = ${op1}, op2 = ${op2}, op3 = ${op3}</p>
+<#assign op3 = op3 + op2>
+<p>op3 = ${op3}</p>
+
+<p>And the subtract operator:</p>
+<#assign op3 = op1 - op2 >
+<p>op1 = ${op1}, op2 = ${op2}, op3 = ${op3}</p>
+<#assign op3 = op3 - op2 >
+<p>op3 = ${op3}</p>
+
+<p>The comparison operators:</p>
+<#assign list1 = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ]>
+<#list list1 as item>
+   <p>Item is: ${item}</p>
+   <#if item lt 5>
+   <p>Item is less than five.</p>
+   </#if>
+   <#if item <= 7>
+   <p>Item is less than or equals to seven.</p>
+   </#if>
+   <#if item gt 2>
+   <p>Item is greater than two.</p>
+   </#if>
+   <#if (item >= 10)>
+   <p>Item is greater than or equal to ten.</p>
+   </#if>
+</#list>
+
+<#-- Signum-based optimization test, all 9 permutations: -->
+<#-- 1 -->
+<@assert test= !(0 != 0) />
+<@assert test= (0 == 0) />
+<@assert test= !(0 > 0) />
+<@assert test= (0 >= 0) />
+<@assert test= !(0 < 0) />
+<@assert test= (0 <= 0) />
+<#-- 2 -->
+<@assert test= !(3 != 3) />
+<@assert test= (3 == 3) />
+<@assert test= !(3 > 3) />
+<@assert test= (3 >= 3) />
+<@assert test= !(3 < 3) />
+<@assert test= (3 <= 3) />
+<#-- 3 -->
+<@assert test= !(-3 != -3) />
+<@assert test= (-3 == -3) />
+<@assert test= !(-3 > -3) />
+<@assert test= (-3 >= -3) />
+<@assert test= !(-3 < -3) />
+<@assert test= (-3 <= -3) />
+<#-- 4 -->
+<@assert test= (3 != 0) />
+<@assert test= !(3 == 0) />
+<@assert test= (3 > 0) />
+<@assert test= (3 >= 0) />
+<@assert test= !(3 < 0) />
+<@assert test= !(3 <= 0) />
+<#-- 5 -->
+<@assert test= (0 != 3) />
+<@assert test= !(0 == 3) />
+<@assert test= !(0 > 3) />
+<@assert test= !(0 >= 3) />
+<@assert test= (0 < 3) />
+<@assert test= (0 <= 3) />
+<#-- 6 -->
+<@assert test= (-3 != 0) />
+<@assert test= !(-3 == 0) />
+<@assert test= !(-3 > 0) />
+<@assert test= !(-3 >= 0) />
+<@assert test= (-3 < 0) />
+<@assert test= (-3 <= 0) />
+<#-- 7 -->
+<@assert test= (0 != -3) />
+<@assert test= !(0 == -3) />
+<@assert test= (0 > -3) />
+<@assert test= (0 >= -3) />
+<@assert test= !(0 < -3) />
+<@assert test= !(0 <= -3) />
+<#-- 8 -->
+<@assert test= (-3 != 3) />
+<@assert test= !(-3 == 3) />
+<@assert test= !(-3 > 3) />
+<@assert test= !(-3 >= 3) />
+<@assert test= (-3 < 3) />
+<@assert test= (-3 <= 3) />
+<#-- 9 -->
+<@assert test= (3 != -3) />
+<@assert test= !(3 == -3) />
+<@assert test= (3 > -3) />
+<@assert test= (3 >= -3) />
+<@assert test= !(3 < -3) />
+<@assert test= !(3 <= -3) />
+<#-- Again, now on runtime: -->
+<#assign m3 = -3>
+<#assign p3 = 3>
+<#assign z = 0>
+<#-- 1 -->
+<@assert test= !(z != z) />
+<@assert test= (z == z) />
+<@assert test= !(z > z) />
+<@assert test= (z >= z) />
+<@assert test= !(z < z) />
+<@assert test= (z <= z) />
+<#-- 2 -->
+<@assert test= !(p3 != p3) />
+<@assert test= (p3 == p3) />
+<@assert test= !(p3 > p3) />
+<@assert test= (p3 >= p3) />
+<@assert test= !(p3 < p3) />
+<@assert test= (p3 <= p3) />
+<#-- 3 -->
+<@assert test= !(m3 != m3) />
+<@assert test= (m3 == m3) />
+<@assert test= !(m3 > m3) />
+<@assert test= (m3 >= m3) />
+<@assert test= !(m3 < m3) />
+<@assert test= (m3 <= m3) />
+<#-- 4 -->
+<@assert test= (p3 != z) />
+<@assert test= !(p3 == z) />
+<@assert test= (p3 > z) />
+<@assert test= (p3 >= z) />
+<@assert test= !(p3 < z) />
+<@assert test= !(p3 <= z) />
+<#-- 5 -->
+<@assert test= (z != p3) />
+<@assert test= !(z == p3) />
+<@assert test= !(z > p3) />
+<@assert test= !(z >= p3) />
+<@assert test= (z < p3) />
+<@assert test= (z <= p3) />
+<#-- 6 -->
+<@assert test= (m3 != z) />
+<@assert test= !(m3 == z) />
+<@assert test= !(m3 > z) />
+<@assert test= !(m3 >= z) />
+<@assert test= (m3 < z) />
+<@assert test= (m3 <= z) />
+<#-- 7 -->
+<@assert test= (z != m3) />
+<@assert test= !(z == m3) />
+<@assert test= (z > m3) />
+<@assert test= (z >= m3) />
+<@assert test= !(z < m3) />
+<@assert test= !(z <= m3) />
+<#-- 8 -->
+<@assert test= (m3 != p3) />
+<@assert test= !(m3 == p3) />
+<@assert test= !(m3 > p3) />
+<@assert test= !(m3 >= p3) />
+<@assert test= (m3 < p3) />
+<@assert test= (m3 <= p3) />
+<#-- 9 -->
+<@assert test= (p3 != m3) />
+<@assert test= !(p3 == m3) />
+<@assert test= (p3 > m3) />
+<@assert test= (p3 >= m3) />
+<@assert test= !(p3 < m3) />
+<@assert test= !(p3 <= m3) />
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/compress.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/compress.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/compress.ftl
new file mode 100644
index 0000000..faf4ad6
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/compress.ftl
@@ -0,0 +1,59 @@
+<#--
+  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.
+-->
+<html>
+<head>
+<title>FreeMarker: Compress Test</title>
+</head>
+<body>
+
+<#assign utility={'standardCompress': "org.apache.freemarker.core.util.StandardCompress"?new()}>
+<p>A simple test follows:</p>
+
+<p>${message}</p>
+
+<#compress>
+
+  <p>This is the same message,  using the &quot;compress&quot; tag:</p>
+
+
+<p>${message}</p>
+</#compress>
+
+<@utility.standardCompress buffer_size=8>
+
+  <p>This is the same message,  using the &quot;StandardCompress&quot; transform model:</p>
+
+
+<p>${message}</p>
+</@>
+
+<@utility.standardCompress single_line=true>
+
+<p>This 
+   multi-line message 
+     should 
+be compressed 
+   to a single line.</p></@>
+
+<p>An example where the first character is not whitespace but the second character is:</p>
+<p><#compress>x y</#compress></p>
+
+<p>The end.</p>
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/date-type-builtins.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/date-type-builtins.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/date-type-builtins.ftl
new file mode 100644
index 0000000..f05654b
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/date-type-builtins.ftl
@@ -0,0 +1,47 @@
+<#--
+  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.
+-->
+<#setting time_zone = "UTC">
+
+<@assert test=unknown?is_unknown_date_like />
+<@assert test=!timeOnly?is_unknown_date_like />
+<@assert test=!dateOnly?is_unknown_date_like />
+<@assert test=!dateTime?is_unknown_date_like />
+
+<@assert test=!unknown?is_date_only />
+<@assert test=!timeOnly?is_date_only />
+<@assert test=dateOnly?is_date_only />
+<@assert test=!dateTime?is_date_only />
+
+<@assert test=!unknown?is_time />
+<@assert test=timeOnly?is_time />
+<@assert test=!dateOnly?is_time />
+<@assert test=!dateTime?is_time />
+
+<@assert test=!unknown?is_datetime />
+<@assert test=!timeOnly?is_datetime />
+<@assert test=!dateOnly?is_datetime />
+<@assert test=dateTime?is_datetime />
+
+<@assertFails message="isn't known if">${unknown?string.xs}</@>
+<@assertEquals expected="2003-04-05T06:07:08Z" actual=unknown?datetime_if_unknown?string.xs />
+<@assertEquals expected="2003-04-05Z" actual=unknown?date_if_unknown?string.xs />
+<@assertEquals expected="06:07:08Z" actual=unknown?time_if_unknown?string.xs />
+<@assertEquals expected="2003-04-05T06:07:08Z" actual=dateTime?date_if_unknown?string.xs />
+<@assertEquals expected="2003-04-05" actual=dateOnly?time_if_unknown?string.xs />
+<@assertEquals expected="06:07:08" actual=timeOnly?date_if_unknown?string.xs />
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/dateformat-iso-bi.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/dateformat-iso-bi.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/dateformat-iso-bi.ftl
new file mode 100644
index 0000000..85fb028
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/dateformat-iso-bi.ftl
@@ -0,0 +1,163 @@
+<#--
+  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.
+-->
+<#assign d = "2010-05-15 22:38:05:23 +0200"?datetime("yyyy-MM-dd HH:mm:ss:S Z")>
+<#setting time_zone="GMT+02">
+<@assertEquals actual=d?iso_utc expected="2010-05-15T20:38:05Z" />
+<@assertEquals actual=d?iso_utc_ms expected="2010-05-15T20:38:05.023Z" />
+<@assertEquals actual=d?iso_utc_m expected="2010-05-15T20:38Z" />
+<@assertEquals actual=d?iso_utc_h expected="2010-05-15T20Z" />
+<@assertEquals actual=d?iso_utc_nz expected="2010-05-15T20:38:05" />
+<@assertEquals actual=d?iso_utc_ms_nz expected="2010-05-15T20:38:05.023" />
+<@assertEquals actual=d?iso_utc_m_nz expected="2010-05-15T20:38" />
+<@assertEquals actual=d?iso_utc_h_nz expected="2010-05-15T20" />
+<@assertEquals actual=d?iso_local expected="2010-05-15T22:38:05+02:00" />
+<@assertEquals actual=d?iso_local_ms expected="2010-05-15T22:38:05.023+02:00" />
+<@assertEquals actual=d?iso_local_m expected="2010-05-15T22:38+02:00" />
+<@assertEquals actual=d?iso_local_h expected="2010-05-15T22+02:00" />
+<@assertEquals actual=d?iso_local_nz expected="2010-05-15T22:38:05" />
+<@assertEquals actual=d?iso_local_ms_nz expected="2010-05-15T22:38:05.023" />
+<@assertEquals actual=d?iso_local_m_nz expected="2010-05-15T22:38" />
+<@assertEquals actual=d?iso_local_h_nz expected="2010-05-15T22" />
+
+<@assertEquals actual=d?date?iso_utc expected="2010-05-15" />
+<@assertEquals actual=d?date?iso_utc_ms expected="2010-05-15" />
+<@assertEquals actual=d?date?iso_utc_m expected="2010-05-15" />
+<@assertEquals actual=d?date?iso_utc_h expected="2010-05-15" />
+<@assertEquals actual=d?date?iso_utc_nz expected="2010-05-15" />
+<@assertEquals actual=d?date?iso_utc_ms_nz expected="2010-05-15" />
+<@assertEquals actual=d?date?iso_utc_m_nz expected="2010-05-15" />
+<@assertEquals actual=d?date?iso_utc_h_nz expected="2010-05-15" />
+<@assertEquals actual=d?date?iso_local expected="2010-05-15" />
+<@assertEquals actual=d?date?iso_local_ms expected="2010-05-15" />
+<@assertEquals actual=d?date?iso_local_m expected="2010-05-15" />
+<@assertEquals actual=d?date?iso_local_h expected="2010-05-15" />
+<@assertEquals actual=d?date?iso_local_nz expected="2010-05-15" />
+<@assertEquals actual=d?date?iso_local_ms_nz expected="2010-05-15" />
+<@assertEquals actual=d?date?iso_local_m_nz expected="2010-05-15" />
+<@assertEquals actual=d?date?iso_local_h_nz expected="2010-05-15" />
+
+<@assertEquals actual=d?time?iso_utc expected="20:38:05Z" />
+<@assertEquals actual=d?time?iso_utc_ms expected="20:38:05.023Z" />
+<@assertEquals actual=d?time?iso_utc_m expected="20:38Z" />
+<@assertEquals actual=d?time?iso_utc_h expected="20Z" />
+<@assertEquals actual=d?time?iso_utc_nz expected="20:38:05" />
+<@assertEquals actual=d?time?iso_utc_ms_nz expected="20:38:05.023" />
+<@assertEquals actual=d?time?iso_utc_m_nz expected="20:38" />
+<@assertEquals actual=d?time?iso_utc_h_nz expected="20" />
+<@assertEquals actual=d?time?iso_local expected="22:38:05+02:00" />
+<@assertEquals actual=d?time?iso_local_ms expected="22:38:05.023+02:00" />
+<@assertEquals actual=d?time?iso_local_m expected="22:38+02:00" />
+<@assertEquals actual=d?time?iso_local_h expected="22+02:00" />
+<@assertEquals actual=d?time?iso_local_nz expected="22:38:05" />
+<@assertEquals actual=d?time?iso_local_ms_nz expected="22:38:05.023" />
+<@assertEquals actual=d?time?iso_local_m_nz expected="22:38" />
+<@assertEquals actual=d?time?iso_local_h_nz expected="22" />
+
+<#assign dStrange = "600-01-01 23:59:59:123 +0000"?datetime("yyyy-MM-dd HH:mm:ss:S Z")>
+<@assertEquals actual=dStrange?iso_utc_ms expected="0600-01-03T23:59:59.123Z" />
+
+<#-- java.sql treatment -->
+<@assertEquals actual=sqlDate?iso_local expected="2010-05-15" />
+<@assertEquals actual=sqlDate?iso_local_nz expected="2010-05-15" />
+<@assertEquals actual=sqlTime?iso_local_nz expected="22:38:05" />
+<@assertEquals actual=sqlTime?iso_utc_nz expected="20:38:05" />
+
+<#setting time_zone="GMT+03"> <#-- should not mater -->
+<@assertEquals actual=d?iso("UTC") expected="2010-05-15T20:38:05Z" />
+<@assertEquals actual=d?iso_ms("UTC") expected="2010-05-15T20:38:05.023Z" />
+<@assertEquals actual=d?iso_m("UTC") expected="2010-05-15T20:38Z" />
+<@assertEquals actual=d?iso_h("UTC") expected="2010-05-15T20Z" />
+<@assertEquals actual=d?iso_nz("UTC") expected="2010-05-15T20:38:05" />
+<@assertEquals actual=d?iso_ms_nz("UTC") expected="2010-05-15T20:38:05.023" />
+<@assertEquals actual=d?iso_m_nz("UTC") expected="2010-05-15T20:38" />
+<@assertEquals actual=d?iso_h_nz("UTC") expected="2010-05-15T20" />
+<@assertEquals actual=d?iso("GMT+02") expected="2010-05-15T22:38:05+02:00" />
+<@assertEquals actual=d?iso_ms("GMT+02") expected="2010-05-15T22:38:05.023+02:00" />
+<@assertEquals actual=d?iso_m("GMT+02") expected="2010-05-15T22:38+02:00" />
+<@assertEquals actual=d?iso_h("GMT+02") expected="2010-05-15T22+02:00" />
+<@assertEquals actual=d?iso_nz("GMT+02") expected="2010-05-15T22:38:05" />
+<@assertEquals actual=d?iso_ms_nz("GMT+02") expected="2010-05-15T22:38:05.023" />
+<@assertEquals actual=d?iso_m_nz("GMT+02") expected="2010-05-15T22:38" />
+<@assertEquals actual=d?iso_h_nz("GMT+02") expected="2010-05-15T22" />
+
+<@assertEquals actual=d?date?iso("UTC") expected="2010-05-15" />
+<@assertEquals actual=d?date?iso_ms("UTC") expected="2010-05-15" />
+<@assertEquals actual=d?date?iso_m("UTC") expected="2010-05-15" />
+<@assertEquals actual=d?date?iso_h("UTC") expected="2010-05-15" />
+<@assertEquals actual=d?date?iso_nz("UTC") expected="2010-05-15" />
+<@assertEquals actual=d?date?iso_ms_nz("UTC") expected="2010-05-15" />
+<@assertEquals actual=d?date?iso_m_nz("UTC") expected="2010-05-15" />
+<@assertEquals actual=d?date?iso_h_nz("UTC") expected="2010-05-15" />
+<@assertEquals actual=d?date?iso("GMT+02") expected="2010-05-15" />
+<@assertEquals actual=d?date?iso_ms("GMT+02") expected="2010-05-15" />
+<@assertEquals actual=d?date?iso_m("GMT+02") expected="2010-05-15" />
+<@assertEquals actual=d?date?iso_h("GMT+02") expected="2010-05-15" />
+<@assertEquals actual=d?date?iso_nz("GMT+02") expected="2010-05-15" />
+<@assertEquals actual=d?date?iso_ms_nz("GMT+02") expected="2010-05-15" />
+<@assertEquals actual=d?date?iso_m_nz("GMT+02") expected="2010-05-15" />
+<@assertEquals actual=d?date?iso_h_nz("GMT+02") expected="2010-05-15" />
+
+<@assertEquals actual=d?time?iso("UTC") expected="20:38:05Z" />
+<@assertEquals actual=d?time?iso_ms("UTC") expected="20:38:05.023Z" />
+<@assertEquals actual=d?time?iso_m("UTC") expected="20:38Z" />
+<@assertEquals actual=d?time?iso_h("UTC") expected="20Z" />
+<@assertEquals actual=d?time?iso_nz("UTC") expected="20:38:05" />
+<@assertEquals actual=d?time?iso_ms_nz("UTC") expected="20:38:05.023" />
+<@assertEquals actual=d?time?iso_m_nz("UTC") expected="20:38" />
+<@assertEquals actual=d?time?iso_h_nz("UTC") expected="20" />
+<@assertEquals actual=d?time?iso("GMT+02") expected="22:38:05+02:00" />
+<@assertEquals actual=d?time?iso_ms("GMT+02") expected="22:38:05.023+02:00" />
+<@assertEquals actual=d?time?iso_m("GMT+02") expected="22:38+02:00" />
+<@assertEquals actual=d?time?iso_h("GMT+02") expected="22+02:00" />
+<@assertEquals actual=d?time?iso_nz("GMT+02") expected="22:38:05" />
+<@assertEquals actual=d?time?iso_ms_nz("GMT+02") expected="22:38:05.023" />
+<@assertEquals actual=d?time?iso_m_nz("GMT+02") expected="22:38" />
+<@assertEquals actual=d?time?iso_h_nz("GMT+02") expected="22" />
+
+<@assertEquals actual=d?iso(javaUTC) expected="2010-05-15T20:38:05Z" />
+<@assertEquals actual=d?iso(javaGMT02) expected="2010-05-15T22:38:05+02:00" />
+<@assertEquals actual=d?iso(adaptedToStringScalar) expected="2010-05-15T22:38:05+02:00" />
+
+<#assign d = "12:00:00:1 +0000"?time("HH:mm:ss:S Z")>
+<@assertEquals actual=d?iso_utc_ms expected="12:00:00.001Z" />
+<#assign d = "12:00:00:10 +0000"?time("HH:mm:ss:S Z")>
+<@assertEquals actual=d?iso_utc_ms expected="12:00:00.01Z" />
+<#assign d = "12:00:00:100 +0000"?time("HH:mm:ss:S Z")>
+<@assertEquals actual=d?iso_utc_ms expected="12:00:00.1Z" />
+<#assign d = "12:00:00:0 +0000"?time("HH:mm:ss:S Z")>
+<@assertEquals actual=d?iso_utc_ms expected="12:00:00Z" />
+
+<#setting time_zone="GMT+02">
+<#assign d = "2010-05-15"?date("yyyy-MM-dd")>
+<@assertEquals actual=d?iso_local expected="2010-05-15" />
+<@assertEquals actual=d?iso_utc expected="2010-05-14" />
+
+<#setting time_zone="GMT+02:30">
+<#assign d = "2010-05-15"?datetime("yyyy-MM-dd")>
+<@assertEquals actual=d?iso_local expected="2010-05-15T00:00:00+02:30" />
+
+<#setting time_zone="America/New_York">
+<@assertEquals actual="2010-05-09 20:00 +0000"?datetime("yyyy-MM-dd HH:mm Z")?iso_local expected="2010-05-09T16:00:00-04:00" />
+<@assertEquals actual="2010-01-01 20:00 +0000"?datetime("yyyy-MM-dd HH:mm Z")?iso_local expected="2010-01-01T15:00:00-05:00" />
+
+<@assertFails>${d?iso("no such zone")}</@>
+
+<#setting time_zone="GMT+02">
+<@assertEquals actual=sqlTime?iso_local expected="22:38:05" />
+<@assertEquals actual=sqlTime?iso_utc expected="20:38:05" />

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/dateformat-iso-like.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/dateformat-iso-like.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/dateformat-iso-like.ftl
new file mode 100644
index 0000000..a5accaf
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/dateformat-iso-like.ftl
@@ -0,0 +1,155 @@
+<#--
+  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.
+-->
+<#assign d = "2010-05-15 22:38:05:23 +0200"?datetime("yyyy-MM-dd HH:mm:ss:S Z")>
+<#setting time_zone="GMT+02">
+<@assertEquals actual=d?string.xs  expected="2010-05-15T22:38:05.023+02:00" />
+<@assertEquals actual=d?string.iso expected="2010-05-15T22:38:05.023+02:00" />
+<@assertEquals actual=d?string('xs')  expected="2010-05-15T22:38:05.023+02:00" />
+<@assertEquals actual=d?string('iso') expected="2010-05-15T22:38:05.023+02:00" />
+<@assertEquals actual=d?string.xs_nz  expected="2010-05-15T22:38:05.023" />
+<@assertEquals actual=d?string.iso_nz expected="2010-05-15T22:38:05.023" />
+<@assertEquals actual=d?string.xs_fz  expected="2010-05-15T22:38:05.023+02:00" />
+<@assertEquals actual=d?string.iso_fz expected="2010-05-15T22:38:05.023+02:00" />
+<@assertEquals actual=d?string.xs_u  expected="2010-05-15T20:38:05.023Z" />
+<@assertEquals actual=d?string.iso_u expected="2010-05-15T20:38:05.023Z" />
+<@assertEquals actual=d?string.xs_s_u  expected="2010-05-15T20:38:05Z" />
+<@assertEquals actual=d?string.iso_s_u expected="2010-05-15T20:38:05Z" />
+
+<@assertEquals actual=d?date?string.xs  expected="2010-05-15+02:00" />
+<@assertEquals actual=d?date?string.iso expected="2010-05-15" />
+<@assertEquals actual=d?date?string.xs_nz  expected="2010-05-15" />
+<@assertEquals actual=d?date?string.iso_nz expected="2010-05-15" />
+<@assertEquals actual=d?date?string.xs_fz  expected="2010-05-15+02:00" />
+<@assertEquals actual=d?date?string.iso_fz expected="2010-05-15" />
+
+<@assertEquals actual=d?time?string.xs  expected="22:38:05.023+02:00" />
+<@assertEquals actual=d?time?string.iso expected="22:38:05.023+02:00" />
+<@assertEquals actual=d?time?string.xs_nz  expected="22:38:05.023" />
+<@assertEquals actual=d?time?string.iso_nz expected="22:38:05.023" />
+<@assertEquals actual=d?time?string.xs_fz  expected="22:38:05.023+02:00" />
+<@assertEquals actual=d?time?string.iso_fz expected="22:38:05.023+02:00" />
+
+<#-- java.sql treatment -->
+<@assertEquals actual=sqlDate?string.xs  expected="2010-05-15" />
+<@assertEquals actual=sqlDate?string.iso expected="2010-05-15" />
+<@assertEquals actual=sqlDate?string.xs_fz  expected="2010-05-15+02:00" />
+<@assertEquals actual=sqlDate?string.iso_fz expected="2010-05-15" />
+<@assertEquals actual=sqlDate?string.xs_nz  expected="2010-05-15" />
+<@assertEquals actual=sqlDate?string.iso_nz expected="2010-05-15" />
+<@assertEquals actual=sqlTime?string.xs  expected="22:38:05.023" />
+<@assertEquals actual=sqlTime?string.iso expected="22:38:05.023" />
+<@assertEquals actual=sqlTime?string.xs_fz  expected="22:38:05.023+02:00" />
+<@assertEquals actual=sqlTime?string.iso_fz expected="22:38:05.023+02:00" />
+<@assertEquals actual=sqlTime?string.xs_nz  expected="22:38:05.023" />
+<@assertEquals actual=sqlTime?string.iso_nz expected="22:38:05.023" />
+
+<#assign d = "12:30:15:1 +0200"?time("HH:mm:ss:S Z")>
+<@assertEquals actual=d?string.xs  expected="12:30:15.001+02:00" />
+<@assertEquals actual=d?string.iso expected="12:30:15.001+02:00" />
+<@assertEquals actual=d?string.xs_ms  expected="12:30:15.001+02:00" />
+<@assertEquals actual=d?string.iso_ms expected="12:30:15.001+02:00" />
+<@assertEquals actual=d?string.iso_s expected="12:30:15+02:00" />
+<@assertEquals actual=d?string.iso_m expected="12:30+02:00" />
+<@assertEquals actual=d?string.iso_h expected="12+02:00" />
+<#assign d = "12:30:15:10 +0200"?time("HH:mm:ss:S Z")>
+<@assertEquals actual=d?string.xs  expected="12:30:15.01+02:00" />
+<@assertEquals actual=d?string.iso expected="12:30:15.01+02:00" />
+<@assertEquals actual=d?string.xs_ms  expected="12:30:15.010+02:00" />
+<@assertEquals actual=d?string.iso_ms expected="12:30:15.010+02:00" />
+<#assign d = "12:30:15:100 +0200"?time("HH:mm:ss:S Z")>
+<@assertEquals actual=d?string.xs  expected="12:30:15.1+02:00" />
+<@assertEquals actual=d?string.iso expected="12:30:15.1+02:00" />
+<@assertEquals actual=d?string.xs_ms  expected="12:30:15.100+02:00" />
+<@assertEquals actual=d?string.iso_ms expected="12:30:15.100+02:00" />
+<#assign d = "12:30:15:0 +0200"?time("HH:mm:ss:S Z")>
+<@assertEquals actual=d?string.xs  expected="12:30:15+02:00" />
+<@assertEquals actual=d?string.iso expected="12:30:15+02:00" />
+<@assertEquals actual=d?string.xs_ms  expected="12:30:15.000+02:00" />
+<@assertEquals actual=d?string.iso_ms expected="12:30:15.000+02:00" />
+
+<#setting time_zone="GMT+02">
+<#assign d = "2010-05-15"?date("yyyy-MM-dd")>
+<@assertEquals actual=d?string.xs  expected="2010-05-15+02:00" />
+<@assertEquals actual=d?string.iso expected="2010-05-15" />
+<#setting time_zone="GMT+00">
+<@assertEquals actual=d?string.xs  expected="2010-05-14Z" />
+<@assertEquals actual=d?string.iso expected="2010-05-14" />
+
+<#setting time_zone="GMT+02:30">
+<#assign d = "2010-05-15"?datetime("yyyy-MM-dd")>
+<@assertEquals actual=d?string.xs  expected="2010-05-15T00:00:00+02:30" />
+<@assertEquals actual=d?string.iso expected="2010-05-15T00:00:00+02:30" />
+
+<#setting time_zone="GMT-05">
+<#setting locale = "en_US">
+<#assign d = "BC 0001-05-15"?date("G yyyy-MM-dd")>
+<#-- Tests that: (a) BC 1 isn't 0 like in ISO 8601; (b) No Julian calendar is used.  -->
+<@assertEquals actual=d?string.xs  expected="-1-05-13-05:00" />
+<@assertEquals actual=d?string.iso expected="0000-05-13" />
+
+<#assign dt = "2010-05-15T01:02:03"?datetime.xs>
+<#setting datetime_format="xs">
+<@assertEquals actual=dt?string expected="2010-05-15T01:02:03-05:00" />
+<#setting datetime_format="xs u">
+<@assertEquals actual=dt?string expected="2010-05-15T06:02:03Z" />
+<#setting datetime_format="iso u">
+<@assertEquals actual=dt?string expected="2010-05-15T06:02:03Z" />
+<#setting datetime_format="xs fz">
+<@assertEquals actual=dt?string expected="2010-05-15T01:02:03-05:00" />
+<#setting datetime_format="xs fz u">
+<@assertEquals actual=dt?string expected="2010-05-15T06:02:03Z" />
+<#setting datetime_format="xs nz u">
+<@assertEquals actual=dt?string expected="2010-05-15T06:02:03" />
+<#setting datetime_format="iso m nz">
+<@assertEquals actual=dt?string expected="2010-05-15T01:02" />
+
+<#assign d = dt?date>
+<#setting date_format="xs">
+<@assertEquals actual=d?string expected="2010-05-15-05:00" />
+<#setting date_format="iso">
+<@assertEquals actual=d?string expected="2010-05-15" />
+<#setting date_format="xs fz">
+<@assertEquals actual=d?string expected="2010-05-15-05:00" />
+<#setting date_format="xs fz u">
+<@assertEquals actual=d?string expected="2010-05-15Z" />
+<#setting date_format="iso fz u">
+<@assertEquals actual=d?string expected="2010-05-15" />
+<#setting date_format="xs nz">
+<@assertEquals actual=d?string expected="2010-05-15" />
+
+<#assign t = dt?time>
+<@assertEquals actual=d?string expected="2010-05-15" />
+<#setting time_format="xs">
+<@assertEquals actual=t?string expected="01:02:03-05:00" />
+<#setting time_format="iso_m">
+<@assertEquals actual=t?string expected="01:02-05:00" />
+<#setting time_format="xs fz">
+<@assertEquals actual=t?string expected="01:02:03-05:00" />
+<#setting time_format="xs nz">
+<@assertEquals actual=t?string expected="01:02:03" />
+<#setting time_format="iso nz ms">
+<@assertEquals actual=t?string expected="01:02:03.000" />
+
+<@assertFails message="Use ?date, ?time, or ?datetime">${unknownDate?string.xs}</@>
+<@assertFails message="Use ?date, ?time, or ?datetime">${unknownDate?string.iso}</@>
+<@assertFails message="format string">${.now?string.xs_fz_nz}</@>
+<@assertFails message="format string">${.now?string.xs_u_fu}</@>
+<@assertFails message="format string">${.now?string.xs_s_ms}</@>
+<@assertFails message="format string">${.now?string.xs_q}</@>
+<@assertFails message="format string">${.now?string.xss}</@>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/dateformat-java.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/dateformat-java.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/dateformat-java.ftl
new file mode 100644
index 0000000..82001db
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/dateformat-java.ftl
@@ -0,0 +1,71 @@
+<#--
+  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.
+-->
+<#setting locale="en_US">
+<#setting time_zone="GMT">
+<#setting datetime_format="">
+${date}
+${unknownDate?datetime}
+${date?string}
+${date?string[""]}
+${date?string.short}
+${date?string.medium}
+${date?string.long}
+${date?string.short_short}
+${date?string.short_medium}
+${date?string.short_long}
+${date?string.medium_short}
+${date?string.medium_medium}
+${date?string.medium_long}
+${date?string.long_short}
+${date?string.long_medium}
+${date?string.long_long}
+${unknownDate?date}
+${date?date?string[""]}
+${date?date?string.short}
+${date?date?string.medium}
+${date?date?string.long}
+${unknownDate?time}
+${date?time?string[""]}
+${date?time?string.short}
+${date?time?string.medium}
+${date?time?string.long}
+<#setting locale="hu_hu">
+<#setting datetime_format="long_long">
+${date}
+<#setting locale="en_US">
+<#setting datetime_format="EEE, dd MMM yyyyy HH:mm:ss z">
+${date}
+${unknownDate?string["EEE, dd MMM yyyy HH:mm:ss z"]}
+${unknownDate?string("EEE, dd MMM yyyy HH:mm:ss z")}
+${unknownDate?string.yyyy}
+
+<#setting datetime_format="yyyy">
+<#assign s = date?string>
+${s}
+<#setting datetime_format="MM">
+${s}
+
+<#-- Check ?string lazy evaluation bug was fixed: -->
+<#setting datetime_format="yyyy">
+<#assign s = date?string>
+<#-- no ${s} -->
+<#setting datetime_format="MM">
+${s}
+<#assign s = date?string>
+${s}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/dateparsing.ftl
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/dateparsing.ftl b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/dateparsing.ftl
new file mode 100644
index 0000000..d830f95
--- /dev/null
+++ b/freemarker-core-test/src/test/resources/org/apache/freemarker/test/templatesuite/templates/dateparsing.ftl
@@ -0,0 +1,84 @@
+<#--
+  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.
+-->
+<#setting locale="en_US">
+<#setting time_zone="GMT">
+<#setting datetime_format="G yyyy-MM-dd HH:mm:ss.S Z">
+<#setting date_format="G yyyy-MM-dd Z">
+<#setting time_format="HH:mm:ss.S Z">
+
+<@assertEquals expected="AD 1998-10-30 15:30:44.512 +0000" actual='AD 1998-10-30 19:30:44.512 +0400'?datetime?string />
+<@assertEquals expected="AD 1998-10-29 +0000" actual='AD 1998-10-30 +0400'?date?string />
+<@assertEquals expected="15:30:44.512 +0000" actual='19:30:44.512 +0400'?time?string />
+
+<@assertEquals expected="AD 1998-10-30 15:30:44.512 +0000"
+               actual='10/30/1998 19:30:44:512 GMT+04:00'?datetime("MM/dd/yyyy HH:mm:ss:S z")?string />
+<@assertEquals expected="AD 1998-10-29 +0000"
+               actual='10/30/1998 GMT+04:00'?date("MM/dd/yyyy z")?string />
+<@assertEquals expected="15:30:44.512 +0000"
+               actual='19:30:44:512 GMT+04:00'?time("HH:mm:ss:S z")?string />
+
+<@assertEquals expected="AD 1998-10-30 15:30:44.512 +0000" actual='1998-10-30T19:30:44.512+04:00'?datetime.xs?string />
+<@assertEquals expected="AD 1998-10-29 +0000" actual='1998-10-30+04:00'?date.xs?string />
+<@assertEquals expected="15:30:44.512 +0000" actual='19:30:44.512+04:00'?time.xs?string />
+
+<#assign gmtStr='1998-10-30T19:30:44.512'?datetime.xs?string />
+<#setting time_zone="GMT+01:00">
+<#assign gmt01Str='1998-10-30T19:30:44.512'?datetime.xs?string />
+<#setting time_zone="default">
+<#assign defStr='1998-10-30T19:30:44.512'?datetime.xs?string />
+<@assert test = gmtStr != gmt01Str />
+<@assert test = defStr != gmtStr || defStr != gmt01Str />
+
+<#assign refDate = "AD 1998-10-30 +0000"?date>
+<#assign refTime = "15:30:44.512 +0000"?time>
+<#assign refDateTime = "AD 1998-10-30 15:30:44.512 +0000"?datetime>
+<#setting time_zone="UTC">
+<#list ['xs', 'xs_nz', 'xs_fz', 'xs s', 'xs ms'] as format>
+  <#setting date_format=format>
+  <#setting time_format=format>
+  <#setting datetime_format=format>
+  <@assertEquals expected=refDate actual="1998-10-30Z"?date />
+  <@assertEquals expected=refTime actual="15:30:44.512Z"?time />
+  <@assertEquals expected=refDateTime actual="1998-10-30T15:30:44.512Z"?datetime />
+</#list>
+<#list ['iso', 'iso_nz', 'iso_fz', 'iso m'] as format>
+  <#setting date_format=format>
+  <#setting time_format=format>
+  <#setting datetime_format=format>
+  <@assertEquals expected=refDate actual="1998-10-30"?date />
+  <@assertEquals expected=refDate actual="19981030"?date />
+  <@assertEquals expected=refTime actual="15:30:44,512Z"?time />
+  <@assertEquals expected=refTime actual="153044,512Z"?time />
+  <@assertEquals expected=refDateTime actual="1998-10-30T15:30:44,512Z"?datetime />
+  <@assertEquals expected=refDateTime actual="19981030T153044,512Z"?datetime />
+</#list>
+
+<#setting time_zone="GMT+01:00">
+<#assign refDateTime='1998-10-30T19:30:44.512'?datetime.xs />
+<@assertEquals expected=refDateTime actual="1998-10-30T19:30:44.512"?datetime.xs />
+<@assertEquals expected=refDateTime actual="1998-10-30T19:30:44.512"?datetime.iso />
+<@assertEquals expected=refDateTime actual="1998-10-30T18:30:44.512"?datetime.xs_u />
+<@assertEquals expected=refDateTime actual="1998-10-30T18:30:44.512"?datetime.iso_u />
+<#setting time_zone="UTC">
+<@assertEquals expected=refDateTime actual="1998-10-30T18:30:44.512"?datetime.xs />
+<@assertEquals expected=refDateTime actual="1998-10-30T18:30:44.512"?datetime.iso />
+<@assertEquals expected=refDateTime actual="1998-10-30T19:30:44.512+01:00"?datetime.xs />
+<@assertEquals expected=refDateTime actual="1998-10-30T19:30:44.512+01:00"?datetime.xs_u />
+<@assertEquals expected=refDateTime actual="1998-10-30T19:30:44.512+01"?datetime.iso />
+<@assertEquals expected=refDateTime actual="1998-10-30T19:30:44.512+01"?datetime.iso_u />
\ No newline at end of file



[14/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/ErrorMessagesTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/ErrorMessagesTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/ErrorMessagesTest.java
deleted file mode 100644
index 4306a50..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/ErrorMessagesTest.java
+++ /dev/null
@@ -1,170 +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.model.impl;
-
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
-import java.util.Collections;
-import java.util.Date;
-
-import org.apache.freemarker.core.Configuration;
-import org.apache.freemarker.core.model.TemplateHashModel;
-import org.apache.freemarker.core.model.TemplateMethodModelEx;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateScalarModel;
-import org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat;
-import org.apache.freemarker.core.outputformat.impl.TemplateHTMLOutputModel;
-import org.junit.Test;
-
-public class ErrorMessagesTest {
-
-    @Test
-    public void getterMessage() throws TemplateModelException {
-        DefaultObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
-        TemplateHashModel thm= (TemplateHashModel) ow.wrap(new TestBean());
-        
-        try {
-            thm.get("foo");
-        } catch (TemplateModelException e) {
-            e.printStackTrace();
-            final String msg = e.getMessage();
-            assertThat(msg, containsString("\"foo\""));
-            assertThat(msg, containsString("existing sub-variable"));
-        }
-        assertNull(thm.get("bar"));
-    }
-    
-    @Test
-    public void markupOutputParameter() throws Exception {
-        TemplateHTMLOutputModel html = HTMLOutputFormat.INSTANCE.fromMarkup("<p>a");
-
-        DefaultObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
-        TemplateHashModel thm = (TemplateHashModel) ow.wrap(new TestBean());
-        
-        {
-            TemplateMethodModelEx m = (TemplateMethodModelEx) thm.get("m1");
-            try {
-                m.exec(Collections.singletonList(html));
-                fail();
-            } catch (TemplateModelException e) {
-                assertThat(e.getMessage(), allOf(
-                        containsString("String"), containsString("convert"), containsString("markup_output"),
-                        containsString("Tip:"), containsString("?markup_string")));
-            }
-        }
-        
-        {
-            TemplateMethodModelEx m = (TemplateMethodModelEx) thm.get("m2");
-            try {
-                m.exec(Collections.singletonList(html));
-                fail();
-            } catch (TemplateModelException e) {
-                assertThat(e.getMessage(), allOf(
-                        containsString("Date"), containsString("convert"), containsString("markup_output"),
-                        not(containsString("?markup_string"))));
-            }
-        }
-        
-        for (String methodName : new String[] { "mOverloaded", "mOverloaded3" }) {
-            TemplateMethodModelEx m = (TemplateMethodModelEx) thm.get(methodName);
-            try {
-                m.exec(Collections.singletonList(html));
-                fail();
-            } catch (TemplateModelException e) {
-                assertThat(e.getMessage(), allOf(
-                        containsString("No compatible overloaded"),
-                        containsString("String"), containsString("markup_output"),
-                        containsString("Tip:"), containsString("?markup_string")));
-            }
-        }
-        
-        {
-            TemplateMethodModelEx m = (TemplateMethodModelEx) thm.get("mOverloaded2");
-            try {
-                m.exec(Collections.singletonList(html));
-                fail();
-            } catch (TemplateModelException e) {
-                assertThat(e.getMessage(), allOf(
-                        containsString("No compatible overloaded"),
-                        containsString("Integer"), containsString("markup_output"),
-                        not(containsString("?markup_string"))));
-            }
-        }
-        
-        {
-            TemplateMethodModelEx m = (TemplateMethodModelEx) thm.get("mOverloaded4");
-            Object r = m.exec(Collections.singletonList(html));
-            if (r instanceof TemplateScalarModel) {
-                r = ((TemplateScalarModel) r).getAsString();
-            }
-            assertEquals("<p>a", r);
-        }
-    }
-    
-    public static class TestBean {
-        
-        public String getFoo() {
-            throw new RuntimeException("Dummy");
-        }
-        
-        public void m1(String s) {
-            // nop
-        }
-
-        public void m2(Date s) {
-            // nop
-        }
-
-        public void mOverloaded(String s) {
-            // nop
-        }
-
-        public void mOverloaded(Date d) {
-            // nop
-        }
-
-        public void mOverloaded2(Integer n) {
-            // nop
-        }
-
-        public void mOverloaded2(Date d) {
-            // nop
-        }
-
-        public void mOverloaded3(String... s) {
-            // nop
-        }
-
-        public void mOverloaded3(Date d) {
-            // nop
-        }
-        
-        public String mOverloaded4(String s) {
-            return s;
-        }
-
-        public String mOverloaded4(TemplateHTMLOutputModel s) throws TemplateModelException {
-            return s.getOutputFormat().getMarkupString(s);
-        }
-        
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/FineTuneMethodAppearanceTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/FineTuneMethodAppearanceTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/FineTuneMethodAppearanceTest.java
deleted file mode 100644
index 92f59fb..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/FineTuneMethodAppearanceTest.java
+++ /dev/null
@@ -1,65 +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.model.impl;
-
-import static org.junit.Assert.*;
-
-import org.apache.freemarker.core.Configuration;
-import org.apache.freemarker.core.model.TemplateHashModel;
-import org.apache.freemarker.core.model.TemplateMethodModelEx;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateScalarModel;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class FineTuneMethodAppearanceTest {
-
-    @Test
-    public void newWayOfConfiguring() throws TemplateModelException {
-        DefaultObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0)
-                .methodAppearanceFineTuner(GetlessMethodsAsPropertyGettersRule.INSTANCE)
-                .exposeFields(true)
-                .build();
-        checkIfProperlyWrapped(ow.wrap(new C()));
-    }
-    
-    private void checkIfProperlyWrapped(TemplateModel tm) throws TemplateModelException {
-        TemplateHashModel thm = (TemplateHashModel) tm;
-        assertEquals("v1", ((TemplateScalarModel) thm.get("v1")).getAsString());
-        assertEquals("v2()", ((TemplateScalarModel) thm.get("v2")).getAsString());
-        assertEquals("getV3()", ((TemplateScalarModel) thm.get("v3")).getAsString());
-        assertTrue(thm.get("getV3") instanceof TemplateMethodModelEx);
-    }
-    
-    static public class C {
-        
-        public String v1 = "v1";
-
-        public String v2 = "v2";
-        public String v2() { return "v2()"; }
-        
-        public String v3() { return "v3()"; }
-        public String getV3() { return "getV3()"; }
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/GetlessMethodsAsPropertyGettersRule.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/GetlessMethodsAsPropertyGettersRule.java b/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/GetlessMethodsAsPropertyGettersRule.java
deleted file mode 100644
index 716f863..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/GetlessMethodsAsPropertyGettersRule.java
+++ /dev/null
@@ -1,67 +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.model.impl;
-
-import java.beans.IntrospectionException;
-import java.beans.PropertyDescriptor;
-import java.lang.reflect.Method;
-
-class GetlessMethodsAsPropertyGettersRule implements MethodAppearanceFineTuner, SingletonCustomizer {
-    
-    static final GetlessMethodsAsPropertyGettersRule INSTANCE = new GetlessMethodsAsPropertyGettersRule();
-    
-    // Can't be constructed from outside
-    private GetlessMethodsAsPropertyGettersRule() { }
-
-    @Override
-    public void process(
-            DecisionInput in, Decision out) {
-        legacyProcess(in.getContainingClass(), in.getMethod(), out);
-    }
-
-    /** This only exists as the tests need to call this through the deprecated method too. */
-    public void legacyProcess(
-            Class clazz, Method m, Decision decision) {
-        if (m.getDeclaringClass() != Object.class
-                && m.getReturnType() != void.class
-                && m.getParameterTypes().length == 0) {
-            String mName = m.getName();
-            if (!looksLikePropertyReadMethod(mName)) {
-                decision.setExposeMethodAs(null);
-                try {
-                    decision.setExposeAsProperty(new PropertyDescriptor(
-                            mName, clazz, mName, null));
-                } catch (IntrospectionException e) {  // Won't happen...
-                    throw new RuntimeException(e); 
-                }
-            }
-        }
-    }
-    
-    private static boolean looksLikePropertyReadMethod(String name) {
-        final int verbEnd;
-        if (name.startsWith("get")) verbEnd = 3;
-        else if (name.startsWith("is")) verbEnd = 2;
-        else return false;
-        
-        return name.length() == verbEnd || Character.isUpperCase(name.charAt(verbEnd));
-    }
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/IsApplicableTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/IsApplicableTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/IsApplicableTest.java
deleted file mode 100644
index 599e6f2..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/IsApplicableTest.java
+++ /dev/null
@@ -1,171 +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.model.impl;
-
-import java.io.Serializable;
-import java.lang.reflect.Method;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.ArrayList;
-import java.util.List;
-
-import junit.framework.TestCase;
-
-@SuppressWarnings("boxing")
-public class IsApplicableTest extends TestCase {
-
-    public IsApplicableTest(String name) {
-        super(name);
-    }
-    
-    public void testSingle() {
-        ArgumentTypes ats = new ArgumentTypes(new Object[] { new Object() });
-        assertApplicable(ats, Object.class);
-        assertNotApplicable(ats, String.class);
-        assertNotApplicable(ats, CharSequence.class);
-        assertNotApplicable(ats, Integer.class);
-        assertNotApplicable(ats, Integer.TYPE);
-        
-        ats = new ArgumentTypes(new Object[] { "" });
-        assertApplicable(ats, Object.class);
-        assertApplicable(ats, CharSequence.class);
-        assertApplicable(ats, String.class);
-        assertNotApplicable(ats, Integer.class);
-        assertNotApplicable(ats, Integer.TYPE);
-
-        ats = new ArgumentTypes(new Object[] { 1 });
-        assertApplicable(ats, Object.class);
-        assertNotApplicable(ats, CharSequence.class);
-        assertNotApplicable(ats, String.class);
-        assertNotApplicable(ats, Short.class);
-        assertNotApplicable(ats, Short.TYPE);
-        assertApplicable(ats, Integer.class);
-        assertApplicable(ats, Integer.TYPE);
-        assertApplicable(ats, Float.class);
-        assertApplicable(ats, Float.TYPE);
-        assertApplicable(ats, Double.class);
-        assertApplicable(ats, Double.TYPE);
-        assertApplicable(ats, BigDecimal.class);
-        assertApplicable(ats, BigInteger.class);
-
-        ats = new ArgumentTypes(new Object[] { new OverloadedNumberUtil.IntegerOrByte(1, (byte) 1) });
-        assertApplicable(ats, Object.class);
-        assertNotApplicable(ats, CharSequence.class);
-        assertNotApplicable(ats, String.class);
-        assertApplicable(ats, Short.class);
-        assertApplicable(ats, Short.TYPE);
-        assertApplicable(ats, Integer.class);
-        assertApplicable(ats, Integer.TYPE);
-        assertApplicable(ats, Float.class);
-        assertApplicable(ats, Float.TYPE);
-        assertApplicable(ats, Double.class);
-        assertApplicable(ats, Double.TYPE);
-        assertApplicable(ats, BigDecimal.class);
-        assertApplicable(ats, BigInteger.class);
-        
-        ats = new ArgumentTypes(new Object[] { 1.0f });
-        assertApplicable(ats, Object.class);
-        assertNotApplicable(ats, CharSequence.class);
-        assertNotApplicable(ats, String.class);
-        assertNotApplicable(ats, Integer.class);
-        assertNotApplicable(ats, Integer.TYPE);
-        assertApplicable(ats, Float.class);
-        assertApplicable(ats, Float.TYPE);
-        assertApplicable(ats, Double.class);
-        assertApplicable(ats, Double.TYPE);
-        assertApplicable(ats, BigDecimal.class);
-        assertNotApplicable(ats, BigInteger.class);
-        
-        ats = new ArgumentTypes(new Object[] { null });
-        assertApplicable(ats, Object.class);
-        assertApplicable(ats, String.class);
-        assertApplicable(ats, Integer.class);
-        assertNotApplicable(ats, Integer.TYPE);
-        assertNotApplicable(ats, Boolean.TYPE);
-        assertNotApplicable(ats, Object.class, Object.class);
-        assertNotApplicable(ats);
-    }
-    
-    public void testMulti() {
-        ArgumentTypes ats = new ArgumentTypes(new Object[] { new Object(), "", 1, true });
-        assertApplicable(ats, Object.class, Object.class, Object.class, Object.class);
-        assertApplicable(ats, Object.class, String.class, Number.class, Boolean.class);
-        assertApplicable(ats, Object.class, CharSequence.class, Integer.class, Serializable.class);
-        assertApplicable(ats, Object.class, Comparable.class, Integer.TYPE, Serializable.class);
-        assertNotApplicable(ats, Object.class, String.class, Number.class, Number.class);
-        assertNotApplicable(ats, Object.class, StringBuilder.class, Number.class, Boolean.class);
-        assertNotApplicable(ats, int.class, Object.class, Object.class, Object.class);
-        assertNotApplicable(ats, Object.class, Object.class, Object.class);
-        assertNotApplicable(ats, Object.class, Object.class, Object.class, Object.class, Object.class);
-    }    
-
-    public void testNoParam() {
-        ArgumentTypes ats = new ArgumentTypes(new Object[] { });
-        assertApplicable(ats);
-        assertNotApplicable(ats, Object.class);
-    }
-
-    public void testVarags() {
-        Object[][] argLists = new Object[][] {
-            new Object[] { "", 1, 2, 3 },
-            new Object[] { "", 1, (byte) 2, 3 },
-            new Object[] { "", 1},
-            new Object[] { "" },
-        };
-        for (Object[] args : argLists) {
-            ArgumentTypes ats = new ArgumentTypes(args);
-            assertApplicable(ats, true, String.class, int[].class);
-            assertApplicable(ats, true, String.class, Integer[].class);
-            assertApplicable(ats, true, Object.class, Comparable[].class);
-            assertApplicable(ats, true, Object.class, Object[].class);
-            assertNotApplicable(ats, true, StringBuilder.class, int[].class);
-            if (args.length > 1) {
-                assertNotApplicable(ats, true, String.class, String[].class);
-            } else {
-                assertApplicable(ats, true, String.class, String[].class);
-            }
-        }
-    }
-    
-    private void assertNotApplicable(ArgumentTypes ats, Class... paramTypes) {
-        assertNotApplicable(ats, false, paramTypes);
-    }
-    
-    private void assertNotApplicable(ArgumentTypes ats, boolean varargs, Class... paramTypes) {
-        List tested = new ArrayList();
-        tested.add(new ReflectionCallableMemberDescriptor((Method) null, paramTypes));
-        if (ats.getApplicables(tested, varargs).size() != 0) {
-            fail("Parameter types were applicable");
-        }
-    }
-
-    private void assertApplicable(ArgumentTypes ats, Class<?>... paramTypes) {
-        assertApplicable(ats, false, paramTypes);
-    }
-    
-    private void assertApplicable(ArgumentTypes ats, boolean varargs, Class<?>... paramTypes) {
-        List tested = new ArrayList();
-        tested.add(new ReflectionCallableMemberDescriptor((Method) null, paramTypes));
-        if (ats.getApplicables(tested, varargs).size() != 1) {
-            fail("Parameter types weren't applicable");
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/IsMoreSpecificParameterTypeTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/IsMoreSpecificParameterTypeTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/IsMoreSpecificParameterTypeTest.java
deleted file mode 100644
index 3de3f13..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/IsMoreSpecificParameterTypeTest.java
+++ /dev/null
@@ -1,98 +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.model.impl;
-
-import java.math.BigDecimal;
-import java.util.HashMap;
-import java.util.Map;
-
-import junit.framework.TestCase;
-
-public class IsMoreSpecificParameterTypeTest extends TestCase {
-
-    public IsMoreSpecificParameterTypeTest(String name) {
-        super(name);
-    }
-    
-    public void testFixed() {
-        assertEquals(1, _MethodUtil.isMoreOrSameSpecificParameterType(String.class, String.class, true, 0));
-        assertEquals(1, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, int.class, true, 0));
-        
-        assertEquals(2, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, Integer.class, true, 0));
-        assertEquals(2, _MethodUtil.isMoreOrSameSpecificParameterType(boolean.class, Boolean.class, true, 0));
-        
-        assertEquals(3, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, long.class, true, 0));
-        assertEquals(3, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, double.class, true, 0));
-        assertEquals(3, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, Long.class, true, 0));
-        assertEquals(3, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, Double.class, true, 0));
-        assertEquals(3, _MethodUtil.isMoreOrSameSpecificParameterType(Integer.class, Long.class, true, 0));
-        assertEquals(3, _MethodUtil.isMoreOrSameSpecificParameterType(Integer.class, Double.class, true, 0));
-
-        assertEquals(4, _MethodUtil.isMoreOrSameSpecificParameterType(HashMap.class, Map.class, true, 0));
-        assertEquals(4, _MethodUtil.isMoreOrSameSpecificParameterType(String.class, CharSequence.class, true, 0));
-        assertEquals(4, _MethodUtil.isMoreOrSameSpecificParameterType(Integer.class, Number.class, true, 0));
-        assertEquals(4, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, Number.class, true, 0));
-        
-        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(Map.class, String.class, true, 0));
-        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(Integer.class, int.class, true, 0));
-        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(Boolean.class, boolean.class, true, 0));
-        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, boolean.class, true, 0));
-        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, Boolean.class, true, 0));
-        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, String.class, true, 0));
-        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, BigDecimal.class, true, 0));
-        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(Long.class, Integer.class, true, 0));
-        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(long.class, Integer.class, true, 0));
-        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(Long.class, int.class, true, 0));
-        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(Integer.class, BigDecimal.class, true, 0));
-    }
-    
-    public void testBuggy() {
-        assertEquals(1, _MethodUtil.isMoreOrSameSpecificParameterType(String.class, String.class, false, 0));
-        assertEquals(1, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, int.class, false, 0));
-        
-        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, Integer.class, false, 0));
-        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(boolean.class, Boolean.class, false, 0));
-        
-        assertEquals(3, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, long.class, false, 0));
-        assertEquals(3, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, double.class, false, 0));
-        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, Long.class, false, 0));
-        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, Double.class, false, 0));
-        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(Integer.class, Long.class, false, 0));
-        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(Integer.class, Double.class, false, 0));
-
-        assertEquals(4, _MethodUtil.isMoreOrSameSpecificParameterType(HashMap.class, Map.class, false, 0));
-        assertEquals(4, _MethodUtil.isMoreOrSameSpecificParameterType(String.class, CharSequence.class, false, 0));
-        assertEquals(4, _MethodUtil.isMoreOrSameSpecificParameterType(Integer.class, Number.class, false, 0));
-        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, Number.class, false, 0));
-        
-        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(Map.class, String.class, true, 0));
-        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(Integer.class, int.class, true, 0));
-        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(Boolean.class, boolean.class, true, 0));
-        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, boolean.class, true, 0));
-        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, Boolean.class, true, 0));
-        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, String.class, true, 0));
-        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(int.class, BigDecimal.class, true, 0));
-        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(Long.class, Integer.class, true, 0));
-        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(long.class, Integer.class, true, 0));
-        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(Long.class, int.class, true, 0));
-        assertEquals(0, _MethodUtil.isMoreOrSameSpecificParameterType(Integer.class, BigDecimal.class, true, 0));
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/Java7MembersOnlyDefaultObjectWrapper.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/Java7MembersOnlyDefaultObjectWrapper.java b/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/Java7MembersOnlyDefaultObjectWrapper.java
deleted file mode 100644
index 96c1adf..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/Java7MembersOnlyDefaultObjectWrapper.java
+++ /dev/null
@@ -1,101 +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.model.impl;
-
-import java.lang.reflect.Method;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.freemarker.core.Configuration;
-import org.apache.freemarker.core.Version;
-
-/**
- * A hack to keep some unit tests producing exactly the same results on Java 8 as on Java 5-7, by hiding members
- * added after Java 7.
- */
-public class Java7MembersOnlyDefaultObjectWrapper extends DefaultObjectWrapper {
-    
-    private static final Set<String> POST_JAVA_7_MAP_METHODS = newHashSet(
-            "compute", "computeIfAbsent", "computeIfPresent",
-            "forEach", "getOrDefault", "merge", "putIfAbsent", "replace", "replaceAll");
-
-    private static final Set<String> POST_JAVA_7_ITERABLE_METHODS = newHashSet("forEach");
-    private static final Set<String> POST_JAVA_7_COLLECTION_METHODS = newHashSet("parallelStream", "removeIf", "stream");
-    private static final Set<String> POST_JAVA_7_LIST_METHODS = newHashSet("sort", "spliterator");
-    
-    static final MethodAppearanceFineTuner POST_JAVA_7_FILTER = new MethodAppearanceFineTuner() {
-
-        @Override
-        public void process(DecisionInput in, Decision out) {
-            Method m = in.getMethod();
-            Class declCl = m.getDeclaringClass();
-            if (Map.class.isAssignableFrom(declCl)) {
-                if (POST_JAVA_7_MAP_METHODS.contains(m.getName())) {
-                    hideMember(out);
-                    return;
-                }
-            }
-            if (Iterable.class.isAssignableFrom(declCl)) {
-                if (POST_JAVA_7_ITERABLE_METHODS.contains(m.getName())) {
-                    hideMember(out);
-                    return;
-                }
-            }
-            if (Collection.class.isAssignableFrom(declCl)) {
-                if (POST_JAVA_7_COLLECTION_METHODS.contains(m.getName())) {
-                    hideMember(out);
-                    return;
-                }
-            }
-            if (List.class.isAssignableFrom(declCl)) {
-                if (POST_JAVA_7_LIST_METHODS.contains(m.getName())) {
-                    hideMember(out);
-                    return;
-                }
-            }
-        }
-
-        private void hideMember(Decision out) {
-            out.setExposeMethodAs(null);
-            out.setExposeAsProperty(null);
-        }
-        
-    };
-    
-    public Java7MembersOnlyDefaultObjectWrapper(Version version) {
-        super(new DefaultObjectWrapper.Builder(version).methodAppearanceFineTuner(POST_JAVA_7_FILTER), true);
-    }
-
-    private static <T> Set<T> newHashSet(T... items) {
-        HashSet<T> r = new HashSet<>();
-        for (T item : items) {
-            r.add(item);
-        }
-        return r;
-    }
-
-    public Java7MembersOnlyDefaultObjectWrapper() {
-        this(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/ManyObjectsOfDifferentClasses.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/ManyObjectsOfDifferentClasses.java b/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/ManyObjectsOfDifferentClasses.java
deleted file mode 100644
index fa7ce29..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/ManyObjectsOfDifferentClasses.java
+++ /dev/null
@@ -1,249 +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.model.impl;
-
-// FMPP template source:
-// ----
-// package org.apache.freemarker.core.model.impl;
-// 
-// // FMPP template source:
-// // ----
-// <#assign src><#include "ManyObjectsOfDifferentClasses.java.ftl" parse=false></#assign>
-// ${src?trim?replace('(.*\r?\n)|.+', r'// $0', 'r')}
-// // ----
-// 
-// <#assign MAX_CLA = 8 - 1>
-// <#assign MAX_MET = 10 - 1>
-// <#assign MAX_PRO = 10 - 1>
-// 
-// public class ManyObjectsOfDifferentClasses {
-// 
-//     public static final Object[] OBJECTS = new Object[] {
-//         <#list 0..MAX_CLA as claI>
-//         new C${claI}(),
-//         </#list>
-//     };
-// 
-//     <#list 0..MAX_CLA as claI>
-//     static public class C${claI} {
-//         <#list 0..MAX_PRO as proI>
-//         public int getP${proI}() { return ${claI} * 1000 + ${proI}; }
-//         </#list>
-//         <#list 0..MAX_MET as metI>
-//         public int m${metI}() { return ${claI} * 1000 + ${metI}; };
-//         </#list>
-//     }
-//     </#list>
-//     
-// }
-// ----
-
-
-public class ManyObjectsOfDifferentClasses {
-
-    public static final Object[] OBJECTS = new Object[] {
-        new C0(),
-        new C1(),
-        new C2(),
-        new C3(),
-        new C4(),
-        new C5(),
-        new C6(),
-        new C7(),
-    };
-
-    static public class C0 {
-        public int getP0() { return 0 * 1000 + 0; }
-        public int getP1() { return 0 * 1000 + 1; }
-        public int getP2() { return 0 * 1000 + 2; }
-        public int getP3() { return 0 * 1000 + 3; }
-        public int getP4() { return 0 * 1000 + 4; }
-        public int getP5() { return 0 * 1000 + 5; }
-        public int getP6() { return 0 * 1000 + 6; }
-        public int getP7() { return 0 * 1000 + 7; }
-        public int getP8() { return 0 * 1000 + 8; }
-        public int getP9() { return 0 * 1000 + 9; }
-        public int m0() { return 0 * 1000 + 0; };
-        public int m1() { return 0 * 1000 + 1; };
-        public int m2() { return 0 * 1000 + 2; };
-        public int m3() { return 0 * 1000 + 3; };
-        public int m4() { return 0 * 1000 + 4; };
-        public int m5() { return 0 * 1000 + 5; };
-        public int m6() { return 0 * 1000 + 6; };
-        public int m7() { return 0 * 1000 + 7; };
-        public int m8() { return 0 * 1000 + 8; };
-        public int m9() { return 0 * 1000 + 9; };
-    }
-    static public class C1 {
-        public int getP0() { return 1 * 1000 + 0; }
-        public int getP1() { return 1 * 1000 + 1; }
-        public int getP2() { return 1 * 1000 + 2; }
-        public int getP3() { return 1 * 1000 + 3; }
-        public int getP4() { return 1 * 1000 + 4; }
-        public int getP5() { return 1 * 1000 + 5; }
-        public int getP6() { return 1 * 1000 + 6; }
-        public int getP7() { return 1 * 1000 + 7; }
-        public int getP8() { return 1 * 1000 + 8; }
-        public int getP9() { return 1 * 1000 + 9; }
-        public int m0() { return 1 * 1000 + 0; };
-        public int m1() { return 1 * 1000 + 1; };
-        public int m2() { return 1 * 1000 + 2; };
-        public int m3() { return 1 * 1000 + 3; };
-        public int m4() { return 1 * 1000 + 4; };
-        public int m5() { return 1 * 1000 + 5; };
-        public int m6() { return 1 * 1000 + 6; };
-        public int m7() { return 1 * 1000 + 7; };
-        public int m8() { return 1 * 1000 + 8; };
-        public int m9() { return 1 * 1000 + 9; };
-    }
-    static public class C2 {
-        public int getP0() { return 2 * 1000 + 0; }
-        public int getP1() { return 2 * 1000 + 1; }
-        public int getP2() { return 2 * 1000 + 2; }
-        public int getP3() { return 2 * 1000 + 3; }
-        public int getP4() { return 2 * 1000 + 4; }
-        public int getP5() { return 2 * 1000 + 5; }
-        public int getP6() { return 2 * 1000 + 6; }
-        public int getP7() { return 2 * 1000 + 7; }
-        public int getP8() { return 2 * 1000 + 8; }
-        public int getP9() { return 2 * 1000 + 9; }
-        public int m0() { return 2 * 1000 + 0; };
-        public int m1() { return 2 * 1000 + 1; };
-        public int m2() { return 2 * 1000 + 2; };
-        public int m3() { return 2 * 1000 + 3; };
-        public int m4() { return 2 * 1000 + 4; };
-        public int m5() { return 2 * 1000 + 5; };
-        public int m6() { return 2 * 1000 + 6; };
-        public int m7() { return 2 * 1000 + 7; };
-        public int m8() { return 2 * 1000 + 8; };
-        public int m9() { return 2 * 1000 + 9; };
-    }
-    static public class C3 {
-        public int getP0() { return 3 * 1000 + 0; }
-        public int getP1() { return 3 * 1000 + 1; }
-        public int getP2() { return 3 * 1000 + 2; }
-        public int getP3() { return 3 * 1000 + 3; }
-        public int getP4() { return 3 * 1000 + 4; }
-        public int getP5() { return 3 * 1000 + 5; }
-        public int getP6() { return 3 * 1000 + 6; }
-        public int getP7() { return 3 * 1000 + 7; }
-        public int getP8() { return 3 * 1000 + 8; }
-        public int getP9() { return 3 * 1000 + 9; }
-        public int m0() { return 3 * 1000 + 0; };
-        public int m1() { return 3 * 1000 + 1; };
-        public int m2() { return 3 * 1000 + 2; };
-        public int m3() { return 3 * 1000 + 3; };
-        public int m4() { return 3 * 1000 + 4; };
-        public int m5() { return 3 * 1000 + 5; };
-        public int m6() { return 3 * 1000 + 6; };
-        public int m7() { return 3 * 1000 + 7; };
-        public int m8() { return 3 * 1000 + 8; };
-        public int m9() { return 3 * 1000 + 9; };
-    }
-    static public class C4 {
-        public int getP0() { return 4 * 1000 + 0; }
-        public int getP1() { return 4 * 1000 + 1; }
-        public int getP2() { return 4 * 1000 + 2; }
-        public int getP3() { return 4 * 1000 + 3; }
-        public int getP4() { return 4 * 1000 + 4; }
-        public int getP5() { return 4 * 1000 + 5; }
-        public int getP6() { return 4 * 1000 + 6; }
-        public int getP7() { return 4 * 1000 + 7; }
-        public int getP8() { return 4 * 1000 + 8; }
-        public int getP9() { return 4 * 1000 + 9; }
-        public int m0() { return 4 * 1000 + 0; };
-        public int m1() { return 4 * 1000 + 1; };
-        public int m2() { return 4 * 1000 + 2; };
-        public int m3() { return 4 * 1000 + 3; };
-        public int m4() { return 4 * 1000 + 4; };
-        public int m5() { return 4 * 1000 + 5; };
-        public int m6() { return 4 * 1000 + 6; };
-        public int m7() { return 4 * 1000 + 7; };
-        public int m8() { return 4 * 1000 + 8; };
-        public int m9() { return 4 * 1000 + 9; };
-    }
-    static public class C5 {
-        public int getP0() { return 5 * 1000 + 0; }
-        public int getP1() { return 5 * 1000 + 1; }
-        public int getP2() { return 5 * 1000 + 2; }
-        public int getP3() { return 5 * 1000 + 3; }
-        public int getP4() { return 5 * 1000 + 4; }
-        public int getP5() { return 5 * 1000 + 5; }
-        public int getP6() { return 5 * 1000 + 6; }
-        public int getP7() { return 5 * 1000 + 7; }
-        public int getP8() { return 5 * 1000 + 8; }
-        public int getP9() { return 5 * 1000 + 9; }
-        public int m0() { return 5 * 1000 + 0; };
-        public int m1() { return 5 * 1000 + 1; };
-        public int m2() { return 5 * 1000 + 2; };
-        public int m3() { return 5 * 1000 + 3; };
-        public int m4() { return 5 * 1000 + 4; };
-        public int m5() { return 5 * 1000 + 5; };
-        public int m6() { return 5 * 1000 + 6; };
-        public int m7() { return 5 * 1000 + 7; };
-        public int m8() { return 5 * 1000 + 8; };
-        public int m9() { return 5 * 1000 + 9; };
-    }
-    static public class C6 {
-        public int getP0() { return 6 * 1000 + 0; }
-        public int getP1() { return 6 * 1000 + 1; }
-        public int getP2() { return 6 * 1000 + 2; }
-        public int getP3() { return 6 * 1000 + 3; }
-        public int getP4() { return 6 * 1000 + 4; }
-        public int getP5() { return 6 * 1000 + 5; }
-        public int getP6() { return 6 * 1000 + 6; }
-        public int getP7() { return 6 * 1000 + 7; }
-        public int getP8() { return 6 * 1000 + 8; }
-        public int getP9() { return 6 * 1000 + 9; }
-        public int m0() { return 6 * 1000 + 0; };
-        public int m1() { return 6 * 1000 + 1; };
-        public int m2() { return 6 * 1000 + 2; };
-        public int m3() { return 6 * 1000 + 3; };
-        public int m4() { return 6 * 1000 + 4; };
-        public int m5() { return 6 * 1000 + 5; };
-        public int m6() { return 6 * 1000 + 6; };
-        public int m7() { return 6 * 1000 + 7; };
-        public int m8() { return 6 * 1000 + 8; };
-        public int m9() { return 6 * 1000 + 9; };
-    }
-    static public class C7 {
-        public int getP0() { return 7 * 1000 + 0; }
-        public int getP1() { return 7 * 1000 + 1; }
-        public int getP2() { return 7 * 1000 + 2; }
-        public int getP3() { return 7 * 1000 + 3; }
-        public int getP4() { return 7 * 1000 + 4; }
-        public int getP5() { return 7 * 1000 + 5; }
-        public int getP6() { return 7 * 1000 + 6; }
-        public int getP7() { return 7 * 1000 + 7; }
-        public int getP8() { return 7 * 1000 + 8; }
-        public int getP9() { return 7 * 1000 + 9; }
-        public int m0() { return 7 * 1000 + 0; };
-        public int m1() { return 7 * 1000 + 1; };
-        public int m2() { return 7 * 1000 + 2; };
-        public int m3() { return 7 * 1000 + 3; };
-        public int m4() { return 7 * 1000 + 4; };
-        public int m5() { return 7 * 1000 + 5; };
-        public int m6() { return 7 * 1000 + 6; };
-        public int m7() { return 7 * 1000 + 7; };
-        public int m8() { return 7 * 1000 + 8; };
-        public int m9() { return 7 * 1000 + 9; };
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/ManyStaticsOfDifferentClasses.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/ManyStaticsOfDifferentClasses.java b/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/ManyStaticsOfDifferentClasses.java
deleted file mode 100644
index dd73bee..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/ManyStaticsOfDifferentClasses.java
+++ /dev/null
@@ -1,236 +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.model.impl;
-
-// FMPP template source:
-// ----
-// package org.apache.freemarker.core.model.impl;
-// 
-// // FMPP template source:
-// // ----
-// <#assign src><#include "ManyStaticsOfDifferentClasses.java.ftl" parse=false></#assign>
-// ${src?trim?replace('(.*\r?\n)|.+', r'// $0', 'r')}
-// // ----
-// 
-// <#assign MAX_CLA = 8 - 1>
-// <#assign MAX_MET = 10 - 1>
-// <#assign MAX_PRO = 10 - 1>
-// 
-// public class ManyStaticsOfDifferentClasses {
-// 
-//     private ManyStaticsOfDifferentClasses() { }
-// 
-//     <#list 0..MAX_CLA as claI>
-//     static public class C${claI} {
-//         <#list 0..MAX_PRO as proI>
-//         public static int p${proI} = ${claI} * 1000 + ${proI};
-//         </#list>
-//         <#list 0..MAX_MET as metI>
-//         public static int m${metI}() { return ${claI} * 1000 + ${metI}; };
-//         </#list>
-//     }
-//     </#list>
-//     
-// }
-// ----
-
-
-public class ManyStaticsOfDifferentClasses {
-
-    private ManyStaticsOfDifferentClasses() { }
-
-    static public class C0 {
-        public static int p0 = 0 * 1000 + 0;
-        public static int p1 = 0 * 1000 + 1;
-        public static int p2 = 0 * 1000 + 2;
-        public static int p3 = 0 * 1000 + 3;
-        public static int p4 = 0 * 1000 + 4;
-        public static int p5 = 0 * 1000 + 5;
-        public static int p6 = 0 * 1000 + 6;
-        public static int p7 = 0 * 1000 + 7;
-        public static int p8 = 0 * 1000 + 8;
-        public static int p9 = 0 * 1000 + 9;
-        public static int m0() { return 0 * 1000 + 0; };
-        public static int m1() { return 0 * 1000 + 1; };
-        public static int m2() { return 0 * 1000 + 2; };
-        public static int m3() { return 0 * 1000 + 3; };
-        public static int m4() { return 0 * 1000 + 4; };
-        public static int m5() { return 0 * 1000 + 5; };
-        public static int m6() { return 0 * 1000 + 6; };
-        public static int m7() { return 0 * 1000 + 7; };
-        public static int m8() { return 0 * 1000 + 8; };
-        public static int m9() { return 0 * 1000 + 9; };
-    }
-    static public class C1 {
-        public static int p0 = 1 * 1000 + 0;
-        public static int p1 = 1 * 1000 + 1;
-        public static int p2 = 1 * 1000 + 2;
-        public static int p3 = 1 * 1000 + 3;
-        public static int p4 = 1 * 1000 + 4;
-        public static int p5 = 1 * 1000 + 5;
-        public static int p6 = 1 * 1000 + 6;
-        public static int p7 = 1 * 1000 + 7;
-        public static int p8 = 1 * 1000 + 8;
-        public static int p9 = 1 * 1000 + 9;
-        public static int m0() { return 1 * 1000 + 0; };
-        public static int m1() { return 1 * 1000 + 1; };
-        public static int m2() { return 1 * 1000 + 2; };
-        public static int m3() { return 1 * 1000 + 3; };
-        public static int m4() { return 1 * 1000 + 4; };
-        public static int m5() { return 1 * 1000 + 5; };
-        public static int m6() { return 1 * 1000 + 6; };
-        public static int m7() { return 1 * 1000 + 7; };
-        public static int m8() { return 1 * 1000 + 8; };
-        public static int m9() { return 1 * 1000 + 9; };
-    }
-    static public class C2 {
-        public static int p0 = 2 * 1000 + 0;
-        public static int p1 = 2 * 1000 + 1;
-        public static int p2 = 2 * 1000 + 2;
-        public static int p3 = 2 * 1000 + 3;
-        public static int p4 = 2 * 1000 + 4;
-        public static int p5 = 2 * 1000 + 5;
-        public static int p6 = 2 * 1000 + 6;
-        public static int p7 = 2 * 1000 + 7;
-        public static int p8 = 2 * 1000 + 8;
-        public static int p9 = 2 * 1000 + 9;
-        public static int m0() { return 2 * 1000 + 0; };
-        public static int m1() { return 2 * 1000 + 1; };
-        public static int m2() { return 2 * 1000 + 2; };
-        public static int m3() { return 2 * 1000 + 3; };
-        public static int m4() { return 2 * 1000 + 4; };
-        public static int m5() { return 2 * 1000 + 5; };
-        public static int m6() { return 2 * 1000 + 6; };
-        public static int m7() { return 2 * 1000 + 7; };
-        public static int m8() { return 2 * 1000 + 8; };
-        public static int m9() { return 2 * 1000 + 9; };
-    }
-    static public class C3 {
-        public static int p0 = 3 * 1000 + 0;
-        public static int p1 = 3 * 1000 + 1;
-        public static int p2 = 3 * 1000 + 2;
-        public static int p3 = 3 * 1000 + 3;
-        public static int p4 = 3 * 1000 + 4;
-        public static int p5 = 3 * 1000 + 5;
-        public static int p6 = 3 * 1000 + 6;
-        public static int p7 = 3 * 1000 + 7;
-        public static int p8 = 3 * 1000 + 8;
-        public static int p9 = 3 * 1000 + 9;
-        public static int m0() { return 3 * 1000 + 0; };
-        public static int m1() { return 3 * 1000 + 1; };
-        public static int m2() { return 3 * 1000 + 2; };
-        public static int m3() { return 3 * 1000 + 3; };
-        public static int m4() { return 3 * 1000 + 4; };
-        public static int m5() { return 3 * 1000 + 5; };
-        public static int m6() { return 3 * 1000 + 6; };
-        public static int m7() { return 3 * 1000 + 7; };
-        public static int m8() { return 3 * 1000 + 8; };
-        public static int m9() { return 3 * 1000 + 9; };
-    }
-    static public class C4 {
-        public static int p0 = 4 * 1000 + 0;
-        public static int p1 = 4 * 1000 + 1;
-        public static int p2 = 4 * 1000 + 2;
-        public static int p3 = 4 * 1000 + 3;
-        public static int p4 = 4 * 1000 + 4;
-        public static int p5 = 4 * 1000 + 5;
-        public static int p6 = 4 * 1000 + 6;
-        public static int p7 = 4 * 1000 + 7;
-        public static int p8 = 4 * 1000 + 8;
-        public static int p9 = 4 * 1000 + 9;
-        public static int m0() { return 4 * 1000 + 0; };
-        public static int m1() { return 4 * 1000 + 1; };
-        public static int m2() { return 4 * 1000 + 2; };
-        public static int m3() { return 4 * 1000 + 3; };
-        public static int m4() { return 4 * 1000 + 4; };
-        public static int m5() { return 4 * 1000 + 5; };
-        public static int m6() { return 4 * 1000 + 6; };
-        public static int m7() { return 4 * 1000 + 7; };
-        public static int m8() { return 4 * 1000 + 8; };
-        public static int m9() { return 4 * 1000 + 9; };
-    }
-    static public class C5 {
-        public static int p0 = 5 * 1000 + 0;
-        public static int p1 = 5 * 1000 + 1;
-        public static int p2 = 5 * 1000 + 2;
-        public static int p3 = 5 * 1000 + 3;
-        public static int p4 = 5 * 1000 + 4;
-        public static int p5 = 5 * 1000 + 5;
-        public static int p6 = 5 * 1000 + 6;
-        public static int p7 = 5 * 1000 + 7;
-        public static int p8 = 5 * 1000 + 8;
-        public static int p9 = 5 * 1000 + 9;
-        public static int m0() { return 5 * 1000 + 0; };
-        public static int m1() { return 5 * 1000 + 1; };
-        public static int m2() { return 5 * 1000 + 2; };
-        public static int m3() { return 5 * 1000 + 3; };
-        public static int m4() { return 5 * 1000 + 4; };
-        public static int m5() { return 5 * 1000 + 5; };
-        public static int m6() { return 5 * 1000 + 6; };
-        public static int m7() { return 5 * 1000 + 7; };
-        public static int m8() { return 5 * 1000 + 8; };
-        public static int m9() { return 5 * 1000 + 9; };
-    }
-    static public class C6 {
-        public static int p0 = 6 * 1000 + 0;
-        public static int p1 = 6 * 1000 + 1;
-        public static int p2 = 6 * 1000 + 2;
-        public static int p3 = 6 * 1000 + 3;
-        public static int p4 = 6 * 1000 + 4;
-        public static int p5 = 6 * 1000 + 5;
-        public static int p6 = 6 * 1000 + 6;
-        public static int p7 = 6 * 1000 + 7;
-        public static int p8 = 6 * 1000 + 8;
-        public static int p9 = 6 * 1000 + 9;
-        public static int m0() { return 6 * 1000 + 0; };
-        public static int m1() { return 6 * 1000 + 1; };
-        public static int m2() { return 6 * 1000 + 2; };
-        public static int m3() { return 6 * 1000 + 3; };
-        public static int m4() { return 6 * 1000 + 4; };
-        public static int m5() { return 6 * 1000 + 5; };
-        public static int m6() { return 6 * 1000 + 6; };
-        public static int m7() { return 6 * 1000 + 7; };
-        public static int m8() { return 6 * 1000 + 8; };
-        public static int m9() { return 6 * 1000 + 9; };
-    }
-    static public class C7 {
-        public static int p0 = 7 * 1000 + 0;
-        public static int p1 = 7 * 1000 + 1;
-        public static int p2 = 7 * 1000 + 2;
-        public static int p3 = 7 * 1000 + 3;
-        public static int p4 = 7 * 1000 + 4;
-        public static int p5 = 7 * 1000 + 5;
-        public static int p6 = 7 * 1000 + 6;
-        public static int p7 = 7 * 1000 + 7;
-        public static int p8 = 7 * 1000 + 8;
-        public static int p9 = 7 * 1000 + 9;
-        public static int m0() { return 7 * 1000 + 0; };
-        public static int m1() { return 7 * 1000 + 1; };
-        public static int m2() { return 7 * 1000 + 2; };
-        public static int m3() { return 7 * 1000 + 3; };
-        public static int m4() { return 7 * 1000 + 4; };
-        public static int m5() { return 7 * 1000 + 5; };
-        public static int m6() { return 7 * 1000 + 6; };
-        public static int m7() { return 7 * 1000 + 7; };
-        public static int m8() { return 7 * 1000 + 8; };
-        public static int m9() { return 7 * 1000 + 9; };
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/MiscNumericalOperationsTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/MiscNumericalOperationsTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/MiscNumericalOperationsTest.java
deleted file mode 100644
index 9e175e5..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/MiscNumericalOperationsTest.java
+++ /dev/null
@@ -1,111 +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.model.impl;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-
-import org.junit.Assert;
-
-import junit.framework.TestCase;
-
-public class MiscNumericalOperationsTest extends TestCase {
-
-    public MiscNumericalOperationsTest(String name) {
-        super(name);
-    }
-    
-    public void testForceUnwrappedNumberToType() {
-        // Usual type to to all other types:
-        Double n = Double.valueOf(123.75);
-        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, Short.class), Short.valueOf(n.shortValue()));
-        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, Short.TYPE), Short.valueOf(n.shortValue()));
-        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, Byte.class), Byte.valueOf(n.byteValue()));
-        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, Byte.TYPE), Byte.valueOf(n.byteValue()));
-        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, Integer.class), Integer.valueOf(n.intValue()));
-        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, Integer.TYPE), Integer.valueOf(n.intValue()));
-        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, Long.class), Long.valueOf(n.longValue()));
-        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, Long.TYPE), Long.valueOf(n.longValue()));
-        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, Float.class), Float.valueOf(n.floatValue()));
-        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, Float.TYPE), Float.valueOf(n.floatValue()));
-        assertTrue(DefaultObjectWrapper.forceUnwrappedNumberToType(n, Double.class) == n);
-        assertTrue(DefaultObjectWrapper.forceUnwrappedNumberToType(n, Double.TYPE) == n);
-        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, BigInteger.class), new BigInteger("123"));
-        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(n, BigDecimal.class), new BigDecimal("123.75"));
-        
-        // Cases of conversion to BigDecimal:
-        BigDecimal bd = new BigDecimal("123");
-        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(new BigInteger("123"), BigDecimal.class), bd);
-        assertTrue(DefaultObjectWrapper.forceUnwrappedNumberToType(bd, BigDecimal.class) == bd);
-        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(Long.valueOf(123), BigDecimal.class), bd);
-        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(Double.valueOf(123), BigDecimal.class), bd);
-        
-        // Cases of conversion to BigInteger:
-        BigInteger bi = new BigInteger("123");
-        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(new BigDecimal("123.6"), BigInteger.class), bi);
-        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(
-                new OverloadedNumberUtil.IntegerBigDecimal(new BigDecimal("123")), BigInteger.class), bi);
-        assertTrue(DefaultObjectWrapper.forceUnwrappedNumberToType(bi, BigInteger.class) == bi);
-        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(Long.valueOf(123), BigInteger.class), bi);
-        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(Double.valueOf(123.6), BigInteger.class), bi);
-
-        assertTrue(DefaultObjectWrapper.forceUnwrappedNumberToType(n, Number.class) == n);
-        assertNull(DefaultObjectWrapper.forceUnwrappedNumberToType(n, RationalNumber.class));
-        RationalNumber r = new RationalNumber(1, 2);
-        assertTrue(DefaultObjectWrapper.forceUnwrappedNumberToType(r, RationalNumber.class) == r);
-        assertTrue(DefaultObjectWrapper.forceUnwrappedNumberToType(r, Number.class) == r);
-        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(r, Double.class), Double.valueOf(0.5));
-        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(r, BigDecimal.class), new BigDecimal("0.5"));
-        assertEquals(DefaultObjectWrapper.forceUnwrappedNumberToType(r, BigInteger.class), BigInteger.ZERO);
-    }
-    
-    @SuppressWarnings("boxing")
-    public void testForceNumberArgumentsToParameterTypes() {
-        OverloadedMethodsSubset oms = new OverloadedFixArgsMethods();
-        Class[] paramTypes = new Class[] { Short.TYPE, Short.class, Double.TYPE, BigDecimal.class, BigInteger.class };
-        Object[] args;
-        
-        args = newArgs();
-        oms.forceNumberArgumentsToParameterTypes(args, paramTypes, new int[] { 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF });
-        Assert.assertArrayEquals(
-                args,
-                new Object[] { (short) 123, (short) 123, 123.75, new BigDecimal("123.75"), BigInteger.valueOf(123) });
-        
-        args = newArgs();
-        oms.forceNumberArgumentsToParameterTypes(args, paramTypes, new int[] { 0, 0, 0, 0, 0 });
-        Assert.assertArrayEquals(args, newArgs());
-        
-        args = newArgs();
-        oms.forceNumberArgumentsToParameterTypes(args, paramTypes, new int[] { 8, 8, 8, 8, 8 });
-        Assert.assertArrayEquals(args, newArgs());
-        
-        args = newArgs();
-        oms.forceNumberArgumentsToParameterTypes(args, paramTypes, new int[] { 0xFFFF, 0, 0xFFFF, 0, 0xFFFF });
-        Assert.assertArrayEquals(
-                args,
-                new Object[] { (short) 123, 123.75, 123.75, 123.75, BigInteger.valueOf(123) });
-    }
-
-    @SuppressWarnings("boxing")
-    private Object[] newArgs() {
-        return new Object[] { 123.75, 123.75, 123.75, 123.75, 123.75 };
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/ModelAPINewInstanceTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/ModelAPINewInstanceTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/ModelAPINewInstanceTest.java
deleted file mode 100644
index 0b0a614..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/ModelAPINewInstanceTest.java
+++ /dev/null
@@ -1,134 +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.model.impl;
-
-import org.apache.freemarker.core.Configuration;
-import org.apache.freemarker.test.TestUtil;
-
-import junit.framework.TestCase;
-
-public class ModelAPINewInstanceTest extends TestCase {
-
-    private DefaultObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
-
-    public ModelAPINewInstanceTest(String name) {
-        super(name);
-    }
-    
-    @SuppressWarnings("boxing")
-    public void test() throws Exception {
-        testClassConstructors("");
-        testClassConstructors("int... [1]", 1);
-        testClassConstructors("int 1, int 2", 1, 2);
-        testClassConstructors("int... [1, 2, 3]", 1, 2, 3);
-        testClassConstructors("int... [1, 2, 3]", 1, (byte) 2, (short) 3);
-        try {
-            testClassConstructors("int... [1, 2, 3]", 1, 2, (long) 3);
-            fail();
-        } catch (NoSuchMethodException e) {
-            // Expected
-        }
-        
-        testClassConstructors("int 1, int 2", (byte) 1, (short) 2);
-        testClassConstructors("double 1.0, double 2.0", (long) 1, (short) 2);
-        testClassConstructors("double 1.0, double 2.0", 1, 2f);
-        testClassConstructors("Integer null, Integer null", null, null);
-        testClassConstructors("Integer null, Integer 1", null, 1);
-        testClassConstructors("int 1, String s", 1, "s");
-        testClassConstructors("int 1, String null", 1, null);
-        testClassConstructors("Object null, Object s", null, "s");
-        testClassConstructors("Object 1.0, Object s", 1f, "s");
-        
-        testClassConstructors("Object s, int... [1, 2]", "s", 1, 2);
-        testClassConstructors("Object s, int... []", "s");
-        
-        testClassConstructors2("int 1, int 2", (byte) 1, (short) 2);
-        try {
-            testClassConstructors2("int 1, int 2", 1, 2L);
-            fail();
-        } catch (NoSuchMethodException e) {
-            // Expected
-        }
-        try {
-            testClassConstructors2("", "", "");
-            fail();
-        } catch (NoSuchMethodException e) {
-            // Expected
-        }
-        try {
-            testClassConstructors2("int 1", 1);
-            fail();
-        } catch (NoSuchMethodException e) {
-            // Expected
-        }
-        try {
-            testClassConstructors2("");
-            fail();
-        } catch (NoSuchMethodException e) {
-            // Expected
-        }
-    }
-    
-    private void testClassConstructors(String expected, Object... args) throws Exception {
-        testCall(expected, Constructors.class, args); 
-    }
-
-    private void testClassConstructors2(String expected, Object... args) throws Exception {
-        testCall(expected, Constructors2.class, args); 
-    }
-    
-    private void testCall(String expected, Class cl, Object... args) throws Exception {
-        Object obj = _ModelAPI.newInstance(cl, args, ow);
-        assertEquals(expected, obj.toString());        
-    }
-    
-    public static class Constructors {
-        private final String s;
-
-        public Constructors() { s = ""; }
-        
-        public Constructors(int x, int y) { s = "int " + x + ", int " + y; }
-        public Constructors(int x, String y) { s = "int " + x + ", String " + y; }
-        public Constructors(int x, long y) { s = "int " + x + ", long " + y; }
-        public Constructors(double x, double y) { s = "double " + x + ", double " + y; }
-        public Constructors(Integer x, Integer y) { s = "Integer " + x + ", Integer " + y; }
-        public Constructors(Object x, Object y) { s = "Object " + x + ", Object " + y; }
-
-        public Constructors(int... xs) { s = "int... " + TestUtil.arrayToString(xs); }
-        public Constructors(Object x, int... ys) { s = "Object " + x + ", int... " + TestUtil.arrayToString(ys); }
-        
-        @Override
-        public String toString() {
-            return s;
-        }
-    }
-
-    public static class Constructors2 {
-        private final String s;
-
-        public Constructors2(int x, int y) { s = "int " + x + ", int " + y; }
-        
-        @Override
-        public String toString() {
-            return s;
-        }
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/ModelCacheTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/ModelCacheTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/ModelCacheTest.java
deleted file mode 100644
index 2498859..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/ModelCacheTest.java
+++ /dev/null
@@ -1,71 +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.model.impl;
-
-import static org.junit.Assert.*;
-
-import org.apache.freemarker.core.Configuration;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class ModelCacheTest {
-    
-    @Test
-    public void modelCacheOff() throws Exception {
-        DefaultObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0).build();
-        assertFalse(ow.getUseModelCache());  // default is off
-        
-        String s = "foo";
-        assertNotSame(ow.wrap(s), ow.wrap(s));
-        
-        C c = new C();
-        assertNotSame(ow.wrap(c), ow.wrap(c));
-    }
-    
-    @Test
-    @Ignore // ModelCache is current removed in FM3
-    public void modelCacheOn() throws Exception {
-        DefaultObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0)
-                .useModelCache(true).build();
-        assertTrue(ow.getUseModelCache());
-
-        TestBean obj = new TestBean();
-        assertSame(ow.wrap(obj), ow.wrap(obj));
-        
-        C c = new C();
-        TemplateModel wrappedC = ow.wrap(c);
-        assertSame(wrappedC, ow.wrap(c));
-        
-        ow.clearClassIntrospecitonCache();
-        assertNotSame(wrappedC, ow.wrap(c));
-        assertSame(ow.wrap(c), ow.wrap(c));
-    }
-
-    static public class C { }
-
-    public static class TestBean {
-        //
-    }
-    
-}


[35/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/util/StringUtilTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/util/StringUtilTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/util/StringUtilTest.java
new file mode 100644
index 0000000..2a0ae9d
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/util/StringUtilTest.java
@@ -0,0 +1,403 @@
+/*
+ * 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.util;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.regex.Pattern;
+
+import org.hamcrest.Matchers;
+import org.junit.Test;
+
+public class StringUtilTest {
+
+    @Test
+    public void testV2319() {
+        assertEquals("\\n\\r\\f\\b\\t\\x00\\x19", _StringUtil.javaScriptStringEnc("\n\r\f\b\t\u0000\u0019"));
+    }
+
+    @Test
+    public void testControlChars() {
+        assertEsc(
+                "\n\r\f\b\t \u0000\u0019\u001F \u007F\u0080\u009F \u2028\u2029",
+                "\\n\\r\\f\\b\\t \\x00\\x19\\x1F \\x7F\\x80\\x9F \\u2028\\u2029",
+                "\\n\\r\\f\\b\\t \\u0000\\u0019\\u001F \\u007F\\u0080\\u009F \\u2028\\u2029");
+    }
+
+    @Test
+    public void testHtmlChars() {
+        assertEsc(
+                "<safe>/>->]> </foo> <!-- --> <![CDATA[ ]]> <?php?>",
+                "<safe>/>->]> <\\/foo> \\x3C!-- --\\> \\x3C![CDATA[ ]]\\> \\x3C?php?>",
+                "<safe>/>->]> <\\/foo> \\u003C!-- --\\u003E \\u003C![CDATA[ ]]\\u003E \\u003C?php?>");
+        assertEsc("<!c", "\\x3C!c", "\\u003C!c");
+        assertEsc("c<!", "c\\x3C!", "c\\u003C!");
+        assertEsc("c<", "c\\x3C", "c\\u003C");
+        assertEsc("c<c", "c<c", "c<c");
+        assertEsc("<c", "<c", "<c");
+        assertEsc(">", "\\>", "\\u003E");
+        assertEsc("->", "-\\>", "-\\u003E");
+        assertEsc("-->", "--\\>", "--\\u003E");
+        assertEsc("c-->", "c--\\>", "c--\\u003E");
+        assertEsc("-->c", "--\\>c", "--\\u003Ec");
+        assertEsc("]>", "]\\>", "]\\u003E");
+        assertEsc("]]>", "]]\\>", "]]\\u003E");
+        assertEsc("c]]>", "c]]\\>", "c]]\\u003E");
+        assertEsc("]]>c", "]]\\>c", "]]\\u003Ec");
+        assertEsc("c->", "c->", "c->");
+        assertEsc("c>", "c>", "c>");
+        assertEsc("-->", "--\\>", "--\\u003E");
+        assertEsc("/", "\\/", "\\/");
+        assertEsc("/c", "\\/c", "\\/c");
+        assertEsc("</", "<\\/", "<\\/");
+        assertEsc("</c", "<\\/c", "<\\/c");
+        assertEsc("c/", "c/", "c/");
+    }
+
+    @Test
+    public void testJSChars() {
+        assertEsc("\"", "\\\"", "\\\"");
+        assertEsc("'", "\\'", "'");
+        assertEsc("\\", "\\\\", "\\\\");
+    }
+
+    @Test
+    public void testSameStringsReturned() {
+        String s = "==> I/m <safe>!";
+        assertTrue(s == _StringUtil.jsStringEnc(s, false));  // "==" because is must return the same object
+        assertTrue(s == _StringUtil.jsStringEnc(s, true));
+
+        s = "";
+        assertTrue(s == _StringUtil.jsStringEnc(s, false));
+        assertTrue(s == _StringUtil.jsStringEnc(s, true));
+
+        s = "\u00E1rv\u00EDzt\u0171r\u0151 \u3020";
+        assertEquals(s, _StringUtil.jsStringEnc(s, false));
+        assertTrue(s == _StringUtil.jsStringEnc(s, false));
+        assertTrue(s == _StringUtil.jsStringEnc(s, true));
+    }
+
+    @Test
+    public void testOneOffs() {
+        assertEsc("c\"c\"cc\"\"c", "c\\\"c\\\"cc\\\"\\\"c", "c\\\"c\\\"cc\\\"\\\"c");
+        assertEsc("\"c\"cc\"", "\\\"c\\\"cc\\\"", "\\\"c\\\"cc\\\"");
+        assertEsc("c/c/cc//c", "c/c/cc//c", "c/c/cc//c");
+        assertEsc("c<c<cc<<c", "c<c<cc<<c", "c<c<cc<<c");
+        assertEsc("/<", "\\/\\x3C", "\\/\\u003C");
+        assertEsc(">", "\\>", "\\u003E");
+        assertEsc("]>", "]\\>", "]\\u003E");
+        assertEsc("->", "-\\>", "-\\u003E");
+    }
+
+    private void assertEsc(String s, String javaScript, String json) {
+        assertEquals(javaScript, _StringUtil.jsStringEnc(s, false));
+        assertEquals(json, _StringUtil.jsStringEnc(s, true));
+    }
+
+    @Test
+    public void testTrim() {
+        assertSame(_CollectionUtil.EMPTY_CHAR_ARRAY, _StringUtil.trim(_CollectionUtil.EMPTY_CHAR_ARRAY));
+        assertSame(_CollectionUtil.EMPTY_CHAR_ARRAY, _StringUtil.trim(" \t\u0001 ".toCharArray()));
+        {
+            char[] cs = "foo".toCharArray();
+            assertSame(cs, cs);
+        }
+        assertArrayEquals("foo".toCharArray(), _StringUtil.trim("foo ".toCharArray()));
+        assertArrayEquals("foo".toCharArray(), _StringUtil.trim(" foo".toCharArray()));
+        assertArrayEquals("foo".toCharArray(), _StringUtil.trim(" foo ".toCharArray()));
+        assertArrayEquals("foo".toCharArray(), _StringUtil.trim("\t\tfoo \r\n".toCharArray()));
+        assertArrayEquals("x".toCharArray(), _StringUtil.trim(" x ".toCharArray()));
+        assertArrayEquals("x y z".toCharArray(), _StringUtil.trim(" x y z ".toCharArray()));
+    }
+
+    @Test
+    public void testIsTrimmedToEmpty() {
+        assertTrue(_StringUtil.isTrimmableToEmpty("".toCharArray()));
+        assertTrue(_StringUtil.isTrimmableToEmpty("\r\r\n\u0001".toCharArray()));
+        assertFalse(_StringUtil.isTrimmableToEmpty("x".toCharArray()));
+        assertFalse(_StringUtil.isTrimmableToEmpty("  x  ".toCharArray()));
+    }
+    
+    @Test
+    public void testJQuote() {
+        assertEquals("null", _StringUtil.jQuote(null));
+        assertEquals("\"foo\"", _StringUtil.jQuote("foo"));
+        assertEquals("\"123\"", _StringUtil.jQuote(Integer.valueOf(123)));
+        assertEquals("\"foo's \\\"bar\\\"\"",
+                _StringUtil.jQuote("foo's \"bar\""));
+        assertEquals("\"\\n\\r\\t\\u0001\"",
+                _StringUtil.jQuote("\n\r\t\u0001"));
+        assertEquals("\"<\\nb\\rc\\td\\u0001>\"",
+                _StringUtil.jQuote("<\nb\rc\td\u0001>"));
+    }
+
+    @Test
+    public void testJQuoteNoXSS() {
+        assertEquals("null", _StringUtil.jQuoteNoXSS(null));
+        assertEquals("\"foo\"", _StringUtil.jQuoteNoXSS("foo"));
+        assertEquals("\"123\"", _StringUtil.jQuoteNoXSS(Integer.valueOf(123)));
+        assertEquals("\"foo's \\\"bar\\\"\"",
+                _StringUtil.jQuoteNoXSS("foo's \"bar\""));
+        assertEquals("\"\\n\\r\\t\\u0001\"",
+                _StringUtil.jQuoteNoXSS("\n\r\t\u0001"));
+        assertEquals("\"\\u003C\\nb\\rc\\td\\u0001>\"",
+                _StringUtil.jQuoteNoXSS("<\nb\rc\td\u0001>"));
+        assertEquals("\"\\u003C\\nb\\rc\\td\\u0001>\"",
+                _StringUtil.jQuoteNoXSS((Object) "<\nb\rc\td\u0001>"));
+    }
+
+    @Test
+    public void testGlobToRegularExpression() {
+        assertGlobMatches("a/b/c.ftl", "a/b/c.ftl");
+        assertGlobDoesNotMatch("/a/b/cxftl", "/a/b/c.ftl", "a/b/C.ftl");
+        
+        assertGlobMatches("a/b/*.ftl", "a/b/.ftl", "a/b/x.ftl", "a/b/xx.ftl");
+        assertGlobDoesNotMatch("a/b/*.ftl", "a/c/x.ftl", "a/b/c/x.ftl", "/a/b/x.ftl", "a/b/xxftl");
+        
+        assertGlobMatches("a/b/?.ftl", "a/b/x.ftl");
+        assertGlobDoesNotMatch("a/b/?.ftl", "a/c/x.ftl", "a/b/.ftl", "a/b/xx.ftl", "a/b/xxftl");
+        
+        assertGlobMatches("a/**/c.ftl", "a/b/c.ftl", "a/c.ftl", "a/b/b2/b3/c.ftl", "a//c.ftl");
+        assertGlobDoesNotMatch("a/**/c.ftl", "x/b/c.ftl", "a/b/x.ftl");
+        
+        assertGlobMatches("**/c.ftl", "a/b/c.ftl", "c.ftl", "/c.ftl", "///c.ftl");
+        assertGlobDoesNotMatch("**/c.ftl", "a/b/x.ftl");
+
+        assertGlobMatches("a/b/**", "a/b/c.ftl", "a/b/c2/c.ftl", "a/b/", "a/b/c/");
+        assertGlobDoesNotMatch("a/b.ftl");
+
+        assertGlobMatches("**", "a/b/c.ftl", "");
+
+        assertGlobMatches("\\[\\{\\*\\?\\}\\]\\\\", "[{*?}]\\");
+        assertGlobDoesNotMatch("\\[\\{\\*\\?\\}\\]\\\\", "[{xx}]\\");
+
+        assertGlobMatches("a/b/\\?.ftl", "a/b/?.ftl");
+        assertGlobDoesNotMatch("a/b/\\?.ftl", "a/b/x.ftl");
+
+        assertGlobMatches("\\?\\?.ftl", "??.ftl");
+        assertGlobMatches("\\\\\\\\", "\\\\");
+        assertGlobMatches("\\\\\\\\?", "\\\\x");
+        assertGlobMatches("x\\", "x");
+
+        assertGlobMatches("???*", "123", "1234", "12345");
+        assertGlobDoesNotMatch("???*", "12", "1", "");
+
+        assertGlobMatches("**/a??/b*.ftl", "a11/b1.ftl", "x/a11/b123.ftl", "x/y/a11/b.ftl");
+        assertGlobDoesNotMatch("**/a??/b*.ftl", "a1/b1.ftl", "x/a11/c123.ftl");
+        
+        assertFalse(_StringUtil.globToRegularExpression("ab*").matcher("aBc").matches());
+        assertTrue(_StringUtil.globToRegularExpression("ab*", true).matcher("aBc").matches());
+        assertTrue(_StringUtil.globToRegularExpression("ab", true).matcher("aB").matches());
+        assertTrue(_StringUtil.globToRegularExpression("\u00E1b*", true).matcher("\u00C1bc").matches());
+        
+        try {
+            _StringUtil.globToRegularExpression("x**/y");
+            fail();
+        } catch (IllegalArgumentException e) {
+            assertThat(e.getMessage(), Matchers.containsString("**"));
+        }
+        
+        try {
+            _StringUtil.globToRegularExpression("**y");
+            fail();
+        } catch (IllegalArgumentException e) {
+            assertThat(e.getMessage(), Matchers.containsString("**"));
+        }
+        
+        try {
+            _StringUtil.globToRegularExpression("[ab]c");
+            fail();
+        } catch (IllegalArgumentException e) {
+            assertThat(e.getMessage(), Matchers.containsString("unsupported"));
+        }
+        
+        try {
+            _StringUtil.globToRegularExpression("{aa,bb}c");
+            fail();
+        } catch (IllegalArgumentException e) {
+            assertThat(e.getMessage(), Matchers.containsString("unsupported"));
+        }
+    }
+    
+    private void assertGlobMatches(String glob, String... ss) {
+        Pattern pattern = _StringUtil.globToRegularExpression(glob);
+        for (String s : ss) {
+            if (!pattern.matcher(s).matches()) {
+                fail("Glob " + glob + " (regexp: " + pattern + ") doesn't match " + s);
+            }
+        }
+    }
+
+    private void assertGlobDoesNotMatch(String glob, String... ss) {
+        Pattern pattern = _StringUtil.globToRegularExpression(glob);
+        for (String s : ss) {
+            if (pattern.matcher(s).matches()) {
+                fail("Glob " + glob + " (regexp: " + pattern + ") matches " + s);
+            }
+        }
+    }
+    
+    @Test
+    public void testHTMLEnc() {
+        String s = "";
+        assertSame(s, _StringUtil.XMLEncNA(s));
+        
+        s = "asd";
+        assertSame(s, _StringUtil.XMLEncNA(s));
+        
+        assertEquals("a&amp;b&lt;c&gt;d&quot;e'f", _StringUtil.XMLEncNA("a&b<c>d\"e'f"));
+        assertEquals("&lt;", _StringUtil.XMLEncNA("<"));
+        assertEquals("&lt;a", _StringUtil.XMLEncNA("<a"));
+        assertEquals("&lt;a&gt;", _StringUtil.XMLEncNA("<a>"));
+        assertEquals("a&gt;", _StringUtil.XMLEncNA("a>"));
+        assertEquals("&lt;&gt;", _StringUtil.XMLEncNA("<>"));
+        assertEquals("a&lt;&gt;b", _StringUtil.XMLEncNA("a<>b"));
+    }
+
+    @Test
+    public void testXHTMLEnc() throws IOException {
+        String s = "";
+        assertSame(s, _StringUtil.XHTMLEnc(s));
+        
+        s = "asd";
+        assertSame(s, _StringUtil.XHTMLEnc(s));
+        
+        testXHTMLEnc("a&amp;b&lt;c&gt;d&quot;e&#39;f", "a&b<c>d\"e'f");
+        testXHTMLEnc("&lt;", "<");
+        testXHTMLEnc("&lt;a", "<a");
+        testXHTMLEnc("&lt;a&gt;", "<a>");
+        testXHTMLEnc("a&gt;", "a>");
+        testXHTMLEnc("&lt;&gt;", "<>");
+        testXHTMLEnc("a&lt;&gt;b", "a<>b");
+    }
+    
+    private void testXHTMLEnc(String expected, String in) throws IOException {
+        assertEquals(expected, _StringUtil.XHTMLEnc(in));
+        
+        StringWriter sw = new StringWriter();
+        _StringUtil.XHTMLEnc(in, sw);
+        assertEquals(expected, sw.toString());
+    }
+
+    @Test
+    public void testXMLEnc() throws IOException {
+        String s = "";
+        assertSame(s, _StringUtil.XMLEnc(s));
+        
+        s = "asd";
+        assertSame(s, _StringUtil.XMLEnc(s));
+        
+        testXMLEnc("a&amp;b&lt;c&gt;d&quot;e&apos;f", "a&b<c>d\"e'f");
+        testXMLEnc("&lt;", "<");
+        testXMLEnc("&lt;a", "<a");
+        testXMLEnc("&lt;a&gt;", "<a>");
+        testXMLEnc("a&gt;", "a>");
+        testXMLEnc("&lt;&gt;", "<>");
+        testXMLEnc("a&lt;&gt;b", "a<>b");
+    }
+    
+    private void testXMLEnc(String expected, String in) throws IOException {
+        assertEquals(expected, _StringUtil.XMLEnc(in));
+        
+        StringWriter sw = new StringWriter();
+        _StringUtil.XMLEnc(in, sw);
+        assertEquals(expected, sw.toString());
+    }
+
+    @Test
+    public void testXMLEncQAttr() throws IOException {
+        String s = "";
+        assertSame(s, _StringUtil.XMLEncQAttr(s));
+        
+        s = "asd";
+        assertSame(s, _StringUtil.XMLEncQAttr(s));
+        
+        assertEquals("a&amp;b&lt;c>d&quot;e'f", _StringUtil.XMLEncQAttr("a&b<c>d\"e'f"));
+        assertEquals("&lt;", _StringUtil.XMLEncQAttr("<"));
+        assertEquals("&lt;a", _StringUtil.XMLEncQAttr("<a"));
+        assertEquals("&lt;a>", _StringUtil.XMLEncQAttr("<a>"));
+        assertEquals("a>", _StringUtil.XMLEncQAttr("a>"));
+        assertEquals("&lt;>", _StringUtil.XMLEncQAttr("<>"));
+        assertEquals("a&lt;>b", _StringUtil.XMLEncQAttr("a<>b"));
+    }
+    
+    @Test
+    public void testXMLEncNQG() throws IOException {
+        String s = "";
+        assertSame(s, _StringUtil.XMLEncNQG(s));
+        
+        s = "asd";
+        assertSame(s, _StringUtil.XMLEncNQG(s));
+        
+        assertEquals("a&amp;b&lt;c>d\"e'f", _StringUtil.XMLEncNQG("a&b<c>d\"e'f"));
+        assertEquals("&lt;", _StringUtil.XMLEncNQG("<"));
+        assertEquals("&lt;a", _StringUtil.XMLEncNQG("<a"));
+        assertEquals("&lt;a>", _StringUtil.XMLEncNQG("<a>"));
+        assertEquals("a>", _StringUtil.XMLEncNQG("a>"));
+        assertEquals("&lt;>", _StringUtil.XMLEncNQG("<>"));
+        assertEquals("a&lt;>b", _StringUtil.XMLEncNQG("a<>b"));
+        
+        assertEquals("&gt;", _StringUtil.XMLEncNQG(">"));
+        assertEquals("]&gt;", _StringUtil.XMLEncNQG("]>"));
+        assertEquals("]]&gt;", _StringUtil.XMLEncNQG("]]>"));
+        assertEquals("x]]&gt;", _StringUtil.XMLEncNQG("x]]>"));
+        assertEquals("x]>", _StringUtil.XMLEncNQG("x]>"));
+        assertEquals("]x>", _StringUtil.XMLEncNQG("]x>"));
+    }
+
+    @Test
+    public void testRTFEnc() throws IOException {
+        String s = "";
+        assertSame(s, _StringUtil.RTFEnc(s));
+        
+        s = "asd";
+        assertSame(s, _StringUtil.RTFEnc(s));
+        
+        testRTFEnc("a\\{b\\}c\\\\d", "a{b}c\\d");
+        testRTFEnc("\\{", "{");
+        testRTFEnc("\\{a", "{a");
+        testRTFEnc("\\{a\\}", "{a}");
+        testRTFEnc("a\\}", "a}");
+        testRTFEnc("\\{\\}", "{}");
+        testRTFEnc("a\\{\\}b", "a{}b");
+    }
+
+    private void testRTFEnc(String expected, String in) throws IOException {
+        assertEquals(expected, _StringUtil.RTFEnc(in));
+        
+        StringWriter sw = new StringWriter();
+        _StringUtil.RTFEnc(in, sw);
+        assertEquals(expected, sw.toString());
+    }
+
+    @Test
+    public void testNormalizeEOLs() {
+        assertNull(_StringUtil.normalizeEOLs(null));
+        assertEquals("", _StringUtil.normalizeEOLs(""));
+        assertEquals("x", _StringUtil.normalizeEOLs("x"));
+        assertEquals("x\ny", _StringUtil.normalizeEOLs("x\ny"));
+        assertEquals("x\ny", _StringUtil.normalizeEOLs("x\r\ny"));
+        assertEquals("x\ny", _StringUtil.normalizeEOLs("x\ry"));
+        assertEquals("\n\n\n\n\n\n", _StringUtil.normalizeEOLs("\n\r\r\r\n\r\n\r"));
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/valueformat/NumberFormatTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/valueformat/NumberFormatTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/valueformat/NumberFormatTest.java
new file mode 100644
index 0000000..8900d2b
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/valueformat/NumberFormatTest.java
@@ -0,0 +1,365 @@
+/*
+ * 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.valueformat;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Collections;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.Environment;
+import org.apache.freemarker.core.Template;
+import org.apache.freemarker.core.TemplateConfiguration;
+import org.apache.freemarker.core.TemplateException;
+import org.apache.freemarker.core.model.TemplateDirectiveBody;
+import org.apache.freemarker.core.model.TemplateDirectiveModel;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateNumberModel;
+import org.apache.freemarker.core.model.impl.SimpleNumber;
+import org.apache.freemarker.core.templateresolver.ConditionalTemplateConfigurationFactory;
+import org.apache.freemarker.core.templateresolver.FileNameGlobMatcher;
+import org.apache.freemarker.core.templateresolver.TemplateConfigurationFactory;
+import org.apache.freemarker.core.userpkg.BaseNTemplateNumberFormatFactory;
+import org.apache.freemarker.core.userpkg.HexTemplateNumberFormatFactory;
+import org.apache.freemarker.core.userpkg.LocaleSensitiveTemplateNumberFormatFactory;
+import org.apache.freemarker.core.userpkg.PrintfGTemplateNumberFormatFactory;
+import org.apache.freemarker.core.valueformat.impl.AliasTemplateNumberFormatFactory;
+import org.apache.freemarker.test.TemplateTest;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableMap;
+
+@SuppressWarnings("boxing")
+public class NumberFormatTest extends TemplateTest {
+    
+    @Test
+    public void testUnknownCustomFormat() throws Exception {
+        {
+            setConfigurationWithNumberFormat("@noSuchFormat");
+            Throwable exc = assertErrorContains("${1}", "\"@noSuchFormat\"", "\"noSuchFormat\"");
+            assertThat(exc.getCause(), instanceOf(UndefinedCustomFormatException.class));
+        }
+
+        {
+            setConfigurationWithNumberFormat("number");
+            Throwable exc = assertErrorContains("${1?string('@noSuchFormat2')}",
+                    "\"@noSuchFormat2\"", "\"noSuchFormat2\"");
+            assertThat(exc.getCause(), instanceOf(UndefinedCustomFormatException.class));
+        }
+    }
+    
+    @Test
+    public void testStringBI() throws Exception {
+        setConfigurationWithNumberFormat(null);
+        assertOutput("${11} ${11?string.@hex} ${12} ${12?string.@hex}", "11 b 12 c");
+    }
+
+    @Test
+    public void testSetting() throws Exception {
+        setConfigurationWithNumberFormat("@hex");
+        assertOutput("${11?string.number} ${11} ${12?string.number} ${12}", "11 b 12 c");
+    }
+
+    @Test
+    public void testSetting2() throws Exception {
+        setConfigurationWithNumberFormat(null);
+        assertOutput(
+                "<#setting numberFormat='@hex'>${11?string.number} ${11} ${12?string.number} ${12} ${13?string}"
+                + "<#setting numberFormat='@loc'>${11?string.number} ${11} ${12?string.number} ${12} ${13?string}",
+                "11 b 12 c d"
+                + "11 11_en_US 12 12_en_US 13_en_US");
+    }
+    
+    @Test
+    public void testUnformattableNumber() throws Exception {
+        setConfigurationWithNumberFormat("@hex");
+        assertErrorContains("${1.1}", "hexadecimal int", "doesn't fit into an int");
+    }
+
+    @Test
+    public void testLocaleSensitive() throws Exception {
+        setConfigurationWithNumberFormat("@loc");
+        assertOutput("${1.1}", "1.1_en_US");
+        setConfigurationWithNumberFormat("@loc", null, null, Locale.GERMANY);
+        assertOutput("${1.1}", "1.1_de_DE");
+    }
+
+    @Test
+    public void testLocaleSensitive2() throws Exception {
+        setConfigurationWithNumberFormat("@loc");
+        assertOutput("${1.1} <#setting locale='de_DE'>${1.1}", "1.1_en_US 1.1_de_DE");
+    }
+
+    @Test
+    public void testCustomParameterized() throws Exception {
+        setConfigurationWithNumberFormat("@base 2");
+        assertOutput("${11}", "1011");
+        assertOutput("${11?string}", "1011");
+        assertOutput("${11?string.@base_3}", "102");
+        
+        assertErrorContains("${11?string.@base_xyz}", "\"@base_xyz\"", "\"xyz\"");
+        setConfigurationWithNumberFormat("@base");
+        assertErrorContains("${11}", "\"@base\"", "format parameter is required");
+    }
+
+    @Test
+    public void testCustomWithFallback() throws Exception {
+        Configuration cfg = getConfiguration();
+        setConfigurationWithNumberFormat("@base 2|0.0#");
+        assertOutput("${11}", "1011");
+        assertOutput("${11.34}", "11.34");
+        assertOutput("${11?string('@base 3|0.00')}", "102");
+        assertOutput("${11.2?string('@base 3|0.00')}", "11.20");
+    }
+
+    @Test
+    public void testEnvironmentGetters() throws Exception {
+        setConfigurationWithNumberFormat(null);
+
+        Template t = new Template(null, "", getConfiguration());
+        Environment env = t.createProcessingEnvironment(null, null);
+        
+        TemplateNumberFormat defF = env.getTemplateNumberFormat();
+        //
+        TemplateNumberFormat explF = env.getTemplateNumberFormat("0.00");
+        assertEquals("1.25", explF.formatToPlainText(new SimpleNumber(1.25)));
+        //
+        TemplateNumberFormat expl2F = env.getTemplateNumberFormat("@loc");
+        assertEquals("1.25_en_US", expl2F.formatToPlainText(new SimpleNumber(1.25)));
+        
+        TemplateNumberFormat explFFr = env.getTemplateNumberFormat("0.00", Locale.FRANCE);
+        assertNotSame(explF, explFFr);
+        assertEquals("1,25", explFFr.formatToPlainText(new SimpleNumber(1.25)));
+        //
+        TemplateNumberFormat expl2FFr = env.getTemplateNumberFormat("@loc", Locale.FRANCE);
+        assertEquals("1.25_fr_FR", expl2FFr.formatToPlainText(new SimpleNumber(1.25)));
+        
+        assertSame(env.getTemplateNumberFormat(), defF);
+        //
+        assertSame(env.getTemplateNumberFormat("0.00"), explF);
+        //
+        assertSame(env.getTemplateNumberFormat("@loc"), expl2F);
+    }
+    
+    /**
+     * ?string formats lazily (at least in 2.3.x), so it must make a snapshot of the format inputs when it's called.
+     */
+    @Test
+    @Ignore // [FM3] We want to rework BI-s so that lazy evaluation won't be needed. Then this will go away too.
+    public void testStringBIDoesSnapshot() throws Exception {
+        // TemplateNumberModel-s shouldn't change, but we have to keep BC when that still happens.
+        final MutableTemplateNumberModel nm = new MutableTemplateNumberModel();
+        nm.setNumber(123);
+        addToDataModel("n", nm);
+        addToDataModel("incN", new TemplateDirectiveModel() {
+            
+            @Override
+            public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
+                    throws TemplateException, IOException {
+                nm.setNumber(nm.getAsNumber().intValue() + 1);
+            }
+        });
+        assertOutput(
+                "<#assign s1 = n?string>"
+                + "<#setting numberFormat='@loc'>"
+                + "<#assign s2 = n?string>"
+                + "<#setting numberFormat='@hex'>"
+                + "<#assign s3 = n?string>"
+                + "${s1} ${s2} ${s3}",
+                "123 123_en_US 7b");
+        assertOutput(
+                "<#assign s1 = n?string>"
+                + "<@incN />"
+                + "<#assign s2 = n?string>"
+                + "${s1} ${s2}",
+                "123 124");
+    }
+
+    @Test
+    public void testNullInModel() throws Exception {
+        addToDataModel("n", new MutableTemplateNumberModel());
+        assertErrorContains("${n}", "nothing inside it");
+        assertErrorContains("${n?string}", "nothing inside it");
+    }
+    
+    @Test
+    public void testAtPrefix() throws Exception {
+        Configuration cfg = getConfiguration();
+
+        setConfigurationWithNumberFormat("@hex");
+        assertOutput("${10}", "a");
+        setConfigurationWithNumberFormat("'@'0");
+        assertOutput("${10}", "@10");
+        setConfigurationWithNumberFormat("@@0");
+        assertOutput("${10}", "@@10");
+
+        setConfigurationWithNumberFormat(
+                "@hex", Collections.<String, TemplateNumberFormatFactory>emptyMap());
+        assertErrorContains("${10}", "custom", "\"hex\"");
+
+        setConfigurationWithNumberFormat(
+                "'@'0", Collections.<String, TemplateNumberFormatFactory>emptyMap());
+        assertOutput("${10}", "@10");
+
+        setConfigurationWithNumberFormat(
+                "@@0", Collections.<String, TemplateNumberFormatFactory>emptyMap());
+        assertOutput("${10}", "@@10");
+    }
+
+    @Test
+    public void testAlieses() throws Exception {
+        setConfigurationWithNumberFormat(
+                "'@'0",
+                ImmutableMap.of(
+                        "f", new AliasTemplateNumberFormatFactory("0.#'f'"),
+                        "d", new AliasTemplateNumberFormatFactory("0.0#"),
+                        "hex", HexTemplateNumberFormatFactory.INSTANCE),
+                new ConditionalTemplateConfigurationFactory(
+                        new FileNameGlobMatcher("*2*"),
+                        new TemplateConfiguration.Builder()
+                                .customNumberFormats(ImmutableMap.<String, TemplateNumberFormatFactory>of(
+                                        "d", new AliasTemplateNumberFormatFactory("0.#'d'"),
+                                        "i", new AliasTemplateNumberFormatFactory("@hex")))
+                                .build()));
+
+        String commonFtl = "${1?string.@f} ${1?string.@d} "
+                + "<#setting locale='fr_FR'>${1.5?string.@d} "
+                + "<#attempt>${10?string.@i}<#recover>E</#attempt>";
+        addTemplate("t1.ftl", commonFtl);
+        addTemplate("t2.ftl", commonFtl);
+        
+        assertOutputForNamed("t1.ftl", "1f 1.0 1,5 E");
+        assertOutputForNamed("t2.ftl", "1f 1d 1,5d a");
+    }
+
+    @Test
+    public void testAlieses2() throws Exception {
+        setConfigurationWithNumberFormat(
+                "@n",
+                ImmutableMap.<String, TemplateNumberFormatFactory>of(
+                        "n", new AliasTemplateNumberFormatFactory("0.0",
+                                ImmutableMap.of(
+                                        new Locale("en"), "0.0'_en'",
+                                        Locale.UK, "0.0'_en_GB'",
+                                        Locale.FRANCE, "0.0'_fr_FR'"))));
+        assertOutput(
+                "<#setting locale='en_US'>${1} "
+                + "<#setting locale='en_GB'>${1} "
+                + "<#setting locale='en_GB_Win'>${1} "
+                + "<#setting locale='fr_FR'>${1} "
+                + "<#setting locale='hu_HU'>${1}",
+                "1.0_en 1.0_en_GB 1.0_en_GB 1,0_fr_FR 1,0");
+    }
+    
+    @Test
+    public void testMarkupFormat() throws IOException, TemplateException {
+        setConfigurationWithNumberFormat("@printfG_3");
+
+        String commonFTL = "${1234567} ${'cat:' + 1234567} ${0.0000123}";
+        String commonOutput = "1.23*10<sup>6</sup> cat:1.23*10<sup>6</sup> 1.23*10<sup>-5</sup>";
+        assertOutput(commonFTL, commonOutput);
+        assertOutput("<#ftl outputFormat='HTML'>" + commonFTL, commonOutput);
+        assertOutput("<#escape x as x?html>" + commonFTL + "</#escape>", commonOutput);
+        assertOutput("<#escape x as x?xhtml>" + commonFTL + "</#escape>", commonOutput);
+        assertOutput("<#escape x as x?xml>" + commonFTL + "</#escape>", commonOutput);
+        assertOutput("${\"" + commonFTL + "\"}", "1.23*10<sup>6</sup> cat:1.23*10<sup>6</sup> 1.23*10<sup>-5</sup>");
+        assertErrorContains("<#ftl outputFormat='plainText'>" + commonFTL, "HTML", "plainText", "conversion");
+    }
+
+    @Test
+    public void testPrintG() throws IOException, TemplateException {
+        setConfigurationWithNumberFormat(null);
+        for (Number n : new Number[] {
+                1234567, 1234567L, 1234567d, 1234567f, BigInteger.valueOf(1234567), BigDecimal.valueOf(1234567) }) {
+            addToDataModel("n", n);
+            
+            assertOutput("${n?string.@printfG}", "1.23457E+06");
+            assertOutput("${n?string.@printfG_3}", "1.23E+06");
+            assertOutput("${n?string.@printfG_7}", "1234567");
+            assertOutput("${0.0000123?string.@printfG}", "1.23000E-05");
+        }
+    }
+
+    private void setConfigurationWithNumberFormat(
+            String numberFormat,
+            Map<String, TemplateNumberFormatFactory> customNumberFormats,
+            TemplateConfigurationFactory templateConfigurationFactory,
+            Locale locale) {
+        TestConfigurationBuilder cfgB = new TestConfigurationBuilder(Configuration.VERSION_3_0_0);
+
+        if (numberFormat != null) {
+            cfgB.setNumberFormat(numberFormat);
+        }
+        cfgB.setCustomNumberFormats(
+                customNumberFormats != null ? customNumberFormats
+                        : ImmutableMap.of(
+                                "hex", HexTemplateNumberFormatFactory.INSTANCE,
+                                "loc", LocaleSensitiveTemplateNumberFormatFactory.INSTANCE,
+                                "base", BaseNTemplateNumberFormatFactory.INSTANCE,
+                                "printfG", PrintfGTemplateNumberFormatFactory.INSTANCE));
+        if (locale != null) {
+            cfgB.setLocale(locale);
+        }
+        if (templateConfigurationFactory != null) {
+            cfgB.setTemplateConfigurations(templateConfigurationFactory);
+        }
+
+        setConfiguration(cfgB.build());
+    }
+
+    private void setConfigurationWithNumberFormat(String numberFormat) {
+        setConfigurationWithNumberFormat(numberFormat, null, null, null);
+    }
+
+    private void setConfigurationWithNumberFormat(
+            String numberFormat, Map<String, TemplateNumberFormatFactory> customNumberFormats) {
+        setConfigurationWithNumberFormat(numberFormat, customNumberFormats, null, null);
+    }
+
+    private void setConfigurationWithNumberFormat(
+            String numberFormat, Map<String, TemplateNumberFormatFactory> customNumberFormats,
+            TemplateConfigurationFactory templateConfigurationFactory) {
+        setConfigurationWithNumberFormat(numberFormat, customNumberFormats, templateConfigurationFactory, null);
+    }
+
+    private static class MutableTemplateNumberModel implements TemplateNumberModel {
+        
+        private Number number;
+
+        public void setNumber(Number number) {
+            this.number = number;
+        }
+
+        @Override
+        public Number getAsNumber() throws TemplateModelException {
+            return number;
+        }
+        
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/core/valueformat/impl/ExtendedDecimalFormatTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/valueformat/impl/ExtendedDecimalFormatTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/valueformat/impl/ExtendedDecimalFormatTest.java
new file mode 100644
index 0000000..76c0bfc
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/valueformat/impl/ExtendedDecimalFormatTest.java
@@ -0,0 +1,343 @@
+/*
+ * 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.valueformat.impl;
+
+import static org.apache.freemarker.test.hamcerst.Matchers.*;
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.text.ParseException;
+import java.util.Locale;
+
+import org.apache.freemarker.core.TemplateException;
+import org.apache.freemarker.test.TemplateTest;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+import org.junit.Test;
+
+public class ExtendedDecimalFormatTest extends TemplateTest {
+    
+    private static final Locale LOC = Locale.US;
+    private static final DecimalFormatSymbols SYMS = DecimalFormatSymbols.getInstance(LOC);
+
+    @Test
+    public void testNonExtended() throws ParseException {
+        for (String fStr : new String[] { "0.00", "0.###", "#,#0.###", "#0.####", "0.0;m", "0.0;",
+                "0'x'", "0'x';'m'", "0';'", "0';';m", "0';';'#'m';'", "0';;'", "" }) {
+            assertFormatsEquivalent(new DecimalFormat(fStr, SYMS), ExtendedDecimalFormatParser.parse(fStr, LOC));
+        }
+        
+        try {
+            new DecimalFormat(";");
+            fail();
+        } catch (IllegalArgumentException e) {
+            // Expected
+        }
+        try {
+            ExtendedDecimalFormatParser.parse(";", LOC);
+        } catch (ParseException e) {
+            // Expected
+        }
+    }
+
+    @Test
+    public void testNonExtended2() throws ParseException {
+        assertFormatsEquivalent(new DecimalFormat("0.0", SYMS), ExtendedDecimalFormatParser.parse("0.0;", LOC));
+        assertFormatsEquivalent(new DecimalFormat("0.0", SYMS), ExtendedDecimalFormatParser.parse("0.0;;", LOC));
+        assertFormatsEquivalent(new DecimalFormat("0.0;m", SYMS), ExtendedDecimalFormatParser.parse("0.0;m;", LOC));
+        assertFormatsEquivalent(new DecimalFormat("", SYMS), ExtendedDecimalFormatParser.parse(";;", LOC));
+        assertFormatsEquivalent(new DecimalFormat("0'x'", SYMS), ExtendedDecimalFormatParser.parse("0'x';;", LOC));
+        assertFormatsEquivalent(new DecimalFormat("0'x';'m'", SYMS),
+                ExtendedDecimalFormatParser.parse("0'x';'m';", LOC));
+        assertFormatsEquivalent(new DecimalFormat("0';'", SYMS), ExtendedDecimalFormatParser.parse("0';';;", LOC));
+        assertFormatsEquivalent(new DecimalFormat("0';';m", SYMS), ExtendedDecimalFormatParser.parse("0';';m;", LOC));
+        assertFormatsEquivalent(new DecimalFormat("0';';'#'m';'", SYMS),
+                ExtendedDecimalFormatParser.parse("0';';'#'m';';", LOC));
+        assertFormatsEquivalent(new DecimalFormat("0';;'", SYMS),
+                ExtendedDecimalFormatParser.parse("0';;';;", LOC));
+
+        try {
+            new DecimalFormat(";m");
+            fail();
+        } catch (IllegalArgumentException e) {
+            // Expected
+        }
+        try {
+            new DecimalFormat("; ;");
+            fail();
+        } catch (IllegalArgumentException e) {
+            // Expected
+        }
+        try {
+            ExtendedDecimalFormatParser.parse("; ;", LOC);
+            fail();
+        } catch (ParseException e) {
+            // Expected
+        }
+        try {
+            ExtendedDecimalFormatParser.parse(";m", LOC);
+            fail();
+        } catch (ParseException e) {
+            // Expected
+        }
+        try {
+            ExtendedDecimalFormatParser.parse(";m;", LOC);
+            fail();
+        } catch (ParseException e) {
+            // Expected
+        }
+    }
+    
+    @SuppressWarnings("boxing")
+    @Test
+    public void testExtendedParamsParsing() throws ParseException {
+        for (String fs : new String[] {
+                "00.##;; decimalSeparator='D'",
+                "00.##;;decimalSeparator=D",
+                "00.##;;  decimalSeparator  =  D ", "00.##;; decimalSeparator = 'D' " }) {
+            assertFormatted(fs, 1.125, "01D12");
+        }
+        for (String fs : new String[] {
+                ",#0.0;; decimalSeparator=D, groupingSeparator=_",
+                ",#0.0;;decimalSeparator=D,groupingSeparator=_",
+                ",#0.0;; decimalSeparator = D , groupingSeparator = _ ",
+                ",#0.0;; decimalSeparator='D', groupingSeparator='_'"
+                }) {
+            assertFormatted(fs, 12345, "1_23_45D0");
+        }
+        
+        assertFormatted("0.0;;infinity=infinity", Double.POSITIVE_INFINITY, "infinity");
+        assertFormatted("0.0;;infinity='infinity'", Double.POSITIVE_INFINITY, "infinity");
+        assertFormatted("0.0;;infinity=\"infinity\"", Double.POSITIVE_INFINITY, "infinity");
+        assertFormatted("0.0;;infinity=''", Double.POSITIVE_INFINITY, "");
+        assertFormatted("0.0;;infinity=\"\"", Double.POSITIVE_INFINITY, "");
+        assertFormatted("0.0;;infinity='x''y'", Double.POSITIVE_INFINITY, "x'y");
+        assertFormatted("0.0;;infinity=\"x'y\"", Double.POSITIVE_INFINITY, "x'y");
+        assertFormatted("0.0;;infinity='x\"\"y'", Double.POSITIVE_INFINITY, "x\"\"y");
+        assertFormatted("0.0;;infinity=\"x''y\"", Double.POSITIVE_INFINITY, "x''y");
+        assertFormatted("0.0;;decimalSeparator=''''", 1, "1'0");
+        assertFormatted("0.0;;decimalSeparator=\"'\"", 1, "1'0");
+        assertFormatted("0.0;;decimalSeparator='\"'", 1, "1\"0");
+        assertFormatted("0.0;;decimalSeparator=\"\"\"\"", 1, "1\"0");
+        
+        try {
+            ExtendedDecimalFormatParser.parse(";;decimalSeparator=D,", LOC);
+            fail();
+        } catch (java.text.ParseException e) {
+            assertThat(e.getMessage(),
+                    allOf(containsStringIgnoringCase("expected a(n) name"), containsString(" end of ")));
+        }
+        try {
+            ExtendedDecimalFormatParser.parse(";;foo=D,", LOC);
+            fail();
+        } catch (java.text.ParseException e) {
+            assertThat(e.getMessage(),
+                    allOf(containsString("\"foo\""), containsString("name")));
+        }
+        try {
+            ExtendedDecimalFormatParser.parse(";;decimalSeparator='D", LOC);
+            fail();
+        } catch (java.text.ParseException e) {
+            assertThat(e.getMessage(),
+                    allOf(containsString("quotation"), containsString("closed")));
+        }
+        try {
+            ExtendedDecimalFormatParser.parse(";;decimalSeparator=\"D", LOC);
+            fail();
+        } catch (java.text.ParseException e) {
+            assertThat(e.getMessage(),
+                    allOf(containsString("quotation"), containsString("closed")));
+        }
+        try {
+            ExtendedDecimalFormatParser.parse(";;decimalSeparator='D'groupingSeparator=G", LOC);
+            fail();
+        } catch (java.text.ParseException e) {
+            assertThat(e.getMessage(), allOf(
+                    containsString("separator"), containsString("whitespace"), containsString("comma")));
+        }
+        try {
+            ExtendedDecimalFormatParser.parse(";;decimalSeparator=., groupingSeparator=G", LOC);
+            fail();
+        } catch (java.text.ParseException e) {
+            assertThat(e.getMessage(), allOf(
+                    containsStringIgnoringCase("expected a(n) value"), containsString("., gr[...]")));
+        }
+        try {
+            ExtendedDecimalFormatParser.parse("0.0;;decimalSeparator=''", LOC);
+            fail();
+        } catch (java.text.ParseException e) {
+            assertThat(e.getMessage(), allOf(
+                    containsStringIgnoringCase("\"decimalSeparator\""), containsString("exactly 1 char")));
+        }
+        try {
+            ExtendedDecimalFormatParser.parse("0.0;;multipier=ten", LOC);
+            fail();
+        } catch (java.text.ParseException e) {
+            assertThat(e.getMessage(), allOf(
+                    containsString("\"multipier\""), containsString("\"ten\""), containsString("integer")));
+        }
+    }
+    
+    @SuppressWarnings("boxing")
+    @Test
+    public void testExtendedParamsEffect() throws ParseException {
+        assertFormatted("0",
+                1.5, "2", 2.5, "2", 3.5, "4", 1.4, "1", 1.6, "2", -1.4, "-1", -1.5, "-2", -2.5, "-2", -1.6, "-2");
+        assertFormatted("0;; roundingMode=halfEven",
+                1.5, "2", 2.5, "2", 3.5, "4", 1.4, "1", 1.6, "2", -1.4, "-1", -1.5, "-2", -2.5, "-2", -1.6, "-2");
+        assertFormatted("0;; roundingMode=halfUp",
+                1.5, "2", 2.5, "3", 3.5, "4", 1.4, "1", 1.6, "2", -1.4, "-1", -1.5, "-2", -2.5, "-3", -1.6, "-2");
+        assertFormatted("0;; roundingMode=halfDown",
+                1.5, "1", 2.5, "2", 3.5, "3", 1.4, "1", 1.6, "2", -1.4, "-1", -1.5, "-1", -2.5, "-2", -1.6, "-2");
+        assertFormatted("0;; roundingMode=floor",
+                1.5, "1", 2.5, "2", 3.5, "3", 1.4, "1", 1.6, "1", -1.4, "-2", -1.5, "-2", -2.5, "-3", -1.6, "-2");
+        assertFormatted("0;; roundingMode=ceiling",
+                1.5, "2", 2.5, "3", 3.5, "4", 1.4, "2", 1.6, "2", -1.4, "-1", -1.5, "-1", -2.5, "-2", -1.6, "-1");
+        assertFormatted("0;; roundingMode=up",
+                1.5, "2", 2.5, "3", 3.5, "4", 1.4, "2", 1.6, "2", -1.4, "-2", -1.5, "-2", -2.5, "-3", -1.6, "-2");
+        assertFormatted("0;; roundingMode=down",
+                1.5, "1", 2.5, "2", 3.5, "3", 1.4, "1", 1.6, "1", -1.4, "-1", -1.5, "-1", -2.5, "-2", -1.6, "-1");
+        assertFormatted("0;; roundingMode=unnecessary", 2, "2");
+        try {
+            assertFormatted("0;; roundingMode=unnecessary", 2.5, "2");
+            fail();
+        } catch (ArithmeticException e) {
+            // Expected
+        }
+
+        assertFormatted("0.##;; multipier=100", 12.345, "1234.5");
+        assertFormatted("0.##;; multipier=1000", 12.345, "12345");
+        
+        assertFormatted(",##0.##;; groupingSeparator=_ decimalSeparator=D", 12345.1, "12_345D1", 1, "1");
+        
+        assertFormatted("0.##E0;; exponentSeparator='*10^'", 12345.1, "1.23*10^4");
+        
+        assertFormatted("0.##;; minusSign=m", -1, "m1", 1, "1");
+        
+        assertFormatted("0.##;; infinity=foo", Double.POSITIVE_INFINITY, "foo", Double.NEGATIVE_INFINITY, "-foo");
+        
+        assertFormatted("0.##;; nan=foo", Double.NaN, "foo");
+        
+        assertFormatted("0%;; percent='c'", 0.75, "75c");
+        
+        assertFormatted("0\u2030;; perMill='m'", 0.75, "750m");
+        
+        assertFormatted("0.00;; zeroDigit='@'", 10.5, "A@.E@");
+        
+        assertFormatted("0;; currencyCode=USD", 10, "10");
+        assertFormatted("0 \u00A4;; currencyCode=USD", 10, "10 $");
+        assertFormatted("0 \u00A4\u00A4;; currencyCode=USD", 10, "10 USD");
+        assertFormatted(Locale.GERMANY, "0 \u00A4;; currencyCode=EUR", 10, "10 \u20AC");
+        assertFormatted(Locale.GERMANY, "0 \u00A4\u00A4;; currencyCode=EUR", 10, "10 EUR");
+        try {
+            assertFormatted("0;; currencyCode=USDX", 10, "10");
+        } catch (ParseException e) {
+            assertThat(e.getMessage(), containsString("ISO 4217"));
+        }
+        assertFormatted("0 \u00A4;; currencyCode=USD currencySymbol=bucks", 10, "10 bucks");
+     // Order doesn't mater:
+        assertFormatted("0 \u00A4;; currencySymbol=bucks currencyCode=USD", 10, "10 bucks");
+        // International symbol isn't affected:
+        assertFormatted("0 \u00A4\u00A4;; currencyCode=USD currencySymbol=bucks", 10, "10 USD");
+        
+        assertFormatted("0.0 \u00A4;; monetaryDecimalSeparator=m", 10.5, "10m5 $");
+        assertFormatted("0.0 kg;; monetaryDecimalSeparator=m", 10.5, "10.5 kg");
+        assertFormatted("0.0 \u00A4;; decimalSeparator=d", 10.5, "10.5 $");
+        assertFormatted("0.0 kg;; decimalSeparator=d", 10.5, "10d5 kg");
+        assertFormatted("0.0 \u00A4;; monetaryDecimalSeparator=m decimalSeparator=d", 10.5, "10m5 $");
+        assertFormatted("0.0 kg;; monetaryDecimalSeparator=m decimalSeparator=d", 10.5, "10d5 kg");
+    }
+    
+    @Test
+    public void testLocale() throws ParseException {
+        assertEquals("1000.0", ExtendedDecimalFormatParser.parse("0.0", Locale.US).format(1000));
+        assertEquals("1000,0", ExtendedDecimalFormatParser.parse("0.0", Locale.FRANCE).format(1000));
+        assertEquals("1_000.0", ExtendedDecimalFormatParser.parse(",000.0;;groupingSeparator=_", Locale.US).format(1000));
+        assertEquals("1_000,0", ExtendedDecimalFormatParser.parse(",000.0;;groupingSeparator=_", Locale.FRANCE).format(1000));
+    }
+    
+    @Test
+    public void testTemplates() throws IOException, TemplateException {
+        TestConfigurationBuilder cfgB = new TestConfigurationBuilder();
+
+        setConfiguration(cfgB.numberFormat(",000.#").build());
+        assertOutput("${1000.15} ${1000.25}", "1,000.2 1,000.2");
+        setConfiguration(cfgB.numberFormat(",000.#;; roundingMode=halfUp groupingSeparator=_").build());;
+        assertOutput("${1000.15} ${1000.25}", "1_000.2 1_000.3");
+        setConfiguration(cfgB.locale(Locale.GERMANY).build());;
+        assertOutput("${1000.15} ${1000.25}", "1_000,2 1_000,3");
+        setConfiguration(cfgB.locale(Locale.US).build());;
+        assertOutput(
+                "${1000.15}; "
+                + "${1000.15?string(',##.#;;groupingSeparator=\" \"')}; "
+                + "<#setting locale='de_DE'>${1000.15}; "
+                + "<#setting numberFormat='0.0;;roundingMode=down'>${1000.15}",
+                "1_000.2; 10 00.2; 1_000,2; 1000,1");
+        assertErrorContains("${1?string('#E')}",
+                TemplateException.class, "\"#E\"", "format string", "exponential");
+        assertErrorContains("<#setting numberFormat='#E'>${1}",
+                TemplateException.class, "\"#E\"", "format string", "exponential");
+        assertErrorContains("<#setting numberFormat=';;foo=bar'>${1}",
+                TemplateException.class, "\"foo\"", "supported");
+        assertErrorContains("<#setting numberFormat='0;;roundingMode=unnecessary'>${1.5}",
+                TemplateException.class, "can't format", "1.5", "UNNECESSARY");
+    }
+
+    private void assertFormatted(String formatString, Object... numberAndExpectedOutput) throws ParseException {
+        assertFormatted(LOC, formatString, numberAndExpectedOutput);
+    }
+    
+    private void assertFormatted(Locale loc, String formatString, Object... numberAndExpectedOutput) throws ParseException {
+        if (numberAndExpectedOutput.length % 2 != 0) {
+            throw new IllegalArgumentException();
+        }
+        
+        DecimalFormat df = ExtendedDecimalFormatParser.parse(formatString, loc);
+        Number num = null;
+        for (int i = 0; i < numberAndExpectedOutput.length; i++) {
+            if (i % 2 == 0) {
+                num = (Number) numberAndExpectedOutput[i];
+            } else {
+                assertEquals(numberAndExpectedOutput[i], df.format(num));
+            }
+        }
+    }
+    
+    private void assertFormatsEquivalent(DecimalFormat dfExpected, DecimalFormat dfActual) {
+        for (int signum : new int[] { 1, -1 }) {
+            assertFormatsEquivalent(dfExpected, dfActual, 0);
+            assertFormatsEquivalent(dfExpected, dfActual, signum * 0.5);
+            assertFormatsEquivalent(dfExpected, dfActual, signum * 0.25);
+            assertFormatsEquivalent(dfExpected, dfActual, signum * 0.125);
+            assertFormatsEquivalent(dfExpected, dfActual, signum);
+            assertFormatsEquivalent(dfExpected, dfActual, signum * 10);
+            assertFormatsEquivalent(dfExpected, dfActual, signum * 100);
+            assertFormatsEquivalent(dfExpected, dfActual, signum * 1000);
+            assertFormatsEquivalent(dfExpected, dfActual, signum * 10000);
+            assertFormatsEquivalent(dfExpected, dfActual, signum * 100000);
+        }
+    }
+
+    private void assertFormatsEquivalent(DecimalFormat dfExpected, DecimalFormat dfActual, double n) {
+        assertEquals(dfExpected.format(n), dfActual.format(n));
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/dom/DOMSiblingTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/dom/DOMSiblingTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/dom/DOMSiblingTest.java
new file mode 100644
index 0000000..56a15eb
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/dom/DOMSiblingTest.java
@@ -0,0 +1,99 @@
+/*
+ * 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.dom;
+
+import java.io.IOException;
+
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.freemarker.core.TemplateException;
+import org.apache.freemarker.test.TemplateTest;
+import org.apache.freemarker.test.XMLLoader;
+import org.junit.Before;
+import org.junit.Test;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+public class DOMSiblingTest extends TemplateTest {
+
+    @Before
+    public void setUp() throws SAXException, IOException, ParserConfigurationException {
+        InputSource is = new InputSource(getClass().getResourceAsStream("DOMSiblingTest.xml"));
+        addToDataModel("doc", XMLLoader.toModel(is));
+    }
+
+    @Test
+    public void testBlankPreviousSibling() throws IOException, TemplateException {
+        assertOutput("${doc.person.name?previousSibling}", "\n    ");
+        assertOutput("${doc.person.name?previous_sibling}", "\n    ");
+    }
+
+    @Test
+    public void testNonBlankPreviousSibling() throws IOException, TemplateException {
+        assertOutput("${doc.person.address?previousSibling}", "12th August");
+    }
+
+    @Test
+    public void testBlankNextSibling() throws IOException, TemplateException {
+        assertOutput("${doc.person.name?nextSibling}", "\n    ");
+        assertOutput("${doc.person.name?next_sibling}", "\n    ");
+    }
+
+    @Test
+    public void testNonBlankNextSibling() throws IOException, TemplateException {
+        assertOutput("${doc.person.dob?nextSibling}", "Chennai, India");
+    }
+
+    @Test
+    public void testNullPreviousSibling() throws IOException, TemplateException {
+        assertOutput("${doc.person?previousSibling?? ?c}", "false");
+    }
+
+    @Test
+    public void testSignificantPreviousSibling() throws IOException, TemplateException {
+        assertOutput("${doc.person.name.@@previous_sibling_element}", "male");
+    }
+
+    @Test
+    public void testSignificantNextSibling() throws IOException, TemplateException {
+        assertOutput("${doc.person.name.@@next_sibling_element}", "12th August");
+    }
+
+    @Test
+    public void testNullSignificantPreviousSibling() throws IOException, TemplateException {
+        assertOutput("${doc.person.phone.@@next_sibling_element?size}", "0");
+    }
+
+    @Test
+    public void testSkippingCommentNode() throws IOException, TemplateException {
+        assertOutput("${doc.person.profession.@@previous_sibling_element}", "Chennai, India");
+    }
+
+    @Test
+    public void testSkippingEmptyCDataNode() throws IOException, TemplateException {
+        assertOutput("${doc.person.hobby.@@previous_sibling_element}", "Software Engineer");
+    }
+
+    @Test
+    public void testValidCDataNode() throws IOException, TemplateException {
+        assertOutput("${doc.person.phone.@@previous_sibling_element?size}", "0");
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/dom/DOMSimplifiersTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/dom/DOMSimplifiersTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/dom/DOMSimplifiersTest.java
new file mode 100644
index 0000000..f135873
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/dom/DOMSimplifiersTest.java
@@ -0,0 +1,201 @@
+/*
+ * 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.dom;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.freemarker.test.XMLLoader;
+import org.junit.Test;
+import org.w3c.dom.CDATASection;
+import org.w3c.dom.Comment;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentType;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.ProcessingInstruction;
+import org.w3c.dom.Text;
+import org.xml.sax.SAXException;
+
+public class DOMSimplifiersTest {
+
+    private static final String COMMON_TEST_XML
+            = "<!DOCTYPE a []><?p?><a>x<![CDATA[y]]><!--c--><?p?>z<?p?><b><!--c--></b><c></c>"
+              + "<d>a<e>c</e>b<!--c--><!--c--><!--c--><?p?><?p?><?p?></d>"
+              + "<f><![CDATA[1]]>2</f></a><!--c-->";
+
+    private static final String TEXT_MERGE_CONTENT =
+            "<a>"
+            + "a<!--c--><s/>"
+            + "<!--c-->a<s/>"
+            + "a<!--c-->b<s/>"
+            + "<!--c-->a<!--c-->b<!--c--><s/>"
+            + "a<b>b</b>c<s/>"
+            + "a<b>b</b><!--c-->c<s/>"
+            + "a<!--c-->1<b>b<!--c--></b>c<!--c-->1<s/>"
+            + "a<!--c-->1<b>b<!--c-->c</b>d<!--c-->1<s/>"
+            + "a<!--c-->1<b>b<!--c-->c</b>d<!--c-->1<s/>"
+            + "a<!--c-->1<b>b<!--c-->1<e>c<!--c-->1</e>d<!--c-->1</b>e<!--c-->1<s/>"
+            + "</a>";
+    private static final String TEXT_MERGE_EXPECTED =
+            "<a>"
+            + "%a<s/>"
+            + "%a<s/>"
+            + "%ab<s/>"
+            + "%ab<s/>"
+            + "%a<b>%b</b>%c<s/>"
+            + "%a<b>%b</b>%c<s/>"
+            + "%a1<b>%b</b>%c1<s/>"
+            + "%a1<b>%bc</b>%d1<s/>"
+            + "%a1<b>%bc</b>%d1<s/>"
+            + "%a1<b>%b1<e>%c1</e>%d1</b>%e1<s/>"
+            + "</a>";
+    
+    @Test
+    public void testTest() throws Exception {
+        String expected = "<!DOCTYPE ...><?p?><a>%x<![CDATA[y]]><!--c--><?p?>%z<?p?><b><!--c--></b><c/>"
+                   + "<d>%a<e>%c</e>%b<!--c--><!--c--><!--c--><?p?><?p?><?p?></d>"
+                   + "<f><![CDATA[1]]>%2</f></a><!--c-->";
+        assertEquals(expected, toString(XMLLoader.toDOM(COMMON_TEST_XML)));
+    }
+
+    @Test
+    public void testMergeAdjacentText() throws Exception {
+        Document dom = XMLLoader.toDOM(COMMON_TEST_XML);
+        NodeModel.mergeAdjacentText(dom);
+        assertEquals(
+                "<!DOCTYPE ...><?p?><a>%xy<!--c--><?p?>%z<?p?><b><!--c--></b><c/>"
+                + "<d>%a<e>%c</e>%b<!--c--><!--c--><!--c--><?p?><?p?><?p?></d>"
+                + "<f><![CDATA[12]]></f></a><!--c-->",
+                toString(dom));
+    }
+
+    @Test
+    public void testRemoveComments() throws Exception {
+        Document dom = XMLLoader.toDOM(COMMON_TEST_XML);
+        NodeModel.removeComments(dom);
+        assertEquals(
+                "<!DOCTYPE ...><?p?><a>%x<![CDATA[y]]><?p?>%z<?p?><b/><c/>"
+                + "<d>%a<e>%c</e>%b<?p?><?p?><?p?></d>"
+                + "<f><![CDATA[1]]>%2</f></a>",
+                toString(dom));
+    }
+
+    @Test
+    public void testRemovePIs() throws Exception {
+        Document dom = XMLLoader.toDOM(COMMON_TEST_XML);
+        NodeModel.removePIs(dom);
+        assertEquals(
+                "<!DOCTYPE ...><a>%x<![CDATA[y]]><!--c-->%z<b><!--c--></b><c/>"
+                + "<d>%a<e>%c</e>%b<!--c--><!--c--><!--c--></d>"
+                + "<f><![CDATA[1]]>%2</f></a><!--c-->",
+                toString(dom));
+    }
+    
+    @Test
+    public void testSimplify() throws Exception {
+        testSimplify(
+                "<!DOCTYPE ...><a>%xyz<b/><c/>"
+                + "<d>%a<e>%c</e>%b</d><f><![CDATA[12]]></f></a>",
+                COMMON_TEST_XML);
+    }
+
+    @Test
+    public void testSimplify2() throws Exception {
+        testSimplify(TEXT_MERGE_EXPECTED, TEXT_MERGE_CONTENT);
+    }
+
+    @Test
+    public void testSimplify3() throws Exception {
+        testSimplify("<a/>", "<a/>");
+    }
+    
+    private void testSimplify(String expected, String content)
+            throws SAXException, IOException, ParserConfigurationException {
+        {
+            Document dom = XMLLoader.toDOM(content);
+            NodeModel.simplify(dom);
+            assertEquals(expected, toString(dom));
+        }
+        
+        // Must be equivalent:
+        {
+            Document dom = XMLLoader.toDOM(content);
+            NodeModel.removeComments(dom);
+            NodeModel.removePIs(dom);
+            NodeModel.mergeAdjacentText(dom);
+            assertEquals(expected, toString(dom));
+        }
+        
+        // Must be equivalent:
+        {
+            Document dom = XMLLoader.toDOM(content);
+            NodeModel.removeComments(dom);
+            NodeModel.removePIs(dom);
+            NodeModel.simplify(dom);
+            assertEquals(expected, toString(dom));
+        }
+    }
+
+    private String toString(Document doc) {
+        StringBuilder sb = new StringBuilder();
+        toString(doc, sb);
+        return sb.toString();
+    }
+
+    private void toString(Node node, StringBuilder sb) {
+        if (node instanceof Document) {
+            childrenToString(node, sb);
+        } else if (node instanceof Element) {
+            if (node.hasChildNodes()) {
+                sb.append("<").append(node.getNodeName()).append(">");
+                childrenToString(node, sb);
+                sb.append("</").append(node.getNodeName()).append(">");
+            } else {
+                sb.append("<").append(node.getNodeName()).append("/>");
+            }
+        } else if (node instanceof Text) {
+            if (node instanceof CDATASection) {
+                sb.append("<![CDATA[").append(node.getNodeValue()).append("]]>");
+            } else {
+                sb.append("%").append(node.getNodeValue());
+            }
+        } else if (node instanceof Comment) {
+            sb.append("<!--").append(node.getNodeValue()).append("-->");
+        } else if (node instanceof ProcessingInstruction) {
+            sb.append("<?").append(node.getNodeName()).append("?>");
+        } else if (node instanceof DocumentType) {
+            sb.append("<!DOCTYPE ...>");
+        } else {
+            throw new IllegalStateException("Unhandled node type: " + node.getClass().getName());
+        }
+    }
+
+    private void childrenToString(Node node, StringBuilder sb) {
+        Node child = node.getFirstChild();
+        while (child != null) {
+            toString(child, sb);
+            child = child.getNextSibling();
+        }
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/dom/DOMTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/dom/DOMTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/dom/DOMTest.java
new file mode 100644
index 0000000..847f503
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/dom/DOMTest.java
@@ -0,0 +1,159 @@
+/*
+ * 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.dom;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.io.StringReader;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.freemarker.core.TemplateException;
+import org.apache.freemarker.test.TemplateTest;
+import org.apache.freemarker.test.XMLLoader;
+import org.junit.Test;
+import org.w3c.dom.Document;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+public class DOMTest extends TemplateTest {
+
+    @Test
+    public void xpathDetectionBugfix() throws Exception {
+        addDocToDataModel("<root><a>A</a><b>B</b><c>C</c></root>");
+        assertOutput("${doc.root.b['following-sibling::c']}", "C");
+        assertOutput("${doc.root.b['following-sibling::*']}", "C");
+    }
+
+    @Test
+    public void xmlnsPrefixes() throws Exception {
+        addDocToDataModel("<root xmlns='http://example.com/ns1' xmlns:ns2='http://example.com/ns2'>"
+                + "<a>A</a><ns2:b>B</ns2:b><c a1='1' ns2:a2='2'/></root>");
+
+        String ftlHeader = "<#ftl ns_prefixes={'D':'http://example.com/ns1', 'n2':'http://example.com/ns2'}>";
+        
+        // @@markup:
+        assertOutput("${doc.@@markup}",
+                "<a:root xmlns:a=\"http://example.com/ns1\" xmlns:b=\"http://example.com/ns2\">"
+                + "<a:a>A</a:a><b:b>B</b:b><a:c a1=\"1\" b:a2=\"2\" />"
+                + "</a:root>");
+        assertOutput(ftlHeader
+                + "${doc.@@markup}",
+                "<root xmlns=\"http://example.com/ns1\" xmlns:n2=\"http://example.com/ns2\">"
+                + "<a>A</a><n2:b>B</n2:b><c a1=\"1\" n2:a2=\"2\" /></root>");
+        assertOutput("<#ftl ns_prefixes={'D':'http://example.com/ns1'}>"
+                + "${doc.@@markup}",
+                "<root xmlns=\"http://example.com/ns1\" xmlns:a=\"http://example.com/ns2\">"
+                + "<a>A</a><a:b>B</a:b><c a1=\"1\" a:a2=\"2\" /></root>");
+        
+        // When there's no matching prefix declared via the #ftl header, return null for qname:
+        assertOutput("${doc?children[0].@@qname!'null'}", "null");
+        assertOutput("${doc?children[0]?children[1].@@qname!'null'}", "null");
+        assertOutput("${doc?children[0]?children[2]['@*'][1].@@qname!'null'}", "null");
+        
+        // When we have prefix declared in the #ftl header:
+        assertOutput(ftlHeader + "${doc?children[0].@@qname}", "root");
+        assertOutput(ftlHeader + "${doc?children[0]?children[1].@@qname}", "n2:b");
+        assertOutput(ftlHeader + "${doc?children[0]?children[2].@@qname}", "c");
+        assertOutput(ftlHeader + "${doc?children[0]?children[2]['@*'][0].@@qname}", "a1");
+        assertOutput(ftlHeader + "${doc?children[0]?children[2]['@*'][1].@@qname}", "n2:a2");
+        // Unfortunately these include the xmlns attributes, but that would be non-BC to fix now:
+        assertThat(getOutput(ftlHeader + "${doc?children[0].@@start_tag}"), startsWith("<root"));
+        assertThat(getOutput(ftlHeader + "${doc?children[0]?children[1].@@start_tag}"), startsWith("<n2:b"));
+    }
+    
+    @Test
+    public void namespaceUnaware() throws Exception {
+        addNSUnawareDocToDataModel("<root><x:a>A</x:a><:>B</:><xyz::c>C</xyz::c></root>");
+        assertOutput("${doc.root['x:a']}", "A");
+        assertOutput("${doc.root[':']}", "B");
+        try {
+            assertOutput("${doc.root['xyz::c']}", "C");
+            fail();
+        } catch (TemplateException e) {
+            assertThat(e.getMessage(), containsString("xyz"));
+        }
+    }
+    
+    private void addDocToDataModel(String xml) throws SAXException, IOException, ParserConfigurationException {
+        addToDataModel("doc", XMLLoader.toModel(new InputSource(new StringReader(xml))));
+    }
+
+    private void addDocToDataModelNoSimplification(String xml) throws SAXException, IOException, ParserConfigurationException {
+        addToDataModel("doc", XMLLoader.toModel(new InputSource(new StringReader(xml)), false));
+    }
+    
+    private void addNSUnawareDocToDataModel(String xml) throws ParserConfigurationException, SAXException, IOException {
+        DocumentBuilderFactory newFactory = DocumentBuilderFactory.newInstance();
+        newFactory.setNamespaceAware(false);
+        DocumentBuilder builder = newFactory.newDocumentBuilder();
+        Document doc = builder.parse(new InputSource(new StringReader(xml)));
+        addToDataModel("doc", doc);
+    }
+
+    @Test
+    public void testInvalidAtAtKeyErrors() throws Exception {
+        addDocToDataModel("<r><multipleMatches /><multipleMatches /></r>");
+        assertErrorContains("${doc.r.@@invalid_key}", "Unsupported @@ key", "@invalid_key");
+        assertErrorContains("${doc.@@start_tag}", "@@start_tag", "not supported", "document");
+        assertErrorContains("${doc.@@}", "\"@@\"", "not supported", "document");
+        assertErrorContains("${doc.r.noMatch.@@invalid_key}", "Unsupported @@ key", "@invalid_key");
+        assertErrorContains("${doc.r.multipleMatches.@@invalid_key}", "Unsupported @@ key", "@invalid_key");
+        assertErrorContains("${doc.r.noMatch.@@attributes_markup}", "single XML node", "@@attributes_markup");
+        assertErrorContains("${doc.r.multipleMatches.@@attributes_markup}", "single XML node", "@@attributes_markup");
+    }
+    
+    @Test
+    public void testAtAtSiblingElement() throws Exception {
+        addDocToDataModel("<r><a/><b/></r>");
+        assertOutput("${doc.r.@@previous_sibling_element?size}", "0");
+        assertOutput("${doc.r.@@next_sibling_element?size}", "0");
+        assertOutput("${doc.r.a.@@previous_sibling_element?size}", "0");
+        assertOutput("${doc.r.a.@@next_sibling_element.@@qname}", "b");
+        assertOutput("${doc.r.b.@@previous_sibling_element.@@qname}", "a");
+        assertOutput("${doc.r.b.@@next_sibling_element?size}", "0");
+        
+        addDocToDataModel("<r>\r\n\t <a/>\r\n\t <b/>\r\n\t </r>");
+        assertOutput("${doc.r.@@previous_sibling_element?size}", "0");
+        assertOutput("${doc.r.@@next_sibling_element?size}", "0");
+        assertOutput("${doc.r.a.@@previous_sibling_element?size}", "0");
+        assertOutput("${doc.r.a.@@next_sibling_element.@@qname}", "b");
+        assertOutput("${doc.r.b.@@previous_sibling_element.@@qname}", "a");
+        assertOutput("${doc.r.b.@@next_sibling_element?size}", "0");
+        
+        addDocToDataModel("<r>t<a/>t<b/>t</r>");
+        assertOutput("${doc.r.a.@@previous_sibling_element?size}", "0");
+        assertOutput("${doc.r.a.@@next_sibling_element?size}", "0");
+        assertOutput("${doc.r.b.@@previous_sibling_element?size}", "0");
+        assertOutput("${doc.r.b.@@next_sibling_element?size}", "0");
+        
+        addDocToDataModelNoSimplification("<r><a/> <!-- --><?pi?>&#x20;<b/></r>");
+        assertOutput("${doc.r.a.@@next_sibling_element.@@qname}", "b");
+        assertOutput("${doc.r.b.@@previous_sibling_element.@@qname}", "a");
+        
+        addDocToDataModelNoSimplification("<r><a/> <!-- -->t<!-- --> <b/></r>");
+        assertOutput("${doc.r.a.@@next_sibling_element?size}", "0");
+        assertOutput("${doc.r.b.@@previous_sibling_element?size}", "0");
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/manualtest/AutoEscapingExample.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/manualtest/AutoEscapingExample.java b/freemarker-core-test/src/test/java/org/apache/freemarker/manualtest/AutoEscapingExample.java
new file mode 100644
index 0000000..036bace
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/manualtest/AutoEscapingExample.java
@@ -0,0 +1,72 @@
+/*
+ * 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.manualtest;
+
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.test.TemplateTest;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+import org.junit.Test;
+
+public class AutoEscapingExample extends TemplateTest {
+
+    @Test
+    public void testInfoBox() throws Exception {
+        assertOutputForNamed("AutoEscapingExample-infoBox.ftlh");
+    }
+
+    @Test
+    public void testCapture() throws Exception {
+        assertOutputForNamed("AutoEscapingExample-capture.ftlh");
+    }
+
+    @Test
+    public void testMarkup() throws Exception {
+        assertOutputForNamed("AutoEscapingExample-markup.ftlh");
+    }
+
+    @Test
+    public void testConvert() throws Exception {
+        assertOutputForNamed("AutoEscapingExample-convert.ftlh");
+    }
+
+    @Test
+    public void testConvert2() throws Exception {
+        assertOutputForNamed("AutoEscapingExample-convert2.ftl");
+    }
+
+    @Test
+    public void testStringLiteral() throws Exception {
+        assertOutputForNamed("AutoEscapingExample-stringLiteral.ftlh");
+    }
+
+    @Test
+    public void testStringLiteral2() throws Exception {
+        assertOutputForNamed("AutoEscapingExample-stringLiteral2.ftlh");
+    }
+
+    @Test
+    public void testStringConcat() throws Exception {
+        assertOutputForNamed("AutoEscapingExample-stringConcat.ftlh");
+    }
+
+    @Override
+    protected Configuration createDefaultConfiguration() throws Exception {
+        return new TestConfigurationBuilder(AutoEscapingExample.class).build();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/manualtest/ConfigureOutputFormatExamples.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/manualtest/ConfigureOutputFormatExamples.java b/freemarker-core-test/src/test/java/org/apache/freemarker/manualtest/ConfigureOutputFormatExamples.java
new file mode 100644
index 0000000..40c1297
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/manualtest/ConfigureOutputFormatExamples.java
@@ -0,0 +1,105 @@
+/*
+ * 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.manualtest;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+
+import org.apache.freemarker.core.TemplateConfiguration;
+import org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat;
+import org.apache.freemarker.core.outputformat.impl.RTFOutputFormat;
+import org.apache.freemarker.core.outputformat.impl.XMLOutputFormat;
+import org.apache.freemarker.core.templateresolver.ConditionalTemplateConfigurationFactory;
+import org.apache.freemarker.core.templateresolver.FileExtensionMatcher;
+import org.apache.freemarker.core.templateresolver.FirstMatchTemplateConfigurationFactory;
+import org.apache.freemarker.core.templateresolver.OrMatcher;
+import org.apache.freemarker.core.templateresolver.PathGlobMatcher;
+import org.apache.freemarker.test.TemplateTest;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+import org.junit.Test;
+
+public class ConfigureOutputFormatExamples extends TemplateTest {
+    
+    @Test
+    public void test() throws Exception {
+        addTemplate("mail/t.ftl", "");
+        addTemplate("t.html", "");
+        addTemplate("t.htm", "");
+        addTemplate("t.xml", "");
+        addTemplate("t.rtf", "");
+
+        example2(true);
+        example2(false);
+        example3(true);
+        example3(false);
+    }
+
+    private void example2(boolean javaCfg) throws IOException {
+        setConfiguration(
+                javaCfg
+                        ? new TestConfigurationBuilder()
+                                .templateConfigurations(
+                                        new ConditionalTemplateConfigurationFactory(
+                                                new PathGlobMatcher("mail/**"),
+                                                new TemplateConfiguration.Builder()
+                                                        .outputFormat(HTMLOutputFormat.INSTANCE)
+                                                        .build()))
+                                .build()
+                        : new TestConfigurationBuilder()
+                                .settings(loadPropertiesFile("ConfigureOutputFormatExamples1.properties"))
+                                .build());
+        assertEquals(HTMLOutputFormat.INSTANCE, getConfiguration().getTemplate("mail/t.ftl").getOutputFormat());
+    }
+
+    private void example3(boolean javaCfg) throws IOException {
+        setConfiguration(
+                javaCfg
+                        ? new TestConfigurationBuilder()
+                                .templateConfigurations(
+                                        new FirstMatchTemplateConfigurationFactory(
+                                                new ConditionalTemplateConfigurationFactory(
+                                                        new FileExtensionMatcher("xml"),
+                                                        new TemplateConfiguration.Builder()
+                                                                .outputFormat(XMLOutputFormat.INSTANCE)
+                                                                .build()),
+                                                new ConditionalTemplateConfigurationFactory(
+                                                        new OrMatcher(
+                                                                new FileExtensionMatcher("html"),
+                                                                new FileExtensionMatcher("htm")),
+                                                        new TemplateConfiguration.Builder()
+                                                                .outputFormat(HTMLOutputFormat.INSTANCE)
+                                                                .build()),
+                                                new ConditionalTemplateConfigurationFactory(
+                                                        new FileExtensionMatcher("rtf"),
+                                                        new TemplateConfiguration.Builder()
+                                                                .outputFormat(RTFOutputFormat.INSTANCE)
+                                                                .build()))
+                                        .allowNoMatch(true))
+                                .build()
+                        : new TestConfigurationBuilder()
+                                .settings(loadPropertiesFile("ConfigureOutputFormatExamples2.properties"))
+                                .build());
+        assertEquals(HTMLOutputFormat.INSTANCE, getConfiguration().getTemplate("t.html").getOutputFormat());
+        assertEquals(HTMLOutputFormat.INSTANCE, getConfiguration().getTemplate("t.htm").getOutputFormat());
+        assertEquals(XMLOutputFormat.INSTANCE, getConfiguration().getTemplate("t.xml").getOutputFormat());
+        assertEquals(RTFOutputFormat.INSTANCE, getConfiguration().getTemplate("t.rtf").getOutputFormat());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/manualtest/CustomFormatsExample.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/manualtest/CustomFormatsExample.java b/freemarker-core-test/src/test/java/org/apache/freemarker/manualtest/CustomFormatsExample.java
new file mode 100644
index 0000000..f38bb14
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/manualtest/CustomFormatsExample.java
@@ -0,0 +1,84 @@
+/*
+ * 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.manualtest;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.util.Date;
+
+import org.apache.freemarker.core.TemplateException;
+import org.apache.freemarker.core.userpkg.BaseNTemplateNumberFormatFactory;
+import org.apache.freemarker.core.valueformat.TemplateDateFormatFactory;
+import org.apache.freemarker.core.valueformat.TemplateNumberFormatFactory;
+import org.apache.freemarker.core.valueformat.impl.AliasTemplateDateFormatFactory;
+import org.apache.freemarker.core.valueformat.impl.AliasTemplateNumberFormatFactory;
+import org.apache.freemarker.test.TemplateTest;
+import org.apache.freemarker.test.TestConfigurationBuilder;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableMap;
+
+@SuppressWarnings("boxing")
+public class CustomFormatsExample extends TemplateTest {
+
+    @Test
+    public void aliases1() throws IOException, TemplateException {
+        setConfiguration(new TestConfigurationBuilder(this.getClass())
+            .customNumberFormats(ImmutableMap.<String, TemplateNumberFormatFactory>of(
+                    "price", new AliasTemplateNumberFormatFactory(",000.00"),
+                    "weight", new AliasTemplateNumberFormatFactory("0.##;; roundingMode=halfUp")))
+            .customDateFormats(ImmutableMap.<String, TemplateDateFormatFactory>of(
+                    "fileDate", new AliasTemplateDateFormatFactory("dd/MMM/yy hh:mm a"),
+                    "logEventTime", new AliasTemplateDateFormatFactory("iso ms u")
+                    ))
+            .build());
+
+        addToDataModel("p", 10000);
+        addToDataModel("w", new BigDecimal("10.305"));
+        addToDataModel("fd", new Date(1450904944213L));
+        addToDataModel("let", new Date(1450904944213L));
+        
+        assertOutputForNamed("CustomFormatsExample-alias1.ftlh");
+    }
+
+    @Test
+    public void aliases2() throws IOException, TemplateException {
+        setConfiguration(new TestConfigurationBuilder(this.getClass())
+                .customNumberFormats(ImmutableMap.of(
+                        "base", BaseNTemplateNumberFormatFactory.INSTANCE,
+                        "oct", new AliasTemplateNumberFormatFactory("@base 8")))
+                .build());
+
+        assertOutputForNamed("CustomFormatsExample-alias2.ftlh");
+    }
+
+    @Test
+    public void modelAware() throws IOException, TemplateException {
+        setConfiguration(new TestConfigurationBuilder(this.getClass())
+                .customNumberFormats(ImmutableMap.<String, TemplateNumberFormatFactory>of(
+                        "ua", UnitAwareTemplateNumberFormatFactory.INSTANCE))
+                .numberFormat("@ua 0.####;; roundingMode=halfUp")
+                .build());
+
+        addToDataModel("weight", new UnitAwareTemplateNumberModel(1.5, "kg"));
+        
+        assertOutputForNamed("CustomFormatsExample-modelAware.ftlh");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core-test/src/test/java/org/apache/freemarker/manualtest/GettingStartedExample.java
----------------------------------------------------------------------
diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/manualtest/GettingStartedExample.java b/freemarker-core-test/src/test/java/org/apache/freemarker/manualtest/GettingStartedExample.java
new file mode 100644
index 0000000..a676bc4
--- /dev/null
+++ b/freemarker-core-test/src/test/java/org/apache/freemarker/manualtest/GettingStartedExample.java
@@ -0,0 +1,69 @@
+/*
+ * 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.manualtest;
+
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.Template;
+import org.apache.freemarker.core.TemplateExceptionHandler;
+import org.apache.freemarker.core.templateresolver.impl.ClassTemplateLoader;
+import org.junit.Test;
+
+public class GettingStartedExample {
+
+    @Test
+    public void main() throws Exception {
+        /* ------------------------------------------------------------------------ */    
+        /* You should do this ONLY ONCE in the whole application life-cycle:        */    
+    
+        /* Create the configuration singleton (using builder pattern) */
+        Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0)
+                .templateLoader(new ClassTemplateLoader(GettingStartedExample.class, ""))
+                .sourceEncoding(StandardCharsets.UTF_8)
+                .templateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER)
+                .logTemplateExceptions(false)
+                .build();
+
+        /* ------------------------------------------------------------------------ */    
+        /* You usually do these for MULTIPLE TIMES in the application life-cycle:   */    
+
+        /* Create a data-model */
+        Map<String, Object> root = new HashMap();
+        root.put("user", "Big Joe");
+        Product latest = new Product();
+        latest.setUrl("products/greenmouse.html");
+        latest.setName("green mouse");
+        root.put("latestProduct", latest);
+
+        /* Get the template (uses cache internally) */
+        Template temp = cfg.getTemplate("test.ftlh");
+
+        /* Merge data-model with template */
+        Writer out = new OutputStreamWriter(System.out);
+        temp.process(root, out);
+        // Note: Depending on what `out` is, you may need to call `out.close()`.
+        // This is usually the case for file output, but not for servlet output.
+    }
+    
+}



[16/51] [abbrv] [partial] incubator-freemarker git commit: Restructured project so that freemarker-test-utils depends on freemarker-core (and hence can provide common classes for testing templates, and can use utility classes defined in the core). As a c

Posted by dd...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/TemplateGetEncodingTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/TemplateGetEncodingTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/TemplateGetEncodingTest.java
deleted file mode 100644
index 4b5bf59..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/TemplateGetEncodingTest.java
+++ /dev/null
@@ -1,64 +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;
-
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.nio.charset.Charset;
-
-import org.apache.freemarker.core.templateresolver.ConditionalTemplateConfigurationFactory;
-import org.apache.freemarker.core.templateresolver.FileNameGlobMatcher;
-import org.apache.freemarker.core.templateresolver.impl.StrongCacheStorage;
-import org.apache.freemarker.test.MonitoredTemplateLoader;
-import org.junit.Test;
-
-public class TemplateGetEncodingTest {
-
-    private static final Charset ISO_8859_2 = Charset.forName("ISO-8859-2");
-
-    @Test
-    public void test() throws IOException {
-        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
-        {
-            cfgB.setSourceEncoding(ISO_8859_2);
-            MonitoredTemplateLoader tl = new MonitoredTemplateLoader();
-            tl.putBinaryTemplate("bin", "test");
-            tl.putBinaryTemplate("bin-static", "<#test>");
-            tl.putTextTemplate("text", "test");
-            tl.putTextTemplate("text-static", "<#test>");
-            TemplateConfiguration.Builder staticTextTCB = new TemplateConfiguration.Builder();
-            staticTextTCB.setTemplateLanguage(TemplateLanguage.STATIC_TEXT);
-            cfgB.setTemplateConfigurations(
-                    new ConditionalTemplateConfigurationFactory(
-                            new FileNameGlobMatcher("*-static*"), staticTextTCB.build()));
-            cfgB.setTemplateLoader(tl);
-            cfgB.setCacheStorage(new StrongCacheStorage());
-        }
-
-        Configuration cfg = cfgB.build();
-        assertEquals(ISO_8859_2, cfg.getTemplate("bin").getActualSourceEncoding());
-        assertEquals(ISO_8859_2, cfg.getTemplate("bin-static").getActualSourceEncoding());
-        assertNull(cfg.getTemplate("text").getActualSourceEncoding());
-        assertNull(cfg.getTemplate("text-static").getActualSourceEncoding());
-        assertNull(new Template(null, "test", cfg).getActualSourceEncoding());
-        assertNull(Template.createPlainTextTemplate(null, "<#test>", cfg).getActualSourceEncoding());
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/TemplateLookupStrategyTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/TemplateLookupStrategyTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/TemplateLookupStrategyTest.java
deleted file mode 100644
index f0e63a8..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/TemplateLookupStrategyTest.java
+++ /dev/null
@@ -1,669 +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;
-
-import static org.apache.freemarker.core.Configuration.ExtendableBuilder.TEMPLATE_LOOKUP_STRATEGY_KEY;
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.io.Serializable;
-import java.io.StringWriter;
-import java.util.Locale;
-
-import org.apache.freemarker.core.templateresolver.TemplateLookupContext;
-import org.apache.freemarker.core.templateresolver.TemplateLookupResult;
-import org.apache.freemarker.core.templateresolver.TemplateLookupStrategy;
-import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateLookupStrategy;
-import org.apache.freemarker.test.MonitoredTemplateLoader;
-import org.junit.Test;
-
-import com.google.common.collect.ImmutableList;
-
-public class TemplateLookupStrategyTest {
-
-    @Test
-    public void testSetSetting() throws Exception {
-        assertSame(
-                DefaultTemplateLookupStrategy.INSTANCE,
-                new Configuration.Builder(Configuration.VERSION_3_0_0).build()
-                        .getTemplateLookupStrategy());
-
-        assertTrue(
-                new Configuration.Builder(Configuration.VERSION_3_0_0)
-                        .setting(TEMPLATE_LOOKUP_STRATEGY_KEY, MyTemplateLookupStrategy.class.getName() + "()")
-                        .build()
-                        .getTemplateLookupStrategy() instanceof MyTemplateLookupStrategy);
-        
-        assertSame(
-                DefaultTemplateLookupStrategy.INSTANCE,
-                new Configuration.Builder(Configuration.VERSION_3_0_0)
-                        .setting(TEMPLATE_LOOKUP_STRATEGY_KEY, "dEfault")
-                        .build()
-                        .getTemplateLookupStrategy());
-    }
-    
-    @Test
-    public void testCustomStrategy() throws IOException {
-        MonitoredTemplateLoader tl = new MonitoredTemplateLoader();
-        tl.putTextTemplate("test.ftl", "");
-        tl.putTextTemplate("aa/test.ftl", "");
-
-        Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0)
-                .templateLoader(tl)
-                .templateLookupStrategy(MyTemplateLookupStrategy.INSTANCE)
-                .build();
-        
-        final Locale locale = new Locale("aa", "BB", "CC_DD");
-        
-        try {
-            cfg.getTemplate("missing.ftl", locale);
-            fail();
-        } catch (TemplateNotFoundException e) {
-            assertEquals("missing.ftl", e.getTemplateName());
-            assertEquals(ImmutableList.of("aa/missing.ftl", "missing.ftl"), tl.getLoadNames());
-            tl.clearEvents();
-            cfg.clearTemplateCache();
-        }
-        
-        {
-            final Template t = cfg.getTemplate("test.ftl", locale);
-            assertEquals("test.ftl", t.getLookupName());
-            assertEquals("aa/test.ftl", t.getSourceName());
-            assertEquals(locale, t.getLocale());
-            assertNull(t.getCustomLookupCondition());
-            assertEquals(ImmutableList.of("aa/test.ftl"), tl.getLoadNames());
-            tl.clearEvents();
-            cfg.clearTemplateCache();
-        }
-    }
-    
-    @Test
-    public void testDefaultStrategy() throws IOException {
-        MonitoredTemplateLoader tl = new MonitoredTemplateLoader();
-        tl.putTextTemplate("test.ftl", "");
-        tl.putTextTemplate("test_aa.ftl", "");
-        tl.putTextTemplate("test_aa_BB.ftl", "");
-        tl.putTextTemplate("test_aa_BB_CC.ftl", "");
-        tl.putTextTemplate("test_aa_BB_CC_DD.ftl", "");
-
-        try {
-            new Configuration.Builder(Configuration.VERSION_3_0_0).templateLoader(tl).build()
-                    .getTemplate("missing.ftl", new Locale("aa", "BB", "CC_DD"));
-            fail();
-        } catch (TemplateNotFoundException e) {
-            assertEquals("missing.ftl", e.getTemplateName());
-            assertEquals(
-                    ImmutableList.of(
-                            "missing_aa_BB_CC_DD.ftl",
-                            "missing_aa_BB_CC.ftl",
-                            "missing_aa_BB.ftl",
-                            "missing_aa.ftl",
-                            "missing.ftl"),
-                    tl.getLoadNames());
-            tl.clearEvents();
-        }
-
-        try {
-            new Configuration.Builder(Configuration.VERSION_3_0_0).templateLoader(tl)
-                    .locale(new Locale("xx")).build()
-                    .getTemplate("missing.ftl");
-            fail();
-        } catch (TemplateNotFoundException e) {
-            assertEquals("missing.ftl", e.getTemplateName());
-            assertEquals(
-                    ImmutableList.of("missing_xx.ftl", "missing.ftl"),
-                    tl.getLoadNames());
-            tl.clearEvents();
-        }
-        
-        try {
-            new Configuration.Builder(Configuration.VERSION_3_0_0).templateLoader(tl)
-                    .locale(new Locale("xx"))
-                    .localizedLookup(false).build()
-                    .getTemplate("missing.ftl");
-            fail();
-        } catch (TemplateNotFoundException e) {
-            assertEquals("missing.ftl", e.getTemplateName());
-            assertEquals(
-                    ImmutableList.of("missing.ftl"),
-                    tl.getLoadNames());
-            tl.clearEvents();
-        }
-
-        try {
-            new Configuration.Builder(Configuration.VERSION_3_0_0).templateLoader(tl).build()
-                    .getTemplate("_a_b_.ftl", new Locale("xx", "yy"));
-            fail();
-        } catch (TemplateNotFoundException e) {
-            assertEquals("_a_b_.ftl", e.getTemplateName());
-            assertEquals(
-                    ImmutableList.of("_a_b__xx_YY.ftl", "_a_b__xx.ftl", "_a_b_.ftl"),
-                    tl.getLoadNames());
-            tl.clearEvents();
-        }
-
-        for (String templateName : new String[] { "test.ftl", "./test.ftl", "/test.ftl", "x/foo/../../test.ftl" }) {
-            {
-                final Locale locale = new Locale("aa", "BB", "CC_DD");
-                final Template t = new Configuration.Builder(Configuration.VERSION_3_0_0).templateLoader(tl).build()
-                        .getTemplate("test.ftl", locale);
-                assertEquals("test.ftl", t.getLookupName());
-                assertEquals("test_aa_BB_CC_DD.ftl", t.getSourceName());
-                assertEquals(locale, t.getLocale());
-                assertNull(t.getCustomLookupCondition());
-                assertEquals(ImmutableList.of("test_aa_BB_CC_DD.ftl"), tl.getLoadNames());
-                assertNull(t.getCustomLookupCondition());
-                tl.clearEvents();
-            }
-            
-            {
-                final Locale locale = new Locale("aa", "BB", "CC_XX");
-                final Template t = new Configuration.Builder(Configuration.VERSION_3_0_0).templateLoader(tl).build()
-                        .getTemplate(templateName, locale);
-                assertEquals("test.ftl", t.getLookupName());
-                assertEquals("test_aa_BB_CC.ftl", t.getSourceName());
-                assertEquals(locale, t.getLocale());
-                assertNull(t.getCustomLookupCondition());
-                assertEquals(ImmutableList.of("test_aa_BB_CC_XX.ftl", "test_aa_BB_CC.ftl"), tl.getLoadNames());
-                tl.clearEvents();
-            }
-            
-            {
-                final Locale locale = new Locale("aa", "BB", "XX_XX");
-                final Template t = new Configuration.Builder(Configuration.VERSION_3_0_0).templateLoader(tl).build()
-                        .getTemplate(templateName, locale);
-                assertEquals("test.ftl", t.getLookupName());
-                assertEquals("test_aa_BB.ftl", t.getSourceName());
-                assertEquals(locale, t.getLocale());
-                assertNull(t.getCustomLookupCondition());
-                assertEquals(
-                        ImmutableList.of("test_aa_BB_XX_XX.ftl", "test_aa_BB_XX.ftl", "test_aa_BB.ftl"),
-                        tl.getLoadNames());
-                tl.clearEvents();
-            }
-    
-            {
-                final Locale locale = new Locale("aa", "BB", "XX_XX");
-                final Template t = new Configuration.Builder(Configuration.VERSION_3_0_0).templateLoader(tl)
-                        .localizedLookup(false).build()
-                        .getTemplate(templateName, locale);
-                assertEquals("test.ftl", t.getLookupName());
-                assertEquals("test.ftl", t.getSourceName());
-                assertEquals(locale, t.getLocale());
-                assertNull(t.getCustomLookupCondition());
-                assertEquals(
-                        ImmutableList.of("test.ftl"),
-                        tl.getLoadNames());
-                tl.clearEvents();
-            }
-    
-            {
-                final Locale locale = new Locale("aa", "XX", "XX_XX");
-                final Template t = new Configuration.Builder(Configuration.VERSION_3_0_0).templateLoader(tl).build()
-                        .getTemplate(templateName, locale);
-                assertEquals("test.ftl", t.getLookupName());
-                assertEquals("test_aa.ftl", t.getSourceName());
-                assertEquals(locale, t.getLocale());
-                assertNull(t.getCustomLookupCondition());
-                assertEquals(
-                        ImmutableList.of("test_aa_XX_XX_XX.ftl", "test_aa_XX_XX.ftl", "test_aa_XX.ftl", "test_aa.ftl"),
-                        tl.getLoadNames());
-                tl.clearEvents();
-            }
-            
-            {
-                final Locale locale = new Locale("xx", "XX", "XX_XX");
-                final Template t = new Configuration.Builder(Configuration.VERSION_3_0_0).templateLoader(tl).build()
-                        .getTemplate(templateName, locale);
-                assertEquals("test.ftl", t.getLookupName());
-                assertEquals("test.ftl", t.getSourceName());
-                assertEquals(locale, t.getLocale());
-                assertNull(t.getCustomLookupCondition());
-                assertEquals(
-                        ImmutableList.of(
-                                "test_xx_XX_XX_XX.ftl", "test_xx_XX_XX.ftl", "test_xx_XX.ftl", "test_xx.ftl", "test.ftl"),
-                        tl.getLoadNames());
-                tl.clearEvents();
-            }
-            
-            {
-                final Locale locale = new Locale("xx", "BB", "CC_DD");
-                final Template t = new Configuration.Builder(Configuration.VERSION_3_0_0).templateLoader(tl).build()
-                        .getTemplate(templateName, locale);
-                assertEquals("test.ftl", t.getLookupName());
-                assertEquals("test.ftl", t.getSourceName());
-                assertEquals(locale, t.getLocale());
-                assertNull(t.getCustomLookupCondition());
-                assertEquals(
-                        ImmutableList.of(
-                            "test_xx_BB_CC_DD.ftl", "test_xx_BB_CC.ftl", "test_xx_BB.ftl", "test_xx.ftl", "test.ftl"),
-                        tl.getLoadNames());
-                tl.clearEvents();
-            }
-        }
-    }
-    
-    @Test
-    public void testAcquisition() throws IOException {
-        MonitoredTemplateLoader tl = new MonitoredTemplateLoader();
-        tl.putTextTemplate("t.ftl", "");
-        tl.putTextTemplate("sub/i.ftl", "");
-        tl.putTextTemplate("x/sub/i.ftl", "");
-
-        Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0).templateLoader(tl).build();
-
-        final Locale locale = new Locale("xx");
-        
-        {
-            final Template t = cfg.getTemplate("/./moo/../x/y/*/sub/i.ftl", locale);
-            assertEquals("x/y/*/sub/i.ftl", t.getLookupName());
-            assertEquals("x/sub/i.ftl", t.getSourceName());
-            assertEquals(locale, t.getLocale());
-            assertNull(t.getCustomLookupCondition());
-            assertEquals(
-                    ImmutableList.of(
-                        "x/y/sub/i_xx.ftl", "x/sub/i_xx.ftl", "sub/i_xx.ftl",
-                        "x/y/sub/i.ftl", "x/sub/i.ftl"),
-                    tl.getLoadNames());
-            tl.clearEvents();
-            cfg.clearTemplateCache();
-        }
-
-        {
-            final Template t = cfg.getTemplate("a/b/*/./sub/i.ftl", locale);
-            assertEquals("a/b/*/sub/i.ftl", t.getLookupName());
-            assertEquals("sub/i.ftl", t.getSourceName());
-            assertEquals(locale, t.getLocale());
-            assertNull(t.getCustomLookupCondition());
-            assertEquals(
-                    ImmutableList.of(
-                        "a/b/sub/i_xx.ftl", "a/sub/i_xx.ftl", "sub/i_xx.ftl",
-                        "a/b/sub/i.ftl", "a/sub/i.ftl", "sub/i.ftl"),
-                    tl.getLoadNames());
-            tl.clearEvents();
-            cfg.clearTemplateCache();
-        }
-    }
-
-    @Test
-    public void testCustomLookupCondition() throws IOException, TemplateException {
-        MonitoredTemplateLoader tl = new MonitoredTemplateLoader();
-
-        final Configuration cfg;
-        final Configuration cfgNoLocLU;
-        {
-            Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0)
-                    .templateLoader(tl)
-                    .templateLookupStrategy(new DomainTemplateLookupStrategy());
-            cfg = cfgB.build();
-            cfgNoLocLU = cfgB.localizedLookup(false).build();
-        }
-
-        final String iAtDefaultContent = "i at default";
-        final String iXxAtDefaultContent = "i_xx at default";
-        final String iAtBaazComContent = "i at baaz.com";
-        final String iAtFooComContent = "i at foo.com";
-        final String tAtDefaultWithoutIncludeContent = "t at default ";
-        final String tAtDefaultContent = toCanonicalFTL(tAtDefaultWithoutIncludeContent + "<#include 'i.ftl'>", cfg);
-        final String tAtBarComWithoutIncludeContent = "t at bar.com ";
-        final String tAtBarComContent = toCanonicalFTL(tAtBarComWithoutIncludeContent + "<#include 'i.ftl'>", cfg);
-        final String tAtFooComWithoutIncludeContent = "t at foo.com ";
-        final String tAtFooComContent = toCanonicalFTL(tAtFooComWithoutIncludeContent + "<#include 'i.ftl'>", cfg);
-        final String t2XxLocaleExpectedOutput = "i3_xx at foo.com";
-        final String t2OtherLocaleExpectedOutput = "i3 at foo.com";
-        
-        tl.putTextTemplate("@foo.com/t.ftl", tAtFooComContent);
-        tl.putTextTemplate("@bar.com/t.ftl", tAtBarComContent);
-        tl.putTextTemplate("@default/t.ftl", tAtDefaultContent);
-        tl.putTextTemplate("@foo.com/i.ftl", iAtFooComContent);
-        tl.putTextTemplate("@baaz.com/i.ftl", iAtBaazComContent);
-        tl.putTextTemplate("@default/i_xx.ftl", iXxAtDefaultContent);
-        tl.putTextTemplate("@default/i.ftl", iAtDefaultContent);
-        tl.putTextTemplate("@foo.com/t2.ftl", "<#import 'i2.ftl' as i2 />${proof}");
-        tl.putTextTemplate("@default/i2.ftl", "<#import 'i3.ftl' as i3 />");
-        tl.putTextTemplate("@foo.com/i3.ftl", "<#global proof = '" + t2OtherLocaleExpectedOutput + "'>");
-        tl.putTextTemplate("@foo.com/i3_xx.ftl", "<#global proof = '" + t2XxLocaleExpectedOutput + "'>");
-
-        {
-            final Locale locale = new Locale("xx");
-            final Domain domain = new Domain("foo.com");
-            final Template t = cfg.getTemplate("t.ftl", locale, domain);
-            assertEquals("t.ftl", t.getLookupName());
-            assertEquals("@foo.com/t.ftl", t.getSourceName());
-            assertEquals(locale, t.getLocale());
-            assertEquals(domain, t.getCustomLookupCondition());
-            assertEquals(tAtFooComContent, t.toString());
-            assertEquals(
-                    ImmutableList.of("@foo.com/t_xx.ftl", "@foo.com/t.ftl"),
-                    tl.getLoadNames());
-            
-            tl.clearEvents();
-            assertOutputEquals(tAtFooComWithoutIncludeContent + iAtFooComContent, t);
-            assertEquals(
-                    ImmutableList.of("@foo.com/i_xx.ftl", "@foo.com/i.ftl"),
-                    tl.getLoadNames());
-            
-            tl.clearEvents();
-            cfg.clearTemplateCache();
-        }
-
-        {
-            final Locale locale = new Locale("xx");
-            final Domain domain = new Domain("bar.com");
-            final Template t = cfg.getTemplate("t.ftl", locale, domain);
-            assertEquals("t.ftl", t.getLookupName());
-            assertEquals("@bar.com/t.ftl", t.getSourceName());
-            assertEquals(locale, t.getLocale());
-            assertEquals(domain, t.getCustomLookupCondition());
-            assertEquals(tAtBarComContent, t.toString());
-            assertEquals(
-                    ImmutableList.of("@bar.com/t_xx.ftl", "@bar.com/t.ftl"),
-                    tl.getLoadNames());
-            
-            tl.clearEvents();
-            assertOutputEquals(tAtBarComWithoutIncludeContent + iXxAtDefaultContent, t);
-            assertEquals(
-                    ImmutableList.of(
-                            "@bar.com/i_xx.ftl", "@bar.com/i.ftl",
-                            "@default/i_xx.ftl"),
-                    tl.getLoadNames());
-            
-            tl.clearEvents();
-            cfg.clearTemplateCache();
-        }
-        
-        {
-            final Locale locale = new Locale("xx", "YY");
-            final Domain domain = new Domain("baaz.com");
-            final Template t = cfg.getTemplate("t.ftl", locale, domain);
-            assertEquals("t.ftl", t.getLookupName());
-            assertEquals("@default/t.ftl", t.getSourceName());
-            assertEquals(locale, t.getLocale());
-            assertEquals(domain, t.getCustomLookupCondition());
-            assertEquals(tAtDefaultContent, t.toString());
-            assertEquals(
-                    ImmutableList.of(
-                            "@baaz.com/t_xx_YY.ftl", "@baaz.com/t_xx.ftl", "@baaz.com/t.ftl",
-                            "@default/t_xx_YY.ftl", "@default/t_xx.ftl", "@default/t.ftl"),
-                    tl.getLoadNames());
-            
-            tl.clearEvents();
-            assertOutputEquals(tAtDefaultWithoutIncludeContent + iAtBaazComContent, t);
-            assertEquals(
-                    ImmutableList.of("@baaz.com/i_xx_YY.ftl", "@baaz.com/i_xx.ftl", "@baaz.com/i.ftl"),
-                    tl.getLoadNames());
-            
-            tl.clearEvents();
-            cfg.clearTemplateCache();
-        }
-        
-        {
-            final Locale locale = new Locale("xx", "YY");
-            final Domain domain = new Domain("nosuch.com");
-            final Template t = cfg.getTemplate("i.ftl", locale, domain);
-            assertEquals("i.ftl", t.getLookupName());
-            assertEquals("@default/i_xx.ftl", t.getSourceName());
-            assertEquals(locale, t.getLocale());
-            assertEquals(domain, t.getCustomLookupCondition());
-            assertEquals(iXxAtDefaultContent, t.toString());
-            assertEquals(
-                    ImmutableList.of(
-                            "@nosuch.com/i_xx_YY.ftl", "@nosuch.com/i_xx.ftl", "@nosuch.com/i.ftl",
-                            "@default/i_xx_YY.ftl", "@default/i_xx.ftl"),
-                    tl.getLoadNames());
-            
-            tl.clearEvents();
-            cfg.clearTemplateCache();
-        }
-
-        {
-            final Locale locale = new Locale("xx", "YY");
-            final Domain domain = new Domain("nosuch.com");
-            final Template t = cfgNoLocLU.getTemplate("i.ftl", locale, domain);
-            assertEquals("i.ftl", t.getLookupName());
-            assertEquals("@default/i.ftl", t.getSourceName());
-            assertEquals(locale, t.getLocale());
-            assertEquals(domain, t.getCustomLookupCondition());
-            assertEquals(iAtDefaultContent, t.toString());
-            assertEquals(
-                    ImmutableList.of("@nosuch.com/i.ftl", "@default/i.ftl"),
-                    tl.getLoadNames());
-            
-            tl.clearEvents();
-            cfgNoLocLU.clearTemplateCache();
-        }
-        
-        {
-            final Locale locale = new Locale("xx");
-            final Domain domain = new Domain("foo.com");
-            final Template t = cfg.getTemplate("t2.ftl", locale, domain);
-            assertOutputEquals(t2XxLocaleExpectedOutput, t);
-            assertEquals(
-                    ImmutableList.of(
-                            "@foo.com/t2_xx.ftl", "@foo.com/t2.ftl",
-                            "@foo.com/i2_xx.ftl", "@foo.com/i2.ftl", "@default/i2_xx.ftl", "@default/i2.ftl",
-                            "@foo.com/i3_xx.ftl"),
-                    tl.getLoadNames());
-            
-            tl.clearEvents();
-            cfg.clearTemplateCache();
-        }
-        
-        {
-            final Locale locale = new Locale("yy");
-            final Domain domain = new Domain("foo.com");
-            final Template t = cfg.getTemplate("t2.ftl", locale, domain);
-            assertOutputEquals(t2OtherLocaleExpectedOutput, t);
-            assertEquals(
-                    ImmutableList.of(
-                            "@foo.com/t2_yy.ftl", "@foo.com/t2.ftl",
-                            "@foo.com/i2_yy.ftl", "@foo.com/i2.ftl", "@default/i2_yy.ftl", "@default/i2.ftl",
-                            "@foo.com/i3_yy.ftl", "@foo.com/i3.ftl"),
-                    tl.getLoadNames());
-            
-            tl.clearEvents();
-            cfg.clearTemplateCache();
-        }
-        
-        {
-            final Locale locale = new Locale("xx");
-            final Domain domain = new Domain("foo.com");
-            final Template t = cfgNoLocLU.getTemplate("t2.ftl", locale, domain);
-            assertOutputEquals(t2OtherLocaleExpectedOutput, t);
-            assertEquals(
-                    ImmutableList.of(
-                            "@foo.com/t2.ftl",
-                            "@foo.com/i2.ftl", "@default/i2.ftl",
-                            "@foo.com/i3.ftl"),
-                    tl.getLoadNames());
-            
-            tl.clearEvents();
-            cfgNoLocLU.clearTemplateCache();
-        }
-        
-        {
-            final Locale locale = new Locale("xx");
-            final Domain domain = new Domain("foo.com");
-            cfg.getTemplate("i3.ftl", locale, domain);
-            assertEquals(
-                    ImmutableList.of("@foo.com/i3_xx.ftl"),
-                    tl.getLoadNames());
-            
-            tl.clearEvents();
-            cfg.clearTemplateCache();
-        }
-        
-        {
-            final Locale locale = new Locale("xx");
-            final Domain domain = new Domain("bar.com");
-            try {
-                cfg.getTemplate("i3.ftl", locale, domain);
-            } catch (TemplateNotFoundException e) {
-                assertEquals("i3.ftl", e.getTemplateName());
-                assertEquals(domain, e.getCustomLookupCondition());
-            }
-            assertEquals(
-                    ImmutableList.of(
-                            "@bar.com/i3_xx.ftl", "@bar.com/i3.ftl",
-                            "@default/i3_xx.ftl", "@default/i3.ftl"),
-                    tl.getLoadNames());
-            
-            tl.clearEvents();
-            cfg.clearTemplateCache();
-        }
-        
-    }
-
-    public static class Domain implements Serializable {
-        private final String name;
-
-        public Domain(String name) {
-            this.name = name;
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (this == o) return true;
-            if (o == null || getClass() != o.getClass()) return false;
-
-            Domain domain = (Domain) o;
-
-            return name != null ? name.equals(domain.name) : domain.name == null;
-        }
-
-        @Override
-        public int hashCode() {
-            return name != null ? name.hashCode() : 0;
-        }
-    }
-    
-    @Test
-    public void testNonparsed() throws IOException {
-        MonitoredTemplateLoader tl = new MonitoredTemplateLoader();
-        tl.putTextTemplate("test.txt", "");
-        tl.putTextTemplate("test_aa.txt", "");
-
-        Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0).templateLoader(tl).build();
-
-        try {
-            cfg.getTemplate("missing.txt", new Locale("aa", "BB"), null, false);
-            fail();
-        } catch (TemplateNotFoundException e) {
-            assertEquals("missing.txt", e.getTemplateName());
-            assertEquals(
-                    ImmutableList.of(
-                            "missing_aa_BB.txt",
-                            "missing_aa.txt",
-                            "missing.txt"),
-                    tl.getLoadNames());
-            tl.clearEvents();
-            cfg.clearTemplateCache();
-        }
-        
-        {
-            Template t = cfg.getTemplate("test.txt", new Locale("aa", "BB"), null, false);
-            assertEquals("test.txt", t.getLookupName());
-            assertEquals("test_aa.txt", t.getSourceName());
-            assertEquals(
-                    ImmutableList.of(
-                            "test_aa_BB.txt",
-                            "test_aa.txt"),
-                    tl.getLoadNames());
-        }
-    }
-
-    @Test
-    public void testParseError() throws IOException {
-        MonitoredTemplateLoader tl = new MonitoredTemplateLoader();
-        tl.putTextTemplate("test.ftl", "");
-        tl.putTextTemplate("test_aa.ftl", "<#wrong>");
-
-        Configuration cfg = new Configuration.Builder(Configuration.VERSION_3_0_0).templateLoader(tl).build();
-        
-        try {
-            cfg.getTemplate("test.ftl", new Locale("aa", "BB"));
-            fail();
-        } catch (ParseException e) {
-            assertEquals("test_aa.ftl", e.getTemplateSourceName());
-            assertEquals("test.ftl", e.getTemplateLookupName());
-        }
-    }
-    
-    private String toCanonicalFTL(String ftl, Configuration cfg) throws IOException {
-        return new Template(null, ftl, cfg).toString();        
-    }
-
-    private void assertOutputEquals(final String expectedContent, final Template t) throws TemplateException,
-            IOException {
-        StringWriter sw = new StringWriter(); 
-        t.process(null, sw);
-        assertEquals(expectedContent, sw.toString());
-    }
-    
-    public static class MyTemplateLookupStrategy extends TemplateLookupStrategy {
-        
-        public static final MyTemplateLookupStrategy INSTANCE = new MyTemplateLookupStrategy();
-        
-        private MyTemplateLookupStrategy() { }
-
-        @Override
-        public <R extends TemplateLookupResult> R lookup(TemplateLookupContext<R> ctx) throws IOException {
-            String lang = ctx.getTemplateLocale().getLanguage().toLowerCase();
-            R lookupResult = ctx.lookupWithAcquisitionStrategy(lang + "/" + ctx.getTemplateName());
-            if (lookupResult.isPositive()) {
-                return lookupResult;
-            }
-            
-            return ctx.lookupWithAcquisitionStrategy(ctx.getTemplateName());
-        }
-        
-    }
-    
-    public static class DomainTemplateLookupStrategy extends TemplateLookupStrategy {
-        
-        public static final DomainTemplateLookupStrategy INSTANCE = new DomainTemplateLookupStrategy();
-
-        @Override
-        public <R extends TemplateLookupResult> R lookup(TemplateLookupContext<R> ctx) throws IOException {
-            Domain domain = (Domain) ctx.getCustomLookupCondition();
-            if (domain == null) {
-                throw new NullPointerException("The domain wasn't specified");
-            }
-            
-            final String templateName = ctx.getTemplateName();
-            
-            // Disallow addressing the domain roots directly:
-            if (templateName.startsWith("@")) {
-                return ctx.createNegativeLookupResult();
-            }
-            
-            R lookupResult = ctx.lookupWithLocalizedThenAcquisitionStrategy(
-                    "@" + domain.name + "/" + templateName,
-                    ctx.getTemplateLocale());
-            if (lookupResult.isPositive()) {
-                return lookupResult;
-            }
-            
-            return ctx.lookupWithLocalizedThenAcquisitionStrategy("@default/" + templateName, ctx.getTemplateLocale());
-        }
-        
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/TemplateNameSpecialVariablesTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/TemplateNameSpecialVariablesTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/TemplateNameSpecialVariablesTest.java
deleted file mode 100644
index 7c9a98f..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/TemplateNameSpecialVariablesTest.java
+++ /dev/null
@@ -1,159 +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;
-
-import java.io.IOException;
-
-import org.apache.freemarker.test.TemplateTest;
-import org.apache.freemarker.test.TestConfigurationBuilder;
-import org.junit.Test;
-
-public class TemplateNameSpecialVariablesTest extends TemplateTest {
-    
-    private static final String PRINT_ALL_FTL
-            = "ct=${.currentTemplateName!'-'}, mt=${.mainTemplateName!'-'}";
-
-    @Test
-    public void testMainTemplateName() throws IOException, TemplateException {
-        addTemplateNameTestTemplates(".mainTemplateName");
-        assertOutputForNamed("main.ftl",
-                "In main: main.ftl\n"
-                + "In imp: main.ftl\n"
-                + "In main: main.ftl\n"
-                + "main.ftl\n"
-                + "{main.ftl}\n"
-                + "In imp call imp:\n"
-                + "main.ftl\n"
-                + "{main.ftl}\n"
-                + "After: main.ftl\n"
-                + "In main: main.ftl\n"
-                + "In inc: main.ftl\n"
-                + "In inc call imp:\n"
-                + "main.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");
-    }
-
-    @Test
-    public void testCurrentTemplateName() throws IOException, TemplateException {
-        addTemplateNameTestTemplates(".currentTemplateName");
-        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");
-    }
-
-    private void addTemplateNameTestTemplates(String specVar) {
-        addTemplate("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"
-        );
-        addTemplate("imp.ftl",
-                "<#global inImp = " + specVar + ">"
-                        + "<#macro impM>"
-                        + "${" + specVar + "}\n"
-                        + "{<#nested>}"
-                        + "</#macro>"
-                        + "<#macro impM2>"
-                        + "In imp call imp:\n"
-                        + "<@impM>${" + specVar + "}</@>\n"
-                        + "After: ${" + specVar + "}"
-                        + "</#macro>"
-        );
-        addTemplate("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>"
-        );
-    }
-
-    @Test
-    public void testInAdhocTemplate() throws TemplateException, IOException {
-        addTemplate("inc.ftl", "Inc: " + PRINT_ALL_FTL);
-
-        // 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()),
-                "ct=-, mt=-; Inc: ct=inc.ftl, mt=-");
-        
-        assertOutput(new Template("foo.ftl", PRINT_ALL_FTL + "; <#include 'inc.ftl'>", getConfiguration()),
-                "ct=foo.ftl, mt=foo.ftl; Inc: ct=inc.ftl, mt=foo.ftl");
-    }
-
-    @Test
-    public void testInInterpretTemplate() throws TemplateException, IOException {
-        addToDataModel("t", PRINT_ALL_FTL);
-        assertOutput(new Template("foo.ftl", PRINT_ALL_FTL + "; <@t?interpret />", getConfiguration()),
-                "ct=foo.ftl, mt=foo.ftl; "
-                + "ct=foo.ftl->anonymous_interpreted, mt=foo.ftl");
-        assertOutput(new Template(null, PRINT_ALL_FTL + "; <@t?interpret />", getConfiguration()),
-                "ct=-, mt=-; "
-                + "ct=nameless_template->anonymous_interpreted, mt=-");
-        assertOutput(new Template("foo.ftl", PRINT_ALL_FTL + "; <@[t,'bar']?interpret />", getConfiguration()),
-                "ct=foo.ftl, mt=foo.ftl; "
-                + "ct=foo.ftl->bar, mt=foo.ftl");
-    }
-
-    @Override
-    protected Configuration createDefaultConfiguration() throws Exception {
-        return new TestConfigurationBuilder().whitespaceStripping(false).build();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/TemplateNotFoundMessageTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/TemplateNotFoundMessageTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/TemplateNotFoundMessageTest.java
deleted file mode 100644
index 66331ad..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/TemplateNotFoundMessageTest.java
+++ /dev/null
@@ -1,207 +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;
-
-import static org.apache.freemarker.test.hamcerst.Matchers.*;
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.Serializable;
-
-import org.apache.freemarker.core.templateresolver.MalformedTemplateNameException;
-import org.apache.freemarker.core.templateresolver.TemplateLoader;
-import org.apache.freemarker.core.templateresolver.TemplateLookupContext;
-import org.apache.freemarker.core.templateresolver.TemplateLookupResult;
-import org.apache.freemarker.core.templateresolver.TemplateLookupStrategy;
-import org.apache.freemarker.core.templateresolver.impl.ClassTemplateLoader;
-import org.apache.freemarker.core.templateresolver.impl.FileTemplateLoader;
-import org.apache.freemarker.core.templateresolver.impl.MultiTemplateLoader;
-import org.apache.freemarker.core.templateresolver.impl.StringTemplateLoader;
-import org.junit.Test;
-
-public class TemplateNotFoundMessageTest {
-
-    @Test
-    public void testFileTemplateLoader() throws IOException {
-        final File baseDir = new File(System.getProperty("user.home"));
-        final String errMsg = failWith(new FileTemplateLoader(baseDir));
-        showErrorMessage(errMsg);
-        assertThat(errMsg, containsString(baseDir.toString()));
-        assertThat(errMsg, containsString("FileTemplateLoader"));
-    }
-
-    @Test
-    public void testClassTemplateLoader() throws IOException {
-        final String errMsg = failWith(new ClassTemplateLoader(getClass(), "foo/bar"));
-        showErrorMessage(errMsg);
-        assertThat(errMsg, containsString("ClassTemplateLoader"));
-        assertThat(errMsg, containsString("foo/bar"));
-    }
-
-    @Test
-    public void testStringTemplateLoader() throws IOException {
-        StringTemplateLoader tl = new StringTemplateLoader();
-        tl.putTemplate("aaa", "A");
-        tl.putTemplate("bbb", "B");
-        tl.putTemplate("ccc", "C");
-        final String errMsg = failWith(tl);
-        showErrorMessage(errMsg);
-        assertThat(errMsg, containsString("StringTemplateLoader"));
-        assertThat(errMsg, containsString("aaa"));
-        assertThat(errMsg, containsString("bbb"));
-        assertThat(errMsg, containsString("ccc"));
-    }
-    
-    @Test
-    public void testMultiTemplateLoader() throws IOException {
-        final String errMsg = failWith(new MultiTemplateLoader(new TemplateLoader[] {
-                new StringTemplateLoader(),
-                new ClassTemplateLoader(getClass(), "foo/bar")
-        }));
-        showErrorMessage(errMsg);
-        assertThat(errMsg, containsString("MultiTemplateLoader"));
-        assertThat(errMsg, containsString("StringTemplateLoader"));
-        assertThat(errMsg, containsString("ClassTemplateLoader"));
-        assertThat(errMsg, containsString("foo/bar"));
-    }
-
-    @Test
-    public void testDefaultTemplateLoader() throws IOException {
-        String errMsg = failWith(null);
-        showErrorMessage(errMsg);
-        assertThat(errMsg, allOf(containsString("setTemplateLoader"), containsString("null")));
-    }
-    
-    @Test
-    public void testOtherMessageDetails() throws IOException {
-        // Non-null TemplateLoader:
-        StringTemplateLoader emptyLoader = new StringTemplateLoader();
-        {
-            String errMsg = failWith(emptyLoader, "../x");
-            showErrorMessage(errMsg);
-            assertThat(errMsg,
-                    allOf(
-                            containsStringIgnoringCase("Malformed template name"),
-                            containsStringIgnoringCase("root directory")));
-        }
-        {
-            String errMsg = failWith(emptyLoader, "x\u0000y");
-            showErrorMessage(errMsg);
-            assertThat(errMsg,
-                    allOf(
-                            containsStringIgnoringCase("Malformed template name"),
-                            containsStringIgnoringCase("null character")));
-        }
-        {
-            String errMsg = failWith(emptyLoader, "x\\y");
-            showErrorMessage(errMsg);
-            assertThat(errMsg,
-                    allOf(containsStringIgnoringCase("warning"), containsStringIgnoringCase("backslash")));
-        }
-        {
-            String errMsg = failWith(emptyLoader, "x/./y");
-            showErrorMessage(errMsg);
-            assertThat(errMsg,
-                    allOf(containsStringIgnoringCase("normalized"), containsStringIgnoringCase("x/y")));
-        }
-        {
-            String errMsg = failWith(emptyLoader, "/x/y");
-            showErrorMessage(errMsg);
-            assertThat(errMsg, not(containsStringIgnoringCase("normalized")));
-        }
-        {
-            String errMsg = failWith(emptyLoader, "x/y");
-            showErrorMessage(errMsg);
-            assertThat(errMsg, not(containsStringIgnoringCase("normalized")));
-            assertThat(errMsg, not(containsStringIgnoringCase("lookup strategy")));
-        }
-
-        Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0)
-                .templateLoader(new StringTemplateLoader())
-                .templateLookupStrategy(
-                        new TemplateLookupStrategy() {
-                            @Override
-                            public TemplateLookupResult lookup(TemplateLookupContext ctx) throws IOException {
-                                return ctx.lookupWithAcquisitionStrategy(ctx.getTemplateName());
-                            }
-                        }
-        );
-        {
-            String errMsg = failWith(emptyLoader, "x/y",
-                    new TemplateLookupStrategy() {
-                        @Override
-                        public TemplateLookupResult lookup(TemplateLookupContext ctx) throws IOException {
-                            return ctx.lookupWithAcquisitionStrategy(ctx.getTemplateName());
-                        }
-                    }
-            );
-            showErrorMessage(errMsg);
-            assertThat(errMsg, containsStringIgnoringCase("lookup strategy"));
-        }
-        
-        try {
-            cfgB.build().getTemplate("./missing", null, new DomainLookupCondition());
-            fail();
-        } catch (TemplateNotFoundException e) {
-            showErrorMessage(e.getMessage());
-            assertThat(e.getMessage(), containsStringIgnoringCase("example.com"));
-        }
-    }
-
-    private void showErrorMessage(String errMsg) {
-        // System.out.println(errMsg);
-    }
-
-    private String failWith(TemplateLoader tl, String name, TemplateLookupStrategy templateLookupStrategy) {
-        try {
-            Configuration.Builder cfgB = new Configuration.Builder(Configuration.VERSION_3_0_0);
-            cfgB.setTemplateLoader(tl);
-            if (templateLookupStrategy != null) {
-                cfgB.setTemplateLookupStrategy(templateLookupStrategy);
-            }
-            cfgB.build().getTemplate(name);
-            fail();
-        } catch (TemplateNotFoundException | MalformedTemplateNameException e) {
-            return e.getMessage();
-        } catch (IOException e) {
-            fail("Unexpected exception: " + e);
-        }
-        return null;
-    }
-
-    private String failWith(TemplateLoader tl, String name) {
-        return failWith(tl, name, null);
-    }
-
-    private String failWith(TemplateLoader tl) {
-        return failWith(tl, "missing.ftl", null);
-    }
-
-    @SuppressWarnings("serial")
-    private static final class DomainLookupCondition implements Serializable {
-        @Override
-        public String toString() {
-            return "example.com";
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/TheadInterruptingSupportTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/TheadInterruptingSupportTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/TheadInterruptingSupportTest.java
deleted file mode 100644
index a0174b3..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/TheadInterruptingSupportTest.java
+++ /dev/null
@@ -1,163 +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;
-
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.util.Map;
-
-import org.apache.freemarker.core.ThreadInterruptionSupportTemplatePostProcessor.TemplateProcessingThreadInterruptedException;
-import org.apache.freemarker.core.model.TemplateDirectiveBody;
-import org.apache.freemarker.core.model.TemplateDirectiveModel;
-import org.apache.freemarker.core.model.TemplateModel;
-import org.apache.freemarker.core.util._NullWriter;
-import org.apache.freemarker.test.TestConfigurationBuilder;
-import org.junit.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class TheadInterruptingSupportTest {
-    
-    private static final Logger LOG = LoggerFactory.getLogger(TheadInterruptingSupportTest.class);
-
-    private static final int TEMPLATE_INTERRUPTION_TIMEOUT = 5000;
-    private final Configuration cfg = new TestConfigurationBuilder().build();
-
-    @Test
-    public void test() throws IOException, InterruptedException {
-        assertCanBeInterrupted("<#list 1.. as x></#list>");
-        assertCanBeInterrupted("<#list 1.. as x>${x}</#list>");
-        assertCanBeInterrupted("<#list 1.. as x>t${x}</#list>");
-        assertCanBeInterrupted("<#list 1.. as x><#list 1.. as y>${y}</#list></#list>");
-        assertCanBeInterrupted("<#list 1.. as x>${x}<#else>nope</#list>");
-        assertCanBeInterrupted("<#list 1..>[<#items as x>${x}</#items>]<#else>nope</#list>");
-        assertCanBeInterrupted("<@customLoopDirective />");
-        assertCanBeInterrupted("<@customLoopDirective>x</@>");
-        assertCanBeInterrupted("<@customLoopDirective><#if true>x</#if></@>");
-        assertCanBeInterrupted("<#macro selfCalling><@sleepDirective/><@selfCalling /></#macro><@selfCalling />");
-        assertCanBeInterrupted("<#function selfCalling><@sleepDirective/>${selfCalling()}</#function>${selfCalling()}");
-        assertCanBeInterrupted("<#list 1.. as _><#attempt><@sleepDirective/><#recover>suppress</#attempt></#list>");
-        assertCanBeInterrupted("<#attempt><#list 1.. as _></#list><#recover>suppress</#attempt>");
-    }
-
-    private void assertCanBeInterrupted(final String templateSourceCode) throws IOException, InterruptedException {
-        TemplateRunnerThread trt = new TemplateRunnerThread(templateSourceCode);
-        trt.start();
-        synchronized (trt) {
-            while (!trt.isStarted()) {
-                trt.wait();
-            }
-        }
-        Thread.sleep(50); // Just to ensure (hope...) that the template execution reaches "deep" enough
-        trt.interrupt();
-        trt.join(TEMPLATE_INTERRUPTION_TIMEOUT);
-        assertTrue(trt.isTemplateProcessingInterrupted());
-    }
-
-    public class TemplateRunnerThread extends Thread {
-
-        private final Template template;
-        private boolean started;
-        private boolean templateProcessingInterrupted;
-
-        public TemplateRunnerThread(String templateSourceCode) throws IOException {
-            template = new Template(null, "<@startedDirective/>" + templateSourceCode, cfg);
-            _CoreAPI.addThreadInterruptedChecks(template);
-        }
-
-        @Override
-        public void run() {
-            try {
-                template.process(this, _NullWriter.INSTANCE);
-            } catch (TemplateProcessingThreadInterruptedException e) {
-                //LOG.debug("Template processing interrupted", e);
-                synchronized (this) {
-                    templateProcessingInterrupted = true;
-                }
-            } catch (Throwable e) {
-                LOG.error("Template processing failed", e);
-            }
-        }
-
-        public synchronized boolean isTemplateProcessingInterrupted() {
-            return templateProcessingInterrupted;
-        }
-        
-        public synchronized boolean isStarted() {
-            return started;
-        }
-        
-        public TemplateDirectiveModel getStartedDirective() {
-            return new StartedDirective();
-        }
-
-        public TemplateDirectiveModel getCustomLoopDirective() {
-            return new CustomLoopDirective();
-        }
-        
-        public TemplateDirectiveModel getSleepDirective() {
-            return new SleepDirective();
-        }
-
-        public class StartedDirective implements TemplateDirectiveModel {
-            
-            @Override
-            public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
-                    throws TemplateException, IOException {
-                synchronized (TemplateRunnerThread.this) {
-                    started = true;
-                    TemplateRunnerThread.this.notifyAll();
-                }
-            }
-            
-        }
-
-        public class CustomLoopDirective implements TemplateDirectiveModel {
-
-            @Override
-            public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
-                    throws TemplateException, IOException {
-                // Deliberate infinite loop
-                while (true) {
-                    body.render(_NullWriter.INSTANCE);
-                }
-            }
-            
-        }
-        
-        public class SleepDirective implements TemplateDirectiveModel {
-
-            @Override
-            public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
-                    throws TemplateException, IOException {
-                try {
-                    Thread.sleep(100);
-                } catch (InterruptedException e) {
-                    // Thread.sleep has reset the interrupted flag (because it has thrown InterruptedException).  
-                    Thread.currentThread().interrupt();
-                }
-            }
-            
-        }
-        
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/TypeErrorMessagesTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/TypeErrorMessagesTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/TypeErrorMessagesTest.java
deleted file mode 100644
index 749d057..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/TypeErrorMessagesTest.java
+++ /dev/null
@@ -1,105 +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;
-
-import java.io.StringReader;
-import java.util.Map;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-
-import org.apache.freemarker.test.TemplateTest;
-import org.junit.Test;
-import org.w3c.dom.Document;
-import org.xml.sax.InputSource;
-
-public class TypeErrorMessagesTest extends TemplateTest {
-
-    static final Document doc;
-    static {
-        try {
-            DocumentBuilder docBuilder;
-            docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
-            doc = docBuilder.parse(new InputSource(new StringReader(
-                    "<a><b>123</b><c a='true'>1</c><c a='false'>2</c></a>")));
-        } catch (Exception e) {
-            throw new RuntimeException("Failed to build data-model", e);
-        }
-    }
-
-    @Test
-    public void testNumericalBinaryOperator() {
-        assertErrorContains("${n - s}", "\"-\"", "right-hand", "number", "string");
-        assertErrorContains("${s - n}", "\"-\"", "left-hand", "number", "string");
-    }
-
-    @Test
-    public void testGetterMistake() {
-        assertErrorContains("${bean.getX}", "${...}",
-                "number", "string", "method", "obj.getSomething", "obj.something");
-        assertErrorContains("${1 * bean.getX}", "right-hand",
-                "number", "\\!string", "method", "obj.getSomething", "obj.something");
-        assertErrorContains("<#if bean.isB></#if>", "condition",
-                "boolean", "method", "obj.isSomething", "obj.something");
-        assertErrorContains("<#if bean.isB></#if>", "condition",
-                "boolean", "method", "obj.isSomething", "obj.something");
-        assertErrorContains("${bean.voidM}",
-                "string", "method", "\\!()");
-        assertErrorContains("${bean.intM}",
-                "string", "method", "obj.something()");
-        assertErrorContains("${bean.intMP}",
-                "string", "method", "obj.something(params)");
-    }
-
-    @Test
-    public void testXMLTypeMismarches() throws Exception {
-        assertErrorContains("${doc.a.c}",
-                "used as string", "query result", "2", "multiple matches");
-        assertErrorContains("${doc.a.c?boolean}",
-                "used as string", "query result", "2", "multiple matches");
-        assertErrorContains("${doc.a.d}",
-                "used as string", "query result", "0", "no matches");
-        assertErrorContains("${doc.a.d?boolean}",
-                "used as string", "query result", "0", "no matches");
-        
-        assertErrorContains("${doc.a.c.@a}",
-                "used as string", "query result", "2", "multiple matches");
-        assertErrorContains("${doc.a.d.@b}",
-                "used as string", "query result", "x", "no matches");
-        
-        assertErrorContains("${doc.a.b * 2}",
-                "used as number", "text", "explicit conversion");
-        assertErrorContains("<#if doc.a.b></#if>",
-                "used as number", "text", "explicit conversion");
-
-        assertErrorContains("${doc.a.d?nodeName}",
-                "used as node", "query result", "0", "no matches");
-        assertErrorContains("${doc.a.c?nodeName}",
-                "used as node", "query result", "2", "multiple matches");
-    }
-
-    @Override
-    protected Object createDataModel() {
-        Map<String, Object> dataModel = createCommonTestValuesDataModel();
-        dataModel.put("doc", doc);
-        return dataModel;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/UnclosedCommentTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/UnclosedCommentTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/UnclosedCommentTest.java
deleted file mode 100644
index 99bf5d3..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/UnclosedCommentTest.java
+++ /dev/null
@@ -1,41 +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;
-
-import java.io.IOException;
-
-import org.apache.freemarker.test.TemplateTest;
-import org.junit.Test;
-
-public class UnclosedCommentTest extends TemplateTest {
-    
-    @Test
-    public void test() throws IOException, TemplateException {
-        assertErrorContains("foo<#--", "end of file");  // Not too good...
-        assertErrorContains("foo<#-- ", "Unclosed", "<#--");
-        assertErrorContains("foo<#--bar", "Unclosed", "<#--");
-        assertErrorContains("foo\n<#--\n", "Unclosed", "<#--");
-        assertErrorContains("foo<#noparse>", "end of file");  // Not too good...
-        assertErrorContains("foo<#noparse> ", "Unclosed", "#noparse");
-        assertErrorContains("foo<#noparse>bar", "Unclosed", "#noparse");
-        assertErrorContains("foo\n<#noparse>\n", "Unclosed", "#noparse");
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/VersionTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/VersionTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/VersionTest.java
deleted file mode 100644
index 8c54df5..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/VersionTest.java
+++ /dev/null
@@ -1,227 +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;
-
-import static org.junit.Assert.*;
-
-import java.sql.Date;
-
-import org.junit.Test;
-
-@SuppressWarnings("boxing")
-public class VersionTest {
-
-    @Test
-    public void testFromNumber() {
-        Version v = new Version(1, 2, 3);
-        assertEquals("1.2.3", v.toString());
-        assertEquals(1002003, v.intValue());
-        assertEquals(1, v.getMajor());
-        assertEquals(2, v.getMinor());
-        assertEquals(3, v.getMicro());
-        assertNull(v.getExtraInfo());
-        assertNull(v.isGAECompliant());
-        assertNull(v.getBuildDate());
-    }
-
-    @Test
-    public void testFromNumber2() {
-        Version v = new Version(1, 2, 3, "beta8", Boolean.TRUE, new Date(5000));
-        assertEquals("1.2.3-beta8", v.toString());
-        assertEquals("beta8", v.getExtraInfo());
-        assertTrue(v.isGAECompliant().booleanValue());
-        assertEquals(new Date(5000), v.getBuildDate());
-    }
-
-    @Test
-    public void testFromNumber3() {
-        Version v = new Version(new Version(1, 2, 3).intValue());
-        assertEquals(1, v.getMajor());
-        assertEquals(2, v.getMinor());
-        assertEquals(3, v.getMicro());
-    }
-    
-    public void testFromNumberIncubating() {
-        Version v = new Version(2, 3, 24, "rc01-incubating", Boolean.FALSE, new Date(5000));
-        assertEquals("2.3.24-rc01-incubating", v.toString());
-        assertEquals("rc01-incubating", v.getExtraInfo());
-        assertFalse(v.isGAECompliant().booleanValue());
-        assertEquals(new Date(5000), v.getBuildDate());
-    }
-    
-    @Test
-    public void testFromString() {
-        Version v = new Version("1.2.3-beta2");
-        assertEquals("1.2.3-beta2", v.toString());
-        assertEquals(1002003, v.intValue());
-        assertEquals(1, v.getMajor());
-        assertEquals(2, v.getMinor());
-        assertEquals(3, v.getMicro());
-        assertEquals("beta2", v.getExtraInfo());
-        assertNull(v.isGAECompliant());
-        assertNull(v.getBuildDate());
-    }
-
-    @Test
-    public void testFromString2() {
-        Version v = new Version("10.20.30", Boolean.TRUE, new Date(5000));
-        assertEquals("10.20.30", v.toString());
-        assertEquals(10020030, v.intValue());
-        assertEquals(10, v.getMajor());
-        assertEquals(20, v.getMinor());
-        assertEquals(30, v.getMicro());
-        assertNull(v.getExtraInfo());
-        assertTrue(v.isGAECompliant().booleanValue());
-        assertEquals(new Date(5000), v.getBuildDate());
-    }
-
-    @Test
-    public void testFromString3() {
-        Version v = new Version("01.002.0003-20130524");
-        assertEquals("01.002.0003-20130524", v.toString());
-        assertEquals(1, v.getMajor());
-        assertEquals(2, v.getMinor());
-        assertEquals(3, v.getMicro());
-        assertEquals("20130524", v.getExtraInfo());
-
-        v = new Version("01.002.0003.4");
-        assertEquals("01.002.0003.4", v.toString());
-        assertEquals(1, v.getMajor());
-        assertEquals(2, v.getMinor());
-        assertEquals(3, v.getMicro());
-        assertEquals("4", v.getExtraInfo());
-        
-        v = new Version("1.2.3.FC");
-        assertEquals("1.2.3.FC", v.toString());
-        assertEquals("FC", v.getExtraInfo());
-        
-        v = new Version("1.2.3mod");
-        assertEquals("1.2.3mod", v.toString());
-        assertEquals(1, v.getMajor());
-        assertEquals(2, v.getMinor());
-        assertEquals(3, v.getMicro());
-        assertEquals("mod", v.getExtraInfo());
-        
-    }
-
-    @Test
-    public void testFromStringIncubating() {
-        Version v = new Version("2.3.24-rc01-incubating");
-        assertEquals("2.3.24-rc01-incubating", v.toString());
-        assertEquals(2, v.getMajor());
-        assertEquals(3, v.getMinor());
-        assertEquals(24, v.getMicro());
-        assertEquals("rc01-incubating", v.getExtraInfo());
-    }
-    
-    @Test
-    public void testHashAndEquals() {
-        Version v1 = new Version("1.2.3-beta2");
-        Version v2 = new Version(1, 2, 3, "beta2", null, null);
-        assertEquals(v1, v2);
-        assertEquals(v1.hashCode(), v2.hashCode());
-        
-        v2 = new Version("1.2.3-beta3");
-        assertTrue(!v1.equals(v2));
-        assertTrue(v1.hashCode() != v2.hashCode());
-        
-        v2 = new Version(1, 2, 3, "beta2", true, null);
-        assertTrue(!v1.equals(v2));
-        assertTrue(v1.hashCode() != v2.hashCode());
-        
-        v2 = new Version(1, 2, 3, "beta2", null, new Date(5000));
-        assertTrue(!v1.equals(v2));
-        assertTrue(v1.hashCode() != v2.hashCode());
-        
-        v2 = new Version("1.2.9-beta2");
-        assertTrue(!v1.equals(v2));
-        assertTrue(v1.hashCode() != v2.hashCode());
-        
-        v2 = new Version("1.9.3-beta2");
-        assertTrue(!v1.equals(v2));
-        assertTrue(v1.hashCode() != v2.hashCode());
-        
-        v2 = new Version("9.2.3-beta2");
-        assertTrue(!v1.equals(v2));
-        assertTrue(v1.hashCode() != v2.hashCode());
-        
-        v2 = new Version("1.2.3");
-        assertTrue(!v1.equals(v2));
-        assertTrue(v1.hashCode() != v2.hashCode());
-    }
-
-    @Test
-    public void testShortForms() {
-        Version v = new Version("1.0.0-beta2");
-        assertEquals(v, new Version("1.0-beta2"));
-        assertEquals(v, new Version("1-beta2"));
-
-        v = new Version("1.0.0");
-        assertEquals(v, new Version("1.0"));
-        assertEquals(v, new Version("1"));
-    }
-    
-    @Test
-    public void testMalformed() {
-        try {
-            new Version("1.2.");
-            fail();
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-        
-        try {
-            new Version("1.2.3.");
-            fail();
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-        
-        try {
-            new Version("1..3");
-            fail();
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-
-        try {
-            new Version(".2");
-            fail();
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-        
-        try {
-            new Version("a");
-            fail();
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-        
-        try {
-            new Version("-a");
-            fail();
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-    }
-    
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/WhitespaceStrippingTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/WhitespaceStrippingTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/WhitespaceStrippingTest.java
deleted file mode 100644
index 8e5b52e..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/WhitespaceStrippingTest.java
+++ /dev/null
@@ -1,63 +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;
-
-import java.io.IOException;
-
-import org.apache.freemarker.test.TemplateTest;
-import org.apache.freemarker.test.TestConfigurationBuilder;
-import org.junit.Test;
-
-public class WhitespaceStrippingTest extends TemplateTest {
-
-    @Test
-    public void testBasics() throws Exception {
-        assertOutput("<#assign x = 1>\n<#assign y = 2>\n${x}\n${y}", "1\n2", "\n\n1\n2");
-        assertOutput(" <#assign x = 1> \n <#assign y = 2> \n${x}\n${y}", "1\n2", "  \n  \n1\n2");
-    }
-
-    @Test
-    public void testFTLHeader() throws Exception {
-        assertOutput("<#ftl>x", "x", "x");
-        assertOutput("  <#ftl>  x", "  x", "  x");
-        assertOutput("\n<#ftl>\nx", "x", "x");
-        assertOutput("\n<#ftl>\t \nx", "x", "x");
-        assertOutput("  \n \n  <#ftl> \n \n  x", " \n  x", " \n  x");
-    }
-
-    @Test
-    public void testComment() throws Exception {
-        assertOutput(" a <#-- --> b ", " a  b ", " a  b ");
-        assertOutput(" a \n<#-- -->\n b ", " a \n b ", " a \n\n b ");
-        // These are wrong, but needed for 2.3.0 compatibility:
-        assertOutput(" a \n <#-- --> \n b ", " a \n  b ", " a \n  \n b ");
-        assertOutput(" a \n\t<#-- --> \n b ", " a \n\t b ", " a \n\t \n b ");
-    }
-    
-    private void assertOutput(String ftl, String expectedOutStripped, String expectedOutNonStripped)
-            throws IOException, TemplateException {
-        setConfiguration(new TestConfigurationBuilder().build());
-        assertOutput(ftl, expectedOutStripped);
-        
-        setConfiguration(new TestConfigurationBuilder().whitespaceStripping(false).build());
-        assertOutput(ftl, expectedOutNonStripped);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/XHTMLOutputFormatTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/XHTMLOutputFormatTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/XHTMLOutputFormatTest.java
deleted file mode 100644
index 77951ed..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/XHTMLOutputFormatTest.java
+++ /dev/null
@@ -1,59 +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;
-
-import static org.apache.freemarker.core.outputformat.impl.XHTMLOutputFormat.*;
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.io.StringWriter;
-
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.junit.Test; 
-
-public class XHTMLOutputFormatTest {
-    
-    @Test
-    public void testOutputMO() throws TemplateModelException, IOException {
-       StringWriter out = new StringWriter();
-       INSTANCE.output(INSTANCE.fromPlainTextByEscaping("a'b"), out);
-       assertEquals("a&#39;b", out.toString());
-    }
-    
-    @Test
-    public void testOutputString() throws TemplateModelException, IOException {
-        StringWriter out = new StringWriter();
-        INSTANCE.output("a'b", out);
-        assertEquals("a&#39;b", out.toString());
-    }
-    
-    @Test
-    public void testEscaplePlainText() {
-        assertEquals("", INSTANCE.escapePlainText(""));
-        assertEquals("a", INSTANCE.escapePlainText("a"));
-        assertEquals("&lt;a&amp;b&#39;c&quot;d&gt;", INSTANCE.escapePlainText("<a&b'c\"d>"));
-        assertEquals("&lt;&gt;", INSTANCE.escapePlainText("<>"));
-    }
-    
-    @Test
-    public void testGetMimeType() {
-        assertEquals("application/xhtml+xml", INSTANCE.getMimeType());
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/XMLOutputFormatTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/XMLOutputFormatTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/XMLOutputFormatTest.java
deleted file mode 100644
index 7e95e6d..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/XMLOutputFormatTest.java
+++ /dev/null
@@ -1,59 +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;
-
-import static org.apache.freemarker.core.outputformat.impl.XMLOutputFormat.*;
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.io.StringWriter;
-
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.junit.Test; 
-
-public class XMLOutputFormatTest {
-    
-    @Test
-    public void testOutputMO() throws TemplateModelException, IOException {
-       StringWriter out = new StringWriter();
-       INSTANCE.output(INSTANCE.fromPlainTextByEscaping("a'b"), out);
-       assertEquals("a&apos;b", out.toString());
-    }
-    
-    @Test
-    public void testOutputString() throws TemplateModelException, IOException {
-        StringWriter out = new StringWriter();
-        INSTANCE.output("a'b", out);
-        assertEquals("a&apos;b", out.toString());
-    }
-    
-    @Test
-    public void testEscaplePlainText() {
-        assertEquals("", INSTANCE.escapePlainText(""));
-        assertEquals("a", INSTANCE.escapePlainText("a"));
-        assertEquals("&lt;a&amp;b&apos;c&quot;d&gt;", INSTANCE.escapePlainText("<a&b'c\"d>"));
-        assertEquals("&lt;&gt;", INSTANCE.escapePlainText("<>"));
-    }
-    
-    @Test
-    public void testGetMimeType() {
-        assertEquals("application/xml", INSTANCE.getMimeType());
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/AbstractParallelIntrospectionTest.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/AbstractParallelIntrospectionTest.java b/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/AbstractParallelIntrospectionTest.java
deleted file mode 100644
index bdb9a56..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/AbstractParallelIntrospectionTest.java
+++ /dev/null
@@ -1,126 +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.model.impl;
-
-import org.apache.freemarker.core.Configuration;
-import org.apache.freemarker.core.model.TemplateHashModel;
-import org.apache.freemarker.core.model.TemplateMethodModel;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.model.TemplateNumberModel;
-
-import junit.framework.TestCase;
-
-public abstract class AbstractParallelIntrospectionTest extends TestCase {
-    
-    private static final int NUM_THREADS = 8;
-    private static final int NUM_ENTITYES = 8;
-    private static final int NUM_MEMBERS = 8;
-    private static final int ITERATIONS = 20000;
-    private static final double CACHE_CLEARING_CHANCE = 0.01;
-    
-    private DefaultObjectWrapper ow = new DefaultObjectWrapper.Builder(Configuration.VERSION_3_0_0)
-            .usePrivateCaches(true).build();
-    
-    public AbstractParallelIntrospectionTest(String name) {
-        super(name);
-    }
-    
-    public void testReliability() {
-        testReliability(ITERATIONS);
-    }
-    
-    public void testReliability(int iterations) {
-        TestThread[] ts = new TestThread[NUM_THREADS]; 
-        for (int i = 0; i < NUM_THREADS; i++) {
-            ts[i] = new TestThread(iterations);
-            ts[i].start();
-        }
-
-        for (int i = 0; i < NUM_THREADS; i++) {
-            try {
-                ts[i].join();
-                if (ts[i].error != null) {
-                    throw new AssertionError(ts[i].error);
-                }
-            } catch (InterruptedException e) {
-                throw new RuntimeException(e);
-            }
-        }
-    }
-
-    protected abstract TemplateHashModel getWrappedEntity(int objIdx) throws TemplateModelException;
-    
-    protected final DefaultObjectWrapper getObjectWrapper() {
-        return ow;
-    }
-    
-    private class TestThread extends Thread {
-        
-        private final int iterations;
-        
-        private Throwable error;
-        
-        private TestThread(int iterations) {
-            this.iterations = iterations;
-        }
-
-        @Override
-        public void run() {
-            try {
-                for (int i = 0; i < iterations; i++) {
-                    if (Math.random() < CACHE_CLEARING_CHANCE) {
-                        ow.clearClassIntrospecitonCache();
-                    }
-                    int objIdx = (int) (Math.random() * NUM_ENTITYES);
-                    TemplateHashModel h = getWrappedEntity(objIdx);
-                    int mIdx = (int) (Math.random() * NUM_MEMBERS);
-                    testProperty(h, objIdx, mIdx);
-                    testMethod(h, objIdx, mIdx);
-                }
-            } catch (Throwable e) {
-                error = e;
-            }
-        }
-
-        private void testProperty(TemplateHashModel h, int objIdx, int mIdx)
-                throws TemplateModelException, AssertionError {
-            TemplateNumberModel pv = (TemplateNumberModel) h.get("p" + mIdx);
-            final int expected = objIdx * 1000 + mIdx;
-            final int got = pv.getAsNumber().intValue();
-            if (got != expected) {
-                throw new AssertionError("Property assertation failed; " +
-                        "expected " + expected + ", but got " + got);
-            }
-        }
-
-        private void testMethod(TemplateHashModel h, int objIdx, int mIdx)
-                throws TemplateModelException, AssertionError {
-            TemplateMethodModel pv = (TemplateMethodModel) h.get("m" + mIdx);
-            final int expected = objIdx * 1000 + mIdx;
-            final int got = ((TemplateNumberModel) pv.exec(null)).getAsNumber().intValue();
-            if (got != expected) {
-                throw new AssertionError("Method assertation failed; " +
-                        "expected " + expected + ", but got " + got);
-            }
-        }
-        
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/28a276c8/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/AlphabeticalMethodSorter.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/AlphabeticalMethodSorter.java b/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/AlphabeticalMethodSorter.java
deleted file mode 100644
index 149ad0d..0000000
--- a/freemarker-core/src/test/java/org/apache/freemarker/core/model/impl/AlphabeticalMethodSorter.java
+++ /dev/null
@@ -1,45 +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.model.impl;
-
-import java.beans.MethodDescriptor;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-
-class AlphabeticalMethodSorter implements MethodSorter {
-
-    private final boolean desc;
-    
-    public AlphabeticalMethodSorter(boolean desc) {
-        this.desc = desc;
-    }
-
-    @Override
-    public void sortMethodDescriptors(List<MethodDescriptor> methodDescriptors) {
-        Collections.sort(methodDescriptors, new Comparator<MethodDescriptor>() {
-            public int compare(MethodDescriptor o1, MethodDescriptor o2) {
-                int res = o1.getMethod().toString().compareTo(o2.getMethod().toString());
-                return desc ? -res : res;
-            }
-        });
-    }
-    
-}
\ No newline at end of file