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:24:04 UTC
[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
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;
+ }
+
+}