<commit_before>/*
 * 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.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;

import java.io.Serializable;
import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
import java.util.stream.Stream;

import org.apache.commons.lang3.LocaleUtils;
import org.apache.commons.lang3.SerializationUtils;
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.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

/**
 * Unit tests {@link org.apache.commons.lang3.time.FastDateParser}.
 *
 * @since 3.2
 */
public class FastDateParserTest {

    private enum Expected1806 {
        India(INDIA, "+05", "+0530", "+05:30", true), Greenwich(GMT, "Z", "Z", "Z", false),
        NewYork(NEW_YORK, "-05", "-0500", "-05:00", false);

        final TimeZone zone;

        final String one;
        final String two;
        final String three;
        final long offset;

        Expected1806(final TimeZone zone, final String one, final String two, final String three,
            final boolean hasHalfHourOffset) {
            this.zone = zone;
            this.one = one;
            this.two = two;
            this.three = three;
            this.offset = hasHalfHourOffset ? 30 * 60 * 1000 : 0;
        }
    }

    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 DMY_DOT = "dd.MM.yyyy";
    private static final String YMD_SLASH = "yyyy/MM/dd";
    private static final String MDY_DASH = "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 NEW_YORK = TimeZone.getTimeZone("America/New_York");
    static final TimeZone GMT = TimeZone.getTimeZone("GMT");
    private static final TimeZone INDIA = TimeZone.getTimeZone("Asia/Calcutta");

    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) {
        final Calendar cal = Calendar.getInstance(tz);
        cal.set(Calendar.YEAR, 2001);
        cal.set(Calendar.MONTH, 1); // not daylight savings
        cal.set(Calendar.DAY_OF_MONTH, 4);
        cal.set(Calendar.HOUR_OF_DAY, 12);
        cal.set(Calendar.MINUTE, 8);
        cal.set(Calendar.SECOND, 56);
        cal.set(Calendar.MILLISECOND, 235);
        return cal;
    }

    private final TriFunction<String, TimeZone, Locale, DateParser> dateParserProvider = (format, timeZone,
        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.toLowerCase(locale));
        checkParse(locale, sdf, fdf, formattedDate.toUpperCase(locale));
    }

    static void checkParse(final Locale locale, final SimpleDateFormat sdf, final DateParser fdf,
        final String formattedDate) {
        try {
            final Date expectedTime = sdf.parse(formattedDate);
            final Date actualTime = fdf.parse(formattedDate);
            assertEquals(expectedTime, actualTime, "locale : " + locale + " formattedDate : " + formattedDate + "\n");
        } catch (final Exception e) {
            fail("locale : " + locale + " formattedDate : " + formattedDate + " error : " + e + "\n", e);
        }
    }

    private DateParser getDateInstance(final int dateStyle, final Locale locale) {
        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) {
        final Calendar cal = Calendar.getInstance(zone, locale);
        cal.clear();

        // http://docs.oracle.com/javase/6/docs/technotes/guides/intl/calendar.doc.html
        if (locale.equals(FastDateParser.JAPANESE_IMPERIAL)) {
            if (year < 1868) {
                cal.set(Calendar.ERA, 0);
                cal.set(Calendar.YEAR, 1868 - year);
            }<commit_msg>Show Java version in assertion failure message.<commit_after>/*
 * 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.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;

import java.io.Serializable;
import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
import java.util.stream.Stream;

import org.apache.commons.lang3.LocaleUtils;
import org.apache.commons.lang3.SerializationUtils;
import org.apache.commons.lang3.SystemUtils;
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.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

/**
 * Unit tests {@link org.apache.commons.lang3.time.FastDateParser}.
 *
 * @since 3.2
 */
public class FastDateParserTest {

    private enum Expected1806 {
        India(INDIA, "+05", "+0530", "+05:30", true), Greenwich(GMT, "Z", "Z", "Z", false),
        NewYork(NEW_YORK, "-05", "-0500", "-05:00", false);

        final TimeZone zone;

        final String one;
        final String two;
        final String three;
        final long offset;

        Expected1806(final TimeZone zone, final String one, final String two, final String three,
            final boolean hasHalfHourOffset) {
            this.zone = zone;
            this.one = one;
            this.two = two;
            this.three = three;
            this.offset = hasHalfHourOffset ? 30 * 60 * 1000 : 0;
        }
    }

    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 DMY_DOT = "dd.MM.yyyy";
    private static final String YMD_SLASH = "yyyy/MM/dd";
    private static final String MDY_DASH = "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 NEW_YORK = TimeZone.getTimeZone("America/New_York");
    static final TimeZone GMT = TimeZone.getTimeZone("GMT");
    private static final TimeZone INDIA = TimeZone.getTimeZone("Asia/Calcutta");

    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) {
        final Calendar cal = Calendar.getInstance(tz);
        cal.set(Calendar.YEAR, 2001);
        cal.set(Calendar.MONTH, 1); // not daylight savings
        cal.set(Calendar.DAY_OF_MONTH, 4);
        cal.set(Calendar.HOUR_OF_DAY, 12);
        cal.set(Calendar.MINUTE, 8);
        cal.set(Calendar.SECOND, 56);
        cal.set(Calendar.MILLISECOND, 235);
        return cal;
    }

    private final TriFunction<String, TimeZone, Locale, DateParser> dateParserProvider = (format, timeZone,
        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.toLowerCase(locale));
        checkParse(locale, sdf, fdf, formattedDate.toUpperCase(locale));
    }

    static void checkParse(final Locale locale, final SimpleDateFormat sdf, final DateParser fdf,
        final String formattedDate) {
        try {
            final Date expectedTime = sdf.parse(formattedDate);
            final Date actualTime = fdf.parse(formattedDate);
            assertEquals(expectedTime, actualTime, "locale : " + locale + ", formattedDate : " + formattedDate
                + ", Java: " + SystemUtils.JAVA_RUNTIME_VERSION + "\n");
        } catch (final Exception e) {
            fail("locale : " + locale + " formattedDate : " + formattedDate + " error : " + e + "\n", e);
        }
    }

    private DateParser getDateInstance(final int dateStyle, final Locale locale) {
        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) {
        final Calendar cal = Calendar.getInstance(zone, locale);
        cal.clear();

        // http://docs.oracle.com/javase/6/docs/technotes/guides/intl/calendar.doc.html
        if (locale.equals(FastDateParser.JAPANESE_IMPERIAL)) {
            if (year < 1868) {
                cal.set(Calendar.ERA, 0);
                cal.set(Calendar.YEAR, 1868 - year);
            }
{'fraction_non_alphanumeric': 0.10552763819095477, 'fraction_numerical': 0.01104004872849094, 'mean_word_length': 3.2743247640741946, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5629388', 'n_tokens_mistral': 3990, 'n_tokens_neox': 3767, 'n_words': 1036}