From 693adf3987c192c9ec649bc88e3e41b52f23204d Mon Sep 17 00:00:00 2001 From: Jeff Genovy <29107334+jefgen@users.noreply.github.com> Date: Wed, 24 Apr 2019 14:02:06 -0700 Subject: [PATCH] ICU-20558 Fix regression in DateTimePatternGenerator This fixes a regression introduced by commit b12a927c9365bb38831afbf76fdd0999f8f33deb for issue ICU-13778. The above commit improved the error checking in the DateTimePatternGenerator class, adding checks for errors/failures where there previously was none at all. This was done in order to catch catastrophic errors like out-of-memory (OOM), and properly report them to the caller, rather than ignoring/hiding these errors. However, in doing so it exposed a case where the code was depending on ignoring errors in order to fall-back to the Gregorian calendar when the default ICU locale is set to root. This restores the previous behavior, by allowing the error of U_MISSING_RESOURCE_ERROR to fall-though and continue without reporting back an error to the caller. Note: This regression was technically introduced in ICU 63, and also effects ICU 64 as well. --- icu4c/source/i18n/dtptngen.cpp | 14 ++++++++----- icu4c/source/test/intltest/dtptngts.cpp | 28 +++++++++++++++++++++++++ icu4c/source/test/intltest/dtptngts.h | 1 + 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/icu4c/source/i18n/dtptngen.cpp b/icu4c/source/i18n/dtptngen.cpp index fcc5977c56d7..8128d679129c 100644 --- a/icu4c/source/i18n/dtptngen.cpp +++ b/icu4c/source/i18n/dtptngen.cpp @@ -787,6 +787,7 @@ void DateTimePatternGenerator::getCalendarTypeToUse(const Locale& locale, CharString& destination, UErrorCode& err) { destination.clear().append(DT_DateTimeGregorianTag, -1, err); // initial default if ( U_SUCCESS(err) ) { + UErrorCode localStatus = U_ZERO_ERROR; char localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY]; // obtain a locale that always has the calendar key value that should be used ures_getFunctionalEquivalent( @@ -798,8 +799,7 @@ DateTimePatternGenerator::getCalendarTypeToUse(const Locale& locale, CharString& locale.getName(), nullptr, FALSE, - &err); - if (U_FAILURE(err)) { return; } + &localStatus); localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY-1] = 0; // ensure null termination // now get the calendar key value from that locale char calendarType[ULOC_KEYWORDS_CAPACITY]; @@ -808,13 +808,17 @@ DateTimePatternGenerator::getCalendarTypeToUse(const Locale& locale, CharString& "calendar", calendarType, ULOC_KEYWORDS_CAPACITY, - &err); - if (U_FAILURE(err)) { return; } + &localStatus); + // If the input locale was invalid, don't fail with missing resource error, instead + // continue with default of Gregorian. + if (U_FAILURE(localStatus) && localStatus != U_MISSING_RESOURCE_ERROR) { + err = localStatus; + return; + } if (calendarTypeLen < ULOC_KEYWORDS_CAPACITY) { destination.clear().append(calendarType, -1, err); if (U_FAILURE(err)) { return; } } - err = U_ZERO_ERROR; } } diff --git a/icu4c/source/test/intltest/dtptngts.cpp b/icu4c/source/test/intltest/dtptngts.cpp index 1827f21d290f..800aba7bdbf2 100644 --- a/icu4c/source/test/intltest/dtptngts.cpp +++ b/icu4c/source/test/intltest/dtptngts.cpp @@ -41,6 +41,7 @@ void IntlTestDateTimePatternGeneratorAPI::runIndexedTest( int32_t index, UBool e TESTCASE(5, testSkeletonsWithDayPeriods); TESTCASE(6, testGetFieldDisplayNames); TESTCASE(7, testJjMapping); + TESTCASE(8, testFallbackWithDefaultRootLocale); default: name = ""; break; } } @@ -1341,4 +1342,31 @@ void IntlTestDateTimePatternGeneratorAPI::testJjMapping() { } } +void IntlTestDateTimePatternGeneratorAPI::testFallbackWithDefaultRootLocale() { + UErrorCode status = U_ZERO_ERROR; + char original[ULOC_FULLNAME_CAPACITY]; + + uprv_strcpy(original, uloc_getDefault()); + uloc_setDefault("root", &status); + if (U_FAILURE(status)) { + errln("ERROR: Failed to change the default locale to root! Default is: %s\n", uloc_getDefault()); + } + + DateTimePatternGenerator* dtpg = icu::DateTimePatternGenerator::createInstance("abcdedf", status); + + if (U_FAILURE(status)) { + errln("ERROR: expected createInstance with invalid locale to succeed. Status: %s", u_errorName(status)); + } + if (status != U_USING_DEFAULT_WARNING) { + errln("ERROR: expected createInstance to return U_USING_DEFAULT_WARNING for invalid locale and default root locale. Status: %s", u_errorName(status)); + } + + delete dtpg; + + uloc_setDefault(original, &status); + if (U_FAILURE(status)) { + errln("ERROR: Failed to change the default locale back to %s\n", original); + } +} + #endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/icu4c/source/test/intltest/dtptngts.h b/icu4c/source/test/intltest/dtptngts.h index 93842a252ed2..d9f4f428a492 100644 --- a/icu4c/source/test/intltest/dtptngts.h +++ b/icu4c/source/test/intltest/dtptngts.h @@ -33,6 +33,7 @@ class IntlTestDateTimePatternGeneratorAPI : public IntlTest { void testSkeletonsWithDayPeriods(); void testGetFieldDisplayNames(); void testJjMapping(); + void testFallbackWithDefaultRootLocale(); }; #endif /* #if !UCONFIG_NO_FORMATTING */