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