12e5b6d6dSopenharmony_ci// © 2019 and later: Unicode, Inc. and others. 22e5b6d6dSopenharmony_ci// License & terms of use: http://www.unicode.org/copyright.html 32e5b6d6dSopenharmony_ci 42e5b6d6dSopenharmony_ci// localematchertest.cpp 52e5b6d6dSopenharmony_ci// created: 2019jul04 Markus W. Scherer 62e5b6d6dSopenharmony_ci 72e5b6d6dSopenharmony_ci#include <string> 82e5b6d6dSopenharmony_ci#include <vector> 92e5b6d6dSopenharmony_ci#include <utility> 102e5b6d6dSopenharmony_ci 112e5b6d6dSopenharmony_ci#include "unicode/utypes.h" 122e5b6d6dSopenharmony_ci#include "unicode/localematcher.h" 132e5b6d6dSopenharmony_ci#include "unicode/locid.h" 142e5b6d6dSopenharmony_ci#include "charstr.h" 152e5b6d6dSopenharmony_ci#include "cmemory.h" 162e5b6d6dSopenharmony_ci#include "intltest.h" 172e5b6d6dSopenharmony_ci#include "localeprioritylist.h" 182e5b6d6dSopenharmony_ci#include "ucbuf.h" 192e5b6d6dSopenharmony_ci 202e5b6d6dSopenharmony_ci#define ARRAY_RANGE(array) (array), ((array) + UPRV_LENGTHOF(array)) 212e5b6d6dSopenharmony_ci 222e5b6d6dSopenharmony_cinamespace { 232e5b6d6dSopenharmony_ci 242e5b6d6dSopenharmony_ciconst char *locString(const Locale *loc) { 252e5b6d6dSopenharmony_ci return loc != nullptr ? loc->getName() : "(null)"; 262e5b6d6dSopenharmony_ci} 272e5b6d6dSopenharmony_ci 282e5b6d6dSopenharmony_cistruct TestCase { 292e5b6d6dSopenharmony_ci int32_t lineNr = 0; 302e5b6d6dSopenharmony_ci 312e5b6d6dSopenharmony_ci CharString supported; 322e5b6d6dSopenharmony_ci CharString def; 332e5b6d6dSopenharmony_ci UnicodeString favor; 342e5b6d6dSopenharmony_ci UnicodeString threshold; 352e5b6d6dSopenharmony_ci CharString desired; 362e5b6d6dSopenharmony_ci CharString expMatch; 372e5b6d6dSopenharmony_ci CharString expDesired; 382e5b6d6dSopenharmony_ci CharString expCombined; 392e5b6d6dSopenharmony_ci 402e5b6d6dSopenharmony_ci void reset() { 412e5b6d6dSopenharmony_ci supported.clear(); 422e5b6d6dSopenharmony_ci def.clear(); 432e5b6d6dSopenharmony_ci favor.remove(); 442e5b6d6dSopenharmony_ci threshold.remove(); 452e5b6d6dSopenharmony_ci } 462e5b6d6dSopenharmony_ci}; 472e5b6d6dSopenharmony_ci 482e5b6d6dSopenharmony_ci} // namespace 492e5b6d6dSopenharmony_ci 502e5b6d6dSopenharmony_ciclass LocaleMatcherTest : public IntlTest { 512e5b6d6dSopenharmony_cipublic: 522e5b6d6dSopenharmony_ci LocaleMatcherTest() {} 532e5b6d6dSopenharmony_ci 542e5b6d6dSopenharmony_ci void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par=NULL) override; 552e5b6d6dSopenharmony_ci 562e5b6d6dSopenharmony_ci void testEmpty(); 572e5b6d6dSopenharmony_ci void testCopyErrorTo(); 582e5b6d6dSopenharmony_ci void testBasics(); 592e5b6d6dSopenharmony_ci void testSupportedDefault(); 602e5b6d6dSopenharmony_ci void testUnsupportedDefault(); 612e5b6d6dSopenharmony_ci void testNoDefault(); 622e5b6d6dSopenharmony_ci void testDemotion(); 632e5b6d6dSopenharmony_ci void testDirection(); 642e5b6d6dSopenharmony_ci void testMaxDistanceAndIsMatch(); 652e5b6d6dSopenharmony_ci void testMatch(); 662e5b6d6dSopenharmony_ci void testResolvedLocale(); 672e5b6d6dSopenharmony_ci void testDataDriven(); 682e5b6d6dSopenharmony_ci 692e5b6d6dSopenharmony_ciprivate: 702e5b6d6dSopenharmony_ci UBool dataDriven(const TestCase &test, IcuTestErrorCode &errorCode); 712e5b6d6dSopenharmony_ci}; 722e5b6d6dSopenharmony_ci 732e5b6d6dSopenharmony_ciextern IntlTest *createLocaleMatcherTest() { 742e5b6d6dSopenharmony_ci return new LocaleMatcherTest(); 752e5b6d6dSopenharmony_ci} 762e5b6d6dSopenharmony_ci 772e5b6d6dSopenharmony_civoid LocaleMatcherTest::runIndexedTest(int32_t index, UBool exec, const char *&name, char * /*par*/) { 782e5b6d6dSopenharmony_ci if(exec) { 792e5b6d6dSopenharmony_ci logln("TestSuite LocaleMatcherTest: "); 802e5b6d6dSopenharmony_ci } 812e5b6d6dSopenharmony_ci TESTCASE_AUTO_BEGIN; 822e5b6d6dSopenharmony_ci TESTCASE_AUTO(testEmpty); 832e5b6d6dSopenharmony_ci TESTCASE_AUTO(testCopyErrorTo); 842e5b6d6dSopenharmony_ci TESTCASE_AUTO(testBasics); 852e5b6d6dSopenharmony_ci TESTCASE_AUTO(testSupportedDefault); 862e5b6d6dSopenharmony_ci TESTCASE_AUTO(testUnsupportedDefault); 872e5b6d6dSopenharmony_ci TESTCASE_AUTO(testNoDefault); 882e5b6d6dSopenharmony_ci TESTCASE_AUTO(testDemotion); 892e5b6d6dSopenharmony_ci TESTCASE_AUTO(testDirection); 902e5b6d6dSopenharmony_ci TESTCASE_AUTO(testMaxDistanceAndIsMatch); 912e5b6d6dSopenharmony_ci TESTCASE_AUTO(testMatch); 922e5b6d6dSopenharmony_ci TESTCASE_AUTO(testResolvedLocale); 932e5b6d6dSopenharmony_ci TESTCASE_AUTO(testDataDriven); 942e5b6d6dSopenharmony_ci TESTCASE_AUTO_END; 952e5b6d6dSopenharmony_ci} 962e5b6d6dSopenharmony_ci 972e5b6d6dSopenharmony_civoid LocaleMatcherTest::testEmpty() { 982e5b6d6dSopenharmony_ci IcuTestErrorCode errorCode(*this, "testEmpty"); 992e5b6d6dSopenharmony_ci LocaleMatcher matcher = LocaleMatcher::Builder().build(errorCode); 1002e5b6d6dSopenharmony_ci const Locale *best = matcher.getBestMatch(Locale::getFrench(), errorCode); 1012e5b6d6dSopenharmony_ci assertEquals("getBestMatch(fr)", "(null)", locString(best)); 1022e5b6d6dSopenharmony_ci LocaleMatcher::Result result = matcher.getBestMatchResult("fr", errorCode); 1032e5b6d6dSopenharmony_ci assertEquals("getBestMatchResult(fr).des", "(null)", locString(result.getDesiredLocale())); 1042e5b6d6dSopenharmony_ci assertEquals("getBestMatchResult(fr).desIndex", -1, result.getDesiredIndex()); 1052e5b6d6dSopenharmony_ci assertEquals("getBestMatchResult(fr).supp", 1062e5b6d6dSopenharmony_ci "(null)", locString(result.getSupportedLocale())); 1072e5b6d6dSopenharmony_ci assertEquals("getBestMatchResult(fr).suppIndex", 1082e5b6d6dSopenharmony_ci -1, result.getSupportedIndex()); 1092e5b6d6dSopenharmony_ci} 1102e5b6d6dSopenharmony_ci 1112e5b6d6dSopenharmony_civoid LocaleMatcherTest::testCopyErrorTo() { 1122e5b6d6dSopenharmony_ci IcuTestErrorCode errorCode(*this, "testCopyErrorTo"); 1132e5b6d6dSopenharmony_ci // The builder does not set any errors except out-of-memory. 1142e5b6d6dSopenharmony_ci // Test what we can. 1152e5b6d6dSopenharmony_ci LocaleMatcher::Builder builder; 1162e5b6d6dSopenharmony_ci UErrorCode success = U_ZERO_ERROR; 1172e5b6d6dSopenharmony_ci assertFalse("no error", builder.copyErrorTo(success)); 1182e5b6d6dSopenharmony_ci assertTrue("still success", U_SUCCESS(success)); 1192e5b6d6dSopenharmony_ci UErrorCode failure = U_INVALID_FORMAT_ERROR; 1202e5b6d6dSopenharmony_ci assertTrue("failure passed in", builder.copyErrorTo(failure)); 1212e5b6d6dSopenharmony_ci assertEquals("same failure", U_INVALID_FORMAT_ERROR, failure); 1222e5b6d6dSopenharmony_ci} 1232e5b6d6dSopenharmony_ci 1242e5b6d6dSopenharmony_civoid LocaleMatcherTest::testBasics() { 1252e5b6d6dSopenharmony_ci IcuTestErrorCode errorCode(*this, "testBasics"); 1262e5b6d6dSopenharmony_ci Locale locales[] = { "fr", "en_GB", "en" }; 1272e5b6d6dSopenharmony_ci { 1282e5b6d6dSopenharmony_ci LocaleMatcher matcher = LocaleMatcher::Builder(). 1292e5b6d6dSopenharmony_ci setSupportedLocales(ARRAY_RANGE(locales)).build(errorCode); 1302e5b6d6dSopenharmony_ci const Locale *best = matcher.getBestMatch("en_GB", errorCode); 1312e5b6d6dSopenharmony_ci assertEquals("fromRange.getBestMatch(en_GB)", "en_GB", locString(best)); 1322e5b6d6dSopenharmony_ci best = matcher.getBestMatch("en_US", errorCode); 1332e5b6d6dSopenharmony_ci assertEquals("fromRange.getBestMatch(en_US)", "en", locString(best)); 1342e5b6d6dSopenharmony_ci best = matcher.getBestMatch("fr_FR", errorCode); 1352e5b6d6dSopenharmony_ci assertEquals("fromRange.getBestMatch(fr_FR)", "fr", locString(best)); 1362e5b6d6dSopenharmony_ci best = matcher.getBestMatch("ja_JP", errorCode); 1372e5b6d6dSopenharmony_ci assertEquals("fromRange.getBestMatch(ja_JP)", "fr", locString(best)); 1382e5b6d6dSopenharmony_ci } 1392e5b6d6dSopenharmony_ci // Code coverage: Variations of setting supported locales. 1402e5b6d6dSopenharmony_ci { 1412e5b6d6dSopenharmony_ci std::vector<Locale> locales{ "fr", "en_GB", "en" }; 1422e5b6d6dSopenharmony_ci LocaleMatcher matcher = LocaleMatcher::Builder(). 1432e5b6d6dSopenharmony_ci setSupportedLocales(locales.begin(), locales.end()).build(errorCode); 1442e5b6d6dSopenharmony_ci const Locale *best = matcher.getBestMatch("en_GB", errorCode); 1452e5b6d6dSopenharmony_ci assertEquals("fromRange.getBestMatch(en_GB)", "en_GB", locString(best)); 1462e5b6d6dSopenharmony_ci best = matcher.getBestMatch("en_US", errorCode); 1472e5b6d6dSopenharmony_ci assertEquals("fromRange.getBestMatch(en_US)", "en", locString(best)); 1482e5b6d6dSopenharmony_ci best = matcher.getBestMatch("fr_FR", errorCode); 1492e5b6d6dSopenharmony_ci assertEquals("fromRange.getBestMatch(fr_FR)", "fr", locString(best)); 1502e5b6d6dSopenharmony_ci best = matcher.getBestMatch("ja_JP", errorCode); 1512e5b6d6dSopenharmony_ci assertEquals("fromRange.getBestMatch(ja_JP)", "fr", locString(best)); 1522e5b6d6dSopenharmony_ci } 1532e5b6d6dSopenharmony_ci { 1542e5b6d6dSopenharmony_ci Locale::RangeIterator<Locale *> iter(ARRAY_RANGE(locales)); 1552e5b6d6dSopenharmony_ci LocaleMatcher matcher = LocaleMatcher::Builder(). 1562e5b6d6dSopenharmony_ci setSupportedLocales(iter).build(errorCode); 1572e5b6d6dSopenharmony_ci const Locale *best = matcher.getBestMatch("en_GB", errorCode); 1582e5b6d6dSopenharmony_ci assertEquals("fromIter.getBestMatch(en_GB)", "en_GB", locString(best)); 1592e5b6d6dSopenharmony_ci best = matcher.getBestMatch("en_US", errorCode); 1602e5b6d6dSopenharmony_ci assertEquals("fromIter.getBestMatch(en_US)", "en", locString(best)); 1612e5b6d6dSopenharmony_ci best = matcher.getBestMatch("fr_FR", errorCode); 1622e5b6d6dSopenharmony_ci assertEquals("fromIter.getBestMatch(fr_FR)", "fr", locString(best)); 1632e5b6d6dSopenharmony_ci best = matcher.getBestMatch("ja_JP", errorCode); 1642e5b6d6dSopenharmony_ci assertEquals("fromIter.getBestMatch(ja_JP)", "fr", locString(best)); 1652e5b6d6dSopenharmony_ci } 1662e5b6d6dSopenharmony_ci { 1672e5b6d6dSopenharmony_ci Locale *pointers[] = { locales, locales + 1, locales + 2 }; 1682e5b6d6dSopenharmony_ci // Lambda with explicit reference return type to prevent copy-constructing a temporary 1692e5b6d6dSopenharmony_ci // which would be destructed right away. 1702e5b6d6dSopenharmony_ci LocaleMatcher matcher = LocaleMatcher::Builder(). 1712e5b6d6dSopenharmony_ci setSupportedLocalesViaConverter( 1722e5b6d6dSopenharmony_ci ARRAY_RANGE(pointers), [](const Locale *p) -> const Locale & { return *p; }). 1732e5b6d6dSopenharmony_ci build(errorCode); 1742e5b6d6dSopenharmony_ci const Locale *best = matcher.getBestMatch("en_GB", errorCode); 1752e5b6d6dSopenharmony_ci assertEquals("viaConverter.getBestMatch(en_GB)", "en_GB", locString(best)); 1762e5b6d6dSopenharmony_ci best = matcher.getBestMatch("en_US", errorCode); 1772e5b6d6dSopenharmony_ci assertEquals("viaConverter.getBestMatch(en_US)", "en", locString(best)); 1782e5b6d6dSopenharmony_ci best = matcher.getBestMatch("fr_FR", errorCode); 1792e5b6d6dSopenharmony_ci assertEquals("viaConverter.getBestMatch(fr_FR)", "fr", locString(best)); 1802e5b6d6dSopenharmony_ci best = matcher.getBestMatch("ja_JP", errorCode); 1812e5b6d6dSopenharmony_ci assertEquals("viaConverter.getBestMatch(ja_JP)", "fr", locString(best)); 1822e5b6d6dSopenharmony_ci } 1832e5b6d6dSopenharmony_ci { 1842e5b6d6dSopenharmony_ci LocaleMatcher matcher = LocaleMatcher::Builder(). 1852e5b6d6dSopenharmony_ci addSupportedLocale(locales[0]). 1862e5b6d6dSopenharmony_ci addSupportedLocale(locales[1]). 1872e5b6d6dSopenharmony_ci addSupportedLocale(locales[2]). 1882e5b6d6dSopenharmony_ci build(errorCode); 1892e5b6d6dSopenharmony_ci const Locale *best = matcher.getBestMatch("en_GB", errorCode); 1902e5b6d6dSopenharmony_ci assertEquals("added.getBestMatch(en_GB)", "en_GB", locString(best)); 1912e5b6d6dSopenharmony_ci best = matcher.getBestMatch("en_US", errorCode); 1922e5b6d6dSopenharmony_ci assertEquals("added.getBestMatch(en_US)", "en", locString(best)); 1932e5b6d6dSopenharmony_ci best = matcher.getBestMatch("fr_FR", errorCode); 1942e5b6d6dSopenharmony_ci assertEquals("added.getBestMatch(fr_FR)", "fr", locString(best)); 1952e5b6d6dSopenharmony_ci best = matcher.getBestMatch("ja_JP", errorCode); 1962e5b6d6dSopenharmony_ci assertEquals("added.getBestMatch(ja_JP)", "fr", locString(best)); 1972e5b6d6dSopenharmony_ci } 1982e5b6d6dSopenharmony_ci { 1992e5b6d6dSopenharmony_ci LocaleMatcher matcher = LocaleMatcher::Builder(). 2002e5b6d6dSopenharmony_ci setSupportedLocalesFromListString( 2012e5b6d6dSopenharmony_ci " el, fr;q=0.555555, en-GB ; q = 0.88 , el; q =0, en;q=0.88 , fr "). 2022e5b6d6dSopenharmony_ci build(errorCode); 2032e5b6d6dSopenharmony_ci const Locale *best = matcher.getBestMatchForListString("el, fr, fr;q=0, en-GB", errorCode); 2042e5b6d6dSopenharmony_ci assertEquals("fromList.getBestMatch(en_GB)", "en_GB", locString(best)); 2052e5b6d6dSopenharmony_ci best = matcher.getBestMatch("en_US", errorCode); 2062e5b6d6dSopenharmony_ci assertEquals("fromList.getBestMatch(en_US)", "en", locString(best)); 2072e5b6d6dSopenharmony_ci best = matcher.getBestMatch("fr_FR", errorCode); 2082e5b6d6dSopenharmony_ci assertEquals("fromList.getBestMatch(fr_FR)", "fr", locString(best)); 2092e5b6d6dSopenharmony_ci best = matcher.getBestMatch("ja_JP", errorCode); 2102e5b6d6dSopenharmony_ci assertEquals("fromList.getBestMatch(ja_JP)", "fr", locString(best)); 2112e5b6d6dSopenharmony_ci } 2122e5b6d6dSopenharmony_ci // more API coverage 2132e5b6d6dSopenharmony_ci { 2142e5b6d6dSopenharmony_ci LocalePriorityList list("fr, en-GB", errorCode); 2152e5b6d6dSopenharmony_ci LocalePriorityList::Iterator iter(list.iterator()); 2162e5b6d6dSopenharmony_ci LocaleMatcher matcher = LocaleMatcher::Builder(). 2172e5b6d6dSopenharmony_ci setSupportedLocales(iter). 2182e5b6d6dSopenharmony_ci addSupportedLocale(Locale::getEnglish()). 2192e5b6d6dSopenharmony_ci setDefaultLocale(&Locale::getGerman()). 2202e5b6d6dSopenharmony_ci build(errorCode); 2212e5b6d6dSopenharmony_ci const Locale *best = matcher.getBestMatch("en_GB", errorCode); 2222e5b6d6dSopenharmony_ci assertEquals("withDefault.getBestMatch(en_GB)", "en_GB", locString(best)); 2232e5b6d6dSopenharmony_ci best = matcher.getBestMatch("en_US", errorCode); 2242e5b6d6dSopenharmony_ci assertEquals("withDefault.getBestMatch(en_US)", "en", locString(best)); 2252e5b6d6dSopenharmony_ci best = matcher.getBestMatch("fr_FR", errorCode); 2262e5b6d6dSopenharmony_ci assertEquals("withDefault.getBestMatch(fr_FR)", "fr", locString(best)); 2272e5b6d6dSopenharmony_ci best = matcher.getBestMatch("ja_JP", errorCode); 2282e5b6d6dSopenharmony_ci assertEquals("withDefault.getBestMatch(ja_JP)", "de", locString(best)); 2292e5b6d6dSopenharmony_ci 2302e5b6d6dSopenharmony_ci Locale desired("en_GB"); // distinct object from Locale.UK 2312e5b6d6dSopenharmony_ci LocaleMatcher::Result result = matcher.getBestMatchResult(desired, errorCode); 2322e5b6d6dSopenharmony_ci assertTrue("withDefault: exactly desired en-GB object", 2332e5b6d6dSopenharmony_ci &desired == result.getDesiredLocale()); 2342e5b6d6dSopenharmony_ci assertEquals("withDefault: en-GB desired index", 0, result.getDesiredIndex()); 2352e5b6d6dSopenharmony_ci assertEquals("withDefault: en-GB supported", 2362e5b6d6dSopenharmony_ci "en_GB", locString(result.getSupportedLocale())); 2372e5b6d6dSopenharmony_ci assertEquals("withDefault: en-GB supported index", 1, result.getSupportedIndex()); 2382e5b6d6dSopenharmony_ci 2392e5b6d6dSopenharmony_ci LocalePriorityList list2("ja-JP, en-US", errorCode); 2402e5b6d6dSopenharmony_ci LocalePriorityList::Iterator iter2(list2.iterator()); 2412e5b6d6dSopenharmony_ci result = matcher.getBestMatchResult(iter2, errorCode); 2422e5b6d6dSopenharmony_ci assertEquals("withDefault: ja-JP, en-US desired index", 1, result.getDesiredIndex()); 2432e5b6d6dSopenharmony_ci assertEquals("withDefault: ja-JP, en-US desired", 2442e5b6d6dSopenharmony_ci "en_US", locString(result.getDesiredLocale())); 2452e5b6d6dSopenharmony_ci 2462e5b6d6dSopenharmony_ci desired = Locale("en", "US"); // distinct object from Locale.US 2472e5b6d6dSopenharmony_ci result = matcher.getBestMatchResult(desired, errorCode); 2482e5b6d6dSopenharmony_ci assertTrue("withDefault: exactly desired en-US object", 2492e5b6d6dSopenharmony_ci &desired == result.getDesiredLocale()); 2502e5b6d6dSopenharmony_ci assertEquals("withDefault: en-US desired index", 0, result.getDesiredIndex()); 2512e5b6d6dSopenharmony_ci assertEquals("withDefault: en-US supported", "en", locString(result.getSupportedLocale())); 2522e5b6d6dSopenharmony_ci assertEquals("withDefault: en-US supported index", 2, result.getSupportedIndex()); 2532e5b6d6dSopenharmony_ci 2542e5b6d6dSopenharmony_ci result = matcher.getBestMatchResult("ja_JP", errorCode); 2552e5b6d6dSopenharmony_ci assertEquals("withDefault: ja-JP desired", "(null)", locString(result.getDesiredLocale())); 2562e5b6d6dSopenharmony_ci assertEquals("withDefault: ja-JP desired index", -1, result.getDesiredIndex()); 2572e5b6d6dSopenharmony_ci assertEquals("withDefault: ja-JP supported", "de", locString(result.getSupportedLocale())); 2582e5b6d6dSopenharmony_ci assertEquals("withDefault: ja-JP supported index", -1, result.getSupportedIndex()); 2592e5b6d6dSopenharmony_ci } 2602e5b6d6dSopenharmony_ci} 2612e5b6d6dSopenharmony_ci 2622e5b6d6dSopenharmony_civoid LocaleMatcherTest::testSupportedDefault() { 2632e5b6d6dSopenharmony_ci // The default locale is one of the supported locales. 2642e5b6d6dSopenharmony_ci IcuTestErrorCode errorCode(*this, "testSupportedDefault"); 2652e5b6d6dSopenharmony_ci Locale locales[] = { "fr", "en_GB", "en" }; 2662e5b6d6dSopenharmony_ci LocaleMatcher matcher = LocaleMatcher::Builder(). 2672e5b6d6dSopenharmony_ci setSupportedLocales(ARRAY_RANGE(locales)). 2682e5b6d6dSopenharmony_ci setDefaultLocale(&locales[1]). 2692e5b6d6dSopenharmony_ci build(errorCode); 2702e5b6d6dSopenharmony_ci const Locale *best = matcher.getBestMatch("en_GB", errorCode); 2712e5b6d6dSopenharmony_ci assertEquals("getBestMatch(en_GB)", "en_GB", locString(best)); 2722e5b6d6dSopenharmony_ci best = matcher.getBestMatch("en_US", errorCode); 2732e5b6d6dSopenharmony_ci assertEquals("getBestMatch(en_US)", "en", locString(best)); 2742e5b6d6dSopenharmony_ci best = matcher.getBestMatch("fr_FR", errorCode); 2752e5b6d6dSopenharmony_ci assertEquals("getBestMatch(fr_FR)", "fr", locString(best)); 2762e5b6d6dSopenharmony_ci best = matcher.getBestMatch("ja_JP", errorCode); 2772e5b6d6dSopenharmony_ci assertEquals("getBestMatch(ja_JP)", "en_GB", locString(best)); 2782e5b6d6dSopenharmony_ci LocaleMatcher::Result result = matcher.getBestMatchResult("ja_JP", errorCode); 2792e5b6d6dSopenharmony_ci assertEquals("getBestMatchResult(ja_JP).supp", 2802e5b6d6dSopenharmony_ci "en_GB", locString(result.getSupportedLocale())); 2812e5b6d6dSopenharmony_ci assertEquals("getBestMatchResult(ja_JP).suppIndex", 2822e5b6d6dSopenharmony_ci -1, result.getSupportedIndex()); 2832e5b6d6dSopenharmony_ci} 2842e5b6d6dSopenharmony_ci 2852e5b6d6dSopenharmony_civoid LocaleMatcherTest::testUnsupportedDefault() { 2862e5b6d6dSopenharmony_ci // The default locale does not match any of the supported locales. 2872e5b6d6dSopenharmony_ci IcuTestErrorCode errorCode(*this, "testUnsupportedDefault"); 2882e5b6d6dSopenharmony_ci Locale locales[] = { "fr", "en_GB", "en" }; 2892e5b6d6dSopenharmony_ci Locale def("de"); 2902e5b6d6dSopenharmony_ci LocaleMatcher matcher = LocaleMatcher::Builder(). 2912e5b6d6dSopenharmony_ci setSupportedLocales(ARRAY_RANGE(locales)). 2922e5b6d6dSopenharmony_ci setDefaultLocale(&def). 2932e5b6d6dSopenharmony_ci build(errorCode); 2942e5b6d6dSopenharmony_ci const Locale *best = matcher.getBestMatch("en_GB", errorCode); 2952e5b6d6dSopenharmony_ci assertEquals("getBestMatch(en_GB)", "en_GB", locString(best)); 2962e5b6d6dSopenharmony_ci best = matcher.getBestMatch("en_US", errorCode); 2972e5b6d6dSopenharmony_ci assertEquals("getBestMatch(en_US)", "en", locString(best)); 2982e5b6d6dSopenharmony_ci best = matcher.getBestMatch("fr_FR", errorCode); 2992e5b6d6dSopenharmony_ci assertEquals("getBestMatch(fr_FR)", "fr", locString(best)); 3002e5b6d6dSopenharmony_ci best = matcher.getBestMatch("ja_JP", errorCode); 3012e5b6d6dSopenharmony_ci assertEquals("getBestMatch(ja_JP)", "de", locString(best)); 3022e5b6d6dSopenharmony_ci LocaleMatcher::Result result = matcher.getBestMatchResult("ja_JP", errorCode); 3032e5b6d6dSopenharmony_ci assertEquals("getBestMatchResult(ja_JP).supp", 3042e5b6d6dSopenharmony_ci "de", locString(result.getSupportedLocale())); 3052e5b6d6dSopenharmony_ci assertEquals("getBestMatchResult(ja_JP).suppIndex", 3062e5b6d6dSopenharmony_ci -1, result.getSupportedIndex()); 3072e5b6d6dSopenharmony_ci} 3082e5b6d6dSopenharmony_ci 3092e5b6d6dSopenharmony_civoid LocaleMatcherTest::testNoDefault() { 3102e5b6d6dSopenharmony_ci // We want nullptr instead of any default locale. 3112e5b6d6dSopenharmony_ci IcuTestErrorCode errorCode(*this, "testNoDefault"); 3122e5b6d6dSopenharmony_ci Locale locales[] = { "fr", "en_GB", "en" }; 3132e5b6d6dSopenharmony_ci LocaleMatcher matcher = LocaleMatcher::Builder(). 3142e5b6d6dSopenharmony_ci setSupportedLocales(ARRAY_RANGE(locales)). 3152e5b6d6dSopenharmony_ci setNoDefaultLocale(). 3162e5b6d6dSopenharmony_ci build(errorCode); 3172e5b6d6dSopenharmony_ci const Locale *best = matcher.getBestMatch("en_GB", errorCode); 3182e5b6d6dSopenharmony_ci assertEquals("getBestMatch(en_GB)", "en_GB", locString(best)); 3192e5b6d6dSopenharmony_ci best = matcher.getBestMatch("en_US", errorCode); 3202e5b6d6dSopenharmony_ci assertEquals("getBestMatch(en_US)", "en", locString(best)); 3212e5b6d6dSopenharmony_ci best = matcher.getBestMatch("fr_FR", errorCode); 3222e5b6d6dSopenharmony_ci assertEquals("getBestMatch(fr_FR)", "fr", locString(best)); 3232e5b6d6dSopenharmony_ci best = matcher.getBestMatch("ja_JP", errorCode); 3242e5b6d6dSopenharmony_ci assertEquals("getBestMatch(ja_JP)", "(null)", locString(best)); 3252e5b6d6dSopenharmony_ci LocaleMatcher::Result result = matcher.getBestMatchResult("ja_JP", errorCode); 3262e5b6d6dSopenharmony_ci assertEquals("getBestMatchResult(ja_JP).supp", 3272e5b6d6dSopenharmony_ci "(null)", locString(result.getSupportedLocale())); 3282e5b6d6dSopenharmony_ci assertEquals("getBestMatchResult(ja_JP).suppIndex", 3292e5b6d6dSopenharmony_ci -1, result.getSupportedIndex()); 3302e5b6d6dSopenharmony_ci} 3312e5b6d6dSopenharmony_ci 3322e5b6d6dSopenharmony_civoid LocaleMatcherTest::testDemotion() { 3332e5b6d6dSopenharmony_ci IcuTestErrorCode errorCode(*this, "testDemotion"); 3342e5b6d6dSopenharmony_ci Locale supported[] = { "fr", "de-CH", "it" }; 3352e5b6d6dSopenharmony_ci Locale desired[] = { "fr-CH", "de-CH", "it" }; 3362e5b6d6dSopenharmony_ci { 3372e5b6d6dSopenharmony_ci LocaleMatcher noDemotion = LocaleMatcher::Builder(). 3382e5b6d6dSopenharmony_ci setSupportedLocales(ARRAY_RANGE(supported)). 3392e5b6d6dSopenharmony_ci setDemotionPerDesiredLocale(ULOCMATCH_DEMOTION_NONE).build(errorCode); 3402e5b6d6dSopenharmony_ci Locale::RangeIterator<Locale *> desiredIter(ARRAY_RANGE(desired)); 3412e5b6d6dSopenharmony_ci assertEquals("no demotion", 3422e5b6d6dSopenharmony_ci "de_CH", locString(noDemotion.getBestMatch(desiredIter, errorCode))); 3432e5b6d6dSopenharmony_ci } 3442e5b6d6dSopenharmony_ci 3452e5b6d6dSopenharmony_ci { 3462e5b6d6dSopenharmony_ci LocaleMatcher regionDemotion = LocaleMatcher::Builder(). 3472e5b6d6dSopenharmony_ci setSupportedLocales(ARRAY_RANGE(supported)). 3482e5b6d6dSopenharmony_ci setDemotionPerDesiredLocale(ULOCMATCH_DEMOTION_REGION).build(errorCode); 3492e5b6d6dSopenharmony_ci Locale::RangeIterator<Locale *> desiredIter(ARRAY_RANGE(desired)); 3502e5b6d6dSopenharmony_ci assertEquals("region demotion", 3512e5b6d6dSopenharmony_ci "fr", locString(regionDemotion.getBestMatch(desiredIter, errorCode))); 3522e5b6d6dSopenharmony_ci } 3532e5b6d6dSopenharmony_ci} 3542e5b6d6dSopenharmony_ci 3552e5b6d6dSopenharmony_civoid LocaleMatcherTest::testDirection() { 3562e5b6d6dSopenharmony_ci IcuTestErrorCode errorCode(*this, "testDirection"); 3572e5b6d6dSopenharmony_ci Locale supported[] = { "ar", "nn" }; 3582e5b6d6dSopenharmony_ci Locale desired[] = { "arz-EG", "nb-DK" }; 3592e5b6d6dSopenharmony_ci LocaleMatcher::Builder builder; 3602e5b6d6dSopenharmony_ci builder.setSupportedLocales(ARRAY_RANGE(supported)); 3612e5b6d6dSopenharmony_ci { 3622e5b6d6dSopenharmony_ci // arz is a close one-way match to ar, and the region matches. 3632e5b6d6dSopenharmony_ci // (Egyptian Arabic vs. Arabic) 3642e5b6d6dSopenharmony_ci // Also explicitly exercise the move copy constructor. 3652e5b6d6dSopenharmony_ci LocaleMatcher built = builder.build(errorCode); 3662e5b6d6dSopenharmony_ci LocaleMatcher withOneWay(std::move(built)); 3672e5b6d6dSopenharmony_ci Locale::RangeIterator<Locale *> desiredIter(ARRAY_RANGE(desired)); 3682e5b6d6dSopenharmony_ci assertEquals("with one-way", "ar", 3692e5b6d6dSopenharmony_ci locString(withOneWay.getBestMatch(desiredIter, errorCode))); 3702e5b6d6dSopenharmony_ci } 3712e5b6d6dSopenharmony_ci { 3722e5b6d6dSopenharmony_ci // nb is a less close two-way match to nn, and the regions differ. 3732e5b6d6dSopenharmony_ci // (Norwegian Bokmal vs. Nynorsk) 3742e5b6d6dSopenharmony_ci // Also explicitly exercise the move assignment operator. 3752e5b6d6dSopenharmony_ci LocaleMatcher onlyTwoWay = builder.build(errorCode); 3762e5b6d6dSopenharmony_ci LocaleMatcher built = 3772e5b6d6dSopenharmony_ci builder.setDirection(ULOCMATCH_DIRECTION_ONLY_TWO_WAY).build(errorCode); 3782e5b6d6dSopenharmony_ci onlyTwoWay = std::move(built); 3792e5b6d6dSopenharmony_ci Locale::RangeIterator<Locale *> desiredIter(ARRAY_RANGE(desired)); 3802e5b6d6dSopenharmony_ci assertEquals("only two-way", "nn", 3812e5b6d6dSopenharmony_ci locString(onlyTwoWay.getBestMatch(desiredIter, errorCode))); 3822e5b6d6dSopenharmony_ci } 3832e5b6d6dSopenharmony_ci} 3842e5b6d6dSopenharmony_ci 3852e5b6d6dSopenharmony_civoid LocaleMatcherTest::testMaxDistanceAndIsMatch() { 3862e5b6d6dSopenharmony_ci IcuTestErrorCode errorCode(*this, "testMaxDistanceAndIsMatch"); 3872e5b6d6dSopenharmony_ci LocaleMatcher::Builder builder; 3882e5b6d6dSopenharmony_ci LocaleMatcher standard = builder.build(errorCode); 3892e5b6d6dSopenharmony_ci Locale germanLux("de-LU"); 3902e5b6d6dSopenharmony_ci Locale germanPhoenician("de-Phnx-AT"); 3912e5b6d6dSopenharmony_ci Locale greek("el"); 3922e5b6d6dSopenharmony_ci assertTrue("standard de-LU / de", standard.isMatch(germanLux, Locale::getGerman(), errorCode)); 3932e5b6d6dSopenharmony_ci assertFalse("standard de-Phnx-AT / de", 3942e5b6d6dSopenharmony_ci standard.isMatch(germanPhoenician, Locale::getGerman(), errorCode)); 3952e5b6d6dSopenharmony_ci 3962e5b6d6dSopenharmony_ci // Allow a script difference to still match. 3972e5b6d6dSopenharmony_ci LocaleMatcher loose = 3982e5b6d6dSopenharmony_ci builder.setMaxDistance(germanPhoenician, Locale::getGerman()).build(errorCode); 3992e5b6d6dSopenharmony_ci assertTrue("loose de-LU / de", loose.isMatch(germanLux, Locale::getGerman(), errorCode)); 4002e5b6d6dSopenharmony_ci assertTrue("loose de-Phnx-AT / de", 4012e5b6d6dSopenharmony_ci loose.isMatch(germanPhoenician, Locale::getGerman(), errorCode)); 4022e5b6d6dSopenharmony_ci assertFalse("loose el / de", loose.isMatch(greek, Locale::getGerman(), errorCode)); 4032e5b6d6dSopenharmony_ci 4042e5b6d6dSopenharmony_ci // Allow at most a regional difference. 4052e5b6d6dSopenharmony_ci LocaleMatcher regional = 4062e5b6d6dSopenharmony_ci builder.setMaxDistance(Locale("de-AT"), Locale::getGerman()).build(errorCode); 4072e5b6d6dSopenharmony_ci assertTrue("regional de-LU / de", 4082e5b6d6dSopenharmony_ci regional.isMatch(Locale("de-LU"), Locale::getGerman(), errorCode)); 4092e5b6d6dSopenharmony_ci assertFalse("regional da / no", regional.isMatch(Locale("da"), Locale("no"), errorCode)); 4102e5b6d6dSopenharmony_ci assertFalse("regional zh-Hant / zh", 4112e5b6d6dSopenharmony_ci regional.isMatch(Locale::getChinese(), Locale::getTraditionalChinese(), errorCode)); 4122e5b6d6dSopenharmony_ci} 4132e5b6d6dSopenharmony_ci 4142e5b6d6dSopenharmony_ci 4152e5b6d6dSopenharmony_civoid LocaleMatcherTest::testMatch() { 4162e5b6d6dSopenharmony_ci IcuTestErrorCode errorCode(*this, "testMatch"); 4172e5b6d6dSopenharmony_ci LocaleMatcher matcher = LocaleMatcher::Builder().build(errorCode); 4182e5b6d6dSopenharmony_ci 4192e5b6d6dSopenharmony_ci // Java test function testMatch_exact() 4202e5b6d6dSopenharmony_ci Locale en_CA("en_CA"); 4212e5b6d6dSopenharmony_ci assertEquals("exact match", 1.0, matcher.internalMatch(en_CA, en_CA, errorCode)); 4222e5b6d6dSopenharmony_ci 4232e5b6d6dSopenharmony_ci // testMatch_none 4242e5b6d6dSopenharmony_ci Locale ar_MK("ar_MK"); 4252e5b6d6dSopenharmony_ci double match = matcher.internalMatch(ar_MK, en_CA, errorCode); 4262e5b6d6dSopenharmony_ci assertTrue("mismatch: 0<=match<0.2", 0 <= match && match < 0.2); 4272e5b6d6dSopenharmony_ci 4282e5b6d6dSopenharmony_ci // testMatch_matchOnMaximized 4292e5b6d6dSopenharmony_ci Locale und_TW("und_TW"); 4302e5b6d6dSopenharmony_ci Locale zh("zh"); 4312e5b6d6dSopenharmony_ci Locale zh_Hant("zh_Hant"); 4322e5b6d6dSopenharmony_ci double matchZh = matcher.internalMatch(und_TW, zh, errorCode); 4332e5b6d6dSopenharmony_ci double matchZhHant = matcher.internalMatch(und_TW, zh_Hant, errorCode); 4342e5b6d6dSopenharmony_ci assertTrue("und_TW should be closer to zh_Hant than to zh", 4352e5b6d6dSopenharmony_ci matchZh < matchZhHant); 4362e5b6d6dSopenharmony_ci Locale en_Hant_TW("en_Hant_TW"); 4372e5b6d6dSopenharmony_ci double matchEnHantTw = matcher.internalMatch(en_Hant_TW, zh_Hant, errorCode); 4382e5b6d6dSopenharmony_ci assertTrue("zh_Hant should be closer to und_TW than to en_Hant_TW", 4392e5b6d6dSopenharmony_ci matchEnHantTw < matchZhHant); 4402e5b6d6dSopenharmony_ci assertTrue("zh should not match und_TW or en_Hant_TW", 4412e5b6d6dSopenharmony_ci matchZh == 0.0 && matchEnHantTw == 0.0); // with changes in CLDR-1435 4422e5b6d6dSopenharmony_ci} 4432e5b6d6dSopenharmony_ci 4442e5b6d6dSopenharmony_civoid LocaleMatcherTest::testResolvedLocale() { 4452e5b6d6dSopenharmony_ci IcuTestErrorCode errorCode(*this, "testResolvedLocale"); 4462e5b6d6dSopenharmony_ci LocaleMatcher matcher = LocaleMatcher::Builder(). 4472e5b6d6dSopenharmony_ci addSupportedLocale("ar-EG"). 4482e5b6d6dSopenharmony_ci build(errorCode); 4492e5b6d6dSopenharmony_ci Locale desired("ar-SA-u-nu-latn"); 4502e5b6d6dSopenharmony_ci LocaleMatcher::Result result = matcher.getBestMatchResult(desired, errorCode); 4512e5b6d6dSopenharmony_ci assertEquals("best", "ar_EG", locString(result.getSupportedLocale())); 4522e5b6d6dSopenharmony_ci Locale resolved = result.makeResolvedLocale(errorCode); 4532e5b6d6dSopenharmony_ci assertEquals("ar-EG + ar-SA-u-nu-latn = ar-SA-u-nu-latn", 4542e5b6d6dSopenharmony_ci "ar-SA-u-nu-latn", 4552e5b6d6dSopenharmony_ci resolved.toLanguageTag<std::string>(errorCode).data()); 4562e5b6d6dSopenharmony_ci} 4572e5b6d6dSopenharmony_ci 4582e5b6d6dSopenharmony_cinamespace { 4592e5b6d6dSopenharmony_ci 4602e5b6d6dSopenharmony_cibool toInvariant(const UnicodeString &s, CharString &inv, ErrorCode &errorCode) { 4612e5b6d6dSopenharmony_ci if (errorCode.isSuccess()) { 4622e5b6d6dSopenharmony_ci inv.clear().appendInvariantChars(s, errorCode); 4632e5b6d6dSopenharmony_ci return errorCode.isSuccess(); 4642e5b6d6dSopenharmony_ci } 4652e5b6d6dSopenharmony_ci return false; 4662e5b6d6dSopenharmony_ci} 4672e5b6d6dSopenharmony_ci 4682e5b6d6dSopenharmony_cibool getSuffixAfterPrefix(const UnicodeString &s, int32_t limit, 4692e5b6d6dSopenharmony_ci const UnicodeString &prefix, UnicodeString &suffix) { 4702e5b6d6dSopenharmony_ci if (prefix.length() <= limit && s.startsWith(prefix)) { 4712e5b6d6dSopenharmony_ci suffix.setTo(s, prefix.length(), limit - prefix.length()); 4722e5b6d6dSopenharmony_ci return true; 4732e5b6d6dSopenharmony_ci } else { 4742e5b6d6dSopenharmony_ci return false; 4752e5b6d6dSopenharmony_ci } 4762e5b6d6dSopenharmony_ci} 4772e5b6d6dSopenharmony_ci 4782e5b6d6dSopenharmony_cibool getInvariantSuffixAfterPrefix(const UnicodeString &s, int32_t limit, 4792e5b6d6dSopenharmony_ci const UnicodeString &prefix, CharString &suffix, 4802e5b6d6dSopenharmony_ci ErrorCode &errorCode) { 4812e5b6d6dSopenharmony_ci UnicodeString u_suffix; 4822e5b6d6dSopenharmony_ci return getSuffixAfterPrefix(s, limit, prefix, u_suffix) && 4832e5b6d6dSopenharmony_ci toInvariant(u_suffix, suffix, errorCode); 4842e5b6d6dSopenharmony_ci} 4852e5b6d6dSopenharmony_ci 4862e5b6d6dSopenharmony_cibool readTestCase(const UnicodeString &line, TestCase &test, IcuTestErrorCode &errorCode) { 4872e5b6d6dSopenharmony_ci if (errorCode.isFailure()) { return false; } 4882e5b6d6dSopenharmony_ci ++test.lineNr; 4892e5b6d6dSopenharmony_ci // Start of comment, or end of line, minus trailing spaces. 4902e5b6d6dSopenharmony_ci int32_t limit = line.indexOf(u'#'); 4912e5b6d6dSopenharmony_ci if (limit < 0) { 4922e5b6d6dSopenharmony_ci limit = line.length(); 4932e5b6d6dSopenharmony_ci // Remove trailing CR LF. 4942e5b6d6dSopenharmony_ci char16_t c; 4952e5b6d6dSopenharmony_ci while (limit > 0 && ((c = line.charAt(limit - 1)) == u'\n' || c == u'\r')) { 4962e5b6d6dSopenharmony_ci --limit; 4972e5b6d6dSopenharmony_ci } 4982e5b6d6dSopenharmony_ci } 4992e5b6d6dSopenharmony_ci // Remove spaces before comment or at the end of the line. 5002e5b6d6dSopenharmony_ci char16_t c; 5012e5b6d6dSopenharmony_ci while (limit > 0 && ((c = line.charAt(limit - 1)) == u' ' || c == u'\t')) { 5022e5b6d6dSopenharmony_ci --limit; 5032e5b6d6dSopenharmony_ci } 5042e5b6d6dSopenharmony_ci if (limit == 0) { // empty line 5052e5b6d6dSopenharmony_ci return false; 5062e5b6d6dSopenharmony_ci } 5072e5b6d6dSopenharmony_ci if (line.startsWith(u"** test: ")) { 5082e5b6d6dSopenharmony_ci test.reset(); 5092e5b6d6dSopenharmony_ci } else if (getInvariantSuffixAfterPrefix(line, limit, u"@supported=", 5102e5b6d6dSopenharmony_ci test.supported, errorCode)) { 5112e5b6d6dSopenharmony_ci } else if (getInvariantSuffixAfterPrefix(line, limit, u"@default=", 5122e5b6d6dSopenharmony_ci test.def, errorCode)) { 5132e5b6d6dSopenharmony_ci } else if (getSuffixAfterPrefix(line, limit, u"@favor=", test.favor)) { 5142e5b6d6dSopenharmony_ci } else if (getSuffixAfterPrefix(line, limit, u"@threshold=", test.threshold)) { 5152e5b6d6dSopenharmony_ci } else { 5162e5b6d6dSopenharmony_ci int32_t matchSep = line.indexOf(u">>"); 5172e5b6d6dSopenharmony_ci // >> before an inline comment, and followed by more than white space. 5182e5b6d6dSopenharmony_ci if (0 <= matchSep && (matchSep + 2) < limit) { 5192e5b6d6dSopenharmony_ci toInvariant(line.tempSubStringBetween(0, matchSep).trim(), test.desired, errorCode); 5202e5b6d6dSopenharmony_ci test.expDesired.clear(); 5212e5b6d6dSopenharmony_ci test.expCombined.clear(); 5222e5b6d6dSopenharmony_ci int32_t start = matchSep + 2; 5232e5b6d6dSopenharmony_ci int32_t expLimit = line.indexOf(u'|', start); 5242e5b6d6dSopenharmony_ci if (expLimit < 0) { 5252e5b6d6dSopenharmony_ci toInvariant(line.tempSubStringBetween(start, limit).trim(), 5262e5b6d6dSopenharmony_ci test.expMatch, errorCode); 5272e5b6d6dSopenharmony_ci } else { 5282e5b6d6dSopenharmony_ci toInvariant(line.tempSubStringBetween(start, expLimit).trim(), 5292e5b6d6dSopenharmony_ci test.expMatch, errorCode); 5302e5b6d6dSopenharmony_ci start = expLimit + 1; 5312e5b6d6dSopenharmony_ci expLimit = line.indexOf(u'|', start); 5322e5b6d6dSopenharmony_ci if (expLimit < 0) { 5332e5b6d6dSopenharmony_ci toInvariant(line.tempSubStringBetween(start, limit).trim(), 5342e5b6d6dSopenharmony_ci test.expDesired, errorCode); 5352e5b6d6dSopenharmony_ci } else { 5362e5b6d6dSopenharmony_ci toInvariant(line.tempSubStringBetween(start, expLimit).trim(), 5372e5b6d6dSopenharmony_ci test.expDesired, errorCode); 5382e5b6d6dSopenharmony_ci toInvariant(line.tempSubStringBetween(expLimit + 1, limit).trim(), 5392e5b6d6dSopenharmony_ci test.expCombined, errorCode); 5402e5b6d6dSopenharmony_ci } 5412e5b6d6dSopenharmony_ci } 5422e5b6d6dSopenharmony_ci return errorCode.isSuccess(); 5432e5b6d6dSopenharmony_ci } else { 5442e5b6d6dSopenharmony_ci errorCode.set(U_INVALID_FORMAT_ERROR); 5452e5b6d6dSopenharmony_ci } 5462e5b6d6dSopenharmony_ci } 5472e5b6d6dSopenharmony_ci return false; 5482e5b6d6dSopenharmony_ci} 5492e5b6d6dSopenharmony_ci 5502e5b6d6dSopenharmony_ciLocale *getLocaleOrNull(const CharString &s, Locale &locale) { 5512e5b6d6dSopenharmony_ci if (s == "null") { 5522e5b6d6dSopenharmony_ci return nullptr; 5532e5b6d6dSopenharmony_ci } else { 5542e5b6d6dSopenharmony_ci return &(locale = Locale(s.data())); 5552e5b6d6dSopenharmony_ci } 5562e5b6d6dSopenharmony_ci} 5572e5b6d6dSopenharmony_ci 5582e5b6d6dSopenharmony_ci} // namespace 5592e5b6d6dSopenharmony_ci 5602e5b6d6dSopenharmony_ciUBool LocaleMatcherTest::dataDriven(const TestCase &test, IcuTestErrorCode &errorCode) { 5612e5b6d6dSopenharmony_ci LocaleMatcher::Builder builder; 5622e5b6d6dSopenharmony_ci builder.setSupportedLocalesFromListString(test.supported.toStringPiece()); 5632e5b6d6dSopenharmony_ci if (!test.def.isEmpty()) { 5642e5b6d6dSopenharmony_ci Locale defaultLocale(test.def.data()); 5652e5b6d6dSopenharmony_ci builder.setDefaultLocale(&defaultLocale); 5662e5b6d6dSopenharmony_ci } 5672e5b6d6dSopenharmony_ci if (!test.favor.isEmpty()) { 5682e5b6d6dSopenharmony_ci ULocMatchFavorSubtag favor; 5692e5b6d6dSopenharmony_ci if (test.favor == u"normal") { 5702e5b6d6dSopenharmony_ci favor = ULOCMATCH_FAVOR_LANGUAGE; 5712e5b6d6dSopenharmony_ci } else if (test.favor == u"script") { 5722e5b6d6dSopenharmony_ci favor = ULOCMATCH_FAVOR_SCRIPT; 5732e5b6d6dSopenharmony_ci } else { 5742e5b6d6dSopenharmony_ci errln(UnicodeString(u"unsupported FavorSubtag value ") + test.favor); 5752e5b6d6dSopenharmony_ci return false; 5762e5b6d6dSopenharmony_ci } 5772e5b6d6dSopenharmony_ci builder.setFavorSubtag(favor); 5782e5b6d6dSopenharmony_ci } 5792e5b6d6dSopenharmony_ci if (!test.threshold.isEmpty()) { 5802e5b6d6dSopenharmony_ci infoln("skipping test case on line %d with non-default threshold: not exposed via API", 5812e5b6d6dSopenharmony_ci (int)test.lineNr); 5822e5b6d6dSopenharmony_ci return true; 5832e5b6d6dSopenharmony_ci // int32_t threshold = Integer.valueOf(test.threshold); 5842e5b6d6dSopenharmony_ci // builder.internalSetThresholdDistance(threshold); 5852e5b6d6dSopenharmony_ci } 5862e5b6d6dSopenharmony_ci LocaleMatcher matcher = builder.build(errorCode); 5872e5b6d6dSopenharmony_ci if (errorCode.errIfFailureAndReset("LocaleMatcher::Builder::build()")) { 5882e5b6d6dSopenharmony_ci return false; 5892e5b6d6dSopenharmony_ci } 5902e5b6d6dSopenharmony_ci 5912e5b6d6dSopenharmony_ci Locale expMatchLocale(""); 5922e5b6d6dSopenharmony_ci Locale *expMatch = getLocaleOrNull(test.expMatch, expMatchLocale); 5932e5b6d6dSopenharmony_ci if (test.expDesired.isEmpty() && test.expCombined.isEmpty()) { 5942e5b6d6dSopenharmony_ci StringPiece desiredSP = test.desired.toStringPiece(); 5952e5b6d6dSopenharmony_ci const Locale *bestSupported = matcher.getBestMatchForListString(desiredSP, errorCode); 5962e5b6d6dSopenharmony_ci if (!assertEquals("bestSupported from string", 5972e5b6d6dSopenharmony_ci locString(expMatch), locString(bestSupported))) { 5982e5b6d6dSopenharmony_ci return false; 5992e5b6d6dSopenharmony_ci } 6002e5b6d6dSopenharmony_ci LocalePriorityList desired(test.desired.toStringPiece(), errorCode); 6012e5b6d6dSopenharmony_ci LocalePriorityList::Iterator desiredIter = desired.iterator(); 6022e5b6d6dSopenharmony_ci if (desired.getLength() == 1) { 6032e5b6d6dSopenharmony_ci const Locale &desiredLocale = desiredIter.next(); 6042e5b6d6dSopenharmony_ci bestSupported = matcher.getBestMatch(desiredLocale, errorCode); 6052e5b6d6dSopenharmony_ci UBool ok = assertEquals("bestSupported from Locale", 6062e5b6d6dSopenharmony_ci locString(expMatch), locString(bestSupported)); 6072e5b6d6dSopenharmony_ci 6082e5b6d6dSopenharmony_ci LocaleMatcher::Result result = matcher.getBestMatchResult(desiredLocale, errorCode); 6092e5b6d6dSopenharmony_ci return ok & assertEquals("result.getSupportedLocale from Locale", 6102e5b6d6dSopenharmony_ci locString(expMatch), locString(result.getSupportedLocale())); 6112e5b6d6dSopenharmony_ci } else { 6122e5b6d6dSopenharmony_ci bestSupported = matcher.getBestMatch(desiredIter, errorCode); 6132e5b6d6dSopenharmony_ci return assertEquals("bestSupported from Locale iterator", 6142e5b6d6dSopenharmony_ci locString(expMatch), locString(bestSupported)); 6152e5b6d6dSopenharmony_ci } 6162e5b6d6dSopenharmony_ci } else { 6172e5b6d6dSopenharmony_ci LocalePriorityList desired(test.desired.toStringPiece(), errorCode); 6182e5b6d6dSopenharmony_ci LocalePriorityList::Iterator desiredIter = desired.iterator(); 6192e5b6d6dSopenharmony_ci LocaleMatcher::Result result = matcher.getBestMatchResult(desiredIter, errorCode); 6202e5b6d6dSopenharmony_ci UBool ok = assertEquals("result.getSupportedLocale from Locales", 6212e5b6d6dSopenharmony_ci locString(expMatch), locString(result.getSupportedLocale())); 6222e5b6d6dSopenharmony_ci if (!test.expDesired.isEmpty()) { 6232e5b6d6dSopenharmony_ci Locale expDesiredLocale(""); 6242e5b6d6dSopenharmony_ci Locale *expDesired = getLocaleOrNull(test.expDesired, expDesiredLocale); 6252e5b6d6dSopenharmony_ci ok &= assertEquals("result.getDesiredLocale from Locales", 6262e5b6d6dSopenharmony_ci locString(expDesired), locString(result.getDesiredLocale())); 6272e5b6d6dSopenharmony_ci } 6282e5b6d6dSopenharmony_ci if (!test.expCombined.isEmpty()) { 6292e5b6d6dSopenharmony_ci if (test.expMatch.contains("-u-")) { 6302e5b6d6dSopenharmony_ci logKnownIssue("20727", 6312e5b6d6dSopenharmony_ci UnicodeString(u"ignoring makeResolvedLocale() line ") + test.lineNr); 6322e5b6d6dSopenharmony_ci return ok; 6332e5b6d6dSopenharmony_ci } 6342e5b6d6dSopenharmony_ci Locale expCombinedLocale(""); 6352e5b6d6dSopenharmony_ci Locale *expCombined = getLocaleOrNull(test.expCombined, expCombinedLocale); 6362e5b6d6dSopenharmony_ci Locale combined = result.makeResolvedLocale(errorCode); 6372e5b6d6dSopenharmony_ci ok &= assertEquals("combined Locale from Locales", 6382e5b6d6dSopenharmony_ci locString(expCombined), locString(&combined)); 6392e5b6d6dSopenharmony_ci } 6402e5b6d6dSopenharmony_ci return ok; 6412e5b6d6dSopenharmony_ci } 6422e5b6d6dSopenharmony_ci} 6432e5b6d6dSopenharmony_ci 6442e5b6d6dSopenharmony_civoid LocaleMatcherTest::testDataDriven() { 6452e5b6d6dSopenharmony_ci IcuTestErrorCode errorCode(*this, "testDataDriven"); 6462e5b6d6dSopenharmony_ci CharString path(getSourceTestData(errorCode), errorCode); 6472e5b6d6dSopenharmony_ci path.appendPathPart("localeMatcherTest.txt", errorCode); 6482e5b6d6dSopenharmony_ci const char *codePage = "UTF-8"; 6492e5b6d6dSopenharmony_ci LocalUCHARBUFPointer f(ucbuf_open(path.data(), &codePage, true, false, errorCode)); 6502e5b6d6dSopenharmony_ci if(errorCode.errIfFailureAndReset("ucbuf_open(localeMatcherTest.txt)")) { 6512e5b6d6dSopenharmony_ci return; 6522e5b6d6dSopenharmony_ci } 6532e5b6d6dSopenharmony_ci int32_t lineLength; 6542e5b6d6dSopenharmony_ci const UChar *p; 6552e5b6d6dSopenharmony_ci UnicodeString line; 6562e5b6d6dSopenharmony_ci TestCase test; 6572e5b6d6dSopenharmony_ci int32_t numPassed = 0; 6582e5b6d6dSopenharmony_ci while ((p = ucbuf_readline(f.getAlias(), &lineLength, errorCode)) != nullptr && 6592e5b6d6dSopenharmony_ci errorCode.isSuccess()) { 6602e5b6d6dSopenharmony_ci line.setTo(false, p, lineLength); 6612e5b6d6dSopenharmony_ci if (!readTestCase(line, test, errorCode)) { 6622e5b6d6dSopenharmony_ci if (errorCode.errIfFailureAndReset( 6632e5b6d6dSopenharmony_ci "test data syntax error on line %d", (int)test.lineNr)) { 6642e5b6d6dSopenharmony_ci infoln(line); 6652e5b6d6dSopenharmony_ci } 6662e5b6d6dSopenharmony_ci continue; 6672e5b6d6dSopenharmony_ci } 6682e5b6d6dSopenharmony_ci UBool ok = dataDriven(test, errorCode); 6692e5b6d6dSopenharmony_ci if (errorCode.errIfFailureAndReset("test error on line %d", (int)test.lineNr)) { 6702e5b6d6dSopenharmony_ci infoln(line); 6712e5b6d6dSopenharmony_ci } else if (!ok) { 6722e5b6d6dSopenharmony_ci infoln("test failure on line %d", (int)test.lineNr); 6732e5b6d6dSopenharmony_ci infoln(line); 6742e5b6d6dSopenharmony_ci } else { 6752e5b6d6dSopenharmony_ci ++numPassed; 6762e5b6d6dSopenharmony_ci } 6772e5b6d6dSopenharmony_ci } 6782e5b6d6dSopenharmony_ci infoln("number of passing test cases: %d", (int)numPassed); 6792e5b6d6dSopenharmony_ci} 680