• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /********************************************************************
4  * COPYRIGHT:
5  * Copyright (c) 1997-2016, International Business Machines Corporation and
6  * others. All Rights Reserved.
7  ********************************************************************/
8 
9 #include <algorithm>
10 #include <functional>
11 #include <iterator>
12 #include <set>
13 #include <utility>
14 
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 
36 static const char* const rawData[33][8] = {
37 
38         // language code
39         {   "en",   "fr",   "ca",   "el",   "no",   "it",   "xx",   "zh"  },
40         // script code
41         {   "",     "",     "",     "",     "",     "",     "",     "Hans" },
42         // country code
43         {   "US",   "FR",   "ES",   "GR",   "NO",   "",     "YY",   "CN"  },
44         // variant code
45         {   "",     "",     "",     "",     "NY",   "",     "",   ""    },
46         // full name
47         {   "en_US",    "fr_FR",    "ca_ES",    "el_GR",    "no_NO_NY", "it",   "xx_YY",   "zh_Hans_CN" },
48         // ISO-3 language
49         {   "eng",  "fra",  "cat",  "ell",  "nor",  "ita",  "",   "zho"   },
50         // ISO-3 country
51         {   "USA",  "FRA",  "ESP",  "GRC",  "NOR",  "",     "",   "CHN"   },
52         // LCID
53         {   "409", "40c", "403", "408", "814", "10",     "0",   "804"  },
54 
55         // display language (English)
56         {   "English",  "French",   "Catalan", "Greek",    "Norwegian",    "Italian",  "xx",   "Chinese" },
57         // display script (English)
58         {   "",     "",     "",     "",     "",   "",     "",   "Simplified Han" },
59         // display country (English)
60         {   "United States",    "France",   "Spain",  "Greece",   "Norway",   "",     "YY",   "China" },
61         // display variant (English)
62         {   "",     "",     "",     "",     "NY",   "",     "",   ""},
63         // display name (English)
64         // Updated no_NO_NY English display name for new pattern-based algorithm
65         // (part of Euro support).
66         {   "English (United States)", "French (France)", "Catalan (Spain)", "Greek (Greece)", "Norwegian (Norway, NY)", "Italian", "xx (YY)", "Chinese (Simplified, China)" },
67 
68         // display language (French)
69         {   "anglais",  "fran\\u00E7ais",   "catalan", "grec",    "norv\\u00E9gien",    "italien", "xx", "chinois" },
70         // display script (French)
71         {   "",     "",     "",     "",     "",     "",     "",   "sinogrammes simplifi\\u00E9s" },
72         // display country (French)
73         {   "\\u00C9tats-Unis",    "France",   "Espagne",  "Gr\\u00E8ce",   "Norv\\u00E8ge", "", "YY", "Chine" },
74         // display variant (French)
75         {   "",     "",     "",     "",     "NY",     "",     "",   "" },
76         // display name (French)
77         //{   "anglais (Etats-Unis)", "francais (France)", "catalan (Espagne)", "grec (Grece)", "norvegien (Norvege,Nynorsk)", "italien", "xx (YY)" },
78         {   "anglais (\\u00C9tats-Unis)", "fran\\u00E7ais (France)", "catalan (Espagne)", "grec (Gr\\u00E8ce)", "norv\\u00E9gien (Norv\\u00E8ge, NY)", "italien", "xx (YY)", "chinois (simplifi\\u00E9, Chine)" },
79 
80 
81         /* display language (Catalan) */
82         {   "angl\\u00E8s", "franc\\u00E8s", "catal\\u00E0", "grec",  "noruec", "itali\\u00E0", "", "xin\\u00E8s" },
83         /* display script (Catalan) */
84         {   "", "", "",                    "", "", "", "", "han simplificat" },
85         /* display country (Catalan) */
86         {   "Estats Units", "Fran\\u00E7a", "Espanya",  "Gr\\u00E8cia", "Noruega", "", "", "Xina" },
87         /* display variant (Catalan) */
88         {   "", "", "",                    "", "NY", "", "" },
89         /* display name (Catalan) */
90         {   "angl\\u00E8s (Estats Units)", "franc\\u00E8s (Fran\\u00E7a)", "catal\\u00E0 (Espanya)", "grec (Gr\\u00E8cia)", "noruec (Noruega, NY)", "itali\\u00E0", "", "xin\\u00E8s (simplificat, Xina)" },
91 
92         // display language (Greek)[actual values listed below]
93         {   "\\u0391\\u03b3\\u03b3\\u03bb\\u03b9\\u03ba\\u03ac",
94             "\\u0393\\u03b1\\u03bb\\u03bb\\u03b9\\u03ba\\u03ac",
95             "\\u039a\\u03b1\\u03c4\\u03b1\\u03bb\\u03b1\\u03bd\\u03b9\\u03ba\\u03ac",
96             "\\u0395\\u03bb\\u03bb\\u03b7\\u03bd\\u03b9\\u03ba\\u03ac",
97             "\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03b9\\u03ba\\u03ac",
98             "\\u0399\\u03c4\\u03b1\\u03bb\\u03b9\\u03ba\\u03ac",
99             "",
100             "\\u039A\\u03B9\\u03BD\\u03B5\\u03B6\\u03B9\\u03BA\\u03AC"
101         },
102         // display script (Greek)
103         {   "", "", "", "", "", "", "", "\\u0391\\u03c0\\u03bb\\u03bf\\u03c0\\u03bf\\u03b9\\u03b7\\u03bc\\u03ad\\u03bd\\u03bf \\u03a7\\u03b1\\u03bd" },
104         // display country (Greek)[actual values listed below]
105         {   "\\u0397\\u03BD\\u03C9\\u03BC\\u03AD\\u03BD\\u03B5\\u03C2 \\u03A0\\u03BF\\u03BB\\u03B9\\u03C4\\u03B5\\u03AF\\u03B5\\u03C2",
106             "\\u0393\\u03b1\\u03bb\\u03bb\\u03af\\u03b1",
107             "\\u0399\\u03c3\\u03c0\\u03b1\\u03bd\\u03af\\u03b1",
108             "\\u0395\\u03bb\\u03bb\\u03ac\\u03b4\\u03b1",
109             "\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03af\\u03b1",
110             "",
111             "",
112             "\\u039A\\u03AF\\u03BD\\u03B1"
113         },
114         // display variant (Greek)
115         {   "", "", "", "", "NY", "", "" },
116         // display name (Greek)[actual values listed below]
117         {   "\\u0391\\u03b3\\u03b3\\u03bb\\u03b9\\u03ba\\u03ac (\\u0397\\u03BD\\u03C9\\u03BC\\u03AD\\u03BD\\u03B5\\u03C2 \\u03A0\\u03BF\\u03BB\\u03B9\\u03C4\\u03B5\\u03AF\\u03B5\\u03C2)",
118             "\\u0393\\u03b1\\u03bb\\u03bb\\u03b9\\u03ba\\u03ac (\\u0393\\u03b1\\u03bb\\u03bb\\u03af\\u03b1)",
119             "\\u039a\\u03b1\\u03c4\\u03b1\\u03bb\\u03b1\\u03bd\\u03b9\\u03ba\\u03ac (\\u0399\\u03c3\\u03c0\\u03b1\\u03bd\\u03af\\u03b1)",
120             "\\u0395\\u03bb\\u03bb\\u03b7\\u03bd\\u03b9\\u03ba\\u03ac (\\u0395\\u03bb\\u03bb\\u03ac\\u03b4\\u03b1)",
121             "\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03b9\\u03ba\\u03ac (\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03af\\u03b1, NY)",
122             "\\u0399\\u03c4\\u03b1\\u03bb\\u03b9\\u03ba\\u03ac",
123             "",
124             "\\u039A\\u03B9\\u03BD\\u03B5\\u03B6\\u03B9\\u03BA\\u03AC (\\u0391\\u03c0\\u03bb\\u03bf\\u03c0\\u03bf\\u03b9\\u03b7\\u03bc\\u03ad\\u03bd\\u03bf, \\u039A\\u03AF\\u03BD\\u03B1)"
125         },
126 
127         // display language (<root>)
128         {   "English",  "French",   "Catalan", "Greek",    "Norwegian",    "Italian",  "xx", "" },
129         // display script (<root>)
130         {   "",     "",     "",     "",     "",   "",     "", ""},
131         // display country (<root>)
132         {   "United States",    "France",   "Spain",  "Greece",   "Norway",   "",     "YY", "" },
133         // display variant (<root>)
134         {   "",     "",     "",     "",     "Nynorsk",   "",     "", ""},
135         // display name (<root>)
136         //{   "English (United States)", "French (France)", "Catalan (Spain)", "Greek (Greece)", "Norwegian (Norway,Nynorsk)", "Italian", "xx (YY)" },
137         {   "English (United States)", "French (France)", "Catalan (Spain)", "Greek (Greece)", "Norwegian (Norway,NY)", "Italian", "xx (YY)", "" }
138 };
139 
140 
141 /*
142  Usage:
143     test_assert(    Test (should be TRUE)  )
144 
145    Example:
146        test_assert(i==3);
147 
148    the macro is ugly but makes the tests pretty.
149 */
150 
151 #define test_assert(test) UPRV_BLOCK_MACRO_BEGIN { \
152     if(!(test)) \
153         errln("FAIL: " #test " was not true. In " __FILE__ " on line %d", __LINE__ ); \
154     else \
155         logln("PASS: asserted " #test); \
156 } UPRV_BLOCK_MACRO_END
157 
158 /*
159  Usage:
160     test_assert_print(    Test (should be TRUE),  printable  )
161 
162    Example:
163        test_assert(i==3, toString(i));
164 
165    the macro is ugly but makes the tests pretty.
166 */
167 
168 #define test_assert_print(test,print) UPRV_BLOCK_MACRO_BEGIN { \
169     if(!(test)) \
170         errln("FAIL: " #test " was not true. " + UnicodeString(print) ); \
171     else \
172         logln("PASS: asserted " #test "-> " + UnicodeString(print)); \
173 } UPRV_BLOCK_MACRO_END
174 
175 
176 #define test_dumpLocale(l) UPRV_BLOCK_MACRO_BEGIN { \
177     logln(#l " = " + UnicodeString(l.getName(), "")); \
178 } UPRV_BLOCK_MACRO_END
179 
LocaleTest()180 LocaleTest::LocaleTest()
181 : dataTable(NULL)
182 {
183     setUpDataTable();
184 }
185 
~LocaleTest()186 LocaleTest::~LocaleTest()
187 {
188     if (dataTable != 0) {
189         for (int32_t i = 0; i < 33; i++) {
190             delete []dataTable[i];
191         }
192         delete []dataTable;
193         dataTable = 0;
194     }
195 }
196 
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)197 void LocaleTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
198 {
199     TESTCASE_AUTO_BEGIN;
200     TESTCASE_AUTO(TestBug11421);         // Must run early in list to trigger failure.
201     TESTCASE_AUTO(TestBasicGetters);
202     TESTCASE_AUTO(TestSimpleResourceInfo);
203     TESTCASE_AUTO(TestDisplayNames);
204     TESTCASE_AUTO(TestSimpleObjectStuff);
205     TESTCASE_AUTO(TestPOSIXParsing);
206     TESTCASE_AUTO(TestGetAvailableLocales);
207     TESTCASE_AUTO(TestDataDirectory);
208     TESTCASE_AUTO(TestISO3Fallback);
209     TESTCASE_AUTO(TestGetLangsAndCountries);
210     TESTCASE_AUTO(TestSimpleDisplayNames);
211     TESTCASE_AUTO(TestUninstalledISO3Names);
212     TESTCASE_AUTO(TestAtypicalLocales);
213 #if !UCONFIG_NO_FORMATTING
214     TESTCASE_AUTO(TestThaiCurrencyFormat);
215     TESTCASE_AUTO(TestEuroSupport);
216 #endif
217     TESTCASE_AUTO(TestToString);
218 #if !UCONFIG_NO_FORMATTING
219     TESTCASE_AUTO(Test4139940);
220     TESTCASE_AUTO(Test4143951);
221 #endif
222     TESTCASE_AUTO(Test4147315);
223     TESTCASE_AUTO(Test4147317);
224     TESTCASE_AUTO(Test4147552);
225     TESTCASE_AUTO(TestVariantParsing);
226     TESTCASE_AUTO(Test20639_DeprecatesISO3Language);
227 #if !UCONFIG_NO_FORMATTING
228     TESTCASE_AUTO(Test4105828);
229 #endif
230     TESTCASE_AUTO(TestSetIsBogus);
231     TESTCASE_AUTO(TestParallelAPIValues);
232     TESTCASE_AUTO(TestAddLikelySubtags);
233     TESTCASE_AUTO(TestMinimizeSubtags);
234     TESTCASE_AUTO(TestAddLikelyAndMinimizeSubtags);
235     TESTCASE_AUTO(TestKeywordVariants);
236     TESTCASE_AUTO(TestCreateUnicodeKeywords);
237     TESTCASE_AUTO(TestKeywordVariantParsing);
238     TESTCASE_AUTO(TestCreateKeywordSet);
239     TESTCASE_AUTO(TestCreateKeywordSetEmpty);
240     TESTCASE_AUTO(TestCreateUnicodeKeywordSet);
241     TESTCASE_AUTO(TestCreateUnicodeKeywordSetEmpty);
242     TESTCASE_AUTO(TestGetKeywordValueStdString);
243     TESTCASE_AUTO(TestGetUnicodeKeywordValueStdString);
244     TESTCASE_AUTO(TestSetKeywordValue);
245     TESTCASE_AUTO(TestSetKeywordValueStringPiece);
246     TESTCASE_AUTO(TestSetUnicodeKeywordValueStringPiece);
247     TESTCASE_AUTO(TestGetBaseName);
248 #if !UCONFIG_NO_FILE_IO
249     TESTCASE_AUTO(TestGetLocale);
250 #endif
251     TESTCASE_AUTO(TestVariantWithOutCountry);
252     TESTCASE_AUTO(TestCanonicalization);
253     TESTCASE_AUTO(TestCurrencyByDate);
254     TESTCASE_AUTO(TestGetVariantWithKeywords);
255     TESTCASE_AUTO(TestIsRightToLeft);
256     TESTCASE_AUTO(TestBug13277);
257     TESTCASE_AUTO(TestBug13554);
258     TESTCASE_AUTO(TestBug20410);
259     TESTCASE_AUTO(TestBug20900);
260     TESTCASE_AUTO(TestConstructorAcceptsBCP47);
261     TESTCASE_AUTO(TestForLanguageTag);
262     TESTCASE_AUTO(TestToLanguageTag);
263     TESTCASE_AUTO(TestToLanguageTagOmitTrue);
264     TESTCASE_AUTO(TestMoveAssign);
265     TESTCASE_AUTO(TestMoveCtor);
266     TESTCASE_AUTO(TestBug20407iVariantPreferredValue);
267     TESTCASE_AUTO(TestBug13417VeryLongLanguageTag);
268     TESTCASE_AUTO(TestBug11053UnderlineTimeZone);
269     TESTCASE_AUTO(TestUnd);
270     TESTCASE_AUTO(TestUndScript);
271     TESTCASE_AUTO(TestUndRegion);
272     TESTCASE_AUTO(TestUndCAPI);
273     TESTCASE_AUTO(TestRangeIterator);
274     TESTCASE_AUTO(TestPointerConvertingIterator);
275     TESTCASE_AUTO(TestTagConvertingIterator);
276     TESTCASE_AUTO(TestCapturingTagConvertingIterator);
277     TESTCASE_AUTO(TestSetUnicodeKeywordValueInLongLocale);
278     TESTCASE_AUTO(TestSetUnicodeKeywordValueNullInLongLocale);
279     TESTCASE_AUTO(TestCanonicalize);
280     TESTCASE_AUTO_END;
281 }
282 
TestBasicGetters()283 void LocaleTest::TestBasicGetters() {
284     UnicodeString   temp;
285 
286     int32_t i;
287     for (i = 0; i <= MAX_LOCALES; i++) {
288         Locale testLocale("");
289         if (rawData[SCRIPT][i] && rawData[SCRIPT][i][0] != 0) {
290             testLocale = Locale(rawData[LANG][i], rawData[SCRIPT][i], rawData[CTRY][i], rawData[VAR][i]);
291         }
292         else {
293             testLocale = Locale(rawData[LANG][i], rawData[CTRY][i], rawData[VAR][i]);
294         }
295         logln("Testing " + (UnicodeString)testLocale.getName() + "...");
296 
297         if ( (temp=testLocale.getLanguage()) != (dataTable[LANG][i]))
298             errln("  Language code mismatch: " + temp + " versus "
299                         + dataTable[LANG][i]);
300         if ( (temp=testLocale.getScript()) != (dataTable[SCRIPT][i]))
301             errln("  Script code mismatch: " + temp + " versus "
302                         + dataTable[SCRIPT][i]);
303         if ( (temp=testLocale.getCountry()) != (dataTable[CTRY][i]))
304             errln("  Country code mismatch: " + temp + " versus "
305                         + dataTable[CTRY][i]);
306         if ( (temp=testLocale.getVariant()) != (dataTable[VAR][i]))
307             errln("  Variant code mismatch: " + temp + " versus "
308                         + dataTable[VAR][i]);
309         if ( (temp=testLocale.getName()) != (dataTable[NAME][i]))
310             errln("  Locale name mismatch: " + temp + " versus "
311                         + dataTable[NAME][i]);
312     }
313 
314     logln("Same thing without variant codes...");
315     for (i = 0; i <= MAX_LOCALES; i++) {
316         Locale testLocale("");
317         if (rawData[SCRIPT][i] && rawData[SCRIPT][i][0] != 0) {
318             testLocale = Locale(rawData[LANG][i], rawData[SCRIPT][i], rawData[CTRY][i]);
319         }
320         else {
321             testLocale = Locale(rawData[LANG][i], rawData[CTRY][i]);
322         }
323         logln("Testing " + (temp=testLocale.getName()) + "...");
324 
325         if ( (temp=testLocale.getLanguage()) != (dataTable[LANG][i]))
326             errln("Language code mismatch: " + temp + " versus "
327                         + dataTable[LANG][i]);
328         if ( (temp=testLocale.getScript()) != (dataTable[SCRIPT][i]))
329             errln("Script code mismatch: " + temp + " versus "
330                         + dataTable[SCRIPT][i]);
331         if ( (temp=testLocale.getCountry()) != (dataTable[CTRY][i]))
332             errln("Country code mismatch: " + temp + " versus "
333                         + dataTable[CTRY][i]);
334         if (testLocale.getVariant()[0] != 0)
335             errln("Variant code mismatch: something versus \"\"");
336     }
337 
338     logln("Testing long language names and getters");
339     Locale  test8 = Locale::createFromName("x-klingon-latn-zx.utf32be@special");
340 
341     temp = test8.getLanguage();
342     if (temp != UnicodeString("x-klingon") )
343         errln("Language code mismatch: " + temp + "  versus \"x-klingon\"");
344 
345     temp = test8.getScript();
346     if (temp != UnicodeString("Latn") )
347         errln("Script code mismatch: " + temp + "  versus \"Latn\"");
348 
349     temp = test8.getCountry();
350     if (temp != UnicodeString("ZX") )
351         errln("Country code mismatch: " + temp + "  versus \"ZX\"");
352 
353     temp = test8.getVariant();
354     //if (temp != UnicodeString("SPECIAL") )
355     //    errln("Variant code mismatch: " + temp + "  versus \"SPECIAL\"");
356     // As of 3.0, the "@special" will *not* be parsed by uloc_getName()
357     if (temp != UnicodeString("") )
358         errln("Variant code mismatch: " + temp + "  versus \"\"");
359 
360     if (Locale::getDefault() != Locale::createFromName(NULL))
361         errln("Locale::getDefault() == Locale::createFromName(NULL)");
362 
363     /*----------*/
364     // NOTE: There used to be a special test for locale names that had language or
365     // country codes that were longer than two letters.  The new version of Locale
366     // doesn't support anything that isn't an officially recognized language or
367     // country code, so we no longer support this feature.
368 
369     Locale bogusLang("THISISABOGUSLANGUAGE"); // Jitterbug 2864: language code too long
370     if(!bogusLang.isBogus()) {
371         errln("Locale(\"THISISABOGUSLANGUAGE\").isBogus()==FALSE");
372     }
373 
374     bogusLang=Locale("eo");
375     if( bogusLang.isBogus() ||
376         strcmp(bogusLang.getLanguage(), "eo")!=0 ||
377         *bogusLang.getCountry()!=0 ||
378         *bogusLang.getVariant()!=0 ||
379         strcmp(bogusLang.getName(), "eo")!=0
380     ) {
381         errln("assignment to bogus Locale does not unbogus it or sets bad data");
382     }
383 
384     Locale a("eo_DE@currency=DEM");
385     Locale *pb=a.clone();
386     if(pb==&a || *pb!=a) {
387         errln("Locale.clone() failed");
388     }
389     delete pb;
390 }
391 
TestParallelAPIValues()392 void LocaleTest::TestParallelAPIValues() {
393     logln("Test synchronization between C and C++ API");
394     if (strcmp(Locale::getChinese().getName(), ULOC_CHINESE) != 0) {
395         errln("Differences for ULOC_CHINESE Locale");
396     }
397     if (strcmp(Locale::getEnglish().getName(), ULOC_ENGLISH) != 0) {
398         errln("Differences for ULOC_ENGLISH Locale");
399     }
400     if (strcmp(Locale::getFrench().getName(), ULOC_FRENCH) != 0) {
401         errln("Differences for ULOC_FRENCH Locale");
402     }
403     if (strcmp(Locale::getGerman().getName(), ULOC_GERMAN) != 0) {
404         errln("Differences for ULOC_GERMAN Locale");
405     }
406     if (strcmp(Locale::getItalian().getName(), ULOC_ITALIAN) != 0) {
407         errln("Differences for ULOC_ITALIAN Locale");
408     }
409     if (strcmp(Locale::getJapanese().getName(), ULOC_JAPANESE) != 0) {
410         errln("Differences for ULOC_JAPANESE Locale");
411     }
412     if (strcmp(Locale::getKorean().getName(), ULOC_KOREAN) != 0) {
413         errln("Differences for ULOC_KOREAN Locale");
414     }
415     if (strcmp(Locale::getSimplifiedChinese().getName(), ULOC_SIMPLIFIED_CHINESE) != 0) {
416         errln("Differences for ULOC_SIMPLIFIED_CHINESE Locale");
417     }
418     if (strcmp(Locale::getTraditionalChinese().getName(), ULOC_TRADITIONAL_CHINESE) != 0) {
419         errln("Differences for ULOC_TRADITIONAL_CHINESE Locale");
420     }
421 
422 
423     if (strcmp(Locale::getCanada().getName(), ULOC_CANADA) != 0) {
424         errln("Differences for ULOC_CANADA Locale");
425     }
426     if (strcmp(Locale::getCanadaFrench().getName(), ULOC_CANADA_FRENCH) != 0) {
427         errln("Differences for ULOC_CANADA_FRENCH Locale");
428     }
429     if (strcmp(Locale::getChina().getName(), ULOC_CHINA) != 0) {
430         errln("Differences for ULOC_CHINA Locale");
431     }
432     if (strcmp(Locale::getPRC().getName(), ULOC_PRC) != 0) {
433         errln("Differences for ULOC_PRC Locale");
434     }
435     if (strcmp(Locale::getFrance().getName(), ULOC_FRANCE) != 0) {
436         errln("Differences for ULOC_FRANCE Locale");
437     }
438     if (strcmp(Locale::getGermany().getName(), ULOC_GERMANY) != 0) {
439         errln("Differences for ULOC_GERMANY Locale");
440     }
441     if (strcmp(Locale::getItaly().getName(), ULOC_ITALY) != 0) {
442         errln("Differences for ULOC_ITALY Locale");
443     }
444     if (strcmp(Locale::getJapan().getName(), ULOC_JAPAN) != 0) {
445         errln("Differences for ULOC_JAPAN Locale");
446     }
447     if (strcmp(Locale::getKorea().getName(), ULOC_KOREA) != 0) {
448         errln("Differences for ULOC_KOREA Locale");
449     }
450     if (strcmp(Locale::getTaiwan().getName(), ULOC_TAIWAN) != 0) {
451         errln("Differences for ULOC_TAIWAN Locale");
452     }
453     if (strcmp(Locale::getUK().getName(), ULOC_UK) != 0) {
454         errln("Differences for ULOC_UK Locale");
455     }
456     if (strcmp(Locale::getUS().getName(), ULOC_US) != 0) {
457         errln("Differences for ULOC_US Locale");
458     }
459 }
460 
461 
TestSimpleResourceInfo()462 void LocaleTest::TestSimpleResourceInfo() {
463     UnicodeString   temp;
464     char            temp2[20];
465     UErrorCode err = U_ZERO_ERROR;
466     int32_t i = 0;
467 
468     for (i = 0; i <= MAX_LOCALES; i++) {
469         Locale testLocale(rawData[LANG][i], rawData[CTRY][i], rawData[VAR][i]);
470         logln("Testing " + (temp=testLocale.getName()) + "...");
471 
472         if ( (temp=testLocale.getISO3Language()) != (dataTable[LANG3][i]))
473             errln("  ISO-3 language code mismatch: " + temp
474                 + " versus " + dataTable[LANG3][i]);
475         if ( (temp=testLocale.getISO3Country()) != (dataTable[CTRY3][i]))
476             errln("  ISO-3 country code mismatch: " + temp
477                 + " versus " + dataTable[CTRY3][i]);
478 
479         sprintf(temp2, "%x", (int)testLocale.getLCID());
480         if (UnicodeString(temp2) != dataTable[LCID][i])
481             errln((UnicodeString)"  LCID mismatch: " + temp2 + " versus "
482                 + dataTable[LCID][i]);
483 
484         if(U_FAILURE(err))
485         {
486             errln((UnicodeString)"Some error on number " + i + u_errorName(err));
487         }
488         err = U_ZERO_ERROR;
489     }
490 
491     Locale locale("en");
492     if(strcmp(locale.getName(), "en") != 0||
493         strcmp(locale.getLanguage(), "en") != 0) {
494         errln("construction of Locale(en) failed\n");
495     }
496     /*-----*/
497 
498 }
499 
500 /*
501  * Jitterbug 2439 -- markus 20030425
502  *
503  * The lookup of display names must not fall back through the default
504  * locale because that yields useless results.
505  */
506 void
TestDisplayNames()507 LocaleTest::TestDisplayNames()
508 {
509     Locale  english("en", "US");
510     Locale  french("fr", "FR");
511     Locale  croatian("ca", "ES");
512     Locale  greek("el", "GR");
513 
514     logln("  In locale = en_US...");
515     doTestDisplayNames(english, DLANG_EN);
516     logln("  In locale = fr_FR...");
517     doTestDisplayNames(french, DLANG_FR);
518     logln("  In locale = ca_ES...");
519     doTestDisplayNames(croatian, DLANG_CA);
520     logln("  In locale = el_GR...");
521     doTestDisplayNames(greek, DLANG_EL);
522 
523     UnicodeString s;
524     UErrorCode status = U_ZERO_ERROR;
525 
526 #if !UCONFIG_NO_FORMATTING
527     DecimalFormatSymbols symb(status);
528     /* Check to see if ICU supports this locale */
529     if (symb.getLocale(ULOC_VALID_LOCALE, status) != Locale("root")) {
530         /* test that the default locale has a display name for its own language */
531         /* Currently, there is no language information in the "tl" data file so this test will fail if default locale is "tl" */
532         if (uprv_strcmp(Locale().getLanguage(), "tl") != 0) {
533             Locale().getDisplayLanguage(Locale(), s);
534             if(s.length()<=3 && s.charAt(0)<=0x7f) {
535                 /* check <=3 to reject getting the language code as a display name */
536                 dataerrln("unable to get a display string for the language of the default locale: " + s);
537             }
538 
539             /*
540              * API coverage improvements: call
541              * Locale::getDisplayLanguage(UnicodeString &) and
542              * Locale::getDisplayCountry(UnicodeString &)
543              */
544             s.remove();
545             Locale().getDisplayLanguage(s);
546             if(s.length()<=3 && s.charAt(0)<=0x7f) {
547                 dataerrln("unable to get a display string for the language of the default locale [2]: " + s);
548             }
549         }
550     }
551     else {
552         logln("Default locale %s is unsupported by ICU\n", Locale().getName());
553     }
554     s.remove();
555 #endif
556 
557     french.getDisplayCountry(s);
558     if(s.isEmpty()) {
559         errln("unable to get any default-locale display string for the country of fr_FR\n");
560     }
561     s.remove();
562     Locale("zh", "Hant").getDisplayScript(s);
563     if(s.isEmpty()) {
564         errln("unable to get any default-locale display string for the country of zh_Hant\n");
565     }
566 }
567 
TestSimpleObjectStuff()568 void LocaleTest::TestSimpleObjectStuff() {
569     Locale  test1("aa", "AA");
570     Locale  test2("aa", "AA");
571     Locale  test3(test1);
572     Locale  test4("zz", "ZZ");
573     Locale  test5("aa", "AA", "");
574     Locale  test6("aa", "AA", "ANTARES");
575     Locale  test7("aa", "AA", "JUPITER");
576     Locale  test8 = Locale::createFromName("aa-aa-jupiTER"); // was "aa-aa.utf8@jupiter" but in 3.0 getName won't normalize that
577 
578     // now list them all for debugging usage.
579     test_dumpLocale(test1);
580     test_dumpLocale(test2);
581     test_dumpLocale(test3);
582     test_dumpLocale(test4);
583     test_dumpLocale(test5);
584     test_dumpLocale(test6);
585     test_dumpLocale(test7);
586     test_dumpLocale(test8);
587 
588     // Make sure things compare to themselves!
589     test_assert(test1 == test1);
590     test_assert(test2 == test2);
591     test_assert(test3 == test3);
592     test_assert(test4 == test4);
593     test_assert(test5 == test5);
594     test_assert(test6 == test6);
595     test_assert(test7 == test7);
596     test_assert(test8 == test8);
597 
598     // make sure things are not equal to themselves.
599     test_assert(!(test1 != test1));
600     test_assert(!(test2 != test2));
601     test_assert(!(test3 != test3));
602     test_assert(!(test4 != test4));
603     test_assert(!(test5 != test5));
604     test_assert(!(test6 != test6));
605     test_assert(!(test7 != test7));
606     test_assert(!(test8 != test8));
607 
608     // make sure things that are equal to each other don't show up as unequal.
609     test_assert(!(test1 != test2));
610     test_assert(!(test2 != test1));
611     test_assert(!(test1 != test3));
612     test_assert(!(test2 != test3));
613     test_assert(test5 == test1);
614     test_assert(test6 != test2);
615     test_assert(test6 != test5);
616 
617     test_assert(test6 != test7);
618 
619     // test for things that shouldn't compare equal.
620     test_assert(!(test1 == test4));
621     test_assert(!(test2 == test4));
622     test_assert(!(test3 == test4));
623 
624     test_assert(test7 == test8);
625 
626     // test for hash codes to be the same.
627     int32_t hash1 = test1.hashCode();
628     int32_t hash2 = test2.hashCode();
629     int32_t hash3 = test3.hashCode();
630 
631     test_assert(hash1 == hash2);
632     test_assert(hash1 == hash3);
633     test_assert(hash2 == hash3);
634 
635     // test that the assignment operator works.
636     test4 = test1;
637     logln("test4=test1;");
638     test_dumpLocale(test4);
639     test_assert(test4 == test4);
640 
641     test_assert(!(test1 != test4));
642     test_assert(!(test2 != test4));
643     test_assert(!(test3 != test4));
644     test_assert(test1 == test4);
645     test_assert(test4 == test1);
646 
647     // test assignments with a variant
648     logln("test7 = test6");
649     test7 = test6;
650     test_dumpLocale(test7);
651     test_assert(test7 == test7);
652     test_assert(test7 == test6);
653     test_assert(test7 != test5);
654 
655     logln("test6 = test1");
656     test6=test1;
657     test_dumpLocale(test6);
658     test_assert(test6 != test7);
659     test_assert(test6 == test1);
660     test_assert(test6 == test6);
661 }
662 
663 // A class which exposes constructors that are implemented in terms of the POSIX parsing code.
664 class POSIXLocale : public Locale
665 {
666 public:
POSIXLocale(const UnicodeString & l)667     POSIXLocale(const UnicodeString& l)
668         :Locale()
669     {
670       char *ch;
671       ch = new char[l.length() + 1];
672       ch[l.extract(0, 0x7fffffff, ch, "")] = 0;
673       setFromPOSIXID(ch);
674       delete [] ch;
675     }
POSIXLocale(const char * l)676     POSIXLocale(const char *l)
677         :Locale()
678     {
679         setFromPOSIXID(l);
680     }
681 };
682 
TestPOSIXParsing()683 void LocaleTest::TestPOSIXParsing()
684 {
685     POSIXLocale  test1("ab_AB");
686     POSIXLocale  test2(UnicodeString("ab_AB"));
687     Locale  test3("ab","AB");
688 
689     POSIXLocale test4("ab_AB_Antares");
690     POSIXLocale test5(UnicodeString("ab_AB_Antares"));
691     Locale  test6("ab", "AB", "Antares");
692 
693     test_dumpLocale(test1);
694     test_dumpLocale(test2);
695     test_dumpLocale(test3);
696     test_dumpLocale(test4);
697     test_dumpLocale(test5);
698     test_dumpLocale(test6);
699 
700     test_assert(test1 == test1);
701 
702     test_assert(test1 == test2);
703     test_assert(test2 == test3);
704     test_assert(test3 == test1);
705 
706     test_assert(test4 == test5);
707     test_assert(test5 == test6);
708     test_assert(test6 == test4);
709 
710     test_assert(test1 != test4);
711     test_assert(test5 != test3);
712     test_assert(test5 != test2);
713 
714     int32_t hash1 = test1.hashCode();
715     int32_t hash2 = test2.hashCode();
716     int32_t hash3 = test3.hashCode();
717 
718     test_assert(hash1 == hash2);
719     test_assert(hash2 == hash3);
720     test_assert(hash3 == hash1);
721 }
722 
TestGetAvailableLocales()723 void LocaleTest::TestGetAvailableLocales()
724 {
725     int32_t locCount = 0;
726     const Locale* locList = Locale::getAvailableLocales(locCount);
727 
728     if (locCount == 0)
729         dataerrln("getAvailableLocales() returned an empty list!");
730     else {
731         logln(UnicodeString("Number of locales returned = ") + locCount);
732         UnicodeString temp;
733         for(int32_t i = 0; i < locCount; ++i)
734             logln(locList[i].getName());
735     }
736     // I have no idea how to test this function...
737 }
738 
739 // This test isn't applicable anymore - getISO3Language is
740 // independent of the data directory
TestDataDirectory()741 void LocaleTest::TestDataDirectory()
742 {
743 /*
744     char            oldDirectory[80];
745     const char*     temp;
746     UErrorCode       err = U_ZERO_ERROR;
747     UnicodeString   testValue;
748 
749     temp = Locale::getDataDirectory();
750     strcpy(oldDirectory, temp);
751     logln(UnicodeString("oldDirectory = ") + oldDirectory);
752 
753     Locale  test(Locale::US);
754     test.getISO3Language(testValue);
755     logln("first fetch of language retrieved " + testValue);
756     if (testValue != "eng")
757         errln("Initial check of ISO3 language failed: expected \"eng\", got \"" + testValue + "\"");
758 
759     {
760         char *path;
761         path=IntlTest::getTestDirectory();
762         Locale::setDataDirectory( path );
763     }
764 
765     test.getISO3Language(testValue);
766     logln("second fetch of language retrieved " + testValue);
767     if (testValue != "xxx")
768         errln("setDataDirectory() failed: expected \"xxx\", got \"" + testValue + "\"");
769 
770     Locale::setDataDirectory(oldDirectory);
771     test.getISO3Language(testValue);
772     logln("third fetch of language retrieved " + testValue);
773     if (testValue != "eng")
774         errln("get/setDataDirectory() failed: expected \"eng\", got \"" + testValue + "\"");
775 */
776 }
777 
778 //===========================================================
779 
doTestDisplayNames(Locale & displayLocale,int32_t compareIndex)780 void LocaleTest::doTestDisplayNames(Locale& displayLocale, int32_t compareIndex) {
781     UnicodeString   temp;
782 
783     for (int32_t i = 0; i <= MAX_LOCALES; i++) {
784         Locale testLocale("");
785         if (rawData[SCRIPT][i] && rawData[SCRIPT][i][0] != 0) {
786             testLocale = Locale(rawData[LANG][i], rawData[SCRIPT][i], rawData[CTRY][i], rawData[VAR][i]);
787         }
788         else {
789             testLocale = Locale(rawData[LANG][i], rawData[CTRY][i], rawData[VAR][i]);
790         }
791         logln("  Testing " + (temp=testLocale.getName()) + "...");
792 
793         UnicodeString  testLang;
794         UnicodeString  testScript;
795         UnicodeString  testCtry;
796         UnicodeString  testVar;
797         UnicodeString  testName;
798 
799         testLocale.getDisplayLanguage(displayLocale, testLang);
800         testLocale.getDisplayScript(displayLocale, testScript);
801         testLocale.getDisplayCountry(displayLocale, testCtry);
802         testLocale.getDisplayVariant(displayLocale, testVar);
803         testLocale.getDisplayName(displayLocale, testName);
804 
805         UnicodeString  expectedLang;
806         UnicodeString  expectedScript;
807         UnicodeString  expectedCtry;
808         UnicodeString  expectedVar;
809         UnicodeString  expectedName;
810 
811         expectedLang = dataTable[compareIndex][i];
812         if (expectedLang.length() == 0)
813             expectedLang = dataTable[DLANG_EN][i];
814 
815         expectedScript = dataTable[compareIndex + 1][i];
816         if (expectedScript.length() == 0)
817             expectedScript = dataTable[DSCRIPT_EN][i];
818 
819         expectedCtry = dataTable[compareIndex + 2][i];
820         if (expectedCtry.length() == 0)
821             expectedCtry = dataTable[DCTRY_EN][i];
822 
823         expectedVar = dataTable[compareIndex + 3][i];
824         if (expectedVar.length() == 0)
825             expectedVar = dataTable[DVAR_EN][i];
826 
827         expectedName = dataTable[compareIndex + 4][i];
828         if (expectedName.length() == 0)
829             expectedName = dataTable[DNAME_EN][i];
830 
831         if (testLang != expectedLang)
832             dataerrln("Display language (" + UnicodeString(displayLocale.getName()) + ") of (" + UnicodeString(testLocale.getName()) + ") got " + testLang + " expected " + expectedLang);
833         if (testScript != expectedScript)
834             dataerrln("Display script (" + UnicodeString(displayLocale.getName()) + ") of (" + UnicodeString(testLocale.getName()) + ") got " + testScript + " expected " + expectedScript);
835         if (testCtry != expectedCtry)
836             dataerrln("Display country (" + UnicodeString(displayLocale.getName()) + ") of (" + UnicodeString(testLocale.getName()) + ") got " + testCtry + " expected " + expectedCtry);
837         if (testVar != expectedVar)
838             dataerrln("Display variant (" + UnicodeString(displayLocale.getName()) + ") of (" + UnicodeString(testLocale.getName()) + ") got " + testVar + " expected " + expectedVar);
839         if (testName != expectedName)
840             dataerrln("Display name (" + UnicodeString(displayLocale.getName()) + ") of (" + UnicodeString(testLocale.getName()) + ") got " + testName + " expected " + expectedName);
841     }
842 }
843 
844 //---------------------------------------------------
845 // table of valid data
846 //---------------------------------------------------
847 
848 
849 
setUpDataTable()850 void LocaleTest::setUpDataTable()
851 {
852     if (dataTable == 0) {
853         dataTable = new UnicodeString*[33];
854 
855         for (int32_t i = 0; i < 33; i++) {
856             dataTable[i] = new UnicodeString[8];
857             for (int32_t j = 0; j < 8; j++) {
858                 dataTable[i][j] = CharsToUnicodeString(rawData[i][j]);
859             }
860         }
861     }
862 }
863 
864 // ====================
865 
866 
867 /**
868  * @bug 4011756 4011380
869  */
870 void
TestISO3Fallback()871 LocaleTest::TestISO3Fallback()
872 {
873     Locale test("xx", "YY");
874 
875     const char * result;
876 
877     result = test.getISO3Language();
878 
879     // Conform to C API usage
880 
881     if (!result || (result[0] != 0))
882         errln("getISO3Language() on xx_YY returned " + UnicodeString(result) + " instead of \"\"");
883 
884     result = test.getISO3Country();
885 
886     if (!result || (result[0] != 0))
887         errln("getISO3Country() on xx_YY returned " + UnicodeString(result) + " instead of \"\"");
888 }
889 
890 /**
891  * @bug 4106155 4118587
892  */
893 void
TestGetLangsAndCountries()894 LocaleTest::TestGetLangsAndCountries()
895 {
896     // It didn't seem right to just do an exhaustive test of everything here, so I check
897     // for the following things:
898     // 1) Does each list have the right total number of entries?
899     // 2) Does each list contain certain language and country codes we think are important
900     //     (the G7 countries, plus a couple others)?
901     // 3) Does each list have every entry formatted correctly? (i.e., two characters,
902     //     all lower case for the language codes, all upper case for the country codes)
903     // 4) Is each list in sorted order?
904     int32_t testCount = 0;
905     const char * const * test = Locale::getISOLanguages();
906     const char spotCheck1[ ][4] = { "en", "es", "fr", "de", "it",
907                                     "ja", "ko", "zh", "th", "he",
908                                     "id", "iu", "ug", "yi", "za" };
909 
910     int32_t i;
911 
912     for(testCount = 0;test[testCount];testCount++)
913       ;
914 
915     /* TODO: Change this test to be more like the cloctst version? */
916     if (testCount != 597)
917         errln("Expected getISOLanguages() to return 597 languages; it returned %d", testCount);
918     else {
919         for (i = 0; i < 15; i++) {
920             int32_t j;
921             for (j = 0; j < testCount; j++)
922               if (uprv_strcmp(test[j],spotCheck1[i])== 0)
923                     break;
924             if (j == testCount || (uprv_strcmp(test[j],spotCheck1[i])!=0))
925                 errln("Couldn't find " + (UnicodeString)spotCheck1[i] + " in language list.");
926         }
927     }
928     for (i = 0; i < testCount; i++) {
929         UnicodeString testee(test[i],"");
930         UnicodeString lc(test[i],"");
931         if (testee != lc.toLower())
932             errln(lc + " is not all lower case.");
933         if ( (testee.length() != 2) && (testee.length() != 3))
934             errln(testee + " is not two or three characters long.");
935         if (i > 0 && testee.compare(test[i - 1]) <= 0)
936             errln(testee + " appears in an out-of-order position in the list.");
937     }
938 
939     test = Locale::getISOCountries();
940     UnicodeString spotCheck2 [] = { "US", "CA", "GB", "FR", "DE",
941                                     "IT", "JP", "KR", "CN", "TW",
942                                     "TH" };
943     int32_t spot2Len = 11;
944     for(testCount=0;test[testCount];testCount++)
945       ;
946 
947     if (testCount != 249){
948         errln("Expected getISOCountries to return 249 countries; it returned %d", testCount);
949     }else {
950         for (i = 0; i < spot2Len; i++) {
951             int32_t j;
952             for (j = 0; j < testCount; j++)
953               {
954                 UnicodeString testee(test[j],"");
955 
956                 if (testee == spotCheck2[i])
957                     break;
958               }
959                 UnicodeString testee(test[j],"");
960             if (j == testCount || testee != spotCheck2[i])
961                 errln("Couldn't find " + spotCheck2[i] + " in country list.");
962         }
963     }
964     for (i = 0; i < testCount; i++) {
965         UnicodeString testee(test[i],"");
966         UnicodeString uc(test[i],"");
967         if (testee != uc.toUpper())
968             errln(testee + " is not all upper case.");
969         if (testee.length() != 2)
970             errln(testee + " is not two characters long.");
971         if (i > 0 && testee.compare(test[i - 1]) <= 0)
972             errln(testee + " appears in an out-of-order position in the list.");
973     }
974 
975     // This getAvailableLocales and getISO3Language
976     {
977         int32_t numOfLocales;
978         Locale  enLoc ("en");
979         const Locale *pLocales = Locale::getAvailableLocales(numOfLocales);
980 
981         for (int i = 0; i < numOfLocales; i++) {
982             const Locale    &loc(pLocales[i]);
983             UnicodeString   name;
984             char        szName[200];
985 
986             loc.getDisplayName (enLoc, name);
987             name.extract (0, 200, szName, sizeof(szName));
988 
989             if (strlen(loc.getISO3Language()) == 0) {
990                 errln("getISO3Language() returned an empty string for: " + name);
991             }
992         }
993     }
994 }
995 
996 /**
997  * @bug 4118587
998  */
999 void
TestSimpleDisplayNames()1000 LocaleTest::TestSimpleDisplayNames()
1001 {
1002     // This test is different from TestDisplayNames because TestDisplayNames checks
1003     // fallback behavior, combination of language and country names to form locale
1004     // names, and other stuff like that.  This test just checks specific language
1005     // and country codes to make sure we have the correct names for them.
1006     char languageCodes[] [4] = { "he", "id", "iu", "ug", "yi", "za" };
1007     UnicodeString languageNames [] = { "Hebrew", "Indonesian", "Inuktitut", "Uyghur", "Yiddish",
1008                                "Zhuang" };
1009 
1010     for (int32_t i = 0; i < 6; i++) {
1011         UnicodeString test;
1012         Locale l(languageCodes[i], "", "");
1013         l.getDisplayLanguage(Locale::getUS(), test);
1014         if (test != languageNames[i])
1015             dataerrln("Got wrong display name for " + UnicodeString(languageCodes[i]) + ": Expected \"" +
1016                   languageNames[i] + "\", got \"" + test + "\".");
1017     }
1018 }
1019 
1020 /**
1021  * @bug 4118595
1022  */
1023 void
TestUninstalledISO3Names()1024 LocaleTest::TestUninstalledISO3Names()
1025 {
1026     // This test checks to make sure getISO3Language and getISO3Country work right
1027     // even for locales that are not installed.
1028     const char iso2Languages [][4] = {     "am", "ba", "fy", "mr", "rn",
1029                                         "ss", "tw", "zu" };
1030     const char iso3Languages [][5] = {     "amh", "bak", "fry", "mar", "run",
1031                                         "ssw", "twi", "zul" };
1032 
1033     int32_t i;
1034 
1035     for (i = 0; i < 8; i++) {
1036       UErrorCode err = U_ZERO_ERROR;
1037 
1038       UnicodeString test;
1039         Locale l(iso2Languages[i], "", "");
1040         test = l.getISO3Language();
1041         if((test != iso3Languages[i]) || U_FAILURE(err))
1042             errln("Got wrong ISO3 code for " + UnicodeString(iso2Languages[i]) + ": Expected \"" +
1043                     iso3Languages[i] + "\", got \"" + test + "\"." + UnicodeString(u_errorName(err)));
1044     }
1045 
1046     char iso2Countries [][4] = {     "AF", "BW", "KZ", "MO", "MN",
1047                                         "SB", "TC", "ZW" };
1048     char iso3Countries [][4] = {     "AFG", "BWA", "KAZ", "MAC", "MNG",
1049                                         "SLB", "TCA", "ZWE" };
1050 
1051     for (i = 0; i < 8; i++) {
1052       UErrorCode err = U_ZERO_ERROR;
1053         Locale l("", iso2Countries[i], "");
1054         UnicodeString test(l.getISO3Country(), "");
1055         if (test != iso3Countries[i])
1056             errln("Got wrong ISO3 code for " + UnicodeString(iso2Countries[i]) + ": Expected \"" +
1057                     UnicodeString(iso3Countries[i]) + "\", got \"" + test + "\"." + u_errorName(err));
1058     }
1059 }
1060 
1061 /**
1062  * @bug 4092475
1063  * I could not reproduce this bug.  I'm pretty convinced it was fixed with the
1064  * big locale-data reorg of 10/28/97.  The lookup logic for language and country
1065  * display names was also changed at that time in that check-in.    --rtg 3/20/98
1066  */
1067 void
TestAtypicalLocales()1068 LocaleTest::TestAtypicalLocales()
1069 {
1070     Locale localesToTest [] = { Locale("de", "CA"),
1071                                   Locale("ja", "ZA"),
1072                                    Locale("ru", "MX"),
1073                                    Locale("en", "FR"),
1074                                    Locale("es", "DE"),
1075                                    Locale("", "HR"),
1076                                    Locale("", "SE"),
1077                                    Locale("", "DO"),
1078                                    Locale("", "BE") };
1079 
1080     UnicodeString englishDisplayNames [] = { "German (Canada)",
1081                                      "Japanese (South Africa)",
1082                                      "Russian (Mexico)",
1083                                      "English (France)",
1084                                      "Spanish (Germany)",
1085                                      "Unknown language (Croatia)",
1086                                      "Unknown language (Sweden)",
1087                                      "Unknown language (Dominican Republic)",
1088                                      "Unknown language (Belgium)" };
1089     UnicodeString frenchDisplayNames []= { "allemand (Canada)",
1090                                      "japonais (Afrique du Sud)",
1091                                      "russe (Mexique)",
1092                                      "anglais (France)",
1093                                      "espagnol (Allemagne)",
1094                                      u"langue indéterminée (Croatie)",
1095                                      u"langue indéterminée (Suède)",
1096                                      u"langue indéterminée (République dominicaine)",
1097                                      u"langue indéterminée (Belgique)" };
1098     UnicodeString spanishDisplayNames [] = {
1099                                      u"alemán (Canadá)",
1100                                      u"japonés (Sudáfrica)",
1101                                      u"ruso (México)",
1102                                      u"inglés (Francia)",
1103                                      u"español (Alemania)",
1104                                      "lengua desconocida (Croacia)",
1105                                      "lengua desconocida (Suecia)",
1106                                      u"lengua desconocida (República Dominicana)",
1107                                      u"lengua desconocida (Bélgica)" };
1108     // De-Anglicizing root required the change from
1109     // English display names to ISO Codes - ram 2003/09/26
1110     UnicodeString invDisplayNames [] = { "German (Canada)",
1111                                      "Japanese (South Africa)",
1112                                      "Russian (Mexico)",
1113                                      "English (France)",
1114                                      "Spanish (Germany)",
1115                                      "Unknown language (Croatia)",
1116                                      "Unknown language (Sweden)",
1117                                      "Unknown language (Dominican Republic)",
1118                                      "Unknown language (Belgium)" };
1119 
1120     int32_t i;
1121     UErrorCode status = U_ZERO_ERROR;
1122     Locale saveLocale;
1123     Locale::setDefault(Locale::getUS(), status);
1124     for (i = 0; i < 9; ++i) {
1125         UnicodeString name;
1126         localesToTest[i].getDisplayName(Locale::getUS(), name);
1127         logln(name);
1128         if (name != englishDisplayNames[i])
1129         {
1130             dataerrln("Lookup in English failed: expected \"" + englishDisplayNames[i]
1131                         + "\", got \"" + name + "\"");
1132             logln("Locale name was-> " + (name=localesToTest[i].getName()));
1133         }
1134     }
1135 
1136     for (i = 0; i < 9; i++) {
1137         UnicodeString name;
1138         localesToTest[i].getDisplayName(Locale("es", "ES"), name);
1139         logln(name);
1140         if (name != spanishDisplayNames[i])
1141             dataerrln("Lookup in Spanish failed: expected \"" + spanishDisplayNames[i]
1142                         + "\", got \"" + name + "\"");
1143     }
1144 
1145     for (i = 0; i < 9; i++) {
1146         UnicodeString name;
1147         localesToTest[i].getDisplayName(Locale::getFrance(), name);
1148         logln(name);
1149         if (name != frenchDisplayNames[i])
1150             dataerrln("Lookup in French failed: expected \"" + frenchDisplayNames[i]
1151                         + "\", got \"" + name + "\"");
1152     }
1153 
1154     for (i = 0; i < 9; i++) {
1155         UnicodeString name;
1156         localesToTest[i].getDisplayName(Locale("inv", "IN"), name);
1157         logln(name + " Locale fallback to be, and data fallback to root");
1158         if (name != invDisplayNames[i])
1159             dataerrln("Lookup in INV failed: expected \"" + prettify(invDisplayNames[i])
1160                         + "\", got \"" + prettify(name) + "\"");
1161         localesToTest[i].getDisplayName(Locale("inv", "BD"), name);
1162         logln(name + " Data fallback to root");
1163         if (name != invDisplayNames[i])
1164             dataerrln("Lookup in INV failed: expected \"" + prettify(invDisplayNames[i])
1165                         + "\", got \"" + prettify(name )+ "\"");
1166     }
1167     Locale::setDefault(saveLocale, status);
1168 }
1169 
1170 #if !UCONFIG_NO_FORMATTING
1171 
1172 /**
1173  * @bug 4135752
1174  * This would be better tested by the LocaleDataTest.  Will move it when I
1175  * get the LocaleDataTest working again.
1176  */
1177 void
TestThaiCurrencyFormat()1178 LocaleTest::TestThaiCurrencyFormat()
1179 {
1180     UErrorCode status = U_ZERO_ERROR;
1181     DecimalFormat *thaiCurrency = (DecimalFormat*)NumberFormat::createCurrencyInstance(
1182                     Locale("th", "TH"), status);
1183     UnicodeString posPrefix(u"\u0E3F");
1184     UnicodeString temp;
1185 
1186     if(U_FAILURE(status) || !thaiCurrency)
1187     {
1188         dataerrln("Couldn't get th_TH currency -> " + UnicodeString(u_errorName(status)));
1189         return;
1190     }
1191     if (thaiCurrency->getPositivePrefix(temp) != posPrefix)
1192         errln("Thai currency prefix wrong: expected Baht sign, got \"" +
1193                         thaiCurrency->getPositivePrefix(temp) + "\"");
1194     if (thaiCurrency->getPositiveSuffix(temp) != "")
1195         errln("Thai currency suffix wrong: expected \"\", got \"" +
1196                         thaiCurrency->getPositiveSuffix(temp) + "\"");
1197 
1198     delete thaiCurrency;
1199 }
1200 
1201 /**
1202  * @bug 4122371
1203  * Confirm that Euro support works.  This test is pretty rudimentary; all it does
1204  * is check that any locales with the EURO variant format a number using the
1205  * Euro currency symbol.
1206  *
1207  * ASSUME: All locales encode the Euro character "\u20AC".
1208  * If this is changed to use the single-character Euro symbol, this
1209  * test must be updated.
1210  *
1211  */
1212 void
TestEuroSupport()1213 LocaleTest::TestEuroSupport()
1214 {
1215     UChar euro = 0x20ac;
1216     const UnicodeString EURO_CURRENCY(&euro, 1, 1); // Look for this UnicodeString in formatted Euro currency
1217     const char* localeArr[] = {
1218                             "ca_ES",
1219                             "de_AT",
1220                             "de_DE",
1221                             "de_LU",
1222                             "el_GR",
1223                             "en_BE",
1224                             "en_IE",
1225                             "en_GB@currency=EUR",
1226                             "en_US@currency=EUR",
1227                             "es_ES",
1228                             "eu_ES",
1229                             "fi_FI",
1230                             "fr_BE",
1231                             "fr_FR",
1232                             "fr_LU",
1233                             "ga_IE",
1234                             "gl_ES",
1235                             "it_IT",
1236                             "nl_BE",
1237                             "nl_NL",
1238                             "pt_PT",
1239                             NULL
1240                         };
1241     const char** locales = localeArr;
1242 
1243     UErrorCode status = U_ZERO_ERROR;
1244 
1245     UnicodeString temp;
1246 
1247     for (;*locales!=NULL;locales++) {
1248         Locale loc (*locales);
1249         UnicodeString temp;
1250         NumberFormat *nf = NumberFormat::createCurrencyInstance(loc, status);
1251         UnicodeString pos;
1252 
1253         if (U_FAILURE(status)) {
1254             dataerrln("Error calling NumberFormat::createCurrencyInstance(%s)", *locales);
1255             continue;
1256         }
1257 
1258         nf->format(271828.182845, pos);
1259         UnicodeString neg;
1260         nf->format(-271828.182845, neg);
1261         if (pos.indexOf(EURO_CURRENCY) >= 0 &&
1262             neg.indexOf(EURO_CURRENCY) >= 0) {
1263             logln("Ok: " + (temp=loc.getName()) +
1264                 ": " + pos + " / " + neg);
1265         }
1266         else {
1267             errln("Fail: " + (temp=loc.getName()) +
1268                 " formats without " + EURO_CURRENCY +
1269                 ": " + pos + " / " + neg +
1270                 "\n*** THIS FAILURE MAY ONLY MEAN THAT LOCALE DATA HAS CHANGED ***");
1271         }
1272 
1273         delete nf;
1274     }
1275 
1276     UnicodeString dollarStr("USD", ""), euroStr("EUR", ""), genericStr((UChar)0x00a4), resultStr;
1277     UChar tmp[4];
1278     status = U_ZERO_ERROR;
1279 
1280     ucurr_forLocale("en_US", tmp, 4, &status);
1281     resultStr.setTo(tmp);
1282     if (dollarStr != resultStr) {
1283         errcheckln(status, "Fail: en_US didn't return USD - %s", u_errorName(status));
1284     }
1285     ucurr_forLocale("en_US@currency=EUR", tmp, 4, &status);
1286     resultStr.setTo(tmp);
1287     if (euroStr != resultStr) {
1288         errcheckln(status, "Fail: en_US@currency=EUR didn't return EUR - %s", u_errorName(status));
1289     }
1290     ucurr_forLocale("en_GB@currency=EUR", tmp, 4, &status);
1291     resultStr.setTo(tmp);
1292     if (euroStr != resultStr) {
1293         errcheckln(status, "Fail: en_GB@currency=EUR didn't return EUR - %s", u_errorName(status));
1294     }
1295     ucurr_forLocale("en_US_Q", tmp, 4, &status);
1296     resultStr.setTo(tmp);
1297     if (dollarStr != resultStr) {
1298         errcheckln(status, "Fail: en_US_Q didn't fallback to en_US - %s", u_errorName(status));
1299     }
1300     int32_t invalidLen = ucurr_forLocale("en_QQ", tmp, 4, &status);
1301     if (invalidLen || U_SUCCESS(status)) {
1302         errln("Fail: en_QQ didn't return NULL");
1303     }
1304 
1305     // The currency keyword value is as long as the destination buffer.
1306     // It should detect the overflow internally, and default to the locale's currency.
1307     tmp[0] = u'¤';
1308     status = U_ZERO_ERROR;
1309     int32_t length = ucurr_forLocale("en_US@currency=euro", tmp, 4, &status);
1310     if (U_FAILURE(status) || dollarStr != UnicodeString(tmp, length)) {
1311         if (U_SUCCESS(status) && tmp[0] == u'¤') {
1312             errln("Fail: ucurr_forLocale(en_US@currency=euro) succeeded without writing output");
1313         } else {
1314             errln("Fail: ucurr_forLocale(en_US@currency=euro) != USD - %s", u_errorName(status));
1315         }
1316     }
1317 }
1318 
1319 #endif
1320 
1321 /**
1322  * @bug 4139504
1323  * toString() doesn't work with language_VARIANT.
1324  */
1325 void
TestToString()1326 LocaleTest::TestToString() {
1327     Locale DATA [] = {
1328         Locale("xx", "", ""),
1329         Locale("", "YY", ""),
1330         Locale("", "", "ZZ"),
1331         Locale("xx", "YY", ""),
1332         Locale("xx", "", "ZZ"),
1333         Locale("", "YY", "ZZ"),
1334         Locale("xx", "YY", "ZZ"),
1335     };
1336 
1337     const char DATA_S [][20] = {
1338         "xx",
1339         "_YY",
1340         "__ZZ",
1341         "xx_YY",
1342         "xx__ZZ",
1343         "_YY_ZZ",
1344         "xx_YY_ZZ",
1345     };
1346 
1347     for (int32_t i=0; i < 7; ++i) {
1348       const char *name;
1349       name = DATA[i].getName();
1350 
1351       if (strcmp(name, DATA_S[i]) != 0)
1352         {
1353             errln("Fail: Locale.getName(), got:" + UnicodeString(name) + ", expected: " + DATA_S[i]);
1354         }
1355         else
1356             logln("Pass: Locale.getName(), got:" + UnicodeString(name) );
1357     }
1358 }
1359 
1360 #if !UCONFIG_NO_FORMATTING
1361 
1362 /**
1363  * @bug 4139940
1364  * Couldn't reproduce this bug -- probably was fixed earlier.
1365  *
1366  * ORIGINAL BUG REPORT:
1367  * -- basically, hungarian for monday shouldn't have an \u00f4
1368  * (o circumflex)in it instead it should be an o with 2 inclined
1369  * (right) lines over it..
1370  *
1371  * You may wonder -- why do all this -- why not just add a line to
1372  * LocaleData?  Well, I could see by inspection that the locale file had the
1373  * right character in it, so I wanted to check the rest of the pipeline -- a
1374  * very remote possibility, but I wanted to be sure.  The other possibility
1375  * is that something is wrong with the font mapping subsystem, but we can't
1376  * test that here.
1377  */
1378 void
Test4139940()1379 LocaleTest::Test4139940()
1380 {
1381     Locale mylocale("hu", "", "");
1382     UDate mydate = date(98,3,13); // A Monday
1383     UErrorCode status = U_ZERO_ERROR;
1384     SimpleDateFormat df_full("EEEE", mylocale, status);
1385     if(U_FAILURE(status)){
1386         dataerrln(UnicodeString("Could not create SimpleDateFormat object for locale hu. Error: ") + UnicodeString(u_errorName(status)));
1387         return;
1388     }
1389     UnicodeString str;
1390     FieldPosition pos(FieldPosition::DONT_CARE);
1391     df_full.format(mydate, str, pos);
1392     // Make sure that o circumflex (\u00F4) is NOT there, and
1393     // o double acute (\u0151) IS.
1394     UChar ocf = 0x00f4;
1395     UChar oda = 0x0151;
1396     if (str.indexOf(oda) < 0 || str.indexOf(ocf) >= 0) {
1397       /* If the default locale is "th" this test will fail because of the buddhist calendar. */
1398       if (strcmp(Locale::getDefault().getLanguage(), "th") != 0) {
1399         errln("Fail: Monday in Hungarian is wrong - oda's index is %d and ocf's is %d",
1400               str.indexOf(oda), str.indexOf(ocf));
1401       } else {
1402         logln(UnicodeString("An error is produce in buddhist calendar."));
1403       }
1404       logln(UnicodeString("String is: ") + str );
1405     }
1406 }
1407 
1408 UDate
date(int32_t y,int32_t m,int32_t d,int32_t hr,int32_t min,int32_t sec)1409 LocaleTest::date(int32_t y, int32_t m, int32_t d, int32_t hr, int32_t min, int32_t sec)
1410 {
1411     UErrorCode status = U_ZERO_ERROR;
1412     Calendar *cal = Calendar::createInstance(status);
1413     if (cal == 0)
1414         return 0.0;
1415     cal->clear();
1416     cal->set(1900 + y, m, d, hr, min, sec); // Add 1900 to follow java.util.Date protocol
1417     UDate dt = cal->getTime(status);
1418     if (U_FAILURE(status))
1419         return 0.0;
1420 
1421     delete cal;
1422     return dt;
1423 }
1424 
1425 /**
1426  * @bug 4143951
1427  * Russian first day of week should be Monday. Confirmed.
1428  */
1429 void
Test4143951()1430 LocaleTest::Test4143951()
1431 {
1432     UErrorCode status = U_ZERO_ERROR;
1433     Calendar *cal = Calendar::createInstance(Locale("ru", "", ""), status);
1434     if(U_SUCCESS(status)) {
1435       if (cal->getFirstDayOfWeek(status) != UCAL_MONDAY) {
1436           dataerrln("Fail: First day of week in Russia should be Monday");
1437       }
1438     }
1439     delete cal;
1440 }
1441 
1442 #endif
1443 
1444 /**
1445  * @bug 4147315
1446  * java.util.Locale.getISO3Country() works wrong for non ISO-3166 codes.
1447  * Should throw an exception for unknown locales
1448  */
1449 void
Test4147315()1450 LocaleTest::Test4147315()
1451 {
1452   UnicodeString temp;
1453     // Try with codes that are the wrong length but happen to match text
1454     // at a valid offset in the mapping table
1455     Locale locale("xxx", "CCC");
1456 
1457     const char *result = locale.getISO3Country();
1458 
1459     // Change to conform to C api usage
1460     if((result==NULL)||(result[0] != 0))
1461       errln("ERROR: getISO3Country() returns: " + UnicodeString(result,"") +
1462                 " for locale '" + (temp=locale.getName()) + "' rather than exception" );
1463 }
1464 
1465 /**
1466  * @bug 4147317
1467  * java.util.Locale.getISO3Language() works wrong for non ISO-3166 codes.
1468  * Should throw an exception for unknown locales
1469  */
1470 void
Test4147317()1471 LocaleTest::Test4147317()
1472 {
1473     UnicodeString temp;
1474     // Try with codes that are the wrong length but happen to match text
1475     // at a valid offset in the mapping table
1476     Locale locale("xxx", "CCC");
1477 
1478     const char *result = locale.getISO3Language();
1479 
1480     // Change to conform to C api usage
1481     if((result==NULL)||(result[0] != 0))
1482       errln("ERROR: getISO3Language() returns: " + UnicodeString(result,"") +
1483                 " for locale '" + (temp=locale.getName()) + "' rather than exception" );
1484 }
1485 
1486 /*
1487  * @bug 4147552
1488  */
1489 void
Test4147552()1490 LocaleTest::Test4147552()
1491 {
1492     Locale locales [] = {     Locale("no", "NO"),
1493                             Locale("no", "NO", "B"),
1494                              Locale("no", "NO", "NY")
1495     };
1496 
1497     UnicodeString edn("Norwegian (Norway, B)");
1498     UnicodeString englishDisplayNames [] = {
1499                                                 "Norwegian (Norway)",
1500                                                  edn,
1501                                                  // "Norwegian (Norway,B)",
1502                                                  //"Norwegian (Norway,NY)"
1503                                                  "Norwegian (Norway, NY)"
1504     };
1505     UnicodeString ndn("norsk (Norge, B");
1506     UnicodeString norwegianDisplayNames [] = {
1507                                                 "norsk (Norge)",
1508                                                 "norsk (Norge, B)",
1509                                                 //ndn,
1510                                                  "norsk (Noreg, NY)"
1511                                                  //"Norsk (Noreg, Nynorsk)"
1512     };
1513     UErrorCode status = U_ZERO_ERROR;
1514 
1515     Locale saveLocale;
1516     Locale::setDefault(Locale::getEnglish(), status);
1517     for (int32_t i = 0; i < 3; ++i) {
1518         Locale loc = locales[i];
1519         UnicodeString temp;
1520         if (loc.getDisplayName(temp) != englishDisplayNames[i])
1521            dataerrln("English display-name mismatch: expected " +
1522                    englishDisplayNames[i] + ", got " + loc.getDisplayName(temp));
1523         if (loc.getDisplayName(loc, temp) != norwegianDisplayNames[i])
1524             dataerrln("Norwegian display-name mismatch: expected " +
1525                    norwegianDisplayNames[i] + ", got " +
1526                    loc.getDisplayName(loc, temp));
1527     }
1528     Locale::setDefault(saveLocale, status);
1529 }
1530 
1531 void
TestVariantParsing()1532 LocaleTest::TestVariantParsing()
1533 {
1534     Locale en_US_custom("en", "US", "De Anza_Cupertino_California_United States_Earth");
1535 
1536     UnicodeString dispName("English (United States, DE ANZA_CUPERTINO_CALIFORNIA_UNITED STATES_EARTH)");
1537     UnicodeString dispVar("DE ANZA_CUPERTINO_CALIFORNIA_UNITED STATES_EARTH");
1538 
1539     UnicodeString got;
1540 
1541     en_US_custom.getDisplayVariant(Locale::getUS(), got);
1542     if(got != dispVar) {
1543         errln("FAIL: getDisplayVariant()");
1544         errln("Wanted: " + dispVar);
1545         errln("Got   : " + got);
1546     }
1547 
1548     en_US_custom.getDisplayName(Locale::getUS(), got);
1549     if(got != dispName) {
1550         dataerrln("FAIL: getDisplayName()");
1551         dataerrln("Wanted: " + dispName);
1552         dataerrln("Got   : " + got);
1553     }
1554 
1555     Locale shortVariant("fr", "FR", "foo");
1556     shortVariant.getDisplayVariant(got);
1557 
1558     if(got != "FOO") {
1559         errln("FAIL: getDisplayVariant()");
1560         errln("Wanted: foo");
1561         errln("Got   : " + got);
1562     }
1563 
1564     Locale bogusVariant("fr", "FR", "_foo");
1565     bogusVariant.getDisplayVariant(got);
1566 
1567     if(got != "FOO") {
1568         errln("FAIL: getDisplayVariant()");
1569         errln("Wanted: foo");
1570         errln("Got   : " + got);
1571     }
1572 
1573     Locale bogusVariant2("fr", "FR", "foo_");
1574     bogusVariant2.getDisplayVariant(got);
1575 
1576     if(got != "FOO") {
1577         errln("FAIL: getDisplayVariant()");
1578         errln("Wanted: foo");
1579         errln("Got   : " + got);
1580     }
1581 
1582     Locale bogusVariant3("fr", "FR", "_foo_");
1583     bogusVariant3.getDisplayVariant(got);
1584 
1585     if(got != "FOO") {
1586         errln("FAIL: getDisplayVariant()");
1587         errln("Wanted: foo");
1588         errln("Got   : " + got);
1589     }
1590 }
1591 
Test20639_DeprecatesISO3Language()1592 void LocaleTest::Test20639_DeprecatesISO3Language() {
1593     IcuTestErrorCode status(*this, "Test20639_DeprecatesISO3Language");
1594 
1595     const struct TestCase {
1596         const char* localeName;
1597         const char* expectedISO3Language;
1598     } cases[] = {
1599         {"nb", "nob"},
1600         {"no", "nor"}, // why not nob?
1601         {"he", "heb"},
1602         {"iw", "heb"},
1603         {"ro", "ron"},
1604         {"mo", "mol"},
1605     };
1606     for (auto& cas : cases) {
1607         Locale loc(cas.localeName);
1608         const char* actual = loc.getISO3Language();
1609         assertEquals(cas.localeName, cas.expectedISO3Language, actual);
1610     }
1611 }
1612 
1613 #if !UCONFIG_NO_FORMATTING
1614 
1615 /**
1616  * @bug 4105828
1617  * Currency symbol in zh is wrong.  We will test this at the NumberFormat
1618  * end to test the whole pipe.
1619  */
1620 void
Test4105828()1621 LocaleTest::Test4105828()
1622 {
1623     Locale LOC [] = { Locale::getChinese(),  Locale("zh", "CN", ""),
1624                      Locale("zh", "TW", ""), Locale("zh", "HK", "") };
1625     UErrorCode status = U_ZERO_ERROR;
1626     for (int32_t i = 0; i < 4; ++i) {
1627         NumberFormat *fmt = NumberFormat::createPercentInstance(LOC[i], status);
1628         if(U_FAILURE(status)) {
1629             dataerrln("Couldn't create NumberFormat - %s", u_errorName(status));
1630             return;
1631         }
1632         UnicodeString result;
1633         FieldPosition pos(FieldPosition::DONT_CARE);
1634         fmt->format((int32_t)1, result, pos);
1635         UnicodeString temp;
1636         if(result != "100%") {
1637             errln(UnicodeString("Percent for ") + LOC[i].getDisplayName(temp) + " should be 100%, got " + result);
1638         }
1639         delete fmt;
1640     }
1641 }
1642 
1643 #endif
1644 
1645 // Tests setBogus and isBogus APIs for Locale
1646 // Jitterbug 1735
1647 void
TestSetIsBogus()1648 LocaleTest::TestSetIsBogus() {
1649     Locale l("en_US");
1650     l.setToBogus();
1651     if(l.isBogus() != TRUE) {
1652         errln("After setting bogus, didn't return TRUE");
1653     }
1654     l = "en_US"; // This should reset bogus
1655     if(l.isBogus() != FALSE) {
1656         errln("After resetting bogus, didn't return FALSE");
1657     }
1658 }
1659 
1660 
1661 void
TestAddLikelySubtags()1662 LocaleTest::TestAddLikelySubtags() {
1663     IcuTestErrorCode status(*this, "TestAddLikelySubtags()");
1664 
1665     static const Locale min("sv");
1666     static const Locale max("sv_Latn_SE");
1667 
1668     Locale result(min);
1669     result.addLikelySubtags(status);
1670     status.errIfFailureAndReset("\"%s\"", min.getName());
1671     assertEquals("addLikelySubtags", max.getName(), result.getName());
1672 }
1673 
1674 
1675 void
TestMinimizeSubtags()1676 LocaleTest::TestMinimizeSubtags() {
1677     IcuTestErrorCode status(*this, "TestMinimizeSubtags()");
1678 
1679     static const Locale max("zh_Hant_TW");
1680     static const Locale min("zh_TW");
1681 
1682     Locale result(max);
1683     result.minimizeSubtags(status);
1684     status.errIfFailureAndReset("\"%s\"", max.getName());
1685     assertEquals("minimizeSubtags", min.getName(), result.getName());
1686 }
1687 
1688 
1689 void
TestAddLikelyAndMinimizeSubtags()1690 LocaleTest::TestAddLikelyAndMinimizeSubtags() {
1691     IcuTestErrorCode status(*this, "TestAddLikelyAndMinimizeSubtags()");
1692 
1693     static const struct {
1694         const char* const from;
1695         const char* const add;
1696         const char* const remove;
1697     } full_data[] = {
1698         {
1699             "und_AQ",
1700             "_Latn_AQ",
1701             "_AQ"
1702         }, {
1703             "und_Zzzz_AQ",
1704             "_Latn_AQ",
1705             "_AQ"
1706         }, {
1707             "und_Latn_AQ",
1708             "_Latn_AQ",
1709             "_AQ"
1710         }, {
1711             "und_Moon_AQ",
1712             "_Moon_AQ",
1713             "_Moon_AQ"
1714         },
1715     };
1716 
1717     for (const auto& item : full_data) {
1718         const char* const org = item.from;
1719         const char* const exp = item.add;
1720         Locale res(org);
1721         res.addLikelySubtags(status);
1722         status.errIfFailureAndReset("\"%s\"", org);
1723         assertEquals("addLikelySubtags", exp, res.getName());
1724     }
1725 
1726     for (const auto& item : full_data) {
1727         const char* const org = item.from;
1728         const char* const exp = item.remove;
1729         Locale res(org);
1730         res.minimizeSubtags(status);
1731         status.errIfFailureAndReset("\"%s\"", org);
1732         assertEquals("minimizeSubtags", exp, res.getName());
1733     }
1734 }
1735 
1736 
1737 void
TestKeywordVariants(void)1738 LocaleTest::TestKeywordVariants(void) {
1739     static const struct {
1740         const char *localeID;
1741         const char *expectedLocaleID;
1742         //const char *expectedLocaleIDNoKeywords;
1743         //const char *expectedCanonicalID;
1744         const char *expectedKeywords[10];
1745         int32_t numKeywords;
1746         UErrorCode expectedStatus;
1747     } testCases[] = {
1748         {
1749             "de_DE@  currency = euro; C o ll A t i o n   = Phonebook   ; C alen dar = buddhist   ",
1750             "de_DE@calendar=buddhist;collation=Phonebook;currency=euro",
1751             //"de_DE",
1752             //"de_DE@calendar=buddhist;collation=Phonebook;currency=euro",
1753             {"calendar", "collation", "currency"},
1754             3,
1755             U_ZERO_ERROR
1756         },
1757         {
1758             "de_DE@euro",
1759             "de_DE@euro",
1760             //"de_DE",
1761             //"de_DE@currency=EUR",
1762             {"","","","","","",""},
1763             0,
1764             U_INVALID_FORMAT_ERROR /* must have '=' after '@' */
1765         }
1766     };
1767     UErrorCode status = U_ZERO_ERROR;
1768 
1769     int32_t i = 0, j = 0;
1770     const char *result = NULL;
1771     StringEnumeration *keywords;
1772     int32_t keyCount = 0;
1773     const char *keyword = NULL;
1774     const UnicodeString *keywordString;
1775     int32_t keywordLen = 0;
1776 
1777     for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
1778         status = U_ZERO_ERROR;
1779         Locale l(testCases[i].localeID);
1780         keywords = l.createKeywords(status);
1781 
1782         if(status != testCases[i].expectedStatus) {
1783             err("Expected to get status %s. Got %s instead\n",
1784                 u_errorName(testCases[i].expectedStatus), u_errorName(status));
1785         }
1786         status = U_ZERO_ERROR;
1787         if(keywords) {
1788             if((keyCount = keywords->count(status)) != testCases[i].numKeywords) {
1789                 err("Expected to get %i keywords, got %i\n", testCases[i].numKeywords, keyCount);
1790             }
1791             if(keyCount) {
1792                 for(j = 0;;) {
1793                     if((j&1)==0) {
1794                         if((keyword = keywords->next(&keywordLen, status)) == NULL) {
1795                             break;
1796                         }
1797                         if(strcmp(keyword, testCases[i].expectedKeywords[j]) != 0) {
1798                             err("Expected to get keyword value %s, got %s\n", testCases[i].expectedKeywords[j], keyword);
1799                         }
1800                     } else {
1801                         if((keywordString = keywords->snext(status)) == NULL) {
1802                             break;
1803                         }
1804                         if(*keywordString != UnicodeString(testCases[i].expectedKeywords[j], "")) {
1805                             err("Expected to get keyword UnicodeString %s, got %s\n", testCases[i].expectedKeywords[j], keyword);
1806                         }
1807                     }
1808                     j++;
1809 
1810                     if(j == keyCount / 2) {
1811                         // replace keywords with a clone of itself
1812                         StringEnumeration *k2 = keywords->clone();
1813                         if(k2 == NULL || keyCount != k2->count(status)) {
1814                             errln("KeywordEnumeration.clone() failed");
1815                         } else {
1816                             delete keywords;
1817                             keywords = k2;
1818                         }
1819                     }
1820                 }
1821                 keywords->reset(status); // Make sure that reset works.
1822                 for(j = 0;;) {
1823                     if((keyword = keywords->next(&keywordLen, status)) == NULL) {
1824                         break;
1825                     }
1826                     if(strcmp(keyword, testCases[i].expectedKeywords[j]) != 0) {
1827                         err("Expected to get keyword value %s, got %s\n", testCases[i].expectedKeywords[j], keyword);
1828                     }
1829                     j++;
1830                 }
1831             }
1832             delete keywords;
1833         }
1834         result = l.getName();
1835         if(uprv_strcmp(testCases[i].expectedLocaleID, result) != 0) {
1836             err("Expected to get \"%s\" from \"%s\". Got \"%s\" instead\n",
1837                 testCases[i].expectedLocaleID, testCases[i].localeID, result);
1838         }
1839 
1840     }
1841 
1842 }
1843 
1844 
1845 void
TestCreateUnicodeKeywords(void)1846 LocaleTest::TestCreateUnicodeKeywords(void) {
1847     IcuTestErrorCode status(*this, "TestCreateUnicodeKeywords()");
1848 
1849     static const Locale l("de@calendar=buddhist;collation=phonebook");
1850 
1851     LocalPointer<StringEnumeration> keys(l.createUnicodeKeywords(status));
1852     status.errIfFailureAndReset("\"%s\"", l.getName());
1853 
1854     const char* key;
1855     int32_t resultLength;
1856 
1857     key = keys->next(&resultLength, status);
1858     status.errIfFailureAndReset("key #1");
1859     assertEquals("resultLength", 2, resultLength);
1860     assertTrue("key != nullptr", key != nullptr);
1861     if (key != nullptr) {
1862         assertEquals("calendar", "ca", key);
1863     }
1864 
1865     key = keys->next(&resultLength, status);
1866     status.errIfFailureAndReset("key #2");
1867     assertEquals("resultLength", 2, resultLength);
1868     assertTrue("key != nullptr", key != nullptr);
1869     if (key != nullptr) {
1870         assertEquals("collation", "co", key);
1871     }
1872 
1873     key = keys->next(&resultLength, status);
1874     status.errIfFailureAndReset("end of keys");
1875     assertEquals("resultLength", 0, resultLength);
1876     assertTrue("key == nullptr", key == nullptr);
1877 
1878     const UnicodeString* skey;
1879     keys->reset(status);  // KeywordEnumeration::reset() never touches status.
1880 
1881     skey = keys->snext(status);
1882     status.errIfFailureAndReset("skey #1");
1883     assertTrue("skey != nullptr", skey != nullptr);
1884     if (skey != nullptr) {
1885         assertEquals("calendar", "ca", *skey);
1886     }
1887 
1888     skey = keys->snext(status);
1889     status.errIfFailureAndReset("skey #2");
1890     assertTrue("skey != nullptr", skey != nullptr);
1891     if (skey != nullptr) {
1892         assertEquals("collation", "co", *skey);
1893     }
1894 
1895     skey = keys->snext(status);
1896     status.errIfFailureAndReset("end of keys");
1897     assertTrue("skey == nullptr", skey == nullptr);
1898 }
1899 
1900 
1901 void
TestKeywordVariantParsing(void)1902 LocaleTest::TestKeywordVariantParsing(void) {
1903     static const struct {
1904         const char *localeID;
1905         const char *keyword;
1906         const char *expectedValue;
1907     } testCases[] = {
1908         { "de_DE@  C o ll A t i o n   = Phonebook   ", "collation", "Phonebook" },
1909         { "de_DE", "collation", ""},
1910         { "de_DE@collation= PHONEBOOK", "collation", "PHONEBOOK" },
1911         { "de_DE@ currency = euro   ; CoLLaTion   = PHONEBOOk   ", "collation", "PHONEBOOk" },
1912     };
1913 
1914     UErrorCode status = U_ZERO_ERROR;
1915 
1916     int32_t i = 0;
1917     int32_t resultLen = 0;
1918     char buffer[256];
1919 
1920     for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
1921         *buffer = 0;
1922         Locale l(testCases[i].localeID);
1923         resultLen = l.getKeywordValue(testCases[i].keyword, buffer, 256, status);
1924         (void)resultLen;  // Suppress unused variable warning.
1925         if(uprv_strcmp(testCases[i].expectedValue, buffer) != 0) {
1926             err("Expected to extract \"%s\" from \"%s\" for keyword \"%s\". Got \"%s\" instead\n",
1927                 testCases[i].expectedValue, testCases[i].localeID, testCases[i].keyword, buffer);
1928         }
1929     }
1930 }
1931 
1932 void
TestCreateKeywordSet(void)1933 LocaleTest::TestCreateKeywordSet(void) {
1934     IcuTestErrorCode status(*this, "TestCreateKeywordSet()");
1935 
1936     static const Locale l("de@calendar=buddhist;collation=phonebook");
1937 
1938     std::set<std::string> result;
1939     l.getKeywords<std::string>(
1940             std::insert_iterator<decltype(result)>(result, result.begin()),
1941             status);
1942     status.errIfFailureAndReset("\"%s\"", l.getName());
1943 
1944     assertEquals("set::size()", 2, static_cast<int32_t>(result.size()));
1945     assertTrue("set::find(\"calendar\")",
1946                result.find("calendar") != result.end());
1947     assertTrue("set::find(\"collation\")",
1948                result.find("collation") != result.end());
1949 }
1950 
1951 void
TestCreateKeywordSetEmpty(void)1952 LocaleTest::TestCreateKeywordSetEmpty(void) {
1953     IcuTestErrorCode status(*this, "TestCreateKeywordSetEmpty()");
1954 
1955     static const Locale l("de");
1956 
1957     std::set<std::string> result;
1958     l.getKeywords<std::string>(
1959             std::insert_iterator<decltype(result)>(result, result.begin()),
1960             status);
1961     status.errIfFailureAndReset("\"%s\"", l.getName());
1962 
1963     assertEquals("set::size()", 0, static_cast<int32_t>(result.size()));
1964 }
1965 
1966 void
TestCreateUnicodeKeywordSet(void)1967 LocaleTest::TestCreateUnicodeKeywordSet(void) {
1968     IcuTestErrorCode status(*this, "TestCreateUnicodeKeywordSet()");
1969 
1970     static const Locale l("de@calendar=buddhist;collation=phonebook");
1971 
1972     std::set<std::string> result;
1973     l.getUnicodeKeywords<std::string>(
1974             std::insert_iterator<decltype(result)>(result, result.begin()),
1975             status);
1976     status.errIfFailureAndReset("\"%s\"", l.getName());
1977 
1978     assertEquals("set::size()", 2, static_cast<int32_t>(result.size()));
1979     assertTrue("set::find(\"ca\")",
1980                result.find("ca") != result.end());
1981     assertTrue("set::find(\"co\")",
1982                result.find("co") != result.end());
1983 }
1984 
1985 void
TestCreateUnicodeKeywordSetEmpty(void)1986 LocaleTest::TestCreateUnicodeKeywordSetEmpty(void) {
1987     IcuTestErrorCode status(*this, "TestCreateUnicodeKeywordSetEmpty()");
1988 
1989     static const Locale l("de");
1990 
1991     std::set<std::string> result;
1992     l.getUnicodeKeywords<std::string>(
1993             std::insert_iterator<decltype(result)>(result, result.begin()),
1994             status);
1995     status.errIfFailureAndReset("\"%s\"", l.getName());
1996 
1997     assertEquals("set::size()", 0, static_cast<int32_t>(result.size()));
1998 }
1999 
2000 void
TestGetKeywordValueStdString(void)2001 LocaleTest::TestGetKeywordValueStdString(void) {
2002     IcuTestErrorCode status(*this, "TestGetKeywordValueStdString()");
2003 
2004     static const char tag[] = "fa-u-nu-latn";
2005     static const char keyword[] = "numbers";
2006     static const char expected[] = "latn";
2007 
2008     Locale l = Locale::forLanguageTag(tag, status);
2009     status.errIfFailureAndReset("\"%s\"", tag);
2010 
2011     std::string result = l.getKeywordValue<std::string>(keyword, status);
2012     status.errIfFailureAndReset("\"%s\"", keyword);
2013     assertEquals(keyword, expected, result.c_str());
2014 }
2015 
2016 void
TestGetUnicodeKeywordValueStdString(void)2017 LocaleTest::TestGetUnicodeKeywordValueStdString(void) {
2018     IcuTestErrorCode status(*this, "TestGetUnicodeKeywordValueStdString()");
2019 
2020     static const char keyword[] = "co";
2021     static const char expected[] = "phonebk";
2022 
2023     static const Locale l("de@calendar=buddhist;collation=phonebook");
2024 
2025     std::string result = l.getUnicodeKeywordValue<std::string>(keyword, status);
2026     status.errIfFailureAndReset("\"%s\"", keyword);
2027     assertEquals(keyword, expected, result.c_str());
2028 }
2029 
2030 void
TestSetKeywordValue(void)2031 LocaleTest::TestSetKeywordValue(void) {
2032     static const struct {
2033         const char *keyword;
2034         const char *value;
2035     } testCases[] = {
2036         { "collation", "phonebook" },
2037         { "currency", "euro" },
2038         { "calendar", "buddhist" }
2039     };
2040 
2041     UErrorCode status = U_ZERO_ERROR;
2042 
2043     int32_t i = 0;
2044     int32_t resultLen = 0;
2045     char buffer[256];
2046 
2047     Locale l(Locale::getGerman());
2048 
2049     for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
2050         l.setKeywordValue(testCases[i].keyword, testCases[i].value, status);
2051         if(U_FAILURE(status)) {
2052             err("FAIL: Locale::setKeywordValue failed - %s\n", u_errorName(status));
2053         }
2054 
2055         *buffer = 0;
2056         resultLen = l.getKeywordValue(testCases[i].keyword, buffer, 256, status);
2057         (void)resultLen;  // Suppress unused variable warning.
2058         if(uprv_strcmp(testCases[i].value, buffer) != 0) {
2059             err("Expected to extract \"%s\" for keyword \"%s\". Got \"%s\" instead\n",
2060                 testCases[i].value, testCases[i].keyword, buffer);
2061         }
2062     }
2063 }
2064 
2065 void
TestSetKeywordValueStringPiece(void)2066 LocaleTest::TestSetKeywordValueStringPiece(void) {
2067     IcuTestErrorCode status(*this, "TestSetKeywordValueStringPiece()");
2068     Locale l(Locale::getGerman());
2069 
2070     l.setKeywordValue(StringPiece("collation"), StringPiece("phonebook"), status);
2071     l.setKeywordValue(StringPiece("calendarxxx", 8), StringPiece("buddhistxxx", 8), status);
2072 
2073     static const char expected[] = "de@calendar=buddhist;collation=phonebook";
2074     assertEquals("", expected, l.getName());
2075 }
2076 
2077 void
TestSetUnicodeKeywordValueStringPiece(void)2078 LocaleTest::TestSetUnicodeKeywordValueStringPiece(void) {
2079     IcuTestErrorCode status(*this, "TestSetUnicodeKeywordValueStringPiece()");
2080     Locale l(Locale::getGerman());
2081 
2082     l.setUnicodeKeywordValue(StringPiece("co"), StringPiece("phonebk"), status);
2083     status.errIfFailureAndReset();
2084 
2085     l.setUnicodeKeywordValue(StringPiece("caxxx", 2), StringPiece("buddhistxxx", 8), status);
2086     status.errIfFailureAndReset();
2087 
2088     static const char expected[] = "de@calendar=buddhist;collation=phonebook";
2089     assertEquals("", expected, l.getName());
2090 
2091     l.setUnicodeKeywordValue("cu", nullptr, status);
2092     status.errIfFailureAndReset();
2093     assertEquals("", expected, l.getName());
2094 
2095     l.setUnicodeKeywordValue("!!", nullptr, status);
2096     assertEquals("status", U_ILLEGAL_ARGUMENT_ERROR, status.reset());
2097     assertEquals("", expected, l.getName());
2098 
2099     l.setUnicodeKeywordValue("co", "!!", status);
2100     assertEquals("status", U_ILLEGAL_ARGUMENT_ERROR, status.reset());
2101     assertEquals("", expected, l.getName());
2102 
2103     l.setUnicodeKeywordValue("co", nullptr, status);
2104     status.errIfFailureAndReset();
2105 
2106     l.setUnicodeKeywordValue("ca", "", status);
2107     status.errIfFailureAndReset();
2108 
2109     assertEquals("", Locale::getGerman().getName(), l.getName());
2110 }
2111 
2112 void
TestGetBaseName(void)2113 LocaleTest::TestGetBaseName(void) {
2114     static const struct {
2115         const char *localeID;
2116         const char *baseName;
2117     } testCases[] = {
2118         { "de_DE@  C o ll A t i o n   = Phonebook   ", "de_DE" },
2119         { "de@currency = euro; CoLLaTion   = PHONEBOOk", "de" },
2120         { "ja@calendar = buddhist", "ja" },
2121         { "de-u-co-phonebk", "de"}
2122     };
2123 
2124     int32_t i = 0;
2125 
2126     for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
2127         Locale loc(testCases[i].localeID);
2128         if(strcmp(testCases[i].baseName, loc.getBaseName())) {
2129             errln("For locale \"%s\" expected baseName \"%s\", but got \"%s\"",
2130                 testCases[i].localeID, testCases[i].baseName, loc.getBaseName());
2131             return;
2132         }
2133     }
2134 
2135     // Verify that adding a keyword to an existing Locale doesn't change the base name.
2136     UErrorCode status = U_ZERO_ERROR;
2137     Locale loc2("en-US");
2138     if (strcmp("en_US", loc2.getBaseName())) {
2139         errln("%s:%d Expected \"en_US\", got \"%s\"", __FILE__, __LINE__, loc2.getBaseName());
2140     }
2141     loc2.setKeywordValue("key", "value", status);
2142     if (strcmp("en_US@key=value", loc2.getName())) {
2143         errln("%s:%d Expected \"en_US@key=value\", got \"%s\"", __FILE__, __LINE__, loc2.getName());
2144     }
2145     if (strcmp("en_US", loc2.getBaseName())) {
2146         errln("%s:%d Expected \"en_US\", got \"%s\"", __FILE__, __LINE__, loc2.getBaseName());
2147     }
2148 }
2149 
2150 /**
2151  * Compare two locale IDs.  If they are equal, return 0.  If `string'
2152  * starts with `prefix' plus an additional element, that is, string ==
2153  * prefix + '_' + x, then return 1.  Otherwise return a value < 0.
2154  */
_loccmp(const char * string,const char * prefix)2155 static UBool _loccmp(const char* string, const char* prefix) {
2156     int32_t slen = (int32_t)strlen(string),
2157             plen = (int32_t)strlen(prefix);
2158     int32_t c = uprv_strncmp(string, prefix, plen);
2159     /* 'root' is "less than" everything */
2160     if (prefix[0] == '\0') {
2161         return string[0] != '\0';
2162     }
2163     if (c) return -1; /* mismatch */
2164     if (slen == plen) return 0;
2165     if (string[plen] == '_') return 1;
2166     return -2; /* false match, e.g. "en_USX" cmp "en_US" */
2167 }
2168 
2169 /**
2170  * Check the relationship between requested locales, and report problems.
2171  * The caller specifies the expected relationships between requested
2172  * and valid (expReqValid) and between valid and actual (expValidActual).
2173  * Possible values are:
2174  * "gt" strictly greater than, e.g., en_US > en
2175  * "ge" greater or equal,      e.g., en >= en
2176  * "eq" equal,                 e.g., en == en
2177  */
_checklocs(const char * label,const char * req,const Locale & validLoc,const Locale & actualLoc,const char * expReqValid,const char * expValidActual)2178 void LocaleTest::_checklocs(const char* label,
2179                             const char* req,
2180                             const Locale& validLoc,
2181                             const Locale& actualLoc,
2182                             const char* expReqValid,
2183                             const char* expValidActual) {
2184     const char* valid = validLoc.getName();
2185     const char* actual = actualLoc.getName();
2186     int32_t reqValid = _loccmp(req, valid);
2187     int32_t validActual = _loccmp(valid, actual);
2188     if (((0 == uprv_strcmp(expReqValid, "gt") && reqValid > 0) ||
2189          (0 == uprv_strcmp(expReqValid, "ge") && reqValid >= 0) ||
2190          (0 == uprv_strcmp(expReqValid, "eq") && reqValid == 0)) &&
2191         ((0 == uprv_strcmp(expValidActual, "gt") && validActual > 0) ||
2192          (0 == uprv_strcmp(expValidActual, "ge") && validActual >= 0) ||
2193          (0 == uprv_strcmp(expValidActual, "eq") && validActual == 0))) {
2194         logln("%s; req=%s, valid=%s, actual=%s",
2195               label, req, valid, actual);
2196     } else {
2197         dataerrln("FAIL: %s; req=%s, valid=%s, actual=%s.  Require (R %s V) and (V %s A)",
2198               label, req, valid, actual,
2199               expReqValid, expValidActual);
2200     }
2201 }
2202 
TestGetLocale(void)2203 void LocaleTest::TestGetLocale(void) {
2204 #if !UCONFIG_NO_SERVICE
2205     const char *req;
2206     Locale valid, actual, reqLoc;
2207 
2208     // Calendar
2209 #if !UCONFIG_NO_FORMATTING
2210     {
2211         UErrorCode ec = U_ZERO_ERROR;  // give each resource type its own error code
2212         req = "en_US_BROOKLYN";
2213         Calendar* cal = Calendar::createInstance(Locale::createFromName(req), ec);
2214         if (U_FAILURE(ec)) {
2215             dataerrln("FAIL: Calendar::createInstance failed - %s", u_errorName(ec));
2216         } else {
2217             valid = cal->getLocale(ULOC_VALID_LOCALE, ec);
2218             actual = cal->getLocale(ULOC_ACTUAL_LOCALE, ec);
2219             if (U_FAILURE(ec)) {
2220                 errln("FAIL: Calendar::getLocale() failed");
2221             } else {
2222                 _checklocs("Calendar", req, valid, actual);
2223             }
2224             /* Make sure that it fails correctly */
2225             ec = U_FILE_ACCESS_ERROR;
2226             if (cal->getLocale(ULOC_VALID_LOCALE, ec).getName()[0] != 0) {
2227                 errln("FAIL: Calendar::getLocale() failed to fail correctly. It should have returned \"\"");
2228             }
2229             ec = U_ZERO_ERROR;
2230         }
2231         delete cal;
2232     }
2233 #endif
2234 
2235     // DecimalFormat, DecimalFormatSymbols
2236 #if !UCONFIG_NO_FORMATTING
2237     {
2238         UErrorCode ec = U_ZERO_ERROR;  // give each resource type its own error code
2239         req = "fr_FR_NICE";
2240         NumberFormat* nf = NumberFormat::createInstance(Locale::createFromName(req), ec);
2241         if (U_FAILURE(ec)) {
2242             dataerrln("FAIL: NumberFormat::createInstance failed - %s", u_errorName(ec));
2243         } else {
2244             DecimalFormat* dec = dynamic_cast<DecimalFormat*>(nf);
2245             if (dec == NULL) {
2246                 errln("FAIL: NumberFormat::createInstance does not return a DecimalFormat");
2247                 return;
2248             }
2249             valid = dec->getLocale(ULOC_VALID_LOCALE, ec);
2250             actual = dec->getLocale(ULOC_ACTUAL_LOCALE, ec);
2251             if (U_FAILURE(ec)) {
2252                 errln("FAIL: DecimalFormat::getLocale() failed");
2253             } else {
2254                 _checklocs("DecimalFormat", req, valid, actual);
2255             }
2256 
2257             const DecimalFormatSymbols* sym = dec->getDecimalFormatSymbols();
2258             if (sym == NULL) {
2259                 errln("FAIL: getDecimalFormatSymbols returned NULL");
2260                 return;
2261             }
2262             valid = sym->getLocale(ULOC_VALID_LOCALE, ec);
2263             actual = sym->getLocale(ULOC_ACTUAL_LOCALE, ec);
2264             if (U_FAILURE(ec)) {
2265                 errln("FAIL: DecimalFormatSymbols::getLocale() failed");
2266             } else {
2267                 _checklocs("DecimalFormatSymbols", req, valid, actual);
2268             }
2269         }
2270         delete nf;
2271     }
2272 #endif
2273 
2274     // DateFormat, DateFormatSymbols
2275 #if !UCONFIG_NO_FORMATTING
2276     {
2277         UErrorCode ec = U_ZERO_ERROR;  // give each resource type its own error code
2278         req = "de_CH_LUCERNE";
2279         DateFormat* df =
2280             DateFormat::createDateInstance(DateFormat::kDefault,
2281                                            Locale::createFromName(req));
2282         if (df == 0){
2283             dataerrln("Error calling DateFormat::createDateInstance()");
2284         } else {
2285             SimpleDateFormat* dat = dynamic_cast<SimpleDateFormat*>(df);
2286             if (dat == NULL) {
2287                 errln("FAIL: DateFormat::createInstance does not return a SimpleDateFormat");
2288                 return;
2289             }
2290             valid = dat->getLocale(ULOC_VALID_LOCALE, ec);
2291             actual = dat->getLocale(ULOC_ACTUAL_LOCALE, ec);
2292             if (U_FAILURE(ec)) {
2293                 errln("FAIL: SimpleDateFormat::getLocale() failed");
2294             } else {
2295                 _checklocs("SimpleDateFormat", req, valid, actual);
2296             }
2297 
2298             const DateFormatSymbols* sym = dat->getDateFormatSymbols();
2299             if (sym == NULL) {
2300                 errln("FAIL: getDateFormatSymbols returned NULL");
2301                 return;
2302             }
2303             valid = sym->getLocale(ULOC_VALID_LOCALE, ec);
2304             actual = sym->getLocale(ULOC_ACTUAL_LOCALE, ec);
2305             if (U_FAILURE(ec)) {
2306                 errln("FAIL: DateFormatSymbols::getLocale() failed");
2307             } else {
2308                 _checklocs("DateFormatSymbols", req, valid, actual);
2309             }
2310         }
2311         delete df;
2312     }
2313 #endif
2314 
2315     // BreakIterator
2316 #if !UCONFIG_NO_BREAK_ITERATION
2317     {
2318         UErrorCode ec = U_ZERO_ERROR;  // give each resource type its own error code
2319         req = "es_ES_BARCELONA";
2320         reqLoc = Locale::createFromName(req);
2321         BreakIterator* brk = BreakIterator::createWordInstance(reqLoc, ec);
2322         if (U_FAILURE(ec)) {
2323             dataerrln("FAIL: BreakIterator::createWordInstance failed - %s", u_errorName(ec));
2324         } else {
2325             valid = brk->getLocale(ULOC_VALID_LOCALE, ec);
2326             actual = brk->getLocale(ULOC_ACTUAL_LOCALE, ec);
2327             if (U_FAILURE(ec)) {
2328                 errln("FAIL: BreakIterator::getLocale() failed");
2329             } else {
2330                 _checklocs("BreakIterator", req, valid, actual);
2331             }
2332 
2333             // After registering something, the behavior should be different
2334             URegistryKey key = BreakIterator::registerInstance(brk, reqLoc, UBRK_WORD, ec);
2335             brk = 0; // registerInstance adopts
2336             if (U_FAILURE(ec)) {
2337                 errln("FAIL: BreakIterator::registerInstance() failed");
2338             } else {
2339                 brk = BreakIterator::createWordInstance(reqLoc, ec);
2340                 if (U_FAILURE(ec)) {
2341                     errln("FAIL: BreakIterator::createWordInstance failed");
2342                 } else {
2343                     valid = brk->getLocale(ULOC_VALID_LOCALE, ec);
2344                     actual = brk->getLocale(ULOC_ACTUAL_LOCALE, ec);
2345                     if (U_FAILURE(ec)) {
2346                         errln("FAIL: BreakIterator::getLocale() failed");
2347                     } else {
2348                         // N.B.: now expect valid==actual==req
2349                         _checklocs("BreakIterator(registered)",
2350                                    req, valid, actual, "eq", "eq");
2351                     }
2352                 }
2353                 // No matter what, unregister
2354                 BreakIterator::unregister(key, ec);
2355                 if (U_FAILURE(ec)) {
2356                     errln("FAIL: BreakIterator::unregister() failed");
2357                 }
2358                 delete brk;
2359                 brk = 0;
2360             }
2361 
2362             // After unregistering, should behave normally again
2363             brk = BreakIterator::createWordInstance(reqLoc, ec);
2364             if (U_FAILURE(ec)) {
2365                 errln("FAIL: BreakIterator::createWordInstance failed");
2366             } else {
2367                 valid = brk->getLocale(ULOC_VALID_LOCALE, ec);
2368                 actual = brk->getLocale(ULOC_ACTUAL_LOCALE, ec);
2369                 if (U_FAILURE(ec)) {
2370                     errln("FAIL: BreakIterator::getLocale() failed");
2371                 } else {
2372                     _checklocs("BreakIterator(unregistered)", req, valid, actual);
2373                 }
2374             }
2375         }
2376         delete brk;
2377     }
2378 #endif
2379 
2380     // Collator
2381 #if !UCONFIG_NO_COLLATION
2382     {
2383         UErrorCode ec = U_ZERO_ERROR;  // give each resource type its own error code
2384 
2385         checkRegisteredCollators(NULL); // Don't expect any extras
2386 
2387         req = "hi_IN_BHOPAL";
2388         reqLoc = Locale::createFromName(req);
2389         Collator* coll = Collator::createInstance(reqLoc, ec);
2390         if (U_FAILURE(ec)) {
2391             dataerrln("FAIL: Collator::createInstance failed - %s", u_errorName(ec));
2392         } else {
2393             valid = coll->getLocale(ULOC_VALID_LOCALE, ec);
2394             actual = coll->getLocale(ULOC_ACTUAL_LOCALE, ec);
2395             if (U_FAILURE(ec)) {
2396                 errln("FAIL: Collator::getLocale() failed");
2397             } else {
2398                 _checklocs("Collator", req, valid, actual);
2399             }
2400 
2401             // After registering something, the behavior should be different
2402             URegistryKey key = Collator::registerInstance(coll, reqLoc, ec);
2403             coll = 0; // registerInstance adopts
2404             if (U_FAILURE(ec)) {
2405                 errln("FAIL: Collator::registerInstance() failed");
2406             } else {
2407                 coll = Collator::createInstance(reqLoc, ec);
2408                 if (U_FAILURE(ec)) {
2409                     errln("FAIL: Collator::createWordInstance failed");
2410                 } else {
2411                     valid = coll->getLocale(ULOC_VALID_LOCALE, ec);
2412                     actual = coll->getLocale(ULOC_ACTUAL_LOCALE, ec);
2413                     if (U_FAILURE(ec)) {
2414                         errln("FAIL: Collator::getLocale() failed");
2415                     } else {
2416                         // N.B.: now expect valid==actual==req
2417                         _checklocs("Collator(registered)",
2418                                    req, valid, actual, "eq", "eq");
2419                     }
2420                 }
2421                 checkRegisteredCollators(req); // include hi_IN_BHOPAL
2422 
2423                 // No matter what, unregister
2424                 Collator::unregister(key, ec);
2425                 if (U_FAILURE(ec)) {
2426                     errln("FAIL: Collator::unregister() failed");
2427                 }
2428                 delete coll;
2429                 coll = 0;
2430             }
2431 
2432             // After unregistering, should behave normally again
2433             coll = Collator::createInstance(reqLoc, ec);
2434             if (U_FAILURE(ec)) {
2435                 errln("FAIL: Collator::createInstance failed");
2436             } else {
2437                 valid = coll->getLocale(ULOC_VALID_LOCALE, ec);
2438                 actual = coll->getLocale(ULOC_ACTUAL_LOCALE, ec);
2439                 if (U_FAILURE(ec)) {
2440                     errln("FAIL: Collator::getLocale() failed");
2441                 } else {
2442                     _checklocs("Collator(unregistered)", req, valid, actual);
2443                 }
2444             }
2445         }
2446         delete coll;
2447 
2448         checkRegisteredCollators(NULL); // extra should be gone again
2449     }
2450 #endif
2451 #endif
2452 }
2453 
2454 #if !UCONFIG_NO_COLLATION
2455 /**
2456  * Compare Collator::getAvailableLocales(int) [ "old", returning an array ]
2457  *   with  Collator::getAvailableLocales()    [ "new", returning a StringEnumeration ]
2458  * These should be identical (check their API docs) EXCEPT that
2459  * if expectExtra is non-NULL, it will be in the "new" array but not "old".
2460  * Does not return any status but calls errln on error.
2461  * @param expectExtra an extra locale, will be in "new" but not "old". Or NULL.
2462  */
checkRegisteredCollators(const char * expectExtra)2463 void LocaleTest::checkRegisteredCollators(const char *expectExtra) {
2464     UErrorCode status = U_ZERO_ERROR;
2465     int32_t count1=0,count2=0;
2466     Hashtable oldHash(status);
2467     Hashtable newHash(status);
2468     assertSuccess(WHERE, status);
2469 
2470     UnicodeString expectStr(expectExtra?expectExtra:"n/a", "");
2471 
2472     // the 'old' list (non enumeration)
2473     const Locale*  oldList = Collator::getAvailableLocales(count1);
2474     if(oldList == NULL) {
2475         dataerrln("Error: Collator::getAvailableLocales(count) returned NULL");
2476         return;
2477     }
2478 
2479     // the 'new' list (enumeration)
2480     LocalPointer<StringEnumeration> newEnum(Collator::getAvailableLocales());
2481     if(newEnum.isNull()) {
2482        errln("Error: collator::getAvailableLocales() returned NULL");
2483        return;
2484     }
2485 
2486     // OK. Let's add all of the OLD
2487     // then check for any in the NEW not in OLD
2488     // then check for any in OLD not in NEW.
2489 
2490     // 1. add all of OLD
2491     for(int32_t i=0;i<count1;i++) {
2492         const UnicodeString key(oldList[i].getName(), "");
2493         int32_t oldI = oldHash.puti(key, 1, status);
2494         if( oldI == 1 ){
2495             errln("Error: duplicate key %s in Collator::getAvailableLocales(count) list.\n",
2496                 oldList[i].getName());
2497             return;
2498         }
2499         if(expectExtra != NULL && !strcmp(expectExtra, oldList[i].getName())) {
2500             errln("Inexplicably, Collator::getAvailableCollators(count) had registered collator %s. This shouldn't happen, so I am going to consider it an error.\n", expectExtra);
2501         }
2502     }
2503 
2504     // 2. add all of NEW
2505     const UnicodeString *locStr;
2506     UBool foundExpected = FALSE;
2507     while((locStr = newEnum->snext(status)) && U_SUCCESS(status)) {
2508         count2++;
2509 
2510         if(expectExtra != NULL && expectStr == *locStr) {
2511             foundExpected = TRUE;
2512             logln(UnicodeString("Found expected registered collator: ","") + expectStr);
2513         }
2514         (void)foundExpected;    // Hush unused variable compiler warning.
2515 
2516         if( oldHash.geti(*locStr) == 0 ) {
2517             if(expectExtra != NULL && expectStr==*locStr) {
2518                 logln(UnicodeString("As expected, Collator::getAvailableLocales(count) is missing registered collator ") + expectStr);
2519             } else {
2520                 errln(UnicodeString("Error: Collator::getAvailableLocales(count) is missing: ","")
2521                     + *locStr);
2522             }
2523         }
2524         newHash.puti(*locStr, 1, status);
2525     }
2526 
2527     // 3. check all of OLD again
2528     for(int32_t i=0;i<count1;i++) {
2529         const UnicodeString key(oldList[i].getName(), "");
2530         int32_t newI = newHash.geti(key);
2531         if(newI == 0) {
2532             errln(UnicodeString("Error: Collator::getAvailableLocales() is missing: ","")
2533                 + key);
2534         }
2535     }
2536 
2537     int32_t expectCount2 = count1;
2538     if(expectExtra != NULL) {
2539         expectCount2 ++; // if an extra item registered, bump the expect count
2540     }
2541 
2542     assertEquals("Collator::getAvail() count", expectCount2, count2);
2543 }
2544 #endif
2545 
2546 
2547 
TestVariantWithOutCountry(void)2548 void LocaleTest::TestVariantWithOutCountry(void) {
2549     Locale loc("en","","POSIX");
2550     if (0 != strcmp(loc.getVariant(), "POSIX")) {
2551         errln("FAIL: en__POSIX didn't get parsed correctly - name is %s - expected %s got %s", loc.getName(), "POSIX", loc.getVariant());
2552     }
2553     Locale loc2("en","","FOUR");
2554     if (0 != strcmp(loc2.getVariant(), "FOUR")) {
2555         errln("FAIL: en__FOUR didn't get parsed correctly - name is %s - expected %s got %s", loc2.getName(), "FOUR", loc2.getVariant());
2556     }
2557     Locale loc3("en","Latn","","FOUR");
2558     if (0 != strcmp(loc3.getVariant(), "FOUR")) {
2559         errln("FAIL: en_Latn__FOUR didn't get parsed correctly - name is %s - expected %s got %s", loc3.getName(), "FOUR", loc3.getVariant());
2560     }
2561     Locale loc4("","Latn","","FOUR");
2562     if (0 != strcmp(loc4.getVariant(), "FOUR")) {
2563         errln("FAIL: _Latn__FOUR didn't get parsed correctly - name is %s - expected %s got %s", loc4.getName(), "FOUR", loc4.getVariant());
2564     }
2565     Locale loc5("","Latn","US","FOUR");
2566     if (0 != strcmp(loc5.getVariant(), "FOUR")) {
2567         errln("FAIL: _Latn_US_FOUR didn't get parsed correctly - name is %s - expected %s got %s", loc5.getName(), "FOUR", loc5.getVariant());
2568     }
2569     Locale loc6("de-1901");
2570     if (0 != strcmp(loc6.getVariant(), "1901")) {
2571         errln("FAIL: de-1901 didn't get parsed correctly - name is %s - expected %s got %s", loc6.getName(), "1901", loc6.getVariant());
2572     }
2573 }
2574 
_canonicalize(int32_t selector,const char * localeID)2575 static Locale _canonicalize(int32_t selector, /* 0==createFromName, 1==createCanonical, 2==Locale ct */
2576                             const char* localeID) {
2577     switch (selector) {
2578     case 0:
2579         return Locale::createFromName(localeID);
2580     case 1:
2581         return Locale::createCanonical(localeID);
2582     case 2:
2583         return Locale(localeID);
2584     default:
2585         return Locale("");
2586     }
2587 }
2588 
TestCanonicalization(void)2589 void LocaleTest::TestCanonicalization(void)
2590 {
2591     static const struct {
2592         const char *localeID;    /* input */
2593         const char *getNameID;   /* expected getName() result */
2594         const char *canonicalID; /* expected canonicalize() result */
2595     } testCases[] = {
2596         { "ca_ES-with-extra-stuff-that really doesn't make any sense-unless-you're trying to increase code coverage",
2597           "ca_ES_WITH_EXTRA_STUFF_THAT REALLY DOESN'T MAKE ANY SENSE_UNLESS_YOU'RE TRYING TO INCREASE CODE COVERAGE",
2598           "ca_ES_WITH_EXTRA_STUFF_THAT REALLY DOESN'T MAKE ANY SENSE_UNLESS_YOU'RE TRYING TO INCREASE CODE COVERAGE"},
2599         { "zh@collation=pinyin", "zh@collation=pinyin", "zh@collation=pinyin" },
2600         { "zh_CN@collation=pinyin", "zh_CN@collation=pinyin", "zh_Hans_CN@collation=pinyin" },
2601         { "zh_CN_CA@collation=pinyin", "zh_CN_CA@collation=pinyin", "zh_Hans_CN_CA@collation=pinyin" },
2602         { "en_US_POSIX", "en_US_POSIX", "en_US_POSIX" },
2603         { "hy_AM_REVISED", "hy_AM_REVISED", "hy_AM_REVISED" },
2604         { "no_NO_NY", "no_NO_NY", "nb_NO_NY" /* not: "nn_NO" [alan ICU3.0] */ },
2605         { "no@ny", "no@ny", "nb__NY" /* not: "nn" [alan ICU3.0] */ }, /* POSIX ID */
2606         { "no-no.utf32@B", "no_NO.utf32@B", "nb_NO_B" /* not: "nb_NO_B" [alan ICU3.0] */ }, /* POSIX ID */
2607         { "qz-qz@Euro", "qz_QZ@Euro", "qz_QZ_EURO" }, /* qz-qz uses private use iso codes */
2608         // NOTE: uloc_getName() works on en-BOONT, but Locale() parser considers it BOGUS
2609         // TODO: unify this behavior
2610         { "en-BOONT", "en__BOONT", "en__BOONT" }, /* registered name */
2611         { "de-1901", "de__1901", "de__1901" }, /* registered name */
2612         { "de-1906", "de__1906", "de__1906" }, /* registered name */
2613 
2614         /* posix behavior that used to be performed by getName */
2615         { "mr.utf8", "mr.utf8", "mr" },
2616         { "de-tv.koi8r", "de_TV.koi8r", "de_TV" },
2617         { "x-piglatin_ML.MBE", "x-piglatin_ML.MBE", "x-piglatin_ML" },
2618         { "i-cherokee_US.utf7", "i-cherokee_US.utf7", "i-cherokee_US" },
2619         { "x-filfli_MT_FILFLA.gb-18030", "x-filfli_MT_FILFLA.gb-18030", "x-filfli_MT_FILFLA" },
2620         { "no-no-ny.utf8@B", "no_NO_NY.utf8@B", "nb_NO_NY_B" /* not: "nn_NO" [alan ICU3.0] */ }, /* @ ignored unless variant is empty */
2621 
2622         /* fleshing out canonicalization */
2623         /* trim space and sort keywords, ';' is separator so not present at end in canonical form */
2624         { "en_Hant_IL_VALLEY_GIRL@ currency = EUR; calendar = Japanese ;", "en_Hant_IL_VALLEY_GIRL@calendar=Japanese;currency=EUR", "en_Hant_IL_VALLEY_GIRL@calendar=Japanese;currency=EUR" },
2625         /* already-canonical ids are not changed */
2626         { "en_Hant_IL_VALLEY_GIRL@calendar=Japanese;currency=EUR", "en_Hant_IL_VALLEY_GIRL@calendar=Japanese;currency=EUR", "en_Hant_IL_VALLEY_GIRL@calendar=Japanese;currency=EUR" },
2627         /* norwegian is just too weird, if we handle things in their full generality */
2628         { "no-Hant-GB_NY@currency=$$$", "no_Hant_GB_NY@currency=$$$", "nb_Hant_GB_NY@currency=$$$" /* not: "nn_Hant_GB@currency=$$$" [alan ICU3.0] */ },
2629 
2630         /* test cases reflecting internal resource bundle usage */
2631         { "root@kw=foo", "root@kw=foo", "root@kw=foo" },
2632         { "@calendar=gregorian", "@calendar=gregorian", "@calendar=gregorian" },
2633         { "ja_JP@calendar=Japanese", "ja_JP@calendar=Japanese", "ja_JP@calendar=Japanese" },
2634 
2635         // Before ICU 64, ICU locale canonicalization had some additional mappings.
2636         // They were removed for ICU-20187 "drop support for long-obsolete locale ID variants".
2637         // The following now use standard canonicalization.
2638         { "", "", "" },
2639         { "C", "c", "c" },
2640         { "POSIX", "posix", "posix" },
2641         { "ca_ES_PREEURO", "ca_ES_PREEURO", "ca_ES_PREEURO" },
2642         { "de_AT_PREEURO", "de_AT_PREEURO", "de_AT_PREEURO" },
2643         { "de_DE_PREEURO", "de_DE_PREEURO", "de_DE_PREEURO" },
2644         { "de_LU_PREEURO", "de_LU_PREEURO", "de_LU_PREEURO" },
2645         { "el_GR_PREEURO", "el_GR_PREEURO", "el_GR_PREEURO" },
2646         { "en_BE_PREEURO", "en_BE_PREEURO", "en_BE_PREEURO" },
2647         { "en_IE_PREEURO", "en_IE_PREEURO", "en_IE_PREEURO" },
2648         { "es_ES_PREEURO", "es_ES_PREEURO", "es_ES_PREEURO" },
2649         { "eu_ES_PREEURO", "eu_ES_PREEURO", "eu_ES_PREEURO" },
2650         { "fi_FI_PREEURO", "fi_FI_PREEURO", "fi_FI_PREEURO" },
2651         { "fr_BE_PREEURO", "fr_BE_PREEURO", "fr_BE_PREEURO" },
2652         { "fr_FR_PREEURO", "fr_FR_PREEURO", "fr_FR_PREEURO" },
2653         { "fr_LU_PREEURO", "fr_LU_PREEURO", "fr_LU_PREEURO" },
2654         { "ga_IE_PREEURO", "ga_IE_PREEURO", "ga_IE_PREEURO" },
2655         { "gl_ES_PREEURO", "gl_ES_PREEURO", "gl_ES_PREEURO" },
2656         { "it_IT_PREEURO", "it_IT_PREEURO", "it_IT_PREEURO" },
2657         { "nl_BE_PREEURO", "nl_BE_PREEURO", "nl_BE_PREEURO" },
2658         { "nl_NL_PREEURO", "nl_NL_PREEURO", "nl_NL_PREEURO" },
2659         { "pt_PT_PREEURO", "pt_PT_PREEURO", "pt_PT_PREEURO" },
2660         { "de__PHONEBOOK", "de__PHONEBOOK", "de__PHONEBOOK" },
2661         { "en_GB_EURO", "en_GB_EURO", "en_GB_EURO" },
2662         { "en_GB@EURO", "en_GB@EURO", "en_GB_EURO" }, /* POSIX ID */
2663         { "es__TRADITIONAL", "es__TRADITIONAL", "es__TRADITIONAL" },
2664         { "hi__DIRECT", "hi__DIRECT", "hi__DIRECT" },
2665         { "ja_JP_TRADITIONAL", "ja_JP_TRADITIONAL", "ja_JP_TRADITIONAL" },
2666         { "th_TH_TRADITIONAL", "th_TH_TRADITIONAL", "th_TH_TRADITIONAL" },
2667         { "zh_TW_STROKE", "zh_TW_STROKE", "zh_Hant_TW_STROKE" },
2668         { "zh__PINYIN", "zh__PINYIN", "zh__PINYIN" },
2669         { "sr-SP-Cyrl", "sr_SP_CYRL", "sr_SP_CYRL" }, /* .NET name */
2670         { "sr-SP-Latn", "sr_SP_LATN", "sr_SP_LATN" }, /* .NET name */
2671         { "sr_YU_CYRILLIC", "sr_YU_CYRILLIC", "sr_RS_CYRILLIC" }, /* Linux name */
2672         { "uz-UZ-Cyrl", "uz_UZ_CYRL", "uz_Latn_UZ_CYRL" }, /* .NET name */
2673         { "uz-UZ-Latn", "uz_UZ_LATN", "uz_Latn_UZ_LATN" }, /* .NET name */
2674         { "zh-CHS", "zh_CHS", "zh_CHS" }, /* .NET name */
2675         { "zh-CHT", "zh_CHT", "zh_CHT" }, /* .NET name This may change back to zh_Hant */
2676         /* PRE_EURO and EURO conversions don't affect other keywords */
2677         { "es_ES_PREEURO@CALendar=Japanese", "es_ES_PREEURO@calendar=Japanese", "es_ES_PREEURO@calendar=Japanese" },
2678         { "es_ES_EURO@SHOUT=zipeedeedoodah", "es_ES_EURO@shout=zipeedeedoodah", "es_ES_EURO@shout=zipeedeedoodah" },
2679         /* currency keyword overrides PRE_EURO and EURO currency */
2680         { "es_ES_PREEURO@currency=EUR", "es_ES_PREEURO@currency=EUR", "es_ES_PREEURO@currency=EUR" },
2681         { "es_ES_EURO@currency=ESP", "es_ES_EURO@currency=ESP", "es_ES_EURO@currency=ESP" },
2682     };
2683 
2684     static const char* label[] = { "createFromName", "createCanonical", "Locale" };
2685 
2686     int32_t i, j;
2687 
2688     for (i=0; i < UPRV_LENGTHOF(testCases); i++) {
2689         for (j=0; j<3; ++j) {
2690             const char* expected = (j==1) ? testCases[i].canonicalID : testCases[i].getNameID;
2691             Locale loc = _canonicalize(j, testCases[i].localeID);
2692             const char* getName = loc.isBogus() ? "BOGUS" : loc.getName();
2693             if(uprv_strcmp(expected, getName) != 0) {
2694                 errln("FAIL: %s(%s).getName() => \"%s\", expected \"%s\"",
2695                       label[j], testCases[i].localeID, getName, expected);
2696             } else {
2697                 logln("Ok: %s(%s) => \"%s\"",
2698                       label[j], testCases[i].localeID, getName);
2699             }
2700         }
2701     }
2702 }
2703 
TestCanonicalize(void)2704 void LocaleTest::TestCanonicalize(void)
2705 {
2706     static const struct {
2707         const char *localeID;    /* input */
2708         const char *canonicalID; /* expected canonicalize() result */
2709     } testCases[] = {
2710         // language _ variant -> language
2711         { "no-BOKMAL", "nb" },
2712         // also test with script, country and extensions
2713         { "no-Cyrl-ID-BOKMAL-u-ca-japanese", "nb-Cyrl-ID-u-ca-japanese" },
2714         { "no-Cyrl-ID-1901-BOKMAL-xsistemo-u-ca-japanese", "nb-Cyrl-ID-1901-xsistemo-u-ca-japanese" },
2715         { "no-Cyrl-ID-1901-BOKMAL-u-ca-japanese", "nb-Cyrl-ID-1901-u-ca-japanese" },
2716         { "no-Cyrl-ID-BOKMAL-xsistemo-u-ca-japanese", "nb-Cyrl-ID-xsistemo-u-ca-japanese" },
2717         { "no-NYNORSK", "nn" },
2718         { "no-Cyrl-ID-NYNORSK-u-ca-japanese", "nn-Cyrl-ID-u-ca-japanese" },
2719         { "aa-SAAHO", "ssy" },
2720         // also test with script, country and extensions
2721         { "aa-Deva-IN-SAAHO-u-ca-japanese", "ssy-Deva-IN-u-ca-japanese" },
2722 
2723         // language -> language
2724         { "aam", "aas" },
2725         // also test with script, country, variants and extensions
2726         { "aam-Cyrl-ID-3456-u-ca-japanese", "aas-Cyrl-ID-3456-u-ca-japanese" },
2727 
2728         // language -> language _ Script
2729         { "sh", "sr-Latn" },
2730         // also test with script
2731         { "sh-Cyrl", "sr-Cyrl" },
2732         // also test with country, variants and extensions
2733         { "sh-ID-3456-u-ca-roc", "sr-Latn-ID-3456-u-ca-roc" },
2734 
2735         // language -> language _ country
2736         { "prs", "fa-AF" },
2737         // also test with country
2738         { "prs-RU", "fa-RU" },
2739         // also test with script, variants and extensions
2740         { "prs-Cyrl-1009-u-ca-roc", "fa-Cyrl-AF-1009-u-ca-roc" },
2741 
2742         //  language _ country -> language _ script _ country
2743         { "pa-IN", "pa-Guru-IN" },
2744         // also test with script
2745         { "pa-Latn-IN", "pa-Latn-IN" },
2746         // also test with variants and extensions
2747         { "pa-IN-5678-u-ca-hindi", "pa-Guru-IN-5678-u-ca-hindi" },
2748 
2749         //  language _ script _ country -> language _ country
2750         { "ky-Cyrl-KG", "ky-KG" },
2751         // also test with variants and extensions
2752         { "ky-Cyrl-KG-3456-u-ca-roc", "ky-KG-3456-u-ca-roc" },
2753 
2754         // Test replacement of territoryAlias
2755         // 554 has one replacement
2756         { "en-554", "en-NZ" },
2757         { "en-554-u-nu-arab", "en-NZ-u-nu-arab" },
2758         // 172 has multiple replacements
2759         // also test with variants
2760         { "ru-172-1234", "ru-RU-1234" },
2761         // also test with extensions
2762         { "ru-172-1234-u-nu-latn", "ru-RU-1234-u-nu-latn" },
2763         // also test with scripts
2764         { "uz-172", "uz-UZ" },
2765         { "uz-Cyrl-172", "uz-Cyrl-UZ" },
2766         { "uz-Bopo-172", "uz-Bopo-UZ" },
2767         // also test with variants and scripts
2768         { "uz-Cyrl-172-5678-u-nu-latn", "uz-Cyrl-UZ-5678-u-nu-latn" },
2769         // a language not used in this region
2770         { "fr-172", "fr-RU" },
2771     };
2772     int32_t i;
2773     for (i=0; i < UPRV_LENGTHOF(testCases); i++) {
2774         UErrorCode status = U_ZERO_ERROR;
2775         std::string otag = testCases[i].localeID;
2776         Locale loc = Locale::forLanguageTag(otag.c_str(), status);
2777         loc.canonicalize(status);
2778         std::string tag = loc.toLanguageTag<std::string>(status);
2779         if (tag != testCases[i].canonicalID) {
2780             errcheckln(status, "FAIL: %s should be canonicalized to %s but got %s - %s",
2781                        otag.c_str(),
2782                        testCases[i].canonicalID,
2783                        tag.c_str(),
2784                        u_errorName(status));
2785         }
2786     }
2787 }
2788 
TestCurrencyByDate(void)2789 void LocaleTest::TestCurrencyByDate(void)
2790 {
2791 #if !UCONFIG_NO_FORMATTING
2792     UErrorCode status = U_ZERO_ERROR;
2793     UDate date = uprv_getUTCtime();
2794 	UChar TMP[4] = {0, 0, 0, 0};
2795 	int32_t index = 0;
2796 	int32_t resLen = 0;
2797     UnicodeString tempStr, resultStr;
2798 
2799 	// Cycle through historical currencies
2800     date = (UDate)-630720000000.0; // pre 1961 - no currency defined
2801     index = ucurr_countCurrencies("eo_AM", date, &status);
2802     if (index != 0)
2803 	{
2804 		errcheckln(status, "FAIL: didn't return 0 for eo_AM - %s", u_errorName(status));
2805 	}
2806     resLen = ucurr_forLocaleAndDate("eo_AM", date, index, TMP, 4, &status);
2807     if (resLen != 0) {
2808 		errcheckln(status, "FAIL: eo_AM didn't return NULL - %s", u_errorName(status));
2809     }
2810     status = U_ZERO_ERROR;
2811 
2812     date = (UDate)0.0; // 1970 - one currency defined
2813     index = ucurr_countCurrencies("eo_AM", date, &status);
2814     if (index != 1)
2815 	{
2816 		errcheckln(status, "FAIL: didn't return 1 for eo_AM - %s", u_errorName(status));
2817 	}
2818     resLen = ucurr_forLocaleAndDate("eo_AM", date, index, TMP, 4, &status);
2819 	tempStr.setTo(TMP);
2820     resultStr.setTo("SUR");
2821     if (resultStr != tempStr) {
2822         errcheckln(status, "FAIL: didn't return SUR for eo_AM - %s", u_errorName(status));
2823     }
2824 
2825     date = (UDate)693792000000.0; // 1992 - one currency defined
2826 	index = ucurr_countCurrencies("eo_AM", date, &status);
2827     if (index != 1)
2828 	{
2829 		errcheckln(status, "FAIL: didn't return 1 for eo_AM - %s", u_errorName(status));
2830 	}
2831     resLen = ucurr_forLocaleAndDate("eo_AM", date, index, TMP, 4, &status);
2832 	tempStr.setTo(TMP);
2833     resultStr.setTo("RUR");
2834     if (resultStr != tempStr) {
2835         errcheckln(status, "FAIL: didn't return RUR for eo_AM - %s", u_errorName(status));
2836     }
2837 
2838 	date = (UDate)977616000000.0; // post 1993 - one currency defined
2839 	index = ucurr_countCurrencies("eo_AM", date, &status);
2840     if (index != 1)
2841 	{
2842 		errcheckln(status, "FAIL: didn't return 1 for eo_AM - %s", u_errorName(status));
2843 	}
2844     resLen = ucurr_forLocaleAndDate("eo_AM", date, index, TMP, 4, &status);
2845 	tempStr.setTo(TMP);
2846     resultStr.setTo("AMD");
2847     if (resultStr != tempStr) {
2848         errcheckln(status, "FAIL: didn't return AMD for eo_AM - %s", u_errorName(status));
2849     }
2850 
2851     // Locale AD has multiple currencies at once
2852 	date = (UDate)977616000000.0; // year 2001
2853 	index = ucurr_countCurrencies("eo_AD", date, &status);
2854     if (index != 4)
2855 	{
2856 		errcheckln(status, "FAIL: didn't return 4 for eo_AD - %s", u_errorName(status));
2857 	}
2858     resLen = ucurr_forLocaleAndDate("eo_AD", date, 1, TMP, 4, &status);
2859 	tempStr.setTo(TMP);
2860     resultStr.setTo("EUR");
2861     if (resultStr != tempStr) {
2862         errcheckln(status, "FAIL: didn't return EUR for eo_AD - %s", u_errorName(status));
2863     }
2864     resLen = ucurr_forLocaleAndDate("eo_AD", date, 2, TMP, 4, &status);
2865 	tempStr.setTo(TMP);
2866     resultStr.setTo("ESP");
2867     if (resultStr != tempStr) {
2868         errcheckln(status, "FAIL: didn't return ESP for eo_AD - %s", u_errorName(status));
2869     }
2870     resLen = ucurr_forLocaleAndDate("eo_AD", date, 3, TMP, 4, &status);
2871 	tempStr.setTo(TMP);
2872     resultStr.setTo("FRF");
2873     if (resultStr != tempStr) {
2874         errcheckln(status, "FAIL: didn't return FRF for eo_AD - %s", u_errorName(status));
2875     }
2876     resLen = ucurr_forLocaleAndDate("eo_AD", date, 4, TMP, 4, &status);
2877 	tempStr.setTo(TMP);
2878     resultStr.setTo("ADP");
2879     if (resultStr != tempStr) {
2880         errcheckln(status, "FAIL: didn't return ADP for eo_AD - %s", u_errorName(status));
2881     }
2882 
2883 	date = (UDate)0.0; // year 1970
2884 	index = ucurr_countCurrencies("eo_AD", date, &status);
2885     if (index != 3)
2886 	{
2887 		errcheckln(status, "FAIL: didn't return 3 for eo_AD - %s", u_errorName(status));
2888 	}
2889     resLen = ucurr_forLocaleAndDate("eo_AD", date, 1, TMP, 4, &status);
2890 	tempStr.setTo(TMP);
2891     resultStr.setTo("ESP");
2892     if (resultStr != tempStr) {
2893         errcheckln(status, "FAIL: didn't return ESP for eo_AD - %s", u_errorName(status));
2894     }
2895     resLen = ucurr_forLocaleAndDate("eo_AD", date, 2, TMP, 4, &status);
2896 	tempStr.setTo(TMP);
2897     resultStr.setTo("FRF");
2898     if (resultStr != tempStr) {
2899         errcheckln(status, "FAIL: didn't return FRF for eo_AD - %s", u_errorName(status));
2900     }
2901     resLen = ucurr_forLocaleAndDate("eo_AD", date, 3, TMP, 4, &status);
2902 	tempStr.setTo(TMP);
2903     resultStr.setTo("ADP");
2904     if (resultStr != tempStr) {
2905         errcheckln(status, "FAIL: didn't return ADP for eo_AD - %s", u_errorName(status));
2906     }
2907 
2908 	date = (UDate)-630720000000.0; // year 1950
2909 	index = ucurr_countCurrencies("eo_AD", date, &status);
2910     if (index != 2)
2911 	{
2912 		errcheckln(status, "FAIL: didn't return 2 for eo_AD - %s", u_errorName(status));
2913 	}
2914     resLen = ucurr_forLocaleAndDate("eo_AD", date, 1, TMP, 4, &status);
2915 	tempStr.setTo(TMP);
2916     resultStr.setTo("ESP");
2917     if (resultStr != tempStr) {
2918         errcheckln(status, "FAIL: didn't return ESP for eo_AD - %s", u_errorName(status));
2919     }
2920     resLen = ucurr_forLocaleAndDate("eo_AD", date, 2, TMP, 4, &status);
2921 	tempStr.setTo(TMP);
2922     resultStr.setTo("ADP");
2923     if (resultStr != tempStr) {
2924         errcheckln(status, "FAIL: didn't return ADP for eo_AD - %s", u_errorName(status));
2925     }
2926 
2927 	date = (UDate)-2207520000000.0; // year 1900
2928 	index = ucurr_countCurrencies("eo_AD", date, &status);
2929     if (index != 1)
2930 	{
2931 		errcheckln(status, "FAIL: didn't return 1 for eo_AD - %s", u_errorName(status));
2932 	}
2933     resLen = ucurr_forLocaleAndDate("eo_AD", date, 1, TMP, 4, &status);
2934 	tempStr.setTo(TMP);
2935     resultStr.setTo("ESP");
2936     if (resultStr != tempStr) {
2937         errcheckln(status, "FAIL: didn't return ESP for eo_AD - %s", u_errorName(status));
2938     }
2939 
2940 	// Locale UA has gap between years 1994 - 1996
2941 	date = (UDate)788400000000.0;
2942 	index = ucurr_countCurrencies("eo_UA", date, &status);
2943     if (index != 0)
2944 	{
2945 		errcheckln(status, "FAIL: didn't return 0 for eo_UA - %s", u_errorName(status));
2946 	}
2947     resLen = ucurr_forLocaleAndDate("eo_UA", date, index, TMP, 4, &status);
2948     if (resLen != 0) {
2949 		errcheckln(status, "FAIL: eo_UA didn't return NULL - %s", u_errorName(status));
2950     }
2951     status = U_ZERO_ERROR;
2952 
2953 	// Test index bounds
2954     resLen = ucurr_forLocaleAndDate("eo_UA", date, 100, TMP, 4, &status);
2955     if (resLen != 0) {
2956 		errcheckln(status, "FAIL: eo_UA didn't return NULL - %s", u_errorName(status));
2957     }
2958     status = U_ZERO_ERROR;
2959 
2960     resLen = ucurr_forLocaleAndDate("eo_UA", date, 0, TMP, 4, &status);
2961     if (resLen != 0) {
2962 		errcheckln(status, "FAIL: eo_UA didn't return NULL - %s", u_errorName(status));
2963     }
2964     status = U_ZERO_ERROR;
2965 
2966 	// Test for bogus locale
2967 	index = ucurr_countCurrencies("eo_QQ", date, &status);
2968     if (index != 0)
2969 	{
2970 		errcheckln(status, "FAIL: didn't return 0 for eo_QQ - %s", u_errorName(status));
2971 	}
2972     status = U_ZERO_ERROR;
2973     resLen = ucurr_forLocaleAndDate("eo_QQ", date, 1, TMP, 4, &status);
2974     if (resLen != 0) {
2975 		errcheckln(status, "FAIL: eo_QQ didn't return NULL - %s", u_errorName(status));
2976     }
2977     status = U_ZERO_ERROR;
2978     resLen = ucurr_forLocaleAndDate("eo_QQ", date, 0, TMP, 4, &status);
2979     if (resLen != 0) {
2980 		errcheckln(status, "FAIL: eo_QQ didn't return NULL - %s", u_errorName(status));
2981     }
2982     status = U_ZERO_ERROR;
2983 
2984     // Cycle through histrocial currencies
2985 	date = (UDate)977616000000.0; // 2001 - one currency
2986 	index = ucurr_countCurrencies("eo_AO", date, &status);
2987     if (index != 1)
2988 	{
2989 		errcheckln(status, "FAIL: didn't return 1 for eo_AO - %s", u_errorName(status));
2990 	}
2991     resLen = ucurr_forLocaleAndDate("eo_AO", date, 1, TMP, 4, &status);
2992 	tempStr.setTo(TMP);
2993     resultStr.setTo("AOA");
2994     if (resultStr != tempStr) {
2995         errcheckln(status, "FAIL: didn't return AOA for eo_AO - %s", u_errorName(status));
2996     }
2997 
2998 	date = (UDate)819936000000.0; // 1996 - 2 currencies
2999 	index = ucurr_countCurrencies("eo_AO", date, &status);
3000     if (index != 2)
3001 	{
3002 		errcheckln(status, "FAIL: didn't return 1 for eo_AO - %s", u_errorName(status));
3003 	}
3004     resLen = ucurr_forLocaleAndDate("eo_AO", date, 1, TMP, 4, &status);
3005 	tempStr.setTo(TMP);
3006     resultStr.setTo("AOR");
3007     if (resultStr != tempStr) {
3008         errcheckln(status, "FAIL: didn't return AOR for eo_AO - %s", u_errorName(status));
3009     }
3010     resLen = ucurr_forLocaleAndDate("eo_AO", date, 2, TMP, 4, &status);
3011 	tempStr.setTo(TMP);
3012     resultStr.setTo("AON");
3013     if (resultStr != tempStr) {
3014         errcheckln(status, "FAIL: didn't return AON for eo_AO - %s", u_errorName(status));
3015     }
3016 
3017 	date = (UDate)662256000000.0; // 1991 - 2 currencies
3018 	index = ucurr_countCurrencies("eo_AO", date, &status);
3019     if (index != 2)
3020 	{
3021 		errcheckln(status, "FAIL: didn't return 1 for eo_AO - %s", u_errorName(status));
3022 	}
3023     resLen = ucurr_forLocaleAndDate("eo_AO", date, 1, TMP, 4, &status);
3024 	tempStr.setTo(TMP);
3025     resultStr.setTo("AON");
3026     if (resultStr != tempStr) {
3027         errcheckln(status, "FAIL: didn't return AON for eo_AO - %s", u_errorName(status));
3028     }
3029     resLen = ucurr_forLocaleAndDate("eo_AO", date, 2, TMP, 4, &status);
3030 	tempStr.setTo(TMP);
3031     resultStr.setTo("AOK");
3032     if (resultStr != tempStr) {
3033         errcheckln(status, "FAIL: didn't return AOK for eo_AO - %s", u_errorName(status));
3034     }
3035 
3036 	date = (UDate)315360000000.0; // 1980 - one currency
3037 	index = ucurr_countCurrencies("eo_AO", date, &status);
3038     if (index != 1)
3039 	{
3040 		errcheckln(status, "FAIL: didn't return 1 for eo_AO - %s", u_errorName(status));
3041 	}
3042     resLen = ucurr_forLocaleAndDate("eo_AO", date, 1, TMP, 4, &status);
3043 	tempStr.setTo(TMP);
3044     resultStr.setTo("AOK");
3045     if (resultStr != tempStr) {
3046         errcheckln(status, "FAIL: didn't return AOK for eo_AO - %s", u_errorName(status));
3047     }
3048 
3049 	date = (UDate)0.0; // 1970 - no currencies
3050 	index = ucurr_countCurrencies("eo_AO", date, &status);
3051     if (index != 0)
3052 	{
3053 		errcheckln(status, "FAIL: didn't return 1 for eo_AO - %s", u_errorName(status));
3054 	}
3055     resLen = ucurr_forLocaleAndDate("eo_AO", date, 1, TMP, 4, &status);
3056     if (resLen != 0) {
3057 		errcheckln(status, "FAIL: eo_AO didn't return NULL - %s", u_errorName(status));
3058     }
3059     status = U_ZERO_ERROR;
3060 
3061     // Test with currency keyword override
3062 	date = (UDate)977616000000.0; // 2001 - two currencies
3063 	index = ucurr_countCurrencies("eo_DE@currency=DEM", date, &status);
3064     if (index != 2)
3065 	{
3066 		errcheckln(status, "FAIL: didn't return 2 for eo_DE@currency=DEM - %s", u_errorName(status));
3067 	}
3068     resLen = ucurr_forLocaleAndDate("eo_DE@currency=DEM", date, 1, TMP, 4, &status);
3069 	tempStr.setTo(TMP);
3070     resultStr.setTo("EUR");
3071     if (resultStr != tempStr) {
3072         errcheckln(status, "FAIL: didn't return EUR for eo_DE@currency=DEM - %s", u_errorName(status));
3073     }
3074     resLen = ucurr_forLocaleAndDate("eo_DE@currency=DEM", date, 2, TMP, 4, &status);
3075 	tempStr.setTo(TMP);
3076     resultStr.setTo("DEM");
3077     if (resultStr != tempStr) {
3078         errcheckln(status, "FAIL: didn't return DEM for eo_DE@currency=DEM - %s", u_errorName(status));
3079     }
3080 
3081     // Test Euro Support
3082 	status = U_ZERO_ERROR; // reset
3083     date = uprv_getUTCtime();
3084 
3085     UChar USD[4];
3086     ucurr_forLocaleAndDate("en_US", date, 1, USD, 4, &status);
3087 
3088 	UChar YEN[4];
3089     ucurr_forLocaleAndDate("ja_JP", date, 1, YEN, 4, &status);
3090 
3091     ucurr_forLocaleAndDate("en_US", date, 1, TMP, 4, &status);
3092     if (u_strcmp(USD, TMP) != 0) {
3093         errcheckln(status, "Fail: en_US didn't return USD - %s", u_errorName(status));
3094     }
3095     ucurr_forLocaleAndDate("en_US_Q", date, 1, TMP, 4, &status);
3096     if (u_strcmp(USD, TMP) != 0) {
3097         errcheckln(status, "Fail: en_US_Q didn't fallback to en_US - %s", u_errorName(status));
3098     }
3099     status = U_ZERO_ERROR; // reset
3100 #endif
3101 }
3102 
TestGetVariantWithKeywords(void)3103 void LocaleTest::TestGetVariantWithKeywords(void)
3104 {
3105   Locale l("en_US_VALLEY@foo=value");
3106   const char *variant = l.getVariant();
3107   logln(variant);
3108   test_assert(strcmp("VALLEY", variant) == 0);
3109 
3110   UErrorCode status = U_ZERO_ERROR;
3111   char buffer[50];
3112   int32_t len = l.getKeywordValue("foo", buffer, 50, status);
3113   buffer[len] = '\0';
3114   test_assert(strcmp("value", buffer) == 0);
3115 }
3116 
TestIsRightToLeft()3117 void LocaleTest::TestIsRightToLeft() {
3118     assertFalse("root LTR", Locale::getRoot().isRightToLeft());
3119     assertFalse("zh LTR", Locale::getChinese().isRightToLeft());
3120     assertTrue("ar RTL", Locale("ar").isRightToLeft());
3121     assertTrue("und-EG RTL", Locale("und-EG").isRightToLeft(), FALSE, TRUE);
3122     assertFalse("fa-Cyrl LTR", Locale("fa-Cyrl").isRightToLeft());
3123     assertTrue("en-Hebr RTL", Locale("en-Hebr").isRightToLeft());
3124     assertTrue("ckb RTL", Locale("ckb").isRightToLeft(), FALSE, TRUE);  // Sorani Kurdish
3125     assertFalse("fil LTR", Locale("fil").isRightToLeft());
3126     assertFalse("he-Zyxw LTR", Locale("he-Zyxw").isRightToLeft());
3127 }
3128 
TestBug11421()3129 void LocaleTest::TestBug11421() {
3130     Locale::getDefault().getBaseName();
3131     int32_t numLocales;
3132     const Locale *localeList = Locale::getAvailableLocales(numLocales);
3133     for (int localeIndex = 0; localeIndex < numLocales; localeIndex++) {
3134         const Locale &loc = localeList[localeIndex];
3135         if (strncmp(loc.getName(), loc.getBaseName(), strlen(loc.getBaseName()))) {
3136             errln("%s:%d loc.getName=\"%s\"; loc.getBaseName=\"%s\"",
3137                 __FILE__, __LINE__, loc.getName(), loc.getBaseName());
3138             break;
3139         }
3140     }
3141 }
3142 
3143 //  TestBug13277. The failure manifests as valgrind errors.
3144 //                See the trac ticket for details.
3145 //
3146 
TestBug13277()3147 void LocaleTest::TestBug13277() {
3148     UErrorCode status = U_ZERO_ERROR;
3149     CharString name("en-us-x-foo", -1, status);
3150     while (name.length() < 152) {
3151         name.append("-x-foo", -1, status);
3152     }
3153 
3154     while (name.length() < 160) {
3155         name.append('z', status);
3156         Locale loc(name.data(), nullptr, nullptr, nullptr);
3157     }
3158 }
3159 
3160 // TestBug13554 Check for read past end of array in getPosixID().
3161 //              The bug shows as an Address Sanitizer failure.
3162 
TestBug13554()3163 void LocaleTest::TestBug13554() {
3164     UErrorCode status = U_ZERO_ERROR;
3165     const int BUFFER_SIZE = 100;
3166     char  posixID[BUFFER_SIZE];
3167 
3168     for (uint32_t hostid = 0; hostid < 0x500; ++hostid) {
3169         status = U_ZERO_ERROR;
3170         uprv_convertToPosix(hostid, posixID, BUFFER_SIZE, &status);
3171     }
3172 }
3173 
TestBug20410()3174 void LocaleTest::TestBug20410() {
3175     IcuTestErrorCode status(*this, "TestBug20410()");
3176 
3177     static const char tag1[] = "art-lojban-x-0";
3178     static const Locale expected1("jbo@x=0");
3179     Locale result1 = Locale::forLanguageTag(tag1, status);
3180     status.errIfFailureAndReset("\"%s\"", tag1);
3181     assertEquals(tag1, expected1.getName(), result1.getName());
3182 
3183     static const char tag2[] = "zh-xiang-u-nu-thai-x-0";
3184     static const Locale expected2("hsn@numbers=thai;x=0");
3185     Locale result2 = Locale::forLanguageTag(tag2, status);
3186     status.errIfFailureAndReset("\"%s\"", tag2);
3187     assertEquals(tag2, expected2.getName(), result2.getName());
3188 
3189     static const char locid3[] = "art__lojban@x=0";
3190     Locale result3 = Locale::createCanonical(locid3);
3191     static const Locale expected3("jbo@x=0");
3192     assertEquals(locid3, expected3.getName(), result3.getName());
3193 
3194     static const char locid4[] = "art-lojban-x-0";
3195     Locale result4 = Locale::createCanonical(locid4);
3196     static const Locale expected4("jbo@x=0");
3197     assertEquals(locid4, expected4.getName(), result4.getName());
3198 }
3199 
TestBug20900()3200 void LocaleTest::TestBug20900() {
3201     static const struct {
3202         const char *localeID;    /* input */
3203         const char *canonicalID; /* expected canonicalize() result */
3204     } testCases[] = {
3205         { "art-lojban", "jbo" },
3206         { "zh-guoyu", "zh" },
3207         { "zh-hakka", "hak" },
3208         { "zh-xiang", "hsn" },
3209         { "zh-min-nan", "nan" },
3210         { "zh-gan", "gan" },
3211         { "zh-wuu", "wuu" },
3212         { "zh-yue", "yue" },
3213     };
3214 
3215     IcuTestErrorCode status(*this, "TestBug20900");
3216     for (int32_t i=0; i < UPRV_LENGTHOF(testCases); i++) {
3217         Locale loc = Locale::createCanonical(testCases[i].localeID);
3218         std::string result = loc.toLanguageTag<std::string>(status);
3219         const char* tag = loc.isBogus() ? "BOGUS" : result.c_str();
3220         status.errIfFailureAndReset("FAIL: createCanonical(%s).toLanguageTag() expected \"%s\"",
3221                     testCases[i].localeID, tag);
3222         assertEquals("createCanonical", testCases[i].canonicalID, tag);
3223     }
3224 }
3225 
TestConstructorAcceptsBCP47()3226 void LocaleTest::TestConstructorAcceptsBCP47() {
3227     IcuTestErrorCode status(*this, "TestConstructorAcceptsBCP47");
3228 
3229     Locale loc1("ar-EG-u-nu-latn");
3230     Locale loc2("ar-EG@numbers=latn");
3231     Locale loc3("ar-EG");
3232     std::string val;
3233 
3234     // Check getKeywordValue "numbers"
3235     val = loc1.getKeywordValue<std::string>("numbers", status);
3236     assertEquals("BCP47 syntax has ICU keyword value", "latn", val.c_str());
3237 
3238     val = loc2.getKeywordValue<std::string>("numbers", status);
3239     assertEquals("ICU syntax has ICU keyword value", "latn", val.c_str());
3240 
3241     val = loc3.getKeywordValue<std::string>("numbers", status);
3242     assertEquals("Default, ICU keyword", "", val.c_str());
3243 
3244     // Check getUnicodeKeywordValue "nu"
3245     val = loc1.getUnicodeKeywordValue<std::string>("nu", status);
3246     assertEquals("BCP47 syntax has short unicode keyword value", "latn", val.c_str());
3247 
3248     val = loc2.getUnicodeKeywordValue<std::string>("nu", status);
3249     assertEquals("ICU syntax has short unicode keyword value", "latn", val.c_str());
3250 
3251     val = loc3.getUnicodeKeywordValue<std::string>("nu", status);
3252     status.expectErrorAndReset(U_ILLEGAL_ARGUMENT_ERROR, "Default, short unicode keyword");
3253 
3254     // Check getUnicodeKeywordValue "numbers"
3255     val = loc1.getUnicodeKeywordValue<std::string>("numbers", status);
3256     assertEquals("BCP47 syntax has long unicode keyword value", "latn", val.c_str());
3257 
3258     val = loc2.getUnicodeKeywordValue<std::string>("numbers", status);
3259     assertEquals("ICU syntax has long unicode keyword value", "latn", val.c_str());
3260 
3261     val = loc3.getUnicodeKeywordValue<std::string>("numbers", status);
3262     status.expectErrorAndReset(U_ILLEGAL_ARGUMENT_ERROR, "Default, long unicode keyword");
3263 }
3264 
TestForLanguageTag()3265 void LocaleTest::TestForLanguageTag() {
3266     IcuTestErrorCode status(*this, "TestForLanguageTag()");
3267 
3268     static const char tag_en[] = "en-US";
3269     static const char tag_oed[] = "en-GB-oed";
3270     static const char tag_af[] = "af-t-ar-i0-handwrit-u-ca-coptic-x-foo";
3271     static const char tag_ill[] = "!";
3272     static const char tag_no_nul[] = { 'e', 'n', '-', 'G', 'B' };
3273     static const char tag_ext[] = "en-GB-1-abc-efg-a-xyz";
3274     static const char tag_var[] = "sl-rozaj-biske-1994";
3275 
3276     static const Locale loc_en("en_US");
3277     static const Locale loc_oed("en_GB_OXENDICT");
3278     static const Locale loc_af("af@calendar=coptic;t=ar-i0-handwrit;x=foo");
3279     static const Locale loc_null("");
3280     static const Locale loc_gb("en_GB");
3281     static const Locale loc_ext("en_GB@1=abc-efg;a=xyz");
3282     static const Locale loc_var("sl__1994_BISKE_ROZAJ");
3283 
3284     Locale result_en = Locale::forLanguageTag(tag_en, status);
3285     status.errIfFailureAndReset("\"%s\"", tag_en);
3286     assertEquals(tag_en, loc_en.getName(), result_en.getName());
3287 
3288     Locale result_oed = Locale::forLanguageTag(tag_oed, status);
3289     status.errIfFailureAndReset("\"%s\"", tag_oed);
3290     assertEquals(tag_oed, loc_oed.getName(), result_oed.getName());
3291 
3292     Locale result_af = Locale::forLanguageTag(tag_af, status);
3293     status.errIfFailureAndReset("\"%s\"", tag_af);
3294     assertEquals(tag_af, loc_af.getName(), result_af.getName());
3295 
3296     Locale result_var = Locale::forLanguageTag(tag_var, status);
3297     status.errIfFailureAndReset("\"%s\"", tag_var);
3298     assertEquals(tag_var, loc_var.getName(), result_var.getName());
3299 
3300     Locale result_ill = Locale::forLanguageTag(tag_ill, status);
3301     assertEquals(tag_ill, U_ILLEGAL_ARGUMENT_ERROR, status.reset());
3302     assertTrue(result_ill.getName(), result_ill.isBogus());
3303 
3304     Locale result_null = Locale::forLanguageTag(nullptr, status);
3305     status.errIfFailureAndReset("nullptr");
3306     assertEquals("nullptr", loc_null.getName(), result_null.getName());
3307 
3308     StringPiece sp_substr(tag_oed, 5);  // "en-GB", no NUL.
3309     Locale result_substr = Locale::forLanguageTag(sp_substr, status);
3310     status.errIfFailureAndReset("\"%.*s\"", sp_substr.size(), sp_substr.data());
3311     assertEquals(CharString(sp_substr, status).data(),
3312             loc_gb.getName(), result_substr.getName());
3313 
3314     StringPiece sp_no_nul(tag_no_nul, sizeof tag_no_nul);  // "en-GB", no NUL.
3315     Locale result_no_nul = Locale::forLanguageTag(sp_no_nul, status);
3316     status.errIfFailureAndReset("\"%.*s\"", sp_no_nul.size(), sp_no_nul.data());
3317     assertEquals(CharString(sp_no_nul, status).data(),
3318             loc_gb.getName(), result_no_nul.getName());
3319 
3320     Locale result_ext = Locale::forLanguageTag(tag_ext, status);
3321     status.errIfFailureAndReset("\"%s\"", tag_ext);
3322     assertEquals(tag_ext, loc_ext.getName(), result_ext.getName());
3323 }
3324 
TestToLanguageTag()3325 void LocaleTest::TestToLanguageTag() {
3326     IcuTestErrorCode status(*this, "TestToLanguageTag()");
3327 
3328     static const Locale loc_c("en_US_POSIX");
3329     static const Locale loc_en("en_US");
3330     static const Locale loc_af("af@calendar=coptic;t=ar-i0-handwrit;x=foo");
3331     static const Locale loc_ext("en@0=abc;a=xyz");
3332     static const Locale loc_empty("");
3333     static const Locale loc_ill("!");
3334     static const Locale loc_variant("sl__ROZAJ_BISKE_1994");
3335 
3336     static const char tag_c[] = "en-US-u-va-posix";
3337     static const char tag_en[] = "en-US";
3338     static const char tag_af[] = "af-t-ar-i0-handwrit-u-ca-coptic-x-foo";
3339     static const char tag_ext[] = "en-0-abc-a-xyz";
3340     static const char tag_und[] = "und";
3341     static const char tag_variant[] = "sl-1994-biske-rozaj";
3342 
3343     std::string result;
3344     StringByteSink<std::string> sink(&result);
3345     loc_c.toLanguageTag(sink, status);
3346     status.errIfFailureAndReset("\"%s\"", loc_c.getName());
3347     assertEquals(loc_c.getName(), tag_c, result.c_str());
3348 
3349     std::string result_c = loc_c.toLanguageTag<std::string>(status);
3350     status.errIfFailureAndReset("\"%s\"", loc_c.getName());
3351     assertEquals(loc_c.getName(), tag_c, result_c.c_str());
3352 
3353     std::string result_en = loc_en.toLanguageTag<std::string>(status);
3354     status.errIfFailureAndReset("\"%s\"", loc_en.getName());
3355     assertEquals(loc_en.getName(), tag_en, result_en.c_str());
3356 
3357     std::string result_af = loc_af.toLanguageTag<std::string>(status);
3358     status.errIfFailureAndReset("\"%s\"", loc_af.getName());
3359     assertEquals(loc_af.getName(), tag_af, result_af.c_str());
3360 
3361     std::string result_ext = loc_ext.toLanguageTag<std::string>(status);
3362     status.errIfFailureAndReset("\"%s\"", loc_ext.getName());
3363     assertEquals(loc_ext.getName(), tag_ext, result_ext.c_str());
3364 
3365     std::string result_empty = loc_empty.toLanguageTag<std::string>(status);
3366     status.errIfFailureAndReset("\"%s\"", loc_empty.getName());
3367     assertEquals(loc_empty.getName(), tag_und, result_empty.c_str());
3368 
3369     std::string result_ill = loc_ill.toLanguageTag<std::string>(status);
3370     status.errIfFailureAndReset("\"%s\"", loc_ill.getName());
3371     assertEquals(loc_ill.getName(), tag_und, result_ill.c_str());
3372 
3373     std::string result_variant = loc_variant.toLanguageTag<std::string>(status);
3374     status.errIfFailureAndReset("\"%s\"", loc_variant.getName());
3375     assertEquals(loc_variant.getName(), tag_variant, result_variant.c_str());
3376 
3377     Locale loc_bogus;
3378     loc_bogus.setToBogus();
3379     std::string result_bogus = loc_bogus.toLanguageTag<std::string>(status);
3380     assertEquals("bogus", U_ILLEGAL_ARGUMENT_ERROR, status.reset());
3381     assertTrue(result_bogus.c_str(), result_bogus.empty());
3382 }
3383 
3384 /* ICU-20310 */
TestToLanguageTagOmitTrue()3385 void LocaleTest::TestToLanguageTagOmitTrue() {
3386     IcuTestErrorCode status(*this, "TestToLanguageTagOmitTrue()");
3387     assertEquals("en-u-kn should drop true",
3388                  "en-u-kn", Locale("en-u-kn-true").toLanguageTag<std::string>(status).c_str());
3389     status.errIfFailureAndReset();
3390     assertEquals("en-u-kn should drop true",
3391                  "en-u-kn", Locale("en-u-kn").toLanguageTag<std::string>(status).c_str());
3392     status.errIfFailureAndReset();
3393 
3394     assertEquals("de-u-co should drop true",
3395                  "de-u-co", Locale("de-u-co").toLanguageTag<std::string>(status).c_str());
3396     status.errIfFailureAndReset();
3397     assertEquals("de-u-co should drop true",
3398                  "de-u-co", Locale("de-u-co-yes").toLanguageTag<std::string>(status).c_str());
3399     status.errIfFailureAndReset();
3400     assertEquals("de@collation=yes should drop true",
3401                  "de-u-co", Locale("de@collation=yes").toLanguageTag<std::string>(status).c_str());
3402     status.errIfFailureAndReset();
3403 
3404     assertEquals("cmn-Hans-CN-t-ca-u-ca-x-t-u should drop true",
3405                  "cmn-Hans-CN-t-ca-u-ca-x-t-u",
3406                  Locale("cmn-hans-cn-u-ca-t-ca-x-t-u").toLanguageTag<std::string>(status).c_str());
3407     status.errIfFailureAndReset();
3408 }
3409 
TestMoveAssign()3410 void LocaleTest::TestMoveAssign() {
3411     // ULOC_FULLNAME_CAPACITY == 157 (uloc.h)
3412     Locale l1("de@collation=phonebook;x="
3413               "aaaaabbbbbcccccdddddeeeeefffffggggghhhhh"
3414               "aaaaabbbbbcccccdddddeeeeefffffggggghhhhh"
3415               "aaaaabbbbbcccccdddddeeeeefffffggggghhhhh"
3416               "aaaaabbbbbzz");
3417 
3418     Locale l2;
3419     {
3420         Locale l3(l1);
3421         assertTrue("l1 == l3", l1 == l3);
3422         l2 = std::move(l3);
3423         assertTrue("l1 == l2", l1 == l2);
3424         assertTrue("l2 != l3", l2.getName() != l3.getName());
3425     }
3426 
3427     // This should remain true also after l3 has been destructed.
3428     assertTrue("l1 == l2, again", l1 == l2);
3429 
3430     Locale l4("de@collation=phonebook");
3431 
3432     Locale l5;
3433     {
3434         Locale l6(l4);
3435         assertTrue("l4 == l6", l4 == l6);
3436         l5 = std::move(l6);
3437         assertTrue("l4 == l5", l4 == l5);
3438         assertTrue("l5 != l6", l5.getName() != l6.getName());
3439     }
3440 
3441     // This should remain true also after l6 has been destructed.
3442     assertTrue("l4 == l5, again", l4 == l5);
3443 
3444     Locale l7("vo_Cyrl_AQ_EURO");
3445 
3446     Locale l8;
3447     {
3448         Locale l9(l7);
3449         assertTrue("l7 == l9", l7 == l9);
3450         l8 = std::move(l9);
3451         assertTrue("l7 == l8", l7 == l8);
3452         assertTrue("l8 != l9", l8.getName() != l9.getName());
3453     }
3454 
3455     // This should remain true also after l9 has been destructed.
3456     assertTrue("l7 == l8, again", l7 == l8);
3457 
3458     assertEquals("language", l7.getLanguage(), l8.getLanguage());
3459     assertEquals("script", l7.getScript(), l8.getScript());
3460     assertEquals("country", l7.getCountry(), l8.getCountry());
3461     assertEquals("variant", l7.getVariant(), l8.getVariant());
3462     assertEquals("bogus", l7.isBogus(), l8.isBogus());
3463 }
3464 
TestMoveCtor()3465 void LocaleTest::TestMoveCtor() {
3466     // ULOC_FULLNAME_CAPACITY == 157 (uloc.h)
3467     Locale l1("de@collation=phonebook;x="
3468               "aaaaabbbbbcccccdddddeeeeefffffggggghhhhh"
3469               "aaaaabbbbbcccccdddddeeeeefffffggggghhhhh"
3470               "aaaaabbbbbcccccdddddeeeeefffffggggghhhhh"
3471               "aaaaabbbbbzz");
3472 
3473     Locale l3(l1);
3474     assertTrue("l1 == l3", l1 == l3);
3475     Locale l2(std::move(l3));
3476     assertTrue("l1 == l2", l1 == l2);
3477     assertTrue("l2 != l3", l2.getName() != l3.getName());
3478 
3479     Locale l4("de@collation=phonebook");
3480 
3481     Locale l6(l4);
3482     assertTrue("l4 == l6", l4 == l6);
3483     Locale l5(std::move(l6));
3484     assertTrue("l4 == l5", l4 == l5);
3485     assertTrue("l5 != l6", l5.getName() != l6.getName());
3486 
3487     Locale l7("vo_Cyrl_AQ_EURO");
3488 
3489     Locale l9(l7);
3490     assertTrue("l7 == l9", l7 == l9);
3491     Locale l8(std::move(l9));
3492     assertTrue("l7 == l8", l7 == l8);
3493     assertTrue("l8 != l9", l8.getName() != l9.getName());
3494 
3495     assertEquals("language", l7.getLanguage(), l8.getLanguage());
3496     assertEquals("script", l7.getScript(), l8.getScript());
3497     assertEquals("country", l7.getCountry(), l8.getCountry());
3498     assertEquals("variant", l7.getVariant(), l8.getVariant());
3499     assertEquals("bogus", l7.isBogus(), l8.isBogus());
3500 }
3501 
TestBug20407iVariantPreferredValue()3502 void LocaleTest::TestBug20407iVariantPreferredValue() {
3503     IcuTestErrorCode status(*this, "TestBug20407iVariantPreferredValue()");
3504 
3505     Locale l = Locale::forLanguageTag("hy-arevela", status);
3506     status.errIfFailureAndReset("hy-arevela fail");
3507     assertTrue("!l.isBogus()", !l.isBogus());
3508 
3509     std::string result = l.toLanguageTag<std::string>(status);
3510     assertEquals(l.getName(), "hy", result.c_str());
3511 
3512     l = Locale::forLanguageTag("hy-arevmda", status);
3513     status.errIfFailureAndReset("hy-arevmda");
3514     assertTrue("!l.isBogus()", !l.isBogus());
3515 
3516     result = l.toLanguageTag<std::string>(status);
3517     assertEquals(l.getName(), "hyw", result.c_str());
3518 }
3519 
TestBug13417VeryLongLanguageTag()3520 void LocaleTest::TestBug13417VeryLongLanguageTag() {
3521     IcuTestErrorCode status(*this, "TestBug13417VeryLongLanguageTag()");
3522 
3523     static const char tag[] =
3524         "zh-x"
3525         "-foo-bar-baz-foo-bar-baz-foo-bar-baz-foo-bar-baz"
3526         "-foo-bar-baz-foo-bar-baz-foo-bar-baz-foo-bar-baz"
3527         "-foo-bar-baz-foo-bar-baz-foo-bar-baz-foo-bar-baz"
3528         "-foo-bar-baz-fxx"
3529     ;
3530 
3531     Locale l = Locale::forLanguageTag(tag, status);
3532     status.errIfFailureAndReset("\"%s\"", tag);
3533     assertTrue("!l.isBogus()", !l.isBogus());
3534 
3535     std::string result = l.toLanguageTag<std::string>(status);
3536     status.errIfFailureAndReset("\"%s\"", l.getName());
3537     assertEquals("equals", tag, result.c_str());
3538 }
3539 
TestBug11053UnderlineTimeZone()3540 void LocaleTest::TestBug11053UnderlineTimeZone() {
3541     static const char* const tz_in_ext[] = {
3542         "etadd",
3543         "tzdar",
3544         "eheai",
3545         "sttms",
3546         "arirj",
3547         "arrgl",
3548         "aruaq",
3549         "arluq",
3550         "mxpvr",
3551         "brbvb",
3552         "arbue",
3553         "caycb",
3554         "brcgr",
3555         "cayzs",
3556         "crsjo",
3557         "caydq",
3558         "svsal",
3559         "cafne",
3560         "caglb",
3561         "cagoo",
3562         "tcgdt",
3563         "ustel",
3564         "bolpb",
3565         "uslax",
3566         "sxphi",
3567         "mxmex",
3568         "usnyc",
3569         "usxul",
3570         "usndcnt",
3571         "usndnsl",
3572         "ttpos",
3573         "brpvh",
3574         "prsju",
3575         "clpuq",
3576         "caffs",
3577         "cayek",
3578         "brrbr",
3579         "mxstis",
3580         "dosdq",
3581         "brsao",
3582         "gpsbh",
3583         "casjf",
3584         "knbas",
3585         "lccas",
3586         "vistt",
3587         "vcsvd",
3588         "cayyn",
3589         "cathu",
3590         "hkhkg",
3591         "mykul",
3592         "khpnh",
3593         "cvrai",
3594         "gsgrv",
3595         "shshn",
3596         "aubhq",
3597         "auldh",
3598         "imdgs",
3599         "smsai",
3600         "asppg",
3601         "pgpom",
3602     };
3603     static const char* const tzname_with_underline[] = {
3604         "America/Buenos_Aires",
3605         "America/Coral_Harbour",
3606         "America/Los_Angeles",
3607         "America/Mexico_City",
3608         "America/New_York",
3609         "America/Rio_Branco",
3610         "America/Sao_Paulo",
3611         "America/St_Johns",
3612         "America/St_Thomas",
3613         "Australia/Broken_Hill",
3614         "Australia/Lord_Howe",
3615         "Pacific/Pago_Pago",
3616     };
3617     std::string locale_str;
3618     for (int32_t i = 0; i < UPRV_LENGTHOF(tz_in_ext); i++) {
3619         locale_str = "en-u-tz-";
3620         locale_str += tz_in_ext[i];
3621         Locale l(locale_str.c_str());
3622         assertTrue((locale_str + " !l.isBogus()").c_str(), !l.isBogus());
3623     }
3624     for (int32_t i = 0; i < UPRV_LENGTHOF(tzname_with_underline); i++) {
3625         locale_str = "en@timezone=";
3626         locale_str +=  tzname_with_underline[i];
3627         Locale l(locale_str.c_str());
3628         assertTrue((locale_str + " !l.isBogus()").c_str(), !l.isBogus());
3629     }
3630     locale_str = "en_US@timezone=America/Coral_Harbour";
3631     Locale l2(locale_str.c_str());
3632     assertTrue((locale_str + " !l2.isBogus()").c_str(), !l2.isBogus());
3633     locale_str = "en_Latn@timezone=America/New_York";
3634     Locale l3(locale_str.c_str());
3635     assertTrue((locale_str + " !l3.isBogus()").c_str(), !l3.isBogus());
3636     locale_str = "en_Latn_US@timezone=Australia/Broken_Hill";
3637     Locale l4(locale_str.c_str());
3638     assertTrue((locale_str + " !l4.isBogus()").c_str(), !l4.isBogus());
3639     locale_str = "en-u-tz-ciabj";
3640     Locale l5(locale_str.c_str());
3641     assertTrue((locale_str + " !l5.isBogus()").c_str(), !l5.isBogus());
3642     locale_str = "en-US-u-tz-asppg";
3643     Locale l6(locale_str.c_str());
3644     assertTrue((locale_str + " !l6.isBogus()").c_str(), !l6.isBogus());
3645     locale_str = "fil-Latn-u-tz-cvrai";
3646     Locale l7(locale_str.c_str());
3647     assertTrue((locale_str + " !l7.isBogus()").c_str(), !l7.isBogus());
3648     locale_str = "fil-Latn-PH-u-tz-gsgrv";
3649     Locale l8(locale_str.c_str());
3650     assertTrue((locale_str + " !l8.isBogus()").c_str(), !l8.isBogus());
3651 }
3652 
TestUnd()3653 void LocaleTest::TestUnd() {
3654     IcuTestErrorCode status(*this, "TestUnd()");
3655 
3656     static const char empty[] = "";
3657     static const char root[] = "root";
3658     static const char und[] = "und";
3659 
3660     Locale empty_ctor(empty);
3661     Locale empty_tag = Locale::forLanguageTag(empty, status);
3662     status.errIfFailureAndReset("\"%s\"", empty);
3663 
3664     Locale root_ctor(root);
3665     Locale root_tag = Locale::forLanguageTag(root, status);
3666     Locale root_build = LocaleBuilder().setLanguageTag(root).build(status);
3667     status.errIfFailureAndReset("\"%s\"", root);
3668 
3669     Locale und_ctor(und);
3670     Locale und_tag = Locale::forLanguageTag(und, status);
3671     Locale und_build = LocaleBuilder().setLanguageTag(und).build(status);
3672     status.errIfFailureAndReset("\"%s\"", und);
3673 
3674     assertEquals("getName()", empty, empty_ctor.getName());
3675     assertEquals("getName()", empty, root_ctor.getName());
3676     assertEquals("getName()", empty, und_ctor.getName());
3677 
3678     assertEquals("getName()", empty, empty_tag.getName());
3679     assertEquals("getName()", empty, root_tag.getName());
3680     assertEquals("getName()", empty, und_tag.getName());
3681 
3682     assertEquals("getName()", empty, root_build.getName());
3683     assertEquals("getName()", empty, und_build.getName());
3684 
3685     assertEquals("toLanguageTag()", und, empty_ctor.toLanguageTag<std::string>(status).c_str());
3686     assertEquals("toLanguageTag()", und, root_ctor.toLanguageTag<std::string>(status).c_str());
3687     assertEquals("toLanguageTag()", und, und_ctor.toLanguageTag<std::string>(status).c_str());
3688     status.errIfFailureAndReset();
3689 
3690     assertEquals("toLanguageTag()", und, empty_tag.toLanguageTag<std::string>(status).c_str());
3691     assertEquals("toLanguageTag()", und, root_tag.toLanguageTag<std::string>(status).c_str());
3692     assertEquals("toLanguageTag()", und, und_tag.toLanguageTag<std::string>(status).c_str());
3693     status.errIfFailureAndReset();
3694 
3695     assertEquals("toLanguageTag()", und, root_build.toLanguageTag<std::string>(status).c_str());
3696     assertEquals("toLanguageTag()", und, und_build.toLanguageTag<std::string>(status).c_str());
3697     status.errIfFailureAndReset();
3698 
3699     assertTrue("empty_ctor == empty_tag", empty_ctor == empty_tag);
3700 
3701     assertTrue("root_ctor == root_tag", root_ctor == root_tag);
3702     assertTrue("root_ctor == root_build", root_ctor == root_build);
3703     assertTrue("root_tag == root_build", root_tag == root_build);
3704 
3705     assertTrue("und_ctor == und_tag", und_ctor == und_tag);
3706     assertTrue("und_ctor == und_build", und_ctor == und_build);
3707     assertTrue("und_tag == und_build", und_tag == und_build);
3708 
3709     assertTrue("empty_ctor == root_ctor", empty_ctor == root_ctor);
3710     assertTrue("empty_ctor == und_ctor", empty_ctor == und_ctor);
3711     assertTrue("root_ctor == und_ctor", root_ctor == und_ctor);
3712 
3713     assertTrue("empty_tag == root_tag", empty_tag == root_tag);
3714     assertTrue("empty_tag == und_tag", empty_tag == und_tag);
3715     assertTrue("root_tag == und_tag", root_tag == und_tag);
3716 
3717     assertTrue("root_build == und_build", root_build == und_build);
3718 
3719     static const Locale& displayLocale = Locale::getEnglish();
3720     static const UnicodeString displayName("Unknown language");
3721     UnicodeString tmp;
3722 
3723     assertEquals("getDisplayName()", displayName, empty_ctor.getDisplayName(displayLocale, tmp));
3724     assertEquals("getDisplayName()", displayName, root_ctor.getDisplayName(displayLocale, tmp));
3725     assertEquals("getDisplayName()", displayName, und_ctor.getDisplayName(displayLocale, tmp));
3726 
3727     assertEquals("getDisplayName()", displayName, empty_tag.getDisplayName(displayLocale, tmp));
3728     assertEquals("getDisplayName()", displayName, root_tag.getDisplayName(displayLocale, tmp));
3729     assertEquals("getDisplayName()", displayName, und_tag.getDisplayName(displayLocale, tmp));
3730 
3731     assertEquals("getDisplayName()", displayName, root_build.getDisplayName(displayLocale, tmp));
3732     assertEquals("getDisplayName()", displayName, und_build.getDisplayName(displayLocale, tmp));
3733 }
3734 
TestUndScript()3735 void LocaleTest::TestUndScript() {
3736     IcuTestErrorCode status(*this, "TestUndScript()");
3737 
3738     static const char id[] = "_Cyrl";
3739     static const char tag[] = "und-Cyrl";
3740     static const char script[] = "Cyrl";
3741 
3742     Locale locale_ctor(id);
3743     Locale locale_legacy(tag);
3744     Locale locale_tag = Locale::forLanguageTag(tag, status);
3745     Locale locale_build = LocaleBuilder().setScript(script).build(status);
3746     status.errIfFailureAndReset("\"%s\"", tag);
3747 
3748     assertEquals("getName()", id, locale_ctor.getName());
3749     assertEquals("getName()", id, locale_legacy.getName());
3750     assertEquals("getName()", id, locale_tag.getName());
3751     assertEquals("getName()", id, locale_build.getName());
3752 
3753     assertEquals("toLanguageTag()", tag, locale_ctor.toLanguageTag<std::string>(status).c_str());
3754     assertEquals("toLanguageTag()", tag, locale_legacy.toLanguageTag<std::string>(status).c_str());
3755     assertEquals("toLanguageTag()", tag, locale_tag.toLanguageTag<std::string>(status).c_str());
3756     assertEquals("toLanguageTag()", tag, locale_build.toLanguageTag<std::string>(status).c_str());
3757     status.errIfFailureAndReset();
3758 
3759     static const Locale& displayLocale = Locale::getEnglish();
3760     static const UnicodeString displayName("Unknown language (Cyrillic)");
3761     UnicodeString tmp;
3762 
3763     assertEquals("getDisplayName()", displayName, locale_ctor.getDisplayName(displayLocale, tmp));
3764     assertEquals("getDisplayName()", displayName, locale_legacy.getDisplayName(displayLocale, tmp));
3765     assertEquals("getDisplayName()", displayName, locale_tag.getDisplayName(displayLocale, tmp));
3766     assertEquals("getDisplayName()", displayName, locale_build.getDisplayName(displayLocale, tmp));
3767 }
3768 
TestUndRegion()3769 void LocaleTest::TestUndRegion() {
3770     IcuTestErrorCode status(*this, "TestUndRegion()");
3771 
3772     static const char id[] = "_AQ";
3773     static const char tag[] = "und-AQ";
3774     static const char region[] = "AQ";
3775 
3776     Locale locale_ctor(id);
3777     Locale locale_legacy(tag);
3778     Locale locale_tag = Locale::forLanguageTag(tag, status);
3779     Locale locale_build = LocaleBuilder().setRegion(region).build(status);
3780     status.errIfFailureAndReset("\"%s\"", tag);
3781 
3782     assertEquals("getName()", id, locale_ctor.getName());
3783     assertEquals("getName()", id, locale_legacy.getName());
3784     assertEquals("getName()", id, locale_tag.getName());
3785     assertEquals("getName()", id, locale_build.getName());
3786 
3787     assertEquals("toLanguageTag()", tag, locale_ctor.toLanguageTag<std::string>(status).c_str());
3788     assertEquals("toLanguageTag()", tag, locale_legacy.toLanguageTag<std::string>(status).c_str());
3789     assertEquals("toLanguageTag()", tag, locale_tag.toLanguageTag<std::string>(status).c_str());
3790     assertEquals("toLanguageTag()", tag, locale_build.toLanguageTag<std::string>(status).c_str());
3791     status.errIfFailureAndReset();
3792 
3793     static const Locale& displayLocale = Locale::getEnglish();
3794     static const UnicodeString displayName("Unknown language (Antarctica)");
3795     UnicodeString tmp;
3796 
3797     assertEquals("getDisplayName()", displayName, locale_ctor.getDisplayName(displayLocale, tmp));
3798     assertEquals("getDisplayName()", displayName, locale_legacy.getDisplayName(displayLocale, tmp));
3799     assertEquals("getDisplayName()", displayName, locale_tag.getDisplayName(displayLocale, tmp));
3800     assertEquals("getDisplayName()", displayName, locale_build.getDisplayName(displayLocale, tmp));
3801 }
3802 
TestUndCAPI()3803 void LocaleTest::TestUndCAPI() {
3804     IcuTestErrorCode status(*this, "TestUndCAPI()");
3805 
3806     static const char empty[] = "";
3807     static const char root[] = "root";
3808     static const char und[] = "und";
3809 
3810     static const char empty_script[] = "_Cyrl";
3811     static const char empty_region[] = "_AQ";
3812 
3813     static const char und_script[] = "und_Cyrl";
3814     static const char und_region[] = "und_AQ";
3815 
3816     char tmp[ULOC_FULLNAME_CAPACITY];
3817     int32_t reslen;
3818 
3819     // uloc_getName()
3820 
3821     uprv_memset(tmp, '!', sizeof tmp);
3822     reslen = uloc_getName(empty, tmp, sizeof tmp, status);
3823     status.errIfFailureAndReset("\"%s\"", empty);
3824     assertTrue("reslen >= 0", reslen >= 0);
3825     assertEquals("uloc_getName()", empty, tmp);
3826 
3827     uprv_memset(tmp, '!', sizeof tmp);
3828     reslen = uloc_getName(root, tmp, sizeof tmp, status);
3829     status.errIfFailureAndReset("\"%s\"", root);
3830     assertTrue("reslen >= 0", reslen >= 0);
3831     assertEquals("uloc_getName()", empty, tmp);
3832 
3833     uprv_memset(tmp, '!', sizeof tmp);
3834     reslen = uloc_getName(und, tmp, sizeof tmp, status);
3835     status.errIfFailureAndReset("\"%s\"", und);
3836     assertTrue("reslen >= 0", reslen >= 0);
3837     assertEquals("uloc_getName()", empty, tmp);
3838 
3839     uprv_memset(tmp, '!', sizeof tmp);
3840     reslen = uloc_getName(empty_script, tmp, sizeof tmp, status);
3841     status.errIfFailureAndReset("\"%s\"", empty_script);
3842     assertTrue("reslen >= 0", reslen >= 0);
3843     assertEquals("uloc_getName()", empty_script, tmp);
3844 
3845     uprv_memset(tmp, '!', sizeof tmp);
3846     reslen = uloc_getName(empty_region, tmp, sizeof tmp, status);
3847     status.errIfFailureAndReset("\"%s\"", empty_region);
3848     assertTrue("reslen >= 0", reslen >= 0);
3849     assertEquals("uloc_getName()", empty_region, tmp);
3850 
3851     uprv_memset(tmp, '!', sizeof tmp);
3852     reslen = uloc_getName(und_script, tmp, sizeof tmp, status);
3853     status.errIfFailureAndReset("\"%s\"", und_script);
3854     assertTrue("reslen >= 0", reslen >= 0);
3855     assertEquals("uloc_getName()", empty_script, tmp);
3856 
3857     uprv_memset(tmp, '!', sizeof tmp);
3858     reslen = uloc_getName(und_region, tmp, sizeof tmp, status);
3859     status.errIfFailureAndReset("\"%s\"", und_region);
3860     assertTrue("reslen >= 0", reslen >= 0);
3861     assertEquals("uloc_getName()", empty_region, tmp);
3862 
3863     // uloc_getBaseName()
3864 
3865     uprv_memset(tmp, '!', sizeof tmp);
3866     reslen = uloc_getBaseName(empty, tmp, sizeof tmp, status);
3867     status.errIfFailureAndReset("\"%s\"", empty);
3868     assertTrue("reslen >= 0", reslen >= 0);
3869     assertEquals("uloc_getBaseName()", empty, tmp);
3870 
3871     uprv_memset(tmp, '!', sizeof tmp);
3872     reslen = uloc_getBaseName(root, tmp, sizeof tmp, status);
3873     status.errIfFailureAndReset("\"%s\"", root);
3874     assertTrue("reslen >= 0", reslen >= 0);
3875     assertEquals("uloc_getBaseName()", empty, tmp);
3876 
3877     uprv_memset(tmp, '!', sizeof tmp);
3878     reslen = uloc_getBaseName(und, tmp, sizeof tmp, status);
3879     status.errIfFailureAndReset("\"%s\"", und);
3880     assertTrue("reslen >= 0", reslen >= 0);
3881     assertEquals("uloc_getBaseName()", empty, tmp);
3882 
3883     uprv_memset(tmp, '!', sizeof tmp);
3884     reslen = uloc_getBaseName(empty_script, tmp, sizeof tmp, status);
3885     status.errIfFailureAndReset("\"%s\"", empty_script);
3886     assertTrue("reslen >= 0", reslen >= 0);
3887     assertEquals("uloc_getBaseName()", empty_script, tmp);
3888 
3889     uprv_memset(tmp, '!', sizeof tmp);
3890     reslen = uloc_getBaseName(empty_region, tmp, sizeof tmp, status);
3891     status.errIfFailureAndReset("\"%s\"", empty_region);
3892     assertTrue("reslen >= 0", reslen >= 0);
3893     assertEquals("uloc_getBaseName()", empty_region, tmp);
3894 
3895     uprv_memset(tmp, '!', sizeof tmp);
3896     reslen = uloc_getBaseName(und_script, tmp, sizeof tmp, status);
3897     status.errIfFailureAndReset("\"%s\"", und_script);
3898     assertTrue("reslen >= 0", reslen >= 0);
3899     assertEquals("uloc_getBaseName()", empty_script, tmp);
3900 
3901     uprv_memset(tmp, '!', sizeof tmp);
3902     reslen = uloc_getBaseName(und_region, tmp, sizeof tmp, status);
3903     status.errIfFailureAndReset("\"%s\"", und_region);
3904     assertTrue("reslen >= 0", reslen >= 0);
3905     assertEquals("uloc_getBaseName()", empty_region, tmp);
3906 
3907     // uloc_getParent()
3908 
3909     uprv_memset(tmp, '!', sizeof tmp);
3910     reslen = uloc_getParent(empty, tmp, sizeof tmp, status);
3911     status.errIfFailureAndReset("\"%s\"", empty);
3912     assertTrue("reslen >= 0", reslen >= 0);
3913     assertEquals("uloc_getParent()", empty, tmp);
3914 
3915     uprv_memset(tmp, '!', sizeof tmp);
3916     reslen = uloc_getParent(root, tmp, sizeof tmp, status);
3917     status.errIfFailureAndReset("\"%s\"", root);
3918     assertTrue("reslen >= 0", reslen >= 0);
3919     assertEquals("uloc_getParent()", empty, tmp);
3920 
3921     uprv_memset(tmp, '!', sizeof tmp);
3922     reslen = uloc_getParent(und, tmp, sizeof tmp, status);
3923     status.errIfFailureAndReset("\"%s\"", und);
3924     assertTrue("reslen >= 0", reslen >= 0);
3925     assertEquals("uloc_getParent()", empty, tmp);
3926 
3927     uprv_memset(tmp, '!', sizeof tmp);
3928     reslen = uloc_getParent(empty_script, tmp, sizeof tmp, status);
3929     status.errIfFailureAndReset("\"%s\"", empty_script);
3930     assertTrue("reslen >= 0", reslen >= 0);
3931     assertEquals("uloc_getParent()", empty, tmp);
3932 
3933     uprv_memset(tmp, '!', sizeof tmp);
3934     reslen = uloc_getParent(empty_region, tmp, sizeof tmp, status);
3935     status.errIfFailureAndReset("\"%s\"", empty_region);
3936     assertTrue("reslen >= 0", reslen >= 0);
3937     assertEquals("uloc_getParent()", empty, tmp);
3938 
3939     uprv_memset(tmp, '!', sizeof tmp);
3940     reslen = uloc_getParent(und_script, tmp, sizeof tmp, status);
3941     status.errIfFailureAndReset("\"%s\"", und_script);
3942     assertTrue("reslen >= 0", reslen >= 0);
3943     assertEquals("uloc_getParent()", empty, tmp);
3944 
3945     uprv_memset(tmp, '!', sizeof tmp);
3946     reslen = uloc_getParent(und_region, tmp, sizeof tmp, status);
3947     status.errIfFailureAndReset("\"%s\"", und_region);
3948     assertTrue("reslen >= 0", reslen >= 0);
3949     assertEquals("uloc_getParent()", empty, tmp);
3950 
3951     // uloc_getLanguage()
3952 
3953     uprv_memset(tmp, '!', sizeof tmp);
3954     reslen = uloc_getLanguage(empty, tmp, sizeof tmp, status);
3955     status.errIfFailureAndReset("\"%s\"", empty);
3956     assertTrue("reslen >= 0", reslen >= 0);
3957     assertEquals("uloc_getLanguage()", empty, tmp);
3958 
3959     uprv_memset(tmp, '!', sizeof tmp);
3960     reslen = uloc_getLanguage(root, tmp, sizeof tmp, status);
3961     status.errIfFailureAndReset("\"%s\"", root);
3962     assertTrue("reslen >= 0", reslen >= 0);
3963     assertEquals("uloc_getLanguage()", empty, tmp);
3964 
3965     uprv_memset(tmp, '!', sizeof tmp);
3966     reslen = uloc_getLanguage(und, tmp, sizeof tmp, status);
3967     status.errIfFailureAndReset("\"%s\"", und);
3968     assertTrue("reslen >= 0", reslen >= 0);
3969     assertEquals("uloc_getLanguage()", empty, tmp);
3970 
3971     uprv_memset(tmp, '!', sizeof tmp);
3972     reslen = uloc_getLanguage(empty_script, tmp, sizeof tmp, status);
3973     status.errIfFailureAndReset("\"%s\"", empty_script);
3974     assertTrue("reslen >= 0", reslen >= 0);
3975     assertEquals("uloc_getLanguage()", empty, tmp);
3976 
3977     uprv_memset(tmp, '!', sizeof tmp);
3978     reslen = uloc_getLanguage(empty_region, tmp, sizeof tmp, status);
3979     status.errIfFailureAndReset("\"%s\"", empty_region);
3980     assertTrue("reslen >= 0", reslen >= 0);
3981     assertEquals("uloc_getLanguage()", empty, tmp);
3982 
3983     uprv_memset(tmp, '!', sizeof tmp);
3984     reslen = uloc_getLanguage(und_script, tmp, sizeof tmp, status);
3985     status.errIfFailureAndReset("\"%s\"", und_script);
3986     assertTrue("reslen >= 0", reslen >= 0);
3987     assertEquals("uloc_getLanguage()", empty, tmp);
3988 
3989     uprv_memset(tmp, '!', sizeof tmp);
3990     reslen = uloc_getLanguage(und_region, tmp, sizeof tmp, status);
3991     status.errIfFailureAndReset("\"%s\"", und_region);
3992     assertTrue("reslen >= 0", reslen >= 0);
3993     assertEquals("uloc_getLanguage()", empty, tmp);
3994 }
3995 
3996 #define ARRAY_RANGE(array) (array), ((array) + UPRV_LENGTHOF(array))
3997 
TestRangeIterator()3998 void LocaleTest::TestRangeIterator() {
3999     IcuTestErrorCode status(*this, "TestRangeIterator");
4000     Locale locales[] = { "fr", "en_GB", "en" };
4001     Locale::RangeIterator<Locale *> iter(ARRAY_RANGE(locales));
4002 
4003     assertTrue("0.hasNext()", iter.hasNext());
4004     const Locale &l0 = iter.next();
4005     assertEquals("0.next()", "fr", l0.getName());
4006     assertTrue("&0.next()", &l0 == &locales[0]);
4007 
4008     assertTrue("1.hasNext()", iter.hasNext());
4009     const Locale &l1 = iter.next();
4010     assertEquals("1.next()", "en_GB", l1.getName());
4011     assertTrue("&1.next()", &l1 == &locales[1]);
4012 
4013     assertTrue("2.hasNext()", iter.hasNext());
4014     const Locale &l2 = iter.next();
4015     assertEquals("2.next()", "en", l2.getName());
4016     assertTrue("&2.next()", &l2 == &locales[2]);
4017 
4018     assertFalse("3.hasNext()", iter.hasNext());
4019 }
4020 
TestPointerConvertingIterator()4021 void LocaleTest::TestPointerConvertingIterator() {
4022     IcuTestErrorCode status(*this, "TestPointerConvertingIterator");
4023     Locale locales[] = { "fr", "en_GB", "en" };
4024     Locale *pointers[] = { locales, locales + 1, locales + 2 };
4025     // Lambda with explicit reference return type to prevent copy-constructing a temporary
4026     // which would be destructed right away.
4027     Locale::ConvertingIterator<Locale **, std::function<const Locale &(const Locale *)>> iter(
4028         ARRAY_RANGE(pointers), [](const Locale *p) -> const Locale & { return *p; });
4029 
4030     assertTrue("0.hasNext()", iter.hasNext());
4031     const Locale &l0 = iter.next();
4032     assertEquals("0.next()", "fr", l0.getName());
4033     assertTrue("&0.next()", &l0 == pointers[0]);
4034 
4035     assertTrue("1.hasNext()", iter.hasNext());
4036     const Locale &l1 = iter.next();
4037     assertEquals("1.next()", "en_GB", l1.getName());
4038     assertTrue("&1.next()", &l1 == pointers[1]);
4039 
4040     assertTrue("2.hasNext()", iter.hasNext());
4041     const Locale &l2 = iter.next();
4042     assertEquals("2.next()", "en", l2.getName());
4043     assertTrue("&2.next()", &l2 == pointers[2]);
4044 
4045     assertFalse("3.hasNext()", iter.hasNext());
4046 }
4047 
4048 namespace {
4049 
4050 class LocaleFromTag {
4051 public:
LocaleFromTag()4052     LocaleFromTag() : locale(Locale::getRoot()) {}
operator ()(const char * tag)4053     const Locale &operator()(const char *tag) { return locale = Locale(tag); }
4054 
4055 private:
4056     // Store the locale in the converter, rather than return a reference to a temporary,
4057     // or a value which could go out of scope with the caller's reference to it.
4058     Locale locale;
4059 };
4060 
4061 }  // namespace
4062 
TestTagConvertingIterator()4063 void LocaleTest::TestTagConvertingIterator() {
4064     IcuTestErrorCode status(*this, "TestTagConvertingIterator");
4065     const char *tags[] = { "fr", "en_GB", "en" };
4066     LocaleFromTag converter;
4067     Locale::ConvertingIterator<const char **, LocaleFromTag> iter(ARRAY_RANGE(tags), converter);
4068 
4069     assertTrue("0.hasNext()", iter.hasNext());
4070     const Locale &l0 = iter.next();
4071     assertEquals("0.next()", "fr", l0.getName());
4072 
4073     assertTrue("1.hasNext()", iter.hasNext());
4074     const Locale &l1 = iter.next();
4075     assertEquals("1.next()", "en_GB", l1.getName());
4076 
4077     assertTrue("2.hasNext()", iter.hasNext());
4078     const Locale &l2 = iter.next();
4079     assertEquals("2.next()", "en", l2.getName());
4080 
4081     assertFalse("3.hasNext()", iter.hasNext());
4082 }
4083 
TestCapturingTagConvertingIterator()4084 void LocaleTest::TestCapturingTagConvertingIterator() {
4085     IcuTestErrorCode status(*this, "TestCapturingTagConvertingIterator");
4086     const char *tags[] = { "fr", "en_GB", "en" };
4087     // Store the converted locale in a locale variable,
4088     // rather than return a reference to a temporary,
4089     // or a value which could go out of scope with the caller's reference to it.
4090     Locale locale;
4091     // Lambda with explicit reference return type to prevent copy-constructing a temporary
4092     // which would be destructed right away.
4093     Locale::ConvertingIterator<const char **, std::function<const Locale &(const char *)>> iter(
4094         ARRAY_RANGE(tags), [&](const char *tag) -> const Locale & { return locale = Locale(tag); });
4095 
4096     assertTrue("0.hasNext()", iter.hasNext());
4097     const Locale &l0 = iter.next();
4098     assertEquals("0.next()", "fr", l0.getName());
4099 
4100     assertTrue("1.hasNext()", iter.hasNext());
4101     const Locale &l1 = iter.next();
4102     assertEquals("1.next()", "en_GB", l1.getName());
4103 
4104     assertTrue("2.hasNext()", iter.hasNext());
4105     const Locale &l2 = iter.next();
4106     assertEquals("2.next()", "en", l2.getName());
4107 
4108     assertFalse("3.hasNext()", iter.hasNext());
4109 }
4110 
TestSetUnicodeKeywordValueInLongLocale()4111 void LocaleTest::TestSetUnicodeKeywordValueInLongLocale() {
4112     IcuTestErrorCode status(*this, "TestSetUnicodeKeywordValueInLongLocale");
4113     const char* value = "efghijkl";
4114     icu::Locale l("de");
4115     char keyword[3];
4116     CharString expected("de-u", status);
4117     keyword[2] = '\0';
4118     for (char i = 'a'; i < 's'; i++) {
4119         keyword[0] = keyword[1] = i;
4120         expected.append("-", status);
4121         expected.append(keyword, status);
4122         expected.append("-", status);
4123         expected.append(value, status);
4124         l.setUnicodeKeywordValue(keyword, value, status);
4125         if (status.errIfFailureAndReset(
4126             "setUnicodeKeywordValue(\"%s\", \"%s\") fail while locale is \"%s\"",
4127             keyword, value, l.getName())) {
4128             return;
4129         }
4130         std::string tag = l.toLanguageTag<std::string>(status);
4131         if (status.errIfFailureAndReset(
4132             "toLanguageTag fail on \"%s\"", l.getName())) {
4133             return;
4134         }
4135         if (tag != expected.data()) {
4136             errln("Expected to get \"%s\" bug got \"%s\"", tag.c_str(),
4137                   expected.data());
4138             return;
4139         }
4140     }
4141 }
4142 
TestSetUnicodeKeywordValueNullInLongLocale()4143 void LocaleTest::TestSetUnicodeKeywordValueNullInLongLocale() {
4144     IcuTestErrorCode status(*this, "TestSetUnicodeKeywordValueNullInLongLocale");
4145     const char *exts[] = {"cf", "cu", "em", "kk", "kr", "ks", "kv", "lb", "lw",
4146       "ms", "nu", "rg", "sd", "ss", "tz"};
4147     for (int32_t i = 0; i < UPRV_LENGTHOF(exts); i++) {
4148         CharString tag("de-u", status);
4149         for (int32_t j = 0; j <= i; j++) {
4150             tag.append("-", status).append(exts[j], status);
4151         }
4152         if (status.errIfFailureAndReset(
4153                 "Cannot create tag \"%s\"", tag.data())) {
4154             continue;
4155         }
4156         Locale l = Locale::forLanguageTag(tag.data(), status);
4157         if (status.errIfFailureAndReset(
4158                 "Locale::forLanguageTag(\"%s\") failed", tag.data())) {
4159             continue;
4160         }
4161         for (int32_t j = 0; j <= i; j++) {
4162             l.setUnicodeKeywordValue(exts[j], nullptr, status);
4163             if (status.errIfFailureAndReset(
4164                     "Locale(\"%s\").setUnicodeKeywordValue(\"%s\", nullptr) failed",
4165                     tag.data(), exts[j])) {
4166                  continue;
4167             }
4168         }
4169         if (strcmp("de", l.getName()) != 0) {
4170             errln("setUnicodeKeywordValue should remove all extensions from "
4171                   "\"%s\" and only have \"de\", but is \"%s\" instead.",
4172                   tag.data(), l.getName());
4173         }
4174     }
4175 }
4176