1 // © 2019 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html#License
4 // localematchertest.cpp
5 // created: 2019jul04 Markus W. Scherer
10 #include "unicode/utypes.h"
11 #include "unicode/localematcher.h"
12 #include "unicode/locid.h"
16 #include "localeprioritylist.h"
19 #define ARRAY_RANGE(array) (array), ((array) + UPRV_LENGTHOF(array))
23 const char *locString(const Locale
*loc
) {
24 return loc
!= nullptr ? loc
->getName() : "(null)";
33 UnicodeString threshold
;
36 CharString expDesired
;
37 CharString expCombined
;
49 class LocaleMatcherTest
: public IntlTest
{
51 LocaleMatcherTest() {}
53 void runIndexedTest(int32_t index
, UBool exec
, const char *&name
, char *par
=NULL
);
56 void testCopyErrorTo();
58 void testSupportedDefault();
59 void testUnsupportedDefault();
62 void testResolvedLocale();
63 void testDataDriven();
66 UBool
dataDriven(const TestCase
&test
, IcuTestErrorCode
&errorCode
);
69 extern IntlTest
*createLocaleMatcherTest() {
70 return new LocaleMatcherTest();
73 void LocaleMatcherTest::runIndexedTest(int32_t index
, UBool exec
, const char *&name
, char * /*par*/) {
75 logln("TestSuite LocaleMatcherTest: ");
78 TESTCASE_AUTO(testEmpty
);
79 TESTCASE_AUTO(testCopyErrorTo
);
80 TESTCASE_AUTO(testBasics
);
81 TESTCASE_AUTO(testSupportedDefault
);
82 TESTCASE_AUTO(testUnsupportedDefault
);
83 TESTCASE_AUTO(testDemotion
);
84 TESTCASE_AUTO(testMatch
);
85 TESTCASE_AUTO(testResolvedLocale
);
86 TESTCASE_AUTO(testDataDriven
);
90 void LocaleMatcherTest::testEmpty() {
91 IcuTestErrorCode
errorCode(*this, "testEmpty");
92 LocaleMatcher matcher
= LocaleMatcher::Builder().build(errorCode
);
93 const Locale
*best
= matcher
.getBestMatch(Locale::getFrench(), errorCode
);
94 assertEquals("getBestMatch(fr)", "(null)", locString(best
));
95 LocaleMatcher::Result result
= matcher
.getBestMatchResult("fr", errorCode
);
96 assertEquals("getBestMatchResult(fr).des", "(null)", locString(result
.getDesiredLocale()));
97 assertEquals("getBestMatchResult(fr).desIndex", -1, result
.getDesiredIndex());
98 assertEquals("getBestMatchResult(fr).supp",
99 "(null)", locString(result
.getSupportedLocale()));
100 assertEquals("getBestMatchResult(fr).suppIndex",
101 -1, result
.getSupportedIndex());
104 void LocaleMatcherTest::testCopyErrorTo() {
105 IcuTestErrorCode
errorCode(*this, "testCopyErrorTo");
106 // The builder does not set any errors except out-of-memory.
108 LocaleMatcher::Builder builder
;
109 UErrorCode success
= U_ZERO_ERROR
;
110 assertFalse("no error", builder
.copyErrorTo(success
));
111 assertTrue("still success", U_SUCCESS(success
));
112 UErrorCode failure
= U_INVALID_FORMAT_ERROR
;
113 assertTrue("failure passed in", builder
.copyErrorTo(failure
));
114 assertEquals("same failure", U_INVALID_FORMAT_ERROR
, failure
);
117 void LocaleMatcherTest::testBasics() {
118 IcuTestErrorCode
errorCode(*this, "testBasics");
119 Locale locales
[] = { "fr", "en_GB", "en" };
121 LocaleMatcher matcher
= LocaleMatcher::Builder().
122 setSupportedLocales(ARRAY_RANGE(locales
)).build(errorCode
);
123 const Locale
*best
= matcher
.getBestMatch("en_GB", errorCode
);
124 assertEquals("fromRange.getBestMatch(en_GB)", "en_GB", locString(best
));
125 best
= matcher
.getBestMatch("en_US", errorCode
);
126 assertEquals("fromRange.getBestMatch(en_US)", "en", locString(best
));
127 best
= matcher
.getBestMatch("fr_FR", errorCode
);
128 assertEquals("fromRange.getBestMatch(fr_FR)", "fr", locString(best
));
129 best
= matcher
.getBestMatch("ja_JP", errorCode
);
130 assertEquals("fromRange.getBestMatch(ja_JP)", "fr", locString(best
));
132 // Code coverage: Variations of setting supported locales.
134 std::vector
<Locale
> locales
{ "fr", "en_GB", "en" };
135 LocaleMatcher matcher
= LocaleMatcher::Builder().
136 setSupportedLocales(locales
.begin(), locales
.end()).build(errorCode
);
137 const Locale
*best
= matcher
.getBestMatch("en_GB", errorCode
);
138 assertEquals("fromRange.getBestMatch(en_GB)", "en_GB", locString(best
));
139 best
= matcher
.getBestMatch("en_US", errorCode
);
140 assertEquals("fromRange.getBestMatch(en_US)", "en", locString(best
));
141 best
= matcher
.getBestMatch("fr_FR", errorCode
);
142 assertEquals("fromRange.getBestMatch(fr_FR)", "fr", locString(best
));
143 best
= matcher
.getBestMatch("ja_JP", errorCode
);
144 assertEquals("fromRange.getBestMatch(ja_JP)", "fr", locString(best
));
147 Locale::RangeIterator
<Locale
*> iter(ARRAY_RANGE(locales
));
148 LocaleMatcher matcher
= LocaleMatcher::Builder().
149 setSupportedLocales(iter
).build(errorCode
);
150 const Locale
*best
= matcher
.getBestMatch("en_GB", errorCode
);
151 assertEquals("fromIter.getBestMatch(en_GB)", "en_GB", locString(best
));
152 best
= matcher
.getBestMatch("en_US", errorCode
);
153 assertEquals("fromIter.getBestMatch(en_US)", "en", locString(best
));
154 best
= matcher
.getBestMatch("fr_FR", errorCode
);
155 assertEquals("fromIter.getBestMatch(fr_FR)", "fr", locString(best
));
156 best
= matcher
.getBestMatch("ja_JP", errorCode
);
157 assertEquals("fromIter.getBestMatch(ja_JP)", "fr", locString(best
));
160 Locale
*pointers
[] = { locales
, locales
+ 1, locales
+ 2 };
161 // Lambda with explicit reference return type to prevent copy-constructing a temporary
162 // which would be destructed right away.
163 LocaleMatcher matcher
= LocaleMatcher::Builder().
164 setSupportedLocalesViaConverter(
165 ARRAY_RANGE(pointers
), [](const Locale
*p
) -> const Locale
& { return *p
; }).
167 const Locale
*best
= matcher
.getBestMatch("en_GB", errorCode
);
168 assertEquals("viaConverter.getBestMatch(en_GB)", "en_GB", locString(best
));
169 best
= matcher
.getBestMatch("en_US", errorCode
);
170 assertEquals("viaConverter.getBestMatch(en_US)", "en", locString(best
));
171 best
= matcher
.getBestMatch("fr_FR", errorCode
);
172 assertEquals("viaConverter.getBestMatch(fr_FR)", "fr", locString(best
));
173 best
= matcher
.getBestMatch("ja_JP", errorCode
);
174 assertEquals("viaConverter.getBestMatch(ja_JP)", "fr", locString(best
));
177 LocaleMatcher matcher
= LocaleMatcher::Builder().
178 addSupportedLocale(locales
[0]).
179 addSupportedLocale(locales
[1]).
180 addSupportedLocale(locales
[2]).
182 const Locale
*best
= matcher
.getBestMatch("en_GB", errorCode
);
183 assertEquals("added.getBestMatch(en_GB)", "en_GB", locString(best
));
184 best
= matcher
.getBestMatch("en_US", errorCode
);
185 assertEquals("added.getBestMatch(en_US)", "en", locString(best
));
186 best
= matcher
.getBestMatch("fr_FR", errorCode
);
187 assertEquals("added.getBestMatch(fr_FR)", "fr", locString(best
));
188 best
= matcher
.getBestMatch("ja_JP", errorCode
);
189 assertEquals("added.getBestMatch(ja_JP)", "fr", locString(best
));
192 LocaleMatcher matcher
= LocaleMatcher::Builder().
193 setSupportedLocalesFromListString(
194 " el, fr;q=0.555555, en-GB ; q = 0.88 , el; q =0, en;q=0.88 , fr ").
196 const Locale
*best
= matcher
.getBestMatchForListString("el, fr, fr;q=0, en-GB", errorCode
);
197 assertEquals("fromList.getBestMatch(en_GB)", "en_GB", locString(best
));
198 best
= matcher
.getBestMatch("en_US", errorCode
);
199 assertEquals("fromList.getBestMatch(en_US)", "en", locString(best
));
200 best
= matcher
.getBestMatch("fr_FR", errorCode
);
201 assertEquals("fromList.getBestMatch(fr_FR)", "fr", locString(best
));
202 best
= matcher
.getBestMatch("ja_JP", errorCode
);
203 assertEquals("fromList.getBestMatch(ja_JP)", "fr", locString(best
));
207 LocalePriorityList
list("fr, en-GB", errorCode
);
208 LocalePriorityList::Iterator
iter(list
.iterator());
209 LocaleMatcher matcher
= LocaleMatcher::Builder().
210 setSupportedLocales(iter
).
211 addSupportedLocale(Locale::getEnglish()).
212 setDefaultLocale(&Locale::getGerman()).
214 const Locale
*best
= matcher
.getBestMatch("en_GB", errorCode
);
215 assertEquals("withDefault.getBestMatch(en_GB)", "en_GB", locString(best
));
216 best
= matcher
.getBestMatch("en_US", errorCode
);
217 assertEquals("withDefault.getBestMatch(en_US)", "en", locString(best
));
218 best
= matcher
.getBestMatch("fr_FR", errorCode
);
219 assertEquals("withDefault.getBestMatch(fr_FR)", "fr", locString(best
));
220 best
= matcher
.getBestMatch("ja_JP", errorCode
);
221 assertEquals("withDefault.getBestMatch(ja_JP)", "de", locString(best
));
223 Locale
desired("en_GB"); // distinct object from Locale.UK
224 LocaleMatcher::Result result
= matcher
.getBestMatchResult(desired
, errorCode
);
225 assertTrue("withDefault: exactly desired en-GB object",
226 &desired
== result
.getDesiredLocale());
227 assertEquals("withDefault: en-GB desired index", 0, result
.getDesiredIndex());
228 assertEquals("withDefault: en-GB supported",
229 "en_GB", locString(result
.getSupportedLocale()));
230 assertEquals("withDefault: en-GB supported index", 1, result
.getSupportedIndex());
232 LocalePriorityList
list2("ja-JP, en-US", errorCode
);
233 LocalePriorityList::Iterator
iter2(list2
.iterator());
234 result
= matcher
.getBestMatchResult(iter2
, errorCode
);
235 assertEquals("withDefault: ja-JP, en-US desired index", 1, result
.getDesiredIndex());
236 assertEquals("withDefault: ja-JP, en-US desired",
237 "en_US", locString(result
.getDesiredLocale()));
239 desired
= Locale("en", "US"); // distinct object from Locale.US
240 result
= matcher
.getBestMatchResult(desired
, errorCode
);
241 assertTrue("withDefault: exactly desired en-US object",
242 &desired
== result
.getDesiredLocale());
243 assertEquals("withDefault: en-US desired index", 0, result
.getDesiredIndex());
244 assertEquals("withDefault: en-US supported", "en", locString(result
.getSupportedLocale()));
245 assertEquals("withDefault: en-US supported index", 2, result
.getSupportedIndex());
247 result
= matcher
.getBestMatchResult("ja_JP", errorCode
);
248 assertEquals("withDefault: ja-JP desired", "(null)", locString(result
.getDesiredLocale()));
249 assertEquals("withDefault: ja-JP desired index", -1, result
.getDesiredIndex());
250 assertEquals("withDefault: ja-JP supported", "de", locString(result
.getSupportedLocale()));
251 assertEquals("withDefault: ja-JP supported index", -1, result
.getSupportedIndex());
255 void LocaleMatcherTest::testSupportedDefault() {
256 // The default locale is one of the supported locales.
257 IcuTestErrorCode
errorCode(*this, "testSupportedDefault");
258 Locale locales
[] = { "fr", "en_GB", "en" };
259 LocaleMatcher matcher
= LocaleMatcher::Builder().
260 setSupportedLocales(ARRAY_RANGE(locales
)).
261 setDefaultLocale(&locales
[1]).
263 const Locale
*best
= matcher
.getBestMatch("en_GB", errorCode
);
264 assertEquals("getBestMatch(en_GB)", "en_GB", locString(best
));
265 best
= matcher
.getBestMatch("en_US", errorCode
);
266 assertEquals("getBestMatch(en_US)", "en", locString(best
));
267 best
= matcher
.getBestMatch("fr_FR", errorCode
);
268 assertEquals("getBestMatch(fr_FR)", "fr", locString(best
));
269 best
= matcher
.getBestMatch("ja_JP", errorCode
);
270 assertEquals("getBestMatch(ja_JP)", "en_GB", locString(best
));
271 LocaleMatcher::Result result
= matcher
.getBestMatchResult("ja_JP", errorCode
);
272 assertEquals("getBestMatchResult(ja_JP).supp",
273 "en_GB", locString(result
.getSupportedLocale()));
274 assertEquals("getBestMatchResult(ja_JP).suppIndex",
275 1, result
.getSupportedIndex());
278 void LocaleMatcherTest::testUnsupportedDefault() {
279 // The default locale does not match any of the supported locales.
280 IcuTestErrorCode
errorCode(*this, "testUnsupportedDefault");
281 Locale locales
[] = { "fr", "en_GB", "en" };
283 LocaleMatcher matcher
= LocaleMatcher::Builder().
284 setSupportedLocales(ARRAY_RANGE(locales
)).
285 setDefaultLocale(&def
).
287 const Locale
*best
= matcher
.getBestMatch("en_GB", errorCode
);
288 assertEquals("getBestMatch(en_GB)", "en_GB", locString(best
));
289 best
= matcher
.getBestMatch("en_US", errorCode
);
290 assertEquals("getBestMatch(en_US)", "en", locString(best
));
291 best
= matcher
.getBestMatch("fr_FR", errorCode
);
292 assertEquals("getBestMatch(fr_FR)", "fr", locString(best
));
293 best
= matcher
.getBestMatch("ja_JP", errorCode
);
294 assertEquals("getBestMatch(ja_JP)", "de", locString(best
));
295 LocaleMatcher::Result result
= matcher
.getBestMatchResult("ja_JP", errorCode
);
296 assertEquals("getBestMatchResult(ja_JP).supp",
297 "de", locString(result
.getSupportedLocale()));
298 assertEquals("getBestMatchResult(ja_JP).suppIndex",
299 -1, result
.getSupportedIndex());
302 void LocaleMatcherTest::testDemotion() {
303 IcuTestErrorCode
errorCode(*this, "testDemotion");
304 Locale supported
[] = { "fr", "de-CH", "it" };
305 Locale desired
[] = { "fr-CH", "de-CH", "it" };
307 LocaleMatcher noDemotion
= LocaleMatcher::Builder().
308 setSupportedLocales(ARRAY_RANGE(supported
)).
309 setDemotionPerDesiredLocale(ULOCMATCH_DEMOTION_NONE
).build(errorCode
);
310 Locale::RangeIterator
<Locale
*> desiredIter(ARRAY_RANGE(desired
));
311 assertEquals("no demotion",
312 "de_CH", locString(noDemotion
.getBestMatch(desiredIter
, errorCode
)));
316 LocaleMatcher regionDemotion
= LocaleMatcher::Builder().
317 setSupportedLocales(ARRAY_RANGE(supported
)).
318 setDemotionPerDesiredLocale(ULOCMATCH_DEMOTION_REGION
).build(errorCode
);
319 Locale::RangeIterator
<Locale
*> desiredIter(ARRAY_RANGE(desired
));
320 assertEquals("region demotion",
321 "fr", locString(regionDemotion
.getBestMatch(desiredIter
, errorCode
)));
325 void LocaleMatcherTest::testMatch() {
326 IcuTestErrorCode
errorCode(*this, "testMatch");
327 LocaleMatcher matcher
= LocaleMatcher::Builder().build(errorCode
);
329 // Java test function testMatch_exact()
330 Locale
en_CA("en_CA");
331 assertEquals("exact match", 1.0, matcher
.internalMatch(en_CA
, en_CA
, errorCode
));
334 Locale
ar_MK("ar_MK");
335 double match
= matcher
.internalMatch(ar_MK
, en_CA
, errorCode
);
336 assertTrue("mismatch: 0<=match<0.2", 0 <= match
&& match
< 0.2);
338 // testMatch_matchOnMaximized
339 Locale
und_TW("und_TW");
341 Locale
zh_Hant("zh_Hant");
342 double matchZh
= matcher
.internalMatch(und_TW
, zh
, errorCode
);
343 double matchZhHant
= matcher
.internalMatch(und_TW
, zh_Hant
, errorCode
);
344 assertTrue("und_TW should be closer to zh_Hant than to zh",
345 matchZh
< matchZhHant
);
346 Locale
en_Hant_TW("en_Hant_TW");
347 double matchEnHantTw
= matcher
.internalMatch(en_Hant_TW
, zh_Hant
, errorCode
);
348 assertTrue("zh_Hant should be closer to und_TW than to en_Hant_TW",
349 matchEnHantTw
< matchZhHant
);
350 assertTrue("zh should be closer to und_TW than to en_Hant_TW",
351 matchEnHantTw
< matchZh
);
354 void LocaleMatcherTest::testResolvedLocale() {
355 IcuTestErrorCode
errorCode(*this, "testResolvedLocale");
356 LocaleMatcher matcher
= LocaleMatcher::Builder().
357 addSupportedLocale("ar-EG").
359 Locale
desired("ar-SA-u-nu-latn");
360 LocaleMatcher::Result result
= matcher
.getBestMatchResult(desired
, errorCode
);
361 assertEquals("best", "ar_EG", locString(result
.getSupportedLocale()));
362 Locale resolved
= result
.makeResolvedLocale(errorCode
);
363 assertEquals("ar-EG + ar-SA-u-nu-latn = ar-SA-u-nu-latn",
365 resolved
.toLanguageTag
<std::string
>(errorCode
).data());
370 bool toInvariant(const UnicodeString
&s
, CharString
&inv
, ErrorCode
&errorCode
) {
371 if (errorCode
.isSuccess()) {
372 inv
.clear().appendInvariantChars(s
, errorCode
);
373 return errorCode
.isSuccess();
378 bool getSuffixAfterPrefix(const UnicodeString
&s
, int32_t limit
,
379 const UnicodeString
&prefix
, UnicodeString
&suffix
) {
380 if (prefix
.length() <= limit
&& s
.startsWith(prefix
)) {
381 suffix
.setTo(s
, prefix
.length(), limit
- prefix
.length());
388 bool getInvariantSuffixAfterPrefix(const UnicodeString
&s
, int32_t limit
,
389 const UnicodeString
&prefix
, CharString
&suffix
,
390 ErrorCode
&errorCode
) {
391 UnicodeString u_suffix
;
392 return getSuffixAfterPrefix(s
, limit
, prefix
, u_suffix
) &&
393 toInvariant(u_suffix
, suffix
, errorCode
);
396 bool readTestCase(const UnicodeString
&line
, TestCase
&test
, IcuTestErrorCode
&errorCode
) {
397 if (errorCode
.isFailure()) { return false; }
399 // Start of comment, or end of line, minus trailing spaces.
400 int32_t limit
= line
.indexOf(u
'#');
402 limit
= line
.length();
403 // Remove trailing CR LF.
405 while (limit
> 0 && ((c
= line
.charAt(limit
- 1)) == u
'\n' || c
== u
'\r')) {
409 // Remove spaces before comment or at the end of the line.
411 while (limit
> 0 && ((c
= line
.charAt(limit
- 1)) == u
' ' || c
== u
'\t')) {
414 if (limit
== 0) { // empty line
417 if (line
.startsWith(u
"** test: ")) {
419 } else if (getInvariantSuffixAfterPrefix(line
, limit
, u
"@supported=",
420 test
.supported
, errorCode
)) {
421 } else if (getInvariantSuffixAfterPrefix(line
, limit
, u
"@default=",
422 test
.def
, errorCode
)) {
423 } else if (getSuffixAfterPrefix(line
, limit
, u
"@favor=", test
.favor
)) {
424 } else if (getSuffixAfterPrefix(line
, limit
, u
"@threshold=", test
.threshold
)) {
426 int32_t matchSep
= line
.indexOf(u
">>");
427 // >> before an inline comment, and followed by more than white space.
428 if (0 <= matchSep
&& (matchSep
+ 2) < limit
) {
429 toInvariant(line
.tempSubStringBetween(0, matchSep
).trim(), test
.desired
, errorCode
);
430 test
.expDesired
.clear();
431 test
.expCombined
.clear();
432 int32_t start
= matchSep
+ 2;
433 int32_t expLimit
= line
.indexOf(u
'|', start
);
435 toInvariant(line
.tempSubStringBetween(start
, limit
).trim(),
436 test
.expMatch
, errorCode
);
438 toInvariant(line
.tempSubStringBetween(start
, expLimit
).trim(),
439 test
.expMatch
, errorCode
);
440 start
= expLimit
+ 1;
441 expLimit
= line
.indexOf(u
'|', start
);
443 toInvariant(line
.tempSubStringBetween(start
, limit
).trim(),
444 test
.expDesired
, errorCode
);
446 toInvariant(line
.tempSubStringBetween(start
, expLimit
).trim(),
447 test
.expDesired
, errorCode
);
448 toInvariant(line
.tempSubStringBetween(expLimit
+ 1, limit
).trim(),
449 test
.expCombined
, errorCode
);
452 return errorCode
.isSuccess();
454 errorCode
.set(U_INVALID_FORMAT_ERROR
);
460 Locale
*getLocaleOrNull(const CharString
&s
, Locale
&locale
) {
464 return &(locale
= Locale(s
.data()));
470 UBool
LocaleMatcherTest::dataDriven(const TestCase
&test
, IcuTestErrorCode
&errorCode
) {
471 LocaleMatcher::Builder builder
;
472 builder
.setSupportedLocalesFromListString(test
.supported
.toStringPiece());
473 if (!test
.def
.isEmpty()) {
474 Locale
defaultLocale(test
.def
.data());
475 builder
.setDefaultLocale(&defaultLocale
);
477 if (!test
.favor
.isEmpty()) {
478 ULocMatchFavorSubtag favor
;
479 if (test
.favor
== u
"normal") {
480 favor
= ULOCMATCH_FAVOR_LANGUAGE
;
481 } else if (test
.favor
== u
"script") {
482 favor
= ULOCMATCH_FAVOR_SCRIPT
;
484 errln(UnicodeString(u
"unsupported FavorSubtag value ") + test
.favor
);
487 builder
.setFavorSubtag(favor
);
489 if (!test
.threshold
.isEmpty()) {
490 infoln("skipping test case on line %d with non-default threshold: not exposed via API",
493 // int32_t threshold = Integer.valueOf(test.threshold);
494 // builder.internalSetThresholdDistance(threshold);
496 LocaleMatcher matcher
= builder
.build(errorCode
);
497 if (errorCode
.errIfFailureAndReset("LocaleMatcher::Builder::build()")) {
501 Locale
expMatchLocale("");
502 Locale
*expMatch
= getLocaleOrNull(test
.expMatch
, expMatchLocale
);
503 if (test
.expDesired
.isEmpty() && test
.expCombined
.isEmpty()) {
504 StringPiece desiredSP
= test
.desired
.toStringPiece();
505 const Locale
*bestSupported
= matcher
.getBestMatchForListString(desiredSP
, errorCode
);
506 if (!assertEquals("bestSupported from string",
507 locString(expMatch
), locString(bestSupported
))) {
510 LocalePriorityList
desired(test
.desired
.toStringPiece(), errorCode
);
511 LocalePriorityList::Iterator desiredIter
= desired
.iterator();
512 if (desired
.getLength() == 1) {
513 const Locale
&desiredLocale
= desiredIter
.next();
514 bestSupported
= matcher
.getBestMatch(desiredLocale
, errorCode
);
515 UBool ok
= assertEquals("bestSupported from Locale",
516 locString(expMatch
), locString(bestSupported
));
518 LocaleMatcher::Result result
= matcher
.getBestMatchResult(desiredLocale
, errorCode
);
519 return ok
& assertEquals("result.getSupportedLocale from Locale",
520 locString(expMatch
), locString(result
.getSupportedLocale()));
522 bestSupported
= matcher
.getBestMatch(desiredIter
, errorCode
);
523 return assertEquals("bestSupported from Locale iterator",
524 locString(expMatch
), locString(bestSupported
));
527 LocalePriorityList
desired(test
.desired
.toStringPiece(), errorCode
);
528 LocalePriorityList::Iterator desiredIter
= desired
.iterator();
529 LocaleMatcher::Result result
= matcher
.getBestMatchResult(desiredIter
, errorCode
);
530 UBool ok
= assertEquals("result.getSupportedLocale from Locales",
531 locString(expMatch
), locString(result
.getSupportedLocale()));
532 if (!test
.expDesired
.isEmpty()) {
533 Locale
expDesiredLocale("");
534 Locale
*expDesired
= getLocaleOrNull(test
.expDesired
, expDesiredLocale
);
535 ok
&= assertEquals("result.getDesiredLocale from Locales",
536 locString(expDesired
), locString(result
.getDesiredLocale()));
538 if (!test
.expCombined
.isEmpty()) {
539 if (test
.expMatch
.contains("-u-")) {
540 logKnownIssue("20727",
541 UnicodeString(u
"ignoring makeResolvedLocale() line ") + test
.lineNr
);
544 Locale
expCombinedLocale("");
545 Locale
*expCombined
= getLocaleOrNull(test
.expCombined
, expCombinedLocale
);
546 Locale combined
= result
.makeResolvedLocale(errorCode
);
547 ok
&= assertEquals("combined Locale from Locales",
548 locString(expCombined
), locString(&combined
));
554 void LocaleMatcherTest::testDataDriven() {
555 IcuTestErrorCode
errorCode(*this, "testDataDriven");
556 CharString
path(getSourceTestData(errorCode
), errorCode
);
557 path
.appendPathPart("localeMatcherTest.txt", errorCode
);
558 const char *codePage
= "UTF-8";
559 LocalUCHARBUFPointer
f(ucbuf_open(path
.data(), &codePage
, TRUE
, FALSE
, errorCode
));
560 if(errorCode
.errIfFailureAndReset("ucbuf_open(localeMatcherTest.txt)")) {
567 int32_t numPassed
= 0;
568 while ((p
= ucbuf_readline(f
.getAlias(), &lineLength
, errorCode
)) != nullptr &&
569 errorCode
.isSuccess()) {
570 line
.setTo(FALSE
, p
, lineLength
);
571 if (!readTestCase(line
, test
, errorCode
)) {
572 if (errorCode
.errIfFailureAndReset(
573 "test data syntax error on line %d", (int)test
.lineNr
)) {
578 UBool ok
= dataDriven(test
, errorCode
);
579 if (errorCode
.errIfFailureAndReset("test error on line %d", (int)test
.lineNr
)) {
582 infoln("test failure on line %d", (int)test
.lineNr
);
588 infoln("number of passing test cases: %d", (int)numPassed
);