| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS 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 static org.junit.jupiter.api.Assertions.assertEquals; |
| import static org.junit.jupiter.api.Assertions.assertFalse; |
| import static org.junit.jupiter.api.Assertions.assertNotEquals; |
| import static org.junit.jupiter.api.Assertions.assertTrue; |
| |
| import java.text.ParseException; |
| import java.text.ParsePosition; |
| import java.text.SimpleDateFormat; |
| import java.util.Date; |
| import java.util.Locale; |
| import java.util.TimeZone; |
| import java.util.stream.Stream; |
| |
| import org.apache.commons.lang3.AbstractLangTest; |
| import org.junit.jupiter.params.ParameterizedTest; |
| import org.junit.jupiter.params.provider.Arguments; |
| import org.junit.jupiter.params.provider.MethodSource; |
| |
| /** |
| * Compare FastDateParser with SimpleDateFormat |
| */ |
| public class FastDateParserSDFTest extends AbstractLangTest { |
| |
| private static final TimeZone timeZone = TimeZone.getDefault(); |
| |
| public static Stream<Arguments> data() { |
| // @formatter:off |
| return Stream.of( |
| // General Time zone tests |
| Arguments.of("z yyyy", "GMT 2010", Locale.UK, true), // no offset specified, but this is allowed as a TimeZone name |
| Arguments.of("z yyyy", "GMT-123 2010", Locale.UK, false), |
| Arguments.of("z yyyy", "GMT-1234 2010", Locale.UK, false), |
| Arguments.of("z yyyy", "GMT-12:34 2010", Locale.UK, true), |
| Arguments.of("z yyyy", "GMT-1:23 2010", Locale.UK, true), |
| // RFC 822 tests |
| Arguments.of("z yyyy", "-1234 2010", Locale.UK, true), |
| Arguments.of("z yyyy", "-12:34 2010", Locale.UK, false), |
| Arguments.of("z yyyy", "-123 2010", Locale.UK, false), |
| // year tests |
| Arguments.of( "MM/dd/yyyy", "01/11/12", Locale.UK, true), |
| Arguments.of( "MM/dd/yy", "01/11/12", Locale.UK, true), |
| |
| // LANG-1089 |
| Arguments.of( "HH", "00", Locale.UK, true), // Hour in day (0-23) |
| Arguments.of( "KK", "00", Locale.UK, true), // Hour in am/pm (0-11) |
| Arguments.of( "hh", "00", Locale.UK, true), // Hour in am/pm (1-12), i.e. midday/midnight is 12, not 0 |
| Arguments.of( "kk", "00", Locale.UK, true), // Hour in day (1-24), i.e. midnight is 24, not 0 |
| |
| Arguments.of( "HH", "01", Locale.UK, true), // Hour in day (0-23) |
| Arguments.of( "KK", "01", Locale.UK, true), // Hour in am/pm (0-11) |
| Arguments.of( "hh", "01", Locale.UK, true), // Hour in am/pm (1-12), i.e. midday/midnight is 12, not 0 |
| Arguments.of( "kk", "01", Locale.UK, true), // Hour in day (1-24), i.e. midnight is 24, not 0 |
| |
| Arguments.of( "HH", "11", Locale.UK, true), // Hour in day (0-23) |
| Arguments.of( "KK", "11", Locale.UK, true), // Hour in am/pm (0-11) |
| Arguments.of( "hh", "11", Locale.UK, true), // Hour in am/pm (1-12), i.e. midday/midnight is 12, not 0 |
| Arguments.of( "kk", "11", Locale.UK, true), // Hour in day (1-24), i.e. midnight is 24, not 0 |
| |
| Arguments.of( "HH", "12", Locale.UK, true), // Hour in day (0-23) |
| Arguments.of( "KK", "12", Locale.UK, true), // Hour in am/pm (0-11) |
| Arguments.of( "hh", "12", Locale.UK, true), // Hour in am/pm (1-12), i.e. midday/midnight is 12, not 0 |
| Arguments.of( "kk", "12", Locale.UK, true), // Hour in day (1-24), i.e. midnight is 24, not 0 |
| |
| Arguments.of( "HH", "13", Locale.UK, true), // Hour in day (0-23) |
| Arguments.of( "KK", "13", Locale.UK, true), // Hour in am/pm (0-11) |
| Arguments.of( "hh", "13", Locale.UK, true), // Hour in am/pm (1-12), i.e. midday/midnight is 12, not 0 |
| Arguments.of( "kk", "13", Locale.UK, true), // Hour in day (1-24), i.e. midnight is 24, not 0 |
| |
| Arguments.of( "HH", "23", Locale.UK, true), // Hour in day (0-23) |
| Arguments.of( "KK", "23", Locale.UK, true), // Hour in am/pm (0-11) |
| Arguments.of( "hh", "23", Locale.UK, true), // Hour in am/pm (1-12), i.e. midday/midnight is 12, not 0 |
| Arguments.of( "kk", "23", Locale.UK, true), // Hour in day (1-24), i.e. midnight is 24, not 0 |
| |
| Arguments.of( "HH", "24", Locale.UK, true), // Hour in day (0-23) |
| Arguments.of( "KK", "24", Locale.UK, true), // Hour in am/pm (0-11) |
| Arguments.of( "hh", "24", Locale.UK, true), // Hour in am/pm (1-12), i.e. midday/midnight is 12, not 0 |
| Arguments.of( "kk", "24", Locale.UK, true), // Hour in day (1-24), i.e. midnight is 24, not 0 |
| |
| Arguments.of( "HH", "25", Locale.UK, true), // Hour in day (0-23) |
| Arguments.of( "KK", "25", Locale.UK, true), // Hour in am/pm (0-11) |
| Arguments.of( "hh", "25", Locale.UK, true), // Hour in am/pm (1-12), i.e. midday/midnight is 12, not 0 |
| Arguments.of( "kk", "25", Locale.UK, true), // Hour in day (1-24), i.e. midnight is 24, not 0 |
| |
| Arguments.of( "HH", "48", Locale.UK, true), // Hour in day (0-23) |
| Arguments.of( "KK", "48", Locale.UK, true), // Hour in am/pm (0-11) |
| Arguments.of( "hh", "48", Locale.UK, true), // Hour in am/pm (1-12), i.e. midday/midnight is 12, not 0 |
| Arguments.of( "kk", "48", Locale.UK, true) // Hour in day (1-24), i.e. midnight is 24, not 0 |
| ); |
| // @formatter:on |
| } |
| |
| private void checkParse(final String formattedDate, final String format, final Locale locale, final boolean valid) { |
| final SimpleDateFormat sdf = new SimpleDateFormat(format, locale); |
| sdf.setTimeZone(timeZone); |
| final DateParser fdf = new FastDateParser(format, timeZone, locale); |
| Date expectedTime = null; |
| Class<?> sdfE = null; |
| try { |
| expectedTime = sdf.parse(formattedDate); |
| if (!valid) { |
| // Error in test data |
| throw new RuntimeException("Test data error: expected SDF parse to fail, but got " + expectedTime); |
| } |
| } catch (final ParseException e) { |
| if (valid) { |
| // Error in test data |
| throw new RuntimeException("Test data error: expected SDF parse to succeed, but got " + e); |
| } |
| sdfE = e.getClass(); |
| } |
| Date actualTime = null; |
| Class<?> fdfE = null; |
| try { |
| actualTime = fdf.parse(formattedDate); |
| // failure in test |
| assertTrue(valid, "Expected FDP parse to fail, but got " + actualTime); |
| } catch (final ParseException e) { |
| // failure in test |
| assertFalse(valid, "Expected FDP parse to succeed, but got " + e); |
| fdfE = e.getClass(); |
| } |
| if (valid) { |
| assertEquals(expectedTime, actualTime, locale + " " + formattedDate + "\n"); |
| } else { |
| assertEquals(sdfE, fdfE, locale + " " + formattedDate + " expected same Exception "); |
| } |
| } |
| |
| private void checkParsePosition(final String formattedDate, final String format, final Locale locale, final boolean valid) { |
| final SimpleDateFormat sdf = new SimpleDateFormat(format, locale); |
| sdf.setTimeZone(timeZone); |
| final DateParser fdf = new FastDateParser(format, timeZone, locale); |
| |
| final ParsePosition sdfP = new ParsePosition(0); |
| final Date expectedTime = sdf.parse(formattedDate, sdfP); |
| final int sdferrorIndex = sdfP.getErrorIndex(); |
| if (valid) { |
| assertEquals(-1, sdferrorIndex, "Expected SDF error index -1 "); |
| final int endIndex = sdfP.getIndex(); |
| final int length = formattedDate.length(); |
| if (endIndex != length) { |
| // Error in test data |
| throw new RuntimeException("Test data error: expected SDF parse to consume entire string; endindex " + endIndex + " != " + length); |
| } |
| } else { |
| final int errorIndex = sdfP.getErrorIndex(); |
| if (errorIndex == -1) { |
| throw new RuntimeException("Test data error: expected SDF parse to fail, but got " + expectedTime); |
| } |
| } |
| |
| final ParsePosition fdfP = new ParsePosition(0); |
| final Date actualTime = fdf.parse(formattedDate, fdfP); |
| final int fdferrorIndex = fdfP.getErrorIndex(); |
| if (valid) { |
| assertEquals(-1, fdferrorIndex, "Expected FDF error index -1 "); |
| final int endIndex = fdfP.getIndex(); |
| final int length = formattedDate.length(); |
| assertEquals(length, endIndex, "Expected FDF to parse full string " + fdfP); |
| assertEquals(expectedTime, actualTime, locale + " " + formattedDate + "\n"); |
| } else { |
| assertNotEquals(-1, fdferrorIndex, "Test data error: expected FDF parse to fail, but got " + actualTime); |
| assertTrue(sdferrorIndex - fdferrorIndex <= 4, "FDF error index (" + fdferrorIndex + ") should approximate SDF index (" + sdferrorIndex + ")"); |
| } |
| } |
| |
| @ParameterizedTest |
| @MethodSource("data") |
| public void testLowerCase(final String format, final String input, final Locale locale, final boolean valid) { |
| checkParse(input.toLowerCase(locale), format, locale, valid); |
| } |
| |
| @ParameterizedTest |
| @MethodSource("data") |
| public void testLowerCasePP(final String format, final String input, final Locale locale, final boolean valid) { |
| checkParsePosition(input.toLowerCase(locale), format, locale, valid); |
| } |
| |
| @ParameterizedTest |
| @MethodSource("data") |
| public void testOriginal(final String format, final String input, final Locale locale, final boolean valid) { |
| checkParse(input, format, locale, valid); |
| } |
| |
| @ParameterizedTest |
| @MethodSource("data") |
| public void testOriginalPP(final String format, final String input, final Locale locale, final boolean valid) { |
| checkParsePosition(input, format, locale, valid); |
| } |
| |
| @ParameterizedTest |
| @MethodSource("data") |
| public void testUpperCase(final String format, final String input, final Locale locale, final boolean valid) { |
| checkParse(input.toUpperCase(locale), format, locale, valid); |
| } |
| @ParameterizedTest |
| @MethodSource("data") |
| public void testUpperCasePP(final String format, final String input, final Locale locale, final boolean valid) { |
| checkParsePosition(input.toUpperCase(locale), format, locale, valid); |
| } |
| } |