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