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