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 2021/11/06 23:29:39 UTC
[freemarker] branch FREEMARKER-35 updated: [FREEMARKER-35] Extended
customTemporalFormat test coverage.
This is an automated email from the ASF dual-hosted git repository.
ddekany pushed a commit to branch FREEMARKER-35
in repository https://gitbox.apache.org/repos/asf/freemarker.git
The following commit(s) were added to refs/heads/FREEMARKER-35 by this push:
new 3b24b1b [FREEMARKER-35] Extended customTemporalFormat test coverage.
3b24b1b is described below
commit 3b24b1be33ecb31fb815efeb7ca3a593b27231a9
Author: ddekany <dd...@apache.org>
AuthorDate: Sun Nov 7 00:29:08 2021 +0100
[FREEMARKER-35] Extended customTemporalFormat test coverage.
---
.../freemarker/template/utility/ClassUtil.java | 7 +-
.../freemarker/core/CoercionToTextualTest.java | 31 ++++--
...dTZSensitiveTemplateTemporalFormatFactory.java} | 7 +-
.../freemarker/core/TemplateConfigurationTest.java | 13 +++
.../java/freemarker/core/TemporalFormatTest2.java | 2 +-
.../freemarker/template/ConfigurationTest.java | 113 ++++++++++++++++++++-
6 files changed, 160 insertions(+), 13 deletions(-)
diff --git a/src/main/java/freemarker/template/utility/ClassUtil.java b/src/main/java/freemarker/template/utility/ClassUtil.java
index 7fc4046..3fa4aa4 100644
--- a/src/main/java/freemarker/template/utility/ClassUtil.java
+++ b/src/main/java/freemarker/template/utility/ClassUtil.java
@@ -62,6 +62,7 @@ import freemarker.template.TemplateNodeModelEx;
import freemarker.template.TemplateNumberModel;
import freemarker.template.TemplateScalarModel;
import freemarker.template.TemplateSequenceModel;
+import freemarker.template.TemplateTemporalModel;
import freemarker.template.TemplateTransformModel;
/**
@@ -274,7 +275,11 @@ public class ClassUtil {
if (TemplateDateModel.class.isAssignableFrom(cl)) {
appendTypeName(sb, typeNamesAppended, "date_or_time_or_datetime");
}
-
+
+ if (TemplateTemporalModel.class.isAssignableFrom(cl)) {
+ appendTypeName(sb, typeNamesAppended, "temporal");
+ }
+
if (TemplateBooleanModel.class.isAssignableFrom(cl)) {
appendTypeName(sb, typeNamesAppended, "boolean");
}
diff --git a/src/test/java/freemarker/core/CoercionToTextualTest.java b/src/test/java/freemarker/core/CoercionToTextualTest.java
index 3525c50..efa015a 100644
--- a/src/test/java/freemarker/core/CoercionToTextualTest.java
+++ b/src/test/java/freemarker/core/CoercionToTextualTest.java
@@ -19,6 +19,7 @@
package freemarker.core;
import java.io.IOException;
+import java.time.Instant;
import java.util.Collections;
import java.util.Date;
@@ -27,25 +28,25 @@ import org.junit.Test;
import freemarker.template.Configuration;
import freemarker.template.SimpleDate;
+import freemarker.template.SimpleTemporal;
import freemarker.template.TemplateDateModel;
import freemarker.template.TemplateException;
import freemarker.template.TemplateModelException;
+import freemarker.template.utility.DateUtil;
import freemarker.test.TemplateTest;
@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");
+ assertOutput("${ti?string?lowerCase}", "2015-09-06t12:00:00z");
assertErrorContains("${dt?lowerCase}", "convert", "string", "markup", "text/html");
+ assertErrorContains("${ti?lowerCase}", "convert", "string", "markup", "text/html");
assertOutput("${b?upperCase}", "Y");
assertErrorContains("${m?upperCase}", "convertible to string", "HTMLOutputModel");
}
@@ -62,6 +63,8 @@ public class CoercionToTextualTest extends TemplateTest {
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("${ti?string?esc}", "2015-09-06T12:00:00Z");
+ assertOutput("${ti?esc}", "2015-09-06<span class='T'>T</span>12:00:00Z");
assertOutput("${b?esc}", "<y>");
assertOutput("${m?esc}", "<p>M</p>");
}
@@ -74,6 +77,8 @@ public class CoercionToTextualTest extends TemplateTest {
assertErrorContains("${n?indexOf('E')}", "convert", "string", "markup", "text/html");
assertOutput("${dt?string?contains('0')}", "y");
assertErrorContains("${dt?contains('0')}", "convert", "string", "markup", "text/html");
+ assertOutput("${ti?string?contains('0')}", "y");
+ assertErrorContains("${ti?contains('0')}", "convert", "string", "markup", "text/html");
assertErrorContains("${m?contains('0')}", "convertible to string", "HTMLOutputModel");
assertErrorContains("${m?indexOf('0')}", "convertible to string", "HTMLOutputModel");
}
@@ -83,6 +88,7 @@ public class CoercionToTextualTest extends TemplateTest {
assertErrorContains("${n?string?markupString}", "Expected", "markup", "string");
assertErrorContains("${n?markupString}", "Expected", "markup", "number");
assertErrorContains("${dt?markupString}", "Expected", "markup", "date");
+ assertErrorContains("${ti?markupString}", "Expected", "markup", "temporal");
}
@Test
@@ -92,6 +98,8 @@ public class CoercionToTextualTest extends TemplateTest {
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("${ti?string}", "2015-09-06T12:00:00Z");
+ assertOutput("${ti}", "2015-09-06<span class='T'>T</span>12:00:00Z");
assertOutput("${b}", "y");
assertOutput("${m}", "<p>M</p>");
}
@@ -103,6 +111,8 @@ public class CoercionToTextualTest extends TemplateTest {
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("${ti?string + '&'}", "2015-09-06T12:00:00Z&");
+ assertOutput("${ti + '&'}", "2015-09-06<span class='T'>T</span>12:00:00Z&");
assertOutput("${b + '&'}", "y&");
assertOutput("${m + '&'}", "<p>M</p>&");
}
@@ -114,6 +124,8 @@ public class CoercionToTextualTest extends TemplateTest {
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("${'&' + ti?string}", "&2015-09-06T12:00:00Z");
+ assertOutput("${'&' + ti}", "&2015-09-06<span class='T'>T</span>12:00:00Z");
assertOutput("${'&' + b}", "&y");
assertOutput("${'&' + m}", "&<p>M</p>");
}
@@ -123,13 +135,18 @@ public class CoercionToTextualTest extends TemplateTest {
Configuration cfg = getConfiguration();
cfg.setCustomNumberFormats(Collections.singletonMap("G", PrintfGTemplateNumberFormatFactory.INSTANCE));
cfg.setCustomDateFormats(Collections.singletonMap("HI", HTMLISOTemplateDateFormatFactory.INSTANCE));
+ cfg.setCustomTemporalFormats(Collections.singletonMap("HI", HTMLISOTemplateTemporalFormatFactory.INSTANCE));
cfg.setNumberFormat("@G 3");
cfg.setDateTimeFormat("@HI");
+ cfg.setInstantFormat("@HI");
cfg.setBooleanFormat("y,n");
-
+ cfg.setTimeZone(DateUtil.UTC);
+
addToDataModel("s", "abc");
addToDataModel("n", 1500);
- addToDataModel("dt", TM);
+ long epochMillis = 1441540800000L; // 2015-09-06T12:00:00Z
+ addToDataModel("dt", new SimpleDate(new Date(epochMillis), TemplateDateModel.DATETIME));
+ addToDataModel("ti", new SimpleTemporal(Instant.ofEpochMilli(epochMillis)));
addToDataModel("b", Boolean.TRUE);
addToDataModel("m", HTMLOutputFormat.INSTANCE.fromMarkup("<p>M</p>"));
}
diff --git a/src/test/java/freemarker/core/LocAndTZSensitiveTemporalFormatFactory.java b/src/test/java/freemarker/core/LocAndTZSensitiveTemplateTemporalFormatFactory.java
similarity index 90%
rename from src/test/java/freemarker/core/LocAndTZSensitiveTemporalFormatFactory.java
rename to src/test/java/freemarker/core/LocAndTZSensitiveTemplateTemporalFormatFactory.java
index 4b7b46a..446f3c3 100644
--- a/src/test/java/freemarker/core/LocAndTZSensitiveTemporalFormatFactory.java
+++ b/src/test/java/freemarker/core/LocAndTZSensitiveTemplateTemporalFormatFactory.java
@@ -26,11 +26,12 @@ import java.util.TimeZone;
import freemarker.template.TemplateModelException;
import freemarker.template.TemplateTemporalModel;
-public class LocAndTZSensitiveTemporalFormatFactory extends TemplateTemporalFormatFactory {
+public class LocAndTZSensitiveTemplateTemporalFormatFactory extends TemplateTemporalFormatFactory {
- public static final LocAndTZSensitiveTemporalFormatFactory INSTANCE = new LocAndTZSensitiveTemporalFormatFactory();
+ public static final LocAndTZSensitiveTemplateTemporalFormatFactory
+ INSTANCE = new LocAndTZSensitiveTemplateTemporalFormatFactory();
- private LocAndTZSensitiveTemporalFormatFactory() {
+ private LocAndTZSensitiveTemplateTemporalFormatFactory() {
// Defined to decrease visibility
}
diff --git a/src/test/java/freemarker/core/TemplateConfigurationTest.java b/src/test/java/freemarker/core/TemplateConfigurationTest.java
index c5aa08b..dc1dba1 100644
--- a/src/test/java/freemarker/core/TemplateConfigurationTest.java
+++ b/src/test/java/freemarker/core/TemplateConfigurationTest.java
@@ -343,6 +343,9 @@ public class TemplateConfigurationTest {
tc1.setCustomDateFormats(ImmutableMap.of(
"epoch", EpochMillisTemplateDateFormatFactory.INSTANCE,
"x", LocAndTZSensitiveTemplateDateFormatFactory.INSTANCE));
+ tc1.setCustomTemporalFormats(ImmutableMap.of(
+ "epoch", EpochMillisTemplateTemporalFormatFactory.INSTANCE,
+ "x", LocAndTZSensitiveTemplateTemporalFormatFactory.INSTANCE));
tc1.setCustomNumberFormats(ImmutableMap.of(
"hex", HexTemplateNumberFormatFactory.INSTANCE,
"x", LocaleSensitiveTemplateNumberFormatFactory.INSTANCE));
@@ -352,6 +355,9 @@ public class TemplateConfigurationTest {
tc2.setCustomDateFormats(ImmutableMap.of(
"loc", LocAndTZSensitiveTemplateDateFormatFactory.INSTANCE,
"x", EpochMillisDivTemplateDateFormatFactory.INSTANCE));
+ tc2.setCustomTemporalFormats(ImmutableMap.of(
+ "loc", LocAndTZSensitiveTemplateTemporalFormatFactory.INSTANCE,
+ "x", EpochMillisDivTemplateTemporalFormatFactory.INSTANCE));
tc2.setCustomNumberFormats(ImmutableMap.of(
"loc", LocaleSensitiveTemplateNumberFormatFactory.INSTANCE,
"x", BaseNTemplateNumberFormatFactory.INSTANCE));
@@ -364,6 +370,11 @@ public class TemplateConfigurationTest {
assertEquals(LocAndTZSensitiveTemplateDateFormatFactory.INSTANCE, mergedCustomDateFormats.get("loc"));
assertEquals(EpochMillisDivTemplateDateFormatFactory.INSTANCE, mergedCustomDateFormats.get("x"));
+ Map<String, ? extends TemplateTemporalFormatFactory> mergedCustomTemporalFormats = tc1.getCustomTemporalFormats();
+ assertEquals(EpochMillisTemplateTemporalFormatFactory.INSTANCE, mergedCustomTemporalFormats.get("epoch"));
+ assertEquals(LocAndTZSensitiveTemplateTemporalFormatFactory.INSTANCE, mergedCustomTemporalFormats.get("loc"));
+ assertEquals(EpochMillisDivTemplateTemporalFormatFactory.INSTANCE, mergedCustomTemporalFormats.get("x"));
+
Map<String, ? extends TemplateNumberFormatFactory> mergedCustomNumberFormats = tc1.getCustomNumberFormats();
assertEquals(HexTemplateNumberFormatFactory.INSTANCE, mergedCustomNumberFormats.get("hex"));
assertEquals(LocaleSensitiveTemplateNumberFormatFactory.INSTANCE, mergedCustomNumberFormats.get("loc"));
@@ -377,12 +388,14 @@ public class TemplateConfigurationTest {
// Empty map merging optimization:
tc1.merge(new TemplateConfiguration());
assertSame(mergedCustomDateFormats, tc1.getCustomDateFormats());
+ assertSame(mergedCustomTemporalFormats, tc1.getCustomTemporalFormats());
assertSame(mergedCustomNumberFormats, tc1.getCustomNumberFormats());
// Empty map merging optimization:
TemplateConfiguration tc3 = new TemplateConfiguration();
tc3.merge(tc1);
assertSame(mergedCustomDateFormats, tc3.getCustomDateFormats());
+ assertSame(mergedCustomTemporalFormats, tc3.getCustomTemporalFormats());
assertSame(mergedCustomNumberFormats, tc3.getCustomNumberFormats());
}
diff --git a/src/test/java/freemarker/core/TemporalFormatTest2.java b/src/test/java/freemarker/core/TemporalFormatTest2.java
index 215eb7c..c519c68 100644
--- a/src/test/java/freemarker/core/TemporalFormatTest2.java
+++ b/src/test/java/freemarker/core/TemporalFormatTest2.java
@@ -46,7 +46,7 @@ public class TemporalFormatTest2 extends TemplateTest {
cfg.setCustomTemporalFormats(ImmutableMap.of(
"epoch", EpochMillisTemplateTemporalFormatFactory.INSTANCE,
- "loc", LocAndTZSensitiveTemporalFormatFactory.INSTANCE,
+ "loc", LocAndTZSensitiveTemplateTemporalFormatFactory.INSTANCE,
"div", EpochMillisDivTemplateTemporalFormatFactory.INSTANCE,
"htmlIso", HTMLISOTemplateTemporalFormatFactory.INSTANCE));
}
diff --git a/src/test/java/freemarker/template/ConfigurationTest.java b/src/test/java/freemarker/template/ConfigurationTest.java
index 9bf0609..a377922 100644
--- a/src/test/java/freemarker/template/ConfigurationTest.java
+++ b/src/test/java/freemarker/template/ConfigurationTest.java
@@ -64,7 +64,9 @@ import freemarker.core.DefaultTruncateBuiltinAlgorithm;
import freemarker.core.DummyOutputFormat;
import freemarker.core.Environment;
import freemarker.core.EpochMillisDivTemplateDateFormatFactory;
+import freemarker.core.EpochMillisDivTemplateTemporalFormatFactory;
import freemarker.core.EpochMillisTemplateDateFormatFactory;
+import freemarker.core.EpochMillisTemplateTemporalFormatFactory;
import freemarker.core.HTMLOutputFormat;
import freemarker.core.HexTemplateNumberFormatFactory;
import freemarker.core.MarkupOutputFormat;
@@ -75,6 +77,7 @@ import freemarker.core.RTFOutputFormat;
import freemarker.core.TemplateClassResolver;
import freemarker.core.TemplateDateFormatFactory;
import freemarker.core.TemplateNumberFormatFactory;
+import freemarker.core.TemplateTemporalFormatFactory;
import freemarker.core.UndefinedOutputFormat;
import freemarker.core.UnregisteredOutputFormatException;
import freemarker.core.XHTMLOutputFormat;
@@ -1566,6 +1569,78 @@ public class ConfigurationTest extends TestCase {
containsString(TemplateDateFormatFactory.class.getName())));
}
}
+ @SuppressFBWarnings(value="NP_NULL_PARAM_DEREF_ALL_TARGETS_DANGEROUS", justification="We test failures")
+ @Test
+ public void testSetCustomTemporalFormat() throws Exception {
+ Configuration cfg = new Configuration(Configuration.VERSION_2_3_0);
+
+ try {
+ cfg.setCustomTemporalFormats(null);
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertThat(e.getMessage(), containsString("null"));
+ }
+
+ try {
+ cfg.setCustomTemporalFormats(Collections.singletonMap("", EpochMillisTemplateTemporalFormatFactory.INSTANCE));
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertThat(e.getMessage(), containsString("0 length"));
+ }
+
+ try {
+ cfg.setCustomTemporalFormats(Collections.singletonMap("a_b", EpochMillisTemplateTemporalFormatFactory.INSTANCE));
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertThat(e.getMessage(), containsString("a_b"));
+ }
+
+ try {
+ cfg.setCustomTemporalFormats(Collections.singletonMap("a b", EpochMillisTemplateTemporalFormatFactory.INSTANCE));
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertThat(e.getMessage(), containsString("a b"));
+ }
+
+ try {
+ cfg.setCustomTemporalFormats(ImmutableMap.of(
+ "a", EpochMillisTemplateTemporalFormatFactory.INSTANCE,
+ "@wrong", EpochMillisTemplateTemporalFormatFactory.INSTANCE));
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertThat(e.getMessage(), containsString("@wrong"));
+ }
+
+ cfg.setSetting(Configurable.CUSTOM_TEMPORAL_FORMATS_KEY_CAMEL_CASE,
+ "{ 'epoch': " + EpochMillisTemplateTemporalFormatFactory.class.getName() + "() }");
+ assertEquals(
+ Collections.singletonMap("epoch", EpochMillisTemplateTemporalFormatFactory.INSTANCE),
+ cfg.getCustomTemporalFormats());
+
+ cfg.setSetting(Configurable.CUSTOM_TEMPORAL_FORMATS_KEY_SNAKE_CASE,
+ "{ "
+ + "'epoch': " + EpochMillisTemplateTemporalFormatFactory.class.getName() + "(), "
+ + "'epochDiv': " + EpochMillisDivTemplateTemporalFormatFactory.class.getName() + "()"
+ + " }");
+ assertEquals(
+ ImmutableMap.of(
+ "epoch", EpochMillisTemplateTemporalFormatFactory.INSTANCE,
+ "epochDiv", EpochMillisDivTemplateTemporalFormatFactory.INSTANCE),
+ cfg.getCustomTemporalFormats());
+
+ cfg.setSetting(Configurable.CUSTOM_TEMPORAL_FORMATS_KEY, "{}");
+ assertEquals(Collections.emptyMap(), cfg.getCustomTemporalFormats());
+
+ try {
+ cfg.setSetting(Configurable.CUSTOM_TEMPORAL_FORMATS_KEY_CAMEL_CASE,
+ "{ 'x': " + HexTemplateNumberFormatFactory.class.getName() + "() }");
+ fail();
+ } catch (TemplateException e) {
+ assertThat(e.getCause().getMessage(), allOf(
+ containsString(HexTemplateNumberFormatFactory.class.getName()),
+ containsString(TemplateTemporalFormatFactory.class.getName())));
+ }
+ }
@Test
public void testHasCustomFormats() throws IOException, TemplateException {
@@ -1605,7 +1680,43 @@ public class ConfigurationTest extends TestCase {
assertFalse(cfg.hasCustomFormats());
assertFalse(t.hasCustomFormats());
assertFalse(env.hasCustomFormats());
-
+
+ // Same with temporal formats:
+
+ assertFalse(cfg.hasCustomFormats());
+ assertFalse(t.hasCustomFormats());
+ assertFalse(env.hasCustomFormats());
+
+ env.setCustomTemporalFormats(Collections.singletonMap("f", EpochMillisTemplateTemporalFormatFactory.INSTANCE));
+ assertFalse(t.hasCustomFormats());
+ assertTrue(env.hasCustomFormats());
+ t.setCustomTemporalFormats(Collections.singletonMap("f", EpochMillisTemplateTemporalFormatFactory.INSTANCE));
+ assertFalse(cfg.hasCustomFormats());
+ assertTrue(t.hasCustomFormats());
+ cfg.setCustomTemporalFormats(Collections.singletonMap("f", EpochMillisTemplateTemporalFormatFactory.INSTANCE));
+ assertTrue(cfg.hasCustomFormats());
+ assertTrue(t.hasCustomFormats());
+ assertTrue(env.hasCustomFormats());
+
+ cfg.setCustomTemporalFormats(Collections.emptyMap());
+ t.setCustomTemporalFormats(Collections.emptyMap());
+ env.setCustomTemporalFormats(Collections.emptyMap());
+ assertFalse(cfg.hasCustomFormats());
+ assertFalse(t.hasCustomFormats());
+ assertFalse(env.hasCustomFormats());
+
+ cfg.setCustomTemporalFormats(Collections.singletonMap("f", EpochMillisTemplateTemporalFormatFactory.INSTANCE));
+ assertTrue(cfg.hasCustomFormats());
+ assertTrue(t.hasCustomFormats());
+ assertTrue(env.hasCustomFormats());
+
+ cfg.setCustomTemporalFormats(Collections.emptyMap());
+ t.setCustomTemporalFormats(Collections.emptyMap());
+ env.setCustomTemporalFormats(Collections.emptyMap());
+ assertFalse(cfg.hasCustomFormats());
+ assertFalse(t.hasCustomFormats());
+ assertFalse(env.hasCustomFormats());
+
// Same with number formats:
env.setCustomNumberFormats(Collections.singletonMap("f", HexTemplateNumberFormatFactory.INSTANCE));