• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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