Split out tests for a Java 15 bug.

These tests fail on Java 15 due to a bug which was only fixed for Java
16.
See https://bugs.openjdk.java.net/browse/JDK-8248434
See https://bugs.openjdk.java.net/browse/JDK-8248655
This commit is contained in:
Gary Gregory 2020-10-22 14:47:45 -04:00
parent bcdff98f02
commit 7995aad79f
5 changed files with 426 additions and 264 deletions

20
pom.xml
View File

@ -941,6 +941,26 @@
<jacoco.skip>true</jacoco.skip> <jacoco.skip>true</jacoco.skip>
</properties> </properties>
</profile> </profile>
<profile>
<id>java15</id>
<activation>
<!-- This is ONLY activated for Java 15 -->
<jdk>15</jdk>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<excludes>
<exclude>org/apache/commons/lang3/time/Java15BugFastDateParserTest.java</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile> <profile>
<id>benchmark</id> <id>benchmark</id>

View File

@ -0,0 +1,65 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang3.function;
import java.util.Objects;
import java.util.function.Function;
/**
* Represents a function that accepts three arguments and produces a result. This is the three-arity specialization of
* {@link Function}.
*
* <p>
* This is a <a href="package-summary.html">functional interface</a> whose functional method is
* {@link #apply(Object, Object, Object)}.
*
* @param <T> the type of the first argument to the function
* @param <U> the type of the second argument to the function
* @param <V> the type of the third argument to the function
* @param <R> the type of the result of the function
*
* @see Function
* @since 3.12.0
*/
@FunctionalInterface
public interface TriFunction<T, U, V, R> {
/**
* Applies this function to the given arguments.
*
* @param t the first function argument
* @param u the second function argument
* @param v the third function argument
* @return the function result
*/
R apply(T t, U u, V v);
/**
* Returns a composed function that first applies this function to its input, and then applies the {@code after}
* function to the result. If evaluation of either function throws an exception, it is relayed to the caller of the
* composed function.
*
* @param <W> the type of output of the {@code after} function, and of the composed function
* @param after the function to apply after this function is applied
* @return a composed function that first applies this function and then applies the {@code after} function
* @throws NullPointerException if after is null
*/
default <W> TriFunction<T, U, V, W> andThen(Function<? super R, ? extends W> after) {
Objects.requireNonNull(after);
return (T t, U u, V v) -> after.apply(apply(t, u, v));
}
}

View File

@ -1,33 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang3.time;
import java.util.Locale;
import java.util.TimeZone;
/**
* Unit tests for the parse methods of FastDateFormat
*
* @since 3.2
*/
public class FastDateFormat_ParserTest extends FastDateParserTest {
@Override
protected DateParser getInstance(final String format, final TimeZone timeZone, final Locale locale) {
return FastDateFormat.getInstance(format, timeZone, locale);
}
}

View File

