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