diff --git a/src/test/java/org/javarosa/core/model/data/test/TimeDataLimitationsTest.java b/src/test/java/org/javarosa/core/model/data/test/TimeDataLimitationsTest.java
index 2bd0b14ac..9b4b51969 100644
--- a/src/test/java/org/javarosa/core/model/data/test/TimeDataLimitationsTest.java
+++ b/src/test/java/org/javarosa/core/model/data/test/TimeDataLimitationsTest.java
@@ -1,63 +1,54 @@
package org.javarosa.core.model.data.test;
+import static org.javarosa.test.utils.SystemHelper.withTimeZone;
+import static org.junit.Assert.assertEquals;
+
+import java.util.Date;
+import java.util.TimeZone;
import org.javarosa.core.model.data.TimeData;
import org.javarosa.core.model.utils.DateUtils;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Test;
-import java.util.Date;
-import java.util.TimeZone;
-
-import static org.junit.Assert.assertEquals;
/**
- This test is intended to show the limitation of {@link TimeData}.
-
- Using this data type in countries which change their time (summer/winter - DST) will cause that forms saved during
- wintertime and then edited during summertime (and vice versa) will be treated as saved in a neighbor's timezone.
- It's because we have just time and time offset like: 10:00:00.000+02:00 but we don't know when the form has been
- saved so we parse it using the current date.
-
- Example:
- If we saved 10:00:00.000+02:00 during summertime (in Poland) and we are editing the form during winter time our
- timezone is +01:00 not +02:00. As mentioned above javarosa doesn't know that the form has been saved in the same location
- but different timezone because of DST so it treats the value like saved in the neighbor timezone
- (in Kiev or London for example).
-
- Related issues:
- https://github.com/opendatakit/javarosa/pull/478
- https://github.com/opendatakit/collect/issues/170
+ * This test is intended to show the limitation of {@link TimeData}.
+ *
+ * Using this data type in countries which change their time (summer/winter - DST) will cause that forms saved during
+ * wintertime and then edited during summertime (and vice versa) will be treated as saved in a neighbor's timezone.
+ * It's because we have just time and time offset like: 10:00:00.000+02:00 but we don't know when the form has been
+ * saved so we parse it using the current date.
+ *
+ * Example:
+ * If we saved 10:00:00.000+02:00 during summertime (in Poland) and we are editing the form during winter time our
+ * timezone is +01:00 not +02:00. As mentioned above javarosa doesn't know that the form has been saved in the same location
+ * but different timezone because of DST so it treats the value like saved in the neighbor timezone
+ * (in Kiev or London for example).
+ *
+ * Related issues:
+ * https://github.com/opendatakit/javarosa/pull/478
+ * https://github.com/opendatakit/collect/issues/170
*/
public class TimeDataLimitationsTest {
-
- private TimeZone backupTimeZone;
-
- @Before
- public void setUp() {
- backupTimeZone = TimeZone.getDefault();
- }
-
- @After
- public void tearDown() {
- TimeZone.setDefault(backupTimeZone);
- }
+ public static final TimeZone WARSAW = TimeZone.getTimeZone("Europe/Warsaw");
+ public static final TimeZone KIEV = TimeZone.getTimeZone("Europe/Kiev");
@Test
public void editingFormsSavedInDifferentTimezoneTest() {
+ StringWrapper savedTime = StringWrapper.empty();
// A user is in Warsaw (GMT+2) saved a form with the time question
- TimeZone.setDefault(TimeZone.getTimeZone("Europe/Warsaw"));
-
- boolean isSummerTime = TimeZone.getDefault().inDaylightTime(new Date());
- String savedTime = isSummerTime ? "10:00:00.000+02:00" : "10:00:00.000+01:00";
-
- // A user opens saved form in Warsaw as well - the hour should be the same
- TimeData timeData = new TimeData(DateUtils.parseTime(savedTime));
- assertEquals("10:00", timeData.getDisplayText());
-
+ withTimeZone(WARSAW, () -> {
+ boolean isSummerTime = TimeZone.getDefault().inDaylightTime(new Date());
+ savedTime.set(isSummerTime ? "10:00:00.000+02:00" : "10:00:00.000+01:00");
+
+ // A user opens saved form in Warsaw as well - the hour should be the same
+ TimeData timeData = new TimeData(DateUtils.parseTime(savedTime.get()));
+ assertEquals("10:00", timeData.getDisplayText());
+ });
// A user travels to Kiev (GMT+3) and opens the saved form again - the hour should be edited +1h
- TimeZone.setDefault(TimeZone.getTimeZone("Europe/Kiev"));
- timeData = new TimeData(DateUtils.parseTime(savedTime));
- assertEquals("11:00", timeData.getDisplayText());
+ withTimeZone(KIEV, () -> {
+ TimeData timeData = new TimeData(DateUtils.parseTime(savedTime.get()));
+ assertEquals("11:00", timeData.getDisplayText());
+ });
+
}
@Test
@@ -67,17 +58,37 @@ public void editingFormsSavedInTheSameLocationButAfterDSTChangeTest() {
dateFields.month = 8;
dateFields.day = 1;
- // A user is in Warsaw (during summer time - GMT+2) and saved a form with the time question
- TimeZone.setDefault(TimeZone.getTimeZone("Europe/Warsaw"));
- String savedTime = "10:00:00.000+02:00";
+ withTimeZone(WARSAW, () -> {
+ String savedTime = "10:00:00.000+02:00";
+
+ // A user opens saved form in Warsaw and during summertime as well - the hour should be the same
+ TimeData timeData = new TimeData(DateUtils.parseTimeWithFixedDate(savedTime, dateFields));
+ assertEquals("10:00", timeData.getDisplayText());
+
+ // A user opens saved form in Warsaw as well but during wintertime - the hour is edited -1h (the mentioned limitation)
+ dateFields.month = 12;
+ timeData = new TimeData(DateUtils.parseTimeWithFixedDate(savedTime, dateFields));
+ assertEquals("09:00", timeData.getDisplayText());
+ });
+ }
+
+ static class StringWrapper {
+ private String value;
+
+ StringWrapper(String value) {
+ this.value = value;
+ }
+
+ static StringWrapper empty() {
+ return new StringWrapper("");
+ }
- // A user opens saved form in Warsaw and during summertime as well - the hour should be the same
- TimeData timeData = new TimeData(DateUtils.parseTimeWithFixedDate(savedTime, dateFields));
- assertEquals("10:00", timeData.getDisplayText());
+ public String get() {
+ return value;
+ }
- // A user opens saved form in Warsaw as well but during wintertime - the hour is edited -1h (the mentioned limitation)
- dateFields.month = 12;
- timeData = new TimeData(DateUtils.parseTimeWithFixedDate(savedTime, dateFields));
- assertEquals("09:00", timeData.getDisplayText());
+ public void set(String value) {
+ this.value = value;
+ }
}
}
diff --git a/src/test/java/org/javarosa/core/model/utils/test/DateUtilsFormatLocalizationTests.java b/src/test/java/org/javarosa/core/model/utils/test/DateUtilsFormatLocalizationTests.java
new file mode 100644
index 000000000..e6cacc908
--- /dev/null
+++ b/src/test/java/org/javarosa/core/model/utils/test/DateUtilsFormatLocalizationTests.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2009 JavaRosa
+ *
+ * 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.
+ */
+
+package org.javarosa.core.model.utils.test;
+
+import static java.time.DayOfWeek.SUNDAY;
+import static java.time.Month.JANUARY;
+import static java.time.format.TextStyle.SHORT;
+import static org.hamcrest.Matchers.is;
+import static org.javarosa.test.utils.SystemHelper.withLocale;
+import static org.junit.Assert.assertThat;
+
+import java.time.LocalDateTime;
+import java.time.OffsetDateTime;
+import java.util.Date;
+import java.util.Locale;
+import java.util.stream.Stream;
+import org.javarosa.core.model.utils.DateUtils;
+import org.junit.Test;
+
+public class DateUtilsFormatLocalizationTests {
+ @Test
+ public void format_is_localized() {
+ // Use a Sunday in January for our test
+ LocalDateTime localDateTime = LocalDateTime.parse("2018-01-07T10:20:30.400");
+ Date date = Date.from(localDateTime.toInstant(OffsetDateTime.now().getOffset()));
+
+ Stream.of(
+ Locale.ENGLISH,
+ Locale.forLanguageTag("es-ES"),
+ Locale.FRENCH
+ ).forEach(locale -> withLocale(locale, l -> {
+ assertThat(DateUtils.format(date, "%b"), is(JANUARY.getDisplayName(SHORT, l)));
+ assertThat(DateUtils.format(date, "%a"), is(SUNDAY.getDisplayName(SHORT, l)));
+ }));
+ }
+
+}
diff --git a/src/test/java/org/javarosa/core/model/utils/test/DateUtilsFormatSanityCheckTests.java b/src/test/java/org/javarosa/core/model/utils/test/DateUtilsFormatSanityCheckTests.java
new file mode 100644
index 000000000..29d93b530
--- /dev/null
+++ b/src/test/java/org/javarosa/core/model/utils/test/DateUtilsFormatSanityCheckTests.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2009 JavaRosa
+ *
+ * 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.
+ */
+
+package org.javarosa.core.model.utils.test;
+
+import static java.util.TimeZone.getTimeZone;
+import static org.hamcrest.Matchers.is;
+import static org.javarosa.core.model.utils.DateUtils.FORMAT_ISO8601;
+import static org.javarosa.core.model.utils.DateUtils.formatDateTime;
+import static org.javarosa.core.model.utils.DateUtils.parseDateTime;
+import static org.javarosa.test.utils.SystemHelper.withTimeZone;
+import static org.junit.Assert.assertThat;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.TimeZone;
+import java.util.stream.Stream;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class DateUtilsFormatSanityCheckTests {
+ @Parameterized.Parameter(value = 0)
+ public long inputTimestamp;
+
+ @Parameterized.Parameters(name = "Input timestamp: {0}")
+ public static Collection data() {
+ return Arrays.asList(new Object[][]{
+ {1300139579000L},
+ {0}
+ });
+ }
+
+ @Test
+ public void sanity_check_iso_format_and_parse_back() {
+ Date input = new Date(inputTimestamp);
+ Stream.of(
+ TimeZone.getDefault(),
+ getTimeZone("UTC"),
+ getTimeZone("GMT+12"),
+ getTimeZone("GMT-13"),
+ getTimeZone("GMT+0230")
+ ).forEach(timeZone -> withTimeZone(timeZone, () ->
+ assertThat(parseDateTime(formatDateTime(input, FORMAT_ISO8601)), is(input))));
+ }
+}
diff --git a/src/test/java/org/javarosa/core/model/utils/test/DateUtilsGetXmlStringValueTest.java b/src/test/java/org/javarosa/core/model/utils/test/DateUtilsGetXmlStringValueTest.java
new file mode 100644
index 000000000..baf1adbbd
--- /dev/null
+++ b/src/test/java/org/javarosa/core/model/utils/test/DateUtilsGetXmlStringValueTest.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2009 JavaRosa
+ *
+ * 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.
+ */
+
+package org.javarosa.core.model.utils.test;
+
+import static org.hamcrest.Matchers.is;
+import static org.javarosa.core.model.utils.DateUtils.getXMLStringValue;
+import static org.junit.Assert.assertThat;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.OffsetDateTime;
+import java.util.Date;
+import org.junit.Test;
+
+public class DateUtilsGetXmlStringValueTest {
+ /**
+ * This test ensures that the Strings returned
+ * by the getXMLStringValue function are in
+ * the proper XML compliant format, which can be
+ * parsed by LocalDate.parse()
+ */
+ @Test
+ public void xml_string_is_well_formatted() {
+ LocalDateTime nowDateTime = LocalDateTime.now();
+ Date nowDate = Date.from(nowDateTime.toInstant(OffsetDateTime.now().getOffset()));
+ String nowXmlFormatterDate = getXMLStringValue(nowDate);
+ assertThat(LocalDate.parse(nowXmlFormatterDate), is(nowDateTime.toLocalDate()));
+ }
+
+}
diff --git a/src/test/java/org/javarosa/core/model/utils/test/DateUtilsParseDateTimeTests.java b/src/test/java/org/javarosa/core/model/utils/test/DateUtilsParseDateTimeTests.java
new file mode 100644
index 000000000..b6bd0c179
--- /dev/null
+++ b/src/test/java/org/javarosa/core/model/utils/test/DateUtilsParseDateTimeTests.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2009 JavaRosa
+ *
+ * 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.
+ */
+
+package org.javarosa.core.model.utils.test;
+
+import static java.util.TimeZone.getTimeZone;
+import static org.hamcrest.Matchers.is;
+import static org.javarosa.test.utils.SystemHelper.withTimeZone;
+import static org.junit.Assert.assertThat;
+
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.OffsetDateTime;
+import java.time.ZoneId;
+import java.time.temporal.Temporal;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Objects;
+import java.util.TimeZone;
+import java.util.stream.Stream;
+import org.javarosa.core.model.utils.DateUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class DateUtilsParseDateTimeTests {
+ @Parameterized.Parameter(value = 0)
+ public String input;
+
+ @Parameterized.Parameter(value = 1)
+ public Temporal expectedDateTime;
+
+ @Parameterized.Parameters(name = "Input: {0}")
+ public static Collection data() {
+ return Arrays.asList(new Object[][]{
+ {"2016-04-13T16:26:00.000", LocalDateTime.parse("2016-04-13T16:26:00.000")},
+ {"2016-04-13T16:26:00.000-07", OffsetDateTime.parse("2016-04-13T16:26:00.000-07:00")},
+ {"2015-12-16T16:09:00.000-08", OffsetDateTime.parse("2015-12-16T16:09:00.000-08:00")},
+ {"2015-12-16T07:09:00.000+08", OffsetDateTime.parse("2015-12-16T07:09:00.000+08:00")},
+ {"2015-11-30T16:09:00.000-08", OffsetDateTime.parse("2015-11-30T16:09:00.000-08:00")},
+ {"2015-11-01T07:09:00.000+08", OffsetDateTime.parse("2015-11-01T07:09:00.000+08:00")},
+ {"2015-12-31T16:09:00.000-08", OffsetDateTime.parse("2015-12-31T16:09:00.000-08:00")},
+ });
+ }
+
+ @Test
+ public void parseDateTime_produces_expected_results_in_all_time_zones() {
+ Stream.of(
+ TimeZone.getDefault(),
+ getTimeZone("UTC"),
+ getTimeZone("GMT+12"),
+ getTimeZone("GMT-13"),
+ getTimeZone("GMT+0230")
+ ).forEach(tz -> withTimeZone(tz, () -> assertThat(parseDateTime(input), is(expectedDateTime))));
+ }
+
+ /**
+ * Returns a LocalDateTime or an OffsetTimeTime obtained from the result of
+ * calling DateUtils.parseDateTime() with the provided input, ensuring that
+ * both represent the same instant.
+ */
+ private Temporal parseDateTime(String input) {
+ Instant inputInstant = Objects.requireNonNull(DateUtils.parseDateTime(input)).toInstant();
+
+ String timePart = input.substring(11);
+ if (timePart.contains("+") || timePart.contains("-")) {
+ // The input declares some positive or negative time offset
+ int beginOfOffsetPart = timePart.contains("+") ? timePart.indexOf("+") : timePart.indexOf("-");
+ String offsetPart = timePart.substring(beginOfOffsetPart);
+ // The input declares some positive or negative time offset
+ String offset = offsetPart.length() == 3 ? offsetPart + ":00" : offsetPart;
+ return OffsetDateTime.ofInstant(inputInstant, ZoneId.of(offset));
+ }
+
+ if (input.endsWith("Z"))
+ // The input time is at UTC
+ return OffsetDateTime.ofInstant(inputInstant, ZoneId.of("Z"));
+
+ // No time offset declared. Return a LocalTime
+ return LocalDateTime.ofInstant(inputInstant, ZoneId.systemDefault());
+ }
+}
diff --git a/src/test/java/org/javarosa/core/model/utils/test/DateUtilsParseTimeTests.java b/src/test/java/org/javarosa/core/model/utils/test/DateUtilsParseTimeTests.java
new file mode 100644
index 000000000..097dbf48f
--- /dev/null
+++ b/src/test/java/org/javarosa/core/model/utils/test/DateUtilsParseTimeTests.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2009 JavaRosa
+ *
+ * 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.
+ */
+
+package org.javarosa.core.model.utils.test;
+
+import static java.util.TimeZone.getTimeZone;
+import static org.hamcrest.Matchers.is;
+import static org.javarosa.test.utils.SystemHelper.withTimeZone;
+import static org.junit.Assert.assertThat;
+
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.OffsetDateTime;
+import java.time.OffsetTime;
+import java.time.ZoneId;
+import java.time.temporal.Temporal;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Objects;
+import java.util.TimeZone;
+import java.util.stream.Stream;
+import org.javarosa.core.model.utils.DateUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class DateUtilsParseTimeTests {
+ @Parameterized.Parameter(value = 0)
+ public String input;
+
+ @Parameterized.Parameter(value = 1)
+ public Temporal expectedTime;
+
+ @Parameterized.Parameters(name = "Input: {0}")
+ public static Collection data() {
+ return Arrays.asList(new Object[][]{
+ {"14:00", LocalTime.parse("14:00")},
+ {"14:00Z", OffsetTime.parse("14:00Z")},
+ {"14:00+02", OffsetTime.parse("14:00+02:00")},
+ {"14:00-02", OffsetTime.parse("14:00-02:00")},
+ {"14:00+02:30", OffsetTime.parse("14:00+02:30")},
+ {"14:00-02:30", OffsetTime.parse("14:00-02:30")},
+ });
+ }
+
+ @Test
+ public void parseTime_produces_expected_results_in_all_time_zones() {
+ // The tricky part of DateUtils.parseTime is that we allow for input time
+ // values to include time offset declarations, which has issues at different
+ // levels:
+ // - Conceptually, time values with offsets don't make sense until they're
+ // paired with a date so, how can we reason about what "10:00+02:00" means,
+ // and what should be a valid expected output for that input value?
+ // - Next, DateUtils.parseTime() produces Date values, which are a date and a
+ // time in the system's default time zone. Then, which date would we have to
+ // expect?
+ //
+ // To solve these issues, DateUtils.parseTime() will use the system's current
+ // date as a base for its output value whenever that is and whichever time zone
+ // the system's at.
+ //
+ // By testing parseTime under different system default time zones we're trying
+ // to have the confidence that our resulting Date objects will always translate
+ // to the same time declaration from the input string (ignoring their date part,
+ // of course).
+ Stream.of(
+ TimeZone.getDefault(),
+ getTimeZone("UTC"),
+ getTimeZone("GMT+12"),
+ getTimeZone("GMT-13"),
+ getTimeZone("GMT+0230")
+ ).forEach(tz -> withTimeZone(tz, () -> assertThat(parseTime(input), is(expectedTime))));
+ }
+
+ /**
+ * Returns a LocalTime or a OffsetTime obtained from the result of
+ * calling DateUtils.parseTime() with the provided input.
+ *
+ * The interim OffsetDateTime value ensures that it represents the
+ * same instant as the Date from the call to DateUtils.parseTime().
+ */
+ public Temporal parseTime(String input) {
+ Instant inputInstant = Objects.requireNonNull(DateUtils.parseTime(input)).toInstant();
+
+ if (input.contains("+") || input.contains("-")) {
+ // The input declares some positive or negative time offset
+ int beginOfOffsetPart = input.contains("+") ? input.indexOf("+") : input.indexOf("-");
+ String offsetPart = input.substring(beginOfOffsetPart);
+ // The input declares some positive or negative time offset
+ String offset = offsetPart.length() == 3 ? offsetPart + ":00" : offsetPart;
+ return OffsetDateTime.ofInstant(inputInstant, ZoneId.of(offset)).toOffsetTime();
+ }
+
+ if (input.endsWith("Z"))
+ // The input time is at UTC
+ return OffsetDateTime.ofInstant(inputInstant, ZoneId.of("Z")).toOffsetTime();
+
+ // No time offset declared. Return a LocalTime
+ return LocalDateTime.ofInstant(inputInstant, ZoneId.systemDefault()).toLocalTime();
+ }
+}
diff --git a/src/test/java/org/javarosa/core/model/utils/test/DateUtilsSCTOTests.java b/src/test/java/org/javarosa/core/model/utils/test/DateUtilsSCTOTests.java
index f04620ac8..eae831008 100644
--- a/src/test/java/org/javarosa/core/model/utils/test/DateUtilsSCTOTests.java
+++ b/src/test/java/org/javarosa/core/model/utils/test/DateUtilsSCTOTests.java
@@ -6,67 +6,50 @@
package org.javarosa.core.model.utils.test;
+import static org.javarosa.test.utils.SystemHelper.withTimeZone;
import static org.junit.Assert.assertEquals;
import java.util.Calendar;
import java.util.Date;
-import java.util.Locale;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
import org.javarosa.core.model.utils.DateUtils;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
public class DateUtilsSCTOTests {
- private Locale backupLocale;
- private TimeZone backupZone;
-
- @Before
- public void setUp() {
- backupLocale = Locale.getDefault();
- backupZone = TimeZone.getDefault();
- }
-
- @After
- public void tearDown() {
- TimeZone.setDefault(backupZone);
- Locale.setDefault(backupLocale);
- }
-
@Test
public void testParseDateTime() {
- TimeZone.setDefault(TimeZone.getTimeZone("GMT+02"));
+ withTimeZone(TimeZone.getTimeZone("GMT+02"), () -> {
+ Date date = DateUtils.parseDateTime("2014-10-05T00:03:05.244+03");
+ String str = DateUtils.formatDateTime(date, DateUtils.FORMAT_ISO8601);
- Date date = DateUtils.parseDateTime("2014-10-05T00:03:05.244+03");
- String str = DateUtils.formatDateTime(date, DateUtils.FORMAT_ISO8601);
-
- assertEquals("2014-10-04T23:03:05.244+02:00", str);
+ assertEquals("2014-10-04T23:03:05.244+02:00", str);
+ });
}
@Test
public void testParseDateTime_withDST() {
- applyDST();
-
- Date date = DateUtils.parseDateTime("2014-10-05T00:03:05.244+03");
- String str = DateUtils.formatDateTime(date, DateUtils.FORMAT_ISO8601);
+ withTimeZone(buildDstTimeZone(), () -> {
+ Date date = DateUtils.parseDateTime("2014-10-05T00:03:05.244+03");
+ String str = DateUtils.formatDateTime(date, DateUtils.FORMAT_ISO8601);
- assertEquals("2014-10-05T00:03:05.244+03:00", str);
+ assertEquals("2014-10-05T00:03:05.244+03:00", str);
+ });
}
@Test
public void testParseTime() {
- TimeZone.setDefault(TimeZone.getTimeZone("GMT+02"));
+ withTimeZone(TimeZone.getTimeZone("GMT+02"), () -> {
+ String time = "12:03:05.011+03";
- String time = "12:03:05.011+03";
+ Date date = DateUtils.parseTime(time);
- Date date = DateUtils.parseTime(time);
+ String formatted = DateUtils.formatTime(date, DateUtils.FORMAT_ISO8601);
- String formatted = DateUtils.formatTime(date, DateUtils.FORMAT_ISO8601);
-
- assertEquals("11:03:05.011+02:00", formatted);
+ assertEquals("11:03:05.011+02:00", formatted);
+ });
}
@Test
@@ -77,27 +60,25 @@ public void testParseTime() {
// - We're effectively binding all times to the EPOCH date
// (1970-01-01, UTC), which has no DST
public void testParseTime_withDST() {
- applyDST();
-
- String time = "12:03:05.011+03";
+ withTimeZone(buildDstTimeZone(), () -> {
+ String time = "12:03:05.011+03";
- Date date = DateUtils.parseTime(time);
+ Date date = DateUtils.parseTime(time);
- String formatted = DateUtils.formatTime(date, DateUtils.FORMAT_ISO8601);
+ String formatted = DateUtils.formatTime(date, DateUtils.FORMAT_ISO8601);
- assertEquals("12:03:05.011+03", formatted);
+ assertEquals("12:03:05.011+03", formatted);
+ });
}
- private void applyDST() {
- // this is a timezone that operates DST every day of the year!
- SimpleTimeZone dstTimezone = new SimpleTimeZone(
- 2 * 60 * 60 * 1000,
- "Europe/Athens",
- Calendar.JANUARY, 1, 0,
- 0, SimpleTimeZone.UTC_TIME,
- Calendar.DECEMBER, 31, 0,
- 24 * 60 * 60 * 1000, SimpleTimeZone.UTC_TIME,
- 60 * 60 * 1000);
- TimeZone.setDefault(dstTimezone);
+ private SimpleTimeZone buildDstTimeZone() {
+ return new SimpleTimeZone(
+ 2 * 60 * 60 * 1000,
+ "Europe/Athens",
+ Calendar.JANUARY, 1, 0,
+ 0, SimpleTimeZone.UTC_TIME,
+ Calendar.DECEMBER, 31, 0,
+ 24 * 60 * 60 * 1000, SimpleTimeZone.UTC_TIME,
+ 60 * 60 * 1000);
}
}
diff --git a/src/test/java/org/javarosa/core/model/utils/test/DateUtilsTests.java b/src/test/java/org/javarosa/core/model/utils/test/DateUtilsTests.java
deleted file mode 100644
index 46a17809d..000000000
--- a/src/test/java/org/javarosa/core/model/utils/test/DateUtilsTests.java
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * Copyright (C) 2009 JavaRosa
- *
- * 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.
- */
-
-package org.javarosa.core.model.utils.test;
-
-import static org.junit.Assert.assertEquals;
-
-import java.text.DateFormat;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.Locale;
-import java.util.SimpleTimeZone;
-import java.util.TimeZone;
-import org.javarosa.core.model.utils.DateUtils;
-import org.javarosa.core.model.utils.DateUtils.DateFields;
-import org.joda.time.LocalDateTime;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-
-public class DateUtilsTests {
-
- private Locale backupLocale;
- private TimeZone backupZone;
- private Date testDate;
- private LocalDateTime testLocalDateTime;
-
- @Before
- public void setUp() {
- backupLocale = Locale.getDefault();
- backupZone = TimeZone.getDefault();
- testLocalDateTime = new LocalDateTime(2018, 1, 1, 10, 20, 30, 400);
- testDate = testLocalDateTime.toDate();
- }
-
- @After
- public void tearDown() {
- TimeZone.setDefault(backupZone);
- Locale.setDefault(backupLocale);
- }
-
- /**
- * This test ensures that the Strings returned
- * by the getXMLStringValue function are in
- * the proper XML compliant format.
- */
- @Test
- public void testGetXMLStringValueFormat() {
- String currentDate = DateUtils.getXMLStringValue(testDate);
- assertEquals("The date string was not of the proper length", currentDate.length(), "YYYY-MM-DD".length());
- assertEquals("The date string does not have proper year formatting", currentDate.indexOf("-"), "YYYY-".indexOf("-"));
- assertEquals(testLocalDateTime.getYear(), Integer.parseInt(currentDate.substring(0, 4)));
- assertEquals(testLocalDateTime.getMonthOfYear(), Integer.parseInt(currentDate.substring(5, 7)));
- assertEquals(testLocalDateTime.getDayOfMonth(), Integer.parseInt(currentDate.substring(8, 10)));
- }
-
- @Test
- public void testDateTimeParses() {
- TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
-
- testDateTime("2016-04-13T16:26:00.000-07", 1460589960000L);
- testDateTime("2015-12-16T16:09:00.000-08", 1450310940000L); // wraps day!!!
- testDateTime("2015-12-16T07:09:00.000+08", 1450220940000L); // wraps day!!!
-
- testDateTime("2015-11-30T16:09:00.000-08", 1448928540000L); // wraps month!!!
- testDateTime("2015-11-01T07:09:00.000+08", 1446332940000L); // wraps month!!!
-
- testDateTime("2015-12-31T16:09:00.000-08", 1451606940000L); // wraps year!!!
- testDateTime("2015-01-01T07:09:00.000+08", 1420067340000L); // wraps year!!!
-
- testDateTime("2016-01-26T10:39:00.000-08", 1453833540000L);
-
- TimeZone.setDefault(TimeZone.getTimeZone("PST"));
-
- testDateTime("2016-04-13T16:26:00.000-07", 1460589960000L);
- testDateTime("2015-12-16T16:09:00.000-08", 1450310940000L); // wraps day!!!
- testDateTime("2015-12-16T07:09:00.000+08", 1450220940000L); // wraps day!!!
-
- testDateTime("2015-11-30T16:09:00.000-08", 1448928540000L); // wraps month!!!
- testDateTime("2015-11-01T07:09:00.000+08", 1446332940000L); // wraps month!!!
-
- testDateTime("2015-12-31T16:09:00.000-08", 1451606940000L); // wraps year!!!
- testDateTime("2015-01-01T07:09:00.000+08", 1420067340000L); // wraps year!!!
-
- testDateTime("2016-01-26T10:39:00.000-08", 1453833540000L);
-
- TimeZone.setDefault(TimeZone.getTimeZone("PDT"));
-
- testDateTime("2016-04-13T16:26:00.000-07", 1460589960000L);
- testDateTime("2015-12-16T16:09:00.000-08", 1450310940000L); // wraps day!!!
- testDateTime("2015-12-16T07:09:00.000+08", 1450220940000L); // wraps day!!!
-
- testDateTime("2015-11-30T16:09:00.000-08", 1448928540000L); // wraps month!!!
- testDateTime("2015-11-01T07:09:00.000+08", 1446332940000L); // wraps month!!!
-
- testDateTime("2015-12-31T16:09:00.000-08", 1451606940000L); // wraps year!!!
- testDateTime("2015-01-01T07:09:00.000+08", 1420067340000L); // wraps year!!!
-
- testDateTime("2016-01-26T10:39:00.000-08", 1453833540000L);
- }
-
- private void testDateTime(String in, long test) {
- Date d = DateUtils.parseDateTime(in);
-
- long value = d.getTime();
-
- assertEquals("Fail: " + in + "(" + TimeZone.getDefault().getDisplayName() + ")", test, value);
- }
-
- @Test
- public void testTimeParses() {
- //This is all kind of tricky. We need to assume J2ME level compliance, so
- //dates won't every be assumed to have an intrinsic timezone, they'll be
- //assumed to be in the phone's default timezone
-
- TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
-
- Calendar startOfDay = Calendar.getInstance();
- startOfDay.set(Calendar.HOUR_OF_DAY, 0);
- startOfDay.set(Calendar.MINUTE, 0);
- startOfDay.set(Calendar.SECOND, 0);
- startOfDay.set(Calendar.MILLISECOND, 0);
-
- long startOfDayDate = startOfDay.getTime().getTime();
-
- testTime("10:00", startOfDayDate + 1000 * 60 * 60 * 10 - getOffset());
- testTime("10:00Z", startOfDayDate + 1000 * 60 * 60 * 10);
-
- testTime("10:00+02", startOfDayDate + 1000 * 60 * 60 * 8);
- testTime("10:00-02", startOfDayDate + 1000 * 60 * 60 * 12);
-
- testTime("10:00+02:30", startOfDayDate + 1000 * 60 * (60 * 10 - 150));
- testTime("10:00-02:30", startOfDayDate + 1000 * 60 * (60 * 10 + 150));
-
- TimeZone offsetTwoHours = TimeZone.getTimeZone("GMT+02");
-
- TimeZone.setDefault(offsetTwoHours);
-
- testTime("10:00", startOfDayDate + 1000 * 60 * 60 * 10 - getOffset());
- testTime("10:00Z", startOfDayDate + 1000 * 60 * 60 * 10);
-
- testTime("10:00+02", startOfDayDate + 1000 * 60 * 60 * 8);
- testTime("10:00-02", startOfDayDate + 1000 * 60 * 60 * 12);
-
- testTime("10:00+02:30", startOfDayDate + 1000 * 60 * (60 * 10 - 150));
- testTime("10:00-02:30", startOfDayDate + 1000 * 60 * (60 * 10 + 150));
-
- TimeZone offsetMinusTwoHours = TimeZone.getTimeZone("GMT-02");
-
- TimeZone.setDefault(offsetMinusTwoHours);
-
- testTime("14:00", startOfDayDate + 1000 * 60 * 60 * 14 - getOffset());
- testTime("14:00Z", startOfDayDate + 1000 * 60 * 60 * 14);
-
- testTime("14:00+02", startOfDayDate + 1000 * 60 * 60 * 12);
- testTime("14:00-02", startOfDayDate + 1000 * 60 * 60 * 16);
-
- testTime("14:00+02:30", startOfDayDate + 1000 * 60 * (60 * 14 - 150));
- testTime("14:00-02:30", startOfDayDate + 1000 * 60 * (60 * 14 + 150));
-
-
- TimeZone offsetPlusHalf = TimeZone.getTimeZone("GMT+0230");
-
- TimeZone.setDefault(offsetPlusHalf);
-
- testTime("14:00", startOfDayDate + 1000 * 60 * 60 * 14 - getOffset());
- testTime("14:00Z", startOfDayDate + 1000 * 60 * 60 * 14);
-
- testTime("14:00+02", startOfDayDate + 1000 * 60 * 60 * 12);
- testTime("14:00-02", startOfDayDate + 1000 * 60 * 60 * 16);
-
- testTime("14:00+02:30", startOfDayDate + 1000 * 60 * (60 * 14 - 150));
- testTime("14:00-02:30", startOfDayDate + 1000 * 60 * (60 * 14 + 150));
-
- testTime("14:00+04:00", startOfDayDate + 1000 * 60 * 60 * 10);
- }
-
- private void testTime(String in, long test) {
- Date d = DateUtils.parseTime(in);
-
- long value = d.getTime();
-
- assertEquals("Fail: " + in + "(" + TimeZone.getDefault().getDisplayName() + ")", test, value);
- }
-
- private long getOffset() {
- DateFields df = new DateFields();
- Date d = DateUtils.getDate(df);
-
- return -d.getTime();
- }
-
- @Test
- public void testParity() {
-
- testCycle(new Date(1300139579000L));
- testCycle(new Date(0));
-
- TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
-
- testCycle(new Date(1300139579000L));
- testCycle(new Date(0));
-
- TimeZone offsetTwoHours = TimeZone.getTimeZone("GMT+02");
-
- TimeZone.setDefault(offsetTwoHours);
-
- testCycle(new Date(1300139579000L));
- testCycle(new Date(0));
-
-
- TimeZone offTwoHalf = TimeZone.getTimeZone("GMT+0230");
-
- TimeZone.setDefault(offTwoHalf);
-
- testCycle(new Date(1300139579000L));
- testCycle(new Date(0));
-
- TimeZone offMinTwoHalf = TimeZone.getTimeZone("GMT-0230");
-
- TimeZone.setDefault(offMinTwoHalf);
-
- testCycle(new Date(1300139579000L));
- testCycle(new Date(0));
-
-
- }
-
- @Test
- @Ignore
- // This test doesn't make sense:
- // - A time has no offset nor zone. It can only have one
- // when bound to a date, which is not the case
- // - We're effectively binding all times to the EPOCH date
- // (1970-01-01, UTC), which has no DST
- public void testParseTime_with_DST() {// testFormatting
- Locale.setDefault(Locale.US);
-
- // this is a timezone that operates DST every day of the year!
- SimpleTimeZone dstTimezone = new SimpleTimeZone(
- 2 * 60 * 60 * 1000,
- "Europe/Athens",
- Calendar.JANUARY, 1, 0,
- 0, SimpleTimeZone.UTC_TIME,
- Calendar.DECEMBER, 31, 0,
- 24 * 60 * 60 * 1000, SimpleTimeZone.UTC_TIME,
- 60 * 60 * 1000);
- TimeZone.setDefault(dstTimezone);
-
- String time = "12:03:05.000Z";
- testTime(time, 43385000L);
-
- Date date = DateUtils.parseTime(time);
-
- DateFormat formatter = DateFormat.getTimeInstance();
- String formatted = formatter.format(date);
-
- // It should shift 3 hours, 2 for the zone and 1 for DST.
- assertEquals("3:03:05 PM", formatted);
- }
-
- private void testCycle(Date in) {
- String formatted = DateUtils.formatDateTime(in, DateUtils.FORMAT_ISO8601);
- Date out = DateUtils.parseDateTime(formatted);
- assertEquals("Fail:", in.getTime(), out.getTime());
- }
-
- @Test
- public void testFormatting() {
- class LangJanSun {
- private LangJanSun(String language, String january, String sunday) {
- this.language = language;
- this.january = january;
- this.sunday = sunday;
- }
-
- private String language;
- private String january;
- private String sunday;
- }
-
- LangJanSun langJanSuns[] = new LangJanSun[]{
- new LangJanSun("en", "Jan", "Sun"),
- new LangJanSun("es", "ene", "dom"),
- new LangJanSun("fr", "janv.", "dim.")
- };
-
- for (LangJanSun ljs : langJanSuns) {
- Locale.setDefault(Locale.forLanguageTag(ljs.language));
-
- String month = DateUtils.format(DateFields.of(2018, 1, 1, 10, 20, 30, 400), "%b");
- assertEquals(ljs.january, month);
-
- // 2018-04-01 was sunday
- String day = DateUtils.format(DateFields.of(2018, 4, 1, 10, 20, 30, 400), "%a");
- assertEquals(ljs.sunday, day);
- }
- }
-}
diff --git a/src/test/java/org/javarosa/test/utils/SystemHelper.java b/src/test/java/org/javarosa/test/utils/SystemHelper.java
new file mode 100644
index 000000000..c10588925
--- /dev/null
+++ b/src/test/java/org/javarosa/test/utils/SystemHelper.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2020 Nafundi
+ *
+ * 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.
+ */
+
+package org.javarosa.test.utils;
+
+import java.util.Locale;
+import java.util.TimeZone;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+
+public class SystemHelper {
+ public static void withTimeZone(TimeZone timeZone, Runnable block) {
+ withTimeZone(timeZone, __ -> block.run());
+ }
+
+ public static void withTimeZone(TimeZone timeZone, Consumer block) {
+ TimeZone backupZone = TimeZone.getDefault();
+ TimeZone.setDefault(timeZone);
+ block.accept(timeZone);
+ TimeZone.setDefault(backupZone);
+ }
+
+ public static void withLocale(Locale locale, Runnable block) {
+ withLocale(locale, __ -> block.run());
+ }
+
+ public static void withLocale(Locale locale, Consumer block) {
+ Locale backupLocale = Locale.getDefault();
+ Locale.setDefault(locale);
+ block.accept(locale);
+ Locale.setDefault(backupLocale);
+ }
+
+ public static void withLocaleAndTimeZone(Locale locale, TimeZone timeZone, Runnable block) {
+ withLocaleAndTimeZone(locale, timeZone, (__, ___) -> block.run());
+ }
+
+ public static void withLocaleAndTimeZone(Locale locale, TimeZone timeZone, BiConsumer block) {
+ withLocale(locale, l -> withTimeZone(timeZone, () -> block.accept(l, timeZone)));
+ }
+}
diff --git a/src/test/java/org/javarosa/xpath/expr/ToDateTest.java b/src/test/java/org/javarosa/xpath/expr/ToDateTest.java
index 47d9f3a9d..bbc79827a 100644
--- a/src/test/java/org/javarosa/xpath/expr/ToDateTest.java
+++ b/src/test/java/org/javarosa/xpath/expr/ToDateTest.java
@@ -2,25 +2,23 @@
import static java.lang.Double.NEGATIVE_INFINITY;
import static java.lang.Double.POSITIVE_INFINITY;
+import static org.javarosa.test.utils.SystemHelper.withTimeZone;
import static org.javarosa.xpath.expr.XPathFuncExpr.toDate;
import static org.junit.Assert.assertEquals;
+import java.time.ZoneId;
import java.util.Date;
import java.util.TimeZone;
-import java.util.function.Consumer;
import org.javarosa.xpath.XPathTypeMismatchException;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalDateTime;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
import org.junit.Test;
+// TODO Migrate to java.time for conformity
public class ToDateTest {
private static final DateTime EPOCH = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeZone.UTC);
-
- public static final TimeZone TIME_ZONE = TimeZone.getTimeZone(DateTimeZone.UTC.getID());
- private static TimeZone backupTimeZone;
+ public static final TimeZone PST = TimeZone.getTimeZone(ZoneId.of("America/Los_Angeles"));
private static Date date(int year, int month, int day) {
return new LocalDateTime(year, month, day, 0, 0, 0, 0).toDate();
@@ -30,18 +28,6 @@ private static Date date(int year, int month, int day, int hour, int minute, int
return new LocalDateTime(year, month, day, hour, minute, second, milli).toDate();
}
- @BeforeClass
- public static void forceUTCOffset() {
- // All the tests run on the UTC offset by default.
- backupTimeZone = TimeZone.getDefault();
- TimeZone.setDefault(TIME_ZONE);
- }
-
- @AfterClass
- public static void restoreTimeZone() {
- TimeZone.setDefault(backupTimeZone);
- }
-
@Test
public void convertsISO8601DatesWithoutPreservingTime() {
assertEquals(
@@ -68,17 +54,15 @@ public void convertsISO8601DatesWithOffsetPreservingTime() {
@Test
public void convertsTimestampsWithoutPreservingTime() {
- assertEquals(
+ withTimeZone(TimeZone.getTimeZone("Z"), () -> assertEquals(
EPOCH.withZone(DateTimeZone.getDefault()).plusDays(365).toDate(),
toDate(365d, false)
- );
+ ));
}
@Test
public void convertsTimestampsWithoutPreservingTimeOnLocalTimeZone() {
- runOnTimeZone(
- DateTimeZone.forID("America/Los_Angeles"), // a.k.a. PST (joda doesn't like the short ids)
- zoneId -> {
+ withTimeZone(PST, tz -> {
DateTime utcEpoch = EPOCH.withZone(DateTimeZone.UTC); // 1970-01-01T00:00:00 UTC
DateTime properExpectedDate = utcEpoch.plusDays(365); // 1971-01-01T00:00:00 UTC
// Explanation for all this:
@@ -92,7 +76,7 @@ public void convertsTimestampsWithoutPreservingTimeOnLocalTimeZone() {
// the same local datetime in our target zone.
// 1971-01-01T00:00:00 PST (or 1971-01-01T06:00:00 UTC which is the EPOCH plus
// 365 days *and 6 hours*, but will make our code work)
- DateTime expectedDate = properExpectedDate.withZoneRetainFields(zoneId);
+ DateTime expectedDate = properExpectedDate.withZoneRetainFields(DateTimeZone.forTimeZone(tz));
assertEquals(
expectedDate.toDate(),
toDate(365d, false)
@@ -169,10 +153,4 @@ public void anyOtherTypeThrows() {
toDate(2L, false);
}
- private void runOnTimeZone(DateTimeZone zoneId, Consumer block) {
- TimeZone backup = TimeZone.getDefault();
- TimeZone.setDefault(TimeZone.getTimeZone(zoneId.getID()));
- block.accept(zoneId);
- TimeZone.setDefault(backup);
- }
-}
\ No newline at end of file
+}
diff --git a/src/test/java/org/javarosa/xpath/test/XPathEvalTest.java b/src/test/java/org/javarosa/xpath/test/XPathEvalTest.java
index 5bb6eda73..dd0b3e89c 100644
--- a/src/test/java/org/javarosa/xpath/test/XPathEvalTest.java
+++ b/src/test/java/org/javarosa/xpath/test/XPathEvalTest.java
@@ -24,6 +24,7 @@
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.is;
+import static org.javarosa.test.utils.SystemHelper.withLocaleAndTimeZone;
import static org.javarosa.xpath.test.IFunctionHandlerHelpers.HANDLER_ADD;
import static org.javarosa.xpath.test.IFunctionHandlerHelpers.HANDLER_CHECK_TYPES;
import static org.javarosa.xpath.test.IFunctionHandlerHelpers.HANDLER_CONCAT;
@@ -61,7 +62,6 @@
import org.javarosa.xpath.XPathUnsupportedException;
import org.javarosa.xpath.expr.XPathExpression;
import org.javarosa.xpath.parser.XPathSyntaxException;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -69,11 +69,10 @@
@RunWith(Parameterized.class)
public class XPathEvalTest {
+ public static final TimeZone GMT = TimeZone.getTimeZone("GMT");
@Parameterized.Parameter(value = 0)
public Locale locale;
- private Locale backupLocale;
- private TimeZone backupTimeZone;
private EvaluationContext ec;
@Parameterized.Parameters(name = "Locale {0}")
@@ -86,21 +85,9 @@ public static Iterable testParametersProvider() {
@Before
public void setUp() {
- backupLocale = Locale.getDefault();
- Locale.setDefault(locale);
- backupTimeZone = TimeZone.getDefault();
- TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
ec = new EvaluationContext(null);
}
- @After
- public void tearDown() {
- Locale.setDefault(backupLocale);
- backupLocale = null;
- TimeZone.setDefault(backupTimeZone);
- backupTimeZone = null;
- }
-
@Test
public void counting_functions() {
testEval("count(/data/path)", buildInstance(), null, 5.0);
@@ -299,27 +286,29 @@ should be tested (particularly DST changes), but it's just too hard and
dates cannot reliably be compared/used across time zones (an issue with the code)
any time-of-day or DST should be ignored when comparing/using a date (an issue with testing)
*/
- ec.addFunctionHandler(HANDLER_CONVERTIBLE);
- testEval("date('2000-01-01')", DateUtils.getDate(2000, 1, 1));
- testEval("date('1945-04-26')", DateUtils.getDate(1945, 4, 26));
- testEval("date('1996-02-29')", DateUtils.getDate(1996, 2, 29));
- testEval("date('1983-09-31')", new XPathTypeMismatchException());
- testEval("date('not a date')", new XPathTypeMismatchException());
- testEval("date(0)", DateUtils.getDate(1970, 1, 1));
- testEval("date(6.5)", DateUtils.getDate(1970, 1, 7));
- testEval("date(1)", DateUtils.getDate(1970, 1, 2));
- testEval("date(-1)", DateUtils.getDate(1969, 12, 31));
- testEval("date(14127)", DateUtils.getDate(2008, 9, 5));
- testEval("date(-10252)", DateUtils.getDate(1941, 12, 7));
- testEval("date(date('1989-11-09'))", DateUtils.getDate(1989, 11, 9));
- testEval("date(true())", new XPathTypeMismatchException());
- testEval("date(convertible())", null, ec, new XPathTypeMismatchException());
- testEval("format-date('2018-01-02T10:20:30.123', \"%Y-%m-%e %H:%M:%S\")", "2018-01-2 10:20:30");
- testEval("date-time('2000-01-01T10:20:30.000')", DateUtils.getDateTimeFromString("2000-01-01T10:20:30.000"));
- testEval("decimal-date-time('2000-01-01T10:20:30.000')", 10957.430902777778);
- testEval("decimal-time('2000-01-01T10:20:30.000+03:00')", .30590277777810115);
- testEval("decimal-date-time('-1000')", new XPathTypeMismatchException());
- testEval("decimal-date-time('-01-2019')", new XPathTypeMismatchException());
+ withLocaleAndTimeZone(locale, GMT, () -> {
+ ec.addFunctionHandler(HANDLER_CONVERTIBLE);
+ testEval("date('2000-01-01')", DateUtils.getDate(2000, 1, 1));
+ testEval("date('1945-04-26')", DateUtils.getDate(1945, 4, 26));
+ testEval("date('1996-02-29')", DateUtils.getDate(1996, 2, 29));
+ testEval("date('1983-09-31')", new XPathTypeMismatchException());
+ testEval("date('not a date')", new XPathTypeMismatchException());
+ testEval("date(0)", DateUtils.getDate(1970, 1, 1));
+ testEval("date(6.5)", DateUtils.getDate(1970, 1, 7));
+ testEval("date(1)", DateUtils.getDate(1970, 1, 2));
+ testEval("date(-1)", DateUtils.getDate(1969, 12, 31));
+ testEval("date(14127)", DateUtils.getDate(2008, 9, 5));
+ testEval("date(-10252)", DateUtils.getDate(1941, 12, 7));
+ testEval("date(date('1989-11-09'))", DateUtils.getDate(1989, 11, 9));
+ testEval("date(true())", new XPathTypeMismatchException());
+ testEval("date(convertible())", null, ec, new XPathTypeMismatchException());
+ testEval("format-date('2018-01-02T10:20:30.123', \"%Y-%m-%e %H:%M:%S\")", "2018-01-2 10:20:30");
+ testEval("date-time('2000-01-01T10:20:30.000')", DateUtils.getDateTimeFromString("2000-01-01T10:20:30.000"));
+ testEval("decimal-date-time('2000-01-01T10:20:30.000')", 10957.430902777778);
+ testEval("decimal-time('2000-01-01T10:20:30.000+03:00')", .30590277777810115);
+ testEval("decimal-date-time('-1000')", new XPathTypeMismatchException());
+ testEval("decimal-date-time('-01-2019')", new XPathTypeMismatchException());
+ });
}
@Test