1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /********************************************************************
4 * COPYRIGHT:
5 * Copyright (c) 1997-2016, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 ********************************************************************/
8
9 #include <algorithm>
10 #include <functional>
11 #include <iterator>
12 #include <set>
13 #include <utility>
14
15 #include "loctest.h"
16 #include "unicode/localebuilder.h"
17 #include "unicode/localpointer.h"
18 #include "unicode/decimfmt.h"
19 #include "unicode/ucurr.h"
20 #include "unicode/smpdtfmt.h"
21 #include "unicode/strenum.h"
22 #include "unicode/dtfmtsym.h"
23 #include "unicode/brkiter.h"
24 #include "unicode/coll.h"
25 #include "unicode/ustring.h"
26 #include "unicode/std_string.h"
27 #include "charstr.h"
28 #include "cmemory.h"
29 #include "cstring.h"
30 #include <stdio.h>
31 #include <string.h>
32 #include "putilimp.h"
33 #include "hash.h"
34 #include "locmap.h"
35 #include "uparse.h"
36 #include "ulocimp.h"
37
38 static const char* const rawData[33][8] = {
39
40 // language code
41 { "en", "fr", "ca", "el", "no", "it", "xx", "zh" },
42 // script code
43 { "", "", "", "", "", "", "", "Hans" },
44 // country code
45 { "US", "FR", "ES", "GR", "NO", "", "YY", "CN" },
46 // variant code
47 { "", "", "", "", "NY", "", "", "" },
48 // full name
49 { "en_US", "fr_FR", "ca_ES", "el_GR", "no_NO_NY", "it", "xx_YY", "zh_Hans_CN" },
50 // ISO-3 language
51 { "eng", "fra", "cat", "ell", "nor", "ita", "", "zho" },
52 // ISO-3 country
53 { "USA", "FRA", "ESP", "GRC", "NOR", "", "", "CHN" },
54 // LCID
55 { "409", "40c", "403", "408", "814", "10", "0", "804" },
56
57 // display language (English)
58 { "English", "French", "Catalan", "Greek", "Norwegian", "Italian", "xx", "Chinese" },
59 // display script (English)
60 { "", "", "", "", "", "", "", "Simplified Han" },
61 // display country (English)
62 { "United States", "France", "Spain", "Greece", "Norway", "", "YY", "China" },
63 // display variant (English)
64 { "", "", "", "", "NY", "", "", ""},
65 // display name (English)
66 // Updated no_NO_NY English display name for new pattern-based algorithm
67 // (part of Euro support).
68 { "English (United States)", "French (France)", "Catalan (Spain)", "Greek (Greece)", "Norwegian (Norway, NY)", "Italian", "xx (YY)", "Chinese (Simplified, China)" },
69
70 // display language (French)
71 { "anglais", "fran\\u00E7ais", "catalan", "grec", "norv\\u00E9gien", "italien", "xx", "chinois" },
72 // display script (French)
73 { "", "", "", "", "", "", "", "sinogrammes simplifi\\u00E9s" },
74 // display country (French)
75 { "\\u00C9tats-Unis", "France", "Espagne", "Gr\\u00E8ce", "Norv\\u00E8ge", "", "YY", "Chine" },
76 // display variant (French)
77 { "", "", "", "", "NY", "", "", "" },
78 // display name (French)
79 //{ "anglais (Etats-Unis)", "francais (France)", "catalan (Espagne)", "grec (Grece)", "norvegien (Norvege,Nynorsk)", "italien", "xx (YY)" },
80 { "anglais (\\u00C9tats-Unis)", "fran\\u00E7ais (France)", "catalan (Espagne)", "grec (Gr\\u00E8ce)", "norv\\u00E9gien (Norv\\u00E8ge, NY)", "italien", "xx (YY)", "chinois (simplifi\\u00E9, Chine)" },
81
82
83 /* display language (Catalan) */
84 { "angl\\u00E8s", "franc\\u00E8s", "catal\\u00E0", "grec", "noruec", "itali\\u00E0", "", "xin\\u00E8s" },
85 /* display script (Catalan) */
86 { "", "", "", "", "", "", "", "han simplificat" },
87 /* display country (Catalan) */
88 { "Estats Units", "Fran\\u00E7a", "Espanya", "Gr\\u00E8cia", "Noruega", "", "", "Xina" },
89 /* display variant (Catalan) */
90 { "", "", "", "", "NY", "", "" },
91 /* display name (Catalan) */
92 { "angl\\u00E8s (Estats Units)", "franc\\u00E8s (Fran\\u00E7a)", "catal\\u00E0 (Espanya)", "grec (Gr\\u00E8cia)", "noruec (Noruega, NY)", "itali\\u00E0", "", "xin\\u00E8s (simplificat, Xina)" },
93
94 // display language (Greek)[actual values listed below]
95 { "\\u0391\\u03b3\\u03b3\\u03bb\\u03b9\\u03ba\\u03ac",
96 "\\u0393\\u03b1\\u03bb\\u03bb\\u03b9\\u03ba\\u03ac",
97 "\\u039a\\u03b1\\u03c4\\u03b1\\u03bb\\u03b1\\u03bd\\u03b9\\u03ba\\u03ac",
98 "\\u0395\\u03bb\\u03bb\\u03b7\\u03bd\\u03b9\\u03ba\\u03ac",
99 "\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03b9\\u03ba\\u03ac",
100 "\\u0399\\u03c4\\u03b1\\u03bb\\u03b9\\u03ba\\u03ac",
101 "",
102 "\\u039A\\u03B9\\u03BD\\u03B5\\u03B6\\u03B9\\u03BA\\u03AC"
103 },
104 // display script (Greek)
105 { "", "", "", "", "", "", "", "\\u0391\\u03c0\\u03bb\\u03bf\\u03c0\\u03bf\\u03b9\\u03b7\\u03bc\\u03ad\\u03bd\\u03bf \\u03a7\\u03b1\\u03bd" },
106 // display country (Greek)[actual values listed below]
107 { "\\u0397\\u03BD\\u03C9\\u03BC\\u03AD\\u03BD\\u03B5\\u03C2 \\u03A0\\u03BF\\u03BB\\u03B9\\u03C4\\u03B5\\u03AF\\u03B5\\u03C2",
108 "\\u0393\\u03b1\\u03bb\\u03bb\\u03af\\u03b1",
109 "\\u0399\\u03c3\\u03c0\\u03b1\\u03bd\\u03af\\u03b1",
110 "\\u0395\\u03bb\\u03bb\\u03ac\\u03b4\\u03b1",
111 "\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03af\\u03b1",
112 "",
113 "",
114 "\\u039A\\u03AF\\u03BD\\u03B1"
115 },
116 // display variant (Greek)
117 { "", "", "", "", "NY", "", "" },
118 // display name (Greek)[actual values listed below]
119 { "\\u0391\\u03b3\\u03b3\\u03bb\\u03b9\\u03ba\\u03ac (\\u0397\\u03BD\\u03C9\\u03BC\\u03AD\\u03BD\\u03B5\\u03C2 \\u03A0\\u03BF\\u03BB\\u03B9\\u03C4\\u03B5\\u03AF\\u03B5\\u03C2)",
120 "\\u0393\\u03b1\\u03bb\\u03bb\\u03b9\\u03ba\\u03ac (\\u0393\\u03b1\\u03bb\\u03bb\\u03af\\u03b1)",
121 "\\u039a\\u03b1\\u03c4\\u03b1\\u03bb\\u03b1\\u03bd\\u03b9\\u03ba\\u03ac (\\u0399\\u03c3\\u03c0\\u03b1\\u03bd\\u03af\\u03b1)",
122 "\\u0395\\u03bb\\u03bb\\u03b7\\u03bd\\u03b9\\u03ba\\u03ac (\\u0395\\u03bb\\u03bb\\u03ac\\u03b4\\u03b1)",
123 "\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03b9\\u03ba\\u03ac (\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03af\\u03b1, NY)",
124 "\\u0399\\u03c4\\u03b1\\u03bb\\u03b9\\u03ba\\u03ac",
125 "",
126 "\\u039A\\u03B9\\u03BD\\u03B5\\u03B6\\u03B9\\u03BA\\u03AC (\\u0391\\u03c0\\u03bb\\u03bf\\u03c0\\u03bf\\u03b9\\u03b7\\u03bc\\u03ad\\u03bd\\u03bf, \\u039A\\u03AF\\u03BD\\u03B1)"
127 },
128
129 // display language (<root>)
130 { "English", "French", "Catalan", "Greek", "Norwegian", "Italian", "xx", "" },
131 // display script (<root>)
132 { "", "", "", "", "", "", "", ""},
133 // display country (<root>)
134 { "United States", "France", "Spain", "Greece", "Norway", "", "YY", "" },
135 // display variant (<root>)
136 { "", "", "", "", "Nynorsk", "", "", ""},
137 // display name (<root>)
138 //{ "English (United States)", "French (France)", "Catalan (Spain)", "Greek (Greece)", "Norwegian (Norway,Nynorsk)", "Italian", "xx (YY)" },
139 { "English (United States)", "French (France)", "Catalan (Spain)", "Greek (Greece)", "Norwegian (Norway,NY)", "Italian", "xx (YY)", "" }
140 };
141
142
143 /*
144 Usage:
145 test_assert( Test (should be true) )
146
147 Example:
148 test_assert(i==3);
149
150 the macro is ugly but makes the tests pretty.
151 */
152
153 #define test_assert(test) UPRV_BLOCK_MACRO_BEGIN { \
154 if(!(test)) \
155 errln("FAIL: " #test " was not true. In " __FILE__ " on line %d", __LINE__ ); \
156 else \
157 logln("PASS: asserted " #test); \
158 } UPRV_BLOCK_MACRO_END
159
160 /*
161 Usage:
162 test_assert_print( Test (should be true), printable )
163
164 Example:
165 test_assert(i==3, toString(i));
166
167 the macro is ugly but makes the tests pretty.
168 */
169
170 #define test_assert_print(test,print) UPRV_BLOCK_MACRO_BEGIN { \
171 if(!(test)) \
172 errln("FAIL: " #test " was not true. " + UnicodeString(print) ); \
173 else \
174 logln("PASS: asserted " #test "-> " + UnicodeString(print)); \
175 } UPRV_BLOCK_MACRO_END
176
177
178 #define test_dumpLocale(l) UPRV_BLOCK_MACRO_BEGIN { \
179 logln(#l " = " + UnicodeString(l.getName(), "")); \
180 } UPRV_BLOCK_MACRO_END
181
LocaleTest()182 LocaleTest::LocaleTest()
183 : dataTable(nullptr)
184 {
185 setUpDataTable();
186 }
187
~LocaleTest()188 LocaleTest::~LocaleTest()
189 {
190 if (dataTable != 0) {
191 for (int32_t i = 0; i < 33; i++) {
192 delete []dataTable[i];
193 }
194 delete []dataTable;
195 dataTable = 0;
196 }
197 }
198
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)199 void LocaleTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
200 {
201 TESTCASE_AUTO_BEGIN;
202 TESTCASE_AUTO(TestBug11421); // Must run early in list to trigger failure.
203 TESTCASE_AUTO(TestBasicGetters);
204 TESTCASE_AUTO(TestSimpleResourceInfo);
205 TESTCASE_AUTO(TestDisplayNames);
206 TESTCASE_AUTO(TestSimpleObjectStuff);
207 TESTCASE_AUTO(TestPOSIXParsing);
208 TESTCASE_AUTO(TestGetAvailableLocales);
209 TESTCASE_AUTO(TestDataDirectory);
210 TESTCASE_AUTO(TestISO3Fallback);
211 TESTCASE_AUTO(TestGetLangsAndCountries);
212 TESTCASE_AUTO(TestSimpleDisplayNames);
213 TESTCASE_AUTO(TestUninstalledISO3Names);
214 TESTCASE_AUTO(TestAtypicalLocales);
215 #if !UCONFIG_NO_FORMATTING
216 TESTCASE_AUTO(TestThaiCurrencyFormat);
217 TESTCASE_AUTO(TestEuroSupport);
218 #endif
219 TESTCASE_AUTO(TestToString);
220 #if !UCONFIG_NO_FORMATTING
221 TESTCASE_AUTO(Test4139940);
222 TESTCASE_AUTO(Test4143951);
223 #endif
224 TESTCASE_AUTO(Test4147315);
225 TESTCASE_AUTO(Test4147317);
226 TESTCASE_AUTO(Test4147552);
227 TESTCASE_AUTO(TestVariantParsing);
228 TESTCASE_AUTO(Test20639_DeprecatesISO3Language);
229 #if !UCONFIG_NO_FORMATTING
230 TESTCASE_AUTO(Test4105828);
231 #endif
232 TESTCASE_AUTO(TestSetIsBogus);
233 TESTCASE_AUTO(TestParallelAPIValues);
234 TESTCASE_AUTO(TestAddLikelySubtags);
235 TESTCASE_AUTO(TestMinimizeSubtags);
236 TESTCASE_AUTO(TestAddLikelyAndMinimizeSubtags);
237 TESTCASE_AUTO(TestKeywordVariants);
238 TESTCASE_AUTO(TestCreateUnicodeKeywords);
239 TESTCASE_AUTO(TestKeywordVariantParsing);
240 TESTCASE_AUTO(TestCreateKeywordSet);
241 TESTCASE_AUTO(TestCreateKeywordSetEmpty);
242 TESTCASE_AUTO(TestCreateKeywordSetWithPrivateUse);
243 TESTCASE_AUTO(TestCreateUnicodeKeywordSet);
244 TESTCASE_AUTO(TestCreateUnicodeKeywordSetEmpty);
245 TESTCASE_AUTO(TestCreateUnicodeKeywordSetWithPrivateUse);
246 TESTCASE_AUTO(TestGetKeywordValueStdString);
247 TESTCASE_AUTO(TestGetUnicodeKeywordValueStdString);
248 TESTCASE_AUTO(TestSetKeywordValue);
249 TESTCASE_AUTO(TestSetKeywordValueStringPiece);
250 TESTCASE_AUTO(TestSetUnicodeKeywordValueStringPiece);
251 TESTCASE_AUTO(TestGetBaseName);
252 #if !UCONFIG_NO_FILE_IO
253 TESTCASE_AUTO(TestGetLocale);
254 #endif
255 TESTCASE_AUTO(TestVariantWithOutCountry);
256 TESTCASE_AUTO(TestCanonicalization);
257 TESTCASE_AUTO(TestCurrencyByDate);
258 TESTCASE_AUTO(TestGetVariantWithKeywords);
259 TESTCASE_AUTO(TestIsRightToLeft);
260 TESTCASE_AUTO(TestBug13277);
261 TESTCASE_AUTO(TestBug13554);
262 TESTCASE_AUTO(TestBug20410);
263 TESTCASE_AUTO(TestBug20900);
264 TESTCASE_AUTO(TestLocaleCanonicalizationFromFile);
265 TESTCASE_AUTO(TestKnownCanonicalizedListCorrect);
266 TESTCASE_AUTO(TestConstructorAcceptsBCP47);
267 TESTCASE_AUTO(TestForLanguageTag);
268 TESTCASE_AUTO(TestForLanguageTagLegacyTagBug21676);
269 TESTCASE_AUTO(TestToLanguageTag);
270 TESTCASE_AUTO(TestToLanguageTagOmitTrue);
271 TESTCASE_AUTO(TestMoveAssign);
272 TESTCASE_AUTO(TestMoveCtor);
273 TESTCASE_AUTO(TestBug20407iVariantPreferredValue);
274 TESTCASE_AUTO(TestBug13417VeryLongLanguageTag);
275 TESTCASE_AUTO(TestBug11053UnderlineTimeZone);
276 TESTCASE_AUTO(TestUnd);
277 TESTCASE_AUTO(TestUndScript);
278 TESTCASE_AUTO(TestUndRegion);
279 TESTCASE_AUTO(TestUndCAPI);
280 TESTCASE_AUTO(TestRangeIterator);
281 TESTCASE_AUTO(TestPointerConvertingIterator);
282 TESTCASE_AUTO(TestTagConvertingIterator);
283 TESTCASE_AUTO(TestCapturingTagConvertingIterator);
284 TESTCASE_AUTO(TestSetUnicodeKeywordValueInLongLocale);
285 TESTCASE_AUTO(TestSetUnicodeKeywordValueNullInLongLocale);
286 TESTCASE_AUTO(TestCanonicalize);
287 TESTCASE_AUTO(TestLeak21419);
288 TESTCASE_AUTO(TestNullDereferenceWrite21597);
289 TESTCASE_AUTO(TestLongLocaleSetKeywordAssign);
290 TESTCASE_AUTO(TestLongLocaleSetKeywordMoveAssign);
291 #if !UCONFIG_NO_FORMATTING
292 TESTCASE_AUTO(TestSierraLeoneCurrency21997);
293 #endif
294 TESTCASE_AUTO_END;
295 }
296
TestBasicGetters()297 void LocaleTest::TestBasicGetters() {
298 UnicodeString temp;
299
300 int32_t i;
301 for (i = 0; i <= MAX_LOCALES; i++) {
302 Locale testLocale("");
303 if (rawData[SCRIPT][i] && rawData[SCRIPT][i][0] != 0) {
304 testLocale = Locale(rawData[LANG][i], rawData[SCRIPT][i], rawData[CTRY][i], rawData[VAR][i]);
305 }
306 else {
307 testLocale = Locale(rawData[LANG][i], rawData[CTRY][i], rawData[VAR][i]);
308 }
309 logln("Testing " + (UnicodeString)testLocale.getName() + "...");
310
311 if ( (temp=testLocale.getLanguage()) != (dataTable[LANG][i]))
312 errln(" Language code mismatch: " + temp + " versus "
313 + dataTable[LANG][i]);
314 if ( (temp=testLocale.getScript()) != (dataTable[SCRIPT][i]))
315 errln(" Script code mismatch: " + temp + " versus "
316 + dataTable[SCRIPT][i]);
317 if ( (temp=testLocale.getCountry()) != (dataTable[CTRY][i]))
318 errln(" Country code mismatch: " + temp + " versus "
319 + dataTable[CTRY][i]);
320 if ( (temp=testLocale.getVariant()) != (dataTable[VAR][i]))
321 errln(" Variant code mismatch: " + temp + " versus "
322 + dataTable[VAR][i]);
323 if ( (temp=testLocale.getName()) != (dataTable[NAME][i]))
324 errln(" Locale name mismatch: " + temp + " versus "
325 + dataTable[NAME][i]);
326 }
327
328 logln("Same thing without variant codes...");
329 for (i = 0; i <= MAX_LOCALES; i++) {
330 Locale testLocale("");
331 if (rawData[SCRIPT][i] && rawData[SCRIPT][i][0] != 0) {
332 testLocale = Locale(rawData[LANG][i], rawData[SCRIPT][i], rawData[CTRY][i]);
333 }
334 else {
335 testLocale = Locale(rawData[LANG][i], rawData[CTRY][i]);
336 }
337 logln("Testing " + (temp=testLocale.getName()) + "...");
338
339 if ( (temp=testLocale.getLanguage()) != (dataTable[LANG][i]))
340 errln("Language code mismatch: " + temp + " versus "
341 + dataTable[LANG][i]);
342 if ( (temp=testLocale.getScript()) != (dataTable[SCRIPT][i]))
343 errln("Script code mismatch: " + temp + " versus "
344 + dataTable[SCRIPT][i]);
345 if ( (temp=testLocale.getCountry()) != (dataTable[CTRY][i]))
346 errln("Country code mismatch: " + temp + " versus "
347 + dataTable[CTRY][i]);
348 if (testLocale.getVariant()[0] != 0)
349 errln("Variant code mismatch: something versus \"\"");
350 }
351
352 logln("Testing long language names and getters");
353 Locale test8 = Locale::createFromName("x-klingon-latn-zx.utf32be@special");
354
355 temp = test8.getLanguage();
356 if (temp != UnicodeString("x-klingon") )
357 errln("Language code mismatch: " + temp + " versus \"x-klingon\"");
358
359 temp = test8.getScript();
360 if (temp != UnicodeString("Latn") )
361 errln("Script code mismatch: " + temp + " versus \"Latn\"");
362
363 temp = test8.getCountry();
364 if (temp != UnicodeString("ZX") )
365 errln("Country code mismatch: " + temp + " versus \"ZX\"");
366
367 temp = test8.getVariant();
368 //if (temp != UnicodeString("SPECIAL") )
369 // errln("Variant code mismatch: " + temp + " versus \"SPECIAL\"");
370 // As of 3.0, the "@special" will *not* be parsed by uloc_getName()
371 if (temp != UnicodeString("") )
372 errln("Variant code mismatch: " + temp + " versus \"\"");
373
374 if (Locale::getDefault() != Locale::createFromName(nullptr))
375 errln("Locale::getDefault() == Locale::createFromName(nullptr)");
376
377 /*----------*/
378 // NOTE: There used to be a special test for locale names that had language or
379 // country codes that were longer than two letters. The new version of Locale
380 // doesn't support anything that isn't an officially recognized language or
381 // country code, so we no longer support this feature.
382
383 Locale bogusLang("THISISABOGUSLANGUAGE"); // Jitterbug 2864: language code too long
384 if(!bogusLang.isBogus()) {
385 errln("Locale(\"THISISABOGUSLANGUAGE\").isBogus()==false");
386 }
387
388 bogusLang=Locale("eo");
389 if( bogusLang.isBogus() ||
390 strcmp(bogusLang.getLanguage(), "eo")!=0 ||
391 *bogusLang.getCountry()!=0 ||
392 *bogusLang.getVariant()!=0 ||
393 strcmp(bogusLang.getName(), "eo")!=0
394 ) {
395 errln("assignment to bogus Locale does not unbogus it or sets bad data");
396 }
397
398 Locale a("eo_DE@currency=DEM");
399 Locale *pb=a.clone();
400 if(pb==&a || *pb!=a) {
401 errln("Locale.clone() failed");
402 }
403 delete pb;
404 }
405
TestParallelAPIValues()406 void LocaleTest::TestParallelAPIValues() {
407 logln("Test synchronization between C and C++ API");
408 if (strcmp(Locale::getChinese().getName(), ULOC_CHINESE) != 0) {
409 errln("Differences for ULOC_CHINESE Locale");
410 }
411 if (strcmp(Locale::getEnglish().getName(), ULOC_ENGLISH) != 0) {
412 errln("Differences for ULOC_ENGLISH Locale");
413 }
414 if (strcmp(Locale::getFrench().getName(), ULOC_FRENCH) != 0) {
415 errln("Differences for ULOC_FRENCH Locale");
416 }
417 if (strcmp(Locale::getGerman().getName(), ULOC_GERMAN) != 0) {
418 errln("Differences for ULOC_GERMAN Locale");
419 }
420 if (strcmp(Locale::getItalian().getName(), ULOC_ITALIAN) != 0) {
421 errln("Differences for ULOC_ITALIAN Locale");
422 }
423 if (strcmp(Locale::getJapanese().getName(), ULOC_JAPANESE) != 0) {
424 errln("Differences for ULOC_JAPANESE Locale");
425 }
426 if (strcmp(Locale::getKorean().getName(), ULOC_KOREAN) != 0) {
427 errln("Differences for ULOC_KOREAN Locale");
428 }
429 if (strcmp(Locale::getSimplifiedChinese().getName(), ULOC_SIMPLIFIED_CHINESE) != 0) {
430 errln("Differences for ULOC_SIMPLIFIED_CHINESE Locale");
431 }
432 if (strcmp(Locale::getTraditionalChinese().getName(), ULOC_TRADITIONAL_CHINESE) != 0) {
433 errln("Differences for ULOC_TRADITIONAL_CHINESE Locale");
434 }
435
436
437 if (strcmp(Locale::getCanada().getName(), ULOC_CANADA) != 0) {
438 errln("Differences for ULOC_CANADA Locale");
439 }
440 if (strcmp(Locale::getCanadaFrench().getName(), ULOC_CANADA_FRENCH) != 0) {
441 errln("Differences for ULOC_CANADA_FRENCH Locale");
442 }
443 if (strcmp(Locale::getChina().getName(), ULOC_CHINA) != 0) {
444 errln("Differences for ULOC_CHINA Locale");
445 }
446 if (strcmp(Locale::getPRC().getName(), ULOC_PRC) != 0) {
447 errln("Differences for ULOC_PRC Locale");
448 }
449 if (strcmp(Locale::getFrance().getName(), ULOC_FRANCE) != 0) {
450 errln("Differences for ULOC_FRANCE Locale");
451 }
452 if (strcmp(Locale::getGermany().getName(), ULOC_GERMANY) != 0) {
453 errln("Differences for ULOC_GERMANY Locale");
454 }
455 if (strcmp(Locale::getItaly().getName(), ULOC_ITALY) != 0) {
456 errln("Differences for ULOC_ITALY Locale");
457 }
458 if (strcmp(Locale::getJapan().getName(), ULOC_JAPAN) != 0) {
459 errln("Differences for ULOC_JAPAN Locale");
460 }
461 if (strcmp(Locale::getKorea().getName(), ULOC_KOREA) != 0) {
462 errln("Differences for ULOC_KOREA Locale");
463 }
464 if (strcmp(Locale::getTaiwan().getName(), ULOC_TAIWAN) != 0) {
465 errln("Differences for ULOC_TAIWAN Locale");
466 }
467 if (strcmp(Locale::getUK().getName(), ULOC_UK) != 0) {
468 errln("Differences for ULOC_UK Locale");
469 }
470 if (strcmp(Locale::getUS().getName(), ULOC_US) != 0) {
471 errln("Differences for ULOC_US Locale");
472 }
473 }
474
475
TestSimpleResourceInfo()476 void LocaleTest::TestSimpleResourceInfo() {
477 UnicodeString temp;
478 char temp2[20];
479 UErrorCode err = U_ZERO_ERROR;
480 int32_t i = 0;
481
482 for (i = 0; i <= MAX_LOCALES; i++) {
483 Locale testLocale(rawData[LANG][i], rawData[CTRY][i], rawData[VAR][i]);
484 logln("Testing " + (temp=testLocale.getName()) + "...");
485
486 if ( (temp=testLocale.getISO3Language()) != (dataTable[LANG3][i]))
487 errln(" ISO-3 language code mismatch: " + temp
488 + " versus " + dataTable[LANG3][i]);
489 if ( (temp=testLocale.getISO3Country()) != (dataTable[CTRY3][i]))
490 errln(" ISO-3 country code mismatch: " + temp
491 + " versus " + dataTable[CTRY3][i]);
492
493 snprintf(temp2, sizeof(temp2), "%x", (int)testLocale.getLCID());
494 if (UnicodeString(temp2) != dataTable[LCID][i])
495 errln((UnicodeString)" LCID mismatch: " + temp2 + " versus "
496 + dataTable[LCID][i]);
497
498 if(U_FAILURE(err))
499 {
500 errln((UnicodeString)"Some error on number " + i + u_errorName(err));
501 }
502 err = U_ZERO_ERROR;
503 }
504
505 Locale locale("en");
506 if(strcmp(locale.getName(), "en") != 0||
507 strcmp(locale.getLanguage(), "en") != 0) {
508 errln("construction of Locale(en) failed\n");
509 }
510 /*-----*/
511
512 }
513
514 /*
515 * Jitterbug 2439 -- markus 20030425
516 *
517 * The lookup of display names must not fall back through the default
518 * locale because that yields useless results.
519 */
520 void
TestDisplayNames()521 LocaleTest::TestDisplayNames()
522 {
523 Locale english("en", "US");
524 Locale french("fr", "FR");
525 Locale croatian("ca", "ES");
526 Locale greek("el", "GR");
527
528 logln(" In locale = en_US...");
529 doTestDisplayNames(english, DLANG_EN);
530 logln(" In locale = fr_FR...");
531 doTestDisplayNames(french, DLANG_FR);
532 logln(" In locale = ca_ES...");
533 doTestDisplayNames(croatian, DLANG_CA);
534 logln(" In locale = el_GR...");
535 doTestDisplayNames(greek, DLANG_EL);
536
537 UnicodeString s;
538 UErrorCode status = U_ZERO_ERROR;
539
540 #if !UCONFIG_NO_FORMATTING
541 DecimalFormatSymbols symb(status);
542 /* Check to see if ICU supports this locale */
543 if (symb.getLocale(ULOC_VALID_LOCALE, status) != Locale("root")) {
544 /* test that the default locale has a display name for its own language */
545 /* Currently, there is no language information in the "tl" data file so this test will fail if default locale is "tl" */
546 if (uprv_strcmp(Locale().getLanguage(), "tl") != 0) {
547 Locale().getDisplayLanguage(Locale(), s);
548 if(s.length()<=3 && s.charAt(0)<=0x7f) {
549 /* check <=3 to reject getting the language code as a display name */
550 dataerrln("unable to get a display string for the language of the default locale: " + s);
551 }
552
553 /*
554 * API coverage improvements: call
555 * Locale::getDisplayLanguage(UnicodeString &) and
556 * Locale::getDisplayCountry(UnicodeString &)
557 */
558 s.remove();
559 Locale().getDisplayLanguage(s);
560 if(s.length()<=3 && s.charAt(0)<=0x7f) {
561 dataerrln("unable to get a display string for the language of the default locale [2]: " + s);
562 }
563 }
564 }
565 else {
566 logln("Default locale %s is unsupported by ICU\n", Locale().getName());
567 }
568 s.remove();
569 #endif
570
571 french.getDisplayCountry(s);
572 if(s.isEmpty()) {
573 errln("unable to get any default-locale display string for the country of fr_FR\n");
574 }
575 s.remove();
576 Locale("zh", "Hant").getDisplayScript(s);
577 if(s.isEmpty()) {
578 errln("unable to get any default-locale display string for the country of zh_Hant\n");
579 }
580 }
581
TestSimpleObjectStuff()582 void LocaleTest::TestSimpleObjectStuff() {
583 Locale test1("aa", "AA");
584 Locale test2("aa", "AA");
585 Locale test3(test1);
586 Locale test4("zz", "ZZ");
587 Locale test5("aa", "AA", "");
588 Locale test6("aa", "AA", "ANTARES");
589 Locale test7("aa", "AA", "JUPITER");
590 Locale test8 = Locale::createFromName("aa-aa-jupiTER"); // was "aa-aa.utf8@jupiter" but in 3.0 getName won't normalize that
591
592 // now list them all for debugging usage.
593 test_dumpLocale(test1);
594 test_dumpLocale(test2);
595 test_dumpLocale(test3);
596 test_dumpLocale(test4);
597 test_dumpLocale(test5);
598 test_dumpLocale(test6);
599 test_dumpLocale(test7);
600 test_dumpLocale(test8);
601
602 // Make sure things compare to themselves!
603 test_assert(test1 == test1);
604 test_assert(test2 == test2);
605 test_assert(test3 == test3);
606 test_assert(test4 == test4);
607 test_assert(test5 == test5);
608 test_assert(test6 == test6);
609 test_assert(test7 == test7);
610 test_assert(test8 == test8);
611
612 // make sure things are not equal to themselves.
613 test_assert(!(test1 != test1));
614 test_assert(!(test2 != test2));
615 test_assert(!(test3 != test3));
616 test_assert(!(test4 != test4));
617 test_assert(!(test5 != test5));
618 test_assert(!(test6 != test6));
619 test_assert(!(test7 != test7));
620 test_assert(!(test8 != test8));
621
622 // make sure things that are equal to each other don't show up as unequal.
623 test_assert(!(test1 != test2));
624 test_assert(!(test2 != test1));
625 test_assert(!(test1 != test3));
626 test_assert(!(test2 != test3));
627 test_assert(test5 == test1);
628 test_assert(test6 != test2);
629 test_assert(test6 != test5);
630
631 test_assert(test6 != test7);
632
633 // test for things that shouldn't compare equal.
634 test_assert(!(test1 == test4));
635 test_assert(!(test2 == test4));
636 test_assert(!(test3 == test4));
637
638 test_assert(test7 == test8);
639
640 // test for hash codes to be the same.
641 int32_t hash1 = test1.hashCode();
642 int32_t hash2 = test2.hashCode();
643 int32_t hash3 = test3.hashCode();
644
645 test_assert(hash1 == hash2);
646 test_assert(hash1 == hash3);
647 test_assert(hash2 == hash3);
648
649 // test that the assignment operator works.
650 test4 = test1;
651 logln("test4=test1;");
652 test_dumpLocale(test4);
653 test_assert(test4 == test4);
654
655 test_assert(!(test1 != test4));
656 test_assert(!(test2 != test4));
657 test_assert(!(test3 != test4));
658 test_assert(test1 == test4);
659 test_assert(test4 == test1);
660
661 // test assignments with a variant
662 logln("test7 = test6");
663 test7 = test6;
664 test_dumpLocale(test7);
665 test_assert(test7 == test7);
666 test_assert(test7 == test6);
667 test_assert(test7 != test5);
668
669 logln("test6 = test1");
670 test6=test1;
671 test_dumpLocale(test6);
672 test_assert(test6 != test7);
673 test_assert(test6 == test1);
674 test_assert(test6 == test6);
675 }
676
677 // A class which exposes constructors that are implemented in terms of the POSIX parsing code.
678 class POSIXLocale : public Locale
679 {
680 public:
POSIXLocale(const UnicodeString & l)681 POSIXLocale(const UnicodeString& l)
682 :Locale()
683 {
684 char *ch;
685 ch = new char[l.length() + 1];
686 ch[l.extract(0, 0x7fffffff, ch, "")] = 0;
687 setFromPOSIXID(ch);
688 delete [] ch;
689 }
POSIXLocale(const char * l)690 POSIXLocale(const char *l)
691 :Locale()
692 {
693 setFromPOSIXID(l);
694 }
695 };
696
TestPOSIXParsing()697 void LocaleTest::TestPOSIXParsing()
698 {
699 POSIXLocale test1("ab_AB");
700 POSIXLocale test2(UnicodeString("ab_AB"));
701 Locale test3("ab","AB");
702
703 POSIXLocale test4("ab_AB_Antares");
704 POSIXLocale test5(UnicodeString("ab_AB_Antares"));
705 Locale test6("ab", "AB", "Antares");
706
707 test_dumpLocale(test1);
708 test_dumpLocale(test2);
709 test_dumpLocale(test3);
710 test_dumpLocale(test4);
711 test_dumpLocale(test5);
712 test_dumpLocale(test6);
713
714 test_assert(test1 == test1);
715
716 test_assert(test1 == test2);
717 test_assert(test2 == test3);
718 test_assert(test3 == test1);
719
720 test_assert(test4 == test5);
721 test_assert(test5 == test6);
722 test_assert(test6 == test4);
723
724 test_assert(test1 != test4);
725 test_assert(test5 != test3);
726 test_assert(test5 != test2);
727
728 int32_t hash1 = test1.hashCode();
729 int32_t hash2 = test2.hashCode();
730 int32_t hash3 = test3.hashCode();
731
732 test_assert(hash1 == hash2);
733 test_assert(hash2 == hash3);
734 test_assert(hash3 == hash1);
735 }
736
TestGetAvailableLocales()737 void LocaleTest::TestGetAvailableLocales()
738 {
739 int32_t locCount = 0;
740 const Locale* locList = Locale::getAvailableLocales(locCount);
741
742 if (locCount == 0)
743 dataerrln("getAvailableLocales() returned an empty list!");
744 else {
745 logln(UnicodeString("Number of locales returned = ") + locCount);
746 UnicodeString temp;
747 for(int32_t i = 0; i < locCount; ++i)
748 logln(locList[i].getName());
749 }
750 // I have no idea how to test this function...
751 }
752
753 // This test isn't applicable anymore - getISO3Language is
754 // independent of the data directory
TestDataDirectory()755 void LocaleTest::TestDataDirectory()
756 {
757 /*
758 char oldDirectory[80];
759 const char* temp;
760 UErrorCode err = U_ZERO_ERROR;
761 UnicodeString testValue;
762
763 temp = Locale::getDataDirectory();
764 strcpy(oldDirectory, temp);
765 logln(UnicodeString("oldDirectory = ") + oldDirectory);
766
767 Locale test(Locale::US);
768 test.getISO3Language(testValue);
769 logln("first fetch of language retrieved " + testValue);
770 if (testValue != "eng")
771 errln("Initial check of ISO3 language failed: expected \"eng\", got \"" + testValue + "\"");
772
773 {
774 char *path;
775 path=IntlTest::getTestDirectory();
776 Locale::setDataDirectory( path );
777 }
778
779 test.getISO3Language(testValue);
780 logln("second fetch of language retrieved " + testValue);
781 if (testValue != "xxx")
782 errln("setDataDirectory() failed: expected \"xxx\", got \"" + testValue + "\"");
783
784 Locale::setDataDirectory(oldDirectory);
785 test.getISO3Language(testValue);
786 logln("third fetch of language retrieved " + testValue);
787 if (testValue != "eng")
788 errln("get/setDataDirectory() failed: expected \"eng\", got \"" + testValue + "\"");
789 */
790 }
791
792 //===========================================================
793
doTestDisplayNames(Locale & displayLocale,int32_t compareIndex)794 void LocaleTest::doTestDisplayNames(Locale& displayLocale, int32_t compareIndex) {
795 UnicodeString temp;
796
797 for (int32_t i = 0; i <= MAX_LOCALES; i++) {
798 Locale testLocale("");
799 if (rawData[SCRIPT][i] && rawData[SCRIPT][i][0] != 0) {
800 testLocale = Locale(rawData[LANG][i], rawData[SCRIPT][i], rawData[CTRY][i], rawData[VAR][i]);
801 }
802 else {
803 testLocale = Locale(rawData[LANG][i], rawData[CTRY][i], rawData[VAR][i]);
804 }
805 logln(" Testing " + (temp=testLocale.getName()) + "...");
806
807 UnicodeString testLang;
808 UnicodeString testScript;
809 UnicodeString testCtry;
810 UnicodeString testVar;
811 UnicodeString testName;
812
813 testLocale.getDisplayLanguage(displayLocale, testLang);
814 testLocale.getDisplayScript(displayLocale, testScript);
815 testLocale.getDisplayCountry(displayLocale, testCtry);
816 testLocale.getDisplayVariant(displayLocale, testVar);
817 testLocale.getDisplayName(displayLocale, testName);
818
819 UnicodeString expectedLang;
820 UnicodeString expectedScript;
821 UnicodeString expectedCtry;
822 UnicodeString expectedVar;
823 UnicodeString expectedName;
824
825 expectedLang = dataTable[compareIndex][i];
826 if (expectedLang.length() == 0)
827 expectedLang = dataTable[DLANG_EN][i];
828
829 expectedScript = dataTable[compareIndex + 1][i];
830 if (expectedScript.length() == 0)
831 expectedScript = dataTable[DSCRIPT_EN][i];
832
833 expectedCtry = dataTable[compareIndex + 2][i];
834 if (expectedCtry.length() == 0)
835 expectedCtry = dataTable[DCTRY_EN][i];
836
837 expectedVar = dataTable[compareIndex + 3][i];
838 if (expectedVar.length() == 0)
839 expectedVar = dataTable[DVAR_EN][i];
840
841 expectedName = dataTable[compareIndex + 4][i];
842 if (expectedName.length() == 0)
843 expectedName = dataTable[DNAME_EN][i];
844
845 if (testLang != expectedLang)
846 dataerrln("Display language (" + UnicodeString(displayLocale.getName()) + ") of (" + UnicodeString(testLocale.getName()) + ") got " + testLang + " expected " + expectedLang);
847 if (testScript != expectedScript)
848 dataerrln("Display script (" + UnicodeString(displayLocale.getName()) + ") of (" + UnicodeString(testLocale.getName()) + ") got " + testScript + " expected " + expectedScript);
849 if (testCtry != expectedCtry)
850 dataerrln("Display country (" + UnicodeString(displayLocale.getName()) + ") of (" + UnicodeString(testLocale.getName()) + ") got " + testCtry + " expected " + expectedCtry);
851 if (testVar != expectedVar)
852 dataerrln("Display variant (" + UnicodeString(displayLocale.getName()) + ") of (" + UnicodeString(testLocale.getName()) + ") got " + testVar + " expected " + expectedVar);
853 if (testName != expectedName)
854 dataerrln("Display name (" + UnicodeString(displayLocale.getName()) + ") of (" + UnicodeString(testLocale.getName()) + ") got " + testName + " expected " + expectedName);
855 }
856 }
857
858 //---------------------------------------------------
859 // table of valid data
860 //---------------------------------------------------
861
862
863
setUpDataTable()864 void LocaleTest::setUpDataTable()
865 {
866 if (dataTable == 0) {
867 dataTable = new UnicodeString*[33];
868
869 for (int32_t i = 0; i < 33; i++) {
870 dataTable[i] = new UnicodeString[8];
871 for (int32_t j = 0; j < 8; j++) {
872 dataTable[i][j] = CharsToUnicodeString(rawData[i][j]);
873 }
874 }
875 }
876 }
877
878 // ====================
879
880
881 /**
882 * @bug 4011756 4011380
883 */
884 void
TestISO3Fallback()885 LocaleTest::TestISO3Fallback()
886 {
887 Locale test("xx", "YY");
888
889 const char * result;
890
891 result = test.getISO3Language();
892
893 // Conform to C API usage
894
895 if (!result || (result[0] != 0))
896 errln("getISO3Language() on xx_YY returned " + UnicodeString(result) + " instead of \"\"");
897
898 result = test.getISO3Country();
899
900 if (!result || (result[0] != 0))
901 errln("getISO3Country() on xx_YY returned " + UnicodeString(result) + " instead of \"\"");
902 }
903
904 /**
905 * @bug 4106155 4118587
906 */
907 void
TestGetLangsAndCountries()908 LocaleTest::TestGetLangsAndCountries()
909 {
910 // It didn't seem right to just do an exhaustive test of everything here, so I check
911 // for the following things:
912 // 1) Does each list have the right total number of entries?
913 // 2) Does each list contain certain language and country codes we think are important
914 // (the G7 countries, plus a couple others)?
915 // 3) Does each list have every entry formatted correctly? (i.e., two characters,
916 // all lower case for the language codes, all upper case for the country codes)
917 // 4) Is each list in sorted order?
918 int32_t testCount = 0;
919 const char * const * test = Locale::getISOLanguages();
920 const char spotCheck1[ ][4] = { "en", "es", "fr", "de", "it",
921 "ja", "ko", "zh", "th", "he",
922 "id", "iu", "ug", "yi", "za" };
923
924 int32_t i;
925
926 for(testCount = 0;test[testCount];testCount++)
927 ;
928
929 /* TODO: Change this test to be more like the cloctst version? */
930 if (testCount != 595)
931 errln("Expected getISOLanguages() to return 595 languages; it returned %d", testCount);
932 else {
933 for (i = 0; i < 15; i++) {
934 int32_t j;
935 for (j = 0; j < testCount; j++)
936 if (uprv_strcmp(test[j],spotCheck1[i])== 0)
937 break;
938 if (j == testCount || (uprv_strcmp(test[j],spotCheck1[i])!=0))
939 errln("Couldn't find " + (UnicodeString)spotCheck1[i] + " in language list.");
940 }
941 }
942 for (i = 0; i < testCount; i++) {
943 UnicodeString testee(test[i],"");
944 UnicodeString lc(test[i],"");
945 if (testee != lc.toLower())
946 errln(lc + " is not all lower case.");
947 if ( (testee.length() != 2) && (testee.length() != 3))
948 errln(testee + " is not two or three characters long.");
949 if (i > 0 && testee.compare(test[i - 1]) <= 0)
950 errln(testee + " appears in an out-of-order position in the list.");
951 }
952
953 test = Locale::getISOCountries();
954 UnicodeString spotCheck2 [] = { "US", "CA", "GB", "FR", "DE",
955 "IT", "JP", "KR", "CN", "TW",
956 "TH" };
957 int32_t spot2Len = 11;
958 for(testCount=0;test[testCount];testCount++)
959 ;
960
961 if (testCount != 254){
962 errln("Expected getISOCountries to return 254 countries; it returned %d", testCount);
963 }else {
964 for (i = 0; i < spot2Len; i++) {
965 int32_t j;
966 for (j = 0; j < testCount; j++)
967 {
968 UnicodeString testee(test[j],"");
969
970 if (testee == spotCheck2[i])
971 break;
972 }
973 UnicodeString testee(test[j],"");
974 if (j == testCount || testee != spotCheck2[i])
975 errln("Couldn't find " + spotCheck2[i] + " in country list.");
976 }
977 }
978 for (i = 0; i < testCount; i++) {
979 UnicodeString testee(test[i],"");
980 UnicodeString uc(test[i],"");
981 if (testee != uc.toUpper())
982 errln(testee + " is not all upper case.");
983 if (testee.length() != 2)
984 errln(testee + " is not two characters long.");
985 if (i > 0 && testee.compare(test[i - 1]) <= 0)
986 errln(testee + " appears in an out-of-order position in the list.");
987 }
988
989 // This getAvailableLocales and getISO3Language
990 {
991 int32_t numOfLocales;
992 Locale enLoc ("en");
993 const Locale *pLocales = Locale::getAvailableLocales(numOfLocales);
994
995 for (int i = 0; i < numOfLocales; i++) {
996 const Locale &loc(pLocales[i]);
997 UnicodeString name;
998 char szName[200];
999
1000 loc.getDisplayName (enLoc, name);
1001 name.extract (0, 200, szName, sizeof(szName));
1002
1003 if (strlen(loc.getISO3Language()) == 0) {
1004 errln("getISO3Language() returned an empty string for: " + name);
1005 }
1006 }
1007 }
1008 }
1009
1010 /**
1011 * @bug 4118587
1012 */
1013 void
TestSimpleDisplayNames()1014 LocaleTest::TestSimpleDisplayNames()
1015 {
1016 // This test is different from TestDisplayNames because TestDisplayNames checks
1017 // fallback behavior, combination of language and country names to form locale
1018 // names, and other stuff like that. This test just checks specific language
1019 // and country codes to make sure we have the correct names for them.
1020 char languageCodes[] [4] = { "he", "id", "iu", "ug", "yi", "za" };
1021 UnicodeString languageNames [] = { "Hebrew", "Indonesian", "Inuktitut", "Uyghur", "Yiddish",
1022 "Zhuang" };
1023
1024 for (int32_t i = 0; i < 6; i++) {
1025 UnicodeString test;
1026 Locale l(languageCodes[i], "", "");
1027 l.getDisplayLanguage(Locale::getUS(), test);
1028 if (test != languageNames[i])
1029 dataerrln("Got wrong display name for " + UnicodeString(languageCodes[i]) + ": Expected \"" +
1030 languageNames[i] + "\", got \"" + test + "\".");
1031 }
1032 }
1033
1034 /**
1035 * @bug 4118595
1036 */
1037 void
TestUninstalledISO3Names()1038 LocaleTest::TestUninstalledISO3Names()
1039 {
1040 // This test checks to make sure getISO3Language and getISO3Country work right
1041 // even for locales that are not installed.
1042 const char iso2Languages [][4] = { "am", "ba", "fy", "mr", "rn",
1043 "ss", "tw", "zu" };
1044 const char iso3Languages [][5] = { "amh", "bak", "fry", "mar", "run",
1045 "ssw", "twi", "zul" };
1046
1047 int32_t i;
1048
1049 for (i = 0; i < 8; i++) {
1050 UErrorCode err = U_ZERO_ERROR;
1051
1052 UnicodeString test;
1053 Locale l(iso2Languages[i], "", "");
1054 test = l.getISO3Language();
1055 if((test != iso3Languages[i]) || U_FAILURE(err))
1056 errln("Got wrong ISO3 code for " + UnicodeString(iso2Languages[i]) + ": Expected \"" +
1057 iso3Languages[i] + "\", got \"" + test + "\"." + UnicodeString(u_errorName(err)));
1058 }
1059
1060 char iso2Countries [][4] = { "AF", "BW", "KZ", "MO", "MN",
1061 "SB", "TC", "ZW" };
1062 char iso3Countries [][4] = { "AFG", "BWA", "KAZ", "MAC", "MNG",
1063 "SLB", "TCA", "ZWE" };
1064
1065 for (i = 0; i < 8; i++) {
1066 UErrorCode err = U_ZERO_ERROR;
1067 Locale l("", iso2Countries[i], "");
1068 UnicodeString test(l.getISO3Country(), "");
1069 if (test != iso3Countries[i])
1070 errln("Got wrong ISO3 code for " + UnicodeString(iso2Countries[i]) + ": Expected \"" +
1071 UnicodeString(iso3Countries[i]) + "\", got \"" + test + "\"." + u_errorName(err));
1072 }
1073 }
1074
1075 /**
1076 * @bug 4092475
1077 * I could not reproduce this bug. I'm pretty convinced it was fixed with the
1078 * big locale-data reorg of 10/28/97. The lookup logic for language and country
1079 * display names was also changed at that time in that check-in. --rtg 3/20/98
1080 */
1081 void
TestAtypicalLocales()1082 LocaleTest::TestAtypicalLocales()
1083 {
1084 Locale localesToTest [] = { Locale("de", "CA"),
1085 Locale("ja", "ZA"),
1086 Locale("ru", "MX"),
1087 Locale("en", "FR"),
1088 Locale("es", "DE"),
1089 Locale("", "HR"),
1090 Locale("", "SE"),
1091 Locale("", "DO"),
1092 Locale("", "BE") };
1093
1094 UnicodeString englishDisplayNames [] = { "German (Canada)",
1095 "Japanese (South Africa)",
1096 "Russian (Mexico)",
1097 "English (France)",
1098 "Spanish (Germany)",
1099 "Unknown language (Croatia)",
1100 "Unknown language (Sweden)",
1101 "Unknown language (Dominican Republic)",
1102 "Unknown language (Belgium)" };
1103 UnicodeString frenchDisplayNames []= { "allemand (Canada)",
1104 "japonais (Afrique du Sud)",
1105 "russe (Mexique)",
1106 "anglais (France)",
1107 "espagnol (Allemagne)",
1108 u"langue indéterminée (Croatie)",
1109 u"langue indéterminée (Suède)",
1110 u"langue indéterminée (République dominicaine)",
1111 u"langue indéterminée (Belgique)" };
1112 UnicodeString spanishDisplayNames [] = {
1113 u"alemán (Canadá)",
1114 u"japonés (Sudáfrica)",
1115 u"ruso (México)",
1116 u"inglés (Francia)",
1117 u"español (Alemania)",
1118 "lengua desconocida (Croacia)",
1119 "lengua desconocida (Suecia)",
1120 u"lengua desconocida (República Dominicana)",
1121 u"lengua desconocida (Bélgica)" };
1122 // De-Anglicizing root required the change from
1123 // English display names to ISO Codes - ram 2003/09/26
1124 UnicodeString invDisplayNames [] = { "German (Canada)",
1125 "Japanese (South Africa)",
1126 "Russian (Mexico)",
1127 "English (France)",
1128 "Spanish (Germany)",
1129 "Unknown language (Croatia)",
1130 "Unknown language (Sweden)",
1131 "Unknown language (Dominican Republic)",
1132 "Unknown language (Belgium)" };
1133
1134 int32_t i;
1135 UErrorCode status = U_ZERO_ERROR;
1136 Locale saveLocale;
1137 Locale::setDefault(Locale::getUS(), status);
1138 for (i = 0; i < 9; ++i) {
1139 UnicodeString name;
1140 localesToTest[i].getDisplayName(Locale::getUS(), name);
1141 logln(name);
1142 if (name != englishDisplayNames[i])
1143 {
1144 dataerrln("Lookup in English failed: expected \"" + englishDisplayNames[i]
1145 + "\", got \"" + name + "\"");
1146 logln("Locale name was-> " + (name=localesToTest[i].getName()));
1147 }
1148 }
1149
1150 for (i = 0; i < 9; i++) {
1151 UnicodeString name;
1152 localesToTest[i].getDisplayName(Locale("es", "ES"), name);
1153 logln(name);
1154 if (name != spanishDisplayNames[i])
1155 dataerrln("Lookup in Spanish failed: expected \"" + spanishDisplayNames[i]
1156 + "\", got \"" + name + "\"");
1157 }
1158
1159 for (i = 0; i < 9; i++) {
1160 UnicodeString name;
1161 localesToTest[i].getDisplayName(Locale::getFrance(), name);
1162 logln(name);
1163 if (name != frenchDisplayNames[i])
1164 dataerrln("Lookup in French failed: expected \"" + frenchDisplayNames[i]
1165 + "\", got \"" + name + "\"");
1166 }
1167
1168 for (i = 0; i < 9; i++) {
1169 UnicodeString name;
1170 localesToTest[i].getDisplayName(Locale("inv", "IN"), name);
1171 logln(name + " Locale fallback to be, and data fallback to root");
1172 if (name != invDisplayNames[i])
1173 dataerrln("Lookup in INV failed: expected \"" + prettify(invDisplayNames[i])
1174 + "\", got \"" + prettify(name) + "\"");
1175 localesToTest[i].getDisplayName(Locale("inv", "BD"), name);
1176 logln(name + " Data fallback to root");
1177 if (name != invDisplayNames[i])
1178 dataerrln("Lookup in INV failed: expected \"" + prettify(invDisplayNames[i])
1179 + "\", got \"" + prettify(name )+ "\"");
1180 }
1181 Locale::setDefault(saveLocale, status);
1182 }
1183
1184 #if !UCONFIG_NO_FORMATTING
1185
1186 /**
1187 * @bug 4135752
1188 * This would be better tested by the LocaleDataTest. Will move it when I
1189 * get the LocaleDataTest working again.
1190 */
1191 void
TestThaiCurrencyFormat()1192 LocaleTest::TestThaiCurrencyFormat()
1193 {
1194 UErrorCode status = U_ZERO_ERROR;
1195 DecimalFormat *thaiCurrency = dynamic_cast<DecimalFormat*>(NumberFormat::createCurrencyInstance(
1196 Locale("th", "TH"), status));
1197 UnicodeString posPrefix(u"\u0E3F");
1198 UnicodeString temp;
1199
1200 if(U_FAILURE(status) || !thaiCurrency)
1201 {
1202 dataerrln("Couldn't get th_TH currency -> " + UnicodeString(u_errorName(status)));
1203 return;
1204 }
1205 if (thaiCurrency->getPositivePrefix(temp) != posPrefix)
1206 errln("Thai currency prefix wrong: expected Baht sign, got \"" +
1207 thaiCurrency->getPositivePrefix(temp) + "\"");
1208 if (thaiCurrency->getPositiveSuffix(temp) != "")
1209 errln("Thai currency suffix wrong: expected \"\", got \"" +
1210 thaiCurrency->getPositiveSuffix(temp) + "\"");
1211
1212 delete thaiCurrency;
1213 }
1214
1215 /**
1216 * @bug 4122371
1217 * Confirm that Euro support works. This test is pretty rudimentary; all it does
1218 * is check that any locales with the EURO variant format a number using the
1219 * Euro currency symbol.
1220 *
1221 * ASSUME: All locales encode the Euro character "\u20AC".
1222 * If this is changed to use the single-character Euro symbol, this
1223 * test must be updated.
1224 *
1225 */
1226 void
TestEuroSupport()1227 LocaleTest::TestEuroSupport()
1228 {
1229 char16_t euro = 0x20ac;
1230 const UnicodeString EURO_CURRENCY(&euro, 1, 1); // Look for this UnicodeString in formatted Euro currency
1231 const char* localeArr[] = {
1232 "ca_ES",
1233 "de_AT",
1234 "de_DE",
1235 "de_LU",
1236 "el_GR",
1237 "en_BE",
1238 "en_IE",
1239 "en_GB@currency=EUR",
1240 "en_US@currency=EUR",
1241 "es_ES",
1242 "eu_ES",
1243 "fi_FI",
1244 "fr_BE",
1245 "fr_FR",
1246 "fr_LU",
1247 "ga_IE",
1248 "gl_ES",
1249 "it_IT",
1250 "nl_BE",
1251 "nl_NL",
1252 "pt_PT",
1253 nullptr
1254 };
1255 const char** locales = localeArr;
1256
1257 UErrorCode status = U_ZERO_ERROR;
1258
1259 UnicodeString temp;
1260
1261 for (;*locales!=nullptr;locales++) {
1262 Locale loc (*locales);
1263 UnicodeString temp;
1264 NumberFormat *nf = NumberFormat::createCurrencyInstance(loc, status);
1265 UnicodeString pos;
1266
1267 if (U_FAILURE(status)) {
1268 dataerrln("Error calling NumberFormat::createCurrencyInstance(%s)", *locales);
1269 continue;
1270 }
1271
1272 nf->format(271828.182845, pos);
1273 UnicodeString neg;
1274 nf->format(-271828.182845, neg);
1275 if (pos.indexOf(EURO_CURRENCY) >= 0 &&
1276 neg.indexOf(EURO_CURRENCY) >= 0) {
1277 logln("Ok: " + (temp=loc.getName()) +
1278 ": " + pos + " / " + neg);
1279 }
1280 else {
1281 errln("Fail: " + (temp=loc.getName()) +
1282 " formats without " + EURO_CURRENCY +
1283 ": " + pos + " / " + neg +
1284 "\n*** THIS FAILURE MAY ONLY MEAN THAT LOCALE DATA HAS CHANGED ***");
1285 }
1286
1287 delete nf;
1288 }
1289
1290 UnicodeString dollarStr("USD", ""), euroStr("EUR", ""), genericStr((char16_t)0x00a4), resultStr;
1291 char16_t tmp[4];
1292 status = U_ZERO_ERROR;
1293
1294 ucurr_forLocale("en_US", tmp, 4, &status);
1295 resultStr.setTo(tmp);
1296 if (dollarStr != resultStr) {
1297 errcheckln(status, "Fail: en_US didn't return USD - %s", u_errorName(status));
1298 }
1299 ucurr_forLocale("en_US@currency=EUR", tmp, 4, &status);
1300 resultStr.setTo(tmp);
1301 if (euroStr != resultStr) {
1302 errcheckln(status, "Fail: en_US@currency=EUR didn't return EUR - %s", u_errorName(status));
1303 }
1304 ucurr_forLocale("en_GB@currency=EUR", tmp, 4, &status);
1305 resultStr.setTo(tmp);
1306 if (euroStr != resultStr) {
1307 errcheckln(status, "Fail: en_GB@currency=EUR didn't return EUR - %s", u_errorName(status));
1308 }
1309 ucurr_forLocale("en_US_Q", tmp, 4, &status);
1310 resultStr.setTo(tmp);
1311 if (dollarStr != resultStr) {
1312 errcheckln(status, "Fail: en_US_Q didn't fallback to en_US - %s", u_errorName(status));
1313 }
1314 int32_t invalidLen = ucurr_forLocale("en_QQ", tmp, 4, &status);
1315 if (invalidLen || U_SUCCESS(status)) {
1316 errln("Fail: en_QQ didn't return nullptr");
1317 }
1318
1319 // The currency keyword value is as long as the destination buffer.
1320 // It should detect the overflow internally, and default to the locale's currency.
1321 tmp[0] = u'¤';
1322 status = U_ZERO_ERROR;
1323 int32_t length = ucurr_forLocale("en_US@currency=euro", tmp, 4, &status);
1324 if (U_FAILURE(status) || dollarStr != UnicodeString(tmp, length)) {
1325 if (U_SUCCESS(status) && tmp[0] == u'¤') {
1326 errln("Fail: ucurr_forLocale(en_US@currency=euro) succeeded without writing output");
1327 } else {
1328 errln("Fail: ucurr_forLocale(en_US@currency=euro) != USD - %s", u_errorName(status));
1329 }
1330 }
1331 }
1332
1333 #endif
1334
1335 /**
1336 * @bug 4139504
1337 * toString() doesn't work with language_VARIANT.
1338 */
1339 void
TestToString()1340 LocaleTest::TestToString() {
1341 Locale DATA [] = {
1342 Locale("xx", "", ""),
1343 Locale("", "YY", ""),
1344 Locale("", "", "ZZ"),
1345 Locale("xx", "YY", ""),
1346 Locale("xx", "", "ZZ"),
1347 Locale("", "YY", "ZZ"),
1348 Locale("xx", "YY", "ZZ"),
1349 };
1350
1351 const char DATA_S [][20] = {
1352 "xx",
1353 "_YY",
1354 "__ZZ",
1355 "xx_YY",
1356 "xx__ZZ",
1357 "_YY_ZZ",
1358 "xx_YY_ZZ",
1359 };
1360
1361 for (int32_t i=0; i < 7; ++i) {
1362 const char *name;
1363 name = DATA[i].getName();
1364
1365 if (strcmp(name, DATA_S[i]) != 0)
1366 {
1367 errln("Fail: Locale.getName(), got:" + UnicodeString(name) + ", expected: " + DATA_S[i]);
1368 }
1369 else
1370 logln("Pass: Locale.getName(), got:" + UnicodeString(name) );
1371 }
1372 }
1373
1374 #if !UCONFIG_NO_FORMATTING
1375
1376 /**
1377 * @bug 4139940
1378 * Couldn't reproduce this bug -- probably was fixed earlier.
1379 *
1380 * ORIGINAL BUG REPORT:
1381 * -- basically, hungarian for monday shouldn't have an \u00f4
1382 * (o circumflex)in it instead it should be an o with 2 inclined
1383 * (right) lines over it..
1384 *
1385 * You may wonder -- why do all this -- why not just add a line to
1386 * LocaleData? Well, I could see by inspection that the locale file had the
1387 * right character in it, so I wanted to check the rest of the pipeline -- a
1388 * very remote possibility, but I wanted to be sure. The other possibility
1389 * is that something is wrong with the font mapping subsystem, but we can't
1390 * test that here.
1391 */
1392 void
Test4139940()1393 LocaleTest::Test4139940()
1394 {
1395 Locale mylocale("hu", "", "");
1396 UDate mydate = date(98,3,13); // A Monday
1397 UErrorCode status = U_ZERO_ERROR;
1398 SimpleDateFormat df_full("EEEE", mylocale, status);
1399 if(U_FAILURE(status)){
1400 dataerrln(UnicodeString("Could not create SimpleDateFormat object for locale hu. Error: ") + UnicodeString(u_errorName(status)));
1401 return;
1402 }
1403 UnicodeString str;
1404 FieldPosition pos(FieldPosition::DONT_CARE);
1405 df_full.format(mydate, str, pos);
1406 // Make sure that o circumflex (\u00F4) is NOT there, and
1407 // o double acute (\u0151) IS.
1408 char16_t ocf = 0x00f4;
1409 char16_t oda = 0x0151;
1410
1411 if (str.indexOf(oda) < 0 || str.indexOf(ocf) >= 0) {
1412 /* If the default calendar of the default locale is not "gregorian" this test will fail. */
1413 LocalPointer<Calendar> defaultCalendar(Calendar::createInstance(status));
1414 if (strcmp(defaultCalendar->getType(), "gregorian") == 0) {
1415 errln("Fail: Monday in Hungarian is wrong - oda's index is %d and ocf's is %d",
1416 str.indexOf(oda), str.indexOf(ocf));
1417 } else {
1418 logln(UnicodeString("An error is produce in non Gregorian calendar."));
1419 }
1420 logln(UnicodeString("String is: ") + str );
1421 }
1422 }
1423
1424 UDate
date(int32_t y,int32_t m,int32_t d,int32_t hr,int32_t min,int32_t sec)1425 LocaleTest::date(int32_t y, int32_t m, int32_t d, int32_t hr, int32_t min, int32_t sec)
1426 {
1427 UErrorCode status = U_ZERO_ERROR;
1428 Calendar *cal = Calendar::createInstance(status);
1429 if (cal == 0)
1430 return 0.0;
1431 cal->clear();
1432 cal->set(1900 + y, m, d, hr, min, sec); // Add 1900 to follow java.util.Date protocol
1433 UDate dt = cal->getTime(status);
1434 if (U_FAILURE(status))
1435 return 0.0;
1436
1437 delete cal;
1438 return dt;
1439 }
1440
1441 /**
1442 * @bug 4143951
1443 * Russian first day of week should be Monday. Confirmed.
1444 */
1445 void
Test4143951()1446 LocaleTest::Test4143951()
1447 {
1448 UErrorCode status = U_ZERO_ERROR;
1449 Calendar *cal = Calendar::createInstance(Locale("ru", "", ""), status);
1450 if(U_SUCCESS(status)) {
1451 if (cal->getFirstDayOfWeek(status) != UCAL_MONDAY) {
1452 dataerrln("Fail: First day of week in Russia should be Monday");
1453 }
1454 }
1455 delete cal;
1456 }
1457
1458 #endif
1459
1460 /**
1461 * @bug 4147315
1462 * java.util.Locale.getISO3Country() works wrong for non ISO-3166 codes.
1463 * Should throw an exception for unknown locales
1464 */
1465 void
Test4147315()1466 LocaleTest::Test4147315()
1467 {
1468 UnicodeString temp;
1469 // Try with codes that are the wrong length but happen to match text
1470 // at a valid offset in the mapping table
1471 Locale locale("xxx", "CCC");
1472
1473 const char *result = locale.getISO3Country();
1474
1475 // Change to conform to C api usage
1476 if((result==nullptr)||(result[0] != 0))
1477 errln("ERROR: getISO3Country() returns: " + UnicodeString(result,"") +
1478 " for locale '" + (temp=locale.getName()) + "' rather than exception" );
1479 }
1480
1481 /**
1482 * @bug 4147317
1483 * java.util.Locale.getISO3Language() works wrong for non ISO-3166 codes.
1484 * Should throw an exception for unknown locales
1485 */
1486 void
Test4147317()1487 LocaleTest::Test4147317()
1488 {
1489 UnicodeString temp;
1490 // Try with codes that are the wrong length but happen to match text
1491 // at a valid offset in the mapping table
1492 Locale locale("xxx", "CCC");
1493
1494 const char *result = locale.getISO3Language();
1495
1496 // Change to conform to C api usage
1497 if((result==nullptr)||(result[0] != 0))
1498 errln("ERROR: getISO3Language() returns: " + UnicodeString(result,"") +
1499 " for locale '" + (temp=locale.getName()) + "' rather than exception" );
1500 }
1501
1502 /*
1503 * @bug 4147552
1504 */
1505 void
Test4147552()1506 LocaleTest::Test4147552()
1507 {
1508 Locale locales [] = { Locale("no", "NO"),
1509 Locale("no", "NO", "B"),
1510 Locale("no", "NO", "NY")
1511 };
1512
1513 UnicodeString edn("Norwegian (Norway, B)");
1514 UnicodeString englishDisplayNames [] = {
1515 "Norwegian (Norway)",
1516 edn,
1517 // "Norwegian (Norway,B)",
1518 //"Norwegian (Norway,NY)"
1519 "Norwegian (Norway, NY)"
1520 };
1521 UnicodeString ndn("norsk (Norge, B");
1522 UnicodeString norwegianDisplayNames [] = {
1523 "norsk (Norge)",
1524 "norsk (Norge, B)",
1525 //ndn,
1526 "norsk (Noreg, NY)"
1527 //"Norsk (Noreg, Nynorsk)"
1528 };
1529 UErrorCode status = U_ZERO_ERROR;
1530
1531 Locale saveLocale;
1532 Locale::setDefault(Locale::getEnglish(), status);
1533 for (int32_t i = 0; i < 3; ++i) {
1534 Locale loc = locales[i];
1535 UnicodeString temp;
1536 if (loc.getDisplayName(temp) != englishDisplayNames[i])
1537 dataerrln("English display-name mismatch: expected " +
1538 englishDisplayNames[i] + ", got " + loc.getDisplayName(temp));
1539 if (loc.getDisplayName(loc, temp) != norwegianDisplayNames[i])
1540 dataerrln("Norwegian display-name mismatch: expected " +
1541 norwegianDisplayNames[i] + ", got " +
1542 loc.getDisplayName(loc, temp));
1543 }
1544 Locale::setDefault(saveLocale, status);
1545 }
1546
1547 void
TestVariantParsing()1548 LocaleTest::TestVariantParsing()
1549 {
1550 Locale en_US_custom("en", "US", "De Anza_Cupertino_California_United States_Earth");
1551
1552 UnicodeString dispName("English (United States, DE ANZA_CUPERTINO_CALIFORNIA_UNITED STATES_EARTH)");
1553 UnicodeString dispVar("DE ANZA_CUPERTINO_CALIFORNIA_UNITED STATES_EARTH");
1554
1555 UnicodeString got;
1556
1557 en_US_custom.getDisplayVariant(Locale::getUS(), got);
1558 if(got != dispVar) {
1559 errln("FAIL: getDisplayVariant()");
1560 errln("Wanted: " + dispVar);
1561 errln("Got : " + got);
1562 }
1563
1564 en_US_custom.getDisplayName(Locale::getUS(), got);
1565 if(got != dispName) {
1566 dataerrln("FAIL: getDisplayName()");
1567 dataerrln("Wanted: " + dispName);
1568 dataerrln("Got : " + got);
1569 }
1570
1571 Locale shortVariant("fr", "FR", "foo");
1572 shortVariant.getDisplayVariant(got);
1573
1574 if(got != "FOO") {
1575 errln("FAIL: getDisplayVariant()");
1576 errln("Wanted: foo");
1577 errln("Got : " + got);
1578 }
1579
1580 Locale bogusVariant("fr", "FR", "_foo");
1581 bogusVariant.getDisplayVariant(got);
1582
1583 if(got != "FOO") {
1584 errln("FAIL: getDisplayVariant()");
1585 errln("Wanted: foo");
1586 errln("Got : " + got);
1587 }
1588
1589 Locale bogusVariant2("fr", "FR", "foo_");
1590 bogusVariant2.getDisplayVariant(got);
1591
1592 if(got != "FOO") {
1593 errln("FAIL: getDisplayVariant()");
1594 errln("Wanted: foo");
1595 errln("Got : " + got);
1596 }
1597
1598 Locale bogusVariant3("fr", "FR", "_foo_");
1599 bogusVariant3.getDisplayVariant(got);
1600
1601 if(got != "FOO") {
1602 errln("FAIL: getDisplayVariant()");
1603 errln("Wanted: foo");
1604 errln("Got : " + got);
1605 }
1606 }
1607
Test20639_DeprecatesISO3Language()1608 void LocaleTest::Test20639_DeprecatesISO3Language() {
1609 IcuTestErrorCode status(*this, "Test20639_DeprecatesISO3Language");
1610
1611 const struct TestCase {
1612 const char* localeName;
1613 const char* expectedISO3Language;
1614 } cases[] = {
1615 {"nb", "nob"},
1616 {"no", "nor"}, // why not nob?
1617 {"he", "heb"},
1618 {"iw", "heb"},
1619 {"ro", "ron"},
1620 {"mo", "mol"},
1621 };
1622 for (auto& cas : cases) {
1623 Locale loc(cas.localeName);
1624 const char* actual = loc.getISO3Language();
1625 assertEquals(cas.localeName, cas.expectedISO3Language, actual);
1626 }
1627 }
1628
1629 #if !UCONFIG_NO_FORMATTING
1630
1631 /**
1632 * @bug 4105828
1633 * Currency symbol in zh is wrong. We will test this at the NumberFormat
1634 * end to test the whole pipe.
1635 */
1636 void
Test4105828()1637 LocaleTest::Test4105828()
1638 {
1639 Locale LOC [] = { Locale::getChinese(), Locale("zh", "CN", ""),
1640 Locale("zh", "TW", ""), Locale("zh", "HK", "") };
1641 UErrorCode status = U_ZERO_ERROR;
1642 for (int32_t i = 0; i < 4; ++i) {
1643 NumberFormat *fmt = NumberFormat::createPercentInstance(LOC[i], status);
1644 if(U_FAILURE(status)) {
1645 dataerrln("Couldn't create NumberFormat - %s", u_errorName(status));
1646 return;
1647 }
1648 UnicodeString result;
1649 FieldPosition pos(FieldPosition::DONT_CARE);
1650 fmt->format((int32_t)1, result, pos);
1651 UnicodeString temp;
1652 if(result != "100%") {
1653 errln(UnicodeString("Percent for ") + LOC[i].getDisplayName(temp) + " should be 100%, got " + result);
1654 }
1655 delete fmt;
1656 }
1657 }
1658
1659 #endif
1660
1661 // Tests setBogus and isBogus APIs for Locale
1662 // Jitterbug 1735
1663 void
TestSetIsBogus()1664 LocaleTest::TestSetIsBogus() {
1665 Locale l("en_US");
1666 l.setToBogus();
1667 if(l.isBogus() != true) {
1668 errln("After setting bogus, didn't return true");
1669 }
1670 l = "en_US"; // This should reset bogus
1671 if(l.isBogus() != false) {
1672 errln("After resetting bogus, didn't return false");
1673 }
1674 }
1675
1676
1677 void
TestAddLikelySubtags()1678 LocaleTest::TestAddLikelySubtags() {
1679 IcuTestErrorCode status(*this, "TestAddLikelySubtags()");
1680
1681 static const Locale min("sv");
1682 static const Locale max("sv_Latn_SE");
1683
1684 Locale result(min);
1685 result.addLikelySubtags(status);
1686 status.errIfFailureAndReset("\"%s\"", min.getName());
1687 assertEquals("addLikelySubtags", max.getName(), result.getName());
1688 }
1689
1690
1691 void
TestMinimizeSubtags()1692 LocaleTest::TestMinimizeSubtags() {
1693 IcuTestErrorCode status(*this, "TestMinimizeSubtags()");
1694
1695 static const Locale max("zh_Hant_TW");
1696 static const Locale min("zh_TW");
1697
1698 Locale result(max);
1699 result.minimizeSubtags(status);
1700 status.errIfFailureAndReset("\"%s\"", max.getName());
1701 assertEquals("minimizeSubtags", min.getName(), result.getName());
1702 }
1703
1704
1705 void
TestAddLikelyAndMinimizeSubtags()1706 LocaleTest::TestAddLikelyAndMinimizeSubtags() {
1707 IcuTestErrorCode status(*this, "TestAddLikelyAndMinimizeSubtags()");
1708
1709 static const struct {
1710 const char* const from;
1711 const char* const add;
1712 const char* const remove;
1713 } full_data[] = {
1714 {
1715 "und_AQ",
1716 "_Latn_AQ",
1717 "_AQ"
1718 }, {
1719 "und_Zzzz_AQ",
1720 "_Latn_AQ",
1721 "_AQ"
1722 }, {
1723 "und_Latn_AQ",
1724 "_Latn_AQ",
1725 "_AQ"
1726 }, {
1727 "und_Moon_AQ",
1728 "_Moon_AQ",
1729 "_Moon_AQ"
1730 }, {
1731 "aa",
1732 "aa_Latn_ET",
1733 "aa"
1734 }, {
1735 "af",
1736 "af_Latn_ZA",
1737 "af"
1738 }, {
1739 "ak",
1740 "ak_Latn_GH",
1741 "ak"
1742 }, {
1743 "am",
1744 "am_Ethi_ET",
1745 "am"
1746 }, {
1747 "ar",
1748 "ar_Arab_EG",
1749 "ar"
1750 }, {
1751 "as",
1752 "as_Beng_IN",
1753 "as"
1754 }, {
1755 "az",
1756 "az_Latn_AZ",
1757 "az"
1758 }, {
1759 "be",
1760 "be_Cyrl_BY",
1761 "be"
1762 }, {
1763 "bg",
1764 "bg_Cyrl_BG",
1765 "bg"
1766 }, {
1767 "bn",
1768 "bn_Beng_BD",
1769 "bn"
1770 }, {
1771 "bo",
1772 "bo_Tibt_CN",
1773 "bo"
1774 }, {
1775 "bs",
1776 "bs_Latn_BA",
1777 "bs"
1778 }, {
1779 "ca",
1780 "ca_Latn_ES",
1781 "ca"
1782 }, {
1783 "ch",
1784 "ch_Latn_GU",
1785 "ch"
1786 }, {
1787 "chk",
1788 "chk_Latn_FM",
1789 "chk"
1790 }, {
1791 "cs",
1792 "cs_Latn_CZ",
1793 "cs"
1794 }, {
1795 "cy",
1796 "cy_Latn_GB",
1797 "cy"
1798 }, {
1799 "da",
1800 "da_Latn_DK",
1801 "da"
1802 }, {
1803 "de",
1804 "de_Latn_DE",
1805 "de"
1806 }, {
1807 "dv",
1808 "dv_Thaa_MV",
1809 "dv"
1810 }, {
1811 "dz",
1812 "dz_Tibt_BT",
1813 "dz"
1814 }, {
1815 "ee",
1816 "ee_Latn_GH",
1817 "ee"
1818 }, {
1819 "el",
1820 "el_Grek_GR",
1821 "el"
1822 }, {
1823 "en",
1824 "en_Latn_US",
1825 "en"
1826 }, {
1827 "es",
1828 "es_Latn_ES",
1829 "es"
1830 }, {
1831 "et",
1832 "et_Latn_EE",
1833 "et"
1834 }, {
1835 "eu",
1836 "eu_Latn_ES",
1837 "eu"
1838 }, {
1839 "fa",
1840 "fa_Arab_IR",
1841 "fa"
1842 }, {
1843 "fi",
1844 "fi_Latn_FI",
1845 "fi"
1846 }, {
1847 "fil",
1848 "fil_Latn_PH",
1849 "fil"
1850 }, {
1851 "fj",
1852 "fj_Latn_FJ",
1853 "fj"
1854 }, {
1855 "fo",
1856 "fo_Latn_FO",
1857 "fo"
1858 }, {
1859 "fr",
1860 "fr_Latn_FR",
1861 "fr"
1862 }, {
1863 "fur",
1864 "fur_Latn_IT",
1865 "fur"
1866 }, {
1867 "ga",
1868 "ga_Latn_IE",
1869 "ga"
1870 }, {
1871 "gaa",
1872 "gaa_Latn_GH",
1873 "gaa"
1874 }, {
1875 "gl",
1876 "gl_Latn_ES",
1877 "gl"
1878 }, {
1879 "gn",
1880 "gn_Latn_PY",
1881 "gn"
1882 }, {
1883 "gu",
1884 "gu_Gujr_IN",
1885 "gu"
1886 }, {
1887 "ha",
1888 "ha_Latn_NG",
1889 "ha"
1890 }, {
1891 "haw",
1892 "haw_Latn_US",
1893 "haw"
1894 }, {
1895 "he",
1896 "he_Hebr_IL",
1897 "he"
1898 }, {
1899 "hi",
1900 "hi_Deva_IN",
1901 "hi"
1902 }, {
1903 "hr",
1904 "hr_Latn_HR",
1905 "hr"
1906 }, {
1907 "ht",
1908 "ht_Latn_HT",
1909 "ht"
1910 }, {
1911 "hu",
1912 "hu_Latn_HU",
1913 "hu"
1914 }, {
1915 "hy",
1916 "hy_Armn_AM",
1917 "hy"
1918 }, {
1919 "id",
1920 "id_Latn_ID",
1921 "id"
1922 }, {
1923 "ig",
1924 "ig_Latn_NG",
1925 "ig"
1926 }, {
1927 "ii",
1928 "ii_Yiii_CN",
1929 "ii"
1930 }, {
1931 "is",
1932 "is_Latn_IS",
1933 "is"
1934 }, {
1935 "it",
1936 "it_Latn_IT",
1937 "it"
1938 }, {
1939 "ja",
1940 "ja_Jpan_JP",
1941 "ja"
1942 }, {
1943 "ka",
1944 "ka_Geor_GE",
1945 "ka"
1946 }, {
1947 "kaj",
1948 "kaj_Latn_NG",
1949 "kaj"
1950 }, {
1951 "kam",
1952 "kam_Latn_KE",
1953 "kam"
1954 }, {
1955 "kk",
1956 "kk_Cyrl_KZ",
1957 "kk"
1958 }, {
1959 "kl",
1960 "kl_Latn_GL",
1961 "kl"
1962 }, {
1963 "km",
1964 "km_Khmr_KH",
1965 "km"
1966 }, {
1967 "kn",
1968 "kn_Knda_IN",
1969 "kn"
1970 }, {
1971 "ko",
1972 "ko_Kore_KR",
1973 "ko"
1974 }, {
1975 "kok",
1976 "kok_Deva_IN",
1977 "kok"
1978 }, {
1979 "kpe",
1980 "kpe_Latn_LR",
1981 "kpe"
1982 }, {
1983 "ku",
1984 "ku_Latn_TR",
1985 "ku"
1986 }, {
1987 "ky",
1988 "ky_Cyrl_KG",
1989 "ky"
1990 }, {
1991 "la",
1992 "la_Latn_VA",
1993 "la"
1994 }, {
1995 "ln",
1996 "ln_Latn_CD",
1997 "ln"
1998 }, {
1999 "lo",
2000 "lo_Laoo_LA",
2001 "lo"
2002 }, {
2003 "lt",
2004 "lt_Latn_LT",
2005 "lt"
2006 }, {
2007 "lv",
2008 "lv_Latn_LV",
2009 "lv"
2010 }, {
2011 "mg",
2012 "mg_Latn_MG",
2013 "mg"
2014 }, {
2015 "mh",
2016 "mh_Latn_MH",
2017 "mh"
2018 }, {
2019 "mk",
2020 "mk_Cyrl_MK",
2021 "mk"
2022 }, {
2023 "ml",
2024 "ml_Mlym_IN",
2025 "ml"
2026 }, {
2027 "mn",
2028 "mn_Cyrl_MN",
2029 "mn"
2030 }, {
2031 "mr",
2032 "mr_Deva_IN",
2033 "mr"
2034 }, {
2035 "ms",
2036 "ms_Latn_MY",
2037 "ms"
2038 }, {
2039 "mt",
2040 "mt_Latn_MT",
2041 "mt"
2042 }, {
2043 "my",
2044 "my_Mymr_MM",
2045 "my"
2046 }, {
2047 "na",
2048 "na_Latn_NR",
2049 "na"
2050 }, {
2051 "ne",
2052 "ne_Deva_NP",
2053 "ne"
2054 }, {
2055 "niu",
2056 "niu_Latn_NU",
2057 "niu"
2058 }, {
2059 "nl",
2060 "nl_Latn_NL",
2061 "nl"
2062 }, {
2063 "nn",
2064 "nn_Latn_NO",
2065 "nn"
2066 }, {
2067 "no",
2068 "no_Latn_NO",
2069 "no"
2070 }, {
2071 "nr",
2072 "nr_Latn_ZA",
2073 "nr"
2074 }, {
2075 "nso",
2076 "nso_Latn_ZA",
2077 "nso"
2078 }, {
2079 "om",
2080 "om_Latn_ET",
2081 "om"
2082 }, {
2083 "or",
2084 "or_Orya_IN",
2085 "or"
2086 }, {
2087 "pa",
2088 "pa_Guru_IN",
2089 "pa"
2090 }, {
2091 "pa_Arab",
2092 "pa_Arab_PK",
2093 "pa_PK"
2094 }, {
2095 "pa_PK",
2096 "pa_Arab_PK",
2097 "pa_PK"
2098 }, {
2099 "pap",
2100 "pap_Latn_CW",
2101 "pap"
2102 }, {
2103 "pau",
2104 "pau_Latn_PW",
2105 "pau"
2106 }, {
2107 "pl",
2108 "pl_Latn_PL",
2109 "pl"
2110 }, {
2111 "ps",
2112 "ps_Arab_AF",
2113 "ps"
2114 }, {
2115 "pt",
2116 "pt_Latn_BR",
2117 "pt"
2118 }, {
2119 "rn",
2120 "rn_Latn_BI",
2121 "rn"
2122 }, {
2123 "ro",
2124 "ro_Latn_RO",
2125 "ro"
2126 }, {
2127 "ru",
2128 "ru_Cyrl_RU",
2129 "ru"
2130 }, {
2131 "rw",
2132 "rw_Latn_RW",
2133 "rw"
2134 }, {
2135 "sa",
2136 "sa_Deva_IN",
2137 "sa"
2138 }, {
2139 "se",
2140 "se_Latn_NO",
2141 "se"
2142 }, {
2143 "sg",
2144 "sg_Latn_CF",
2145 "sg"
2146 }, {
2147 "si",
2148 "si_Sinh_LK",
2149 "si"
2150 }, {
2151 "sid",
2152 "sid_Latn_ET",
2153 "sid"
2154 }, {
2155 "sk",
2156 "sk_Latn_SK",
2157 "sk"
2158 }, {
2159 "sl",
2160 "sl_Latn_SI",
2161 "sl"
2162 }, {
2163 "sm",
2164 "sm_Latn_WS",
2165 "sm"
2166 }, {
2167 "so",
2168 "so_Latn_SO",
2169 "so"
2170 }, {
2171 "sq",
2172 "sq_Latn_AL",
2173 "sq"
2174 }, {
2175 "sr",
2176 "sr_Cyrl_RS",
2177 "sr"
2178 }, {
2179 "ss",
2180 "ss_Latn_ZA",
2181 "ss"
2182 }, {
2183 "st",
2184 "st_Latn_ZA",
2185 "st"
2186 }, {
2187 "sv",
2188 "sv_Latn_SE",
2189 "sv"
2190 }, {
2191 "sw",
2192 "sw_Latn_TZ",
2193 "sw"
2194 }, {
2195 "ta",
2196 "ta_Taml_IN",
2197 "ta"
2198 }, {
2199 "te",
2200 "te_Telu_IN",
2201 "te"
2202 }, {
2203 "tet",
2204 "tet_Latn_TL",
2205 "tet"
2206 }, {
2207 "tg",
2208 "tg_Cyrl_TJ",
2209 "tg"
2210 }, {
2211 "th",
2212 "th_Thai_TH",
2213 "th"
2214 }, {
2215 "ti",
2216 "ti_Ethi_ET",
2217 "ti"
2218 }, {
2219 "tig",
2220 "tig_Ethi_ER",
2221 "tig"
2222 }, {
2223 "tk",
2224 "tk_Latn_TM",
2225 "tk"
2226 }, {
2227 "tkl",
2228 "tkl_Latn_TK",
2229 "tkl"
2230 }, {
2231 "tn",
2232 "tn_Latn_ZA",
2233 "tn"
2234 }, {
2235 "to",
2236 "to_Latn_TO",
2237 "to"
2238 }, {
2239 "tpi",
2240 "tpi_Latn_PG",
2241 "tpi"
2242 }, {
2243 "tr",
2244 "tr_Latn_TR",
2245 "tr"
2246 }, {
2247 "ts",
2248 "ts_Latn_ZA",
2249 "ts"
2250 }, {
2251 "tt",
2252 "tt_Cyrl_RU",
2253 "tt"
2254 }, {
2255 "tvl",
2256 "tvl_Latn_TV",
2257 "tvl"
2258 }, {
2259 "ty",
2260 "ty_Latn_PF",
2261 "ty"
2262 }, {
2263 "uk",
2264 "uk_Cyrl_UA",
2265 "uk"
2266 }, {
2267 "und",
2268 "en_Latn_US",
2269 "en"
2270 }, {
2271 "und_AD",
2272 "ca_Latn_AD",
2273 "ca_AD"
2274 }, {
2275 "und_AE",
2276 "ar_Arab_AE",
2277 "ar_AE"
2278 }, {
2279 "und_AF",
2280 "fa_Arab_AF",
2281 "fa_AF"
2282 }, {
2283 "und_AL",
2284 "sq_Latn_AL",
2285 "sq"
2286 }, {
2287 "und_AM",
2288 "hy_Armn_AM",
2289 "hy"
2290 }, {
2291 "und_AO",
2292 "pt_Latn_AO",
2293 "pt_AO"
2294 }, {
2295 "und_AR",
2296 "es_Latn_AR",
2297 "es_AR"
2298 }, {
2299 "und_AS",
2300 "sm_Latn_AS",
2301 "sm_AS"
2302 }, {
2303 "und_AT",
2304 "de_Latn_AT",
2305 "de_AT"
2306 }, {
2307 "und_AW",
2308 "nl_Latn_AW",
2309 "nl_AW"
2310 }, {
2311 "und_AX",
2312 "sv_Latn_AX",
2313 "sv_AX"
2314 }, {
2315 "und_AZ",
2316 "az_Latn_AZ",
2317 "az"
2318 }, {
2319 "und_Arab",
2320 "ar_Arab_EG",
2321 "ar"
2322 }, {
2323 "und_Arab_IN",
2324 "ur_Arab_IN",
2325 "ur_IN"
2326 }, {
2327 "und_Arab_PK",
2328 "ur_Arab_PK",
2329 "ur"
2330 }, {
2331 "und_Arab_SN",
2332 "ar_Arab_SN",
2333 "ar_SN"
2334 }, {
2335 "und_Armn",
2336 "hy_Armn_AM",
2337 "hy"
2338 }, {
2339 "und_BA",
2340 "bs_Latn_BA",
2341 "bs"
2342 }, {
2343 "und_BD",
2344 "bn_Beng_BD",
2345 "bn"
2346 }, {
2347 "und_BE",
2348 "nl_Latn_BE",
2349 "nl_BE"
2350 }, {
2351 "und_BF",
2352 "fr_Latn_BF",
2353 "fr_BF"
2354 }, {
2355 "und_BG",
2356 "bg_Cyrl_BG",
2357 "bg"
2358 }, {
2359 "und_BH",
2360 "ar_Arab_BH",
2361 "ar_BH"
2362 }, {
2363 "und_BI",
2364 "rn_Latn_BI",
2365 "rn"
2366 }, {
2367 "und_BJ",
2368 "fr_Latn_BJ",
2369 "fr_BJ"
2370 }, {
2371 "und_BN",
2372 "ms_Latn_BN",
2373 "ms_BN"
2374 }, {
2375 "und_BO",
2376 "es_Latn_BO",
2377 "es_BO"
2378 }, {
2379 "und_BR",
2380 "pt_Latn_BR",
2381 "pt"
2382 }, {
2383 "und_BT",
2384 "dz_Tibt_BT",
2385 "dz"
2386 }, {
2387 "und_BY",
2388 "be_Cyrl_BY",
2389 "be"
2390 }, {
2391 "und_Beng",
2392 "bn_Beng_BD",
2393 "bn"
2394 }, {
2395 "und_Beng_IN",
2396 "bn_Beng_IN",
2397 "bn_IN"
2398 }, {
2399 "und_CD",
2400 "sw_Latn_CD",
2401 "sw_CD"
2402 }, {
2403 "und_CF",
2404 "fr_Latn_CF",
2405 "fr_CF"
2406 }, {
2407 "und_CG",
2408 "fr_Latn_CG",
2409 "fr_CG"
2410 }, {
2411 "und_CH",
2412 "de_Latn_CH",
2413 "de_CH"
2414 }, {
2415 "und_CI",
2416 "fr_Latn_CI",
2417 "fr_CI"
2418 }, {
2419 "und_CL",
2420 "es_Latn_CL",
2421 "es_CL"
2422 }, {
2423 "und_CM",
2424 "fr_Latn_CM",
2425 "fr_CM"
2426 }, {
2427 "und_CN",
2428 "zh_Hans_CN",
2429 "zh"
2430 }, {
2431 "und_CO",
2432 "es_Latn_CO",
2433 "es_CO"
2434 }, {
2435 "und_CR",
2436 "es_Latn_CR",
2437 "es_CR"
2438 }, {
2439 "und_CU",
2440 "es_Latn_CU",
2441 "es_CU"
2442 }, {
2443 "und_CV",
2444 "pt_Latn_CV",
2445 "pt_CV"
2446 }, {
2447 "und_CY",
2448 "el_Grek_CY",
2449 "el_CY"
2450 }, {
2451 "und_CZ",
2452 "cs_Latn_CZ",
2453 "cs"
2454 }, {
2455 "und_Cyrl",
2456 "ru_Cyrl_RU",
2457 "ru"
2458 }, {
2459 "und_Cyrl_KZ",
2460 "ru_Cyrl_KZ",
2461 "ru_KZ"
2462 }, {
2463 "und_DE",
2464 "de_Latn_DE",
2465 "de"
2466 }, {
2467 "und_DJ",
2468 "aa_Latn_DJ",
2469 "aa_DJ"
2470 }, {
2471 "und_DK",
2472 "da_Latn_DK",
2473 "da"
2474 }, {
2475 "und_DO",
2476 "es_Latn_DO",
2477 "es_DO"
2478 }, {
2479 "und_DZ",
2480 "ar_Arab_DZ",
2481 "ar_DZ"
2482 }, {
2483 "und_Deva",
2484 "hi_Deva_IN",
2485 "hi"
2486 }, {
2487 "und_EC",
2488 "es_Latn_EC",
2489 "es_EC"
2490 }, {
2491 "und_EE",
2492 "et_Latn_EE",
2493 "et"
2494 }, {
2495 "und_EG",
2496 "ar_Arab_EG",
2497 "ar"
2498 }, {
2499 "und_EH",
2500 "ar_Arab_EH",
2501 "ar_EH"
2502 }, {
2503 "und_ER",
2504 "ti_Ethi_ER",
2505 "ti_ER"
2506 }, {
2507 "und_ES",
2508 "es_Latn_ES",
2509 "es"
2510 }, {
2511 "und_ET",
2512 "am_Ethi_ET",
2513 "am"
2514 }, {
2515 "und_Ethi",
2516 "am_Ethi_ET",
2517 "am"
2518 }, {
2519 "und_Ethi_ER",
2520 "am_Ethi_ER",
2521 "am_ER"
2522 }, {
2523 "und_FI",
2524 "fi_Latn_FI",
2525 "fi"
2526 }, {
2527 "und_FM",
2528 "en_Latn_FM",
2529 "en_FM"
2530 }, {
2531 "und_FO",
2532 "fo_Latn_FO",
2533 "fo"
2534 }, {
2535 "und_FR",
2536 "fr_Latn_FR",
2537 "fr"
2538 }, {
2539 "und_GA",
2540 "fr_Latn_GA",
2541 "fr_GA"
2542 }, {
2543 "und_GE",
2544 "ka_Geor_GE",
2545 "ka"
2546 }, {
2547 "und_GF",
2548 "fr_Latn_GF",
2549 "fr_GF"
2550 }, {
2551 "und_GL",
2552 "kl_Latn_GL",
2553 "kl"
2554 }, {
2555 "und_GN",
2556 "fr_Latn_GN",
2557 "fr_GN"
2558 }, {
2559 "und_GP",
2560 "fr_Latn_GP",
2561 "fr_GP"
2562 }, {
2563 "und_GQ",
2564 "es_Latn_GQ",
2565 "es_GQ"
2566 }, {
2567 "und_GR",
2568 "el_Grek_GR",
2569 "el"
2570 }, {
2571 "und_GT",
2572 "es_Latn_GT",
2573 "es_GT"
2574 }, {
2575 "und_GU",
2576 "en_Latn_GU",
2577 "en_GU"
2578 }, {
2579 "und_GW",
2580 "pt_Latn_GW",
2581 "pt_GW"
2582 }, {
2583 "und_Geor",
2584 "ka_Geor_GE",
2585 "ka"
2586 }, {
2587 "und_Grek",
2588 "el_Grek_GR",
2589 "el"
2590 }, {
2591 "und_Gujr",
2592 "gu_Gujr_IN",
2593 "gu"
2594 }, {
2595 "und_Guru",
2596 "pa_Guru_IN",
2597 "pa"
2598 }, {
2599 "und_HK",
2600 "zh_Hant_HK",
2601 "zh_HK"
2602 }, {
2603 "und_HN",
2604 "es_Latn_HN",
2605 "es_HN"
2606 }, {
2607 "und_HR",
2608 "hr_Latn_HR",
2609 "hr"
2610 }, {
2611 "und_HT",
2612 "ht_Latn_HT",
2613 "ht"
2614 }, {
2615 "und_HU",
2616 "hu_Latn_HU",
2617 "hu"
2618 }, {
2619 "und_Hani",
2620 "zh_Hani_CN",
2621 "zh_Hani"
2622 }, {
2623 "und_Hans",
2624 "zh_Hans_CN",
2625 "zh"
2626 }, {
2627 "und_Hant",
2628 "zh_Hant_TW",
2629 "zh_TW"
2630 }, {
2631 "und_Hebr",
2632 "he_Hebr_IL",
2633 "he"
2634 }, {
2635 "und_ID",
2636 "id_Latn_ID",
2637 "id"
2638 }, {
2639 "und_IL",
2640 "he_Hebr_IL",
2641 "he"
2642 }, {
2643 "und_IN",
2644 "hi_Deva_IN",
2645 "hi"
2646 }, {
2647 "und_IQ",
2648 "ar_Arab_IQ",
2649 "ar_IQ"
2650 }, {
2651 "und_IR",
2652 "fa_Arab_IR",
2653 "fa"
2654 }, {
2655 "und_IS",
2656 "is_Latn_IS",
2657 "is"
2658 }, {
2659 "und_IT",
2660 "it_Latn_IT",
2661 "it"
2662 }, {
2663 "und_JO",
2664 "ar_Arab_JO",
2665 "ar_JO"
2666 }, {
2667 "und_JP",
2668 "ja_Jpan_JP",
2669 "ja"
2670 }, {
2671 "und_Jpan",
2672 "ja_Jpan_JP",
2673 "ja"
2674 }, {
2675 "und_KG",
2676 "ky_Cyrl_KG",
2677 "ky"
2678 }, {
2679 "und_KH",
2680 "km_Khmr_KH",
2681 "km"
2682 }, {
2683 "und_KM",
2684 "ar_Arab_KM",
2685 "ar_KM"
2686 }, {
2687 "und_KP",
2688 "ko_Kore_KP",
2689 "ko_KP"
2690 }, {
2691 "und_KR",
2692 "ko_Kore_KR",
2693 "ko"
2694 }, {
2695 "und_KW",
2696 "ar_Arab_KW",
2697 "ar_KW"
2698 }, {
2699 "und_KZ",
2700 "ru_Cyrl_KZ",
2701 "ru_KZ"
2702 }, {
2703 "und_Khmr",
2704 "km_Khmr_KH",
2705 "km"
2706 }, {
2707 "und_Knda",
2708 "kn_Knda_IN",
2709 "kn"
2710 }, {
2711 "und_Kore",
2712 "ko_Kore_KR",
2713 "ko"
2714 }, {
2715 "und_LA",
2716 "lo_Laoo_LA",
2717 "lo"
2718 }, {
2719 "und_LB",
2720 "ar_Arab_LB",
2721 "ar_LB"
2722 }, {
2723 "und_LI",
2724 "de_Latn_LI",
2725 "de_LI"
2726 }, {
2727 "und_LK",
2728 "si_Sinh_LK",
2729 "si"
2730 }, {
2731 "und_LS",
2732 "st_Latn_LS",
2733 "st_LS"
2734 }, {
2735 "und_LT",
2736 "lt_Latn_LT",
2737 "lt"
2738 }, {
2739 "und_LU",
2740 "fr_Latn_LU",
2741 "fr_LU"
2742 }, {
2743 "und_LV",
2744 "lv_Latn_LV",
2745 "lv"
2746 }, {
2747 "und_LY",
2748 "ar_Arab_LY",
2749 "ar_LY"
2750 }, {
2751 "und_Laoo",
2752 "lo_Laoo_LA",
2753 "lo"
2754 }, {
2755 "und_Latn_ES",
2756 "es_Latn_ES",
2757 "es"
2758 }, {
2759 "und_Latn_ET",
2760 "en_Latn_ET",
2761 "en_ET"
2762 }, {
2763 "und_Latn_GB",
2764 "en_Latn_GB",
2765 "en_GB"
2766 }, {
2767 "und_Latn_GH",
2768 "ak_Latn_GH",
2769 "ak"
2770 }, {
2771 "und_Latn_ID",
2772 "id_Latn_ID",
2773 "id"
2774 }, {
2775 "und_Latn_IT",
2776 "it_Latn_IT",
2777 "it"
2778 }, {
2779 "und_Latn_NG",
2780 "en_Latn_NG",
2781 "en_NG"
2782 }, {
2783 "und_Latn_TR",
2784 "tr_Latn_TR",
2785 "tr"
2786 }, {
2787 "und_Latn_ZA",
2788 "en_Latn_ZA",
2789 "en_ZA"
2790 }, {
2791 "und_MA",
2792 "ar_Arab_MA",
2793 "ar_MA"
2794 }, {
2795 "und_MC",
2796 "fr_Latn_MC",
2797 "fr_MC"
2798 }, {
2799 "und_MD",
2800 "ro_Latn_MD",
2801 "ro_MD"
2802 }, {
2803 "und_ME",
2804 "sr_Latn_ME",
2805 "sr_ME"
2806 }, {
2807 "und_MG",
2808 "mg_Latn_MG",
2809 "mg"
2810 }, {
2811 "und_MK",
2812 "mk_Cyrl_MK",
2813 "mk"
2814 }, {
2815 "und_ML",
2816 "bm_Latn_ML",
2817 "bm"
2818 }, {
2819 "und_MM",
2820 "my_Mymr_MM",
2821 "my"
2822 }, {
2823 "und_MN",
2824 "mn_Cyrl_MN",
2825 "mn"
2826 }, {
2827 "und_MO",
2828 "zh_Hant_MO",
2829 "zh_MO"
2830 }, {
2831 "und_MQ",
2832 "fr_Latn_MQ",
2833 "fr_MQ"
2834 }, {
2835 "und_MR",
2836 "ar_Arab_MR",
2837 "ar_MR"
2838 }, {
2839 "und_MT",
2840 "mt_Latn_MT",
2841 "mt"
2842 }, {
2843 "und_MV",
2844 "dv_Thaa_MV",
2845 "dv"
2846 }, {
2847 "und_MX",
2848 "es_Latn_MX",
2849 "es_MX"
2850 }, {
2851 "und_MY",
2852 "ms_Latn_MY",
2853 "ms"
2854 }, {
2855 "und_MZ",
2856 "pt_Latn_MZ",
2857 "pt_MZ"
2858 }, {
2859 "und_Mlym",
2860 "ml_Mlym_IN",
2861 "ml"
2862 }, {
2863 "und_Mymr",
2864 "my_Mymr_MM",
2865 "my"
2866 }, {
2867 "und_NC",
2868 "fr_Latn_NC",
2869 "fr_NC"
2870 }, {
2871 "und_NE",
2872 "ha_Latn_NE",
2873 "ha_NE"
2874 }, {
2875 "und_NG",
2876 "en_Latn_NG",
2877 "en_NG"
2878 }, {
2879 "und_NI",
2880 "es_Latn_NI",
2881 "es_NI"
2882 }, {
2883 "und_NL",
2884 "nl_Latn_NL",
2885 "nl"
2886 }, {
2887 "und_NO",
2888 "nb_Latn_NO",
2889 "nb"
2890 }, {
2891 "und_NP",
2892 "ne_Deva_NP",
2893 "ne"
2894 }, {
2895 "und_NR",
2896 "en_Latn_NR",
2897 "en_NR"
2898 }, {
2899 "und_OM",
2900 "ar_Arab_OM",
2901 "ar_OM"
2902 }, {
2903 "und_Orya",
2904 "or_Orya_IN",
2905 "or"
2906 }, {
2907 "und_PA",
2908 "es_Latn_PA",
2909 "es_PA"
2910 }, {
2911 "und_PE",
2912 "es_Latn_PE",
2913 "es_PE"
2914 }, {
2915 "und_PF",
2916 "fr_Latn_PF",
2917 "fr_PF"
2918 }, {
2919 "und_PG",
2920 "tpi_Latn_PG",
2921 "tpi"
2922 }, {
2923 "und_PH",
2924 "fil_Latn_PH",
2925 "fil"
2926 }, {
2927 "und_PL",
2928 "pl_Latn_PL",
2929 "pl"
2930 }, {
2931 "und_PM",
2932 "fr_Latn_PM",
2933 "fr_PM"
2934 }, {
2935 "und_PR",
2936 "es_Latn_PR",
2937 "es_PR"
2938 }, {
2939 "und_PS",
2940 "ar_Arab_PS",
2941 "ar_PS"
2942 }, {
2943 "und_PT",
2944 "pt_Latn_PT",
2945 "pt_PT"
2946 }, {
2947 "und_PW",
2948 "pau_Latn_PW",
2949 "pau"
2950 }, {
2951 "und_PY",
2952 "gn_Latn_PY",
2953 "gn"
2954 }, {
2955 "und_QA",
2956 "ar_Arab_QA",
2957 "ar_QA"
2958 }, {
2959 "und_RE",
2960 "fr_Latn_RE",
2961 "fr_RE"
2962 }, {
2963 "und_RO",
2964 "ro_Latn_RO",
2965 "ro"
2966 }, {
2967 "und_RS",
2968 "sr_Cyrl_RS",
2969 "sr"
2970 }, {
2971 "und_RU",
2972 "ru_Cyrl_RU",
2973 "ru"
2974 }, {
2975 "und_RW",
2976 "rw_Latn_RW",
2977 "rw"
2978 }, {
2979 "und_SA",
2980 "ar_Arab_SA",
2981 "ar_SA"
2982 }, {
2983 "und_SD",
2984 "ar_Arab_SD",
2985 "ar_SD"
2986 }, {
2987 "und_SE",
2988 "sv_Latn_SE",
2989 "sv"
2990 }, {
2991 "und_SG",
2992 "en_Latn_SG",
2993 "en_SG"
2994 }, {
2995 "und_SI",
2996 "sl_Latn_SI",
2997 "sl"
2998 }, {
2999 "und_SJ",
3000 "nb_Latn_SJ",
3001 "nb_SJ"
3002 }, {
3003 "und_SK",
3004 "sk_Latn_SK",
3005 "sk"
3006 }, {
3007 "und_SM",
3008 "it_Latn_SM",
3009 "it_SM"
3010 }, {
3011 "und_SN",
3012 "fr_Latn_SN",
3013 "fr_SN"
3014 }, {
3015 "und_SO",
3016 "so_Latn_SO",
3017 "so"
3018 }, {
3019 "und_SR",
3020 "nl_Latn_SR",
3021 "nl_SR"
3022 }, {
3023 "und_ST",
3024 "pt_Latn_ST",
3025 "pt_ST"
3026 }, {
3027 "und_SV",
3028 "es_Latn_SV",
3029 "es_SV"
3030 }, {
3031 "und_SY",
3032 "ar_Arab_SY",
3033 "ar_SY"
3034 }, {
3035 "und_Sinh",
3036 "si_Sinh_LK",
3037 "si"
3038 }, {
3039 "und_Syrc",
3040 "syr_Syrc_IQ",
3041 "syr"
3042 }, {
3043 "und_TD",
3044 "fr_Latn_TD",
3045 "fr_TD"
3046 }, {
3047 "und_TG",
3048 "fr_Latn_TG",
3049 "fr_TG"
3050 }, {
3051 "und_TH",
3052 "th_Thai_TH",
3053 "th"
3054 }, {
3055 "und_TJ",
3056 "tg_Cyrl_TJ",
3057 "tg"
3058 }, {
3059 "und_TK",
3060 "tkl_Latn_TK",
3061 "tkl"
3062 }, {
3063 "und_TL",
3064 "pt_Latn_TL",
3065 "pt_TL"
3066 }, {
3067 "und_TM",
3068 "tk_Latn_TM",
3069 "tk"
3070 }, {
3071 "und_TN",
3072 "ar_Arab_TN",
3073 "ar_TN"
3074 }, {
3075 "und_TO",
3076 "to_Latn_TO",
3077 "to"
3078 }, {
3079 "und_TR",
3080 "tr_Latn_TR",
3081 "tr"
3082 }, {
3083 "und_TV",
3084 "tvl_Latn_TV",
3085 "tvl"
3086 }, {
3087 "und_TW",
3088 "zh_Hant_TW",
3089 "zh_TW"
3090 }, {
3091 "und_Taml",
3092 "ta_Taml_IN",
3093 "ta"
3094 }, {
3095 "und_Telu",
3096 "te_Telu_IN",
3097 "te"
3098 }, {
3099 "und_Thaa",
3100 "dv_Thaa_MV",
3101 "dv"
3102 }, {
3103 "und_Thai",
3104 "th_Thai_TH",
3105 "th"
3106 }, {
3107 "und_Tibt",
3108 "bo_Tibt_CN",
3109 "bo"
3110 }, {
3111 "und_UA",
3112 "uk_Cyrl_UA",
3113 "uk"
3114 }, {
3115 "und_UY",
3116 "es_Latn_UY",
3117 "es_UY"
3118 }, {
3119 "und_UZ",
3120 "uz_Latn_UZ",
3121 "uz"
3122 }, {
3123 "und_VA",
3124 "it_Latn_VA",
3125 "it_VA"
3126 }, {
3127 "und_VE",
3128 "es_Latn_VE",
3129 "es_VE"
3130 }, {
3131 "und_VN",
3132 "vi_Latn_VN",
3133 "vi"
3134 }, {
3135 "und_VU",
3136 "bi_Latn_VU",
3137 "bi"
3138 }, {
3139 "und_WF",
3140 "fr_Latn_WF",
3141 "fr_WF"
3142 }, {
3143 "und_WS",
3144 "sm_Latn_WS",
3145 "sm"
3146 }, {
3147 "und_YE",
3148 "ar_Arab_YE",
3149 "ar_YE"
3150 }, {
3151 "und_YT",
3152 "fr_Latn_YT",
3153 "fr_YT"
3154 }, {
3155 "und_Yiii",
3156 "ii_Yiii_CN",
3157 "ii"
3158 }, {
3159 "ur",
3160 "ur_Arab_PK",
3161 "ur"
3162 }, {
3163 "uz",
3164 "uz_Latn_UZ",
3165 "uz"
3166 }, {
3167 "uz_AF",
3168 "uz_Arab_AF",
3169 "uz_AF"
3170 }, {
3171 "uz_Arab",
3172 "uz_Arab_AF",
3173 "uz_AF"
3174 }, {
3175 "ve",
3176 "ve_Latn_ZA",
3177 "ve"
3178 }, {
3179 "vi",
3180 "vi_Latn_VN",
3181 "vi"
3182 }, {
3183 "wal",
3184 "wal_Ethi_ET",
3185 "wal"
3186 }, {
3187 "wo",
3188 "wo_Latn_SN",
3189 "wo"
3190 }, {
3191 "wo_SN",
3192 "wo_Latn_SN",
3193 "wo"
3194 }, {
3195 "xh",
3196 "xh_Latn_ZA",
3197 "xh"
3198 }, {
3199 "yo",
3200 "yo_Latn_NG",
3201 "yo"
3202 }, {
3203 "zh",
3204 "zh_Hans_CN",
3205 "zh"
3206 }, {
3207 "zh_HK",
3208 "zh_Hant_HK",
3209 "zh_HK"
3210 }, {
3211 "zh_Hani",
3212 "zh_Hani_CN",
3213 "zh_Hani"
3214 }, {
3215 "zh_Hant",
3216 "zh_Hant_TW",
3217 "zh_TW"
3218 }, {
3219 "zh_MO",
3220 "zh_Hant_MO",
3221 "zh_MO"
3222 }, {
3223 "zh_TW",
3224 "zh_Hant_TW",
3225 "zh_TW"
3226 }, {
3227 "zu",
3228 "zu_Latn_ZA",
3229 "zu"
3230 }, {
3231 "und",
3232 "en_Latn_US",
3233 "en"
3234 }, {
3235 "und_ZZ",
3236 "en_Latn_US",
3237 "en"
3238 }, {
3239 "und_CN",
3240 "zh_Hans_CN",
3241 "zh"
3242 }, {
3243 "und_TW",
3244 "zh_Hant_TW",
3245 "zh_TW"
3246 }, {
3247 "und_HK",
3248 "zh_Hant_HK",
3249 "zh_HK"
3250 }, {
3251 "und_AQ",
3252 "_Latn_AQ",
3253 "_AQ"
3254 }, {
3255 "und_Zzzz",
3256 "en_Latn_US",
3257 "en"
3258 }, {
3259 "und_Zzzz_ZZ",
3260 "en_Latn_US",
3261 "en"
3262 }, {
3263 "und_Zzzz_CN",
3264 "zh_Hans_CN",
3265 "zh"
3266 }, {
3267 "und_Zzzz_TW",
3268 "zh_Hant_TW",
3269 "zh_TW"
3270 }, {
3271 "und_Zzzz_HK",
3272 "zh_Hant_HK",
3273 "zh_HK"
3274 }, {
3275 "und_Zzzz_AQ",
3276 "_Latn_AQ",
3277 "_AQ"
3278 }, {
3279 "und_Latn",
3280 "en_Latn_US",
3281 "en"
3282 }, {
3283 "und_Latn_ZZ",
3284 "en_Latn_US",
3285 "en"
3286 }, {
3287 "und_Latn_CN",
3288 "za_Latn_CN",
3289 "za"
3290 }, {
3291 "und_Latn_TW",
3292 "trv_Latn_TW",
3293 "trv"
3294 }, {
3295 "und_Latn_HK",
3296 "zh_Latn_HK",
3297 "zh_Latn_HK"
3298 }, {
3299 "und_Latn_AQ",
3300 "_Latn_AQ",
3301 "_AQ"
3302 }, {
3303 "und_Hans",
3304 "zh_Hans_CN",
3305 "zh"
3306 }, {
3307 "und_Hans_ZZ",
3308 "zh_Hans_CN",
3309 "zh"
3310 }, {
3311 "und_Hans_CN",
3312 "zh_Hans_CN",
3313 "zh"
3314 }, {
3315 "und_Hans_TW",
3316 "zh_Hans_TW",
3317 "zh_Hans_TW"
3318 }, {
3319 "und_Hans_HK",
3320 "zh_Hans_HK",
3321 "zh_Hans_HK"
3322 }, {
3323 "und_Hans_AQ",
3324 "zh_Hans_AQ",
3325 "zh_AQ"
3326 }, {
3327 "und_Hant",
3328 "zh_Hant_TW",
3329 "zh_TW"
3330 }, {
3331 "und_Hant_ZZ",
3332 "zh_Hant_TW",
3333 "zh_TW"
3334 }, {
3335 "und_Hant_CN",
3336 "zh_Hant_CN",
3337 "zh_Hant_CN"
3338 }, {
3339 "und_Hant_TW",
3340 "zh_Hant_TW",
3341 "zh_TW"
3342 }, {
3343 "und_Hant_HK",
3344 "zh_Hant_HK",
3345 "zh_HK"
3346 }, {
3347 "und_Hant_AQ",
3348 "zh_Hant_AQ",
3349 "zh_Hant_AQ"
3350 }, {
3351 "und_Moon",
3352 "en_Moon_US",
3353 "en_Moon"
3354 }, {
3355 "und_Moon_ZZ",
3356 "en_Moon_US",
3357 "en_Moon"
3358 }, {
3359 "und_Moon_CN",
3360 "zh_Moon_CN",
3361 "zh_Moon"
3362 }, {
3363 "und_Moon_TW",
3364 "zh_Moon_TW",
3365 "zh_Moon_TW"
3366 }, {
3367 "und_Moon_HK",
3368 "zh_Moon_HK",
3369 "zh_Moon_HK"
3370 }, {
3371 "und_Moon_AQ",
3372 "_Moon_AQ",
3373 "_Moon_AQ"
3374 }, {
3375 "es",
3376 "es_Latn_ES",
3377 "es"
3378 }, {
3379 "es_ZZ",
3380 "es_Latn_ES",
3381 "es"
3382 }, {
3383 "es_CN",
3384 "es_Latn_CN",
3385 "es_CN"
3386 }, {
3387 "es_TW",
3388 "es_Latn_TW",
3389 "es_TW"
3390 }, {
3391 "es_HK",
3392 "es_Latn_HK",
3393 "es_HK"
3394 }, {
3395 "es_AQ",
3396 "es_Latn_AQ",
3397 "es_AQ"
3398 }, {
3399 "es_Zzzz",
3400 "es_Latn_ES",
3401 "es"
3402 }, {
3403 "es_Zzzz_ZZ",
3404 "es_Latn_ES",
3405 "es"
3406 }, {
3407 "es_Zzzz_CN",
3408 "es_Latn_CN",
3409 "es_CN"
3410 }, {
3411 "es_Zzzz_TW",
3412 "es_Latn_TW",
3413 "es_TW"
3414 }, {
3415 "es_Zzzz_HK",
3416 "es_Latn_HK",
3417 "es_HK"
3418 }, {
3419 "es_Zzzz_AQ",
3420 "es_Latn_AQ",
3421 "es_AQ"
3422 }, {
3423 "es_Latn",
3424 "es_Latn_ES",
3425 "es"
3426 }, {
3427 "es_Latn_ZZ",
3428 "es_Latn_ES",
3429 "es"
3430 }, {
3431 "es_Latn_CN",
3432 "es_Latn_CN",
3433 "es_CN"
3434 }, {
3435 "es_Latn_TW",
3436 "es_Latn_TW",
3437 "es_TW"
3438 }, {
3439 "es_Latn_HK",
3440 "es_Latn_HK",
3441 "es_HK"
3442 }, {
3443 "es_Latn_AQ",
3444 "es_Latn_AQ",
3445 "es_AQ"
3446 }, {
3447 "es_Hans",
3448 "es_Hans_ES",
3449 "es_Hans"
3450 }, {
3451 "es_Hans_ZZ",
3452 "es_Hans_ES",
3453 "es_Hans"
3454 }, {
3455 "es_Hans_CN",
3456 "es_Hans_CN",
3457 "es_Hans_CN"
3458 }, {
3459 "es_Hans_TW",
3460 "es_Hans_TW",
3461 "es_Hans_TW"
3462 }, {
3463 "es_Hans_HK",
3464 "es_Hans_HK",
3465 "es_Hans_HK"
3466 }, {
3467 "es_Hans_AQ",
3468 "es_Hans_AQ",
3469 "es_Hans_AQ"
3470 }, {
3471 "es_Hant",
3472 "es_Hant_ES",
3473 "es_Hant"
3474 }, {
3475 "es_Hant_ZZ",
3476 "es_Hant_ES",
3477 "es_Hant"
3478 }, {
3479 "es_Hant_CN",
3480 "es_Hant_CN",
3481 "es_Hant_CN"
3482 }, {
3483 "es_Hant_TW",
3484 "es_Hant_TW",
3485 "es_Hant_TW"
3486 }, {
3487 "es_Hant_HK",
3488 "es_Hant_HK",
3489 "es_Hant_HK"
3490 }, {
3491 "es_Hant_AQ",
3492 "es_Hant_AQ",
3493 "es_Hant_AQ"
3494 }, {
3495 "es_Moon",
3496 "es_Moon_ES",
3497 "es_Moon"
3498 }, {
3499 "es_Moon_ZZ",
3500 "es_Moon_ES",
3501 "es_Moon"
3502 }, {
3503 "es_Moon_CN",
3504 "es_Moon_CN",
3505 "es_Moon_CN"
3506 }, {
3507 "es_Moon_TW",
3508 "es_Moon_TW",
3509 "es_Moon_TW"
3510 }, {
3511 "es_Moon_HK",
3512 "es_Moon_HK",
3513 "es_Moon_HK"
3514 }, {
3515 "es_Moon_AQ",
3516 "es_Moon_AQ",
3517 "es_Moon_AQ"
3518 }, {
3519 "zh",
3520 "zh_Hans_CN",
3521 "zh"
3522 }, {
3523 "zh_ZZ",
3524 "zh_Hans_CN",
3525 "zh"
3526 }, {
3527 "zh_CN",
3528 "zh_Hans_CN",
3529 "zh"
3530 }, {
3531 "zh_TW",
3532 "zh_Hant_TW",
3533 "zh_TW"
3534 }, {
3535 "zh_HK",
3536 "zh_Hant_HK",
3537 "zh_HK"
3538 }, {
3539 "zh_AQ",
3540 "zh_Hans_AQ",
3541 "zh_AQ"
3542 }, {
3543 "zh_Zzzz",
3544 "zh_Hans_CN",
3545 "zh"
3546 }, {
3547 "zh_Zzzz_ZZ",
3548 "zh_Hans_CN",
3549 "zh"
3550 }, {
3551 "zh_Zzzz_CN",
3552 "zh_Hans_CN",
3553 "zh"
3554 }, {
3555 "zh_Zzzz_TW",
3556 "zh_Hant_TW",
3557 "zh_TW"
3558 }, {
3559 "zh_Zzzz_HK",
3560 "zh_Hant_HK",
3561 "zh_HK"
3562 }, {
3563 "zh_Zzzz_AQ",
3564 "zh_Hans_AQ",
3565 "zh_AQ"
3566 }, {
3567 "zh_Latn",
3568 "zh_Latn_CN",
3569 "zh_Latn"
3570 }, {
3571 "zh_Latn_ZZ",
3572 "zh_Latn_CN",
3573 "zh_Latn"
3574 }, {
3575 "zh_Latn_CN",
3576 "zh_Latn_CN",
3577 "zh_Latn"
3578 }, {
3579 "zh_Latn_TW",
3580 "zh_Latn_TW",
3581 "zh_Latn_TW"
3582 }, {
3583 "zh_Latn_HK",
3584 "zh_Latn_HK",
3585 "zh_Latn_HK"
3586 }, {
3587 "zh_Latn_AQ",
3588 "zh_Latn_AQ",
3589 "zh_Latn_AQ"
3590 }, {
3591 "zh_Hans",
3592 "zh_Hans_CN",
3593 "zh"
3594 }, {
3595 "zh_Hans_ZZ",
3596 "zh_Hans_CN",
3597 "zh"
3598 }, {
3599 "zh_Hans_TW",
3600 "zh_Hans_TW",
3601 "zh_Hans_TW"
3602 }, {
3603 "zh_Hans_HK",
3604 "zh_Hans_HK",
3605 "zh_Hans_HK"
3606 }, {
3607 "zh_Hans_AQ",
3608 "zh_Hans_AQ",
3609 "zh_AQ"
3610 }, {
3611 "zh_Hant",
3612 "zh_Hant_TW",
3613 "zh_TW"
3614 }, {
3615 "zh_Hant_ZZ",
3616 "zh_Hant_TW",
3617 "zh_TW"
3618 }, {
3619 "zh_Hant_CN",
3620 "zh_Hant_CN",
3621 "zh_Hant_CN"
3622 }, {
3623 "zh_Hant_AQ",
3624 "zh_Hant_AQ",
3625 "zh_Hant_AQ"
3626 }, {
3627 "zh_Moon",
3628 "zh_Moon_CN",
3629 "zh_Moon"
3630 }, {
3631 "zh_Moon_ZZ",
3632 "zh_Moon_CN",
3633 "zh_Moon"
3634 }, {
3635 "zh_Moon_CN",
3636 "zh_Moon_CN",
3637 "zh_Moon"
3638 }, {
3639 "zh_Moon_TW",
3640 "zh_Moon_TW",
3641 "zh_Moon_TW"
3642 }, {
3643 "zh_Moon_HK",
3644 "zh_Moon_HK",
3645 "zh_Moon_HK"
3646 }, {
3647 "zh_Moon_AQ",
3648 "zh_Moon_AQ",
3649 "zh_Moon_AQ"
3650 }, {
3651 "art",
3652 "",
3653 ""
3654 }, {
3655 "art_ZZ",
3656 "",
3657 ""
3658 }, {
3659 "art_CN",
3660 "",
3661 ""
3662 }, {
3663 "art_TW",
3664 "",
3665 ""
3666 }, {
3667 "art_HK",
3668 "",
3669 ""
3670 }, {
3671 "art_AQ",
3672 "",
3673 ""
3674 }, {
3675 "art_Zzzz",
3676 "",
3677 ""
3678 }, {
3679 "art_Zzzz_ZZ",
3680 "",
3681 ""
3682 }, {
3683 "art_Zzzz_CN",
3684 "",
3685 ""
3686 }, {
3687 "art_Zzzz_TW",
3688 "",
3689 ""
3690 }, {
3691 "art_Zzzz_HK",
3692 "",
3693 ""
3694 }, {
3695 "art_Zzzz_AQ",
3696 "",
3697 ""
3698 }, {
3699 "art_Latn",
3700 "",
3701 ""
3702 }, {
3703 "art_Latn_ZZ",
3704 "",
3705 ""
3706 }, {
3707 "art_Latn_CN",
3708 "",
3709 ""
3710 }, {
3711 "art_Latn_TW",
3712 "",
3713 ""
3714 }, {
3715 "art_Latn_HK",
3716 "",
3717 ""
3718 }, {
3719 "art_Latn_AQ",
3720 "",
3721 ""
3722 }, {
3723 "art_Hans",
3724 "",
3725 ""
3726 }, {
3727 "art_Hans_ZZ",
3728 "",
3729 ""
3730 }, {
3731 "art_Hans_CN",
3732 "",
3733 ""
3734 }, {
3735 "art_Hans_TW",
3736 "",
3737 ""
3738 }, {
3739 "art_Hans_HK",
3740 "",
3741 ""
3742 }, {
3743 "art_Hans_AQ",
3744 "",
3745 ""
3746 }, {
3747 "art_Hant",
3748 "",
3749 ""
3750 }, {
3751 "art_Hant_ZZ",
3752 "",
3753 ""
3754 }, {
3755 "art_Hant_CN",
3756 "",
3757 ""
3758 }, {
3759 "art_Hant_TW",
3760 "",
3761 ""
3762 }, {
3763 "art_Hant_HK",
3764 "",
3765 ""
3766 }, {
3767 "art_Hant_AQ",
3768 "",
3769 ""
3770 }, {
3771 "art_Moon",
3772 "",
3773 ""
3774 }, {
3775 "art_Moon_ZZ",
3776 "",
3777 ""
3778 }, {
3779 "art_Moon_CN",
3780 "",
3781 ""
3782 }, {
3783 "art_Moon_TW",
3784 "",
3785 ""
3786 }, {
3787 "art_Moon_HK",
3788 "",
3789 ""
3790 }, {
3791 "art_Moon_AQ",
3792 "",
3793 ""
3794 }, {
3795 "aae_Latn_IT",
3796 "aae_Latn_IT",
3797 "aae"
3798 }, {
3799 "aae_Thai_CO",
3800 "aae_Thai_CO",
3801 "aae_Thai_CO"
3802 }, {
3803 "und_CW",
3804 "pap_Latn_CW",
3805 "pap"
3806 }, {
3807 "zh_Hant",
3808 "zh_Hant_TW",
3809 "zh_TW"
3810 }, {
3811 "zh_Hani",
3812 "zh_Hani_CN",
3813 "zh_Hani"
3814 }, {
3815 "und",
3816 "en_Latn_US",
3817 "en"
3818 }, {
3819 "und_Thai",
3820 "th_Thai_TH",
3821 "th"
3822 }, {
3823 "und_419",
3824 "es_Latn_419",
3825 "es_419"
3826 }, {
3827 "und_150",
3828 "ru_Cyrl_RU",
3829 "ru"
3830 }, {
3831 "und_AT",
3832 "de_Latn_AT",
3833 "de_AT"
3834 }, {
3835 "und_US",
3836 "en_Latn_US",
3837 "en"
3838 }
3839 };
3840
3841 for (const auto& item : full_data) {
3842 const char* const org = item.from;
3843 const char* const exp = item.add;
3844 Locale res(org);
3845 res.addLikelySubtags(status);
3846 status.errIfFailureAndReset("\"%s\"", org);
3847 if (exp[0]) {
3848 assertEquals("addLikelySubtags", exp, res.getName());
3849 } else {
3850 assertEquals("addLikelySubtags", org, res.getName());
3851 }
3852 }
3853
3854 for (const auto& item : full_data) {
3855 const char* const org = item.from;
3856 const char* const exp = item.remove;
3857 Locale res(org);
3858 res.minimizeSubtags(status);
3859 status.errIfFailureAndReset("\"%s\"", org);
3860 if (exp[0]) {
3861 assertEquals("minimizeSubtags", exp, res.getName());
3862 } else {
3863 assertEquals("minimizeSubtags", org, res.getName());
3864 }
3865 }
3866 }
3867
3868
3869 void
TestKeywordVariants()3870 LocaleTest::TestKeywordVariants() {
3871 static const struct {
3872 const char *localeID;
3873 const char *expectedLocaleID;
3874 //const char *expectedLocaleIDNoKeywords;
3875 //const char *expectedCanonicalID;
3876 const char *expectedKeywords[10];
3877 int32_t numKeywords;
3878 UErrorCode expectedStatus;
3879 } testCases[] = {
3880 {
3881 "de_DE@ currency = euro; C o ll A t i o n = Phonebook ; C alen dar = buddhist ",
3882 "de_DE@calendar=buddhist;collation=Phonebook;currency=euro",
3883 //"de_DE",
3884 //"de_DE@calendar=buddhist;collation=Phonebook;currency=euro",
3885 {"calendar", "collation", "currency"},
3886 3,
3887 U_ZERO_ERROR
3888 },
3889 {
3890 "de_DE@euro",
3891 "de_DE@euro",
3892 //"de_DE",
3893 //"de_DE@currency=EUR",
3894 {"","","","","","",""},
3895 0,
3896 U_INVALID_FORMAT_ERROR /* must have '=' after '@' */
3897 }
3898 };
3899 UErrorCode status = U_ZERO_ERROR;
3900
3901 int32_t i = 0, j = 0;
3902 const char *result = nullptr;
3903 StringEnumeration *keywords;
3904 int32_t keyCount = 0;
3905 const char *keyword = nullptr;
3906 const UnicodeString *keywordString;
3907 int32_t keywordLen = 0;
3908
3909 for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
3910 status = U_ZERO_ERROR;
3911 Locale l(testCases[i].localeID);
3912 keywords = l.createKeywords(status);
3913
3914 if(status != testCases[i].expectedStatus) {
3915 err("Expected to get status %s. Got %s instead\n",
3916 u_errorName(testCases[i].expectedStatus), u_errorName(status));
3917 }
3918 status = U_ZERO_ERROR;
3919 if(keywords) {
3920 if((keyCount = keywords->count(status)) != testCases[i].numKeywords) {
3921 err("Expected to get %i keywords, got %i\n", testCases[i].numKeywords, keyCount);
3922 }
3923 if(keyCount) {
3924 for(j = 0;;) {
3925 if((j&1)==0) {
3926 if((keyword = keywords->next(&keywordLen, status)) == nullptr) {
3927 break;
3928 }
3929 if(strcmp(keyword, testCases[i].expectedKeywords[j]) != 0) {
3930 err("Expected to get keyword value %s, got %s\n", testCases[i].expectedKeywords[j], keyword);
3931 }
3932 } else {
3933 if((keywordString = keywords->snext(status)) == nullptr) {
3934 break;
3935 }
3936 if(*keywordString != UnicodeString(testCases[i].expectedKeywords[j], "")) {
3937 err("Expected to get keyword UnicodeString %s, got %s\n", testCases[i].expectedKeywords[j], keyword);
3938 }
3939 }
3940 j++;
3941
3942 if(j == keyCount / 2) {
3943 // replace keywords with a clone of itself
3944 StringEnumeration *k2 = keywords->clone();
3945 if(k2 == nullptr || keyCount != k2->count(status)) {
3946 errln("KeywordEnumeration.clone() failed");
3947 } else {
3948 delete keywords;
3949 keywords = k2;
3950 }
3951 }
3952 }
3953 keywords->reset(status); // Make sure that reset works.
3954 for(j = 0;;) {
3955 if((keyword = keywords->next(&keywordLen, status)) == nullptr) {
3956 break;
3957 }
3958 if(strcmp(keyword, testCases[i].expectedKeywords[j]) != 0) {
3959 err("Expected to get keyword value %s, got %s\n", testCases[i].expectedKeywords[j], keyword);
3960 }
3961 j++;
3962 }
3963 }
3964 delete keywords;
3965 }
3966 result = l.getName();
3967 if(uprv_strcmp(testCases[i].expectedLocaleID, result) != 0) {
3968 err("Expected to get \"%s\" from \"%s\". Got \"%s\" instead\n",
3969 testCases[i].expectedLocaleID, testCases[i].localeID, result);
3970 }
3971
3972 }
3973
3974 }
3975
3976
3977 void
TestCreateUnicodeKeywords()3978 LocaleTest::TestCreateUnicodeKeywords() {
3979 IcuTestErrorCode status(*this, "TestCreateUnicodeKeywords()");
3980
3981 static const Locale l("de@calendar=buddhist;collation=phonebook");
3982
3983 LocalPointer<StringEnumeration> keys(l.createUnicodeKeywords(status));
3984 status.errIfFailureAndReset("\"%s\"", l.getName());
3985
3986 const char* key;
3987 int32_t resultLength;
3988
3989 key = keys->next(&resultLength, status);
3990 status.errIfFailureAndReset("key #1");
3991 assertEquals("resultLength", 2, resultLength);
3992 assertTrue("key != nullptr", key != nullptr);
3993 if (key != nullptr) {
3994 assertEquals("calendar", "ca", key);
3995 }
3996
3997 key = keys->next(&resultLength, status);
3998 status.errIfFailureAndReset("key #2");
3999 assertEquals("resultLength", 2, resultLength);
4000 assertTrue("key != nullptr", key != nullptr);
4001 if (key != nullptr) {
4002 assertEquals("collation", "co", key);
4003 }
4004
4005 key = keys->next(&resultLength, status);
4006 status.errIfFailureAndReset("end of keys");
4007 assertEquals("resultLength", 0, resultLength);
4008 assertTrue("key == nullptr", key == nullptr);
4009
4010 const UnicodeString* skey;
4011 keys->reset(status); // KeywordEnumeration::reset() never touches status.
4012
4013 skey = keys->snext(status);
4014 status.errIfFailureAndReset("skey #1");
4015 assertTrue("skey != nullptr", skey != nullptr);
4016 if (skey != nullptr) {
4017 assertEquals("calendar", "ca", *skey);
4018 }
4019
4020 skey = keys->snext(status);
4021 status.errIfFailureAndReset("skey #2");
4022 assertTrue("skey != nullptr", skey != nullptr);
4023 if (skey != nullptr) {
4024 assertEquals("collation", "co", *skey);
4025 }
4026
4027 skey = keys->snext(status);
4028 status.errIfFailureAndReset("end of keys");
4029 assertTrue("skey == nullptr", skey == nullptr);
4030 }
4031
4032
4033 void
TestKeywordVariantParsing()4034 LocaleTest::TestKeywordVariantParsing() {
4035 static const struct {
4036 const char *localeID;
4037 const char *keyword;
4038 const char *expectedValue;
4039 } testCases[] = {
4040 { "de_DE@ C o ll A t i o n = Phonebook ", "collation", "Phonebook" },
4041 { "de_DE", "collation", ""},
4042 { "de_DE@collation= PHONEBOOK", "collation", "PHONEBOOK" },
4043 { "de_DE@ currency = euro ; CoLLaTion = PHONEBOOk ", "collation", "PHONEBOOk" },
4044 };
4045
4046 UErrorCode status = U_ZERO_ERROR;
4047
4048 int32_t i = 0;
4049 int32_t resultLen = 0;
4050 char buffer[256];
4051
4052 for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
4053 *buffer = 0;
4054 Locale l(testCases[i].localeID);
4055 resultLen = l.getKeywordValue(testCases[i].keyword, buffer, 256, status);
4056 (void)resultLen; // Suppress unused variable warning.
4057 if(uprv_strcmp(testCases[i].expectedValue, buffer) != 0) {
4058 err("Expected to extract \"%s\" from \"%s\" for keyword \"%s\". Got \"%s\" instead\n",
4059 testCases[i].expectedValue, testCases[i].localeID, testCases[i].keyword, buffer);
4060 }
4061 }
4062 }
4063
4064 void
TestCreateKeywordSet()4065 LocaleTest::TestCreateKeywordSet() {
4066 IcuTestErrorCode status(*this, "TestCreateKeywordSet()");
4067
4068 static const Locale l("de@calendar=buddhist;collation=phonebook");
4069
4070 std::set<std::string> result;
4071 l.getKeywords<std::string>(
4072 std::insert_iterator<decltype(result)>(result, result.begin()),
4073 status);
4074 status.errIfFailureAndReset("\"%s\"", l.getName());
4075
4076 assertEquals("set::size()", 2, static_cast<int32_t>(result.size()));
4077 assertTrue("set::find(\"calendar\")",
4078 result.find("calendar") != result.end());
4079 assertTrue("set::find(\"collation\")",
4080 result.find("collation") != result.end());
4081 }
4082
4083 void
TestCreateKeywordSetEmpty()4084 LocaleTest::TestCreateKeywordSetEmpty() {
4085 IcuTestErrorCode status(*this, "TestCreateKeywordSetEmpty()");
4086
4087 static const Locale l("de");
4088
4089 std::set<std::string> result;
4090 l.getKeywords<std::string>(
4091 std::insert_iterator<decltype(result)>(result, result.begin()),
4092 status);
4093 status.errIfFailureAndReset("\"%s\"", l.getName());
4094
4095 assertEquals("set::size()", 0, static_cast<int32_t>(result.size()));
4096 }
4097
4098 void
TestCreateKeywordSetWithPrivateUse()4099 LocaleTest::TestCreateKeywordSetWithPrivateUse() {
4100 IcuTestErrorCode status(*this, "TestCreateKeywordSetWithPrivateUse()");
4101
4102 static const char tag[] = "en-US-u-ca-gregory-x-foo";
4103 static const Locale l = Locale::forLanguageTag(tag, status);
4104 std::set<std::string> result;
4105 l.getKeywords<std::string>(
4106 std::insert_iterator<decltype(result)>(result, result.begin()),
4107 status);
4108 status.errIfFailureAndReset("getKeywords \"%s\"", l.getName());
4109 assertTrue("getKeywords set::find(\"calendar\")",
4110 result.find("calendar") != result.end());
4111 assertTrue("getKeywords set::find(\"ca\")",
4112 result.find("ca") == result.end());
4113 assertTrue("getKeywords set::find(\"x\")",
4114 result.find("x") != result.end());
4115 assertTrue("getKeywords set::find(\"foo\")",
4116 result.find("foo") == result.end());
4117 }
4118
4119 void
TestCreateUnicodeKeywordSet()4120 LocaleTest::TestCreateUnicodeKeywordSet() {
4121 IcuTestErrorCode status(*this, "TestCreateUnicodeKeywordSet()");
4122
4123 static const Locale l("de@calendar=buddhist;collation=phonebook");
4124
4125 std::set<std::string> result;
4126 l.getUnicodeKeywords<std::string>(
4127 std::insert_iterator<decltype(result)>(result, result.begin()),
4128 status);
4129 status.errIfFailureAndReset("\"%s\"", l.getName());
4130
4131 assertEquals("set::size()", 2, static_cast<int32_t>(result.size()));
4132 assertTrue("set::find(\"ca\")",
4133 result.find("ca") != result.end());
4134 assertTrue("set::find(\"co\")",
4135 result.find("co") != result.end());
4136 }
4137
4138 void
TestCreateUnicodeKeywordSetEmpty()4139 LocaleTest::TestCreateUnicodeKeywordSetEmpty() {
4140 IcuTestErrorCode status(*this, "TestCreateUnicodeKeywordSetEmpty()");
4141
4142 static const Locale l("de");
4143
4144 std::set<std::string> result;
4145 l.getUnicodeKeywords<std::string>(
4146 std::insert_iterator<decltype(result)>(result, result.begin()),
4147 status);
4148 status.errIfFailureAndReset("\"%s\"", l.getName());
4149
4150 assertEquals("set::size()", 0, static_cast<int32_t>(result.size()));
4151 }
4152
4153 void
TestCreateUnicodeKeywordSetWithPrivateUse()4154 LocaleTest::TestCreateUnicodeKeywordSetWithPrivateUse() {
4155 IcuTestErrorCode status(*this, "TestCreateUnicodeKeywordSetWithPrivateUse()");
4156
4157 static const char tag[] = "en-US-u-ca-gregory-x-foo";
4158 static const Locale l = Locale::forLanguageTag(tag, status);
4159
4160 std::set<std::string> result;
4161 l.getUnicodeKeywords<std::string>(
4162 std::insert_iterator<decltype(result)>(result, result.begin()),
4163 status);
4164 status.errIfFailureAndReset("getUnicodeKeywords \"%s\"", l.getName());
4165 assertTrue("getUnicodeKeywords set::find(\"ca\")",
4166 result.find("ca") != result.end());
4167 assertTrue("getUnicodeKeywords set::find(\"x\")",
4168 result.find("x") == result.end());
4169 assertTrue("getUnicodeKeywords set::find(\"foo\")",
4170 result.find("foo") == result.end());
4171 }
4172
4173 void
TestGetKeywordValueStdString()4174 LocaleTest::TestGetKeywordValueStdString() {
4175 IcuTestErrorCode status(*this, "TestGetKeywordValueStdString()");
4176
4177 static const char tag[] = "fa-u-nu-latn";
4178 static const char keyword[] = "numbers";
4179 static const char expected[] = "latn";
4180
4181 Locale l = Locale::forLanguageTag(tag, status);
4182 status.errIfFailureAndReset("\"%s\"", tag);
4183
4184 std::string result = l.getKeywordValue<std::string>(keyword, status);
4185 status.errIfFailureAndReset("\"%s\"", keyword);
4186 assertEquals(keyword, expected, result.c_str());
4187 }
4188
4189 void
TestGetUnicodeKeywordValueStdString()4190 LocaleTest::TestGetUnicodeKeywordValueStdString() {
4191 IcuTestErrorCode status(*this, "TestGetUnicodeKeywordValueStdString()");
4192
4193 static const char keyword[] = "co";
4194 static const char expected[] = "phonebk";
4195
4196 static const Locale l("de@calendar=buddhist;collation=phonebook");
4197
4198 std::string result = l.getUnicodeKeywordValue<std::string>(keyword, status);
4199 status.errIfFailureAndReset("\"%s\"", keyword);
4200 assertEquals(keyword, expected, result.c_str());
4201 }
4202
4203 void
TestSetKeywordValue()4204 LocaleTest::TestSetKeywordValue() {
4205 static const struct {
4206 const char *keyword;
4207 const char *value;
4208 } testCases[] = {
4209 { "collation", "phonebook" },
4210 { "currency", "euro" },
4211 { "calendar", "buddhist" }
4212 };
4213
4214 IcuTestErrorCode status(*this, "TestSetKeywordValue()");
4215
4216 int32_t i = 0;
4217 int32_t resultLen = 0;
4218 char buffer[256];
4219
4220 Locale l(Locale::getGerman());
4221
4222 for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
4223 l.setKeywordValue(testCases[i].keyword, testCases[i].value, status);
4224 if(U_FAILURE(status)) {
4225 err("FAIL: Locale::setKeywordValue failed - %s\n", u_errorName(status));
4226 }
4227
4228 *buffer = 0;
4229 resultLen = l.getKeywordValue(testCases[i].keyword, buffer, 256, status);
4230 (void)resultLen; // Suppress unused variable warning.
4231 if(uprv_strcmp(testCases[i].value, buffer) != 0) {
4232 err("Expected to extract \"%s\" for keyword \"%s\". Got \"%s\" instead\n",
4233 testCases[i].value, testCases[i].keyword, buffer);
4234 }
4235 }
4236
4237 // Test long locale
4238 {
4239 status.errIfFailureAndReset();
4240 const char* input =
4241 "de__POSIX@colnormalization=no;colstrength=primary;currency=eur;"
4242 "em=default;kv=space;lb=strict;lw=normal;measure=metric;"
4243 "numbers=latn;rg=atzzzz;sd=atat1";
4244 const char* expected =
4245 "de__POSIX@colnormalization=no;colstrength=primary;currency=eur;"
4246 "em=default;kv=space;lb=strict;lw=normal;measure=metric;"
4247 "numbers=latn;rg=atzzzz;sd=atat1;ss=none";
4248 // Bug ICU-21385
4249 Locale l2(input);
4250 l2.setKeywordValue("ss", "none", status);
4251 assertEquals("", expected, l2.getName());
4252 status.errIfFailureAndReset();
4253 }
4254 }
4255
4256 void
TestSetKeywordValueStringPiece()4257 LocaleTest::TestSetKeywordValueStringPiece() {
4258 IcuTestErrorCode status(*this, "TestSetKeywordValueStringPiece()");
4259 Locale l(Locale::getGerman());
4260
4261 l.setKeywordValue(StringPiece("collation"), StringPiece("phonebook"), status);
4262 l.setKeywordValue(StringPiece("calendarxxx", 8), StringPiece("buddhistxxx", 8), status);
4263
4264 static const char expected[] = "de@calendar=buddhist;collation=phonebook";
4265 assertEquals("", expected, l.getName());
4266 }
4267
4268 void
TestSetUnicodeKeywordValueStringPiece()4269 LocaleTest::TestSetUnicodeKeywordValueStringPiece() {
4270 IcuTestErrorCode status(*this, "TestSetUnicodeKeywordValueStringPiece()");
4271 Locale l(Locale::getGerman());
4272
4273 l.setUnicodeKeywordValue(StringPiece("co"), StringPiece("phonebk"), status);
4274 status.errIfFailureAndReset();
4275
4276 l.setUnicodeKeywordValue(StringPiece("caxxx", 2), StringPiece("buddhistxxx", 8), status);
4277 status.errIfFailureAndReset();
4278
4279 static const char expected[] = "de@calendar=buddhist;collation=phonebook";
4280 assertEquals("", expected, l.getName());
4281
4282 l.setUnicodeKeywordValue("cu", nullptr, status);
4283 status.errIfFailureAndReset();
4284 assertEquals("", expected, l.getName());
4285
4286 l.setUnicodeKeywordValue("!!", nullptr, status);
4287 assertEquals("status", U_ILLEGAL_ARGUMENT_ERROR, status.reset());
4288 assertEquals("", expected, l.getName());
4289
4290 l.setUnicodeKeywordValue("co", "!!", status);
4291 assertEquals("status", U_ILLEGAL_ARGUMENT_ERROR, status.reset());
4292 assertEquals("", expected, l.getName());
4293
4294 l.setUnicodeKeywordValue("co", nullptr, status);
4295 status.errIfFailureAndReset();
4296
4297 l.setUnicodeKeywordValue("ca", "", status);
4298 status.errIfFailureAndReset();
4299
4300 assertEquals("", Locale::getGerman().getName(), l.getName());
4301 }
4302
4303 void
TestGetBaseName()4304 LocaleTest::TestGetBaseName() {
4305 static const struct {
4306 const char *localeID;
4307 const char *baseName;
4308 } testCases[] = {
4309 { "de_DE@ C o ll A t i o n = Phonebook ", "de_DE" },
4310 { "de@currency = euro; CoLLaTion = PHONEBOOk", "de" },
4311 { "ja@calendar = buddhist", "ja" },
4312 { "de-u-co-phonebk", "de"}
4313 };
4314
4315 int32_t i = 0;
4316
4317 for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
4318 Locale loc(testCases[i].localeID);
4319 if(strcmp(testCases[i].baseName, loc.getBaseName())) {
4320 errln("For locale \"%s\" expected baseName \"%s\", but got \"%s\"",
4321 testCases[i].localeID, testCases[i].baseName, loc.getBaseName());
4322 return;
4323 }
4324 }
4325
4326 // Verify that adding a keyword to an existing Locale doesn't change the base name.
4327 UErrorCode status = U_ZERO_ERROR;
4328 Locale loc2("en-US");
4329 if (strcmp("en_US", loc2.getBaseName())) {
4330 errln("%s:%d Expected \"en_US\", got \"%s\"", __FILE__, __LINE__, loc2.getBaseName());
4331 }
4332 loc2.setKeywordValue("key", "value", status);
4333 if (strcmp("en_US@key=value", loc2.getName())) {
4334 errln("%s:%d Expected \"en_US@key=value\", got \"%s\"", __FILE__, __LINE__, loc2.getName());
4335 }
4336 if (strcmp("en_US", loc2.getBaseName())) {
4337 errln("%s:%d Expected \"en_US\", got \"%s\"", __FILE__, __LINE__, loc2.getBaseName());
4338 }
4339 }
4340
4341 /**
4342 * Compare two locale IDs. If they are equal, return 0. If `string'
4343 * starts with `prefix' plus an additional element, that is, string ==
4344 * prefix + '_' + x, then return 1. Otherwise return a value < 0.
4345 */
_loccmp(const char * string,const char * prefix)4346 static UBool _loccmp(const char* string, const char* prefix) {
4347 int32_t slen = (int32_t)strlen(string),
4348 plen = (int32_t)strlen(prefix);
4349 int32_t c = uprv_strncmp(string, prefix, plen);
4350 /* 'root' is "less than" everything */
4351 if (prefix[0] == '\0') {
4352 return string[0] != '\0';
4353 }
4354 if (c) return -1; /* mismatch */
4355 if (slen == plen) return 0;
4356 if (string[plen] == '_') return 1;
4357 return -2; /* false match, e.g. "en_USX" cmp "en_US" */
4358 }
4359
4360 /**
4361 * Check the relationship between requested locales, and report problems.
4362 * The caller specifies the expected relationships between requested
4363 * and valid (expReqValid) and between valid and actual (expValidActual).
4364 * Possible values are:
4365 * "gt" strictly greater than, e.g., en_US > en
4366 * "ge" greater or equal, e.g., en >= en
4367 * "eq" equal, e.g., en == en
4368 */
_checklocs(const char * label,const char * req,const Locale & validLoc,const Locale & actualLoc,const char * expReqValid,const char * expValidActual)4369 void LocaleTest::_checklocs(const char* label,
4370 const char* req,
4371 const Locale& validLoc,
4372 const Locale& actualLoc,
4373 const char* expReqValid,
4374 const char* expValidActual) {
4375 const char* valid = validLoc.getName();
4376 const char* actual = actualLoc.getName();
4377 int32_t reqValid = _loccmp(req, valid);
4378 int32_t validActual = _loccmp(valid, actual);
4379 if (((0 == uprv_strcmp(expReqValid, "gt") && reqValid > 0) ||
4380 (0 == uprv_strcmp(expReqValid, "ge") && reqValid >= 0) ||
4381 (0 == uprv_strcmp(expReqValid, "eq") && reqValid == 0)) &&
4382 ((0 == uprv_strcmp(expValidActual, "gt") && validActual > 0) ||
4383 (0 == uprv_strcmp(expValidActual, "ge") && validActual >= 0) ||
4384 (0 == uprv_strcmp(expValidActual, "eq") && validActual == 0))) {
4385 logln("%s; req=%s, valid=%s, actual=%s",
4386 label, req, valid, actual);
4387 } else {
4388 dataerrln("FAIL: %s; req=%s, valid=%s, actual=%s. Require (R %s V) and (V %s A)",
4389 label, req, valid, actual,
4390 expReqValid, expValidActual);
4391 }
4392 }
4393
TestGetLocale()4394 void LocaleTest::TestGetLocale() {
4395 #if !UCONFIG_NO_SERVICE
4396 const char *req;
4397 Locale valid, actual, reqLoc;
4398
4399 // Calendar
4400 #if !UCONFIG_NO_FORMATTING
4401 {
4402 UErrorCode ec = U_ZERO_ERROR; // give each resource type its own error code
4403 req = "en_US_BROOKLYN";
4404 Calendar* cal = Calendar::createInstance(Locale::createFromName(req), ec);
4405 if (U_FAILURE(ec)) {
4406 dataerrln("FAIL: Calendar::createInstance failed - %s", u_errorName(ec));
4407 } else {
4408 valid = cal->getLocale(ULOC_VALID_LOCALE, ec);
4409 actual = cal->getLocale(ULOC_ACTUAL_LOCALE, ec);
4410 if (U_FAILURE(ec)) {
4411 errln("FAIL: Calendar::getLocale() failed");
4412 } else {
4413 _checklocs("Calendar", req, valid, actual);
4414 }
4415 /* Make sure that it fails correctly */
4416 ec = U_FILE_ACCESS_ERROR;
4417 if (cal->getLocale(ULOC_VALID_LOCALE, ec).getName()[0] != 0) {
4418 errln("FAIL: Calendar::getLocale() failed to fail correctly. It should have returned \"\"");
4419 }
4420 ec = U_ZERO_ERROR;
4421 }
4422 delete cal;
4423 }
4424 #endif
4425
4426 // DecimalFormat, DecimalFormatSymbols
4427 #if !UCONFIG_NO_FORMATTING
4428 {
4429 UErrorCode ec = U_ZERO_ERROR; // give each resource type its own error code
4430 req = "fr_FR_NICE";
4431 NumberFormat* nf = NumberFormat::createInstance(Locale::createFromName(req), ec);
4432 if (U_FAILURE(ec)) {
4433 dataerrln("FAIL: NumberFormat::createInstance failed - %s", u_errorName(ec));
4434 } else {
4435 DecimalFormat* dec = dynamic_cast<DecimalFormat*>(nf);
4436 if (dec == nullptr) {
4437 errln("FAIL: NumberFormat::createInstance does not return a DecimalFormat");
4438 return;
4439 }
4440 valid = dec->getLocale(ULOC_VALID_LOCALE, ec);
4441 actual = dec->getLocale(ULOC_ACTUAL_LOCALE, ec);
4442 if (U_FAILURE(ec)) {
4443 errln("FAIL: DecimalFormat::getLocale() failed");
4444 } else {
4445 _checklocs("DecimalFormat", req, valid, actual);
4446 }
4447
4448 const DecimalFormatSymbols* sym = dec->getDecimalFormatSymbols();
4449 if (sym == nullptr) {
4450 errln("FAIL: getDecimalFormatSymbols returned nullptr");
4451 return;
4452 }
4453 valid = sym->getLocale(ULOC_VALID_LOCALE, ec);
4454 actual = sym->getLocale(ULOC_ACTUAL_LOCALE, ec);
4455 if (U_FAILURE(ec)) {
4456 errln("FAIL: DecimalFormatSymbols::getLocale() failed");
4457 } else {
4458 _checklocs("DecimalFormatSymbols", req, valid, actual);
4459 }
4460 }
4461 delete nf;
4462 }
4463 #endif
4464
4465 // DateFormat, DateFormatSymbols
4466 #if !UCONFIG_NO_FORMATTING
4467 {
4468 UErrorCode ec = U_ZERO_ERROR; // give each resource type its own error code
4469 req = "de_CH_LUCERNE";
4470 DateFormat* df =
4471 DateFormat::createDateInstance(DateFormat::kDefault,
4472 Locale::createFromName(req));
4473 if (df == 0){
4474 dataerrln("Error calling DateFormat::createDateInstance()");
4475 } else {
4476 SimpleDateFormat* dat = dynamic_cast<SimpleDateFormat*>(df);
4477 if (dat == nullptr) {
4478 errln("FAIL: DateFormat::createInstance does not return a SimpleDateFormat");
4479 return;
4480 }
4481 valid = dat->getLocale(ULOC_VALID_LOCALE, ec);
4482 actual = dat->getLocale(ULOC_ACTUAL_LOCALE, ec);
4483 if (U_FAILURE(ec)) {
4484 errln("FAIL: SimpleDateFormat::getLocale() failed");
4485 } else {
4486 _checklocs("SimpleDateFormat", req, valid, actual);
4487 }
4488
4489 const DateFormatSymbols* sym = dat->getDateFormatSymbols();
4490 if (sym == nullptr) {
4491 errln("FAIL: getDateFormatSymbols returned nullptr");
4492 return;
4493 }
4494 valid = sym->getLocale(ULOC_VALID_LOCALE, ec);
4495 actual = sym->getLocale(ULOC_ACTUAL_LOCALE, ec);
4496 if (U_FAILURE(ec)) {
4497 errln("FAIL: DateFormatSymbols::getLocale() failed");
4498 } else {
4499 _checklocs("DateFormatSymbols", req, valid, actual);
4500 }
4501 }
4502 delete df;
4503 }
4504 #endif
4505
4506 // BreakIterator
4507 #if !UCONFIG_NO_BREAK_ITERATION
4508 {
4509 UErrorCode ec = U_ZERO_ERROR; // give each resource type its own error code
4510 req = "es_ES_BARCELONA";
4511 reqLoc = Locale::createFromName(req);
4512 BreakIterator* brk = BreakIterator::createWordInstance(reqLoc, ec);
4513 if (U_FAILURE(ec)) {
4514 dataerrln("FAIL: BreakIterator::createWordInstance failed - %s", u_errorName(ec));
4515 } else {
4516 valid = brk->getLocale(ULOC_VALID_LOCALE, ec);
4517 actual = brk->getLocale(ULOC_ACTUAL_LOCALE, ec);
4518 if (U_FAILURE(ec)) {
4519 errln("FAIL: BreakIterator::getLocale() failed");
4520 } else {
4521 _checklocs("BreakIterator", req, valid, actual);
4522 }
4523
4524 // After registering something, the behavior should be different
4525 URegistryKey key = BreakIterator::registerInstance(brk, reqLoc, UBRK_WORD, ec);
4526 brk = 0; // registerInstance adopts
4527 if (U_FAILURE(ec)) {
4528 errln("FAIL: BreakIterator::registerInstance() failed");
4529 } else {
4530 brk = BreakIterator::createWordInstance(reqLoc, ec);
4531 if (U_FAILURE(ec)) {
4532 errln("FAIL: BreakIterator::createWordInstance failed");
4533 } else {
4534 valid = brk->getLocale(ULOC_VALID_LOCALE, ec);
4535 actual = brk->getLocale(ULOC_ACTUAL_LOCALE, ec);
4536 if (U_FAILURE(ec)) {
4537 errln("FAIL: BreakIterator::getLocale() failed");
4538 } else {
4539 // N.B.: now expect valid==actual==req
4540 _checklocs("BreakIterator(registered)",
4541 req, valid, actual, "eq", "eq");
4542 }
4543 }
4544 // No matter what, unregister
4545 BreakIterator::unregister(key, ec);
4546 if (U_FAILURE(ec)) {
4547 errln("FAIL: BreakIterator::unregister() failed");
4548 }
4549 delete brk;
4550 brk = 0;
4551 }
4552
4553 // After unregistering, should behave normally again
4554 brk = BreakIterator::createWordInstance(reqLoc, ec);
4555 if (U_FAILURE(ec)) {
4556 errln("FAIL: BreakIterator::createWordInstance failed");
4557 } else {
4558 valid = brk->getLocale(ULOC_VALID_LOCALE, ec);
4559 actual = brk->getLocale(ULOC_ACTUAL_LOCALE, ec);
4560 if (U_FAILURE(ec)) {
4561 errln("FAIL: BreakIterator::getLocale() failed");
4562 } else {
4563 _checklocs("BreakIterator(unregistered)", req, valid, actual);
4564 }
4565 }
4566 }
4567 delete brk;
4568 }
4569 #endif
4570
4571 // Collator
4572 #if !UCONFIG_NO_COLLATION
4573 {
4574 UErrorCode ec = U_ZERO_ERROR; // give each resource type its own error code
4575
4576 checkRegisteredCollators(nullptr); // Don't expect any extras
4577
4578 req = "hi_IN_BHOPAL";
4579 reqLoc = Locale::createFromName(req);
4580 Collator* coll = Collator::createInstance(reqLoc, ec);
4581 if (U_FAILURE(ec)) {
4582 dataerrln("FAIL: Collator::createInstance failed - %s", u_errorName(ec));
4583 } else {
4584 valid = coll->getLocale(ULOC_VALID_LOCALE, ec);
4585 actual = coll->getLocale(ULOC_ACTUAL_LOCALE, ec);
4586 if (U_FAILURE(ec)) {
4587 errln("FAIL: Collator::getLocale() failed");
4588 } else {
4589 _checklocs("Collator", req, valid, actual);
4590 }
4591
4592 // After registering something, the behavior should be different
4593 URegistryKey key = Collator::registerInstance(coll, reqLoc, ec);
4594 coll = 0; // registerInstance adopts
4595 if (U_FAILURE(ec)) {
4596 errln("FAIL: Collator::registerInstance() failed");
4597 } else {
4598 coll = Collator::createInstance(reqLoc, ec);
4599 if (U_FAILURE(ec)) {
4600 errln("FAIL: Collator::createWordInstance failed");
4601 } else {
4602 valid = coll->getLocale(ULOC_VALID_LOCALE, ec);
4603 actual = coll->getLocale(ULOC_ACTUAL_LOCALE, ec);
4604 if (U_FAILURE(ec)) {
4605 errln("FAIL: Collator::getLocale() failed");
4606 } else {
4607 // N.B.: now expect valid==actual==req
4608 _checklocs("Collator(registered)",
4609 req, valid, actual, "eq", "eq");
4610 }
4611 }
4612 checkRegisteredCollators(req); // include hi_IN_BHOPAL
4613
4614 // No matter what, unregister
4615 Collator::unregister(key, ec);
4616 if (U_FAILURE(ec)) {
4617 errln("FAIL: Collator::unregister() failed");
4618 }
4619 delete coll;
4620 coll = 0;
4621 }
4622
4623 // After unregistering, should behave normally again
4624 coll = Collator::createInstance(reqLoc, ec);
4625 if (U_FAILURE(ec)) {
4626 errln("FAIL: Collator::createInstance failed");
4627 } else {
4628 valid = coll->getLocale(ULOC_VALID_LOCALE, ec);
4629 actual = coll->getLocale(ULOC_ACTUAL_LOCALE, ec);
4630 if (U_FAILURE(ec)) {
4631 errln("FAIL: Collator::getLocale() failed");
4632 } else {
4633 _checklocs("Collator(unregistered)", req, valid, actual);
4634 }
4635 }
4636 }
4637 delete coll;
4638
4639 checkRegisteredCollators(nullptr); // extra should be gone again
4640 }
4641 #endif
4642 #endif
4643 }
4644
4645 #if !UCONFIG_NO_COLLATION
4646 /**
4647 * Compare Collator::getAvailableLocales(int) [ "old", returning an array ]
4648 * with Collator::getAvailableLocales() [ "new", returning a StringEnumeration ]
4649 * These should be identical (check their API docs) EXCEPT that
4650 * if expectExtra is non-nullptr, it will be in the "new" array but not "old".
4651 * Does not return any status but calls errln on error.
4652 * @param expectExtra an extra locale, will be in "new" but not "old". Or nullptr.
4653 */
checkRegisteredCollators(const char * expectExtra)4654 void LocaleTest::checkRegisteredCollators(const char *expectExtra) {
4655 UErrorCode status = U_ZERO_ERROR;
4656 int32_t count1=0,count2=0;
4657 Hashtable oldHash(status);
4658 Hashtable newHash(status);
4659 assertSuccess(WHERE, status);
4660
4661 UnicodeString expectStr(expectExtra?expectExtra:"n/a", "");
4662
4663 // the 'old' list (non enumeration)
4664 const Locale* oldList = Collator::getAvailableLocales(count1);
4665 if(oldList == nullptr) {
4666 dataerrln("Error: Collator::getAvailableLocales(count) returned nullptr");
4667 return;
4668 }
4669
4670 // the 'new' list (enumeration)
4671 LocalPointer<StringEnumeration> newEnum(Collator::getAvailableLocales());
4672 if(newEnum.isNull()) {
4673 errln("Error: collator::getAvailableLocales() returned nullptr");
4674 return;
4675 }
4676
4677 // OK. Let's add all of the OLD
4678 // then check for any in the NEW not in OLD
4679 // then check for any in OLD not in NEW.
4680
4681 // 1. add all of OLD
4682 for(int32_t i=0;i<count1;i++) {
4683 const UnicodeString key(oldList[i].getName(), "");
4684 int32_t oldI = oldHash.puti(key, 1, status);
4685 if( oldI == 1 ){
4686 errln("Error: duplicate key %s in Collator::getAvailableLocales(count) list.\n",
4687 oldList[i].getName());
4688 return;
4689 }
4690 if(expectExtra != nullptr && !strcmp(expectExtra, oldList[i].getName())) {
4691 errln("Inexplicably, Collator::getAvailableCollators(count) had registered collator %s. This shouldn't happen, so I am going to consider it an error.\n", expectExtra);
4692 }
4693 }
4694
4695 // 2. add all of NEW
4696 const UnicodeString *locStr;
4697 UBool foundExpected = false;
4698 while((locStr = newEnum->snext(status)) && U_SUCCESS(status)) {
4699 count2++;
4700
4701 if(expectExtra != nullptr && expectStr == *locStr) {
4702 foundExpected = true;
4703 logln(UnicodeString("Found expected registered collator: ","") + expectStr);
4704 }
4705 (void)foundExpected; // Hush unused variable compiler warning.
4706
4707 if( oldHash.geti(*locStr) == 0 ) {
4708 if(expectExtra != nullptr && expectStr==*locStr) {
4709 logln(UnicodeString("As expected, Collator::getAvailableLocales(count) is missing registered collator ") + expectStr);
4710 } else {
4711 errln(UnicodeString("Error: Collator::getAvailableLocales(count) is missing: ","")
4712 + *locStr);
4713 }
4714 }
4715 newHash.puti(*locStr, 1, status);
4716 }
4717
4718 // 3. check all of OLD again
4719 for(int32_t i=0;i<count1;i++) {
4720 const UnicodeString key(oldList[i].getName(), "");
4721 int32_t newI = newHash.geti(key);
4722 if(newI == 0) {
4723 errln(UnicodeString("Error: Collator::getAvailableLocales() is missing: ","")
4724 + key);
4725 }
4726 }
4727
4728 int32_t expectCount2 = count1;
4729 if(expectExtra != nullptr) {
4730 expectCount2 ++; // if an extra item registered, bump the expect count
4731 }
4732
4733 assertEquals("Collator::getAvail() count", expectCount2, count2);
4734 }
4735 #endif
4736
4737
4738
TestVariantWithOutCountry()4739 void LocaleTest::TestVariantWithOutCountry() {
4740 Locale loc("en","","POSIX");
4741 if (0 != strcmp(loc.getVariant(), "POSIX")) {
4742 errln("FAIL: en__POSIX didn't get parsed correctly - name is %s - expected %s got %s", loc.getName(), "POSIX", loc.getVariant());
4743 }
4744 Locale loc2("en","","FOUR");
4745 if (0 != strcmp(loc2.getVariant(), "FOUR")) {
4746 errln("FAIL: en__FOUR didn't get parsed correctly - name is %s - expected %s got %s", loc2.getName(), "FOUR", loc2.getVariant());
4747 }
4748 Locale loc3("en","Latn","","FOUR");
4749 if (0 != strcmp(loc3.getVariant(), "FOUR")) {
4750 errln("FAIL: en_Latn__FOUR didn't get parsed correctly - name is %s - expected %s got %s", loc3.getName(), "FOUR", loc3.getVariant());
4751 }
4752 Locale loc4("","Latn","","FOUR");
4753 if (0 != strcmp(loc4.getVariant(), "FOUR")) {
4754 errln("FAIL: _Latn__FOUR didn't get parsed correctly - name is %s - expected %s got %s", loc4.getName(), "FOUR", loc4.getVariant());
4755 }
4756 Locale loc5("","Latn","US","FOUR");
4757 if (0 != strcmp(loc5.getVariant(), "FOUR")) {
4758 errln("FAIL: _Latn_US_FOUR didn't get parsed correctly - name is %s - expected %s got %s", loc5.getName(), "FOUR", loc5.getVariant());
4759 }
4760 Locale loc6("de-1901");
4761 if (0 != strcmp(loc6.getVariant(), "1901")) {
4762 errln("FAIL: de-1901 didn't get parsed correctly - name is %s - expected %s got %s", loc6.getName(), "1901", loc6.getVariant());
4763 }
4764 }
4765
_canonicalize(int32_t selector,const char * localeID)4766 static Locale _canonicalize(int32_t selector, /* 0==createFromName, 1==createCanonical, 2==Locale ct */
4767 const char* localeID) {
4768 switch (selector) {
4769 case 0:
4770 return Locale::createFromName(localeID);
4771 case 1:
4772 return Locale::createCanonical(localeID);
4773 case 2:
4774 return Locale(localeID);
4775 default:
4776 return Locale("");
4777 }
4778 }
4779
TestCanonicalization()4780 void LocaleTest::TestCanonicalization()
4781 {
4782 static const struct {
4783 const char *localeID; /* input */
4784 const char *getNameID; /* expected getName() result */
4785 const char *canonicalID; /* expected canonicalize() result */
4786 } testCases[] = {
4787 { "ca_ES-with-extra-stuff-that really doesn't make any sense-unless-you're trying to increase code coverage",
4788 "ca_ES_WITH_EXTRA_STUFF_THAT REALLY DOESN'T MAKE ANY SENSE_UNLESS_YOU'RE TRYING TO INCREASE CODE COVERAGE",
4789 "ca_ES_EXTRA_STUFF_THAT REALLY DOESN'T MAKE ANY SENSE_UNLESS_WITH_YOU'RE TRYING TO INCREASE CODE COVERAGE"},
4790 { "zh@collation=pinyin", "zh@collation=pinyin", "zh@collation=pinyin" },
4791 { "zh_CN@collation=pinyin", "zh_CN@collation=pinyin", "zh_CN@collation=pinyin" },
4792 { "zh_CN_CA@collation=pinyin", "zh_CN_CA@collation=pinyin", "zh_CN_CA@collation=pinyin" },
4793 { "en_US_POSIX", "en_US_POSIX", "en_US_POSIX" },
4794 { "hy_AM_REVISED", "hy_AM_REVISED", "hy_AM_REVISED" },
4795 { "no_NO_NY", "no_NO_NY", "no_NO_NY" /* not: "nn_NO" [alan ICU3.0] */ },
4796 { "no@ny", "no@ny", "no__NY" /* not: "nn" [alan ICU3.0] */ }, /* POSIX ID */
4797 { "no-no.utf32@B", "no_NO.utf32@B", "no_NO_B" }, /* POSIX ID */
4798 { "qz-qz@Euro", "qz_QZ@Euro", "qz_QZ_EURO" }, /* qz-qz uses private use iso codes */
4799 // NOTE: uloc_getName() works on en-BOONT, but Locale() parser considers it BOGUS
4800 // TODO: unify this behavior
4801 { "en-BOONT", "en__BOONT", "en__BOONT" }, /* registered name */
4802 { "de-1901", "de__1901", "de__1901" }, /* registered name */
4803 { "de-1906", "de__1906", "de__1906" }, /* registered name */
4804 // New in CLDR 39 / ICU 69
4805 { "nb", "nb", "nb" },
4806
4807 /* posix behavior that used to be performed by getName */
4808 { "mr.utf8", "mr.utf8", "mr" },
4809 { "de-tv.koi8r", "de_TV.koi8r", "de_TV" },
4810 { "x-piglatin_ML.MBE", "x-piglatin_ML.MBE", "x-piglatin_ML" },
4811 { "i-cherokee_US.utf7", "i-cherokee_US.utf7", "i-cherokee_US" },
4812 { "x-filfli_MT_FILFLA.gb-18030", "x-filfli_MT_FILFLA.gb-18030", "x-filfli_MT_FILFLA" },
4813 { "no-no-ny.utf8@B", "no_NO_NY.utf8@B", "no_NO@b=ny" /* not: "nn_NO" [alan ICU3.0] */ }, /* @ ignored unless variant is empty */
4814
4815 /* fleshing out canonicalization */
4816 /* trim space and sort keywords, ';' is separator so not present at end in canonical form */
4817 { "en_Hant_IL_VALLEY_GIRL@ currency = EUR; calendar = Japanese ;",
4818 "en_Hant_IL_VALLEY_GIRL@calendar=Japanese;currency=EUR",
4819 "en_Hant_IL_GIRL_VALLEY@calendar=Japanese;currency=EUR" },
4820 /* already-canonical ids are not changed */
4821 { "en_Hant_IL_VALLEY_GIRL@calendar=Japanese;currency=EUR",
4822 "en_Hant_IL_VALLEY_GIRL@calendar=Japanese;currency=EUR",
4823 "en_Hant_IL_GIRL_VALLEY@calendar=Japanese;currency=EUR" },
4824 /* norwegian is just too weird, if we handle things in their full generality */
4825 { "no-Hant-GB_NY@currency=$$$", "no_Hant_GB_NY@currency=$$$", "no_Hant_GB_NY@currency=$$$" /* not: "nn_Hant_GB@currency=$$$" [alan ICU3.0] */ },
4826
4827 /* test cases reflecting internal resource bundle usage */
4828 { "root@kw=foo", "root@kw=foo", "root@kw=foo" },
4829 { "@calendar=gregorian", "@calendar=gregorian", "@calendar=gregorian" },
4830 { "ja_JP@calendar=Japanese", "ja_JP@calendar=Japanese", "ja_JP@calendar=Japanese" },
4831
4832 // Before ICU 64, ICU locale canonicalization had some additional mappings.
4833 // They were removed for ICU-20187 "drop support for long-obsolete locale ID variants".
4834 // The following now use standard canonicalization.
4835 { "", "", "" },
4836 { "C", "c", "c" },
4837 { "POSIX", "posix", "posix" },
4838 { "ca_ES_PREEURO", "ca_ES_PREEURO", "ca_ES_PREEURO" },
4839 { "de_AT_PREEURO", "de_AT_PREEURO", "de_AT_PREEURO" },
4840 { "de_DE_PREEURO", "de_DE_PREEURO", "de_DE_PREEURO" },
4841 { "de_LU_PREEURO", "de_LU_PREEURO", "de_LU_PREEURO" },
4842 { "el_GR_PREEURO", "el_GR_PREEURO", "el_GR_PREEURO" },
4843 { "en_BE_PREEURO", "en_BE_PREEURO", "en_BE_PREEURO" },
4844 { "en_IE_PREEURO", "en_IE_PREEURO", "en_IE_PREEURO" },
4845 { "es_ES_PREEURO", "es_ES_PREEURO", "es_ES_PREEURO" },
4846 { "eu_ES_PREEURO", "eu_ES_PREEURO", "eu_ES_PREEURO" },
4847 { "fi_FI_PREEURO", "fi_FI_PREEURO", "fi_FI_PREEURO" },
4848 { "fr_BE_PREEURO", "fr_BE_PREEURO", "fr_BE_PREEURO" },
4849 { "fr_FR_PREEURO", "fr_FR_PREEURO", "fr_FR_PREEURO" },
4850 { "fr_LU_PREEURO", "fr_LU_PREEURO", "fr_LU_PREEURO" },
4851 { "ga_IE_PREEURO", "ga_IE_PREEURO", "ga_IE_PREEURO" },
4852 { "gl_ES_PREEURO", "gl_ES_PREEURO", "gl_ES_PREEURO" },
4853 { "it_IT_PREEURO", "it_IT_PREEURO", "it_IT_PREEURO" },
4854 { "nl_BE_PREEURO", "nl_BE_PREEURO", "nl_BE_PREEURO" },
4855 { "nl_NL_PREEURO", "nl_NL_PREEURO", "nl_NL_PREEURO" },
4856 { "pt_PT_PREEURO", "pt_PT_PREEURO", "pt_PT_PREEURO" },
4857 { "de__PHONEBOOK", "de__PHONEBOOK", "de__PHONEBOOK" },
4858 { "en_GB_EURO", "en_GB_EURO", "en_GB_EURO" },
4859 { "en_GB@EURO", "en_GB@EURO", "en_GB_EURO" }, /* POSIX ID */
4860 { "es__TRADITIONAL", "es__TRADITIONAL", "es__TRADITIONAL" },
4861 { "hi__DIRECT", "hi__DIRECT", "hi__DIRECT" },
4862 { "ja_JP_TRADITIONAL", "ja_JP_TRADITIONAL", "ja_JP_TRADITIONAL" },
4863 { "th_TH_TRADITIONAL", "th_TH_TRADITIONAL", "th_TH_TRADITIONAL" },
4864 { "zh_TW_STROKE", "zh_TW_STROKE", "zh_TW_STROKE" },
4865 { "zh__PINYIN", "zh__PINYIN", "zh__PINYIN" },
4866 { "sr-SP-Cyrl", "sr_SP_CYRL", "sr_SP_CYRL" }, /* .NET name */
4867 { "sr-SP-Latn", "sr_SP_LATN", "sr_SP_LATN" }, /* .NET name */
4868 { "sr_YU_CYRILLIC", "sr_YU_CYRILLIC", "sr_RS_CYRILLIC" }, /* Linux name */
4869 { "uz-UZ-Cyrl", "uz_UZ_CYRL", "uz_UZ_CYRL" }, /* .NET name */
4870 { "uz-UZ-Latn", "uz_UZ_LATN", "uz_UZ_LATN" }, /* .NET name */
4871 { "zh-CHS", "zh_CHS", "zh_CHS" }, /* .NET name */
4872 { "zh-CHT", "zh_CHT", "zh_CHT" }, /* .NET name This may change back to zh_Hant */
4873 /* PRE_EURO and EURO conversions don't affect other keywords */
4874 { "es_ES_PREEURO@CALendar=Japanese", "es_ES_PREEURO@calendar=Japanese", "es_ES_PREEURO@calendar=Japanese" },
4875 { "es_ES_EURO@SHOUT=zipeedeedoodah", "es_ES_EURO@shout=zipeedeedoodah", "es_ES_EURO@shout=zipeedeedoodah" },
4876 /* currency keyword overrides PRE_EURO and EURO currency */
4877 { "es_ES_PREEURO@currency=EUR", "es_ES_PREEURO@currency=EUR", "es_ES_PREEURO@currency=EUR" },
4878 { "es_ES_EURO@currency=ESP", "es_ES_EURO@currency=ESP", "es_ES_EURO@currency=ESP" },
4879 };
4880
4881 static const char* label[] = { "createFromName", "createCanonical", "Locale" };
4882
4883 int32_t i, j;
4884
4885 for (i=0; i < UPRV_LENGTHOF(testCases); i++) {
4886 for (j=0; j<3; ++j) {
4887 const char* expected = (j==1) ? testCases[i].canonicalID : testCases[i].getNameID;
4888 Locale loc = _canonicalize(j, testCases[i].localeID);
4889 const char* getName = loc.isBogus() ? "BOGUS" : loc.getName();
4890 if(uprv_strcmp(expected, getName) != 0) {
4891 errln("FAIL: %s(%s).getName() => \"%s\", expected \"%s\"",
4892 label[j], testCases[i].localeID, getName, expected);
4893 } else {
4894 logln("Ok: %s(%s) => \"%s\"",
4895 label[j], testCases[i].localeID, getName);
4896 }
4897 }
4898 }
4899 }
4900
TestCanonicalize()4901 void LocaleTest::TestCanonicalize()
4902 {
4903 static const struct {
4904 const char *localeID; /* input */
4905 const char *canonicalID; /* expected canonicalize() result */
4906 } testCases[] = {
4907 // language _ variant -> language
4908 { "no-BOKMAL", "nb" },
4909 // also test with script, country and extensions
4910 { "no-Cyrl-ID-BOKMAL-u-ca-japanese", "nb-Cyrl-ID-u-ca-japanese" },
4911 { "no-Cyrl-ID-1901-BOKMAL-xsistemo-u-ca-japanese", "nb-Cyrl-ID-1901-xsistemo-u-ca-japanese" },
4912 { "no-Cyrl-ID-1901-BOKMAL-u-ca-japanese", "nb-Cyrl-ID-1901-u-ca-japanese" },
4913 { "no-Cyrl-ID-BOKMAL-xsistemo-u-ca-japanese", "nb-Cyrl-ID-xsistemo-u-ca-japanese" },
4914 { "no-NYNORSK", "nn" },
4915 { "no-Cyrl-ID-NYNORSK-u-ca-japanese", "nn-Cyrl-ID-u-ca-japanese" },
4916 { "aa-SAAHO", "ssy" },
4917 // also test with script, country and extensions
4918 { "aa-Deva-IN-SAAHO-u-ca-japanese", "ssy-Deva-IN-u-ca-japanese" },
4919
4920 // language -> language
4921 { "aam", "aas" },
4922 // also test with script, country, variants and extensions
4923 { "aam-Cyrl-ID-3456-u-ca-japanese", "aas-Cyrl-ID-3456-u-ca-japanese" },
4924
4925 // language -> language _ Script
4926 { "sh", "sr-Latn" },
4927 // also test with script
4928 { "sh-Cyrl", "sr-Cyrl" },
4929 // also test with country, variants and extensions
4930 { "sh-ID-3456-u-ca-roc", "sr-Latn-ID-3456-u-ca-roc" },
4931
4932 // language -> language _ country
4933 { "prs", "fa-AF" },
4934 // also test with country
4935 { "prs-RU", "fa-RU" },
4936 // also test with script, variants and extensions
4937 { "prs-Cyrl-1009-u-ca-roc", "fa-Cyrl-AF-1009-u-ca-roc" },
4938
4939 { "pa-IN", "pa-IN" },
4940 // also test with script
4941 { "pa-Latn-IN", "pa-Latn-IN" },
4942 // also test with variants and extensions
4943 { "pa-IN-5678-u-ca-hindi", "pa-IN-5678-u-ca-hindi" },
4944
4945 { "ky-Cyrl-KG", "ky-Cyrl-KG" },
4946 // also test with variants and extensions
4947 { "ky-Cyrl-KG-3456-u-ca-roc", "ky-Cyrl-KG-3456-u-ca-roc" },
4948
4949 // Test replacement of scriptAlias
4950 { "en-Qaai", "en-Zinh" },
4951
4952 // Test replacement of territoryAlias
4953 // 554 has one replacement
4954 { "en-554", "en-NZ" },
4955 { "en-554-u-nu-arab", "en-NZ-u-nu-arab" },
4956 // 172 has multiple replacements
4957 // also test with variants
4958 { "ru-172-1234", "ru-RU-1234" },
4959 // also test with extensions
4960 { "ru-172-1234-u-nu-latn", "ru-RU-1234-u-nu-latn" },
4961 // also test with scripts
4962 { "uz-172", "uz-UZ" },
4963 { "uz-Cyrl-172", "uz-Cyrl-UZ" },
4964 { "uz-Bopo-172", "uz-Bopo-UZ" },
4965 // also test with variants and scripts
4966 { "uz-Cyrl-172-5678-u-nu-latn", "uz-Cyrl-UZ-5678-u-nu-latn" },
4967 // a language not used in this region
4968 { "fr-172", "fr-RU" },
4969
4970 // variant
4971 { "ja-Latn-hepburn-heploc", "ja-Latn-alalc97"},
4972
4973 { "aaa-Fooo-SU", "aaa-Fooo-RU"},
4974
4975 // ICU-21344
4976 { "ku-Arab-NT", "ku-Arab-IQ"},
4977
4978 // ICU-21402
4979 { "und-u-rg-no23", "und-u-rg-no50"},
4980 { "und-u-rg-cn11", "und-u-rg-cnbj"},
4981 { "und-u-rg-cz10a", "und-u-rg-cz110"},
4982 { "und-u-rg-fra", "und-u-rg-frges"},
4983 { "und-u-rg-frg", "und-u-rg-frges"},
4984 { "und-u-rg-lud", "und-u-rg-lucl"},
4985
4986 { "und-NO-u-sd-no23", "und-NO-u-sd-no50"},
4987 { "und-CN-u-sd-cn11", "und-CN-u-sd-cnbj"},
4988 { "und-CZ-u-sd-cz10a", "und-CZ-u-sd-cz110"},
4989 { "und-FR-u-sd-fra", "und-FR-u-sd-frges"},
4990 { "und-FR-u-sd-frg", "und-FR-u-sd-frges"},
4991 { "und-LU-u-sd-lud", "und-LU-u-sd-lucl"},
4992
4993 // ICU-21550
4994 { "und-u-rg-fi01", "und-u-rg-axzzzz"},
4995 { "und-u-rg-frcp", "und-u-rg-cpzzzz"},
4996 { "und-u-rg-frpm", "und-u-rg-pmzzzz"},
4997 { "und-u-rg-usvi", "und-u-rg-vizzzz"},
4998 { "und-u-rg-cn91", "und-u-rg-hkzzzz"},
4999 { "und-u-rg-nlaw", "und-u-rg-awzzzz"},
5000
5001 { "und-NO-u-sd-frre", "und-NO-u-sd-rezzzz"},
5002 { "und-CN-u-sd-nlcw", "und-CN-u-sd-cwzzzz"},
5003 { "und-CZ-u-sd-usgu", "und-CZ-u-sd-guzzzz"},
5004 { "und-FR-u-sd-shta", "und-FR-u-sd-tazzzz"},
5005 { "und-FR-u-sd-cn71", "und-FR-u-sd-twzzzz"},
5006
5007
5008 // ICU-21401
5009 { "cel-gaulish", "xtg"},
5010
5011 // ICU-21406
5012 // Inside T extension
5013 // Case of Script and Region
5014 { "ja-kana-jp-t-it-latn-it", "ja-Kana-JP-t-it-latn-it"},
5015 { "und-t-zh-hani-tw", "und-t-zh-hani-tw"},
5016 { "und-cyrl-t-und-Latn", "und-Cyrl-t-und-latn"},
5017 // Order of singleton
5018 { "und-u-ca-roc-t-zh", "und-t-zh-u-ca-roc"},
5019 // Variant subtags are alphabetically ordered.
5020 { "sl-t-sl-rozaj-biske-1994", "sl-t-sl-1994-biske-rozaj"},
5021 // tfield subtags are alphabetically ordered.
5022 // (Also tests subtag case normalisation.)
5023 { "DE-T-lv-M0-DIN", "de-t-lv-m0-din"},
5024 { "DE-T-M0-DIN-K0-QWERTZ", "de-t-k0-qwertz-m0-din"},
5025 { "DE-T-lv-M0-DIN-K0-QWERTZ", "de-t-lv-k0-qwertz-m0-din"},
5026 // "true" tvalue subtags aren't removed.
5027 // (UTS 35 version 36, §3.2.1 claims otherwise, but tkey must be followed by
5028 // tvalue, so that's likely a spec bug in UTS 35.)
5029 { "en-t-m0-true", "en-t-m0-true"},
5030 // tlang subtags are canonicalised.
5031 { "en-t-iw", "en-t-he"},
5032 { "en-t-hy-latn-SU", "en-t-hy-latn-am"},
5033 { "ru-t-ru-cyrl-SU", "ru-t-ru-cyrl-ru"},
5034 { "fr-t-fr-172", "fr-t-fr-ru"},
5035 { "und-t-no-latn-BOKMAL", "und-t-nb-latn" },
5036 { "und-t-sgn-qAAi-NL", "und-t-dse-zinh" },
5037 // alias of tvalue should be replaced
5038 { "en-t-m0-NaMeS", "en-t-m0-prprname" },
5039 { "en-t-s0-ascii-d0-NaMe", "en-t-d0-charname-s0-ascii" },
5040 };
5041 int32_t i;
5042 for (i=0; i < UPRV_LENGTHOF(testCases); i++) {
5043 UErrorCode status = U_ZERO_ERROR;
5044 std::string otag = testCases[i].localeID;
5045 Locale loc = Locale::forLanguageTag(otag.c_str(), status);
5046 loc.canonicalize(status);
5047 std::string tag = loc.toLanguageTag<std::string>(status);
5048 if (tag != testCases[i].canonicalID) {
5049 errcheckln(status, "FAIL: %s should be canonicalized to %s but got %s - %s",
5050 otag.c_str(),
5051 testCases[i].canonicalID,
5052 tag.c_str(),
5053 u_errorName(status));
5054 }
5055 }
5056 }
5057
TestCurrencyByDate()5058 void LocaleTest::TestCurrencyByDate()
5059 {
5060 #if !UCONFIG_NO_FORMATTING
5061 UErrorCode status = U_ZERO_ERROR;
5062 UDate date = uprv_getUTCtime();
5063 char16_t TMP[4] = {0, 0, 0, 0};
5064 int32_t index = 0;
5065 int32_t resLen = 0;
5066 UnicodeString tempStr, resultStr;
5067
5068 // Cycle through historical currencies
5069 date = (UDate)-630720000000.0; // pre 1961 - no currency defined
5070 index = ucurr_countCurrencies("eo_AM", date, &status);
5071 if (index != 0)
5072 {
5073 errcheckln(status, "FAIL: didn't return 0 for eo_AM - %s", u_errorName(status));
5074 }
5075 resLen = ucurr_forLocaleAndDate("eo_AM", date, index, TMP, 4, &status);
5076 if (resLen != 0) {
5077 errcheckln(status, "FAIL: eo_AM didn't return nullptr - %s", u_errorName(status));
5078 }
5079 status = U_ZERO_ERROR;
5080
5081 date = (UDate)0.0; // 1970 - one currency defined
5082 index = ucurr_countCurrencies("eo_AM", date, &status);
5083 if (index != 1)
5084 {
5085 errcheckln(status, "FAIL: didn't return 1 for eo_AM - %s", u_errorName(status));
5086 }
5087 resLen = ucurr_forLocaleAndDate("eo_AM", date, index, TMP, 4, &status);
5088 tempStr.setTo(TMP);
5089 resultStr.setTo("SUR");
5090 if (resultStr != tempStr) {
5091 errcheckln(status, "FAIL: didn't return SUR for eo_AM - %s", u_errorName(status));
5092 }
5093
5094 date = (UDate)693792000000.0; // 1992 - one currency defined
5095 index = ucurr_countCurrencies("eo_AM", date, &status);
5096 if (index != 1)
5097 {
5098 errcheckln(status, "FAIL: didn't return 1 for eo_AM - %s", u_errorName(status));
5099 }
5100 resLen = ucurr_forLocaleAndDate("eo_AM", date, index, TMP, 4, &status);
5101 tempStr.setTo(TMP);
5102 resultStr.setTo("RUR");
5103 if (resultStr != tempStr) {
5104 errcheckln(status, "FAIL: didn't return RUR for eo_AM - %s", u_errorName(status));
5105 }
5106
5107 date = (UDate)977616000000.0; // post 1993 - one currency defined
5108 index = ucurr_countCurrencies("eo_AM", date, &status);
5109 if (index != 1)
5110 {
5111 errcheckln(status, "FAIL: didn't return 1 for eo_AM - %s", u_errorName(status));
5112 }
5113 resLen = ucurr_forLocaleAndDate("eo_AM", date, index, TMP, 4, &status);
5114 tempStr.setTo(TMP);
5115 resultStr.setTo("AMD");
5116 if (resultStr != tempStr) {
5117 errcheckln(status, "FAIL: didn't return AMD for eo_AM - %s", u_errorName(status));
5118 }
5119
5120 // Locale AD has multiple currencies at once
5121 date = (UDate)977616000000.0; // year 2001
5122 index = ucurr_countCurrencies("eo_AD", date, &status);
5123 if (index != 4)
5124 {
5125 errcheckln(status, "FAIL: didn't return 4 for eo_AD - %s", u_errorName(status));
5126 }
5127 resLen = ucurr_forLocaleAndDate("eo_AD", date, 1, TMP, 4, &status);
5128 tempStr.setTo(TMP);
5129 resultStr.setTo("EUR");
5130 if (resultStr != tempStr) {
5131 errcheckln(status, "FAIL: didn't return EUR for eo_AD - %s", u_errorName(status));
5132 }
5133 resLen = ucurr_forLocaleAndDate("eo_AD", date, 2, TMP, 4, &status);
5134 tempStr.setTo(TMP);
5135 resultStr.setTo("ESP");
5136 if (resultStr != tempStr) {
5137 errcheckln(status, "FAIL: didn't return ESP for eo_AD - %s", u_errorName(status));
5138 }
5139 resLen = ucurr_forLocaleAndDate("eo_AD", date, 3, TMP, 4, &status);
5140 tempStr.setTo(TMP);
5141 resultStr.setTo("FRF");
5142 if (resultStr != tempStr) {
5143 errcheckln(status, "FAIL: didn't return FRF for eo_AD - %s", u_errorName(status));
5144 }
5145 resLen = ucurr_forLocaleAndDate("eo_AD", date, 4, TMP, 4, &status);
5146 tempStr.setTo(TMP);
5147 resultStr.setTo("ADP");
5148 if (resultStr != tempStr) {
5149 errcheckln(status, "FAIL: didn't return ADP for eo_AD - %s", u_errorName(status));
5150 }
5151
5152 date = (UDate)0.0; // year 1970
5153 index = ucurr_countCurrencies("eo_AD", date, &status);
5154 if (index != 3)
5155 {
5156 errcheckln(status, "FAIL: didn't return 3 for eo_AD - %s", u_errorName(status));
5157 }
5158 resLen = ucurr_forLocaleAndDate("eo_AD", date, 1, TMP, 4, &status);
5159 tempStr.setTo(TMP);
5160 resultStr.setTo("ESP");
5161 if (resultStr != tempStr) {
5162 errcheckln(status, "FAIL: didn't return ESP for eo_AD - %s", u_errorName(status));
5163 }
5164 resLen = ucurr_forLocaleAndDate("eo_AD", date, 2, TMP, 4, &status);
5165 tempStr.setTo(TMP);
5166 resultStr.setTo("FRF");
5167 if (resultStr != tempStr) {
5168 errcheckln(status, "FAIL: didn't return FRF for eo_AD - %s", u_errorName(status));
5169 }
5170 resLen = ucurr_forLocaleAndDate("eo_AD", date, 3, TMP, 4, &status);
5171 tempStr.setTo(TMP);
5172 resultStr.setTo("ADP");
5173 if (resultStr != tempStr) {
5174 errcheckln(status, "FAIL: didn't return ADP for eo_AD - %s", u_errorName(status));
5175 }
5176
5177 date = (UDate)-630720000000.0; // year 1950
5178 index = ucurr_countCurrencies("eo_AD", date, &status);
5179 if (index != 2)
5180 {
5181 errcheckln(status, "FAIL: didn't return 2 for eo_AD - %s", u_errorName(status));
5182 }
5183 resLen = ucurr_forLocaleAndDate("eo_AD", date, 1, TMP, 4, &status);
5184 tempStr.setTo(TMP);
5185 resultStr.setTo("ESP");
5186 if (resultStr != tempStr) {
5187 errcheckln(status, "FAIL: didn't return ESP for eo_AD - %s", u_errorName(status));
5188 }
5189 resLen = ucurr_forLocaleAndDate("eo_AD", date, 2, TMP, 4, &status);
5190 tempStr.setTo(TMP);
5191 resultStr.setTo("ADP");
5192 if (resultStr != tempStr) {
5193 errcheckln(status, "FAIL: didn't return ADP for eo_AD - %s", u_errorName(status));
5194 }
5195
5196 date = (UDate)-2207520000000.0; // year 1900
5197 index = ucurr_countCurrencies("eo_AD", date, &status);
5198 if (index != 1)
5199 {
5200 errcheckln(status, "FAIL: didn't return 1 for eo_AD - %s", u_errorName(status));
5201 }
5202 resLen = ucurr_forLocaleAndDate("eo_AD", date, 1, TMP, 4, &status);
5203 tempStr.setTo(TMP);
5204 resultStr.setTo("ESP");
5205 if (resultStr != tempStr) {
5206 errcheckln(status, "FAIL: didn't return ESP for eo_AD - %s", u_errorName(status));
5207 }
5208
5209 // Locale UA has gap between years 1994 - 1996
5210 date = (UDate)788400000000.0;
5211 index = ucurr_countCurrencies("eo_UA", date, &status);
5212 if (index != 0)
5213 {
5214 errcheckln(status, "FAIL: didn't return 0 for eo_UA - %s", u_errorName(status));
5215 }
5216 resLen = ucurr_forLocaleAndDate("eo_UA", date, index, TMP, 4, &status);
5217 if (resLen != 0) {
5218 errcheckln(status, "FAIL: eo_UA didn't return nullptr - %s", u_errorName(status));
5219 }
5220 status = U_ZERO_ERROR;
5221
5222 // Test index bounds
5223 resLen = ucurr_forLocaleAndDate("eo_UA", date, 100, TMP, 4, &status);
5224 if (resLen != 0) {
5225 errcheckln(status, "FAIL: eo_UA didn't return nullptr - %s", u_errorName(status));
5226 }
5227 status = U_ZERO_ERROR;
5228
5229 resLen = ucurr_forLocaleAndDate("eo_UA", date, 0, TMP, 4, &status);
5230 if (resLen != 0) {
5231 errcheckln(status, "FAIL: eo_UA didn't return nullptr - %s", u_errorName(status));
5232 }
5233 status = U_ZERO_ERROR;
5234
5235 // Test for bogus locale
5236 index = ucurr_countCurrencies("eo_QQ", date, &status);
5237 if (index != 0)
5238 {
5239 errcheckln(status, "FAIL: didn't return 0 for eo_QQ - %s", u_errorName(status));
5240 }
5241 status = U_ZERO_ERROR;
5242 resLen = ucurr_forLocaleAndDate("eo_QQ", date, 1, TMP, 4, &status);
5243 if (resLen != 0) {
5244 errcheckln(status, "FAIL: eo_QQ didn't return nullptr - %s", u_errorName(status));
5245 }
5246 status = U_ZERO_ERROR;
5247 resLen = ucurr_forLocaleAndDate("eo_QQ", date, 0, TMP, 4, &status);
5248 if (resLen != 0) {
5249 errcheckln(status, "FAIL: eo_QQ didn't return nullptr - %s", u_errorName(status));
5250 }
5251 status = U_ZERO_ERROR;
5252
5253 // Cycle through histrocial currencies
5254 date = (UDate)977616000000.0; // 2001 - one currency
5255 index = ucurr_countCurrencies("eo_AO", date, &status);
5256 if (index != 1)
5257 {
5258 errcheckln(status, "FAIL: didn't return 1 for eo_AO - %s", u_errorName(status));
5259 }
5260 resLen = ucurr_forLocaleAndDate("eo_AO", date, 1, TMP, 4, &status);
5261 tempStr.setTo(TMP);
5262 resultStr.setTo("AOA");
5263 if (resultStr != tempStr) {
5264 errcheckln(status, "FAIL: didn't return AOA for eo_AO - %s", u_errorName(status));
5265 }
5266
5267 date = (UDate)819936000000.0; // 1996 - 2 currencies
5268 index = ucurr_countCurrencies("eo_AO", date, &status);
5269 if (index != 2)
5270 {
5271 errcheckln(status, "FAIL: didn't return 1 for eo_AO - %s", u_errorName(status));
5272 }
5273 resLen = ucurr_forLocaleAndDate("eo_AO", date, 1, TMP, 4, &status);
5274 tempStr.setTo(TMP);
5275 resultStr.setTo("AOR");
5276 if (resultStr != tempStr) {
5277 errcheckln(status, "FAIL: didn't return AOR for eo_AO - %s", u_errorName(status));
5278 }
5279 resLen = ucurr_forLocaleAndDate("eo_AO", date, 2, TMP, 4, &status);
5280 tempStr.setTo(TMP);
5281 resultStr.setTo("AON");
5282 if (resultStr != tempStr) {
5283 errcheckln(status, "FAIL: didn't return AON for eo_AO - %s", u_errorName(status));
5284 }
5285
5286 date = (UDate)662256000000.0; // 1991 - 2 currencies
5287 index = ucurr_countCurrencies("eo_AO", date, &status);
5288 if (index != 2)
5289 {
5290 errcheckln(status, "FAIL: didn't return 1 for eo_AO - %s", u_errorName(status));
5291 }
5292 resLen = ucurr_forLocaleAndDate("eo_AO", date, 1, TMP, 4, &status);
5293 tempStr.setTo(TMP);
5294 resultStr.setTo("AON");
5295 if (resultStr != tempStr) {
5296 errcheckln(status, "FAIL: didn't return AON for eo_AO - %s", u_errorName(status));
5297 }
5298 resLen = ucurr_forLocaleAndDate("eo_AO", date, 2, TMP, 4, &status);
5299 tempStr.setTo(TMP);
5300 resultStr.setTo("AOK");
5301 if (resultStr != tempStr) {
5302 errcheckln(status, "FAIL: didn't return AOK for eo_AO - %s", u_errorName(status));
5303 }
5304
5305 date = (UDate)315360000000.0; // 1980 - one currency
5306 index = ucurr_countCurrencies("eo_AO", date, &status);
5307 if (index != 1)
5308 {
5309 errcheckln(status, "FAIL: didn't return 1 for eo_AO - %s", u_errorName(status));
5310 }
5311 resLen = ucurr_forLocaleAndDate("eo_AO", date, 1, TMP, 4, &status);
5312 tempStr.setTo(TMP);
5313 resultStr.setTo("AOK");
5314 if (resultStr != tempStr) {
5315 errcheckln(status, "FAIL: didn't return AOK for eo_AO - %s", u_errorName(status));
5316 }
5317
5318 date = (UDate)0.0; // 1970 - no currencies
5319 index = ucurr_countCurrencies("eo_AO", date, &status);
5320 if (index != 0)
5321 {
5322 errcheckln(status, "FAIL: didn't return 1 for eo_AO - %s", u_errorName(status));
5323 }
5324 resLen = ucurr_forLocaleAndDate("eo_AO", date, 1, TMP, 4, &status);
5325 if (resLen != 0) {
5326 errcheckln(status, "FAIL: eo_AO didn't return nullptr - %s", u_errorName(status));
5327 }
5328 status = U_ZERO_ERROR;
5329
5330 // Test with currency keyword override
5331 date = (UDate)977616000000.0; // 2001 - two currencies
5332 index = ucurr_countCurrencies("eo_DE@currency=DEM", date, &status);
5333 if (index != 2)
5334 {
5335 errcheckln(status, "FAIL: didn't return 2 for eo_DE@currency=DEM - %s", u_errorName(status));
5336 }
5337 resLen = ucurr_forLocaleAndDate("eo_DE@currency=DEM", date, 1, TMP, 4, &status);
5338 tempStr.setTo(TMP);
5339 resultStr.setTo("EUR");
5340 if (resultStr != tempStr) {
5341 errcheckln(status, "FAIL: didn't return EUR for eo_DE@currency=DEM - %s", u_errorName(status));
5342 }
5343 resLen = ucurr_forLocaleAndDate("eo_DE@currency=DEM", date, 2, TMP, 4, &status);
5344 tempStr.setTo(TMP);
5345 resultStr.setTo("DEM");
5346 if (resultStr != tempStr) {
5347 errcheckln(status, "FAIL: didn't return DEM for eo_DE@currency=DEM - %s", u_errorName(status));
5348 }
5349
5350 // Test Euro Support
5351 status = U_ZERO_ERROR; // reset
5352 date = uprv_getUTCtime();
5353
5354 char16_t USD[4];
5355 ucurr_forLocaleAndDate("en_US", date, 1, USD, 4, &status);
5356
5357 char16_t YEN[4];
5358 ucurr_forLocaleAndDate("ja_JP", date, 1, YEN, 4, &status);
5359
5360 ucurr_forLocaleAndDate("en_US", date, 1, TMP, 4, &status);
5361 if (u_strcmp(USD, TMP) != 0) {
5362 errcheckln(status, "Fail: en_US didn't return USD - %s", u_errorName(status));
5363 }
5364 ucurr_forLocaleAndDate("en_US_Q", date, 1, TMP, 4, &status);
5365 if (u_strcmp(USD, TMP) != 0) {
5366 errcheckln(status, "Fail: en_US_Q didn't fallback to en_US - %s", u_errorName(status));
5367 }
5368 status = U_ZERO_ERROR; // reset
5369 #endif
5370 }
5371
TestGetVariantWithKeywords()5372 void LocaleTest::TestGetVariantWithKeywords()
5373 {
5374 Locale l("en_US_VALLEY@foo=value");
5375 const char *variant = l.getVariant();
5376 logln(variant);
5377 test_assert(strcmp("VALLEY", variant) == 0);
5378
5379 UErrorCode status = U_ZERO_ERROR;
5380 char buffer[50];
5381 int32_t len = l.getKeywordValue("foo", buffer, 50, status);
5382 buffer[len] = '\0';
5383 test_assert(strcmp("value", buffer) == 0);
5384 }
5385
TestIsRightToLeft()5386 void LocaleTest::TestIsRightToLeft() {
5387 assertFalse("root LTR", Locale::getRoot().isRightToLeft());
5388 assertFalse("zh LTR", Locale::getChinese().isRightToLeft());
5389 assertTrue("ar RTL", Locale("ar").isRightToLeft());
5390 assertTrue("und-EG RTL", Locale("und-EG").isRightToLeft(), false, true);
5391 assertFalse("fa-Cyrl LTR", Locale("fa-Cyrl").isRightToLeft());
5392 assertTrue("en-Hebr RTL", Locale("en-Hebr").isRightToLeft());
5393 assertTrue("ckb RTL", Locale("ckb").isRightToLeft(), false, true); // Sorani Kurdish
5394 assertFalse("fil LTR", Locale("fil").isRightToLeft());
5395 assertFalse("he-Zyxw LTR", Locale("he-Zyxw").isRightToLeft());
5396 }
5397
TestBug11421()5398 void LocaleTest::TestBug11421() {
5399 Locale::getDefault().getBaseName();
5400 int32_t numLocales;
5401 const Locale *localeList = Locale::getAvailableLocales(numLocales);
5402 for (int localeIndex = 0; localeIndex < numLocales; localeIndex++) {
5403 const Locale &loc = localeList[localeIndex];
5404 if (strncmp(loc.getName(), loc.getBaseName(), strlen(loc.getBaseName()))) {
5405 errln("%s:%d loc.getName=\"%s\"; loc.getBaseName=\"%s\"",
5406 __FILE__, __LINE__, loc.getName(), loc.getBaseName());
5407 break;
5408 }
5409 }
5410 }
5411
5412 // TestBug13277. The failure manifests as valgrind errors.
5413 // See the trac ticket for details.
5414 //
5415
TestBug13277()5416 void LocaleTest::TestBug13277() {
5417 UErrorCode status = U_ZERO_ERROR;
5418 CharString name("en-us-x-foo", -1, status);
5419 while (name.length() < 152) {
5420 name.append("-x-foo", -1, status);
5421 }
5422
5423 while (name.length() < 160) {
5424 name.append('z', status);
5425 Locale loc(name.data(), nullptr, nullptr, nullptr);
5426 }
5427 }
5428
5429 // TestBug13554 Check for read past end of array in getPosixID().
5430 // The bug shows as an Address Sanitizer failure.
5431
TestBug13554()5432 void LocaleTest::TestBug13554() {
5433 UErrorCode status = U_ZERO_ERROR;
5434 const int BUFFER_SIZE = 100;
5435 char posixID[BUFFER_SIZE];
5436
5437 for (uint32_t hostid = 0; hostid < 0x500; ++hostid) {
5438 status = U_ZERO_ERROR;
5439 uprv_convertToPosix(hostid, posixID, BUFFER_SIZE, &status);
5440 }
5441 }
5442
TestBug20410()5443 void LocaleTest::TestBug20410() {
5444 IcuTestErrorCode status(*this, "TestBug20410()");
5445
5446 static const char tag1[] = "art-lojban-x-0";
5447 static const Locale expected1("jbo@x=0");
5448 Locale result1 = Locale::forLanguageTag(tag1, status);
5449 status.errIfFailureAndReset("\"%s\"", tag1);
5450 assertEquals(tag1, expected1.getName(), result1.getName());
5451
5452 static const char tag2[] = "zh-xiang-u-nu-thai-x-0";
5453 static const Locale expected2("hsn@numbers=thai;x=0");
5454 Locale result2 = Locale::forLanguageTag(tag2, status);
5455 status.errIfFailureAndReset("\"%s\"", tag2);
5456 assertEquals(tag2, expected2.getName(), result2.getName());
5457
5458 static const char locid3[] = "art__lojban@x=0";
5459 Locale result3 = Locale::createCanonical(locid3);
5460 static const Locale expected3("jbo@x=0");
5461 assertEquals(locid3, expected3.getName(), result3.getName());
5462
5463 static const char locid4[] = "art-lojban-x-0";
5464 Locale result4 = Locale::createCanonical(locid4);
5465 static const Locale expected4("jbo@x=0");
5466 assertEquals(locid4, expected4.getName(), result4.getName());
5467 }
5468
TestBug20900()5469 void LocaleTest::TestBug20900() {
5470 static const struct {
5471 const char *localeID; /* input */
5472 const char *canonicalID; /* expected canonicalize() result */
5473 } testCases[] = {
5474 { "art-lojban", "jbo" },
5475 { "zh-guoyu", "zh" },
5476 { "zh-hakka", "hak" },
5477 { "zh-xiang", "hsn" },
5478 { "zh-min-nan", "nan" },
5479 { "zh-gan", "gan" },
5480 { "zh-wuu", "wuu" },
5481 { "zh-yue", "yue" },
5482 };
5483
5484 IcuTestErrorCode status(*this, "TestBug20900");
5485 for (int32_t i=0; i < UPRV_LENGTHOF(testCases); i++) {
5486 Locale loc = Locale::createCanonical(testCases[i].localeID);
5487 std::string result = loc.toLanguageTag<std::string>(status);
5488 const char* tag = loc.isBogus() ? "BOGUS" : result.c_str();
5489 status.errIfFailureAndReset("FAIL: createCanonical(%s).toLanguageTag() expected \"%s\"",
5490 testCases[i].localeID, tag);
5491 assertEquals("createCanonical", testCases[i].canonicalID, tag);
5492 }
5493 }
5494
5495 U_DEFINE_LOCAL_OPEN_POINTER(LocalStdioFilePointer, FILE, fclose);
TestLocaleCanonicalizationFromFile()5496 void LocaleTest::TestLocaleCanonicalizationFromFile()
5497 {
5498 IcuTestErrorCode status(*this, "TestLocaleCanonicalizationFromFile");
5499 const char *sourceTestDataPath=getSourceTestData(status);
5500 if(status.errIfFailureAndReset("unable to find the source/test/testdata "
5501 "folder (getSourceTestData())")) {
5502 return;
5503 }
5504 char testPath[400];
5505 char line[256];
5506 strcpy(testPath, sourceTestDataPath);
5507 strcat(testPath, "localeCanonicalization.txt");
5508 LocalStdioFilePointer testFile(fopen(testPath, "r"));
5509 if(testFile.isNull()) {
5510 errln("unable to open %s", testPath);
5511 return;
5512 }
5513 // Format:
5514 // <source locale identifier> ; <expected canonicalized locale identifier>
5515 while (fgets(line, (int)sizeof(line), testFile.getAlias())!=nullptr) {
5516 if (line[0] == '#') {
5517 // ignore any lines start with #
5518 continue;
5519 }
5520 char *semi = strchr(line, ';');
5521 if (semi == nullptr) {
5522 // ignore any lines without ;
5523 continue;
5524 }
5525 *semi = '\0'; // null terminiate on the spot of semi
5526 const char* from = u_skipWhitespace((const char*)line);
5527 u_rtrim((char*)from);
5528 const char* to = u_skipWhitespace((const char*)semi + 1);
5529 u_rtrim((char*)to);
5530 std::string expect(to);
5531 // Change the _ to -
5532 std::transform(expect.begin(), expect.end(), expect.begin(),
5533 [](unsigned char c){ return c == '_' ? '-' : c; });
5534
5535 Locale loc = Locale::createCanonical(from);
5536 std::string result = loc.toLanguageTag<std::string>(status);
5537 const char* tag = loc.isBogus() ? "BOGUS" : result.c_str();
5538 status.errIfFailureAndReset(
5539 "FAIL: createCanonical(%s).toLanguageTag() expected \"%s\" locale is %s",
5540 from, tag, loc.getName());
5541 std::string msg("createCanonical(");
5542 msg += from;
5543 msg += ") locale = ";
5544 msg += loc.getName();
5545 assertEquals(msg.c_str(), expect.c_str(), tag);
5546 }
5547 }
5548
TestKnownCanonicalizedListCorrect()5549 void LocaleTest::TestKnownCanonicalizedListCorrect()
5550 {
5551 IcuTestErrorCode status(*this, "TestKnownCanonicalizedListCorrect");
5552 int32_t numOfKnownCanonicalized;
5553 const char* const* knownCanonicalized =
5554 ulocimp_getKnownCanonicalizedLocaleForTest(&numOfKnownCanonicalized);
5555 for (int32_t i = 0; i < numOfKnownCanonicalized; i++) {
5556 std::string msg("Known Canonicalized Locale is not canonicalized: ");
5557 assertTrue((msg + knownCanonicalized[i]).c_str(),
5558 ulocimp_isCanonicalizedLocaleForTest(knownCanonicalized[i]));
5559 }
5560 }
5561
TestConstructorAcceptsBCP47()5562 void LocaleTest::TestConstructorAcceptsBCP47() {
5563 IcuTestErrorCode status(*this, "TestConstructorAcceptsBCP47");
5564
5565 Locale loc1("ar-EG-u-nu-latn");
5566 Locale loc2("ar-EG@numbers=latn");
5567 Locale loc3("ar-EG");
5568 std::string val;
5569
5570 // Check getKeywordValue "numbers"
5571 val = loc1.getKeywordValue<std::string>("numbers", status);
5572 assertEquals("BCP47 syntax has ICU keyword value", "latn", val.c_str());
5573
5574 val = loc2.getKeywordValue<std::string>("numbers", status);
5575 assertEquals("ICU syntax has ICU keyword value", "latn", val.c_str());
5576
5577 val = loc3.getKeywordValue<std::string>("numbers", status);
5578 assertEquals("Default, ICU keyword", "", val.c_str());
5579
5580 // Check getUnicodeKeywordValue "nu"
5581 val = loc1.getUnicodeKeywordValue<std::string>("nu", status);
5582 assertEquals("BCP47 syntax has short unicode keyword value", "latn", val.c_str());
5583
5584 val = loc2.getUnicodeKeywordValue<std::string>("nu", status);
5585 assertEquals("ICU syntax has short unicode keyword value", "latn", val.c_str());
5586
5587 val = loc3.getUnicodeKeywordValue<std::string>("nu", status);
5588 status.expectErrorAndReset(U_ILLEGAL_ARGUMENT_ERROR, "Default, short unicode keyword");
5589
5590 // Check getUnicodeKeywordValue "numbers"
5591 val = loc1.getUnicodeKeywordValue<std::string>("numbers", status);
5592 assertEquals("BCP47 syntax has long unicode keyword value", "latn", val.c_str());
5593
5594 val = loc2.getUnicodeKeywordValue<std::string>("numbers", status);
5595 assertEquals("ICU syntax has long unicode keyword value", "latn", val.c_str());
5596
5597 val = loc3.getUnicodeKeywordValue<std::string>("numbers", status);
5598 status.expectErrorAndReset(U_ILLEGAL_ARGUMENT_ERROR, "Default, long unicode keyword");
5599 }
5600
TestForLanguageTag()5601 void LocaleTest::TestForLanguageTag() {
5602 IcuTestErrorCode status(*this, "TestForLanguageTag()");
5603
5604 static const char tag_en[] = "en-US";
5605 static const char tag_oed[] = "en-GB-oed";
5606 static const char tag_af[] = "af-t-ar-i0-handwrit-u-ca-coptic-x-foo";
5607 static const char tag_ill[] = "!";
5608 static const char tag_no_nul[] = { 'e', 'n', '-', 'G', 'B' };
5609 static const char tag_ext[] = "en-GB-1-abc-efg-a-xyz";
5610 static const char tag_var[] = "sl-rozaj-biske-1994";
5611
5612 static const Locale loc_en("en_US");
5613 static const Locale loc_oed("en_GB_OXENDICT");
5614 static const Locale loc_af("af@calendar=coptic;t=ar-i0-handwrit;x=foo");
5615 static const Locale loc_null("");
5616 static const Locale loc_gb("en_GB");
5617 static const Locale loc_ext("en_GB@1=abc-efg;a=xyz");
5618 static const Locale loc_var("sl__1994_BISKE_ROZAJ");
5619
5620 Locale result_en = Locale::forLanguageTag(tag_en, status);
5621 status.errIfFailureAndReset("\"%s\"", tag_en);
5622 assertEquals(tag_en, loc_en.getName(), result_en.getName());
5623
5624 Locale result_oed = Locale::forLanguageTag(tag_oed, status);
5625 status.errIfFailureAndReset("\"%s\"", tag_oed);
5626 assertEquals(tag_oed, loc_oed.getName(), result_oed.getName());
5627
5628 Locale result_af = Locale::forLanguageTag(tag_af, status);
5629 status.errIfFailureAndReset("\"%s\"", tag_af);
5630 assertEquals(tag_af, loc_af.getName(), result_af.getName());
5631
5632 Locale result_var = Locale::forLanguageTag(tag_var, status);
5633 status.errIfFailureAndReset("\"%s\"", tag_var);
5634 assertEquals(tag_var, loc_var.getName(), result_var.getName());
5635
5636 Locale result_ill = Locale::forLanguageTag(tag_ill, status);
5637 assertEquals(tag_ill, U_ILLEGAL_ARGUMENT_ERROR, status.reset());
5638 assertTrue(result_ill.getName(), result_ill.isBogus());
5639
5640 Locale result_null = Locale::forLanguageTag(nullptr, status);
5641 status.errIfFailureAndReset("nullptr");
5642 assertEquals("nullptr", loc_null.getName(), result_null.getName());
5643
5644 StringPiece sp_substr(tag_oed, 5); // "en-GB", no NUL.
5645 Locale result_substr = Locale::forLanguageTag(sp_substr, status);
5646 status.errIfFailureAndReset("\"%.*s\"", sp_substr.size(), sp_substr.data());
5647 assertEquals(CharString(sp_substr, status).data(),
5648 loc_gb.getName(), result_substr.getName());
5649
5650 StringPiece sp_no_nul(tag_no_nul, sizeof tag_no_nul); // "en-GB", no NUL.
5651 Locale result_no_nul = Locale::forLanguageTag(sp_no_nul, status);
5652 status.errIfFailureAndReset("\"%.*s\"", sp_no_nul.size(), sp_no_nul.data());
5653 assertEquals(CharString(sp_no_nul, status).data(),
5654 loc_gb.getName(), result_no_nul.getName());
5655
5656 Locale result_ext = Locale::forLanguageTag(tag_ext, status);
5657 status.errIfFailureAndReset("\"%s\"", tag_ext);
5658 assertEquals(tag_ext, loc_ext.getName(), result_ext.getName());
5659
5660 static const struct {
5661 const char *inputTag; /* input */
5662 const char *expectedID; /* expected forLanguageTag().getName() result */
5663 } testCases[] = {
5664 // ICU-21433
5665 {"und-1994-biske-rozaj", "__1994_BISKE_ROZAJ"},
5666 {"de-1994-biske-rozaj", "de__1994_BISKE_ROZAJ"},
5667 {"und-x-private", "@x=private"},
5668 {"de-1994-biske-rozaj-x-private", "de__1994_BISKE_ROZAJ@x=private"},
5669 {"und-1994-biske-rozaj-x-private", "__1994_BISKE_ROZAJ@x=private"},
5670 };
5671 int32_t i;
5672 for (i=0; i < UPRV_LENGTHOF(testCases); i++) {
5673 UErrorCode status = U_ZERO_ERROR;
5674 std::string otag = testCases[i].inputTag;
5675 std::string tag = Locale::forLanguageTag(otag.c_str(), status).getName();
5676 if (tag != testCases[i].expectedID) {
5677 errcheckln(status, "FAIL: %s should be toLanguageTag to %s but got %s - %s",
5678 otag.c_str(),
5679 testCases[i].expectedID,
5680 tag.c_str(),
5681 u_errorName(status));
5682 }
5683 }
5684 }
5685
TestForLanguageTagLegacyTagBug21676()5686 void LocaleTest::TestForLanguageTagLegacyTagBug21676() {
5687 IcuTestErrorCode status(*this, "TestForLanguageTagLegacyTagBug21676()");
5688 std::string tag(
5689 "i-enochian-1nochian-129-515VNTR-64863775-X3il6-110Y101-29-515VNTR-"
5690 "64863775-153zu-u-Y4-H0-t6-X3-u6-110Y101-X");
5691 std::string input(tag);
5692 input += "EXTRA MEMORY AFTER NON-nullptr TERMINATED STRING";
5693 StringPiece stringp(input.c_str(), tag.length());
5694 std::string name = Locale::forLanguageTag(stringp, status).getName();
5695 std::string expected(
5696 "@x=i-enochian-1nochian-129-515vntr-64863775-x3il6-110y101-29-515vntr-"
5697 "64863775-153zu-u-y4-h0-t6-x3-u6-110y101-x");
5698 if (name != expected) {
5699 errcheckln(
5700 status,
5701 "FAIL: forLanguageTag('%s', \n%d).getName() should be \n'%s' but got %s",
5702 tag.c_str(), tag.length(), expected.c_str(), name.c_str());
5703 }
5704 }
5705
TestToLanguageTag()5706 void LocaleTest::TestToLanguageTag() {
5707 IcuTestErrorCode status(*this, "TestToLanguageTag()");
5708
5709 static const Locale loc_c("en_US_POSIX");
5710 static const Locale loc_en("en_US");
5711 static const Locale loc_af("af@calendar=coptic;t=ar-i0-handwrit;x=foo");
5712 static const Locale loc_ext("en@0=abc;a=xyz");
5713 static const Locale loc_empty("");
5714 static const Locale loc_ill("!");
5715 static const Locale loc_variant("sl__ROZAJ_BISKE_1994");
5716
5717 static const char tag_c[] = "en-US-u-va-posix";
5718 static const char tag_en[] = "en-US";
5719 static const char tag_af[] = "af-t-ar-i0-handwrit-u-ca-coptic-x-foo";
5720 static const char tag_ext[] = "en-0-abc-a-xyz";
5721 static const char tag_und[] = "und";
5722 static const char tag_variant[] = "sl-1994-biske-rozaj";
5723
5724 std::string result;
5725 StringByteSink<std::string> sink(&result);
5726 loc_c.toLanguageTag(sink, status);
5727 status.errIfFailureAndReset("\"%s\"", loc_c.getName());
5728 assertEquals(loc_c.getName(), tag_c, result.c_str());
5729
5730 std::string result_c = loc_c.toLanguageTag<std::string>(status);
5731 status.errIfFailureAndReset("\"%s\"", loc_c.getName());
5732 assertEquals(loc_c.getName(), tag_c, result_c.c_str());
5733
5734 std::string result_en = loc_en.toLanguageTag<std::string>(status);
5735 status.errIfFailureAndReset("\"%s\"", loc_en.getName());
5736 assertEquals(loc_en.getName(), tag_en, result_en.c_str());
5737
5738 std::string result_af = loc_af.toLanguageTag<std::string>(status);
5739 status.errIfFailureAndReset("\"%s\"", loc_af.getName());
5740 assertEquals(loc_af.getName(), tag_af, result_af.c_str());
5741
5742 std::string result_ext = loc_ext.toLanguageTag<std::string>(status);
5743 status.errIfFailureAndReset("\"%s\"", loc_ext.getName());
5744 assertEquals(loc_ext.getName(), tag_ext, result_ext.c_str());
5745
5746 std::string result_empty = loc_empty.toLanguageTag<std::string>(status);
5747 status.errIfFailureAndReset("\"%s\"", loc_empty.getName());
5748 assertEquals(loc_empty.getName(), tag_und, result_empty.c_str());
5749
5750 std::string result_ill = loc_ill.toLanguageTag<std::string>(status);
5751 status.errIfFailureAndReset("\"%s\"", loc_ill.getName());
5752 assertEquals(loc_ill.getName(), tag_und, result_ill.c_str());
5753
5754 std::string result_variant = loc_variant.toLanguageTag<std::string>(status);
5755 status.errIfFailureAndReset("\"%s\"", loc_variant.getName());
5756 assertEquals(loc_variant.getName(), tag_variant, result_variant.c_str());
5757
5758 Locale loc_bogus;
5759 loc_bogus.setToBogus();
5760 std::string result_bogus = loc_bogus.toLanguageTag<std::string>(status);
5761 assertEquals("bogus", U_ILLEGAL_ARGUMENT_ERROR, status.reset());
5762 assertTrue(result_bogus.c_str(), result_bogus.empty());
5763
5764 static const struct {
5765 const char *localeID; /* input */
5766 const char *expectedID; /* expected toLanguageTag() result */
5767 } testCases[] = {
5768 /* ICU-21414 */
5769 {"und-x-abc-private", "und-x-abc-private"},
5770 {"und-x-private", "und-x-private"},
5771 {"und-u-ca-roc-x-private", "und-u-ca-roc-x-private"},
5772 {"und-US-x-private", "und-US-x-private"},
5773 {"und-Latn-x-private", "und-Latn-x-private"},
5774 {"und-1994-biske-rozaj", "und-1994-biske-rozaj"},
5775 {"und-1994-biske-rozaj-x-private", "und-1994-biske-rozaj-x-private"},
5776 };
5777 int32_t i;
5778 for (i=0; i < UPRV_LENGTHOF(testCases); i++) {
5779 UErrorCode status = U_ZERO_ERROR;
5780 std::string otag = testCases[i].localeID;
5781 std::string tag = Locale::forLanguageTag(otag.c_str(), status).toLanguageTag<std::string>(status);
5782 if (tag != testCases[i].expectedID) {
5783 errcheckln(status, "FAIL: %s should be toLanguageTag to %s but got %s - %s",
5784 otag.c_str(),
5785 testCases[i].expectedID,
5786 tag.c_str(),
5787 u_errorName(status));
5788 }
5789 }
5790 }
5791
5792 /* ICU-20310 */
TestToLanguageTagOmitTrue()5793 void LocaleTest::TestToLanguageTagOmitTrue() {
5794 IcuTestErrorCode status(*this, "TestToLanguageTagOmitTrue()");
5795 assertEquals("en-u-kn should drop true",
5796 "en-u-kn", Locale("en-u-kn-true").toLanguageTag<std::string>(status).c_str());
5797 status.errIfFailureAndReset();
5798 assertEquals("en-u-kn should drop true",
5799 "en-u-kn", Locale("en-u-kn").toLanguageTag<std::string>(status).c_str());
5800 status.errIfFailureAndReset();
5801
5802 assertEquals("de-u-co should drop true",
5803 "de-u-co", Locale("de-u-co").toLanguageTag<std::string>(status).c_str());
5804 status.errIfFailureAndReset();
5805 assertEquals("de-u-co should drop true",
5806 "de-u-co", Locale("de-u-co-yes").toLanguageTag<std::string>(status).c_str());
5807 status.errIfFailureAndReset();
5808 assertEquals("de@collation=yes should drop true",
5809 "de-u-co", Locale("de@collation=yes").toLanguageTag<std::string>(status).c_str());
5810 status.errIfFailureAndReset();
5811
5812 assertEquals("cmn-Hans-CN-t-ca-u-ca-x-t-u should drop true",
5813 "cmn-Hans-CN-t-ca-u-ca-x-t-u",
5814 Locale("cmn-hans-cn-u-ca-t-ca-x-t-u").toLanguageTag<std::string>(status).c_str());
5815 status.errIfFailureAndReset();
5816 }
5817
TestMoveAssign()5818 void LocaleTest::TestMoveAssign() {
5819 // ULOC_FULLNAME_CAPACITY == 157 (uloc.h)
5820 Locale l1("de@collation=phonebook;x="
5821 "aaaaabbbbbcccccdddddeeeeefffffggggghhhhh"
5822 "aaaaabbbbbcccccdddddeeeeefffffggggghhhhh"
5823 "aaaaabbbbbcccccdddddeeeeefffffggggghhhhh"
5824 "aaaaabbbbbzz");
5825
5826 Locale l2;
5827 {
5828 Locale l3(l1);
5829 assertTrue("l1 == l3", l1 == l3);
5830 l2 = std::move(l3);
5831 assertTrue("l1 == l2", l1 == l2);
5832 assertTrue("l2 != l3", l2.getName() != l3.getName());
5833 }
5834
5835 // This should remain true also after l3 has been destructed.
5836 assertTrue("l1 == l2, again", l1 == l2);
5837
5838 Locale l4("de@collation=phonebook");
5839
5840 Locale l5;
5841 {
5842 Locale l6(l4);
5843 assertTrue("l4 == l6", l4 == l6);
5844 l5 = std::move(l6);
5845 assertTrue("l4 == l5", l4 == l5);
5846 assertTrue("l5 != l6", l5.getName() != l6.getName());
5847 }
5848
5849 // This should remain true also after l6 has been destructed.
5850 assertTrue("l4 == l5, again", l4 == l5);
5851
5852 Locale l7("vo_Cyrl_AQ_EURO");
5853
5854 Locale l8;
5855 {
5856 Locale l9(l7);
5857 assertTrue("l7 == l9", l7 == l9);
5858 l8 = std::move(l9);
5859 assertTrue("l7 == l8", l7 == l8);
5860 assertTrue("l8 != l9", l8.getName() != l9.getName());
5861 }
5862
5863 // This should remain true also after l9 has been destructed.
5864 assertTrue("l7 == l8, again", l7 == l8);
5865
5866 assertEquals("language", l7.getLanguage(), l8.getLanguage());
5867 assertEquals("script", l7.getScript(), l8.getScript());
5868 assertEquals("country", l7.getCountry(), l8.getCountry());
5869 assertEquals("variant", l7.getVariant(), l8.getVariant());
5870 assertEquals("bogus", l7.isBogus(), l8.isBogus());
5871 }
5872
TestMoveCtor()5873 void LocaleTest::TestMoveCtor() {
5874 // ULOC_FULLNAME_CAPACITY == 157 (uloc.h)
5875 Locale l1("de@collation=phonebook;x="
5876 "aaaaabbbbbcccccdddddeeeeefffffggggghhhhh"
5877 "aaaaabbbbbcccccdddddeeeeefffffggggghhhhh"
5878 "aaaaabbbbbcccccdddddeeeeefffffggggghhhhh"
5879 "aaaaabbbbbzz");
5880
5881 Locale l3(l1);
5882 assertTrue("l1 == l3", l1 == l3);
5883 Locale l2(std::move(l3));
5884 assertTrue("l1 == l2", l1 == l2);
5885 assertTrue("l2 != l3", l2.getName() != l3.getName());
5886
5887 Locale l4("de@collation=phonebook");
5888
5889 Locale l6(l4);
5890 assertTrue("l4 == l6", l4 == l6);
5891 Locale l5(std::move(l6));
5892 assertTrue("l4 == l5", l4 == l5);
5893 assertTrue("l5 != l6", l5.getName() != l6.getName());
5894
5895 Locale l7("vo_Cyrl_AQ_EURO");
5896
5897 Locale l9(l7);
5898 assertTrue("l7 == l9", l7 == l9);
5899 Locale l8(std::move(l9));
5900 assertTrue("l7 == l8", l7 == l8);
5901 assertTrue("l8 != l9", l8.getName() != l9.getName());
5902
5903 assertEquals("language", l7.getLanguage(), l8.getLanguage());
5904 assertEquals("script", l7.getScript(), l8.getScript());
5905 assertEquals("country", l7.getCountry(), l8.getCountry());
5906 assertEquals("variant", l7.getVariant(), l8.getVariant());
5907 assertEquals("bogus", l7.isBogus(), l8.isBogus());
5908 }
5909
TestBug20407iVariantPreferredValue()5910 void LocaleTest::TestBug20407iVariantPreferredValue() {
5911 IcuTestErrorCode status(*this, "TestBug20407iVariantPreferredValue()");
5912
5913 Locale l = Locale::forLanguageTag("hy-arevela", status);
5914 status.errIfFailureAndReset("hy-arevela fail");
5915 assertTrue("!l.isBogus()", !l.isBogus());
5916
5917 std::string result = l.toLanguageTag<std::string>(status);
5918 assertEquals(l.getName(), "hy", result.c_str());
5919
5920 l = Locale::forLanguageTag("hy-arevmda", status);
5921 status.errIfFailureAndReset("hy-arevmda");
5922 assertTrue("!l.isBogus()", !l.isBogus());
5923
5924 result = l.toLanguageTag<std::string>(status);
5925 assertEquals(l.getName(), "hyw", result.c_str());
5926 }
5927
TestBug13417VeryLongLanguageTag()5928 void LocaleTest::TestBug13417VeryLongLanguageTag() {
5929 IcuTestErrorCode status(*this, "TestBug13417VeryLongLanguageTag()");
5930
5931 static const char tag[] =
5932 "zh-x"
5933 "-foo-bar-baz-foo-bar-baz-foo-bar-baz-foo-bar-baz"
5934 "-foo-bar-baz-foo-bar-baz-foo-bar-baz-foo-bar-baz"
5935 "-foo-bar-baz-foo-bar-baz-foo-bar-baz-foo-bar-baz"
5936 "-foo-bar-baz-fxx"
5937 ;
5938
5939 Locale l = Locale::forLanguageTag(tag, status);
5940 status.errIfFailureAndReset("\"%s\"", tag);
5941 assertTrue("!l.isBogus()", !l.isBogus());
5942
5943 std::string result = l.toLanguageTag<std::string>(status);
5944 status.errIfFailureAndReset("\"%s\"", l.getName());
5945 assertEquals("equals", tag, result.c_str());
5946 }
5947
TestBug11053UnderlineTimeZone()5948 void LocaleTest::TestBug11053UnderlineTimeZone() {
5949 static const char* const tz_in_ext[] = {
5950 "etadd",
5951 "tzdar",
5952 "eheai",
5953 "sttms",
5954 "arirj",
5955 "arrgl",
5956 "aruaq",
5957 "arluq",
5958 "mxpvr",
5959 "brbvb",
5960 "arbue",
5961 "caycb",
5962 "brcgr",
5963 "cayzs",
5964 "crsjo",
5965 "caydq",
5966 "svsal",
5967 "cafne",
5968 "caglb",
5969 "cagoo",
5970 "tcgdt",
5971 "ustel",
5972 "bolpb",
5973 "uslax",
5974 "sxphi",
5975 "mxmex",
5976 "usnyc",
5977 "usxul",
5978 "usndcnt",
5979 "usndnsl",
5980 "ttpos",
5981 "brpvh",
5982 "prsju",
5983 "clpuq",
5984 "caffs",
5985 "cayek",
5986 "brrbr",
5987 "mxstis",
5988 "dosdq",
5989 "brsao",
5990 "gpsbh",
5991 "casjf",
5992 "knbas",
5993 "lccas",
5994 "vistt",
5995 "vcsvd",
5996 "cayyn",
5997 "cathu",
5998 "hkhkg",
5999 "mykul",
6000 "khpnh",
6001 "cvrai",
6002 "gsgrv",
6003 "shshn",
6004 "aubhq",
6005 "auldh",
6006 "imdgs",
6007 "smsai",
6008 "asppg",
6009 "pgpom",
6010 };
6011 static const char* const tzname_with_underline[] = {
6012 "America/Buenos_Aires",
6013 "America/Coral_Harbour",
6014 "America/Los_Angeles",
6015 "America/Mexico_City",
6016 "America/New_York",
6017 "America/Rio_Branco",
6018 "America/Sao_Paulo",
6019 "America/St_Johns",
6020 "America/St_Thomas",
6021 "Australia/Broken_Hill",
6022 "Australia/Lord_Howe",
6023 "Pacific/Pago_Pago",
6024 };
6025 std::string locale_str;
6026 for (int32_t i = 0; i < UPRV_LENGTHOF(tz_in_ext); i++) {
6027 locale_str = "en-u-tz-";
6028 locale_str += tz_in_ext[i];
6029 Locale l(locale_str.c_str());
6030 assertTrue((locale_str + " !l.isBogus()").c_str(), !l.isBogus());
6031 }
6032 for (int32_t i = 0; i < UPRV_LENGTHOF(tzname_with_underline); i++) {
6033 locale_str = "en@timezone=";
6034 locale_str += tzname_with_underline[i];
6035 Locale l(locale_str.c_str());
6036 assertTrue((locale_str + " !l.isBogus()").c_str(), !l.isBogus());
6037 }
6038 locale_str = "en_US@timezone=America/Coral_Harbour";
6039 Locale l2(locale_str.c_str());
6040 assertTrue((locale_str + " !l2.isBogus()").c_str(), !l2.isBogus());
6041 locale_str = "en_Latn@timezone=America/New_York";
6042 Locale l3(locale_str.c_str());
6043 assertTrue((locale_str + " !l3.isBogus()").c_str(), !l3.isBogus());
6044 locale_str = "en_Latn_US@timezone=Australia/Broken_Hill";
6045 Locale l4(locale_str.c_str());
6046 assertTrue((locale_str + " !l4.isBogus()").c_str(), !l4.isBogus());
6047 locale_str = "en-u-tz-ciabj";
6048 Locale l5(locale_str.c_str());
6049 assertTrue((locale_str + " !l5.isBogus()").c_str(), !l5.isBogus());
6050 locale_str = "en-US-u-tz-asppg";
6051 Locale l6(locale_str.c_str());
6052 assertTrue((locale_str + " !l6.isBogus()").c_str(), !l6.isBogus());
6053 locale_str = "fil-Latn-u-tz-cvrai";
6054 Locale l7(locale_str.c_str());
6055 assertTrue((locale_str + " !l7.isBogus()").c_str(), !l7.isBogus());
6056 locale_str = "fil-Latn-PH-u-tz-gsgrv";
6057 Locale l8(locale_str.c_str());
6058 assertTrue((locale_str + " !l8.isBogus()").c_str(), !l8.isBogus());
6059 }
6060
TestUnd()6061 void LocaleTest::TestUnd() {
6062 IcuTestErrorCode status(*this, "TestUnd()");
6063
6064 static const char empty[] = "";
6065 static const char root[] = "root";
6066 static const char und[] = "und";
6067
6068 Locale empty_ctor(empty);
6069 Locale empty_tag = Locale::forLanguageTag(empty, status);
6070 status.errIfFailureAndReset("\"%s\"", empty);
6071
6072 Locale root_ctor(root);
6073 Locale root_tag = Locale::forLanguageTag(root, status);
6074 Locale root_build = LocaleBuilder().setLanguageTag(root).build(status);
6075 status.errIfFailureAndReset("\"%s\"", root);
6076
6077 Locale und_ctor(und);
6078 Locale und_tag = Locale::forLanguageTag(und, status);
6079 Locale und_build = LocaleBuilder().setLanguageTag(und).build(status);
6080 status.errIfFailureAndReset("\"%s\"", und);
6081
6082 assertEquals("getName()", empty, empty_ctor.getName());
6083 assertEquals("getName()", empty, root_ctor.getName());
6084 assertEquals("getName()", empty, und_ctor.getName());
6085
6086 assertEquals("getName()", empty, empty_tag.getName());
6087 assertEquals("getName()", empty, root_tag.getName());
6088 assertEquals("getName()", empty, und_tag.getName());
6089
6090 assertEquals("getName()", empty, root_build.getName());
6091 assertEquals("getName()", empty, und_build.getName());
6092
6093 assertEquals("toLanguageTag()", und, empty_ctor.toLanguageTag<std::string>(status).c_str());
6094 assertEquals("toLanguageTag()", und, root_ctor.toLanguageTag<std::string>(status).c_str());
6095 assertEquals("toLanguageTag()", und, und_ctor.toLanguageTag<std::string>(status).c_str());
6096 status.errIfFailureAndReset();
6097
6098 assertEquals("toLanguageTag()", und, empty_tag.toLanguageTag<std::string>(status).c_str());
6099 assertEquals("toLanguageTag()", und, root_tag.toLanguageTag<std::string>(status).c_str());
6100 assertEquals("toLanguageTag()", und, und_tag.toLanguageTag<std::string>(status).c_str());
6101 status.errIfFailureAndReset();
6102
6103 assertEquals("toLanguageTag()", und, root_build.toLanguageTag<std::string>(status).c_str());
6104 assertEquals("toLanguageTag()", und, und_build.toLanguageTag<std::string>(status).c_str());
6105 status.errIfFailureAndReset();
6106
6107 assertTrue("empty_ctor == empty_tag", empty_ctor == empty_tag);
6108
6109 assertTrue("root_ctor == root_tag", root_ctor == root_tag);
6110 assertTrue("root_ctor == root_build", root_ctor == root_build);
6111 assertTrue("root_tag == root_build", root_tag == root_build);
6112
6113 assertTrue("und_ctor == und_tag", und_ctor == und_tag);
6114 assertTrue("und_ctor == und_build", und_ctor == und_build);
6115 assertTrue("und_tag == und_build", und_tag == und_build);
6116
6117 assertTrue("empty_ctor == root_ctor", empty_ctor == root_ctor);
6118 assertTrue("empty_ctor == und_ctor", empty_ctor == und_ctor);
6119 assertTrue("root_ctor == und_ctor", root_ctor == und_ctor);
6120
6121 assertTrue("empty_tag == root_tag", empty_tag == root_tag);
6122 assertTrue("empty_tag == und_tag", empty_tag == und_tag);
6123 assertTrue("root_tag == und_tag", root_tag == und_tag);
6124
6125 assertTrue("root_build == und_build", root_build == und_build);
6126
6127 static const Locale& displayLocale = Locale::getEnglish();
6128 static const UnicodeString displayName("Unknown language");
6129 UnicodeString tmp;
6130
6131 assertEquals("getDisplayName()", displayName, empty_ctor.getDisplayName(displayLocale, tmp));
6132 assertEquals("getDisplayName()", displayName, root_ctor.getDisplayName(displayLocale, tmp));
6133 assertEquals("getDisplayName()", displayName, und_ctor.getDisplayName(displayLocale, tmp));
6134
6135 assertEquals("getDisplayName()", displayName, empty_tag.getDisplayName(displayLocale, tmp));
6136 assertEquals("getDisplayName()", displayName, root_tag.getDisplayName(displayLocale, tmp));
6137 assertEquals("getDisplayName()", displayName, und_tag.getDisplayName(displayLocale, tmp));
6138
6139 assertEquals("getDisplayName()", displayName, root_build.getDisplayName(displayLocale, tmp));
6140 assertEquals("getDisplayName()", displayName, und_build.getDisplayName(displayLocale, tmp));
6141 }
6142
TestUndScript()6143 void LocaleTest::TestUndScript() {
6144 IcuTestErrorCode status(*this, "TestUndScript()");
6145
6146 static const char id[] = "_Cyrl";
6147 static const char tag[] = "und-Cyrl";
6148 static const char script[] = "Cyrl";
6149
6150 Locale locale_ctor(id);
6151 Locale locale_legacy(tag);
6152 Locale locale_tag = Locale::forLanguageTag(tag, status);
6153 Locale locale_build = LocaleBuilder().setScript(script).build(status);
6154 status.errIfFailureAndReset("\"%s\"", tag);
6155
6156 assertEquals("getName()", id, locale_ctor.getName());
6157 assertEquals("getName()", id, locale_legacy.getName());
6158 assertEquals("getName()", id, locale_tag.getName());
6159 assertEquals("getName()", id, locale_build.getName());
6160
6161 assertEquals("toLanguageTag()", tag, locale_ctor.toLanguageTag<std::string>(status).c_str());
6162 assertEquals("toLanguageTag()", tag, locale_legacy.toLanguageTag<std::string>(status).c_str());
6163 assertEquals("toLanguageTag()", tag, locale_tag.toLanguageTag<std::string>(status).c_str());
6164 assertEquals("toLanguageTag()", tag, locale_build.toLanguageTag<std::string>(status).c_str());
6165 status.errIfFailureAndReset();
6166
6167 static const Locale& displayLocale = Locale::getEnglish();
6168 static const UnicodeString displayName("Unknown language (Cyrillic)");
6169 UnicodeString tmp;
6170
6171 assertEquals("getDisplayName()", displayName, locale_ctor.getDisplayName(displayLocale, tmp));
6172 assertEquals("getDisplayName()", displayName, locale_legacy.getDisplayName(displayLocale, tmp));
6173 assertEquals("getDisplayName()", displayName, locale_tag.getDisplayName(displayLocale, tmp));
6174 assertEquals("getDisplayName()", displayName, locale_build.getDisplayName(displayLocale, tmp));
6175 }
6176
TestUndRegion()6177 void LocaleTest::TestUndRegion() {
6178 IcuTestErrorCode status(*this, "TestUndRegion()");
6179
6180 static const char id[] = "_AQ";
6181 static const char tag[] = "und-AQ";
6182 static const char region[] = "AQ";
6183
6184 Locale locale_ctor(id);
6185 Locale locale_legacy(tag);
6186 Locale locale_tag = Locale::forLanguageTag(tag, status);
6187 Locale locale_build = LocaleBuilder().setRegion(region).build(status);
6188 status.errIfFailureAndReset("\"%s\"", tag);
6189
6190 assertEquals("getName()", id, locale_ctor.getName());
6191 assertEquals("getName()", id, locale_legacy.getName());
6192 assertEquals("getName()", id, locale_tag.getName());
6193 assertEquals("getName()", id, locale_build.getName());
6194
6195 assertEquals("toLanguageTag()", tag, locale_ctor.toLanguageTag<std::string>(status).c_str());
6196 assertEquals("toLanguageTag()", tag, locale_legacy.toLanguageTag<std::string>(status).c_str());
6197 assertEquals("toLanguageTag()", tag, locale_tag.toLanguageTag<std::string>(status).c_str());
6198 assertEquals("toLanguageTag()", tag, locale_build.toLanguageTag<std::string>(status).c_str());
6199 status.errIfFailureAndReset();
6200
6201 static const Locale& displayLocale = Locale::getEnglish();
6202 static const UnicodeString displayName("Unknown language (Antarctica)");
6203 UnicodeString tmp;
6204
6205 assertEquals("getDisplayName()", displayName, locale_ctor.getDisplayName(displayLocale, tmp));
6206 assertEquals("getDisplayName()", displayName, locale_legacy.getDisplayName(displayLocale, tmp));
6207 assertEquals("getDisplayName()", displayName, locale_tag.getDisplayName(displayLocale, tmp));
6208 assertEquals("getDisplayName()", displayName, locale_build.getDisplayName(displayLocale, tmp));
6209 }
6210
TestUndCAPI()6211 void LocaleTest::TestUndCAPI() {
6212 IcuTestErrorCode status(*this, "TestUndCAPI()");
6213
6214 static const char empty[] = "";
6215 static const char root[] = "root";
6216 static const char und[] = "und";
6217
6218 static const char empty_script[] = "_Cyrl";
6219 static const char empty_region[] = "_AQ";
6220
6221 static const char und_script[] = "und_Cyrl";
6222 static const char und_region[] = "und_AQ";
6223
6224 char tmp[ULOC_FULLNAME_CAPACITY];
6225 int32_t reslen;
6226
6227 // uloc_getName()
6228
6229 uprv_memset(tmp, '!', sizeof tmp);
6230 reslen = uloc_getName(empty, tmp, sizeof tmp, status);
6231 status.errIfFailureAndReset("\"%s\"", empty);
6232 assertTrue("reslen >= 0", reslen >= 0);
6233 assertEquals("uloc_getName()", empty, tmp);
6234
6235 uprv_memset(tmp, '!', sizeof tmp);
6236 reslen = uloc_getName(root, tmp, sizeof tmp, status);
6237 status.errIfFailureAndReset("\"%s\"", root);
6238 assertTrue("reslen >= 0", reslen >= 0);
6239 assertEquals("uloc_getName()", empty, tmp);
6240
6241 uprv_memset(tmp, '!', sizeof tmp);
6242 reslen = uloc_getName(und, tmp, sizeof tmp, status);
6243 status.errIfFailureAndReset("\"%s\"", und);
6244 assertTrue("reslen >= 0", reslen >= 0);
6245 assertEquals("uloc_getName()", empty, tmp);
6246
6247 uprv_memset(tmp, '!', sizeof tmp);
6248 reslen = uloc_getName(empty_script, tmp, sizeof tmp, status);
6249 status.errIfFailureAndReset("\"%s\"", empty_script);
6250 assertTrue("reslen >= 0", reslen >= 0);
6251 assertEquals("uloc_getName()", empty_script, tmp);
6252
6253 uprv_memset(tmp, '!', sizeof tmp);
6254 reslen = uloc_getName(empty_region, tmp, sizeof tmp, status);
6255 status.errIfFailureAndReset("\"%s\"", empty_region);
6256 assertTrue("reslen >= 0", reslen >= 0);
6257 assertEquals("uloc_getName()", empty_region, tmp);
6258
6259 uprv_memset(tmp, '!', sizeof tmp);
6260 reslen = uloc_getName(und_script, tmp, sizeof tmp, status);
6261 status.errIfFailureAndReset("\"%s\"", und_script);
6262 assertTrue("reslen >= 0", reslen >= 0);
6263 assertEquals("uloc_getName()", empty_script, tmp);
6264
6265 uprv_memset(tmp, '!', sizeof tmp);
6266 reslen = uloc_getName(und_region, tmp, sizeof tmp, status);
6267 status.errIfFailureAndReset("\"%s\"", und_region);
6268 assertTrue("reslen >= 0", reslen >= 0);
6269 assertEquals("uloc_getName()", empty_region, tmp);
6270
6271 // uloc_getBaseName()
6272
6273 uprv_memset(tmp, '!', sizeof tmp);
6274 reslen = uloc_getBaseName(empty, tmp, sizeof tmp, status);
6275 status.errIfFailureAndReset("\"%s\"", empty);
6276 assertTrue("reslen >= 0", reslen >= 0);
6277 assertEquals("uloc_getBaseName()", empty, tmp);
6278
6279 uprv_memset(tmp, '!', sizeof tmp);
6280 reslen = uloc_getBaseName(root, tmp, sizeof tmp, status);
6281 status.errIfFailureAndReset("\"%s\"", root);
6282 assertTrue("reslen >= 0", reslen >= 0);
6283 assertEquals("uloc_getBaseName()", empty, tmp);
6284
6285 uprv_memset(tmp, '!', sizeof tmp);
6286 reslen = uloc_getBaseName(und, tmp, sizeof tmp, status);
6287 status.errIfFailureAndReset("\"%s\"", und);
6288 assertTrue("reslen >= 0", reslen >= 0);
6289 assertEquals("uloc_getBaseName()", empty, tmp);
6290
6291 uprv_memset(tmp, '!', sizeof tmp);
6292 reslen = uloc_getBaseName(empty_script, tmp, sizeof tmp, status);
6293 status.errIfFailureAndReset("\"%s\"", empty_script);
6294 assertTrue("reslen >= 0", reslen >= 0);
6295 assertEquals("uloc_getBaseName()", empty_script, tmp);
6296
6297 uprv_memset(tmp, '!', sizeof tmp);
6298 reslen = uloc_getBaseName(empty_region, tmp, sizeof tmp, status);
6299 status.errIfFailureAndReset("\"%s\"", empty_region);
6300 assertTrue("reslen >= 0", reslen >= 0);
6301 assertEquals("uloc_getBaseName()", empty_region, tmp);
6302
6303 uprv_memset(tmp, '!', sizeof tmp);
6304 reslen = uloc_getBaseName(und_script, tmp, sizeof tmp, status);
6305 status.errIfFailureAndReset("\"%s\"", und_script);
6306 assertTrue("reslen >= 0", reslen >= 0);
6307 assertEquals("uloc_getBaseName()", empty_script, tmp);
6308
6309 uprv_memset(tmp, '!', sizeof tmp);
6310 reslen = uloc_getBaseName(und_region, tmp, sizeof tmp, status);
6311 status.errIfFailureAndReset("\"%s\"", und_region);
6312 assertTrue("reslen >= 0", reslen >= 0);
6313 assertEquals("uloc_getBaseName()", empty_region, tmp);
6314
6315 // uloc_getParent()
6316
6317 uprv_memset(tmp, '!', sizeof tmp);
6318 reslen = uloc_getParent(empty, tmp, sizeof tmp, status);
6319 status.errIfFailureAndReset("\"%s\"", empty);
6320 assertTrue("reslen >= 0", reslen >= 0);
6321 assertEquals("uloc_getParent()", empty, tmp);
6322
6323 uprv_memset(tmp, '!', sizeof tmp);
6324 reslen = uloc_getParent(root, tmp, sizeof tmp, status);
6325 status.errIfFailureAndReset("\"%s\"", root);
6326 assertTrue("reslen >= 0", reslen >= 0);
6327 assertEquals("uloc_getParent()", empty, tmp);
6328
6329 uprv_memset(tmp, '!', sizeof tmp);
6330 reslen = uloc_getParent(und, tmp, sizeof tmp, status);
6331 status.errIfFailureAndReset("\"%s\"", und);
6332 assertTrue("reslen >= 0", reslen >= 0);
6333 assertEquals("uloc_getParent()", empty, tmp);
6334
6335 uprv_memset(tmp, '!', sizeof tmp);
6336 reslen = uloc_getParent(empty_script, tmp, sizeof tmp, status);
6337 status.errIfFailureAndReset("\"%s\"", empty_script);
6338 assertTrue("reslen >= 0", reslen >= 0);
6339 assertEquals("uloc_getParent()", empty, tmp);
6340
6341 uprv_memset(tmp, '!', sizeof tmp);
6342 reslen = uloc_getParent(empty_region, tmp, sizeof tmp, status);
6343 status.errIfFailureAndReset("\"%s\"", empty_region);
6344 assertTrue("reslen >= 0", reslen >= 0);
6345 assertEquals("uloc_getParent()", empty, tmp);
6346
6347 uprv_memset(tmp, '!', sizeof tmp);
6348 reslen = uloc_getParent(und_script, tmp, sizeof tmp, status);
6349 status.errIfFailureAndReset("\"%s\"", und_script);
6350 assertTrue("reslen >= 0", reslen >= 0);
6351 assertEquals("uloc_getParent()", empty, tmp);
6352
6353 uprv_memset(tmp, '!', sizeof tmp);
6354 reslen = uloc_getParent(und_region, tmp, sizeof tmp, status);
6355 status.errIfFailureAndReset("\"%s\"", und_region);
6356 assertTrue("reslen >= 0", reslen >= 0);
6357 assertEquals("uloc_getParent()", empty, tmp);
6358
6359 // uloc_getLanguage()
6360
6361 uprv_memset(tmp, '!', sizeof tmp);
6362 reslen = uloc_getLanguage(empty, tmp, sizeof tmp, status);
6363 status.errIfFailureAndReset("\"%s\"", empty);
6364 assertTrue("reslen >= 0", reslen >= 0);
6365 assertEquals("uloc_getLanguage()", empty, tmp);
6366
6367 uprv_memset(tmp, '!', sizeof tmp);
6368 reslen = uloc_getLanguage(root, tmp, sizeof tmp, status);
6369 status.errIfFailureAndReset("\"%s\"", root);
6370 assertTrue("reslen >= 0", reslen >= 0);
6371 assertEquals("uloc_getLanguage()", empty, tmp);
6372
6373 uprv_memset(tmp, '!', sizeof tmp);
6374 reslen = uloc_getLanguage(und, tmp, sizeof tmp, status);
6375 status.errIfFailureAndReset("\"%s\"", und);
6376 assertTrue("reslen >= 0", reslen >= 0);
6377 assertEquals("uloc_getLanguage()", empty, tmp);
6378
6379 uprv_memset(tmp, '!', sizeof tmp);
6380 reslen = uloc_getLanguage(empty_script, tmp, sizeof tmp, status);
6381 status.errIfFailureAndReset("\"%s\"", empty_script);
6382 assertTrue("reslen >= 0", reslen >= 0);
6383 assertEquals("uloc_getLanguage()", empty, tmp);
6384
6385 uprv_memset(tmp, '!', sizeof tmp);
6386 reslen = uloc_getLanguage(empty_region, tmp, sizeof tmp, status);
6387 status.errIfFailureAndReset("\"%s\"", empty_region);
6388 assertTrue("reslen >= 0", reslen >= 0);
6389 assertEquals("uloc_getLanguage()", empty, tmp);
6390
6391 uprv_memset(tmp, '!', sizeof tmp);
6392 reslen = uloc_getLanguage(und_script, tmp, sizeof tmp, status);
6393 status.errIfFailureAndReset("\"%s\"", und_script);
6394 assertTrue("reslen >= 0", reslen >= 0);
6395 assertEquals("uloc_getLanguage()", empty, tmp);
6396
6397 uprv_memset(tmp, '!', sizeof tmp);
6398 reslen = uloc_getLanguage(und_region, tmp, sizeof tmp, status);
6399 status.errIfFailureAndReset("\"%s\"", und_region);
6400 assertTrue("reslen >= 0", reslen >= 0);
6401 assertEquals("uloc_getLanguage()", empty, tmp);
6402 }
6403
6404 #define ARRAY_RANGE(array) (array), ((array) + UPRV_LENGTHOF(array))
6405
TestRangeIterator()6406 void LocaleTest::TestRangeIterator() {
6407 IcuTestErrorCode status(*this, "TestRangeIterator");
6408 Locale locales[] = { "fr", "en_GB", "en" };
6409 Locale::RangeIterator<Locale *> iter(ARRAY_RANGE(locales));
6410
6411 assertTrue("0.hasNext()", iter.hasNext());
6412 const Locale &l0 = iter.next();
6413 assertEquals("0.next()", "fr", l0.getName());
6414 assertTrue("&0.next()", &l0 == &locales[0]);
6415
6416 assertTrue("1.hasNext()", iter.hasNext());
6417 const Locale &l1 = iter.next();
6418 assertEquals("1.next()", "en_GB", l1.getName());
6419 assertTrue("&1.next()", &l1 == &locales[1]);
6420
6421 assertTrue("2.hasNext()", iter.hasNext());
6422 const Locale &l2 = iter.next();
6423 assertEquals("2.next()", "en", l2.getName());
6424 assertTrue("&2.next()", &l2 == &locales[2]);
6425
6426 assertFalse("3.hasNext()", iter.hasNext());
6427 }
6428
TestPointerConvertingIterator()6429 void LocaleTest::TestPointerConvertingIterator() {
6430 IcuTestErrorCode status(*this, "TestPointerConvertingIterator");
6431 Locale locales[] = { "fr", "en_GB", "en" };
6432 Locale *pointers[] = { locales, locales + 1, locales + 2 };
6433 // Lambda with explicit reference return type to prevent copy-constructing a temporary
6434 // which would be destructed right away.
6435 Locale::ConvertingIterator<Locale **, std::function<const Locale &(const Locale *)>> iter(
6436 ARRAY_RANGE(pointers), [](const Locale *p) -> const Locale & { return *p; });
6437
6438 assertTrue("0.hasNext()", iter.hasNext());
6439 const Locale &l0 = iter.next();
6440 assertEquals("0.next()", "fr", l0.getName());
6441 assertTrue("&0.next()", &l0 == pointers[0]);
6442
6443 assertTrue("1.hasNext()", iter.hasNext());
6444 const Locale &l1 = iter.next();
6445 assertEquals("1.next()", "en_GB", l1.getName());
6446 assertTrue("&1.next()", &l1 == pointers[1]);
6447
6448 assertTrue("2.hasNext()", iter.hasNext());
6449 const Locale &l2 = iter.next();
6450 assertEquals("2.next()", "en", l2.getName());
6451 assertTrue("&2.next()", &l2 == pointers[2]);
6452
6453 assertFalse("3.hasNext()", iter.hasNext());
6454 }
6455
6456 namespace {
6457
6458 class LocaleFromTag {
6459 public:
LocaleFromTag()6460 LocaleFromTag() : locale(Locale::getRoot()) {}
operator ()(const char * tag)6461 const Locale &operator()(const char *tag) { return locale = Locale(tag); }
6462
6463 private:
6464 // Store the locale in the converter, rather than return a reference to a temporary,
6465 // or a value which could go out of scope with the caller's reference to it.
6466 Locale locale;
6467 };
6468
6469 } // namespace
6470
TestTagConvertingIterator()6471 void LocaleTest::TestTagConvertingIterator() {
6472 IcuTestErrorCode status(*this, "TestTagConvertingIterator");
6473 const char *tags[] = { "fr", "en_GB", "en" };
6474 LocaleFromTag converter;
6475 Locale::ConvertingIterator<const char **, LocaleFromTag> iter(ARRAY_RANGE(tags), converter);
6476
6477 assertTrue("0.hasNext()", iter.hasNext());
6478 const Locale &l0 = iter.next();
6479 assertEquals("0.next()", "fr", l0.getName());
6480
6481 assertTrue("1.hasNext()", iter.hasNext());
6482 const Locale &l1 = iter.next();
6483 assertEquals("1.next()", "en_GB", l1.getName());
6484
6485 assertTrue("2.hasNext()", iter.hasNext());
6486 const Locale &l2 = iter.next();
6487 assertEquals("2.next()", "en", l2.getName());
6488
6489 assertFalse("3.hasNext()", iter.hasNext());
6490 }
6491
TestCapturingTagConvertingIterator()6492 void LocaleTest::TestCapturingTagConvertingIterator() {
6493 IcuTestErrorCode status(*this, "TestCapturingTagConvertingIterator");
6494 const char *tags[] = { "fr", "en_GB", "en" };
6495 // Store the converted locale in a locale variable,
6496 // rather than return a reference to a temporary,
6497 // or a value which could go out of scope with the caller's reference to it.
6498 Locale locale;
6499 // Lambda with explicit reference return type to prevent copy-constructing a temporary
6500 // which would be destructed right away.
6501 Locale::ConvertingIterator<const char **, std::function<const Locale &(const char *)>> iter(
6502 ARRAY_RANGE(tags), [&](const char *tag) -> const Locale & { return locale = Locale(tag); });
6503
6504 assertTrue("0.hasNext()", iter.hasNext());
6505 const Locale &l0 = iter.next();
6506 assertEquals("0.next()", "fr", l0.getName());
6507
6508 assertTrue("1.hasNext()", iter.hasNext());
6509 const Locale &l1 = iter.next();
6510 assertEquals("1.next()", "en_GB", l1.getName());
6511
6512 assertTrue("2.hasNext()", iter.hasNext());
6513 const Locale &l2 = iter.next();
6514 assertEquals("2.next()", "en", l2.getName());
6515
6516 assertFalse("3.hasNext()", iter.hasNext());
6517 }
6518
TestSetUnicodeKeywordValueInLongLocale()6519 void LocaleTest::TestSetUnicodeKeywordValueInLongLocale() {
6520 IcuTestErrorCode status(*this, "TestSetUnicodeKeywordValueInLongLocale");
6521 const char* value = "efghijkl";
6522 icu::Locale l("de");
6523 char keyword[3];
6524 CharString expected("de-u", status);
6525 keyword[2] = '\0';
6526 for (char i = 'a'; i < 's'; i++) {
6527 keyword[0] = keyword[1] = i;
6528 expected.append("-", status);
6529 expected.append(keyword, status);
6530 expected.append("-", status);
6531 expected.append(value, status);
6532 l.setUnicodeKeywordValue(keyword, value, status);
6533 if (status.errIfFailureAndReset(
6534 "setUnicodeKeywordValue(\"%s\", \"%s\") fail while locale is \"%s\"",
6535 keyword, value, l.getName())) {
6536 return;
6537 }
6538 std::string tag = l.toLanguageTag<std::string>(status);
6539 if (status.errIfFailureAndReset(
6540 "toLanguageTag fail on \"%s\"", l.getName())) {
6541 return;
6542 }
6543 if (tag != expected.data()) {
6544 errln("Expected to get \"%s\" bug got \"%s\"", tag.c_str(),
6545 expected.data());
6546 return;
6547 }
6548 }
6549 }
6550
TestLongLocaleSetKeywordAssign()6551 void LocaleTest::TestLongLocaleSetKeywordAssign() {
6552 IcuTestErrorCode status(*this, "TestLongLocaleSetKeywordAssign");
6553 // A long base name, with an illegal keyword and copy constructor
6554 icu::Locale l("de_AAAAAAA1_AAAAAAA2_AAAAAAA3_AAAAAAA4_AAAAAAA5_AAAAAAA6_"
6555 "AAAAAAA7_AAAAAAA8_AAAAAAA9_AAAAAA10_AAAAAA11_AAAAAA12_"
6556 "AAAAAA13_AAAAAA14_AAAAAA15_AAAAAA16_AAAAAA17_AAAAAA18");
6557 Locale l2;
6558 l.setUnicodeKeywordValue("co", "12", status); // Cause an error
6559 status.reset();
6560 l2 = l; // copy operator on such bogus locale.
6561 }
6562
TestLongLocaleSetKeywordMoveAssign()6563 void LocaleTest::TestLongLocaleSetKeywordMoveAssign() {
6564 IcuTestErrorCode status(*this, "TestLongLocaleSetKeywordMoveAssign");
6565 // A long base name, with an illegal keyword and copy constructor
6566 icu::Locale l("de_AAAAAAA1_AAAAAAA2_AAAAAAA3_AAAAAAA4_AAAAAAA5_AAAAAAA6_"
6567 "AAAAAAA7_AAAAAAA8_AAAAAAA9_AAAAAA10_AAAAAA11_AAAAAA12_"
6568 "AAAAAA13_AAAAAA14_AAAAAA15_AAAAAA16_AAAAAA17");
6569 Locale l2;
6570 l.setUnicodeKeywordValue("co", "12", status); // Cause an error
6571 status.reset();
6572 Locale l3 = std::move(l); // move assign
6573 }
6574
TestSetUnicodeKeywordValueNullInLongLocale()6575 void LocaleTest::TestSetUnicodeKeywordValueNullInLongLocale() {
6576 IcuTestErrorCode status(*this, "TestSetUnicodeKeywordValueNullInLongLocale");
6577 const char *exts[] = {"cf", "cu", "em", "kk", "kr", "ks", "kv", "lb", "lw",
6578 "ms", "nu", "rg", "sd", "ss", "tz"};
6579 for (int32_t i = 0; i < UPRV_LENGTHOF(exts); i++) {
6580 CharString tag("de-u", status);
6581 for (int32_t j = 0; j <= i; j++) {
6582 tag.append("-", status).append(exts[j], status);
6583 }
6584 if (status.errIfFailureAndReset(
6585 "Cannot create tag \"%s\"", tag.data())) {
6586 continue;
6587 }
6588 Locale l = Locale::forLanguageTag(tag.data(), status);
6589 if (status.errIfFailureAndReset(
6590 "Locale::forLanguageTag(\"%s\") failed", tag.data())) {
6591 continue;
6592 }
6593 for (int32_t j = 0; j <= i; j++) {
6594 l.setUnicodeKeywordValue(exts[j], nullptr, status);
6595 if (status.errIfFailureAndReset(
6596 "Locale(\"%s\").setUnicodeKeywordValue(\"%s\", nullptr) failed",
6597 tag.data(), exts[j])) {
6598 continue;
6599 }
6600 }
6601 if (strcmp("de", l.getName()) != 0) {
6602 errln("setUnicodeKeywordValue should remove all extensions from "
6603 "\"%s\" and only have \"de\", but is \"%s\" instead.",
6604 tag.data(), l.getName());
6605 }
6606 }
6607 }
6608
TestLeak21419()6609 void LocaleTest::TestLeak21419() {
6610 IcuTestErrorCode status(*this, "TestLeak21419");
6611 Locale l = Locale("s-yU");
6612 l.canonicalize(status);
6613 status.expectErrorAndReset(U_ILLEGAL_ARGUMENT_ERROR);
6614 }
6615
TestNullDereferenceWrite21597()6616 void LocaleTest::TestNullDereferenceWrite21597() {
6617 IcuTestErrorCode status(*this, "TestNullDereferenceWrite21597");
6618 Locale l = Locale("zu-t-q5-X1-vKf-KK-Ks-cO--Kc");
6619 l.canonicalize(status);
6620 status.expectErrorAndReset(U_ILLEGAL_ARGUMENT_ERROR);
6621 }
6622 #if !UCONFIG_NO_FORMATTING
TestSierraLeoneCurrency21997()6623 void LocaleTest::TestSierraLeoneCurrency21997() {
6624 // CLDR 41: Check that currency of Sierra Leone is SLL (which is legal tender)
6625 // and not the newer currency SLE (which is not legal tender), as of CLDR 41.
6626 // Test will fail once SLE is declared legal.
6627 // CLDR 42: Now check that currency of Sierra Leone is SLE (which is legal tender)
6628 UnicodeString sllStr("SLE", ""), resultStr;
6629 char16_t tmp[4];
6630 UErrorCode status = U_ZERO_ERROR;
6631
6632 ucurr_forLocale("en_SL", tmp, 4, &status);
6633 resultStr.setTo(tmp);
6634 if (sllStr != resultStr) {
6635 errcheckln(status, "Fail: en_SL didn't return SLE - %s", u_errorName(status));
6636 }
6637 }
6638 #endif
6639