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