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