ICU-20706 Fix DateInterval::createInstance w/ test

See #876
This commit is contained in:
Frank Tang 2019-10-09 18:00:51 +00:00 committed by Frank Yung-Fong Tang
parent 67ea323ca2
commit 1ab75afc5f
6 changed files with 146 additions and 3 deletions

View File

@ -50,6 +50,7 @@ U_NAMESPACE_BEGIN
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateIntervalInfo)
static const char gCalendarTag[]="calendar";
static const char gGenericTag[]="generic";
static const char gGregorianTag[]="gregorian";
static const char gIntervalDateTimePatternTag[]="intervalFormats";
static const char gFallbackPatternTag[]="fallback";
@ -421,14 +422,36 @@ DateIntervalInfo::initializeData(const Locale& locale, UErrorCode& status)
UResourceBundle *calTypeBundle, *itvDtPtnResource;
// Get the fallback pattern
const UChar* resStr;
const UChar* resStr = nullptr;
int32_t resStrLen = 0;
calTypeBundle = ures_getByKeyWithFallback(calBundle, calendarTypeToUse, NULL, &status);
itvDtPtnResource = ures_getByKeyWithFallback(calTypeBundle,
gIntervalDateTimePatternTag, NULL, &status);
resStr = ures_getStringByKeyWithFallback(itvDtPtnResource, gFallbackPatternTag,
&resStrLen, &status);
// TODO(ICU-20400): After the fixing, we should find the "fallback" from
// the rb directly by the path "calendar/${calendar}/intervalFormats/fallback".
if ( U_SUCCESS(status) ) {
resStr = ures_getStringByKeyWithFallback(itvDtPtnResource, gFallbackPatternTag,
&resStrLen, &status);
if ( U_FAILURE(status) ) {
// Try to find "fallback" from "generic" to work around the bug in
// ures_getByKeyWithFallback
UErrorCode localStatus = U_ZERO_ERROR;
UResourceBundle *genericCalBundle =
ures_getByKeyWithFallback(calBundle, gGenericTag, NULL, &localStatus);
UResourceBundle *genericItvDtPtnResource =
ures_getByKeyWithFallback(
genericCalBundle, gIntervalDateTimePatternTag, NULL, &localStatus);
resStr = ures_getStringByKeyWithFallback(
genericItvDtPtnResource, gFallbackPatternTag, &resStrLen, &localStatus);
ures_close(genericItvDtPtnResource);
ures_close(genericCalBundle);
if ( U_SUCCESS(localStatus) ) {
status = U_USING_FALLBACK_WARNING;;
}
}
}
if ( U_SUCCESS(status) && (resStr != nullptr)) {
UnicodeString pattern = UnicodeString(TRUE, resStr, resStrLen);
setFallbackIntervalPattern(pattern, status);
}

View File

@ -57,6 +57,7 @@ void DateIntervalFormatTest::runIndexedTest( int32_t index, UBool exec, const ch
TESTCASE(8, testTicket11669);
TESTCASE(9, testTicket12065);
TESTCASE(10, testFormattedDateInterval);
TESTCASE(11, testCreateInstanceForAllLocales);
default: name = ""; break;
}
}
@ -1768,5 +1769,40 @@ void DateIntervalFormatTest::testFormattedDateInterval() {
}
}
void DateIntervalFormatTest::testCreateInstanceForAllLocales() {
IcuTestErrorCode status(*this, "testCreateInstanceForAllLocales");
int32_t locale_count = 0;
const Locale* locales = icu::Locale::getAvailableLocales(locale_count);
// Iterate through all locales
for (int32_t i = 0; i < locale_count; i++) {
std::unique_ptr<icu::StringEnumeration> calendars(
icu::Calendar::getKeywordValuesForLocale(
"calendar", locales[i], FALSE, status));
int32_t calendar_count = calendars->count(status);
if (status.errIfFailureAndReset()) { break; }
// In quick mode, only run 1/5 of locale combination
// to make the test run faster.
if (quick && (i % 5 != 0)) continue;
LocalPointer<DateIntervalFormat> fmt(
DateIntervalFormat::createInstance(u"dMMMMy", locales[i], status),
status);
if (status.errIfFailureAndReset(locales[i].getName())) {
continue;
}
// Iterate through all calendars in this locale
for (int32_t j = 0; j < calendar_count; j++) {
// In quick mode, only run 1/7 of locale/calendar combination
// to make the test run faster.
if (quick && ((i * j) % 7 != 0)) continue;
const char* calendar = calendars->next(nullptr, status);
Locale locale(locales[i]);
locale.setKeywordValue("calendar", calendar, status);
fmt.adoptInsteadAndCheckErrorCode(
DateIntervalFormat::createInstance(u"dMMMMy", locale, status),
status);
status.errIfFailureAndReset(locales[i].getName());
}
}
}
#endif /* #if !UCONFIG_NO_FORMATTING */

