diff options
Diffstat (limited to 'Build/source/libs/icu/icu-src/source/test/intltest')
27 files changed, 1134 insertions, 123 deletions
diff --git a/Build/source/libs/icu/icu-src/source/test/intltest/csdetest.cpp b/Build/source/libs/icu/icu-src/source/test/intltest/csdetest.cpp index 66f9340b83a..95f19d43d1a 100644 --- a/Build/source/libs/icu/icu-src/source/test/intltest/csdetest.cpp +++ b/Build/source/libs/icu/icu-src/source/test/intltest/csdetest.cpp @@ -109,6 +109,10 @@ void CharsetDetectionTest::runIndexedTest( int32_t index, UBool exec, const char if (exec) Ticket6954Test(); break; + case 10: name = "Ticket21823Test"; + if (exec) Ticket21823Test(); + break; + default: name = ""; break; //needed to end loop } @@ -839,3 +843,22 @@ void CharsetDetectionTest::Ticket6954Test() { TEST_ASSERT(strcmp(name1, "windows-1252")==0); #endif } + + +// Ticket 21823 - Issue with Charset Detector for ill-formed input strings. +// Its fix involves returning a failure based error code +// (U_INVALID_CHAR_FOUND) incase no charsets appear to match the input data. +void CharsetDetectionTest::Ticket21823Test() { + UErrorCode status = U_ZERO_ERROR; + std::string str = "\x80"; + UCharsetDetector* csd = ucsdet_open(&status); + + ucsdet_setText(csd, str.data(), str.length(), &status); + const UCharsetMatch* match = ucsdet_detect(csd, &status); + + if (match == NULL) { + TEST_ASSERT(U_FAILURE(status)); + } + + ucsdet_close(csd); +} diff --git a/Build/source/libs/icu/icu-src/source/test/intltest/csdetest.h b/Build/source/libs/icu/icu-src/source/test/intltest/csdetest.h index 72d1ca92aea..8893b88e591 100644 --- a/Build/source/libs/icu/icu-src/source/test/intltest/csdetest.h +++ b/Build/source/libs/icu/icu-src/source/test/intltest/csdetest.h @@ -33,6 +33,7 @@ public: virtual void IBM420Test(); virtual void Ticket6394Test(); virtual void Ticket6954Test(); + virtual void Ticket21823Test(); private: void checkEncoding(const UnicodeString &testString, diff --git a/Build/source/libs/icu/icu-src/source/test/intltest/dtfmttst.cpp b/Build/source/libs/icu/icu-src/source/test/intltest/dtfmttst.cpp index 16f3002a95e..920ec75c8b9 100644 --- a/Build/source/libs/icu/icu-src/source/test/intltest/dtfmttst.cpp +++ b/Build/source/libs/icu/icu-src/source/test/intltest/dtfmttst.cpp @@ -190,7 +190,7 @@ void DateFormatTest::TestPatterns() { {UDAT_ABBR_UTC_TZ, "ZZZZ", "en", "ZZZZ"}, {UDAT_YEAR_NUM_MONTH_DAY UDAT_ABBR_UTC_TZ, "yMdZZZZ", "en", "M/d/y, ZZZZ"}, - {UDAT_MONTH_DAY UDAT_LOCATION_TZ, "MMMMdVVVV", "en", "MMMM d, VVVV"} + {UDAT_MONTH_DAY UDAT_LOCATION_TZ, "MMMMdVVVV", "en", "MMMM d 'at' VVVV"} }; IcuTestErrorCode errorCode(*this, "TestPatterns()"); diff --git a/Build/source/libs/icu/icu-src/source/test/intltest/dtifmtts.cpp b/Build/source/libs/icu/icu-src/source/test/intltest/dtifmtts.cpp index dc9a78dbe16..605eae43614 100644 --- a/Build/source/libs/icu/icu-src/source/test/intltest/dtifmtts.cpp +++ b/Build/source/libs/icu/icu-src/source/test/intltest/dtifmtts.cpp @@ -1107,8 +1107,23 @@ void DateIntervalFormatTest::testHourMetacharacters() { "de", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "HH", "00\\u201301 Uhr", // k and K (ICU-21154 and ICU-21156) - "en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "KK", "0 \\u2013 1 AM", - "de", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "kk", "24\\u201301 Uhr", + // (should behave the same as h and H if not overridden in locale ID) + "en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "KK", "12 \\u2013 1 AM", + "de", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "kk", "00\\u201301 Uhr", + // (overriding hour cycle in locale ID should affect both h and K [or both H and k]) + "en-u-hc-h11", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "hh", "0 \\u2013 1 AM", + "en-u-hc-h11", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "KK", "0 \\u2013 1 AM", + "de-u-hc-h24", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "HH", "24\\u201301 Uhr", + "de-u-hc-h24", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "kk", "24\\u201301 Uhr", + // (overriding hour cycle to h11 should NOT affect H and k; overriding to h24 should NOT affect h and K) + "en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "HH", "00 \\u2013 01", + "en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "kk", "00 \\u2013 01", + "en-u-hc-h11", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "HH", "00 \\u2013 01", + "en-u-hc-h11", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "kk", "00 \\u2013 01", + "de", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "hh", "12 \\u2013 1 Uhr AM", + "de", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "KK", "12 \\u2013 1 Uhr AM", + "de-u-hc-h24", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "hh", "12 \\u2013 1 Uhr AM", + "de-u-hc-h24", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "KK", "12 \\u2013 1 Uhr AM", // different lengths of the 'a' field "en", "CE 2010 09 27 10:00:00", "CE 2010 09 27 13:00:00", "ha", "10 AM \\u2013 1 PM", @@ -1163,14 +1178,22 @@ void DateIntervalFormatTest::testHourMetacharacters() { "hi_IN", "CE 2010 09 27 10:00:00", "CE 2010 09 27 13:00:00", "CC", "\\u0938\\u0941\\u092C\\u0939 10 \\u2013 \\u0926\\u094B\\u092A\\u0939\\u0930 1", "hi_IN", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "CC", "\\u0930\\u093E\\u0924 12\\u20131", - // regression test for ICU-21342 - "en_GB", "CE 2010 09 27 00:00:00", "CE 2010 09 27 10:00:00", "kk", "24\\u201310", - "en_GB", "CE 2010 09 27 00:00:00", "CE 2010 09 27 11:00:00", "kk", "24\\u201311", - "en_GB", "CE 2010 09 27 00:00:00", "CE 2010 09 27 12:00:00", "kk", "24\\u201312", - "en_GB", "CE 2010 09 27 00:00:00", "CE 2010 09 27 13:00:00", "kk", "24\\u201313", + // regression test for ICU-21342 + "en-gb-u-hc-h24", "CE 2010 09 27 00:00:00", "CE 2010 09 27 10:00:00", "kk", "24\\u201310", + "en-gb-u-hc-h24", "CE 2010 09 27 00:00:00", "CE 2010 09 27 11:00:00", "kk", "24\\u201311", + "en-gb-u-hc-h24", "CE 2010 09 27 00:00:00", "CE 2010 09 27 12:00:00", "kk", "24\\u201312", + "en-gb-u-hc-h24", "CE 2010 09 27 00:00:00", "CE 2010 09 27 13:00:00", "kk", "24\\u201313", - // regression test for ICU-21343 - "de", "CE 2010 09 27 01:00:00", "CE 2010 09 27 10:00:00", "KK", "1 \\u2013 10 Uhr AM", + // regression test for ICU-21343 + "de", "CE 2010 09 27 01:00:00", "CE 2010 09 27 10:00:00", "KK", "1 \\u2013 10 Uhr AM", + + // regression test for ICU-21154 (single-date ranges should use the same hour cycle as multi-date ranges) + "en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 00:00:00", "hh", "12 AM", + "en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "hh", "12 \\u2013 1 AM", + "en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 00:00:00", "KK", "12 AM", + "en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "KK", "12 \\u2013 1 AM", // (this was producing "0 - 1 AM" before) + "en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 00:00:00", "jj", "12 AM", + "en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "jj", "12 \\u2013 1 AM", }; expect(DATA, UPRV_LENGTHOF(DATA)); } diff --git a/Build/source/libs/icu/icu-src/source/test/intltest/dtptngts.cpp b/Build/source/libs/icu/icu-src/source/test/intltest/dtptngts.cpp index 6fe8af05b60..dde9d4dd3ac 100644 --- a/Build/source/libs/icu/icu-src/source/test/intltest/dtptngts.cpp +++ b/Build/source/libs/icu/icu-src/source/test/intltest/dtptngts.cpp @@ -46,6 +46,7 @@ void IntlTestDateTimePatternGeneratorAPI::runIndexedTest( int32_t index, UBool e TESTCASE(10, testGetDefaultHourCycle_OnEmptyInstance); TESTCASE(11, test_jConsistencyOddLocales); TESTCASE(12, testBestPattern); + TESTCASE(13, testDateTimePatterns); default: name = ""; break; } } @@ -530,7 +531,7 @@ void IntlTestDateTimePatternGeneratorAPI::testAPI(/*char *par*/) format->applyPattern(gen->getBestPattern(UnicodeString("MMMMdHmm"), status)); dateReturned.remove(); dateReturned = format->format(sampleDate, dateReturned, status); - expectedResult=UnicodeString("14. von Oktober, 08:58", -1, US_INV); + expectedResult=UnicodeString("14. von Oktober um 08:58", -1, US_INV); if ( dateReturned != expectedResult ) { errln(UnicodeString("ERROR: Simple test addPattern failed!: d\'. von\' MMMM Got: ") + dateReturned + UnicodeString(" Expected: ") + expectedResult); } @@ -1631,4 +1632,150 @@ void IntlTestDateTimePatternGeneratorAPI::testBestPattern() { } } +void IntlTestDateTimePatternGeneratorAPI::testDateTimePatterns() { + UnicodeString skeletons[kNumDateTimePatterns] = { + UnicodeString("yMMMMEEEEdjmm"), // full date, short time + UnicodeString("yMMMMdjmm"), // long date, short time + UnicodeString("yMMMdjmm"), // medium date, short time + UnicodeString("yMdjmm") // short date, short time + }; + // The following tests some locales in which there are differences between the + // DateTimePatterns of various length styles. + DTPLocaleAndResults localeAndResults[] = { + { "en", { UnicodeString(u"EEEE, MMMM d, y 'at' h:mm a"), // long != medium + UnicodeString(u"MMMM d, y 'at' h:mm a"), + UnicodeString(u"MMM d, y, h:mm a"), + UnicodeString(u"M/d/y, h:mm a") } }, + { "fr", { UnicodeString(u"EEEE d MMMM y 'à' HH:mm"), // medium != short + UnicodeString(u"d MMMM y 'à' HH:mm"), + UnicodeString(u"d MMM y, HH:mm"), + UnicodeString(u"dd/MM/y HH:mm") } }, + { "ha", { UnicodeString(u"EEEE d MMMM, y HH:mm"), // full != long + UnicodeString(u"d MMMM, y 'da' HH:mm"), + UnicodeString(u"d MMM, y, HH:mm"), + UnicodeString(u"y-MM-dd, HH:mm") } }, + { nullptr, { UnicodeString(""), UnicodeString(""), // terminator + UnicodeString(""), UnicodeString("") } }, + }; + + UnicodeString enDTPatterns[kNumDateTimePatterns] = { + UnicodeString(u"{1} 'at' {0}"), + UnicodeString(u"{1} 'at' {0}"), + UnicodeString(u"{1}, {0}"), + UnicodeString(u"{1}, {0}") + }; + UnicodeString modDTPatterns[kNumDateTimePatterns] = { + UnicodeString(u"{1} _0_ {0}"), + UnicodeString(u"{1} _1_ {0}"), + UnicodeString(u"{1} _2_ {0}"), + UnicodeString(u"{1} _3_ {0}") + }; + DTPLocaleAndResults enModResults = { "en", { UnicodeString(u"EEEE, MMMM d, y _0_ h:mm a"), + UnicodeString(u"MMMM d, y _1_ h:mm a"), + UnicodeString(u"MMM d, y _2_ h:mm a"), + UnicodeString(u"M/d/y _3_ h:mm a") } + }; + + // Test various locales with standard data + UErrorCode status; + LocalPointer<DateTimePatternGenerator> dtpg; + DTPLocaleAndResults* localeAndResultsPtr = localeAndResults; + for (; localeAndResultsPtr->localeID != nullptr; localeAndResultsPtr++) { + status = U_ZERO_ERROR; + Locale locale(localeAndResultsPtr->localeID); + dtpg.adoptInstead(DateTimePatternGenerator::createInstance(locale, status)); + if (U_FAILURE(status)) { + dataerrln("FAIL: DateTimePatternGenerator::createInstance for locale %s: %s", + localeAndResultsPtr->localeID, u_errorName(status)); + } else { + doDTPatternTest(dtpg.getAlias(), skeletons, localeAndResultsPtr); + } + } + // Test getting and modifying date-time combining patterns + status = U_ZERO_ERROR; + dtpg.adoptInstead(DateTimePatternGenerator::createInstance(Locale::getEnglish(), status)); + if (U_FAILURE(status)) { + dataerrln("FAIL: DateTimePatternGenerator::createInstance #2 for locale en: %s", u_errorName(status)); + } else { + char bExpect[64]; + char bGet[64]; + // Test style out of range + status = U_ZERO_ERROR; + const UnicodeString& dtFormat0 = dtpg->getDateTimeFormat(UDAT_NONE, status); + int32_t dtFormat0Len = dtFormat0.length(); + if (status != U_ILLEGAL_ARGUMENT_ERROR || dtFormat0Len != 0) { + errln("ERROR: getDateTimeFormat with invalid style, expected U_ILLEGAL_ARGUMENT_ERROR and lero-length string, " + "got %s with length %d", u_errorName(status), dtFormat0Len); + } + // Test normal getting and setting + for (int32_t patStyle = 0; patStyle < kNumDateTimePatterns; patStyle++) { + status = U_ZERO_ERROR; + const UnicodeString& dtFormat1 = dtpg->getDateTimeFormat((UDateFormatStyle)patStyle, status); + if (U_FAILURE(status)) { + errln("FAIL: getDateTimeFormat for en before mod, style %d, get %s", patStyle, u_errorName(status)); + } else if (dtFormat1 != enDTPatterns[patStyle]) { + enDTPatterns[patStyle].extract(0, enDTPatterns[patStyle].length(), bExpect, 64); + dtFormat1.extract(0, dtFormat1.length(), bGet, 64); + errln("ERROR: getDateTimeFormat for en before mod, style %d, expect \"%s\", get \"%s\"", + patStyle, bExpect, bGet); + } + status = U_ZERO_ERROR; + dtpg->setDateTimeFormat((UDateFormatStyle)patStyle, modDTPatterns[patStyle], status); + if (U_FAILURE(status)) { + errln("FAIL: setDateTimeFormat for en, style %d, get %s", patStyle, u_errorName(status)); + } else { + const UnicodeString& dtFormat2 = dtpg->getDateTimeFormat((UDateFormatStyle)patStyle, status); + if (U_FAILURE(status)) { + errln("FAIL: getDateTimeFormat for en after mod, style %d, get %s", patStyle, u_errorName(status)); + } else if (dtFormat2 != modDTPatterns[patStyle]) { + modDTPatterns[patStyle].extract(0, modDTPatterns[patStyle].length(), bExpect, 64); + dtFormat2.extract(0, dtFormat2.length(), bGet, 64); + errln("ERROR: getDateTimeFormat for en after mod, style %d, expect \"%s\", get \"%s\"", + patStyle, bExpect, bGet); + } + } + } + // Test result of setting + doDTPatternTest(dtpg.getAlias(), skeletons, &enModResults); + // Test old get/set functions + const UnicodeString& dtFormat3 = dtpg->getDateTimeFormat(); + if (dtFormat3 != modDTPatterns[UDAT_MEDIUM]) { + modDTPatterns[UDAT_MEDIUM].extract(0, modDTPatterns[UDAT_MEDIUM].length(), bExpect, 64); + dtFormat3.extract(0, dtFormat3.length(), bGet, 64); + errln("ERROR: old getDateTimeFormat for en after mod, expect \"%s\", get \"%s\"", bExpect, bGet); + } + dtpg->setDateTimeFormat(modDTPatterns[UDAT_SHORT]); // set all dateTimePatterns to the short format + modDTPatterns[UDAT_SHORT].extract(0, modDTPatterns[UDAT_SHORT].length(), bExpect, 64); + for (int32_t patStyle = 0; patStyle < kNumDateTimePatterns; patStyle++) { + status = U_ZERO_ERROR; + const UnicodeString& dtFormat4 = dtpg->getDateTimeFormat((UDateFormatStyle)patStyle, status); + if (U_FAILURE(status)) { + errln("FAIL: getDateTimeFormat for en after second mod, style %d, get %s", patStyle, u_errorName(status)); + } else if (dtFormat4 != modDTPatterns[UDAT_SHORT]) { + dtFormat4.extract(0, dtFormat4.length(), bGet, 64); + errln("ERROR: getDateTimeFormat for en after second mod, style %d, expect \"%s\", get \"%s\"", + patStyle, bExpect, bGet); + } + } + } +} + +void IntlTestDateTimePatternGeneratorAPI::doDTPatternTest(DateTimePatternGenerator* dtpg, UnicodeString* skeletons, DTPLocaleAndResults* localeAndResultsPtr) { + for (int32_t patStyle = 0; patStyle < kNumDateTimePatterns; patStyle++) { + UErrorCode status = U_ZERO_ERROR; + UnicodeString getPat = dtpg->getBestPattern(skeletons[patStyle], UDATPG_MATCH_NO_OPTIONS, status); + if (U_FAILURE(status)) { + errln("FAIL: DateTimePatternGenerator::getBestPattern locale %s, style %d: %s", + localeAndResultsPtr->localeID, patStyle, u_errorName(status)); + } else if (getPat != localeAndResultsPtr->expectPat[patStyle]) { + char bExpect[64]; + char bGet[64]; + localeAndResultsPtr->expectPat[patStyle].extract(0, localeAndResultsPtr->expectPat[patStyle].length(), bExpect, 64); + getPat.extract(0, getPat.length(), bGet, 64); + errln("ERROR: DateTimePatternGenerator::getBestPattern locale %s, style %d, expect \"%s\", get \"%s\"", + localeAndResultsPtr->localeID, patStyle, bExpect, bGet); + } + } +} + #endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/Build/source/libs/icu/icu-src/source/test/intltest/dtptngts.h b/Build/source/libs/icu/icu-src/source/test/intltest/dtptngts.h index 4650fd7fcf6..ec700603eb1 100644 --- a/Build/source/libs/icu/icu-src/source/test/intltest/dtptngts.h +++ b/Build/source/libs/icu/icu-src/source/test/intltest/dtptngts.h @@ -13,6 +13,8 @@ #if !UCONFIG_NO_FORMATTING +#include "unicode/dtptngen.h" +#include "unicode/ustring.h" #include "intltest.h" /** @@ -38,6 +40,14 @@ private: void testGetDefaultHourCycle_OnEmptyInstance(); void test_jConsistencyOddLocales(); void testBestPattern(); + void testDateTimePatterns(); + + enum { kNumDateTimePatterns = 4 }; + typedef struct { + const char* localeID; + const UnicodeString expectPat[kNumDateTimePatterns]; + } DTPLocaleAndResults; + void doDTPatternTest(DateTimePatternGenerator* dtpg, UnicodeString* skeletons, DTPLocaleAndResults* localeAndResultsPtr); }; #endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/Build/source/libs/icu/icu-src/source/test/intltest/icusvtst.cpp b/Build/source/libs/icu/icu-src/source/test/intltest/icusvtst.cpp index aa2d9ca05ce..cb863c5b71b 100644 --- a/Build/source/libs/icu/icu-src/source/test/intltest/icusvtst.cpp +++ b/Build/source/libs/icu/icu-src/source/test/intltest/icusvtst.cpp @@ -558,7 +558,7 @@ class TestMultipleKeyStringFactory : public ICUServiceFactory { , _factoryID(factoryID + ": ") { for (int i = 0; i < count; ++i) { - _ids.addElementX(new UnicodeString(ids[i]), _status); + _ids.adoptElement(new UnicodeString(ids[i]), _status); } } diff --git a/Build/source/libs/icu/icu-src/source/test/intltest/incaltst.cpp b/Build/source/libs/icu/icu-src/source/test/intltest/incaltst.cpp index ad75f185f63..250b61c7ac0 100644 --- a/Build/source/libs/icu/icu-src/source/test/intltest/incaltst.cpp +++ b/Build/source/libs/icu/icu-src/source/test/intltest/incaltst.cpp @@ -988,7 +988,7 @@ void IntlCalendarTest::TestConsistencyEthiopicAmeteAlem() { } void IntlCalendarTest::checkConsistency(const char* locale) { // Check 2.5 years in quick mode and 8000 years in exhaustive mode. - int32_t numOfDaysToTest = (quick ? 2.5 : 8000) * 365; + int32_t numOfDaysToTest = static_cast<int32_t>((quick ? 2.5 : 8000) * 365); constexpr int32_t msInADay = 1000*60*60*24; std::string msg("TestConsistency"); IcuTestErrorCode status(*this, (msg + locale).c_str()); diff --git a/Build/source/libs/icu/icu-src/source/test/intltest/intltest.cpp b/Build/source/libs/icu/icu-src/source/test/intltest/intltest.cpp index 7ff28961271..f2956ebcb48 100644 --- a/Build/source/libs/icu/icu-src/source/test/intltest/intltest.cpp +++ b/Build/source/libs/icu/icu-src/source/test/intltest/intltest.cpp @@ -2188,14 +2188,20 @@ UBool IntlTest::assertEqualsNear(const char* message, double expected, double actual, double delta) { + bool bothNaN = std::isnan(expected) && std::isnan(actual); + bool bothPosInf = uprv_isPositiveInfinity(expected) && uprv_isPositiveInfinity(actual); + bool bothNegInf = uprv_isNegativeInfinity(expected) && uprv_isNegativeInfinity(actual); + if (bothPosInf || bothNegInf || bothNaN) { + // We don't care about delta in these cases + return TRUE; + } if (std::isnan(delta) || std::isinf(delta)) { errln((UnicodeString)("FAIL: ") + message + "; nonsensical delta " + delta + - " - delta may not be NaN or Inf"); + " - delta may not be NaN or Inf. (Got " + actual + "; expected " + expected + ".)"); return FALSE; } - bool bothNaN = std::isnan(expected) && std::isnan(actual); double difference = std::abs(expected - actual); - if (expected != actual && (difference > delta || std::isnan(difference)) && !bothNaN) { + if (expected != actual && (difference > delta || std::isnan(difference))) { errln((UnicodeString)("FAIL: ") + message + "; got " + actual + "; expected " + expected + "; acceptable delta " + delta); return FALSE; diff --git a/Build/source/libs/icu/icu-src/source/test/intltest/listformattertest.cpp b/Build/source/libs/icu/icu-src/source/test/intltest/listformattertest.cpp index 831642241e6..1a4ec97f37d 100644 --- a/Build/source/libs/icu/icu-src/source/test/intltest/listformattertest.cpp +++ b/Build/source/libs/icu/icu-src/source/test/intltest/listformattertest.cpp @@ -49,6 +49,7 @@ void ListFormatterTest::runIndexedTest(int32_t index, UBool exec, TESTCASE_AUTO(TestContextual); TESTCASE_AUTO(TestNextPosition); TESTCASE_AUTO(TestInt32Overflow); + TESTCASE_AUTO(Test21871); TESTCASE_AUTO_END; } @@ -276,7 +277,7 @@ void ListFormatterTest::RunTestFieldPositionIteratorWithNItemsPatternShift( const char* testName) { IcuTestErrorCode errorCode(*this, testName); LocalPointer<ListFormatter> formatter(ListFormatter::createInstance( - Locale("ur", "IN"), + Locale("ur", "IN"), // in CLDR 41 alpha1 the "backwards order" patterns in this and other locales were removed. ULISTFMT_TYPE_UNITS, ULISTFMT_WIDTH_NARROW, errorCode)); @@ -329,21 +330,21 @@ void ListFormatterTest::TestFieldPositionIteratorWith3Items() { } void ListFormatterTest::TestFieldPositionIteratorWith3ItemsPatternShift() { - // 0 1 - // 012345678901234 - // "cc bbb a" + // Note: In CLDR 41 alpha1 the "backwards order" patterns in ur_IN (and one or two + // other locales) were removed, ur_IN now just inherits list patterns from ur. + // So this test may no longer be interesting. UnicodeString data[3] = {"a", "bbb", "cc"}; int32_t expected[] = { - ULISTFMT_ELEMENT_FIELD, 7, 8, - ULISTFMT_LITERAL_FIELD, 6, 7, + ULISTFMT_ELEMENT_FIELD, 0, 1, + ULISTFMT_LITERAL_FIELD, 1, 3, ULISTFMT_ELEMENT_FIELD, 3, 6, - ULISTFMT_LITERAL_FIELD, 2, 3, - ULISTFMT_ELEMENT_FIELD, 0, 2 + ULISTFMT_LITERAL_FIELD, 6, 12, + ULISTFMT_ELEMENT_FIELD, 12, 14 }; int32_t tupleCount = sizeof(expected)/(3 * sizeof(*expected)); RunTestFieldPositionIteratorWithNItemsPatternShift( data, 3, expected, tupleCount, - u"cc bbb a", + u"a، bbb، اور cc", "TestFieldPositionIteratorWith3ItemsPatternShift"); } @@ -365,19 +366,19 @@ void ListFormatterTest::TestFieldPositionIteratorWith2Items() { } void ListFormatterTest::TestFieldPositionIteratorWith2ItemsPatternShift() { - // 0 1 - // 01234567890 - // "cc bbb" + // Note: In CLDR 41 alpha1 the "backwards order" patterns in ur_IN (and one or two + // other locales) were removed, ur_IN now just inherits list patterns from ur. + // So this test may no longer be interesting. UnicodeString data[2] = {"bbb", "cc"}; int32_t expected[] = { - ULISTFMT_ELEMENT_FIELD, 3, 6, - ULISTFMT_LITERAL_FIELD, 2, 3, - ULISTFMT_ELEMENT_FIELD, 0, 2 + ULISTFMT_ELEMENT_FIELD, 0, 3, + ULISTFMT_LITERAL_FIELD, 3, 8, + ULISTFMT_ELEMENT_FIELD, 8, 10 }; int32_t tupleCount = sizeof(expected)/(3 * sizeof(*expected)); RunTestFieldPositionIteratorWithNItemsPatternShift( data, 2, expected, tupleCount, - u"cc bbb", + u"bbb اور cc", "TestFieldPositionIteratorWith2ItemsPatternShift"); } @@ -840,4 +841,30 @@ void ListFormatterTest::TestInt32Overflow() { status.expectErrorAndReset(U_INPUT_TOO_LONG_ERROR); } + +void ListFormatterTest::Test21871() { + IcuTestErrorCode status(*this, "Test21871"); + LocalPointer<ListFormatter> fmt(ListFormatter::createInstance("en", status), status); + { + UnicodeString strings[] = {{u"A"}, {u""}}; + FormattedList result = fmt->formatStringsToValue(strings, 2, status); + ConstrainedFieldPosition cfp; + cfp.constrainField(UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD); + assertTrue("nextPosition 1", result.nextPosition(cfp, status)); + assertEquals("start", cfp.getStart(), 0); + assertEquals("limit", cfp.getLimit(), 1); + assertFalse("nextPosition 2", result.nextPosition(cfp, status)); + } + { + UnicodeString strings[] = {{u""}, {u"B"}}; + FormattedList result = fmt->formatStringsToValue(strings, 2, status); + ConstrainedFieldPosition cfp; + cfp.constrainField(UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD); + assertTrue("nextPosition 1", result.nextPosition(cfp, status)); + assertEquals("start", cfp.getStart(), 5); + assertEquals("limit", cfp.getLimit(), 6); + assertFalse("nextPosition 2", result.nextPosition(cfp, status)); + } +} + #endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/Build/source/libs/icu/icu-src/source/test/intltest/listformattertest.h b/Build/source/libs/icu/icu-src/source/test/intltest/listformattertest.h index d6bf3bc0d68..0f0390010e4 100644 --- a/Build/source/libs/icu/icu-src/source/test/intltest/listformattertest.h +++ b/Build/source/libs/icu/icu-src/source/test/intltest/listformattertest.h @@ -56,6 +56,7 @@ class ListFormatterTest : public IntlTestWithFieldPosition { void TestContextual(); void TestNextPosition(); void TestInt32Overflow(); + void Test21871(); private: void CheckFormatting( diff --git a/Build/source/libs/icu/icu-src/source/test/intltest/lstmbetst.cpp b/Build/source/libs/icu/icu-src/source/test/intltest/lstmbetst.cpp index 6c5d5d0ad61..0ffc0fa20e5 100644 --- a/Build/source/libs/icu/icu-src/source/test/intltest/lstmbetst.cpp +++ b/Build/source/libs/icu/icu-src/source/test/intltest/lstmbetst.cpp @@ -153,7 +153,7 @@ void LSTMBETest::runTestFromFile(const char* filename) { dataerrln("%s:%d Error %s Could not allocate UVextor32", __FILE__, __LINE__, u_errorName(status)); return; } - engine->findBreaks(&ut, 0, value.length(), actual, status); + engine->findBreaks(&ut, 0, value.length(), actual, false, status); if (U_FAILURE(status)) { dataerrln("%s:%d Error %s findBreaks failed", __FILE__, __LINE__, u_errorName(status)); return; @@ -288,7 +288,7 @@ void LSTMBETest::runTestWithLargeMemory( const char* model, UScriptCode script) return; } - engine->findBreaks(&ut, 0, text.length(), actual, status); + engine->findBreaks(&ut, 0, text.length(), actual, false, status); utext_close(&ut); text += text; } diff --git a/Build/source/libs/icu/icu-src/source/test/intltest/measfmttest.cpp b/Build/source/libs/icu/icu-src/source/test/intltest/measfmttest.cpp index 003804db9a4..05488b7c360 100644 --- a/Build/source/libs/icu/icu-src/source/test/intltest/measfmttest.cpp +++ b/Build/source/libs/icu/icu-src/source/test/intltest/measfmttest.cpp @@ -2683,7 +2683,7 @@ void MeasureFormatTest::TestCompatible69() { assertSuccess("", status); } -void MeasureFormatTest::TestCompatible70() { +void MeasureFormatTest::TestCompatible70() { // TestCompatible71 would be identical UErrorCode status = U_ZERO_ERROR; LocalPointer<MeasureUnit> measureUnit; MeasureUnit measureUnitValue; @@ -3064,6 +3064,9 @@ void MeasureFormatTest::TestCompatible70() { assertSuccess("", status); } +// TestCompatible71 would be identical to TestCompatible70, +// no need to add it + void MeasureFormatTest::TestBasic() { UErrorCode status = U_ZERO_ERROR; MeasureUnit *ptr1 = MeasureUnit::createArcMinute(status); diff --git a/Build/source/libs/icu/icu-src/source/test/intltest/numbertest.h b/Build/source/libs/icu/icu-src/source/test/intltest/numbertest.h index d6d71543fb6..c0f2e6fd58a 100644 --- a/Build/source/libs/icu/icu-src/source/test/intltest/numbertest.h +++ b/Build/source/libs/icu/icu-src/source/test/intltest/numbertest.h @@ -66,6 +66,7 @@ class NumberFormatterApiTest : public IntlTestWithFieldPosition { void unitUsageSkeletons(); void unitCurrency(); void unitInflections(); + void unitNounClass(); void unitGender(); void unitNotConvertible(); void unitPercent(); @@ -75,6 +76,7 @@ class NumberFormatterApiTest : public IntlTestWithFieldPosition { void roundingFractionFigures(); void roundingOther(); void roundingIncrementRegressionTest(); + void roundingPriorityCoverageTest(); void grouping(); void padding(); void integerWidth(); @@ -99,7 +101,8 @@ class NumberFormatterApiTest : public IntlTestWithFieldPosition { void toObject(); void toDecimalNumber(); void microPropsInternals(); - + void formatUnitsAliases(); + void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par = 0) override; private: @@ -206,6 +209,7 @@ class DecimalQuantityTest : public IntlTest { void testNickelRounding(); void testScientificAndCompactSuppressedExponent(); void testSuppressedExponentUnchangedByInitialScaling(); + void testDecimalQuantityParseFormatRoundTrip(); void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par = 0) override; diff --git a/Build/source/libs/icu/icu-src/source/test/intltest/numbertest_api.cpp b/Build/source/libs/icu/icu-src/source/test/intltest/numbertest_api.cpp index cf8fecc0a28..b477a16e93e 100644 --- a/Build/source/libs/icu/icu-src/source/test/intltest/numbertest_api.cpp +++ b/Build/source/libs/icu/icu-src/source/test/intltest/numbertest_api.cpp @@ -87,6 +87,7 @@ void NumberFormatterApiTest::runIndexedTest(int32_t index, UBool exec, const cha TESTCASE_AUTO(unitUsageSkeletons); TESTCASE_AUTO(unitCurrency); TESTCASE_AUTO(unitInflections); + TESTCASE_AUTO(unitNounClass); TESTCASE_AUTO(unitGender); TESTCASE_AUTO(unitNotConvertible); TESTCASE_AUTO(unitPercent); @@ -99,6 +100,7 @@ void NumberFormatterApiTest::runIndexedTest(int32_t index, UBool exec, const cha TESTCASE_AUTO(roundingFractionFigures); TESTCASE_AUTO(roundingOther); TESTCASE_AUTO(roundingIncrementRegressionTest); + TESTCASE_AUTO(roundingPriorityCoverageTest); TESTCASE_AUTO(grouping); TESTCASE_AUTO(padding); TESTCASE_AUTO(integerWidth); @@ -127,6 +129,7 @@ void NumberFormatterApiTest::runIndexedTest(int32_t index, UBool exec, const cha TESTCASE_AUTO(toObject); TESTCASE_AUTO(toDecimalNumber); TESTCASE_AUTO(microPropsInternals); + TESTCASE_AUTO(formatUnitsAliases); TESTCASE_AUTO_END; } @@ -1747,6 +1750,46 @@ void NumberFormatterApiTest::unitUsage() { 30500, u"350 m"); + assertFormatSingle(u"Fuel consumption: inverted units", // + u"unit/liter-per-100-kilometer usage/vehicle-fuel", // + u"unit/liter-per-100-kilometer usage/vehicle-fuel", // + NumberFormatter::with() // + .unit(MeasureUnit::forIdentifier("liter-per-100-kilometer", status)) // + .usage("vehicle-fuel"), // + Locale("en-US"), // + 6.6, // + "36 mpg"); + + assertFormatSingle(u"Fuel consumption: inverted units, divide-by-zero, en-US", // + u"unit/liter-per-100-kilometer usage/vehicle-fuel", // + u"unit/liter-per-100-kilometer usage/vehicle-fuel", // + NumberFormatter::with() // + .unit(MeasureUnit::forIdentifier("liter-per-100-kilometer", status)) // + .usage("vehicle-fuel"), // + Locale("en-US"), // + 0, // + u"∞ mpg"); + + assertFormatSingle(u"Fuel consumption: inverted units, divide-by-zero, en-ZA", // + u"unit/mile-per-gallon usage/vehicle-fuel", // + u"unit/mile-per-gallon usage/vehicle-fuel", // + NumberFormatter::with() // + .unit(MeasureUnit::forIdentifier("mile-per-gallon", status)) // + .usage("vehicle-fuel"), // + Locale("en-ZA"), // + 0, // + u"∞ l/100 km"); + + assertFormatSingle(u"Fuel consumption: inverted units, divide-by-inf", // + u"unit/mile-per-gallon usage/vehicle-fuel", // + u"unit/mile-per-gallon usage/vehicle-fuel", // + NumberFormatter::with() // + .unit(MeasureUnit::forIdentifier("mile-per-gallon", status)) // + .usage("vehicle-fuel"), // + Locale("de-CH"), // + uprv_getInfinity(), // + u"0 L/100 km"); + // Test calling `.usage("")` should unset the existing usage. // First: without usage assertFormatSingle(u"Rounding Mode propagates: rounding up", @@ -1853,10 +1896,6 @@ void NumberFormatterApiTest::unitUsage() { Locale("en-US"), // 1, // "0.019 psi"); - - // TODO(icu-units#38): improve unit testing coverage. E.g. add vehicle-fuel - // triggering inversion conversion code. Test with 0 too, to see - // divide-by-zero behaviour. } void NumberFormatterApiTest::unitUsageErrorCodes() { @@ -2384,7 +2423,7 @@ void NumberFormatterApiTest::unitInflections() { {"centimeter", "de", nullptr, 1, u"1 Zentimeter"}, {"centimeter", "de", "genitive", 1, u"1 Zentimeters"}, {"centimeter", "de", "dative", 10, u"10 Zentimetern"}, - // TODO(CLDR-14502): check that these inflections are correct, and + // TODO(CLDR-14582): check that these inflections are correct, and // whether CLDR needs any rules for them (presumably CLDR spec // should mention it, if it's a consistent rule): {"meter-and-centimeter", "de", nullptr, 1.01, u"1 Meter, 1 Zentimeter"}, @@ -2401,6 +2440,307 @@ void NumberFormatterApiTest::unitInflections() { // TODO: look at "↑↑↑" cases: check that inheritance is done right. } +using icu::NounClass; +void NumberFormatterApiTest::unitNounClass() { + IcuTestErrorCode status(*this, "unitNounClass"); + const struct TestCase { + const char *locale; + const char *unitIdentifier; + const NounClass expectedNounClass; + } cases[] = { + {"de", "inch", NounClass::MASCULINE}, + {"de", "yard", NounClass::NEUTER}, + {"de", "meter", NounClass::MASCULINE}, + {"de", "liter", NounClass::MASCULINE}, + {"de", "second", NounClass::FEMININE}, + {"de", "minute", NounClass::FEMININE}, + {"de", "hour", NounClass::FEMININE}, + {"de", "day", NounClass::MASCULINE}, + {"de", "year", NounClass::NEUTER}, + {"de", "gram", NounClass::NEUTER}, + {"de", "watt", NounClass::NEUTER}, + {"de", "bit", NounClass::NEUTER}, + {"de", "byte", NounClass::NEUTER}, + + {"fr", "inch", NounClass::MASCULINE}, + {"fr", "yard", NounClass::MASCULINE}, + {"fr", "meter", NounClass::MASCULINE}, + {"fr", "liter", NounClass::MASCULINE}, + {"fr", "second", NounClass::FEMININE}, + {"fr", "minute", NounClass::FEMININE}, + {"fr", "hour", NounClass::FEMININE}, + {"fr", "day", NounClass::MASCULINE}, + {"fr", "year", NounClass::MASCULINE}, + {"fr", "gram", NounClass::MASCULINE}, + + // grammaticalFeatures deriveCompound "per" rule takes the gender of the + // numerator unit: + {"de", "meter-per-hour", NounClass::MASCULINE}, + {"fr", "meter-per-hour", NounClass::MASCULINE}, + {"af", "meter-per-hour", NounClass::OTHER}, // ungendered language + + // French "times" takes gender from first value, German takes the + // second. Prefix and power does not have impact on gender for these + // languages: + {"de", "square-decimeter-square-second", NounClass::FEMININE}, + {"fr", "square-decimeter-square-second", NounClass::MASCULINE}, + + // TODO(icu-units#149): percent and permille bypasses LongNameHandler + // when unitWidth is not FULL_NAME: + // // Gender of per-second might be that of percent? TODO(icu-units#28) + // {"de", "percent", NounClass::NEUTER}, + // {"fr", "percent", NounClass::MASCULINE}, + + // Built-in units whose simple units lack gender in the CLDR data file + {"de", "kilopascal", NounClass::NEUTER}, + {"fr", "kilopascal", NounClass::MASCULINE}, + // {"de", "pascal", NounClass::OTHER}, + // {"fr", "pascal", NounClass::OTHER}, + + // Built-in units that lack gender in the CLDR data file + // {"de", "revolution", NounClass::OTHER}, + // {"de", "radian", NounClass::OTHER}, + // {"de", "arc-minute", NounClass::OTHER}, + // {"de", "arc-second", NounClass::OTHER}, + {"de", "square-yard", NounClass::NEUTER}, // POWER + {"de", "square-inch", NounClass::MASCULINE}, // POWER + // {"de", "dunam", NounClass::OTHER}, + // {"de", "karat", NounClass::OTHER}, + // {"de", "milligram-ofglucose-per-deciliter", NounClass::OTHER}, // COMPOUND, ofglucose + // {"de", "millimole-per-liter", NounClass::OTHER}, // COMPOUND, mole + // {"de", "permillion", NounClass::OTHER}, + // {"de", "permille", NounClass::OTHER}, + // {"de", "permyriad", NounClass::OTHER}, + // {"de", "mole", NounClass::OTHER}, + {"de", "liter-per-kilometer", NounClass::MASCULINE}, // COMPOUND + {"de", "petabyte", NounClass::NEUTER}, // PREFIX + {"de", "terabit", NounClass::NEUTER}, // PREFIX + // {"de", "century", NounClass::OTHER}, + // {"de", "decade", NounClass::OTHER}, + {"de", "millisecond", NounClass::FEMININE}, // PREFIX + {"de", "microsecond", NounClass::FEMININE}, // PREFIX + {"de", "nanosecond", NounClass::FEMININE}, // PREFIX + // {"de", "ampere", NounClass::OTHER}, + // {"de", "milliampere", NounClass::OTHER}, // PREFIX, ampere + // {"de", "ohm", NounClass::OTHER}, + // {"de", "calorie", NounClass::OTHER}, + // {"de", "kilojoule", NounClass::OTHER}, // PREFIX, joule + // {"de", "joule", NounClass::OTHER}, + {"de", "kilowatt-hour", NounClass::FEMININE}, // COMPOUND + // {"de", "electronvolt", NounClass::OTHER}, + // {"de", "british-thermal-unit", NounClass::OTHER}, + // {"de", "therm-us", NounClass::OTHER}, + // {"de", "pound-force", NounClass::OTHER}, + // {"de", "newton", NounClass::OTHER}, + // {"de", "gigahertz", NounClass::OTHER}, // PREFIX, hertz + // {"de", "megahertz", NounClass::OTHER}, // PREFIX, hertz + // {"de", "kilohertz", NounClass::OTHER}, // PREFIX, hertz + // {"de", "hertz", NounClass::OTHER}, + // {"de", "em", NounClass::OTHER}, + // {"de", "pixel", NounClass::OTHER}, + // {"de", "megapixel", NounClass::OTHER}, + // {"de", "pixel-per-centimeter", NounClass::OTHER}, // COMPOUND, pixel + // {"de", "pixel-per-inch", NounClass::OTHER}, // COMPOUND, pixel + // {"de", "dot-per-centimeter", NounClass::OTHER}, // COMPOUND, dot + // {"de", "dot-per-inch", NounClass::OTHER}, // COMPOUND, dot + // {"de", "dot", NounClass::OTHER}, + // {"de", "earth-radius", NounClass::OTHER}, + {"de", "decimeter", NounClass::MASCULINE}, // PREFIX + {"de", "micrometer", NounClass::MASCULINE}, // PREFIX + {"de", "nanometer", NounClass::MASCULINE}, // PREFIX + // {"de", "light-year", NounClass::OTHER}, + // {"de", "astronomical-unit", NounClass::OTHER}, + // {"de", "furlong", NounClass::OTHER}, + // {"de", "fathom", NounClass::OTHER}, + // {"de", "nautical-mile", NounClass::OTHER}, + // {"de", "mile-scandinavian", NounClass::OTHER}, + // {"de", "point", NounClass::OTHER}, + // {"de", "lux", NounClass::OTHER}, + // {"de", "candela", NounClass::OTHER}, + // {"de", "lumen", NounClass::OTHER}, + // {"de", "metric-ton", NounClass::OTHER}, + // {"de", "microgram", NounClass::NEUTER}, // PREFIX + // {"de", "ton", NounClass::OTHER}, + // {"de", "stone", NounClass::OTHER}, + // {"de", "ounce-troy", NounClass::OTHER}, + // {"de", "carat", NounClass::OTHER}, + {"de", "gigawatt", NounClass::NEUTER}, // PREFIX + {"de", "milliwatt", NounClass::NEUTER}, // PREFIX + // {"de", "horsepower", NounClass::OTHER}, + // {"de", "millimeter-ofhg", NounClass::OTHER}, + // {"de", "pound-force-per-square-inch", NounClass::OTHER}, // COMPOUND, pound-force + // {"de", "inch-ofhg", NounClass::OTHER}, + // {"de", "bar", NounClass::OTHER}, + // {"de", "millibar", NounClass::OTHER}, // PREFIX, bar + // {"de", "atmosphere", NounClass::OTHER}, + // {"de", "pascal", NounClass::OTHER}, // PREFIX, kilopascal? neuter? + // {"de", "hectopascal", NounClass::OTHER}, // PREFIX, pascal, neuter? + // {"de", "megapascal", NounClass::OTHER}, // PREFIX, pascal, neuter? + // {"de", "knot", NounClass::OTHER}, + {"de", "pound-force-foot", NounClass::MASCULINE}, // COMPOUND + {"de", "newton-meter", NounClass::MASCULINE}, // COMPOUND + {"de", "cubic-kilometer", NounClass::MASCULINE}, // POWER + {"de", "cubic-yard", NounClass::NEUTER}, // POWER + {"de", "cubic-inch", NounClass::MASCULINE}, // POWER + {"de", "megaliter", NounClass::MASCULINE}, // PREFIX + {"de", "hectoliter", NounClass::MASCULINE}, // PREFIX + // {"de", "pint-metric", NounClass::OTHER}, + // {"de", "cup-metric", NounClass::OTHER}, + {"de", "acre-foot", NounClass::MASCULINE}, // COMPOUND + // {"de", "bushel", NounClass::OTHER}, + // {"de", "barrel", NounClass::OTHER}, + // Units missing gender in German also misses gender in French: + // {"fr", "revolution", NounClass::OTHER}, + // {"fr", "radian", NounClass::OTHER}, + // {"fr", "arc-minute", NounClass::OTHER}, + // {"fr", "arc-second", NounClass::OTHER}, + {"fr", "square-yard", NounClass::MASCULINE}, // POWER + {"fr", "square-inch", NounClass::MASCULINE}, // POWER + // {"fr", "dunam", NounClass::OTHER}, + // {"fr", "karat", NounClass::OTHER}, + {"fr", "milligram-ofglucose-per-deciliter", NounClass::MASCULINE}, // COMPOUND + // {"fr", "millimole-per-liter", NounClass::OTHER}, // COMPOUND, mole + // {"fr", "permillion", NounClass::OTHER}, + // {"fr", "permille", NounClass::OTHER}, + // {"fr", "permyriad", NounClass::OTHER}, + // {"fr", "mole", NounClass::OTHER}, + {"fr", "liter-per-kilometer", NounClass::MASCULINE}, // COMPOUND + // {"fr", "petabyte", NounClass::OTHER}, // PREFIX + // {"fr", "terabit", NounClass::OTHER}, // PREFIX + // {"fr", "century", NounClass::OTHER}, + // {"fr", "decade", NounClass::OTHER}, + {"fr", "millisecond", NounClass::FEMININE}, // PREFIX + {"fr", "microsecond", NounClass::FEMININE}, // PREFIX + {"fr", "nanosecond", NounClass::FEMININE}, // PREFIX + // {"fr", "ampere", NounClass::OTHER}, + // {"fr", "milliampere", NounClass::OTHER}, // PREFIX, ampere + // {"fr", "ohm", NounClass::OTHER}, + // {"fr", "calorie", NounClass::OTHER}, + // {"fr", "kilojoule", NounClass::OTHER}, // PREFIX, joule + // {"fr", "joule", NounClass::OTHER}, + // {"fr", "kilowatt-hour", NounClass::OTHER}, // COMPOUND + // {"fr", "electronvolt", NounClass::OTHER}, + // {"fr", "british-thermal-unit", NounClass::OTHER}, + // {"fr", "therm-us", NounClass::OTHER}, + // {"fr", "pound-force", NounClass::OTHER}, + // {"fr", "newton", NounClass::OTHER}, + // {"fr", "gigahertz", NounClass::OTHER}, // PREFIX, hertz + // {"fr", "megahertz", NounClass::OTHER}, // PREFIX, hertz + // {"fr", "kilohertz", NounClass::OTHER}, // PREFIX, hertz + // {"fr", "hertz", NounClass::OTHER}, + // {"fr", "em", NounClass::OTHER}, + // {"fr", "pixel", NounClass::OTHER}, + // {"fr", "megapixel", NounClass::OTHER}, + // {"fr", "pixel-per-centimeter", NounClass::OTHER}, // COMPOUND, pixel + // {"fr", "pixel-per-inch", NounClass::OTHER}, // COMPOUND, pixel + // {"fr", "dot-per-centimeter", NounClass::OTHER}, // COMPOUND, dot + // {"fr", "dot-per-inch", NounClass::OTHER}, // COMPOUND, dot + // {"fr", "dot", NounClass::OTHER}, + // {"fr", "earth-radius", NounClass::OTHER}, + {"fr", "decimeter", NounClass::MASCULINE}, // PREFIX + {"fr", "micrometer", NounClass::MASCULINE}, // PREFIX + {"fr", "nanometer", NounClass::MASCULINE}, // PREFIX + // {"fr", "light-year", NounClass::OTHER}, + // {"fr", "astronomical-unit", NounClass::OTHER}, + // {"fr", "furlong", NounClass::OTHER}, + // {"fr", "fathom", NounClass::OTHER}, + // {"fr", "nautical-mile", NounClass::OTHER}, + // {"fr", "mile-scandinavian", NounClass::OTHER}, + // {"fr", "point", NounClass::OTHER}, + // {"fr", "lux", NounClass::OTHER}, + // {"fr", "candela", NounClass::OTHER}, + // {"fr", "lumen", NounClass::OTHER}, + // {"fr", "metric-ton", NounClass::OTHER}, + // {"fr", "microgram", NounClass::MASCULINE}, // PREFIX + // {"fr", "ton", NounClass::OTHER}, + // {"fr", "stone", NounClass::OTHER}, + // {"fr", "ounce-troy", NounClass::OTHER}, + // {"fr", "carat", NounClass::OTHER}, + // {"fr", "gigawatt", NounClass::OTHER}, // PREFIX + // {"fr", "milliwatt", NounClass::OTHER}, + // {"fr", "horsepower", NounClass::OTHER}, + {"fr", "millimeter-ofhg", NounClass::MASCULINE}, + // {"fr", "pound-force-per-square-inch", NounClass::OTHER}, // COMPOUND, pound-force + {"fr", "inch-ofhg", NounClass::MASCULINE}, + // {"fr", "bar", NounClass::OTHER}, + // {"fr", "millibar", NounClass::OTHER}, // PREFIX, bar + // {"fr", "atmosphere", NounClass::OTHER}, + // {"fr", "pascal", NounClass::OTHER}, // PREFIX, kilopascal? + // {"fr", "hectopascal", NounClass::OTHER}, // PREFIX, pascal + // {"fr", "megapascal", NounClass::OTHER}, // PREFIX, pascal + // {"fr", "knot", NounClass::OTHER}, + // {"fr", "pound-force-foot", NounClass::OTHER}, + // {"fr", "newton-meter", NounClass::OTHER}, + {"fr", "cubic-kilometer", NounClass::MASCULINE}, // POWER + {"fr", "cubic-yard", NounClass::MASCULINE}, // POWER + {"fr", "cubic-inch", NounClass::MASCULINE}, // POWER + {"fr", "megaliter", NounClass::MASCULINE}, // PREFIX + {"fr", "hectoliter", NounClass::MASCULINE}, // PREFIX + // {"fr", "pint-metric", NounClass::OTHER}, + // {"fr", "cup-metric", NounClass::OTHER}, + {"fr", "acre-foot", NounClass::FEMININE}, // COMPOUND + // {"fr", "bushel", NounClass::OTHER}, + // {"fr", "barrel", NounClass::OTHER}, + // Some more French units missing gender: + // {"fr", "degree", NounClass::OTHER}, + {"fr", "square-meter", NounClass::MASCULINE}, // POWER + // {"fr", "terabyte", NounClass::OTHER}, // PREFIX, byte + // {"fr", "gigabyte", NounClass::OTHER}, // PREFIX, byte + // {"fr", "gigabit", NounClass::OTHER}, // PREFIX, bit + // {"fr", "megabyte", NounClass::OTHER}, // PREFIX, byte + // {"fr", "megabit", NounClass::OTHER}, // PREFIX, bit + // {"fr", "kilobyte", NounClass::OTHER}, // PREFIX, byte + // {"fr", "kilobit", NounClass::OTHER}, // PREFIX, bit + // {"fr", "byte", NounClass::OTHER}, + // {"fr", "bit", NounClass::OTHER}, + // {"fr", "volt", NounClass::OTHER}, + // {"fr", "watt", NounClass::OTHER}, + {"fr", "cubic-meter", NounClass::MASCULINE}, // POWER + + // gender-lacking builtins within compound units + {"de", "newton-meter-per-second", NounClass::MASCULINE}, + + // TODO(ICU-21494): determine whether list genders behave as follows, + // and implement proper getListGender support (covering more than just + // two genders): + // // gender rule for lists of people: de "neutral", fr "maleTaints" + // {"de", "day-and-hour-and-minute", NounClass::NEUTER}, + // {"de", "hour-and-minute", NounClass::FEMININE}, + // {"fr", "day-and-hour-and-minute", NounClass::MASCULINE}, + // {"fr", "hour-and-minute", NounClass::FEMININE}, + }; + + LocalizedNumberFormatter formatter; + FormattedNumber fn; + for (const TestCase &t : cases) { + formatter = NumberFormatter::with() + .unit(MeasureUnit::forIdentifier(t.unitIdentifier, status)) + .locale(Locale(t.locale)); + fn = formatter.formatDouble(1.1, status); + assertEquals(UnicodeString("Testing NounClass with default width, unit: ") + t.unitIdentifier + + ", locale: " + t.locale, + t.expectedNounClass, fn.getNounClass(status)); + status.assertSuccess(); + + formatter = NumberFormatter::with() + .unit(MeasureUnit::forIdentifier(t.unitIdentifier, status)) + .unitWidth(UNUM_UNIT_WIDTH_FULL_NAME) + .locale(Locale(t.locale)); + fn = formatter.formatDouble(1.1, status); + assertEquals(UnicodeString("Testing NounClass with UNUM_UNIT_WIDTH_FULL_NAME, unit: ") + + t.unitIdentifier + ", locale: " + t.locale, + t.expectedNounClass, fn.getNounClass(status)); + status.assertSuccess(); + } + + // Make sure getNounClass does not return garbage for languages without noun classes. + formatter = NumberFormatter::with().locale(Locale::getEnglish()); + fn = formatter.formatDouble(1.1, status); + status.assertSuccess(); + assertEquals("getNounClasses for a not supported language", NounClass::OTHER, + fn.getNounClass(status)); +} + void NumberFormatterApiTest::unitGender() { IcuTestErrorCode status(*this, "unitGender"); @@ -2975,6 +3315,28 @@ void NumberFormatterApiTest::roundingFraction() { Locale::getEnglish(), 1, "1"); + + assertFormatSingle( + u"Hide If Whole with Rounding Mode A (ICU-21881)", + u".00/w rounding-mode-floor", + u".00/w rounding-mode-floor", + NumberFormatter::with().precision(Precision::fixedFraction(2) + .trailingZeroDisplay(UNUM_TRAILING_ZERO_HIDE_IF_WHOLE)) + .roundingMode(UNUM_ROUND_FLOOR), + Locale::getEnglish(), + 3.009, + "3"); + + assertFormatSingle( + u"Hide If Whole with Rounding Mode B (ICU-21881)", + u".00/w rounding-mode-half-up", + u".00/w rounding-mode-half-up", + NumberFormatter::with().precision(Precision::fixedFraction(2) + .trailingZeroDisplay(UNUM_TRAILING_ZERO_HIDE_IF_WHOLE)) + .roundingMode(UNUM_ROUND_HALFUP), + Locale::getEnglish(), + 3.001, + "3"); } void NumberFormatterApiTest::roundingFigures() { @@ -2997,6 +3359,15 @@ void NumberFormatterApiTest::roundingFigures() { u"-98.8"); assertFormatSingle( + u"Fixed Significant at rounding boundary", + u"@@@", + u"@@@", + NumberFormatter::with().precision(Precision::fixedSignificantDigits(3)), + Locale::getEnglish(), + 9.999, + u"10.0"); + + assertFormatSingle( u"Fixed Significant Zero", u"@@@", u"@@@", @@ -3156,7 +3527,7 @@ void NumberFormatterApiTest::roundingFractionFigures() { assertFormatDescending( u"FracSig withSignificantDigits STRICT", u"precision-integer/@#s", - u"./@#", + u"./@#s", NumberFormatter::with().precision(Precision::maxFraction(0) .withSignificantDigits(1, 2, UNUM_ROUNDING_PRIORITY_STRICT)), Locale::getEnglish(), @@ -3180,7 +3551,7 @@ void NumberFormatterApiTest::roundingFractionFigures() { 1, u"1.00"); - // Trailing zeros are always retained: + // Trailing zeros follow the strategy that was chosen: assertFormatSingle( u"FracSig withSignificantDigits Trailing Zeros STRICT", u".0/@@@s", @@ -3189,7 +3560,7 @@ void NumberFormatterApiTest::roundingFractionFigures() { .withSignificantDigits(3, 3, UNUM_ROUNDING_PRIORITY_STRICT)), Locale::getEnglish(), 1, - u"1.00"); + u"1.0"); assertFormatSingle( u"FracSig withSignificantDigits at rounding boundary", @@ -3199,7 +3570,7 @@ void NumberFormatterApiTest::roundingFractionFigures() { .withSignificantDigits(3, 3, UNUM_ROUNDING_PRIORITY_STRICT)), Locale::getEnglish(), 9.99, - u"10.0"); + u"10"); assertFormatSingle( u"FracSig with Trailing Zero Display", @@ -3397,6 +3768,42 @@ void NumberFormatterApiTest::roundingOther() { u"0.0", u"0.0"); + assertFormatSingle( + u"Large integer increment", + u"precision-increment/24000000000000000000000", + u"precision-increment/24000000000000000000000", + NumberFormatter::with().precision(Precision::incrementExact(24, 21)), + Locale::getEnglish(), + 3.1e22, + u"24,000,000,000,000,000,000,000"); + + assertFormatSingle( + u"Quarter rounding", + u"precision-increment/250", + u"precision-increment/250", + NumberFormatter::with().precision(Precision::incrementExact(250, 0)), + Locale::getEnglish(), + 700, + u"750"); + + assertFormatSingle( + u"ECMA-402 limit", + u"precision-increment/.00000000000000000020", + u"precision-increment/.00000000000000000020", + NumberFormatter::with().precision(Precision::incrementExact(20, -20)), + Locale::getEnglish(), + 333e-20, + u"0.00000000000000000340"); + + assertFormatSingle( + u"ECMA-402 limit with increment = 1", + u"precision-increment/.00000000000000000001", + u"precision-increment/.00000000000000000001", + NumberFormatter::with().precision(Precision::incrementExact(1, -20)), + Locale::getEnglish(), + 4321e-21, + u"0.00000000000000000432"); + assertFormatDescending( u"Currency Standard", u"currency/CZK precision-currency-standard", @@ -3583,6 +3990,67 @@ void NumberFormatterApiTest::roundingIncrementRegressionTest() { assertEquals("ICU-21668", u"5,000", increment); } +void NumberFormatterApiTest::roundingPriorityCoverageTest() { + IcuTestErrorCode status(*this, "roundingPriorityCoverageTest"); + struct TestCase { + double input; + const char16_t* expectedRelaxed0113; + const char16_t* expectedStrict0113; + const char16_t* expectedRelaxed1133; + const char16_t* expectedStrict1133; + } cases[] = { + { 0.9999, u"1", u"1", u"1.00", u"1.0" }, + { 9.9999, u"10", u"10", u"10.0", u"10.0" }, + { 99.999, u"100", u"100", u"100.0", u"100" }, + { 999.99, u"1000", u"1000", u"1000.0", u"1000" }, + + { 0, u"0", u"0", u"0.00", u"0.0" }, + + { 9.876, u"9.88", u"9.9", u"9.88", u"9.9" }, + { 9.001, u"9", u"9", u"9.00", u"9.0" }, + }; + for (const auto& cas : cases) { + auto precisionRelaxed0113 = Precision::minMaxFraction(0, 1) + .withSignificantDigits(1, 3, UNUM_ROUNDING_PRIORITY_RELAXED); + auto precisionStrict0113 = Precision::minMaxFraction(0, 1) + .withSignificantDigits(1, 3, UNUM_ROUNDING_PRIORITY_STRICT); + auto precisionRelaxed1133 = Precision::minMaxFraction(1, 1) + .withSignificantDigits(3, 3, UNUM_ROUNDING_PRIORITY_RELAXED); + auto precisionStrict1133 = Precision::minMaxFraction(1, 1) + .withSignificantDigits(3, 3, UNUM_ROUNDING_PRIORITY_STRICT); + + auto messageBase = DoubleToUnicodeString(cas.input); + + auto check = [&]( + const char16_t* name, + const UnicodeString& expected, + const Precision& precision + ) { + assertEquals( + messageBase + name, + expected, + NumberFormatter::withLocale(Locale::getEnglish()) + .precision(precision) + .grouping(UNUM_GROUPING_OFF) + .formatDouble(cas.input, status) + .toString(status) + ); + }; + + check(u" Relaxed 0113", cas.expectedRelaxed0113, precisionRelaxed0113); + if (status.errIfFailureAndReset()) continue; + + check(u" Strict 0113", cas.expectedStrict0113, precisionStrict0113); + if (status.errIfFailureAndReset()) continue; + + check(u" Relaxed 1133", cas.expectedRelaxed1133, precisionRelaxed1133); + if (status.errIfFailureAndReset()) continue; + + check(u" Strict 1133", cas.expectedStrict1133, precisionStrict1133); + if (status.errIfFailureAndReset()) continue; + } +} + void NumberFormatterApiTest::grouping() { assertFormatDescendingBig( u"Western Grouping", @@ -5707,6 +6175,37 @@ void NumberFormatterApiTest::microPropsInternals() { assertEquals("Copy Assigned capacity", 4, copyAssigned.mixedMeasures.getCapacity()); } +void NumberFormatterApiTest::formatUnitsAliases() { + IcuTestErrorCode status(*this, "formatUnitsAliases"); + + struct TestCase { + const MeasureUnit measureUnit; + const UnicodeString expectedFormat; + } testCases[]{ + // Aliases + {MeasureUnit::getMilligramPerDeciliter(), u"2 milligrams per deciliter"}, + {MeasureUnit::getLiterPer100Kilometers(), u"2 liters per 100 kilometers"}, + {MeasureUnit::getPartPerMillion(), u"2 parts per million"}, + {MeasureUnit::getMillimeterOfMercury(), u"2 millimeters of mercury"}, + + // Replacements + {MeasureUnit::getMilligramOfglucosePerDeciliter(), u"2 milligrams per deciliter"}, + {MeasureUnit::forIdentifier("millimeter-ofhg", status), u"2 millimeters of mercury"}, + {MeasureUnit::forIdentifier("liter-per-100-kilometer", status), u"2 liters per 100 kilometers"}, + {MeasureUnit::forIdentifier("permillion", status), u"2 parts per million"}, + }; + + for (const auto &testCase : testCases) { + UnicodeString actualFormat = NumberFormatter::withLocale(icu::Locale::getEnglish()) + .unit(testCase.measureUnit) + .unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME) + .formatDouble(2.0, status) + .toString(status); + + assertEquals("test unit aliases", testCase.expectedFormat, actualFormat); + } +} + /* For skeleton comparisons: this checks the toSkeleton output for `f` and for * `conciseSkeleton` against the normalized version of `uskeleton` - this does * not round-trip uskeleton itself. @@ -5882,7 +6381,7 @@ NumberFormatterApiTest::assertFormatSingle( // Only compare normalized skeletons: the tests need not provide the normalized forms. // Use the normalized form to construct the testing formatter to ensure no loss of info. UnicodeString normalized = NumberFormatter::forSkeleton(skeleton, status).toSkeleton(status); - assertEquals(message + ": Skeleton:", normalized, f.toSkeleton(status)); + assertEquals(message + ": Skeleton", normalized, f.toSkeleton(status)); LocalizedNumberFormatter l3 = NumberFormatter::forSkeleton(normalized, status).locale(locale); UnicodeString actual3 = l3.formatDouble(input, status).toString(status); assertEquals(message + ": Skeleton Path: '" + normalized + "': " + input, expected, actual3); diff --git a/Build/source/libs/icu/icu-src/source/test/intltest/numbertest_decimalquantity.cpp b/Build/source/libs/icu/icu-src/source/test/intltest/numbertest_decimalquantity.cpp index 7403dda7e75..87cd7707b55 100644 --- a/Build/source/libs/icu/icu-src/source/test/intltest/numbertest_decimalquantity.cpp +++ b/Build/source/libs/icu/icu-src/source/test/intltest/numbertest_decimalquantity.cpp @@ -33,6 +33,7 @@ void DecimalQuantityTest::runIndexedTest(int32_t index, UBool exec, const char * TESTCASE_AUTO(testNickelRounding); TESTCASE_AUTO(testScientificAndCompactSuppressedExponent); TESTCASE_AUTO(testSuppressedExponentUnchangedByInitialScaling); + TESTCASE_AUTO(testDecimalQuantityParseFormatRoundTrip); TESTCASE_AUTO_END; } @@ -101,8 +102,11 @@ void DecimalQuantityTest::testDecimalQuantityBehaviorStandalone() { assertToStringAndHealth(fq, u"<DecimalQuantity 2:-3 long 987654321E-6>"); fq.roundToInfinity(); assertToStringAndHealth(fq, u"<DecimalQuantity 2:-3 long 987654321E-6>"); - fq.roundToIncrement(0.005, RoundingMode::UNUM_ROUND_HALFEVEN, status); + fq.roundToIncrement(4, -3, RoundingMode::UNUM_ROUND_HALFEVEN, status); assertSuccess("Rounding to increment", status); + assertToStringAndHealth(fq, u"<DecimalQuantity 2:-3 long 987656E-3>"); + fq.roundToNickel(-3, RoundingMode::UNUM_ROUND_HALFEVEN, status); + assertSuccess("Rounding to nickel", status); assertToStringAndHealth(fq, u"<DecimalQuantity 2:-3 long 987655E-3>"); fq.roundToMagnitude(-2, RoundingMode::UNUM_ROUND_HALFEVEN, status); assertSuccess("Rounding to magnitude", status); @@ -317,7 +321,7 @@ void DecimalQuantityTest::testUseApproximateDoubleWhenAble() { {1.235, 3, RoundingMode::UNUM_ROUND_CEILING, true}}; UErrorCode status = U_ZERO_ERROR; - for (TestCase cas : cases) { + for (const TestCase& cas : cases) { DecimalQuantity fq; fq.setToDouble(cas.d); assertTrue("Should be using approximate double", !fq.isExplicitExactDouble()); @@ -623,7 +627,7 @@ void DecimalQuantityTest::testScientificAndCompactSuppressedExponent() { // test the actual computed values of the plural operands double expectedNOperand = cas.expectedDouble; - double expectedIOperand = cas.expectedLong; + double expectedIOperand = static_cast<double>(cas.expectedLong); double expectedEOperand = cas.expectedSuppressedScientificExponent; double expectedCOperand = cas.expectedSuppressedCompactExponent; double actualNOperand = dq.getPluralOperand(PLURAL_OPERAND_N); @@ -721,4 +725,52 @@ void DecimalQuantityTest::testSuppressedExponentUnchangedByInitialScaling() { } } + +void DecimalQuantityTest::testDecimalQuantityParseFormatRoundTrip() { + IcuTestErrorCode status(*this, "testDecimalQuantityParseFormatRoundTrip"); + + struct TestCase { + UnicodeString numberString; + } cases[] = { + // number string + { u"0" }, + { u"1" }, + { u"1.0" }, + { u"1.00" }, + { u"1.1" }, + { u"1.10" }, + { u"-1.10" }, + { u"0.0" }, + { u"1c5" }, + { u"1.0c5" }, + { u"1.1c5" }, + { u"1.10c5" }, + { u"0.00" }, + { u"0.1" }, + { u"1c-1" }, + { u"1.0c-1" } + }; + + for (const auto& cas : cases) { + UnicodeString numberString = cas.numberString; + + DecimalQuantity dq = DecimalQuantity::fromExponentString(numberString, status); + UnicodeString roundTrip = dq.toExponentString(); + + assertEquals("DecimalQuantity format(parse(s)) should equal original s", numberString, roundTrip); + } + + DecimalQuantity dq = DecimalQuantity::fromExponentString(u"1c0", status); + assertEquals("Zero ignored for visible exponent", + u"1", + dq.toExponentString()); + + dq.clear(); + dq = DecimalQuantity::fromExponentString(u"1.0c0", status); + assertEquals("Zero ignored for visible exponent", + u"1.0", + dq.toExponentString()); + +} + #endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/Build/source/libs/icu/icu-src/source/test/intltest/numbertest_range.cpp b/Build/source/libs/icu/icu-src/source/test/intltest/numbertest_range.cpp index 08e74df8f52..a47c675c974 100644 --- a/Build/source/libs/icu/icu-src/source/test/intltest/numbertest_range.cpp +++ b/Build/source/libs/icu/icu-src/source/test/intltest/numbertest_range.cpp @@ -811,6 +811,28 @@ void NumberRangeFormatterTest::testFieldPositions() { expectedFieldPositions, UPRV_LENGTHOF(expectedFieldPositions)); } + + { + const char16_t* message = u"Field position with approximately sign"; + const char16_t* expectedString = u"~-100"; + FormattedNumberRange result = assertFormattedRangeEquals( + message, + NumberRangeFormatter::withLocale("en-us"), + -100, + -100, + expectedString); + static const UFieldPositionWithCategory expectedFieldPositions[] = { + // category, field, begin index, end index + {UFIELD_CATEGORY_NUMBER, UNUM_APPROXIMATELY_SIGN_FIELD, 0, 1}, + {UFIELD_CATEGORY_NUMBER, UNUM_SIGN_FIELD, 1, 2}, + {UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD, 2, 5}}; + checkMixedFormattedValue( + message, + result, + expectedString, + expectedFieldPositions, + UPRV_LENGTHOF(expectedFieldPositions)); + } } void NumberRangeFormatterTest::testCopyMove() { diff --git a/Build/source/libs/icu/icu-src/source/test/intltest/numfmtst.cpp b/Build/source/libs/icu/icu-src/source/test/intltest/numfmtst.cpp index 011cc32dd34..7f271cb3f66 100644 --- a/Build/source/libs/icu/icu-src/source/test/intltest/numfmtst.cpp +++ b/Build/source/libs/icu/icu-src/source/test/intltest/numfmtst.cpp @@ -3357,6 +3357,7 @@ void NumberFormatTest::TestRoundingPattern() { void NumberFormatTest::checkRounding(DecimalFormat* df, double base, int iterations, double increment) { df->setRoundingIncrement(increment); + assertEquals("Rounding increment round-trip", increment, df->getRoundingIncrement()); double lastParsed=INT32_MIN; //Intger.MIN_VALUE for (int i=-iterations; i<=iterations;i++) { double iValue=base+(increment*(i*0.1)); @@ -4889,9 +4890,9 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "Peruvian soles1.00", "Peruvian sol (1863\\u20131965)1.00", "Peruvian soles (1863\\u20131965)1.00", - "Philippine Piso1.00", - "Philippine piso1.00", - "Philippine pisos1.00", + "Philippine Peso1.00", + "Philippine peso1.00", + "Philippine pesos1.00", "Platinum1.00", "Platinum1.00", "Polish Zloty (1950\\u20131995)1.00", @@ -5826,9 +5827,9 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "1.00 Peruvian soles random", "1.00 Peruvian sol (1863\\u20131965) random", "1.00 Peruvian soles (1863\\u20131965) random", - "1.00 Philippine Piso random", - "1.00 Philippine piso random", - "1.00 Philippine pisos random", + "1.00 Philippine Peso random", + "1.00 Philippine peso random", + "1.00 Philippine pesos random", "1.00 Platinum random", "1.00 Platinum random", "1.00 Polish Zloty (1950\\u20131995) random", diff --git a/Build/source/libs/icu/icu-src/source/test/intltest/plurults.cpp b/Build/source/libs/icu/icu-src/source/test/intltest/plurults.cpp index 9131d370317..54cc77a0c9e 100644 --- a/Build/source/libs/icu/icu-src/source/test/intltest/plurults.cpp +++ b/Build/source/libs/icu/icu-src/source/test/intltest/plurults.cpp @@ -919,7 +919,7 @@ PluralRulesTest::testDoubleValue() { const int64_t inputNum = cas.inputNum; const double expVal = cas.expVal; - FixedDecimal fd(inputNum); + FixedDecimal fd(static_cast<double>(inputNum)); UnicodeString message(u"FixedDecimal::doubleValue() for" + Int64ToUnicodeString(inputNum)); assertEquals(message, expVal, fd.doubleValue()); } @@ -963,7 +963,7 @@ PluralRulesTest::testLongValue() { const int64_t inputNum = cas.inputNum; const int64_t expVal = cas.expVal; - FixedDecimal fd(inputNum); + FixedDecimal fd(static_cast<double>(inputNum)); UnicodeString message(u"FixedDecimal::longValue() for" + Int64ToUnicodeString(inputNum)); assertEquals(message, expVal, fd.longValue()); } @@ -982,7 +982,7 @@ PluralRulesTest::testLongValue() { const double inputNum = cas.inputNum; const int64_t expVal = cas.expVal; - FixedDecimal fd(inputNum); + FixedDecimal fd(static_cast<double>(inputNum)); UnicodeString message(u"FixedDecimal::longValue() for" + DoubleToUnicodeString(inputNum)); assertEquals(message, expVal, fd.longValue()); } diff --git a/Build/source/libs/icu/icu-src/source/test/intltest/rbbitst.cpp b/Build/source/libs/icu/icu-src/source/test/intltest/rbbitst.cpp index 73d4393843b..69db5db018c 100644 --- a/Build/source/libs/icu/icu-src/source/test/intltest/rbbitst.cpp +++ b/Build/source/libs/icu/icu-src/source/test/intltest/rbbitst.cpp @@ -149,6 +149,10 @@ void RBBITest::runIndexedTest( int32_t index, UBool exec, const char* &name, cha TESTCASE_AUTO(TestTraceCreateLineNormal); TESTCASE_AUTO(TestTraceCreateLineLoose); TESTCASE_AUTO(TestTraceCreateLineStrict); + TESTCASE_AUTO(TestTraceCreateLineNormalPhrase); + TESTCASE_AUTO(TestTraceCreateLineLoosePhrase); + TESTCASE_AUTO(TestTraceCreateLineStrictPhrase); + TESTCASE_AUTO(TestTraceCreateLinePhrase); TESTCASE_AUTO(TestTraceCreateBreakEngine); #endif @@ -5144,7 +5148,7 @@ void RBBITest::TestTraceCreateLine(void) { LocalPointer<BreakIterator> brkitr( BreakIterator::createLineInstance("zh-CN", status)); status.errIfFailureAndReset(); - assertTestTraceResult(UTRACE_UBRK_CREATE_LINE, ""); + assertTestTraceResult(UTRACE_UBRK_CREATE_LINE, "line"); } void RBBITest::TestTraceCreateLineStrict(void) { @@ -5153,7 +5157,7 @@ void RBBITest::TestTraceCreateLineStrict(void) { LocalPointer<BreakIterator> brkitr( BreakIterator::createLineInstance("zh-CN-u-lb-strict", status)); status.errIfFailureAndReset(); - assertTestTraceResult(UTRACE_UBRK_CREATE_LINE, "strict"); + assertTestTraceResult(UTRACE_UBRK_CREATE_LINE, "line_strict"); } void RBBITest::TestTraceCreateLineNormal(void) { @@ -5162,7 +5166,7 @@ void RBBITest::TestTraceCreateLineNormal(void) { LocalPointer<BreakIterator> brkitr( BreakIterator::createLineInstance("zh-CN-u-lb-normal", status)); status.errIfFailureAndReset(); - assertTestTraceResult(UTRACE_UBRK_CREATE_LINE, "normal"); + assertTestTraceResult(UTRACE_UBRK_CREATE_LINE, "line_normal"); } void RBBITest::TestTraceCreateLineLoose(void) { @@ -5171,7 +5175,43 @@ void RBBITest::TestTraceCreateLineLoose(void) { LocalPointer<BreakIterator> brkitr( BreakIterator::createLineInstance("zh-CN-u-lb-loose", status)); status.errIfFailureAndReset(); - assertTestTraceResult(UTRACE_UBRK_CREATE_LINE, "loose"); + assertTestTraceResult(UTRACE_UBRK_CREATE_LINE, "line_loose"); +} + +void RBBITest::TestTraceCreateLineLoosePhrase(void) { + SetupTestTrace(); + IcuTestErrorCode status(*this, "TestTraceCreateLineLoosePhrase"); + LocalPointer<BreakIterator> brkitr( + BreakIterator::createLineInstance("ja-u-lb-loose-lw-phrase", status)); + status.errIfFailureAndReset(); + assertTestTraceResult(UTRACE_UBRK_CREATE_LINE, "line_loose_phrase"); +} + +void RBBITest::TestTraceCreateLineNormalPhrase(void) { + SetupTestTrace(); + IcuTestErrorCode status(*this, "TestTraceCreateLineNormalPhrase"); + LocalPointer<BreakIterator> brkitr( + BreakIterator::createLineInstance("ja-u-lb-normal-lw-phrase", status)); + status.errIfFailureAndReset(); + assertTestTraceResult(UTRACE_UBRK_CREATE_LINE, "line_normal_phrase"); +} + +void RBBITest::TestTraceCreateLineStrictPhrase(void) { + SetupTestTrace(); + IcuTestErrorCode status(*this, "TestTraceCreateLineStrictPhrase"); + LocalPointer<BreakIterator> brkitr( + BreakIterator::createLineInstance("ja-u-lb-strict-lw-phrase", status)); + status.errIfFailureAndReset(); + assertTestTraceResult(UTRACE_UBRK_CREATE_LINE, "line_strict_phrase"); +} + +void RBBITest::TestTraceCreateLinePhrase(void) { + SetupTestTrace(); + IcuTestErrorCode status(*this, "TestTraceCreateLinePhrase"); + LocalPointer<BreakIterator> brkitr( + BreakIterator::createLineInstance("ja-u-lw-phrase", status)); + status.errIfFailureAndReset(); + assertTestTraceResult(UTRACE_UBRK_CREATE_LINE, "line_phrase"); } void RBBITest::TestTraceCreateBreakEngine(void) { diff --git a/Build/source/libs/icu/icu-src/source/test/intltest/rbbitst.h b/Build/source/libs/icu/icu-src/source/test/intltest/rbbitst.h index acb3e82bbec..d5d52119bc0 100644 --- a/Build/source/libs/icu/icu-src/source/test/intltest/rbbitst.h +++ b/Build/source/libs/icu/icu-src/source/test/intltest/rbbitst.h @@ -105,6 +105,10 @@ public: void TestTraceCreateLineNormal(); void TestTraceCreateLineStrict(); void TestTraceCreateLineLoose(); + void TestTraceCreateLineNormalPhrase(); + void TestTraceCreateLineLoosePhrase(); + void TestTraceCreateLineStrictPhrase(); + void TestTraceCreateLinePhrase(); void TestTraceCreateBreakEngine(); #endif diff --git a/Build/source/libs/icu/icu-src/source/test/intltest/strcase.cpp b/Build/source/libs/icu/icu-src/source/test/intltest/strcase.cpp index 006bcd64ed3..b5eff9f0af8 100644 --- a/Build/source/libs/icu/icu-src/source/test/intltest/strcase.cpp +++ b/Build/source/libs/icu/icu-src/source/test/intltest/strcase.cpp @@ -51,6 +51,7 @@ public: void *iter, const char *localeID, uint32_t options); void TestCasing(); void TestTitleOptions(); + void TestDutchTitle(); void TestFullCaseFoldingIterator(); void TestGreekUpper(); void TestArmenian(); @@ -95,6 +96,7 @@ StringCaseTest::runIndexedTest(int32_t index, UBool exec, const char *&name, cha #if !UCONFIG_NO_BREAK_ITERATION && !UCONFIG_NO_FILE_IO && !UCONFIG_NO_LEGACY_CONVERSION TESTCASE_AUTO(TestCasing); TESTCASE_AUTO(TestTitleOptions); + TESTCASE_AUTO(TestDutchTitle); #endif TESTCASE_AUTO(TestFullCaseFoldingIterator); TESTCASE_AUTO(TestGreekUpper); @@ -451,6 +453,7 @@ StringCaseTest::TestCasingImpl(const UnicodeString &input, } if(result!=output) { dataerrln("error: UnicodeString.%s() got a wrong result for a test case from casing.res", name); + dataerrln(UnicodeString("input = [") + input + "], expected = [" + output + "], actual = [" + result + "]"); } #if !UCONFIG_NO_BREAK_ITERATION if(whichCase==TEST_TITLE && options==0) { @@ -667,6 +670,106 @@ StringCaseTest::TestTitleOptions() { #endif } +#if !UCONFIG_NO_BREAK_ITERATION +void StringCaseTest::TestDutchTitle() { + IcuTestErrorCode errorCode(*this, "TestDutchTitle"); + + Locale nl("nl"); // Dutch + LocalPointer<BreakIterator> iter( + BreakIterator::createWordInstance(nl, errorCode)); + + // Dutch titlecase check in English + TestCasingImpl( + u"ijssel igloo IJMUIDEN", + u"Ijssel Igloo Ijmuiden", + TEST_TITLE, + nullptr, + "en", + 0); + + // Dutch titlecase check in Dutch + TestCasingImpl( + u"ijssel igloo IJMUIDEN", + u"IJssel Igloo IJmuiden", + TEST_TITLE, + nullptr, + "nl", + 0); + + // Dutch titlecase check in Dutch with nolowercase option + if (U_SUCCESS(errorCode)) { + iter->setText(u"ijssel igloo IjMUIdEN iPoD ijenough"); + TestCasingImpl( + u"ijssel igloo IjMUIdEN iPoD ijenough", + u"IJssel Igloo IJMUIdEN IPoD IJenough", + TEST_TITLE, + nullptr, + "nl", + U_TITLECASE_NO_LOWERCASE); + } + + errorCode.reset(); + + // Accented IJ testing + + struct dutchTitleTestCase { + const UnicodeString input; + const UnicodeString expectedFull; + const UnicodeString expectedOnlyChanged; + } dutchTitleTestCases[] = { + // input, expectedFull, expectedOnlyChanged + {u"ij", u"IJ", u"IJ"}, + {u"IJ", u"IJ", u""}, + {u"íj́", u"ÍJ́", u"ÍJ"}, + {u"ÍJ́", u"ÍJ́", u""}, + {u"íJ́", u"ÍJ́", u"Í"}, + {u"Ij́", u"Ij́", u""}, + {u"ij́", u"Ij́", u"I"}, + {u"ïj́", u"Ïj́", u"Ï"}, + {u"íj\u0308", u"Íj\u0308", u"Í"}, + {u"íj́\U0001D16E", u"Íj́\U0001D16E", u"Í"}, + {u"íj\u1ABE", u"Íj\u1ABE", u"Í"}, + + {u"ijabc", u"IJabc", u"IJ"}, + {u"IJabc", u"IJabc", u""}, + {u"íj́abc", u"ÍJ́abc", u"ÍJ"}, + {u"ÍJ́abc", u"ÍJ́abc", u""}, + {u"íJ́abc", u"ÍJ́abc", u"Í"}, + {u"Ij́abc", u"Ij́abc", u""}, + {u"ij́abc", u"Ij́abc", u"I"}, + {u"ïj́abc", u"Ïj́abc", u"Ï"}, + {u"íjabc\u0308", u"Íjabc\u0308", u"Í"}, + {u"íj́abc\U0001D16E", u"ÍJ́abc\U0001D16E", u"ÍJ"}, + {u"íjabc\u1ABE", u"Íjabc\u1ABE", u"Í"}, + + // Bug ICU-21919 + {u"Í", u"Í", u""}, + }; + + for (const auto& cas : dutchTitleTestCases) { + const UnicodeString &input = cas.input; + const UnicodeString &expectedFull = cas.expectedFull; + const UnicodeString &expectedOnlyChanged = cas.expectedOnlyChanged; + + for (const auto& isOnlyChanged : {true, false}) { + uint32_t testOptions = U_TITLECASE_NO_LOWERCASE + | (isOnlyChanged ? U_OMIT_UNCHANGED_TEXT : 0); + + const UnicodeString &expected = isOnlyChanged ? expectedOnlyChanged : expectedFull; + + TestCasingImpl( + input, + expected, + TEST_TITLE, + nullptr, + "nl", + testOptions + ); + } + } +} +#endif + void StringCaseTest::TestFullCaseFoldingIterator() { UnicodeString ffi=UNICODE_STRING_SIMPLE("ffi"); diff --git a/Build/source/libs/icu/icu-src/source/test/intltest/tmsgfmt.cpp b/Build/source/libs/icu/icu-src/source/test/intltest/tmsgfmt.cpp index e55aa8fbe37..66f49822217 100644 --- a/Build/source/libs/icu/icu-src/source/test/intltest/tmsgfmt.cpp +++ b/Build/source/libs/icu/icu-src/source/test/intltest/tmsgfmt.cpp @@ -2051,7 +2051,7 @@ void TestMessageFormat::TestMessageFormatDateSkeleton() { UDate date = LocaleTest::date(2021-1900, UCAL_NOVEMBER, 23, 16, 42, 55); doTheRealDateTimeSkeletonTesting(date, u"{0,date,::MMMMd}", "en", u"November 23", status); - doTheRealDateTimeSkeletonTesting(date, u"{0,date,::yMMMMdjm}", "en", u"November 23, 2021, 4:42 PM", status); + doTheRealDateTimeSkeletonTesting(date, u"{0,date,::yMMMMdjm}", "en", u"November 23, 2021 at 4:42 PM", status); doTheRealDateTimeSkeletonTesting(date, u"{0,date, :: yMMMMd }", "en", u"November 23, 2021", status); doTheRealDateTimeSkeletonTesting(date, u"{0,date,::yMMMMd}", "fr", u"23 novembre 2021", status); doTheRealDateTimeSkeletonTesting(date, u"Expiration: {0,date,::yMMM}!", "en", u"Expiration: Nov 2021!", status); @@ -2065,7 +2065,7 @@ void TestMessageFormat::TestMessageFormatTimeSkeleton() { UDate date = LocaleTest::date(2021-1900, UCAL_NOVEMBER, 23, 16, 42, 55); doTheRealDateTimeSkeletonTesting(date, u"{0,time,::MMMMd}", "en", u"November 23", status); - doTheRealDateTimeSkeletonTesting(date, u"{0,time,::yMMMMdjm}", "en", u"November 23, 2021, 4:42 PM", status); + doTheRealDateTimeSkeletonTesting(date, u"{0,time,::yMMMMdjm}", "en", u"November 23, 2021 at 4:42 PM", status); doTheRealDateTimeSkeletonTesting(date, u"{0,time, :: yMMMMd }", "en", u"November 23, 2021", status); doTheRealDateTimeSkeletonTesting(date, u"{0,time,::yMMMMd}", "fr", u"23 novembre 2021", status); doTheRealDateTimeSkeletonTesting(date, u"Expiration: {0,time,::yMMM}!", "en", u"Expiration: Nov 2021!", status); diff --git a/Build/source/libs/icu/icu-src/source/test/intltest/transtst.cpp b/Build/source/libs/icu/icu-src/source/test/intltest/transtst.cpp index 8a81b5b3377..aaf283f7a4e 100644 --- a/Build/source/libs/icu/icu-src/source/test/intltest/transtst.cpp +++ b/Build/source/libs/icu/icu-src/source/test/intltest/transtst.cpp @@ -3639,7 +3639,7 @@ void TransliteratorTest::TestIncrementalProgress(void) { Transliterator *t = Transliterator::createInstance(id, UTRANS_FORWARD, err, status); if (U_FAILURE(status)) { - dataerrln((UnicodeString)"FAIL: Could not create " + id); + dataerrln((UnicodeString)"FAIL: Could not create " + id + ", status " + u_errorName(status)); delete t; continue; } @@ -3654,19 +3654,38 @@ void TransliteratorTest::TestIncrementalProgress(void) { // 1. Devanagari-Arabic // 2. Any-*/BGN // 2a. Any-*/BGN_1981 - // 3. Any-*/UNGEGN - // 4. Any-*/MNS - // If UCONFIG_NO_BREAK_ITERATION is on, Latin-Thai is also not expected to work. + // 3. Any-*/MNS + // + // 4. If UCONFIG_NO_BREAK_ITERATION is on, Latin-Thai is also not expected to work. + // + // The following are direction="both" transforms with variants, inverting the Any-Xxxx/Variant for + // any of these does not work; see ICU-21911 (not sure whether this is intentional or an ICU bug). + // Unfortunately we do not easily have the info at this point as to whether the original transform + // had direction="both" specified. + // 5. Any-*/UNGEGN + // 6. Any-Ethiopic/* + // 7. Any-Braille/* + // 8. Any-*/Gurage_2013 + // 9. Any-*/Gutgarts + // 10. Any-*/Tekie_Alibekit + // 11. Any-*/Xaleget + // if ( id.compare((UnicodeString)"Devanagari-Arabic/") != 0 && !(id.startsWith((UnicodeString)"Any-") && - (id.endsWith((UnicodeString)"/BGN") || id.endsWith((UnicodeString)"/BGN_1981") || id.endsWith((UnicodeString)"/UNGEGN") || id.endsWith((UnicodeString)"/MNS")) + (id.endsWith((UnicodeString)"/BGN") || id.endsWith((UnicodeString)"/BGN_1981") || id.endsWith((UnicodeString)"/MNS")) ) #if UCONFIG_NO_BREAK_ITERATION && id.compare((UnicodeString)"Latin-Thai/") != 0 #endif + && !(logKnownIssue("21911", "ICU4C cannot create inverse of Any-Xxxx/Variant transform created from both-direction transform") && + id.startsWith((UnicodeString)"Any-") && + (id.endsWith((UnicodeString)"/UNGEGN") || id.startsWith((UnicodeString)"Any-Ethiopic/") || id.startsWith((UnicodeString)"Any-Braille/") || + id.endsWith((UnicodeString)"/Gurage_2013") || id.endsWith((UnicodeString)"/Gutgarts") || id.endsWith((UnicodeString)"/Tekie_Alibekit") || + id.endsWith((UnicodeString)"/Xaleget")) + ) ) { - errln((UnicodeString)"FAIL: Could not create inverse of " + id); + errln((UnicodeString)"FAIL: Could not create inverse of " + id + ", status " + u_errorName(status)); } delete t; delete inv; diff --git a/Build/source/libs/icu/icu-src/source/test/intltest/tztest.cpp b/Build/source/libs/icu/icu-src/source/test/intltest/tztest.cpp index 0d58bab197d..5ae9ae7175c 100644 --- a/Build/source/libs/icu/icu-src/source/test/intltest/tztest.cpp +++ b/Build/source/libs/icu/icu-src/source/test/intltest/tztest.cpp @@ -906,7 +906,7 @@ void TimeZoneTest::TestShortZoneIDs() {"AET", 600, TRUE}, // ICU Link - Australia/Sydney {"SST", 660, FALSE}, // ICU Link - Pacific/Guadalcanal {"NST", 720, TRUE}, // ICU Link - Pacific/Auckland - {"MIT", 780, TRUE}, // ICU Link - Pacific/Apia + {"MIT", 780, FALSE}, // ICU Link - Pacific/Apia {"Etc/Unknown", 0, FALSE}, // CLDR @@ -2036,12 +2036,20 @@ void TimeZoneTest::TestCanonicalIDAPI() { void TimeZoneTest::TestCanonicalID() { - // Some canonical IDs in CLDR are defined as "Link" - // in Olson tzdata. + // Olson (IANA) tzdata used to have very few "Link"s long time ago. + // This test case was written when most of CLDR canonical time zones are + // defined as independent "Zone" in the TZ database. + // Since then, the TZ maintainer found some historic rules in mid 20th century + // were not really reliable, and many zones are now sharing rules. + // As of TZ database release 2022a, there are quite a lot of zones defined + // by "Link" to another zone, so the exception table below becomes really + // big. It might be still useful to make sure CLDR zone aliases are consistent + // with zone rules. static const struct { - const char *alias; - const char *zone; + const char *alias; // link-from + const char *zone; // link-to (A zone ID with "Zone" rule) } excluded1[] = { + {"Africa/Accra", "Africa/Abidjan"}, {"Africa/Addis_Ababa", "Africa/Nairobi"}, {"Africa/Asmera", "Africa/Nairobi"}, {"Africa/Bamako", "Africa/Abidjan"}, @@ -2076,35 +2084,43 @@ void TimeZoneTest::TestCanonicalID() { {"Africa/Ouagadougou", "Africa/Abidjan"}, {"Africa/Porto-Novo", "Africa/Lagos"}, {"Africa/Sao_Tome", "Africa/Abidjan"}, - {"America/Antigua", "America/Port_of_Spain"}, - {"America/Anguilla", "America/Port_of_Spain"}, + {"America/Antigua", "America/Puerto_Rico"}, + {"America/Anguilla", "America/Puerto_Rico"}, + {"America/Aruba", "America/Puerto_Rico"}, + {"America/Atikokan", "America/Panama"}, + {"America/Blanc-Sablon", "America/Puerto_Rico"}, {"America/Cayman", "America/Panama"}, {"America/Coral_Harbour", "America/Panama"}, - {"America/Curacao", "America/Aruba"}, - {"America/Dominica", "America/Port_of_Spain"}, - {"America/Grenada", "America/Port_of_Spain"}, - {"America/Guadeloupe", "America/Port_of_Spain"}, - {"America/Kralendijk", "America/Aruba"}, - {"America/Lower_Princes", "America/Aruba"}, - {"America/Marigot", "America/Port_of_Spain"}, - {"America/Montserrat", "America/Port_of_Spain"}, + {"America/Creston", "America/Phoenix"}, + {"America/Curacao", "America/Puerto_Rico"}, + {"America/Dominica", "America/Puerto_Rico"}, + {"America/Grenada", "America/Puerto_Rico"}, + {"America/Guadeloupe", "America/Puerto_Rico"}, + {"America/Kralendijk", "America/Puerto_Rico"}, + {"America/Lower_Princes", "America/Puerto_Rico"}, + {"America/Marigot", "America/Puerto_Rico"}, + {"America/Montreal", "America/Toronto"}, + {"America/Montserrat", "America/Puerto_Rico"}, + {"America/Nassau", "America/Toronto"}, + {"America/Port_of_Spain", "America/Puerto_Rico"}, {"America/Santa_Isabel", "America/Tijuana"}, {"America/Shiprock", "America/Denver"}, - {"America/St_Barthelemy", "America/Port_of_Spain"}, - {"America/St_Kitts", "America/Port_of_Spain"}, - {"America/St_Lucia", "America/Port_of_Spain"}, - {"America/St_Thomas", "America/Port_of_Spain"}, - {"America/St_Vincent", "America/Port_of_Spain"}, - {"America/Toronto", "America/Montreal"}, - {"America/Tortola", "America/Port_of_Spain"}, + {"America/St_Barthelemy", "America/Puerto_Rico"}, + {"America/St_Kitts", "America/Puerto_Rico"}, + {"America/St_Lucia", "America/Puerto_Rico"}, + {"America/St_Thomas", "America/Puerto_Rico"}, + {"America/St_Vincent", "America/Puerto_Rico"}, + {"America/Tortola", "America/Puerto_Rico"}, {"America/Virgin", "America/Puerto_Rico"}, + {"Antarctica/DumontDUrville", "Pacific/Port_Moresby"}, {"Antarctica/South_Pole", "Antarctica/McMurdo"}, + {"Antarctica/Syowa", "Asia/Riyadh"}, {"Arctic/Longyearbyen", "Europe/Oslo"}, - {"Asia/Kuwait", "Asia/Aden"}, + {"Asia/Aden", "Asia/Riyadh"}, + {"Asia/Kuwait", "Asia/Riyadh"}, {"Asia/Muscat", "Asia/Dubai"}, {"Asia/Phnom_Penh", "Asia/Bangkok"}, {"Asia/Qatar", "Asia/Bahrain"}, - {"Asia/Riyadh", "Asia/Aden"}, {"Asia/Vientiane", "Asia/Bangkok"}, {"Atlantic/Jan_Mayen", "Europe/Oslo"}, {"Atlantic/St_Helena", "Africa/Abidjan"}, diff --git a/Build/source/libs/icu/icu-src/source/test/intltest/units_test.cpp b/Build/source/libs/icu/icu-src/source/test/intltest/units_test.cpp index c65a5e03229..ca41e3b0d03 100644 --- a/Build/source/libs/icu/icu-src/source/test/intltest/units_test.cpp +++ b/Build/source/libs/icu/icu-src/source/test/intltest/units_test.cpp @@ -325,6 +325,12 @@ void UnitsTest::testConverter() { // Fuel Consumption {"cubic-meter-per-meter", "mile-per-gallon", 2.1383143939394E-6, 1.1}, {"cubic-meter-per-meter", "mile-per-gallon", 2.6134953703704E-6, 0.9}, + {"liter-per-100-kilometer", "mile-per-gallon", 6.6, 35.6386}, + {"liter-per-100-kilometer", "mile-per-gallon", 0, uprv_getInfinity()}, + {"mile-per-gallon", "liter-per-100-kilometer", 0, uprv_getInfinity()}, + {"mile-per-gallon", "liter-per-100-kilometer", uprv_getInfinity(), 0}, + // We skip testing -Inf, because the inverse conversion loses the sign: + // {"mile-per-gallon", "liter-per-100-kilometer", -uprv_getInfinity(), 0}, // Test Aliases // Alias is just another name to the same unit. Therefore, converting @@ -348,54 +354,42 @@ void UnitsTest::testConverter() { continue; } + double maxDelta = 1e-6 * uprv_fabs(testCase.expectedValue); + if (testCase.expectedValue == 0) { + maxDelta = 1e-12; + } + double inverseMaxDelta = 1e-6 * uprv_fabs(testCase.inputValue); + if (testCase.inputValue == 0) { + inverseMaxDelta = 1e-12; + } + ConversionRates conversionRates(status); if (status.errIfFailureAndReset("conversionRates(status)")) { continue; } + UnitsConverter converter(source, target, conversionRates, status); if (status.errIfFailureAndReset("UnitsConverter(<%s>, <%s>, ...)", testCase.source, testCase.target)) { continue; } - - double maxDelta = 1e-6 * uprv_fabs(testCase.expectedValue); - if (testCase.expectedValue == 0) { - maxDelta = 1e-12; - } assertEqualsNear(UnicodeString("testConverter: ") + testCase.source + " to " + testCase.target, testCase.expectedValue, converter.convert(testCase.inputValue), maxDelta); - - maxDelta = 1e-6 * uprv_fabs(testCase.inputValue); - if (testCase.inputValue == 0) { - maxDelta = 1e-12; - } assertEqualsNear( UnicodeString("testConverter inverse: ") + testCase.target + " back to " + testCase.source, - testCase.inputValue, converter.convertInverse(testCase.expectedValue), maxDelta); + testCase.inputValue, converter.convertInverse(testCase.expectedValue), inverseMaxDelta); - - // TODO: Test UnitsConverter created using CLDR separately. // Test UnitsConverter created by CLDR unit identifiers UnitsConverter converter2(testCase.source, testCase.target, status); if (status.errIfFailureAndReset("UnitsConverter(<%s>, <%s>, ...)", testCase.source, testCase.target)) { continue; } - - maxDelta = 1e-6 * uprv_fabs(testCase.expectedValue); - if (testCase.expectedValue == 0) { - maxDelta = 1e-12; - } assertEqualsNear(UnicodeString("testConverter2: ") + testCase.source + " to " + testCase.target, testCase.expectedValue, converter2.convert(testCase.inputValue), maxDelta); - - maxDelta = 1e-6 * uprv_fabs(testCase.inputValue); - if (testCase.inputValue == 0) { - maxDelta = 1e-12; - } assertEqualsNear( UnicodeString("testConverter2 inverse: ") + testCase.target + " back to " + testCase.source, - testCase.inputValue, converter2.convertInverse(testCase.expectedValue), maxDelta); + testCase.inputValue, converter2.convertInverse(testCase.expectedValue), inverseMaxDelta); } } @@ -647,6 +641,16 @@ void UnitsTest::testComplexUnitsConverter() { Measure(2.1, MeasureUnit::createMeter(status), status)}, 2, 0.001}, + + // Negative numbers + {"Negative number conversion", + "yard", + "mile-and-yard", + -1800, + {Measure(-1, MeasureUnit::createMile(status), status), + Measure(-40, MeasureUnit::createYard(status), status)}, + 2, + 1e-10}, }; status.assertSuccess(); @@ -694,11 +698,7 @@ void UnitsTest::testComplexUnitsConverter() { ComplexUnitsConverter converter2( testCase.input, testCase.output, status); testATestCase(converter2, "ComplexUnitsConverter #1 " , testCase); } - - status.assertSuccess(); - - // TODO(icu-units#63): test negative numbers! } void UnitsTest::testComplexUnitsConverterSorting() { diff --git a/Build/source/libs/icu/icu-src/source/test/intltest/ustrtest.cpp b/Build/source/libs/icu/icu-src/source/test/intltest/ustrtest.cpp index cd9751d761b..309a29713d7 100644 --- a/Build/source/libs/icu/icu-src/source/test/intltest/ustrtest.cpp +++ b/Build/source/libs/icu/icu-src/source/test/intltest/ustrtest.cpp @@ -1653,6 +1653,16 @@ UnicodeStringTest::TestBogus() { if(test1>=test2 || !(test2>test1) || test1.compare(test2)>=0 || !(test2.compare(test1)>0)) { errln("bogus<empty failed"); } + + // test that copy constructor of bogus is bogus & clone of bogus is nullptr + { + test3.setToBogus(); + UnicodeString test3Copy(test3); + UnicodeString *test3Clone = test3.clone(); + assertTrue(WHERE, test3.isBogus()); + assertTrue(WHERE, test3Copy.isBogus()); + assertTrue(WHERE, test3Clone == nullptr); + } } // StringEnumeration ------------------------------------------------------- *** @@ -2354,7 +2364,7 @@ void UnicodeStringTest::TestLargeAppend() { } else if (total <= INT32_MAX) { // Check that a string of exactly the maximum size works UnicodeString str2; - int32_t remain = INT32_MAX - total; + int32_t remain = static_cast<int32_t>(INT32_MAX - total); char16_t *buf2 = str2.getBuffer(remain); if (buf2 == nullptr) { // if somehow memory allocation fail, return the test |