@ -34,10 +34,15 @@
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.stream.Stream;
import org.apache.commons.lang3.LocaleUtils; import org.apache.commons.lang3.LocaleUtils;
import org.apache.commons.lang3.SerializationUtils; import org.apache.commons.lang3.SerializationUtils;
import org.apache.commons.lang3.function.TriFunction;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
/** /**
* Unit tests {@link org.apache.commons.lang3.time.FastDateParser}. * Unit tests {@link org.apache.commons.lang3.time.FastDateParser}.
@ -45,9 +50,9 @@
* @since 3.2 * @since 3.2
*/ */
public class FastDateParserTest { public class FastDateParserTest {
private enum Expected1806 { private enum Expected1806 {
India(INDIA, "+05", "+0530", "+05:30", true), India(INDIA, "+05", "+0530", "+05:30", true), Greenwich(GMT, "Z", "Z", "Z", false),
Greenwich(GMT, "Z", "Z", "Z", false),
NewYork(NEW_YORK, "-05", "-0500", "-05:00", false); NewYork(NEW_YORK, "-05", "-0500", "-05:00", false);
final TimeZone zone; final TimeZone zone;
@ -56,33 +61,48 @@ private enum Expected1806 {
final String two; final String two;
final String three; final String three;
final long offset; final long offset;
Expected1806(final TimeZone zone, final String one, final String two, final String three, final boolean hasHalfHourOffset) {
Expected1806(final TimeZone zone, final String one, final String two, final String three,
final boolean hasHalfHourOffset) {
this.zone = zone; this.zone = zone;
this.one = one; this.one = one;
this.two = two; this.two = two;
this.three = three; this.three = three;
this.offset = hasHalfHourOffset ?30*60*1000 :0; this.offset = hasHalfHourOffset ? 30 * 60 * 1000 : 0;
} }
} }
private static final String SHORT_FORMAT_NOERA = "y/M/d/h/a/m/s/E";
private static final String LONG_FORMAT_NOERA = "yyyy/MMMM/dddd/hhhh/mmmm/ss/aaaa/EEEE";
private static final String SHORT_FORMAT = "G/" + SHORT_FORMAT_NOERA;
private static final String LONG_FORMAT = "GGGG/" + LONG_FORMAT_NOERA; static final String DATE_PARSER_PARAMETERS = "dateParserParameters";
static final String SHORT_FORMAT_NOERA = "y/M/d/h/a/m/s/E";
static final String LONG_FORMAT_NOERA = "yyyy/MMMM/dddd/hhhh/mmmm/ss/aaaa/EEEE";
static final String SHORT_FORMAT = "G/" + SHORT_FORMAT_NOERA;
static final String LONG_FORMAT = "GGGG/" + LONG_FORMAT_NOERA;
private static final String yMdHmsSZ = "yyyy-MM-dd'T'HH:mm:ss.SSS Z"; private static final String yMdHmsSZ = "yyyy-MM-dd'T'HH:mm:ss.SSS Z";
private static final String DMY_DOT = "dd.MM.yyyy"; private static final String DMY_DOT = "dd.MM.yyyy";
private static final String YMD_SLASH = "yyyy/MM/dd"; private static final String YMD_SLASH = "yyyy/MM/dd";
private static final String MDY_DASH = "MM-DD-yyyy"; private static final String MDY_DASH = "MM-DD-yyyy";
private static final String MDY_SLASH = "MM/DD/yyyy"; private static final String MDY_SLASH = "MM/DD/yyyy";
private static final TimeZone REYKJAVIK = TimeZone.getTimeZone("Atlantic/Reykjavik"); private static final TimeZone REYKJAVIK = TimeZone.getTimeZone("Atlantic/Reykjavik");
private static final TimeZone NEW_YORK = TimeZone.getTimeZone("America/New_York"); private static final TimeZone NEW_YORK = TimeZone.getTimeZone("America/New_York");
private static final TimeZone GMT = TimeZone.getTimeZone("GMT"); static final TimeZone GMT = TimeZone.getTimeZone("GMT");
private static final TimeZone INDIA = TimeZone.getTimeZone("Asia/Calcutta"); private static final TimeZone INDIA = TimeZone.getTimeZone("Asia/Calcutta");
private static final Locale SWEDEN = new Locale("sv", "SE"); private static final Locale SWEDEN = new Locale("sv", "SE");
static Stream<Arguments> dateParserParameters() {
return Stream.of(
// @formatter:off
Arguments.of((TriFunction<String, TimeZone, Locale, DateParser>) (format, timeZone, locale)
-> new FastDateParser(format, timeZone, locale, null)),
Arguments.of((TriFunction<String, TimeZone, Locale, DateParser>) FastDateFormat::getInstance)
// @formatter:on
);
}
private static Calendar initializeCalendar(final TimeZone tz) { private static Calendar initializeCalendar(final TimeZone tz) {
final Calendar cal = Calendar.getInstance(tz); final Calendar cal = Calendar.getInstance(tz);
cal.set(Calendar.YEAR, 2001); cal.set(Calendar.YEAR, 2001);
@ -95,25 +115,30 @@ private static Calendar initializeCalendar(final TimeZone tz) {
return cal; return cal;
} }
private void checkParse(final Locale locale, final Calendar cal, final SimpleDateFormat sdf, final DateParser fdf) throws ParseException { private final TriFunction<String, TimeZone, Locale, DateParser> dateParserProvider = (format, timeZone,
final String formattedDate= sdf.format(cal.getTime()); locale) -> new FastDateParser(format, timeZone, locale, null);
static void checkParse(final Locale locale, final Calendar cal, final SimpleDateFormat sdf, final DateParser fdf) {
final String formattedDate = sdf.format(cal.getTime());
checkParse(locale, sdf, fdf, formattedDate); checkParse(locale, sdf, fdf, formattedDate);
checkParse(locale, sdf, fdf, formattedDate.toLowerCase(locale)); checkParse(locale, sdf, fdf, formattedDate.toLowerCase(locale));
checkParse(locale, sdf, fdf, formattedDate.toUpperCase(locale)); checkParse(locale, sdf, fdf, formattedDate.toUpperCase(locale));
} }
private void checkParse(final Locale locale, final SimpleDateFormat sdf, final DateParser fdf, final String formattedDate) throws ParseException { static void checkParse(final Locale locale, final SimpleDateFormat sdf, final DateParser fdf,
final String formattedDate) {
try { try {
final Date expectedTime = sdf.parse(formattedDate); final Date expectedTime = sdf.parse(formattedDate);
final Date actualTime = fdf.parse(formattedDate); final Date actualTime = fdf.parse(formattedDate);
assertEquals(expectedTime, actualTime, "locale : " + locale + " formattedDate : " + formattedDate + "\n"); assertEquals(expectedTime, actualTime, "locale : " + locale + " formattedDate : " + formattedDate + "\n");
} catch (Exception e) { } catch (final Exception e) {
fail("locale : " + locale + " formattedDate : " + formattedDate + " error : " + e + "\n", e); fail("locale : " + locale + " formattedDate : " + formattedDate + " error : " + e + "\n", e);
} }
} }
private DateParser getDateInstance(final int dateStyle, final Locale locale) { private DateParser getDateInstance(final int dateStyle, final Locale locale) {
return getInstance(FormatCache.getPatternForStyle(Integer.valueOf(dateStyle), null, locale), TimeZone.getDefault(), Locale.getDefault()); return getInstance(null, FormatCache.getPatternForStyle(Integer.valueOf(dateStyle), null, locale),
TimeZone.getDefault(), Locale.getDefault());
} }
private Calendar getEraStart(int year, final TimeZone zone, final Locale locale) { private Calendar getEraStart(int year, final TimeZone zone, final Locale locale) {
@ -124,91 +149,68 @@ private Calendar getEraStart(int year, final TimeZone zone, final Locale locale)
if (locale.equals(FastDateParser.JAPANESE_IMPERIAL)) { if (locale.equals(FastDateParser.JAPANESE_IMPERIAL)) {
if (year < 1868) { if (year < 1868) {
cal.set(Calendar.ERA, 0); cal.set(Calendar.ERA, 0);
cal.set(Calendar.YEAR, 1868-year); cal.set(Calendar.YEAR, 1868 - year);
} }
} else { } else {
if (year < 0) { if (year < 0) {
cal.set(Calendar.ERA, GregorianCalendar.BC); cal.set(Calendar.ERA, GregorianCalendar.BC);
year= -year; year = -year;
} }
cal.set(Calendar.YEAR, year/100 * 100); cal.set(Calendar.YEAR, year / 100 * 100);
} }
return cal; return cal;
} }
DateParser getInstance(final String format) { DateParser getInstance(final String format) {
return getInstance(format, TimeZone.getDefault(), Locale.getDefault()); return getInstance(null, format, TimeZone.getDefault(), Locale.getDefault());
} }
private DateParser getInstance(final String format, final Locale locale) { DateParser getInstance(final String format, final Locale locale) {
return getInstance(format, TimeZone.getDefault(), locale); return getInstance(null, format, TimeZone.getDefault(), locale);
} }
private DateParser getInstance(final String format, final TimeZone timeZone) { private DateParser getInstance(final String format, final TimeZone timeZone) {
return getInstance(format, timeZone, Locale.getDefault()); return getInstance(null, format, timeZone, Locale.getDefault());
} }
/** /**
* Override this method in derived tests to change the construction of instances * Override this method in derived tests to change the construction of instances
* *
* @param dpProvider TODO
* @param format the format string to use * @param format the format string to use
* @param timeZone the time zone to use * @param timeZone the time zone to use
* @param locale the locale to use * @param locale the locale to use
* *
* @return the DateParser instance to use for testing * @return the DateParser instance to use for testing
*/ */
protected DateParser getInstance(final String format, final TimeZone timeZone, final Locale locale) { protected DateParser getInstance(final TriFunction<String, TimeZone, Locale, DateParser> dpProvider,
return new FastDateParser(format, timeZone, locale, null); final String format, final TimeZone timeZone, final Locale locale) {
return (dpProvider == null ? this.dateParserProvider : dpProvider).apply(format, timeZone, locale);
} }
@Test @ParameterizedTest
public void java15BuggyLocaleTest() throws ParseException { @MethodSource(DATE_PARSER_PARAMETERS)
final String buggyLocaleName = "ff_LR_#Adlm"; public void test_Equality_Hash(final TriFunction<String, TimeZone, Locale, DateParser> dpProvider) {
Locale buggyLocale = null; final DateParser[] parsers = {getInstance(dpProvider, yMdHmsSZ, NEW_YORK, Locale.US),
for (final Locale locale : Locale.getAvailableLocales()) { getInstance(dpProvider, DMY_DOT, NEW_YORK, Locale.US),
if (buggyLocaleName.equals(locale.toString())) { getInstance(dpProvider, YMD_SLASH, NEW_YORK, Locale.US),
buggyLocale = locale; getInstance(dpProvider, MDY_DASH, NEW_YORK, Locale.US),
break; getInstance(dpProvider, MDY_SLASH, NEW_YORK, Locale.US),
} getInstance(dpProvider, MDY_SLASH, REYKJAVIK, Locale.US),
} getInstance(dpProvider, MDY_SLASH, REYKJAVIK, SWEDEN)};
if (buggyLocale == null) {
return;
}
testSingleLocale(buggyLocale);
}
@Test final Map<DateParser, Integer> map = new HashMap<>();
public void java15BuggyLocaleTestAll() throws ParseException { int i = 0;
for (final Locale locale : Locale.getAvailableLocales()) { for (final DateParser parser : parsers) {
testSingleLocale(locale);
}
}
@Test
public void test_Equality_Hash() {
final DateParser[] parsers= {
getInstance(yMdHmsSZ, NEW_YORK, Locale.US),
getInstance(DMY_DOT, NEW_YORK, Locale.US),
getInstance(YMD_SLASH, NEW_YORK, Locale.US),
getInstance(MDY_DASH, NEW_YORK, Locale.US),
getInstance(MDY_SLASH, NEW_YORK, Locale.US),
getInstance(MDY_SLASH, REYKJAVIK, Locale.US),
getInstance(MDY_SLASH, REYKJAVIK, SWEDEN)
};
final Map<DateParser, Integer> map= new HashMap<>();
int i= 0;
for (final DateParser parser:parsers) {
map.put(parser, Integer.valueOf(i++)); map.put(parser, Integer.valueOf(i++));
} }
i= 0; i = 0;
for (final DateParser parser:parsers) { for (final DateParser parser : parsers) {
assertEquals(i++, map.get(parser).intValue()); assertEquals(i++, map.get(parser).intValue());
} }
} }
@Test @Test
public void test1806() throws ParseException { public void test1806() throws ParseException {
final String formatStub = "yyyy-MM-dd'T'HH:mm:ss.SSS"; final String formatStub = "yyyy-MM-dd'T'HH:mm:ss.SSS";
@ -217,16 +219,17 @@ public void test1806() throws ParseException {
for (final Expected1806 trial : Expected1806.values()) { for (final Expected1806 trial : Expected1806.values()) {
final Calendar cal = initializeCalendar(trial.zone); final Calendar cal = initializeCalendar(trial.zone);
final String message = trial.zone.getDisplayName()+";"; final String message = trial.zone.getDisplayName() + ";";
DateParser parser = getInstance(formatStub+"X", trial.zone); DateParser parser = getInstance(formatStub + "X", trial.zone);
assertEquals(cal.getTime().getTime(), parser.parse(dateStub+trial.one).getTime()-trial.offset, message+trial.one); assertEquals(cal.getTime().getTime(), parser.parse(dateStub + trial.one).getTime() - trial.offset,
message + trial.one);
parser = getInstance(formatStub+"XX", trial.zone); parser = getInstance(formatStub + "XX", trial.zone);
assertEquals(cal.getTime(), parser.parse(dateStub+trial.two), message+trial.two); assertEquals(cal.getTime(), parser.parse(dateStub + trial.two), message + trial.two);
parser = getInstance(formatStub+"XXX", trial.zone); parser = getInstance(formatStub + "XXX", trial.zone);
assertEquals(cal.getTime(), parser.parse(dateStub+trial.three), message+trial.three); assertEquals(cal.getTime(), parser.parse(dateStub + trial.three), message + trial.three);
} }
} }
@ -235,15 +238,16 @@ public void test1806Argument() {
assertThrows(IllegalArgumentException.class, () -> getInstance("XXXX")); assertThrows(IllegalArgumentException.class, () -> getInstance("XXXX"));
} }
@Test @ParameterizedTest
public void testAmPm() throws ParseException { @MethodSource(DATE_PARSER_PARAMETERS)
final Calendar cal= Calendar.getInstance(NEW_YORK, Locale.US); public void testAmPm(final TriFunction<String, TimeZone, Locale, DateParser> dpProvider) throws ParseException {
final Calendar cal = Calendar.getInstance(NEW_YORK, Locale.US);
cal.clear(); cal.clear();
final DateParser h = getInstance("yyyy-MM-dd hh a mm:ss", NEW_YORK, Locale.US); final DateParser h = getInstance(dpProvider, "yyyy-MM-dd hh a mm:ss", NEW_YORK, Locale.US);
final DateParser K = getInstance("yyyy-MM-dd KK a mm:ss", NEW_YORK, Locale.US); final DateParser K = getInstance(dpProvider, "yyyy-MM-dd KK a mm:ss", NEW_YORK, Locale.US);
final DateParser k = getInstance("yyyy-MM-dd kk:mm:ss", NEW_YORK, Locale.US); final DateParser k = getInstance(dpProvider, "yyyy-MM-dd kk:mm:ss", NEW_YORK, Locale.US);
final DateParser H = getInstance("yyyy-MM-dd HH:mm:ss", NEW_YORK, Locale.US); final DateParser H = getInstance(dpProvider, "yyyy-MM-dd HH:mm:ss", NEW_YORK, Locale.US);
cal.set(2010, Calendar.AUGUST, 1, 0, 33, 20); cal.set(2010, Calendar.AUGUST, 1, 0, 33, 20);
assertEquals(cal.getTime(), h.parse("2010-08-01 12 AM 33:20")); assertEquals(cal.getTime(), h.parse("2010-08-01 12 AM 33:20"));
@ -285,20 +289,21 @@ public void testDayNumberOfWeek() throws ParseException {
assertEquals(Calendar.SUNDAY, calendar.get(Calendar.DAY_OF_WEEK)); assertEquals(Calendar.SUNDAY, calendar.get(Calendar.DAY_OF_WEEK));
} }
@Test @ParameterizedTest
public void testDayOf() throws ParseException { @MethodSource(DATE_PARSER_PARAMETERS)
final Calendar cal= Calendar.getInstance(NEW_YORK, Locale.US); public void testDayOf(final TriFunction<String, TimeZone, Locale, DateParser> dpProvider) throws ParseException {
final Calendar cal = Calendar.getInstance(NEW_YORK, Locale.US);
cal.clear(); cal.clear();
cal.set(2003, Calendar.FEBRUARY, 10); cal.set(2003, Calendar.FEBRUARY, 10);
final DateParser fdf = getInstance("W w F D y", NEW_YORK, Locale.US); final DateParser fdf = getInstance(dpProvider, "W w F D y", NEW_YORK, Locale.US);
assertEquals(cal.getTime(), fdf.parse("3 7 2 41 03")); assertEquals(cal.getTime(), fdf.parse("3 7 2 41 03"));
} }
@Test @Test
public void testEquals() { public void testEquals() {
final DateParser parser1= getInstance(YMD_SLASH); final DateParser parser1 = getInstance(YMD_SLASH);
final DateParser parser2= getInstance(YMD_SLASH); final DateParser parser2 = getInstance(YMD_SLASH);
assertEquals(parser1, parser2); assertEquals(parser1, parser2);
assertEquals(parser1.hashCode(), parser2.hashCode()); assertEquals(parser1.hashCode(), parser2.hashCode());
@ -306,10 +311,13 @@ public void testEquals() {
assertNotEquals(parser1, new Object()); assertNotEquals(parser1, new Object());
} }
/**
* @throws ParseException
*/
@Test @Test
public void testJpLocales() throws ParseException { public void testJpLocales() throws ParseException {
final Calendar cal= Calendar.getInstance(GMT); final Calendar cal = Calendar.getInstance(GMT);
cal.clear(); cal.clear();
cal.set(2003, Calendar.FEBRUARY, 10); cal.set(2003, Calendar.FEBRUARY, 10);
cal.set(Calendar.ERA, GregorianCalendar.BC); cal.set(Calendar.ERA, GregorianCalendar.BC);
@ -324,21 +332,24 @@ public void testJpLocales() throws ParseException {
checkParse(locale, cal, sdf, fdf); checkParse(locale, cal, sdf, fdf);
} }
@Test @ParameterizedTest
public void testLANG_831() throws Exception { @MethodSource(DATE_PARSER_PARAMETERS)
testSdfAndFdp("M E", "3 Tue", true); public void testLANG_831(final TriFunction<String, TimeZone, Locale, DateParser> dpProvider) throws Exception {
testSdfAndFdp(dpProvider, "M E", "3 Tue", true);
} }
@Test @ParameterizedTest
public void testLANG_832() throws Exception { @MethodSource(DATE_PARSER_PARAMETERS)
testSdfAndFdp("'d'd", "d3", false); // OK public void testLANG_832(final TriFunction<String, TimeZone, Locale, DateParser> dpProvider) throws Exception {
testSdfAndFdp("'d'd'", "d3", true); // should fail (unterminated quote) testSdfAndFdp(dpProvider, "'d'd", "d3", false); // OK
testSdfAndFdp(dpProvider, "'d'd'", "d3", true); // should fail (unterminated quote)
} }
@Test @ParameterizedTest
public void testLang1121() throws ParseException { @MethodSource(DATE_PARSER_PARAMETERS)
public void testLang1121(final TriFunction<String, TimeZone, Locale, DateParser> dpProvider) throws ParseException {
final TimeZone kst = TimeZone.getTimeZone("KST"); final TimeZone kst = TimeZone.getTimeZone("KST");
final DateParser fdp = getInstance("yyyyMMdd", kst, Locale.KOREA); final DateParser fdp = getInstance(dpProvider, "yyyyMMdd", kst, Locale.KOREA);
assertThrows(ParseException.class, () -> fdp.parse("2015")); assertThrows(ParseException.class, () -> fdp.parse("2015"));
@ -359,13 +370,14 @@ public void testLang1121() throws ParseException {
assertEquals(expected, actual); assertEquals(expected, actual);
} }
@Test @ParameterizedTest
public void testLang1380() throws ParseException { @MethodSource(DATE_PARSER_PARAMETERS)
public void testLang1380(final TriFunction<String, TimeZone, Locale, DateParser> dpProvider) throws ParseException {
final Calendar expected = Calendar.getInstance(GMT, Locale.FRANCE); final Calendar expected = Calendar.getInstance(GMT, Locale.FRANCE);
expected.clear(); expected.clear();
expected.set(2014, Calendar.APRIL, 14); expected.set(2014, Calendar.APRIL, 14);
final DateParser fdp = getInstance("dd MMM yyyy", GMT, Locale.FRANCE); final DateParser fdp = getInstance(dpProvider, "dd MMM yyyy", GMT, Locale.FRANCE);
assertEquals(expected.getTime(), fdp.parse("14 avril 2014")); assertEquals(expected.getTime(), fdp.parse("14 avril 2014"));
assertEquals(expected.getTime(), fdp.parse("14 avr. 2014")); assertEquals(expected.getTime(), fdp.parse("14 avr. 2014"));
assertEquals(expected.getTime(), fdp.parse("14 avr 2014")); assertEquals(expected.getTime(), fdp.parse("14 avr 2014"));
@ -394,13 +406,14 @@ public void testLang538() throws ParseException {
assertEquals(cal.getTime(), parser.parse("2009-10-16T16:42:16.000Z")); assertEquals(cal.getTime(), parser.parse("2009-10-16T16:42:16.000Z"));
} }
@Test @ParameterizedTest
public void testLang996() throws ParseException { @MethodSource(DATE_PARSER_PARAMETERS)
public void testLang996(final TriFunction<String, TimeZone, Locale, DateParser> dpProvider) throws ParseException {
final Calendar expected = Calendar.getInstance(NEW_YORK, Locale.US); final Calendar expected = Calendar.getInstance(NEW_YORK, Locale.US);
expected.clear(); expected.clear();
expected.set(2014, Calendar.MAY, 14); expected.set(2014, Calendar.MAY, 14);
final DateParser fdp = getInstance("ddMMMyyyy", NEW_YORK, Locale.US); final DateParser fdp = getInstance(dpProvider, "ddMMMyyyy", NEW_YORK, Locale.US);
assertEquals(expected.getTime(), fdp.parse("14may2014")); assertEquals(expected.getTime(), fdp.parse("14may2014"));
assertEquals(expected.getTime(), fdp.parse("14MAY2014")); assertEquals(expected.getTime(), fdp.parse("14MAY2014"));
assertEquals(expected.getTime(), fdp.parse("14May2014")); assertEquals(expected.getTime(), fdp.parse("14May2014"));
@ -408,74 +421,13 @@ public void testLang996() throws ParseException {
@Test @Test
public void testLocaleMatches() { public void testLocaleMatches() {
final DateParser parser= getInstance(yMdHmsSZ, SWEDEN); final DateParser parser = getInstance(yMdHmsSZ, SWEDEN);
assertEquals(SWEDEN, parser.getLocale()); assertEquals(SWEDEN, parser.getLocale());
} }
private void testLocales(final String format, final boolean eraBC) throws Exception {
final Calendar cal= Calendar.getInstance(GMT);
cal.clear();
cal.set(2003, Calendar.FEBRUARY, 10);
if (eraBC) {
cal.set(Calendar.ERA, GregorianCalendar.BC);
}
for (final Locale locale : Locale.getAvailableLocales() ) {
// ja_JP_JP cannot handle dates before 1868 properly
if (eraBC && locale.equals(FastDateParser.JAPANESE_IMPERIAL)) {
continue;
}
final SimpleDateFormat sdf = new SimpleDateFormat(format, locale);
final DateParser fdf = getInstance(format, locale);
// If parsing fails, a ParseException will be thrown and the test will fail
checkParse(locale, cal, sdf, fdf);
}
}
@Test
public void testLocales_Long_AD() throws Exception {
testLocales(LONG_FORMAT, false);
}
@Test
public void testLocales_Long_BC() throws Exception {
testLocales(LONG_FORMAT, true);
}
@Test
public void testLocales_LongNoEra_AD() throws Exception {
testLocales(LONG_FORMAT_NOERA, false);
}
@Test
public void testLocales_LongNoEra_BC() throws Exception {
testLocales(LONG_FORMAT_NOERA, true);
}
@Test
public void testLocales_Short_AD() throws Exception {
testLocales(SHORT_FORMAT, false);
}
@Test
public void testLocales_Short_BC() throws Exception {
testLocales(SHORT_FORMAT, true);
}
@Test
public void testLocales_ShortNoEra_AD() throws Exception {
testLocales(SHORT_FORMAT_NOERA, false);
}
@Test
public void testLocales_ShortNoEra_BC() throws Exception {
testLocales(SHORT_FORMAT_NOERA, true);
}
/** /**
* Tests that pre-1000AD years get padded with yyyy * Tests that pre-1000AD years get padded with yyyy
*
* @throws ParseException so we don't have to catch it * @throws ParseException so we don't have to catch it
*/ */
@Test @Test
@ -504,37 +456,42 @@ public void testMilleniumBug() throws ParseException {
assertEquals(cal.getTime(), parser.parse("01.01.1000")); assertEquals(cal.getTime(), parser.parse("01.01.1000"));
} }
@Test @ParameterizedTest
public void testParseLongShort() throws ParseException { @MethodSource(DATE_PARSER_PARAMETERS)
final Calendar cal= Calendar.getInstance(NEW_YORK, Locale.US); public void testParseLongShort(final TriFunction<String, TimeZone, Locale, DateParser> dpProvider)
throws ParseException {
final Calendar cal = Calendar.getInstance(NEW_YORK, Locale.US);
cal.clear(); cal.clear();
cal.set(2003, Calendar.FEBRUARY, 10, 15, 33, 20); cal.set(2003, Calendar.FEBRUARY, 10, 15, 33, 20);
cal.set(Calendar.MILLISECOND, 989); cal.set(Calendar.MILLISECOND, 989);
cal.setTimeZone(NEW_YORK); cal.setTimeZone(NEW_YORK);
DateParser fdf = getInstance("yyyy GGGG MMMM dddd aaaa EEEE HHHH mmmm ssss SSSS ZZZZ", NEW_YORK, Locale.US); DateParser fdf = getInstance(dpProvider, "yyyy GGGG MMMM dddd aaaa EEEE HHHH mmmm ssss SSSS ZZZZ", NEW_YORK,
Locale.US);
assertEquals(cal.getTime(), fdf.parse("2003 AD February 0010 PM Monday 0015 0033 0020 0989 GMT-05:00")); assertEquals(cal.getTime(), fdf.parse("2003 AD February 0010 PM Monday 0015 0033 0020 0989 GMT-05:00"));
cal.set(Calendar.ERA, GregorianCalendar.BC); cal.set(Calendar.ERA, GregorianCalendar.BC);
final Date parse = fdf.parse("2003 BC February 0010 PM Saturday 0015 0033 0020 0989 GMT-05:00"); final Date parse = fdf.parse("2003 BC February 0010 PM Saturday 0015 0033 0020 0989 GMT-05:00");
assertEquals(cal.getTime(), parse); assertEquals(cal.getTime(), parse);
fdf = getInstance("y G M d a E H m s S Z", NEW_YORK, Locale.US); fdf = getInstance(null, "y G M d a E H m s S Z", NEW_YORK, Locale.US);
assertEquals(cal.getTime(), fdf.parse("03 BC 2 10 PM Sat 15 33 20 989 -0500")); assertEquals(cal.getTime(), fdf.parse("03 BC 2 10 PM Sat 15 33 20 989 -0500"));
cal.set(Calendar.ERA, GregorianCalendar.AD); cal.set(Calendar.ERA, GregorianCalendar.AD);
assertEquals(cal.getTime(), fdf.parse("03 AD 2 10 PM Saturday 15 33 20 989 -0500")); assertEquals(cal.getTime(), fdf.parse("03 AD 2 10 PM Saturday 15 33 20 989 -0500"));
} }
@Test @ParameterizedTest
public void testParseNumerics() throws ParseException { @MethodSource(DATE_PARSER_PARAMETERS)
final Calendar cal= Calendar.getInstance(NEW_YORK, Locale.US); public void testParseNumerics(final TriFunction<String, TimeZone, Locale, DateParser> dpProvider)
throws ParseException {
final Calendar cal = Calendar.getInstance(NEW_YORK, Locale.US);
cal.clear(); cal.clear();
cal.set(2003, Calendar.FEBRUARY, 10, 15, 33, 20); cal.set(2003, Calendar.FEBRUARY, 10, 15, 33, 20);
cal.set(Calendar.MILLISECOND, 989); cal.set(Calendar.MILLISECOND, 989);
final DateParser fdf = getInstance("yyyyMMddHHmmssSSS", NEW_YORK, Locale.US); final DateParser fdf = getInstance(dpProvider, "yyyyMMddHHmmssSSS", NEW_YORK, Locale.US);
assertEquals(cal.getTime(), fdf.parse("20030210153320989")); assertEquals(cal.getTime(), fdf.parse("20030210153320989"));
} }
@ -552,18 +509,18 @@ public void testParseOffset() {
@Test @Test
// Check that all Locales can parse the formats we use // Check that all Locales can parse the formats we use
public void testParses() throws Exception { public void testParses() throws Exception {
for (final String format : new String[]{LONG_FORMAT, SHORT_FORMAT}) { for (final String format : new String[] {LONG_FORMAT, SHORT_FORMAT}) {
for (final Locale locale : Locale.getAvailableLocales()) { for (final Locale locale : Locale.getAvailableLocales()) {
for (final TimeZone tz : new TimeZone[]{NEW_YORK, REYKJAVIK, GMT}) { for (final TimeZone tz : new TimeZone[] {NEW_YORK, REYKJAVIK, GMT}) {
for (final int year : new int[]{2003, 1940, 1868, 1867, 1, -1, -1940}) { for (final int year : new int[] {2003, 1940, 1868, 1867, 1, -1, -1940}) {
final Calendar cal= getEraStart(year, tz, locale); final Calendar cal = getEraStart(year, tz, locale);
final Date centuryStart= cal.getTime(); final Date centuryStart = cal.getTime();
cal.set(Calendar.MONTH, 1); cal.set(Calendar.MONTH, 1);
cal.set(Calendar.DAY_OF_MONTH, 10); cal.set(Calendar.DAY_OF_MONTH, 10);
final Date in= cal.getTime(); final Date in = cal.getTime();
final FastDateParser fdp= new FastDateParser(format, tz, locale, centuryStart); final FastDateParser fdp = new FastDateParser(format, tz, locale, centuryStart);
validateSdfFormatFdpParseEquality(format, locale, tz, fdp, in, year, centuryStart); validateSdfFormatFdpParseEquality(format, locale, tz, fdp, in, year, centuryStart);
} }
} }
@ -571,13 +528,15 @@ public void testParses() throws Exception {
} }
} }
@Test @ParameterizedTest
public void testParseZone() throws ParseException { @MethodSource(DATE_PARSER_PARAMETERS)
final Calendar cal= Calendar.getInstance(NEW_YORK, Locale.US); public void testParseZone(final TriFunction<String, TimeZone, Locale, DateParser> dpProvider)
throws ParseException {
final Calendar cal = Calendar.getInstance(NEW_YORK, Locale.US);
cal.clear(); cal.clear();
cal.set(2003, Calendar.JULY, 10, 16, 33, 20); cal.set(2003, Calendar.JULY, 10, 16, 33, 20);
final DateParser fdf = getInstance(yMdHmsSZ, NEW_YORK, Locale.US); final DateParser fdf = getInstance(dpProvider, yMdHmsSZ, NEW_YORK, Locale.US);
assertEquals(cal.getTime(), fdf.parse("2003-07-10T15:33:20.000 -0500")); assertEquals(cal.getTime(), fdf.parse("2003-07-10T15:33:20.000 -0500"));
assertEquals(cal.getTime(), fdf.parse("2003-07-10T15:33:20.000 GMT-05:00")); assertEquals(cal.getTime(), fdf.parse("2003-07-10T15:33:20.000 GMT-05:00"));
@ -597,23 +556,24 @@ public void testParseZone() throws ParseException {
@Test @Test
public void testPatternMatches() { public void testPatternMatches() {
final DateParser parser= getInstance(yMdHmsSZ); final DateParser parser = getInstance(yMdHmsSZ);
assertEquals(yMdHmsSZ, parser.getPattern()); assertEquals(yMdHmsSZ, parser.getPattern());
} }
@Test @ParameterizedTest
public void testQuotes() throws ParseException { @MethodSource(DATE_PARSER_PARAMETERS)
final Calendar cal= Calendar.getInstance(NEW_YORK, Locale.US); public void testQuotes(final TriFunction<String, TimeZone, Locale, DateParser> dpProvider) throws ParseException {
final Calendar cal = Calendar.getInstance(NEW_YORK, Locale.US);
cal.clear(); cal.clear();
cal.set(2003, Calendar.FEBRUARY, 10, 15, 33, 20); cal.set(2003, Calendar.FEBRUARY, 10, 15, 33, 20);
cal.set(Calendar.MILLISECOND, 989); cal.set(Calendar.MILLISECOND, 989);
final DateParser fdf = getInstance("''yyyyMMdd'A''B'HHmmssSSS''", NEW_YORK, Locale.US); final DateParser fdf = getInstance(dpProvider, "''yyyyMMdd'A''B'HHmmssSSS''", NEW_YORK, Locale.US);
assertEquals(cal.getTime(), fdf.parse("'20030210A'B153320989'")); assertEquals(cal.getTime(), fdf.parse("'20030210A'B153320989'"));
} }
private void testSdfAndFdp(final String format, final String date, final boolean shouldFail) private void testSdfAndFdp(final TriFunction<String, TimeZone, Locale, DateParser> dbProvider, final String format,
throws Exception { final String date, final boolean shouldFail) throws Exception {
Date dfdp = null; Date dfdp = null;
Date dsdf = null; Date dsdf = null;
Throwable f = null; Throwable f = null;
@ -623,7 +583,7 @@ private void testSdfAndFdp(final String format, final String date, final boolean
final SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.US); final SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.US);
sdf.setTimeZone(NEW_YORK); sdf.setTimeZone(NEW_YORK);
dsdf = sdf.parse(date); dsdf = sdf.parse(date);
assertFalse(shouldFail, "Expected SDF failure, but got " + dsdf + " for ["+format+", "+date+"]"); assertFalse(shouldFail, "Expected SDF failure, but got " + dsdf + " for [" + format + ", " + date + "]");
} catch (final Exception e) { } catch (final Exception e) {
s = e; s = e;
if (!shouldFail) { if (!shouldFail) {
@ -632,9 +592,9 @@ private void testSdfAndFdp(final String format, final String date, final boolean
} }
try { try {
final DateParser fdp = getInstance(format, NEW_YORK, Locale.US); final DateParser fdp = getInstance(dbProvider, format, NEW_YORK, Locale.US);
dfdp = fdp.parse(date); dfdp = fdp.parse(date);
assertFalse(shouldFail, "Expected FDF failure, but got " + dfdp + " for ["+format+", "+date+"]"); assertFalse(shouldFail, "Expected FDF failure, but got " + dfdp + " for [" + format + ", " + date + "]");
} catch (final Exception e) { } catch (final Exception e) {
f = e; f = e;
if (!shouldFail) { if (!shouldFail) {
@ -648,6 +608,7 @@ private void testSdfAndFdp(final String format, final String date, final boolean
/** /**
* Test case for {@link FastDateParser#FastDateParser(String, TimeZone, Locale)}. * Test case for {@link FastDateParser#FastDateParser(String, TimeZone, Locale)}.
*
* @throws ParseException so we don't have to catch it * @throws ParseException so we don't have to catch it
*/ */
@Test @Test
@ -663,44 +624,35 @@ public void testShortDateStyleWithLocales() throws ParseException {
assertEquals(cal.getTime(), fdf.parse("2004-02-03")); assertEquals(cal.getTime(), fdf.parse("2004-02-03"));
} }
private void testSingleLocale(final Locale locale) throws ParseException { @ParameterizedTest
final Calendar cal = Calendar.getInstance(GMT); @MethodSource(DATE_PARSER_PARAMETERS)
cal.clear(); public void testSpecialCharacters(final TriFunction<String, TimeZone, Locale, DateParser> dpProvider)
cal.set(2003, Calendar.FEBRUARY, 10); throws Exception {
final SimpleDateFormat sdf = new SimpleDateFormat(LONG_FORMAT, locale); testSdfAndFdp(dpProvider, "q", "", true); // bad pattern character (at present)
final String formattedDate = sdf.format(cal.getTime()); testSdfAndFdp(dpProvider, "Q", "", true); // bad pattern character
sdf.parse(formattedDate); testSdfAndFdp(dpProvider, "$", "$", false); // OK
sdf.parse(formattedDate.toUpperCase(locale)); testSdfAndFdp(dpProvider, "?.d", "?.12", false); // OK
sdf.parse(formattedDate.toLowerCase(locale)); testSdfAndFdp(dpProvider, "''yyyyMMdd'A''B'HHmmssSSS''", "'20030210A'B153320989'", false); // OK
} testSdfAndFdp(dpProvider, "''''yyyyMMdd'A''B'HHmmssSSS''", "''20030210A'B153320989'", false); // OK
testSdfAndFdp(dpProvider, "'$\\Ed'", "$\\Ed", false); // OK
@Test
public void testSpecialCharacters() throws Exception {
testSdfAndFdp("q", "", true); // bad pattern character (at present)
testSdfAndFdp("Q", "", true); // bad pattern character
testSdfAndFdp("$", "$", false); // OK
testSdfAndFdp("?.d", "?.12", false); // OK
testSdfAndFdp("''yyyyMMdd'A''B'HHmmssSSS''", "'20030210A'B153320989'", false); // OK
testSdfAndFdp("''''yyyyMMdd'A''B'HHmmssSSS''", "''20030210A'B153320989'", false); // OK
testSdfAndFdp("'$\\Ed'", "$\\Ed", false); // OK
// quoted charaters are case sensitive // quoted charaters are case sensitive
testSdfAndFdp("'QED'", "QED", false); testSdfAndFdp(dpProvider, "'QED'", "QED", false);
testSdfAndFdp("'QED'", "qed", true); testSdfAndFdp(dpProvider, "'QED'", "qed", true);
// case sensitive after insensitive Month field // case sensitive after insensitive Month field
testSdfAndFdp("yyyy-MM-dd 'QED'", "2003-02-10 QED", false); testSdfAndFdp(dpProvider, "yyyy-MM-dd 'QED'", "2003-02-10 QED", false);
testSdfAndFdp("yyyy-MM-dd 'QED'", "2003-02-10 qed", true); testSdfAndFdp(dpProvider, "yyyy-MM-dd 'QED'", "2003-02-10 qed", true);
} }
@Test @Test
public void testTimeZoneMatches() { public void testTimeZoneMatches() {
final DateParser parser= getInstance(yMdHmsSZ, REYKJAVIK); final DateParser parser = getInstance(yMdHmsSZ, REYKJAVIK);
assertEquals(REYKJAVIK, parser.getTimeZone()); assertEquals(REYKJAVIK, parser.getTimeZone());
} }
@Test @Test
public void testToStringContainsName() { public void testToStringContainsName() {
final DateParser parser= getInstance(YMD_SLASH); final DateParser parser = getInstance(YMD_SLASH);
assertTrue(parser.toString().startsWith("FastDate")); assertTrue(parser.toString().startsWith("FastDate"));
} }
@ -710,32 +662,33 @@ public void testToStringContainsName() {
public void testTzParses() throws Exception { public void testTzParses() throws Exception {
// Check that all Locales can parse the time formats we use // Check that all Locales can parse the time formats we use
for (final Locale locale : Locale.getAvailableLocales()) { for (final Locale locale : Locale.getAvailableLocales()) {
final FastDateParser fdp= new FastDateParser("yyyy/MM/dd z", TimeZone.getDefault(), locale); final FastDateParser fdp = new FastDateParser("yyyy/MM/dd z", TimeZone.getDefault(), locale);
for (final TimeZone tz : new TimeZone[]{NEW_YORK, REYKJAVIK, GMT}) { for (final TimeZone tz : new TimeZone[] {NEW_YORK, REYKJAVIK, GMT}) {
final Calendar cal= Calendar.getInstance(tz, locale); final Calendar cal = Calendar.getInstance(tz, locale);
cal.clear(); cal.clear();
cal.set(Calendar.YEAR, 2000); cal.set(Calendar.YEAR, 2000);
cal.set(Calendar.MONTH, 1); cal.set(Calendar.MONTH, 1);
cal.set(Calendar.DAY_OF_MONTH, 10); cal.set(Calendar.DAY_OF_MONTH, 10);
final Date expected= cal.getTime(); final Date expected = cal.getTime();
final Date actual = fdp.parse("2000/02/10 "+tz.getDisplayName(locale)); final Date actual = fdp.parse("2000/02/10 " + tz.getDisplayName(locale));
assertEquals(expected, actual, "tz:"+tz.getID()+" locale:"+locale.getDisplayName()); assertEquals(expected, actual, "tz:" + tz.getID() + " locale:" + locale.getDisplayName());
} }
} }
} }
private void validateSdfFormatFdpParseEquality(final String format, final Locale locale, final TimeZone tz, final DateParser fdp, final Date in, final int year, final Date cs) throws ParseException { private void validateSdfFormatFdpParseEquality(final String format, final Locale locale, final TimeZone tz,
final DateParser fdp, final Date in, final int year, final Date cs) throws ParseException {
final SimpleDateFormat sdf = new SimpleDateFormat(format, locale); final SimpleDateFormat sdf = new SimpleDateFormat(format, locale);
sdf.setTimeZone(tz); sdf.setTimeZone(tz);
if (format.equals(SHORT_FORMAT)) { if (format.equals(SHORT_FORMAT)) {
sdf.set2DigitYearStart( cs ); sdf.set2DigitYearStart(cs);
} }
final String fmt = sdf.format(in); final String fmt = sdf.format(in);
try { try {
final Date out = fdp.parse(fmt); final Date out = fdp.parse(fmt);
assertEquals(in, out, locale.toString()+" "+in+" "+ format+ " "+tz.getID()); assertEquals(in, out, locale.toString() + " " + in + " " + format + " " + tz.getID());
} catch (final ParseException pe) { } catch (final ParseException pe) {
if (year >= 1868 || !locale.getCountry().equals("JP")) {// LANG-978 if (year >= 1868 || !locale.getCountry().equals("JP")) {// LANG-978
throw pe; throw pe;
@ -743,3 +696,4 @@ private void validateSdfFormatFdpParseEquality(final String format, final Locale
} }
} }
} }

View File

@ -0,0 +1,156 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang3.time;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.TimeZone;
import org.apache.commons.lang3.function.TriFunction;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
/**
* These tests fail on Java 15 due to a bug which was only fixed for Java 16.
* <ul>
* <li>https://bugs.openjdk.java.net/browse/JDK-8248434</li>
* <li>https://bugs.openjdk.java.net/browse/JDK-8248655</li>
* </ul>
*/
public class Java15BugFastDateParserTest {
private static final String DATE_PARSER_PARAMETERS = "org.apache.commons.lang3.time.FastDateParserTest#dateParserParameters()";
@Test
public void java15BuggyLocaleTest() throws ParseException {
final String buggyLocaleName = "ff_LR_#Adlm";
Locale buggyLocale = null;
for (final Locale locale : Locale.getAvailableLocales()) {
if (buggyLocaleName.equals(locale.toString())) {
buggyLocale = locale;
break;
}
}
if (buggyLocale == null) {
return;
}
testSingleLocale(buggyLocale);
}
@Test
public void java15BuggyLocaleTestAll() throws ParseException {
for (final Locale locale : Locale.getAvailableLocales()) {
testSingleLocale(locale);
}
}
private void testLocales(final TriFunction<String, TimeZone, Locale, DateParser> dbProvider, final String format,
final boolean eraBC) throws Exception {
final Calendar cal = Calendar.getInstance(FastDateParserTest.GMT);
cal.clear();
cal.set(2003, Calendar.FEBRUARY, 10);
if (eraBC) {
cal.set(Calendar.ERA, GregorianCalendar.BC);
}
for (final Locale locale : Locale.getAvailableLocales()) {
// ja_JP_JP cannot handle dates before 1868 properly
if (eraBC && locale.equals(FastDateParser.JAPANESE_IMPERIAL)) {
continue;
}
final SimpleDateFormat sdf = new SimpleDateFormat(format, locale);
final DateParser fdf = dbProvider.apply(format, TimeZone.getDefault(), locale);
// If parsing fails, a ParseException will be thrown and the test will fail
FastDateParserTest.checkParse(locale, cal, sdf, fdf);
}
}
@ParameterizedTest
@MethodSource(DATE_PARSER_PARAMETERS)
public void testLocales_Long_AD(final TriFunction<String, TimeZone, Locale, DateParser> dpProvider)
throws Exception {
testLocales(dpProvider, FastDateParserTest.LONG_FORMAT, false);
}
@ParameterizedTest
@MethodSource(DATE_PARSER_PARAMETERS)
public void testLocales_Long_BC(final TriFunction<String, TimeZone, Locale, DateParser> dpProvider)
throws Exception {
testLocales(dpProvider, FastDateParserTest.LONG_FORMAT, true);
}
@ParameterizedTest
@MethodSource(DATE_PARSER_PARAMETERS)
public void testLocales_LongNoEra_AD(final TriFunction<String, TimeZone, Locale, DateParser> dpProvider)
throws Exception {
testLocales(dpProvider, FastDateParserTest.LONG_FORMAT_NOERA, false);
}
@ParameterizedTest
@MethodSource(DATE_PARSER_PARAMETERS)
public void testLocales_LongNoEra_BC(final TriFunction<String, TimeZone, Locale, DateParser> dpProvider)
throws Exception {
testLocales(dpProvider, FastDateParserTest.LONG_FORMAT_NOERA, true);
}
@ParameterizedTest
@MethodSource(DATE_PARSER_PARAMETERS)
public void testLocales_Short_AD(final TriFunction<String, TimeZone, Locale, DateParser> dpProvider)
throws Exception {
testLocales(dpProvider, FastDateParserTest.SHORT_FORMAT, false);
}
@ParameterizedTest
@MethodSource(DATE_PARSER_PARAMETERS)
public void testLocales_Short_BC(final TriFunction<String, TimeZone, Locale, DateParser> dpProvider)
throws Exception {
testLocales(dpProvider, FastDateParserTest.SHORT_FORMAT, true);
}
@ParameterizedTest
@MethodSource(DATE_PARSER_PARAMETERS)
public void testLocales_ShortNoEra_AD(final TriFunction<String, TimeZone, Locale, DateParser> dpProvider)
throws Exception {
testLocales(dpProvider, FastDateParserTest.SHORT_FORMAT_NOERA, false);
}
@ParameterizedTest
@MethodSource(DATE_PARSER_PARAMETERS)
public void testLocales_ShortNoEra_BC(final TriFunction<String, TimeZone, Locale, DateParser> dpProvider)
throws Exception {
testLocales(dpProvider, FastDateParserTest.SHORT_FORMAT_NOERA, true);
}
private void testSingleLocale(final Locale locale) throws ParseException {
final Calendar cal = Calendar.getInstance(FastDateParserTest.GMT);
cal.clear();
cal.set(2003, Calendar.FEBRUARY, 10);
final SimpleDateFormat sdf = new SimpleDateFormat(FastDateParserTest.LONG_FORMAT, locale);
final String formattedDate = sdf.format(cal.getTime());
sdf.parse(formattedDate);
sdf.parse(formattedDate.toUpperCase(locale));
sdf.parse(formattedDate.toLowerCase(locale));
}
}