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