View File

@ -65,6 +65,7 @@ public:
void testTicket12065();
void testFormattedDateInterval();
void testCreateInstanceForAllLocales();
private:
/**

View File

@ -7,6 +7,7 @@
#include "unicode/utypes.h"
#include "charstr.h"
#include "cmemory.h"
#include "cstring.h"
#include "unicode/unistr.h"
@ -14,6 +15,7 @@
#include "unicode/brkiter.h"
#include "unicode/utrace.h"
#include "unicode/ucurr.h"
#include "uresimp.h"
#include "restsnew.h"
#include <stdlib.h>
@ -40,6 +42,7 @@ void NewResourceBundleTest::runIndexedTest( int32_t index, UBool exec, const cha
TESTCASE_AUTO(TestGetByFallback);
TESTCASE_AUTO(TestFilter);
TESTCASE_AUTO(TestIntervalAliasFallbacks);
#if U_ENABLE_TRACING
TESTCASE_AUTO(TestTrace);
@ -1392,6 +1395,67 @@ void NewResourceBundleTest::TestFilter() {
}
}
void NewResourceBundleTest::TestIntervalAliasFallbacks() {
const char* locales[] = {
// Thee will not cause infinity loop
"en",
"ja",
// These will cause infinity loop
"fr_CA",
"en_150",
"es_419",
"id",
"in",
"pl",
"pt_PT",
"sr_ME",
"zh_Hant",
"zh_Hant_TW",
"zh_TW",
};
const char* calendars[] = {
// These won't cause infinity loop
"gregorian",
"chinese",
// These will cause infinity loop
"islamic",
"islamic-civil",
"islamic-tbla",
"islamic-umalqura",
"ethiopic-amete-alem",
"islamic-rgsa",
"japanese",
"roc",
};
for (int lidx = 0; lidx < UPRV_LENGTHOF(locales); lidx++) {
UErrorCode status = U_ZERO_ERROR;
UResourceBundle *rb = ures_open(NULL, locales[lidx], &status);
if (U_FAILURE(status)) {
errln("Cannot open bundle for locale %s", locales[lidx]);
break;
}
for (int cidx = 0; cidx < UPRV_LENGTHOF(calendars); cidx++) {
CharString key;
key.append("calendar/", status);
key.append(calendars[cidx], status);
key.append("/intervalFormats/fallback", status);
if (! logKnownIssue("20400")) {
int32_t resStrLen = 0;
ures_getStringByKeyWithFallback(rb, key.data(), &resStrLen, &status);
}
if (U_FAILURE(status)) {
errln("Cannot ures_getStringByKeyWithFallback('%s') on locale %s",
key.data(), locales[lidx]);
break;
}
}
ures_close(rb);
}
}
#if U_ENABLE_TRACING
static std::vector<std::string> gResourcePathsTraced;

View File

@ -39,6 +39,7 @@ public:
void TestGetByFallback(void);
void TestFilter(void);
void TestIntervalAliasFallbacks(void);
#if U_ENABLE_TRACING
void TestTrace(void);

View File

@ -2032,4 +2032,22 @@ public class DateIntervalFormatTest extends TestFmwk {
expectedFieldPositions);
}
}
@Test
public void testCreateInstanceForAllLocales() {
boolean quick = (getExhaustiveness() <= 5);
int count = 0;
for (ULocale locale : ULocale.getAvailableLocalesByType(
ULocale.AvailableType.WITH_LEGACY_ALIASES)) {
// Only test 1/5 of the locale in quick mode.
if (quick && (count++ % 5 > 0)) continue;
DateIntervalFormat fmt = DateIntervalFormat.getInstance("dMMMMy", locale);
for (String calendar : Calendar.getKeywordValuesForLocale(
"calendar", locale, false)) {
// Only test 1/7 of case in quick mode.
if (quick && (count++ % 7 > 0)) continue;
ULocale l = locale.setKeywordValue("calendar", calendar);
fmt = DateIntervalFormat.getInstance("dMMMMy", l);
}
}
}
}